Reflection in Ruby

Reflection in ruby?

Here is an answer that doesn't use eval.

PHP's Reflection is called Metaprogramming in Ruby, but they are quite different. Everything in Ruby is open and could be accessed.

Consider the following code:

class Foo
attr_reader :something

def initialize(input)
@something = input
end

def get_something
return @something
end
end

@registered = { }
def register(reference_name, class_name, params=[])
@registered[reference_name] = { class_name: class_name, params: [params].flatten }
end

def create(reference_name)
h = @registered[reference_name]
Object.const_get(h[:class_name]).new(*(h[:params]))
end

register('foo', 'Foo', ['something'])
puts create('foo').get_something

You can use Object#const_get to get objects from strings. Object.const_get('Foo') will give you the object Foo.

However, you don't need to send class name as string. You can also pass around the class name as object and use that directly.

class Foo
attr_reader :something

def initialize(input)
@something = input
end

def get_something
return @something
end
end

@registered = { }
def register(reference_name, class_name, params=[])
@registered[reference_name] = { class_name: class_name, params: [params].flatten }
end

def create(reference_name)
h = @registered[reference_name]
h[:class_name].new(*(h[:params]))
end

register('foo', Foo, ['something else'])
puts create('foo').get_something

When you say Ruby is reflective, does this mainly refer to duck typing?

Class reopening is a good example of this. Here's a simple example:

class Integer
def moxy
if self.zero?
self - 2
elsif self.nonzero?
self + 2
end
end
end

puts 10.moxy

By reopening a standard Ruby class - Integer - and defining a new method within it called 'moxy', we can perform a newly defined operation directly on a number. In this case, I've defined this made up 'moxy' method to subtract 2 from the Integer if it's zero and add two if it's nonzero. This makes the moxy method available to all objects of class Integer in Ruby. (Here we use the 'self' keyword to get the content of the integer object).

As you can see, it's a very powerful feature of Ruby.

EDIT: Some commenters have questioned whether this is really reflection. In the English language the word reflection refers to looking in on your own thoughts. And that's certainly an important aspect of reflection in programming also - using Ruby methods like is_a, kind_of, instance_of to perform runtime self-inspection. But reflection also refers to the the ability of a program to modify its own behavior at runtime. Reopening classes is one of the key examples of this. It's also called monkey patching. It's not without its risks but all I am doing is describing it here in the context of reflection, of which it is an example.

Ruby: Access member variable with string (Reflection)

I think what you mean with "member variable", is that you have a model that has an attribute called first_name. If so, then you can access that attribute as you'd do in a "plain" ("plain" because the question is focused to Rails) Ruby class:

class Foo
attr_accessor :name
def initialize(name)
@name = name
end
end

foo = Foo.new('bar')
p foo.instance_variables # [:@name]
p foo.instance_variable_get('@name') # "bar"

The most idiomatic way to get dynamically an instance variable is using instance_variable_get, but you can also use send, or better using __send__, or even better in your case using public_send:

foo = Foo.new('bar')
p foo.instance_variables # [:@name]
p foo.instance_variable_get('@name') # "bar"
p foo.send('name') # "bar"
p foo.public_send('name') # "bar"

The way Rails handles your models and attributes is almost the same (NOTE: opened to edition). By instantiating one of your models, you can get the attribute you need:

user = User.first
user.email # email@mail.com
user.public_send('email') # email@mail.com

Ruby reflection composition: call original method from redefined method

In my opinion, this approach is way too complex, and an inappropriate use of Modules.

I recommend thinking about a simpler way to implement this.

One simple way is to just include all the methods in the Phone class.

Or, you could use a hash as a lookup table for ring strategies:

class Phone

attr_accessor :ring_strategy

RING_STRATEGIES = {
ringtone: -> { ring_with_tone },
discreet: -> { ring_quietly },
screening: -> { ring_with_tone; ring_screening_too }
# ...
}

def initialize(ring_strategy = :ringtone)
@ring_strategy = ring_strategy
end

def ring
RING_STRATEGIES[:ring_strategy].()
end

end

Reflection in Ruby. Instantiate an object by given class name

You can do this:

arrayObject = Object::const_get('Array').new

How do you invoke ruby module methods via reflection?

With the following code you could do it:

Class.new.extend(Routes).send(:home)

Retrieving the Method instance from within a method in Ruby

I found a method that exactly does that.

class A
def foo
puts "A#foo: `I am #{method(__method__).super_method || method(__method__)}'"
end
end

I really admire Matz and the Ruby core developers. The existence of such method means that they had in mind such situation, and had thought about what to do with it.

ruby/irb get scope info for method

For the methods defined on Kernel / Object one might simply use:

method :puts
#⇒ #<Method: Object(Kernel)#puts>

For the method defined on the module/class that is not included everywhere, the fully qualified name is required:

Integer.instance_method :to_s
#⇒ #<UnboundMethod: Integer#to_s>

For methods, defined in ruby (not in c,) the source location might be also queried:

URI.method(:split).source_location
#⇒ ["/path_to_ruby/uri/common.rb", 192]


Related Topics



Leave a reply



Submit