I want to share some initialization logic between two classes that DO NOT inherit from one another (so I can't invoke super inside initialize).
For example, notice that both Person and Dog class share the age and name kwargs and initialization logic:
class Person
def initialize(age: , name: , height: )
@age = age.to_i
@name = name.to_sym
@height = height
end
end
class Dog
def initialize(age: , name: , breed: )
@age = age.to_i
@name = name.to_sym
@breed = breed
end
end
To keep code DRY, I don't want to repeat this in both classes; instead I'd like to move that shared logic to a Module and include it on both classes.
However, I don't want to change the initialization params to a options = {} (hash), so I'd like to still use keyword arguments for the initialize method on both classes. In a way, we would need to merge the shared kwargs with the class specific ones on def initialize.
How one could share this initialization logic (keyword arguments and initialize method) between two different classes?
UPDATE
One way to achieve half of the goal (sharing the initialization logic) could be by using binding:
module AgeAndNameInitializationConcern
def self.included(base)
base.class_eval do
attr_reader :name, :age
end
end
def initialize_age_and_name(binding)
code_string = <<~EOT
@age = age.to_i
@name = name.to_sym
EOT
eval(code_string, binding)
end
end
class Person
include AgeAndNameInitializationConcern
def initialize(age: , name: , height: )
initialize_age_and_name(binding)
@height = height
end
end
class Dog
include AgeAndNameInitializationConcern
def initialize(age: , name: , breed: )
initialize_age_and_name(binding)
@breed = breed
end
end
@name = sex.to_symshould be@name = name.to_sym? Also when including aModuleyou can callsuperbecause theModuleis injected into the class Hierarchy. so something as simple asmodule A; def initialize(age:,name:,**); @age = age; @name = name; end; endwould work withclass B; include A; def initialize(age:,name:,height:); super; @height = height; end; endsuperworks perfectly fine the**at the end will collect and ignore all other "kwargs". That being said we can modify the class B definition to beclass B; include A; def initialize(height:,**rest); super(**rest); @height = height; end; endproblem solved.**restinsight. I tried following that path but it took me a problem I specified in another question. If you're interested: stackoverflow.com/q/69824456/1290457