module StringReader
def string_reader(*params)
params.each do |param|
variable_name = "@" + param.to_s
define_method(param) do
self.instance_variable_get(variable_name).to_s
end
end
end
end
class MyClass
class << self
include StringReader
end
string_reader :foo
def initialize
@foo = 42
end
end
require "pp"
my = MyClass.new
pp my.foo #=> "42" (a string)
# I would like to re-write the MyClass definition to:
#
# class MyClass
# include StringReader
#
# string_reader :foo
#
# def initialize
# @foo = 42
# end
# end
#
# How do I refactor StringReader to get this code?
Refactorings
No refactoring yet !
Ryan Bates
June 3, 2008, June 03, 2008 14:08, permalink
You can use extend instead to turn the module methods into class methods.
class MyClass extend StringReader #... end
macournoyer
June 3, 2008, June 03, 2008 14:58, permalink
I think this makes the code easier to understand
module StringReader
def string_reader(*params)
params.each do |param|
class_eval <<-EOS
def #{param}
@#{param}.to_s
end
EOS
end
end
end
Rick DeNatale
June 4, 2008, June 04, 2008 12:12, permalink
Here's a pretty conventional approach to having a module provide class methods when included in another class or module
module StringReader
module ClassMethods
def string_reader(*params)
params.each do |param|
variable_name = "@" + param.to_s
define_method(param) do
self.instance_variable_get(variable_name).to_s
end
end
end
end
def self.included(cls)
cls.extend ClassMethods
end
end
class MyClass
include StringReader
string_reader :foo
def initialize
@foo = 42
end
end
my = MyClass.new
my.foo # => "42"
elliottcable
June 9, 2008, June 09, 2008 16:17, permalink
I like Rick's method, I use that a lot. #included is pretty awesome (-:
See the comment at the bottom of the code, but basically I'd like to move the "class << self" code into the StringReader module.