Reputation: 452
I want to define methods dynamically using an array of strings.
Here is a simple piece of code that should achieve that.
class SomeClass
attr_accessor :my_array
def initialize(user, record)
@my_array=[]
end
my_array.each do |element|
alias_method "#{element}?".to_sym, :awesome_method
end
def awesome_method
puts 'awesome'
end
end
When I instantiate this class in the console, I get the following error
NoMethodError (undefined method `each' for nil:NilClass)
What is wrong with this code and how to make it work. any help highly appreciated :)
Edit 1: What I ultimately want to achieve is to inherit from SomeClass and override my_array in the child class to dynamically define methods with its attributes like so
class OtherClass < SomeClass
my_array = %w[method1 method2 method3]
# Some mechanism to over write my_array.
end
And then use self.inherited
to dynamically define methods in child class.
Is there a good way to achieve this?
Upvotes: 0
Views: 1311
Reputation:
In your code, you use an instance variable (@my_array) and an attr_accessor over it, and then try to access my_array from class level (that is, from the body of the class definition, outside of any methods). But instance variables only exist at instance level, so it is not available in the class scope.
One solution (the natural one, and the one which you would probably use in other languages) is to use a class variable: @@my_array. But class variables in ruby are a little problematic, so the best solution would be to make use of class instance variables, like that:
class SomeClass
class << self
attr_accessor :my_array
end
@my_array=[]
def initialize(user, record)
end
@my_array.each do |element|
alias_method "#{element}?".to_sym, :awesome_method
end
def awesome_method
puts 'awesome'
end
end
The syntax is a little tricky, so, if you look that up and it still doesn't makes sense, try just reading about scopes and using a regular class variable with @@.
Edit:
Ok, so, after your edit, it became more clear what you are trying to accomplish. A full working example is like follows:
class SomeClass
class << self
attr_accessor :my_array
end
@my_array=[]
def awesome_method
puts 'awesome'
end
def self.build!
@my_array.each do |element|
self.define_method("#{element}?".to_sym){ awesome_method }
end
end
end
class ChildClass < SomeClass
@my_array = %w[test little_test]
self.build!
end
child_instance = ChildClass.new
child_instance.test?
>> awesome
child_instance.little_test?
>> awesome
So, I've made some tweaks on SomeClass:
With that done, ChildClass inherits from SomeClass, and it's instances have the dynamically created methods 'test?' and 'little_test?'.
Upvotes: 3
Reputation: 1168
You need to change my_array
to class level accessible, in my case class constant.
class SomeClass
DYNAMIC_METHOD_NAMES = %w(method_a method_b method_C).freeze
def initialize(user, record)
end
DYNAMIC_METHOD_NAMES.each do |element|
alias_method "#{element}?".to_sym, :awesome_method
end
def awesome_method
puts 'awesome'
end
end
Upvotes: 2