Reputation: 321
I have a Ruby class with all static methods. I want to use these methods in another class. Passing just the class name works but wondering if its the right way to go or is there another way.
class Foo
IDENTIFIER = 'UYT78'
def self.some_data
DB.fetch_records
end
# and so forth
end
class Bar
IDENTIFIER = 'XXXXX'
def self.some_data
DB.fetch_records
end
# and so forth
end
class Reporter
def report
Foo.some_data.select {|x| x.id == Foo::identifier}
end
def other_report
Bar.some_data.select {|x| x.id == Foo::identifier}
end
end
Can Reporter be changed to accept Foo as argument to the methods so these methods can be re-used based on the argument being passed?
Reporter.report(Foo)
Reporter.report(Bar)
and report method looks like
def report(klass)
klass.some_data.select {|x| x.id == Foo::identifier}
end
This approach works but passing a class name like this as argument doesn't feel right? Or may be it is?
Upvotes: 0
Views: 2203
Reputation: 110675
Perhaps this is what you are looking for.
class Foo
IDENTIFIER = 'UYT78'
def self.some_data
['ABC21', 'UYT78']
end
end
class Bar
IDENTIFIER = 'XXXXX'
def self.some_data
['XXXXX', 'DEF38']
end
end
class Reporter
def report(klass)
k = Module.const_get(klass)
k.public_send(:some_data).select {|x| x == k::IDENTIFIER}
end
end
reporter = Reporter.new
reporter.report("Foo") #=> ["UYT78"]
reporter.report("Bar") #=> ["XXXXX"]
reporter.report(:Bar) #=> ["XXXXX"]
Upvotes: 0
Reputation: 1179
What you are trying to do is nice but rather than passing the class like that I would use ruby's require
.
foo.rb
class Foo
IDENTIFIER = 'UYT78'.freeze
def self.some_data
'Foo'
end
end
bar.rb
class Bar
IDENTIFIER = 'XXXXX'.freeze
def self.some_data
'Bar'
end
end
reporter.rb
require './foo'
require './bar'
class Reporter
def report
p Foo.some_data
p Foo::IDENTIFIER
end
def other_report
p Bar.some_data
p Bar::IDENTIFIER
end
end
Reporter.new.report
puts '----------------'
Reporter.new.other_report
Which would return like below (Just and example)-
"Foo"
"UYT78"
----------------
"Bar"
"XXXXX"
In my opinion it's much cleaner.
Upvotes: 1
Reputation: 36860
That's fine... generally it's referred to as duck-typing
... as long as the class passed supports #some_data
method, it doesn't really matter what specific class it is. If it looks like a duck, and quacks like a duck...
It's possible you may want to store the target class at initialization.
class Reporter
attr_accessor :klass
def initialize(klass)
self.klass = klass
end
def report
klass.some_data.select
end
end
my_foo_reporter = Reporter.new(Foo)
my_foo_reporter.report # calls some_date on Foo class
Upvotes: 1