I’m new to Ruby. I’m looking for an elegant solution to a simple
problem.
I have some classes like this one in my code:
class A
attr_reader :a1, a2
def initialize(a1, a2) @a1 = a1 @a2 = a2
end
end
I’m looking for a way in order not to have to define the initialize
method in each class. Struct doesn’t fit my needs since due to single
inheritance I can’t have any other superclass, and I would like to.
You could create an attr_initializer, something like:
module MyInitSystem
# extend hack
def self.included(base)
base.extend ClassMethods
end
module ClassMethods
attr_reader :attr_initializers
def attr_initializer(*args)
@attr_initializers ||= []
@attr_initializers.concat(args)
attr_reader *args
end
end
def initialize(*args)
self.class.attr_initializers.each_with_index do |a,i|
instance_variable_set("@#{a}", args[i])
end
end
end
class A
include MyInitSystem
attr_initializer :a, :b
end
Albeit, I’d use a hash to populate my object by var name.
attr_reader :a1, a2
method in each class. Struct doesn’t fit my needs since due to single
inheritance I can’t have any other superclass, and I would like to.
Any suggestions?
Thanks in advance.
Hi
Don’t know if this has been done before, but here’s a quick stab I
took at it:
require ‘generator’
module InitializesWith
def initializes_with(*params)
define_method :initialize do |*args|
iterator = SyncEnumerator.new(params, args)
iterator.each do |param, arg|
instance_variable_set “@#{param}”, arg
end
end
end
end
class Class
include InitializesWith
end
class C
attr_reader :x, :y, :z
initializes_with :x, :y, :z
end
class C
attr_reader :x, :y, :z
initializes_with :x, :y, :z
end
evaluates to a Proc object, due to initializes_with implementation. I
guess it would be better to return nil at the end. Just a minor
aesthetic detail as I said.
I’m looking for a way in order not to have to define the initialize
method in each class. Struct doesn’t fit my needs since due to single
inheritance I can’t have any other superclass, and I would like to.
Are you looking for something like the following?
class A
auto_attr_reader :a1, :a2
end
a = A.new 7,8
puts a.a1 # -> 7
puts a.a2 # -> 8
You mentioned both wanting to be able to inherit from another class
and that you don’t want to define initialize, so will all of the
classes you wish to inherit from not need initialization?
class Class
def generate_initialize(*vars)
define_method(:initialize) do |*args|
vars.zip(args) do |var, arg|
instance_variable_set(“@#{var}”, arg)
end
end
end
end
I’m trying to enhance the previous solution (shown again at the end).
I’d like to call the initialize method of the superclass from the
generated initialize. For the moment it’s ok to call it without
parameters. Simply placing super inside the method definition doesn’t
work. Can anyone explain me how to do it. Thanks in advance.
Why doesn’t it work?
def initialize_with(*params)
define_method(:initialize) do |*args|
if args.size != params.size then
raise ArgumentError.new(“wrong number of arguments”
" (#{args.size} for #{params.size})")
end
super() if defined?(super)
params.zip(args) do |param, arg|
instance_variable_set("@#{param}", arg)
end
end
return params
end
The “()” on super clears the auto-passing of parameters.
The “()” on super clears the auto-passing of parameters.
It seems to work (if this is what you meant):
module HasInitializeWith
def initialize_with(*params)
define_method(:initialize) do |*args|
if args.size != params.size then
raise ArgumentError.new(“wrong number of arguments”
" (#{args.size} for #{params.size})")
end
super() if defined?(super)
params.zip(args) do |param, arg|
instance_variable_set("@#{param}", arg)
end
end
return params
end
end
class A
extend HasInitializeWith
self.initialize_with :foo
end
I’m trying to enhance the previous solution (shown again at the end).
I’d like to call the initialize method of the superclass from the
generated initialize. For the moment it’s ok to call it without
parameters. Simply placing super inside the method definition doesn’t
work. Can anyone explain me how to do it. Thanks in advance.
def initialize_with(*params)
define_method(:initialize) do |*args|
if args.size != params.size then
raise ArgumentError.new(“wrong number of arguments”
" (#{args.size} for #{params.size})")
end
params.zip(args) do |param, arg|
instance_variable_set("@#{param}", arg)
end
end
return params
end