1

I see this popping up all the time in my code

class Foo
  def initialize(foo)
    @foo = foo
  end
  #...
end

This isn't too bad, but it gets worse:

class Foo
  def initialize(foo,baz,bar,a,b,c,d)
    @foo = foo
    @baz = baz
    @bar = bar
    #etc...

You can sortof get around this by doing something like

@foo, @baz, @bar = foo, baz, bar

But even that feels wrong and is annoying to type. Is there a better way to define instance variables according to arguments?

Edit: There seem to be 2 distinct solutions to this problem. See:

Shelvacu
  • 4,245
  • 25
  • 44

5 Answers5

7

You might want to consider using a Struct:

class Foo < Struct.new(foo,baz,bar,a,b,c,d)
end

foo = Foo.new(1,2,3,4,5,6,7)
foo.bar #=> 2

No need to define an extra initialize method at all...

spickermann
  • 100,941
  • 9
  • 101
  • 131
3
def initialize args
  @foo, @baz, @bar = *args
end
Antarr Byrd
  • 24,863
  • 33
  • 100
  • 188
3

Yes, that's the preferred way to initialize instance variables in Ruby. It can be annoying to type, but it's a well understood pattern. As always in Ruby, using metaprogramming to automate it away is possible, but will make your code harder to follow.

I'd also argue that it's probably a good thing for a class to look ugly when it's taking more than two or three arguments. If your class depends on six different things to function, it's a strong candidate for refactoring.

Tobias Cohen
  • 19,893
  • 7
  • 54
  • 51
0

I think there are 3 ways to make initialization of instance variables shorter:

  1. Use Struct or OpenStruct.
  2. Use ruby's parallel assignment.
  3. Use metaprogramming to make a macro like this.
media-slave24
  • 256
  • 2
  • 7
0

The fattr gem was recently endorsed on Ruby Tapas to help solve this problem. Another consideration though, is whether there are too many things being passed into the initializer. It could be that this class is doing too much and needs to be broken into smaller pieces.

DGM
  • 26,629
  • 7
  • 58
  • 79