Code360 powered by Coding Ninjas X Naukri.com. Code360 powered by Coding Ninjas X Naukri.com
Table of contents
1.
Introduction
1.1.
Unicode Codepoint Constants with const_missing
1.2.
Tracing Method Invocations with method_missing
1.2.1.
Program:-
2.
Synchronized Objects by Delegation
3.
Frequently Asked Questions
3.1.
What does Ruby's metaprogramming mean?
3.2.
What do Ruby methods mean?
4.
Conclusion
Last Updated: Mar 27, 2024
Medium

Missing Methods and Missing Constants in Ruby

Author Sarthak
0 upvote

Introduction

A crucial component of Ruby's method lookup process, the method_missing method offers a powerful way of detecting and handling arbitrary invocations on an object. Similar work is done for the constant lookup technique by the const_missing method of Module, enabling on-the-fly computation or lazy initialization of constants. Both of these techniques are illustrated in the following blog.

Missing Methods and Missing Constants

Let's dive into the article to get information about missing methods and constants in Ruby.

Unicode Codepoint Constants with const_missing

The example that follows defines a Unicode module that seems to represent a constant (a UTF-8 encoded text) for every Unicode codepoint between U+0000 and U+10FFFF. The const_missing function is the only feasible technique to support this many constants. The const_missing method invokes Module.const_set to define an actual constant to refer to each value it computes since the code assumes that if a constant is referenced once, it will likely be used again.
 

Program:

# For all Unicode codepoints, this module offers constants that define the #UTF-8 strings
. It hastily defines them using const_missing.

module
 Unicode 
# 
Using this technique, we can define Unicode codepoint constants on the fly.
def self.const_missing(name) # Undefined constant passed as symbol 
# Verify the correct form of the constant name
.
# Hexadecimal value between 0000 and 10FFFF, then a capital U.
if name.to_s =~ /^U([0-9a-fA-F]{4,5}|10[0-9a-fA-F]{4})$/ 
#The matched hexadecimal value is $1. To an integer
, convert.
codepoint = $1.to_i(16) 
# Convert number to a UTF-8 string with magic of Array.pack. 
utf8 = [codepoint].pack("U") 
# Make the string immutable in UTF-8. 
utf8.freeze 
# Define real constant for faster lookup next time,  
# and return
 the UTF-8 text this time. const_set(name, utf8) 
else 
# Raise an error for constants of wrong form. raise NameError, "Uninitialized constant: Unicode::#{name}" 
end 
end 
end
You can also try this code with Online Ruby Compiler
Run Code

Tracing Method Invocations with method_missing

We used method_missing earlier in this chapter to show how the Hash class might be extended. In the following example, we show how to delegate arbitrary calls on one object to another by using method_missing. In this illustration, we carry out this action to produce tracing messages for the object.

A TracedObject class and the object.trace instance method is defined in Example. The return value of the trace method is an instance of the TracedObject class that utilizes method_missing to track down and delegate invoked methods to the object being traced. This is one way to employ it:

a = [1,2,3].trace("a") 
a.reverse 
puts a[2] 
puts a.fetch(3)
You can also try this code with Online Ruby Compiler
Run Code

This produces the following output:-

Invoking: a.reverse() at trace1.rb:66 
Returning: [3, 2, 1] from a.reverse to trace1.rb:66 
Invoking: a.fetch(3) at trace1.rb:67 
Raising: IndexError:index 3 out of array from a.fetch

Program:-

# Call any object's trace function to create a duplicate object that 
mimics
#the original while tracking all method calls
 made to it. If tracing multiple
# objects, give each one a name 
that will appear in the output. Messages  
# are often sent to STDERR, 
by default, but you can choose any stream (or object) 
#that accepts strings 
as arguments to.
class Object 
def trace(name="", stream=STDERR) 
# Return TracedObject that traces and delegates everything. TracedObject.new(self, name, stream)
  end 
end 
# This class uses the method missing function to track method 
calls
#before delegating them to another object. 
To prevent getting in the way
#of method missing, it deletes the
 majority of its instance methods.
