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 Module
s.
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
Download a Carrierwave Upload from S3
How to Specify Regexp Options Using Regexp.Union
Best/Most Elegant Way to Share Objects Between a Stack of Rack Mounted Apps/Middlewares
Why Does Including This Module Not Override a Dynamically-Generated Method
How to Implement Curry(Partial Function) in Ruby
Activemodel::Validations on Anonymous Class
What Is Returned in Ruby If The Last Statement Evaluated Is an If Statement
Fresh Ruby Gem from Bundler - Cannot Load My Version.Rb File
Can't Log into Active Admin. Any Way to Create an Admin User
Paperclip and Amazon S3 How to Do Paths
How to Parse Days/Hours/Minutes/Seconds in Ruby
Posting Ruby Data in JSON Format with Net/Http
Explanation of Ruby Code for Building Trie Data Structures
Why Slicing The Params Hash Poses a Security Issue on Mass-Assignment