I am looking into someones code and found that he has done class eval with something like this
self.class_eval("@default_robot_engine = RobotEngine.new(some_block)")
and later it is accessed like this
self.class_eval("@default_robot_engine")
I need help to understand this code. Is there any other way to access @default_robot_engine rather than doing class_eval on it?
when I do Class.instance_variable_names I get
["@attribute_methods_mutex", "@generated_attribute_methods", "@generated_feature_methods", "@observer_instances", "@per_page", "@parent_name", "@registered_robot_engines", "@default_robot_engine", "@primary_key", "@quoted_primary_key", "@locking_column", "@attribute_methods_generated", "@table_name", "@quoted_table_name", "@arel_table", "@arel_engine", "@relation", "@columns", "@column_names", "@columns_hash", "@cached_attributes", "@attribute_method_matchers_cache", "@generated_external_attribute_methods"]
and I am able to access all the instance variable like this ClassName.registered_robot_engine
except default_robot_engine
. why?
Ok I got the answer because this instance variable is a dynamic one and attr_reader is not set on it so I think only way to access it is via class_eval
I am able to access all the instance variable like this ClassName.registered_robot_engine except default_robot_engine. why?
class Dog
class<< self
attr_accessor :registered_robot_engine
def set_stuff
@registered_robot_engine = 'hello'
@default_robot_engine = 20
end
end
end
Dog.set_stuff
puts Dog.registered_robot_engine
puts Dog.default_robot_engine
--output:--
hello
1.rb:16:in `<main>': undefined method `default_robot_engine' for Dog:Class (NoMethodError)
The basic rule in ruby is that all instance variables are private by default, so unless you provide accessor methods for an instance variable you can't access it. In the example above, there are no accessor methods defined for @default_robot_engine, so it is inaccessible, while the other instance variable does have accessor methods defined for it, so it is accessible.
Both class_eval() and instance_eval() allow you to violate encapsulation and read or write private instance variables:
class Dog
class <<self
def set_stuff
@registered_robot_engine = 'hello'
@default_robot_engine = 20
end
def set_more_stuff
class_eval do
@default_robot_engine = 100
end
end
end
end
Dog.set_stuff
Dog.set_more_stuff
puts Dog.class_eval{ @default_robot_engine }
--output:--
100
instance_variable_set() and instance_variable_get() allow you to do the same thing:
class Dog
def initialize
@name = "Rover"
end
end
d = Dog.new
d.instance_variable_set(:@name, "John")
puts d.instance_variable_get(:@name)
--output:--
John
Secondly, it is hard to imagine why the programmer didn't use standard getter and setter, as in:
class << self attr_accessor :default_robot_engine end
I would guess that the programmer is using someone else's module, and the programmer has decided to violate encapsulation, which ruby allows you to do. Some languages believe that although encapsulation is good, it shouldn't be strictly enforced. If for some reason a programmer wants to violate encapsulation, they should have the freedom to do so.
Collected from the Internet
Please contact [email protected] to delete if infringement.
Comments