tags:

views:

247

answers:

4

In ruby, I often find myself writing the following:

class Foo
  def initialize(bar, baz)
    @bar = bar
    @baz = baz
  end

  << more stuff >>

end

or even

class Foo
  attr_accessor :bar, :baz

  def initialize(bar, baz)
    @bar = bar
    @baz = baz
  end

  << more stuff >>

end

I'm always keen to minimise boilerplate as much as possible - so is there a more idiomatic way of creating objects in ruby?

+4  A: 

One option is that you can inherit your class definition from Struct:

class Foo < Struct.new(:bar, :baz)
  # << more stuff >>
end

f = Foo.new("bar value","baz value")
f.bar #=> "bar value"
f.baz #=> "baz value"
Raimonds Simanovskis
Instead of subclassing you can also do `Foo = Struct.new(:bar, :baz) do ... end`
sepp2k
Can you provide an example, sepp2k?
Geo
Interesting... but what if you want Foo to subclass something else?
grifaton
It's worth noting that a Struct isn't exactly same as just a bunch of macros that do all the boilerplate class stuff for you.
Benjamin Oakes
A: 

You could use an object as param.

class Foo
  attr_accessor :param

  def initialize(p)
    @param = p
  end
end

f = Foo.new
f.param.bar = 1
f.param.bax = 2

This does not save much lines in this case but it will if your class has to handle a large number of param. You could also implement a set_param and get_param method if you want to keep your @param var private.

XPac27
+1  A: 

Struct

Struct object's are classes which do almost what you want. The only difference is, the initialize method has nil as default value for all it's arguments. You use it like this

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

or

class A < Struc.new(:a, :b, :c)
end

Struct has one big drawback. You can not inherit from another class.

Write your own attribute specifier

You could write your own method to specify attributes

def attributes(*attr)
  self.class_eval do
    attr.each { |a| attr_accessor a }
    class_variable_set(:@@attributes, attr)

      def self.get_attributes
        class_variable_get(:@@attributes)
      end

      def initialize(*vars)
        attr= self.class.get_attributes
        raise ArgumentError unless vars.size == attr.size
        attr.each_with_index { |a, ind| send(:"#{a}=", vars[ind]) }
        super()
      end
  end
end

class A
end

class B < A
  attributes :a, :b, :c
end

Now your class can inherit from other classes. The only drawback here is, you can not get the number of arguments for initialize. This is the same for Struct.

B.method(:initialize).arity # => -1
johannes
A: 

I sometimes do

@bar, @baz = bar, baz

Still boilerplate, but it only takes up one line.

I guess you could also do

["bar", "baz"].each {|variable_name| eval("@#{variable_name} = variable_name")}

(I'm sure there's a less dangerous way to do that, mind you)

Andrew Grimm