Hello, this is my first post to this list and I have only been using
ruby for a couple of weeks so forgive me if its overly simple, I spent a
few hours searching and wasn’t able to figure this out myself.
What I am trying to do is use some meta-programming techniques to create
a simple DSL that allows me to define functions dynamically and collect
other information that I can iterate over. I have an implementation that
is using “Class Variables” that is working but I have to specify all of
the functions that use the @@ variables in all of the subclasses which
violates DRY and my sensiblities. What I am looking for is a way to have
subclass specific information used by a common class.
Below is the implementation I have (boiled down to its simplest possible
form with a testcase to show the behavior I need). I know there must be
a better way to do this but my ruby-fu is not up to the task yet, im
really interested to see what the idiomatic ruby way to do this is.
Sam H.
------------ Example.rb --------------
require ‘test/unit’
module MethodCollector
def self.included( klass)
klass.extend ClassMethods
end
module ClassMethods
def addpoint(array_name, name)
is_defined = send(:class_variable_defined?, array_name)
if !is_defined
arr = Array.new
send(:class_variable_set, array_name, arr)
elsif
arr = send(:class_variable_get,array_name)
end
arr << name
end
def add_method(name)
method_name = (name.to_s).to_sym
self.send :define_method, method_name do
"MethodName is: #{method_name}"
end
addpoint(:@@extra_methods, name)
end
end
end
class MethodAdderBase
include MethodCollector
# ideally I would define this method (and any others with other
common functionality that
# use the “class specific” variables
#def extra_methods
# @@extra_methods
#end
end
class Foo < MethodAdderBase
add_method :foo_1
add_method :foo_2
add_method :foo_3
def extra_methods
@@extra_methods
end
end
class Bar < MethodAdderBase
add_method :bar_1
add_method :bar_2
add_method :bar_3
add_method :bar_4
def extra_methods
@@extra_methods
end
end
class Check < Test::Unit::TestCase
def test_methods_created
foo = Foo.new
bar = Bar.new
assert_equal(foo.foo_1, "MethodName is: foo_1")
assert_equal(bar.bar_1, "MethodName is: bar_1")
end
def test_methods_collected
foo = Foo.new
bar = Bar.new
assert_equal(foo.extra_methods.size, 3)
assert_equal(bar.extra_methods.size, 4)
end
end