# Take note that only calls made via the TracedObject will be trac
ked.
# These invocations 
# will not be trac
ked if the delegate object uses its own methods.


class TracedObject 
# Note the use of Module.instance_methods and Module.undef_method. instance_methods.each do |m| 
m = m.to_sym # Ruby 1.8 returns strings, instead of symbols 
next if m == :object_id || m == :__id__ || m == :__send__ undef_method m
end 


# Initialize this TracedObject instance. 
def initialize(o, name, stream) 
@o = o # The object we delegate to 
@n = name # The object name to appear in tracing messages 
@trace = stream # Where those tracing messages are sent 
end 


def method_missing(*args, &block) 
m = args.shift # First arg is the name of the method 
begin 
# Trace the invocation of the method. 
arglist = args.map {|a| a.inspect}.join(', ') 
@trace << "Invoking: #{@n}.#{m}(#{arglist}) at #{caller[0]}\n" 
# Invoke the method on our delegate object and get the return value.
 r = @o.send m, *args, &block 
# Trace a normal return of the method. 
@trace << "Returning: #{r.inspect} from #{@n}.#{m} to #{caller[0]}\n" # Return whatever value the delegate object returned.
r 
rescue Exception => e 
# Trace an abnormal return from the method. 
@trace << "Raising: #{e.class}:#{e} from #{@n}.#{m}\n" 
# And re-raise whatever exception the delegate object raised.
raise 
end 
end 
# Return the object we delegate to. 
def __delegate 
@o 
end 
end
You can also try this code with Online Ruby Compiler
Run Code

Synchronized Objects by Delegation

A global method receives an object and performs a block while being protected by the Mutex connected to that object, as demonstrated in the following example. The object.mutex method's implementation took up most of the example. The synchronized approach was simple:

def synchronized(o) 
o.mutex.synchronize { yield } 
end
You can also try this code with Online Ruby Compiler
Run Code

Example1: changes this function by returning a SynchronizedObject wrapper around the object when it is called without a block. A delegating wrapper class based on method_missing is called SynchronizedObject. It is quite similar to the TracedObject class in the following example of the program. Still, it is written as a subclass of BasicObject in Ruby 1.9, so the object instance methods do not need to be explicitly deleted. It should be noted that the example code needs the object.mutex method that was previously defined; it cannot be run independently.

def synchronized(o) 
if block_given? 
o.mutex.synchronize { yield } 
else 
SynchronizedObject.new(o) 
end 
end 
# Using method missing as a delegating wrapper class for 
#thread safety
. We just extend 
# BasicObject, which is defined 
#in Ruby 1.9, rather than extending Object and removing our methods.
#Since BasicObject does not 
# descend from Object or Kernel, it is simply
#not possible for BasicObject 
methods to call top-level methods since they do not exist.
class SynchronizedObject < BasicObject 
def initialize(o); 
@delegate = o; 
end 
def __delegate; 
@delegate; 
end 


def method_missing(*args, &block) 
@delegate.mutex.synchronize { 
@delegate.send *args, &block 
} 
end 
end
You can also try this code with Online Ruby Compiler
Run Code

Frequently Asked Questions

What does Ruby's metaprogramming mean?

Writing code that automatically writes code at runtime using the metaprogramming technique. This implies that you can define classes and methods at runtime.

What do Ruby methods mean?

A Ruby method is a collection of expressions that yields a result. With the aid of methods, one can divide their code into simple-to-use subroutines that can be called from different parts of their program. This is sometimes referred to as a function in other languages. A method may be defined alone or as a component of a class.

Conclusion

In this article, we have extensively discussed the missing methods and missing constants with the help of various program examples in the Ruby programming language.

We hope this blog has helped you enhance your missing constants and missing methods in ruby knowledge. If you want to learn more, check out our rubyruby language, and ruby documentation articles. Practice makes a man perfect. To practice and improve yourself in the interview, you can check out Top 100 SQL problemsInterview experienceCoding interview questions, and the Ultimate guide path for interviews.

Do upvote our blog to help other ninjas grow. 

Happy Coding!

Live masterclass