8

It's time to make it shorter:

class Foo
  attr_accessor :a, :b, :c, :d, :e

  def initialize(a, b, c, d, e)
    @a = a
    @b = b
    @c = c
    @d = d
    @e = e
  end
end

We have 'attr_accessor' to generate getters and setters.

Do we have anything to generate initializers by attributes?

tshepang
  • 12,111
  • 21
  • 91
  • 136
Chris Xue
  • 2,317
  • 1
  • 25
  • 21

5 Answers5

15

Easiest:

Foo = Struct.new( :a, :b, :c )

Generates both accessors and initializer. You can further customize your class with:

Foo = Struct.new( … ) do
  def some_method
    …
  end
end
Phrogz
  • 296,393
  • 112
  • 651
  • 745
2

We can create something like def_initializer like this:

# Create a new Module-level method "def_initializer"
class Module
  def def_initializer(*args)
    self.class_eval <<END
      def initialize(#{args.join(", ")})
        #{args.map { |arg| "@#{arg} = #{arg}" }.join("\n")}
      end
END
  end
end

# Use it like this
class Foo
  attr_accessor   :a, :b, :c, :d
  def_initializer :a, :b, :c, :d

  def test
    puts a, b, c, d
  end
end

# Testing
Foo.new(1, 2, 3, 4).test

# Outputs:
# 1
# 2
# 3
# 4
Casper
  • 33,403
  • 4
  • 84
  • 79
  • 1
    +1 for using the string form of `eval` to require the proper arity. You should probably place this method on `Module` or the singleton class of `Class`, as there's not a lot of sense in using this on object instances other than classes. – Phrogz Apr 30 '12 at 18:56
1

You can use a gem like constructor. From the description:

Declarative means to define object properties by passing a hash to the constructor, which will set the corresponding ivars.

It is easily used:

Class Foo
  constructor :a, :b, :c, :d, :e, :accessors => true
end

foo = Foo.new(:a => 'hello world', :b => 'b',:c => 'c', :d => 'd', :e => 'e')
puts foo.a # 'hello world'

If you don't want the ivars generated with accessors, you can leave off the :accessors => true

Hope this helps /Salernost

salernost
  • 428
  • 1
  • 3
  • 6
1
class Module
  def initialize_with( *names )
    define_method :initialize do |*args|
      names.zip(args).each do |name,val|
        instance_variable_set :"@#{name}", val
      end
    end
  end
end
fl00r
  • 82,987
  • 33
  • 217
  • 237
Phrogz
  • 296,393
  • 112
  • 651
  • 745
  • 1
    This is pretty nice, except it will skip the normal `initialize` argument checking: `initialize_with :a, :b` + `Foo.new(1,2,3,4,5)` will produce no error. – Casper Apr 30 '12 at 14:48
-1
class Foo
  class InvalidAttrbute < StandardError; end

  ACCESSORS = [:a, :b, :c, :d, :e]
  ACCESSORS.each{ |atr| attr_accessor atr }

  def initialize(args)
    args.each do |atr, val|
      raise InvalidAttrbute, "Invalid attribute for Foo class: #{atr}" unless ACCESSORS.include? atr
      instance_variable_set("@#{atr}", val)
    end
  end
end

foo = Foo.new(a: 1)
puts foo.a
#=> 1

foo = Foo.new(invalid: 1)
#=> Exception
fl00r
  • 82,987
  • 33
  • 217
  • 237