Generation of initialize

Hi everyone,

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.

Any suggestions?

Thanks in advance.

On Oct 13, 5:20 am, [email protected] wrote:

Any suggestions?

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.

T.

On Oct 13, 2007, at 1:20 pm, [email protected] wrote:

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

obj = C.new(1,2,3)

obj.x # => 1
obj.y # => 2
obj.z # => 3

Any good?

Ashley

Thank you both for your replies.

Just a minor detail regarding:

 end

end

class Class
include InitializesWith
end

This:

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.

On Oct 13, 7:55 am, [email protected] wrote:

   define_method :initialize do |*args|

end
aesthetic detail as I said.
Return the attributes instead and you can do:

class C
  attr_reader *initializes_with(:x, :y, :z)
end

T.

On Oct 13, 8:19 am, [email protected] wrote:

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.

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?

It can be as simple as this.

gegroet,
Erik V. - http://www.erikveen.dds.nl/


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

class Foo
generate_initialize :a, :b, :c
end

p Foo.new(1, 2, 3)

On Oct 13, 2007, at 5:00 pm, Trans wrote:

class C
  attr_reader *initializes_with(:x, :y, :z)
end

Very clever :slight_smile:

On Oct 13, 4:01 pm, Erik V. [email protected] wrote:

   vars.zip(args) do |var, arg|

p Foo.new(1, 2, 3)
Might as well define the attrs while you’re at it so you can get the
data out :slight_smile:

On Oct 31, 4:10 pm, [email protected] wrote:

Hi again,

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.

T.

Trans wrote:

Why doesn’t it work?
end
end
return params
end

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

p A.new(3) # ==> #<A:0xb7c28cbc @foo=3>

Hi again,

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

Thanks. It was the “()” on super.