Page Content

Tutorials

Reflection In Ruby: Inspecting Objects & Classes At Runtime

Reflection in Ruby

Introspection, sometimes referred to as reflection, is fundamental to Ruby’s dynamic nature and is intimately associated with the metaprogramming strategies we just covered. The ability of a program to analyze its own state and structure is basically what is meant by reflection. At runtime, it enables a Ruby program to retrieve details about its elements (such as classes, objects, and methods) and their settings.

Ruby’s broad reflection API is mostly implemented using methods included in the Module, Object, and Kernel classes.

Key Uses of Reflection

Examining Program State and Structure: You can query the existence and properties of classes and methods by treating them as objects using reflection. This is particularly helpful for interactively investigating a new object or class hierarchy, like in troubleshooting.

Dynamic Interaction: Beyond simple inspection, the reflection API enables a program to dynamically change its structure and state by adding new classes and methods, setting variables, and calling methods by name.

Enforcing Contracts and Duck Typing: The idea of duck typing can be used to enforce interfaces or software contracts by using reflection to make sure an object implements specific needed functions.

Reflection Methods and Code Examples

Many techniques for inspecting objects, classes, and methods are available in Ruby.

Inspecting Object Types and Ancestry

With reflection methods, you may quickly find out an object’s type, class, and relationship to other classes.

MethodPurposeSource
o.classReturns the class of object o
c.superclassReturns the parent class of class c
C.ancestorsReturns an array listing the ancestors (classes and modules) of class C
o.instance_of? cDetermines whether o is an instance of class c
o.kind_of? c or o.is_a? cChecks if o is an instance of c, one of its subclasses, or if it includes module c

Example (Class and Ancestry Introspection):

class A
  def a; end
end

module B
  def b; end
end

class C < A
  include B
  def c; end
end

# Print the results
puts "C.superclass:"
puts C.superclass

puts "\nC.ancestors:"
puts C.ancestors.inspect

puts "\nC.instance_methods(false):"
puts C.instance_methods(false).inspect

Output

C.superclass:
A

C.ancestors:
[C, B, A, Object, Kernel, BasicObject]

C.instance_methods(false):
[:c]

Listing and Testing Methods

The methods that an object or class implements can be dynamically found, which aids in the implementation of “duck typing” logic.

MethodPurposeSource
o.methodsReturns an array of names (symbols/strings) of all public methods available to object o
o.respond_to? nameDetermines whether o has a public or protected method with the specified name (pass true as the second argument to check private methods too)
C.instance_methods(false)Returns public instance methods defined directly in class C, excluding inherited ones
o.singleton_methodsReturns the names of singleton methods defined specifically on object o

Example (Method Listing and Checking):

s = "Hello"

puts "Class of s:"
puts s.class                      # => String

puts "\nDoes s respond to :upcase?"
puts s.respond_to?(:upcase)       # => true

puts "\nDoes s respond to :undefined_method?"
puts s.respond_to?(:undefined_method)  # => false

Output

Class of s:
String

Does s respond to :upcase?
true

Does s respond to :undefined_method?
false

Inspecting and Manipulating Variables

Direct variable inspection and manipulation are made possible via reflection; however, local variables typically necessitate the usage of eval with a Binding object.

MethodPurposeSource
o.instance_variablesReturns an array of instance variable names (symbols/strings) for object o
o.instance_variable_get(symbol)Returns the value of the named instance variable
o.instance_variable_set(symbol, value)Sets the value of the named instance variable
o.instance_variable_defined?(:@name)Checks if the specified instance variable has been defined on the object

Example (Instance Variable Reflection):

class Foo
  def initialize
    @bar = 42
  end
end

f = Foo.new

puts "Instance variables:"
p f.instance_variables            # => [:@bar]

puts "\nGet value of @bar:"
p f.instance_variable_get(:@bar)  # => 42

puts "\nSet @bar to 17:"
p f.instance_variable_set(:@bar, 17) # => 17

puts "\nIs @bar defined?"
p f.instance_variable_defined?(:@bar) # => true

puts "\nRemove @bar and return its value:"
p f.remove_instance_variable(:@bar)   # => 17

puts "\nInstance variables after removal:"
p f.instance_variables               # => []

Output

Instance variables:
[:@bar]

Get value of @bar:
42

Set @bar to 17:
17

Is @bar defined?
true

Remove @bar and return its value:
17

Instance variables after removal:
[]

Obtaining Method Objects and Dynamic Invocation

For dynamic execution and giving methods as arguments (such as callbacks), it is necessary that methods themselves be able to be regarded as data objects.

MethodPurposeSource
o.method(:name)Looks up the named method in object o and returns a callable Method object
M.instance_method(:name)Returns an UnboundMethod object associated with method :name in module/class M
m.call(*args)Invokes the method object m
o.send(symbol, *args)Invokes the method identified by the symbol/name directly on object o

Example (Dynamic Method Invocation using send): Using send allows you to call a method whose name is determined at runtime:

greeting = "hello"
method_name = :upcase

# Dynamically call the :upcase method
puts greeting.send(method_name)   # => "HELLO"

# A method object can be stored and called later:
reverse_method = greeting.method(:reverse)
puts reverse_method.call          # => "olleh"

Output

HELLO
olleh

Reflection gives Ruby developers a powerful microscope and a range of dynamic tools that allow them to examine and manipulate the program’s components in great detail. This serves as the basis for advanced metaprogramming design patterns.

Agarapu Geetha
Agarapu Geetha
My name is Agarapu Geetha, a B.Com graduate with a strong passion for technology and innovation. I work as a content writer at Govindhtech, where I dedicate myself to exploring and publishing the latest updates in the world of tech.
Index