Reputation: 30022
In Ruby how would you define a method
def make_class(method_name, method_body, s_value)
returning a class with the following implementation
class Anonymous
def method_name(args)
method_body(args)
end
def to_s
return s_value
end
end
If you can link to any resources you found useful on basic Ruby metaprogramming that would be great as well.
Upvotes: 2
Views: 413
Reputation: 66837
Easiest way I can think of:
def make_class(method_name, method_body, s_value)
klass = Class.new
klass.class_eval "def #{method_name} ; #{method_body} ; end"
klass.class_eval "def to_s ; #{s_value} ; end"
klass
end
Usage:
>> Anonymous = make_class(:foobar, "puts 'foo'", 23)
=> Anonymous
>> a = Anonymous.new
=> 23
>> a.foobar
foo
=> nil
>> a.to_s
=> 23
Edit: ok, I was a bit too simplistic here, this doesn't handle the args for the method.
Upvotes: 1
Reputation: 77
def make_class(method_name, method_body, s_value)
Class.new {
define_method method_name do |*args|
eval(method_body)
end
define_method :to_s do
s_value
end
}
end
"Metaprogramming Ruby: Program Like the Ruby Pros" is a very good book to learn about ruby metaprogramming.
Upvotes: 2
Reputation: 47618
You can use smth like that:
def make_class(s_value, method_name, &method_body)
Class.new do
define_method method_name, method_body
define_method :to_s do
s_value
end
end
end
klass = make_class 'foo instance', :foo do |*args|
"called foo with #{args.inspect}"
end
k = klass.new
puts k.to_s # => foo instance
puts k.foo [1, 2], 'hello' # => called foo with [[1, 2], "hello"]
In that case you are supposed to pass your method's body as a block (you can replace |*args|
with any list of arguments you want to have as parameters for you method). If you want to pass method_body
not as a block but as a string then eval
is your friend.
Upvotes: 5
Reputation: 18835
i would not recommend doing this, but you could...
def make_class(method_name, method_body, s_value)
eval("
class Anonymous
def #{method_name}(args)
#{method_body}(args)
end
def to_s
return '#{s_value}'
end
end
")
end
make_class(:bla, :puts, 'bla')
Anonymous.new.bla('moin')
puts Anonymous.new.to_s
returning
moin
bla
Upvotes: 0