Reputation: 35
Not sure if this is possible with Ruby, but I am trying to write a class with several methods that will be shared by a number of subclasses. This superclass will contain both class and instance methods that I want the subclasses to inherit. Assume that I will never use the superclass directly, I am only using it to abstract out methods that are repeated (thinking DRY). This involves having constants (API URIs) that will change from subclass to subclass.
Here's an example of what I am trying to do:
class Foo
attr_accessor :param
def initialize(param)
@param = param
end
def self.get
<SubClass>.new(self::MY_CONSTANT)
end
end
class Bar < Foo
MY_CONSTANT = 'Woot'
end
class Baz < Foo
MY_CONSTANT = 'Pew Pew'
end
The behavior I want is something like this:
Bar.get
puts Bar.param # => Woot
Baz.get
puts baz.param # => Pew Pew
Is this possible? Am I approaching this completely the wrong way?
Update
Per @Nathan, self.new
in the self.get
method did the trick here.
[39] pry(main)> test = Bar.get
=> #<Bar:0x000001072ecc20 @param="Woot">
[40] pry(main)> test.param
=> "Woot"
[41] pry(main)> test
=> #<Bar:0x000001072ecc20 @param="Woot">
[42] pry(main)> test.class
=> Bar
[43] pry(main)> test2 = Baz.get
=> #<Baz:0x000001071b5528 @param="Pew Pew">
[44] pry(main)> test2.class
=> Baz
[45] pry(main)> test2.param
=> "Pew Pew"
Upvotes: 3
Views: 2338
Reputation: 8026
Use self
.
Inside Foo.get
, self
is the class you're calling get
on, which would be Bar
and Baz
when you execute Bar.get
and Baz.get
, respectively.
Therefore, where you have <SubClass>
, just put self
, and everything will work as you expect.
def self.get
self.new(self::MY_CONSTANT)
end
You can also omit self
because that's what Ruby uses automatically when no explicit object is specified.
def self.get
new(self::MY_CONSTANT)
end
Also, in your code where you're testing the values, I think what you intend is this:
bar = Bar.get
puts bar.param # => Woot
baz = Baz.get
puts baz.param # => Pew Pew
Finally as for whether this is the best way, that's opinion-based, but it seems odd to me that you're trying to pass the value into initialize
when it's already available as a constant. In other words, if you have a method that needs to use the API URI, just reference the constant directly rather than initializing the instance itself with @param
. You can reference the constant inside an instance method like this: self.class::MY_CONSTANT
Upvotes: 5