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"
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With