-1

I've got a class just like this:

class Equipment

    attr_reader :text
    attr_reader :name
    attr_reader :array1
    attr_reader :number

end

then, I want to make 2 constructors with 3 parameters each:

1º one -> (text,name,array1)

2º one -> (text, name,number)

The first one as an argument has an array and the other one has an integer (1,2...), so I need to define both constructors so when I create an object of this class it makes a difference between array or integer as the 3º argument.

Any ideas?

EDIT.: I thought this:

def initialize(text = "", name = "", array = array.new, number =0)

    @text = text
    @name = name
    @array1 = array
    @number = number

end

(initializing all of them) then:

def Equipment.newc_witharray(sometext, somename, somearray)

    @text = sometext
    @name = somename
    @array1 = somearray

end

def Equipment.newc_withint(sometext, somename, somenumber)

    @text = text
    @name = name
    @number = somenumber

end

and finally calling objects like this:

character1 = Equipment.newc_withint("Barbarian", "conan", 3)

shouldn't this work?

BenMorel
  • 34,448
  • 50
  • 182
  • 322
Zasito
  • 281
  • 1
  • 7
  • 17

4 Answers4

3

You can create as many constructors as you want on the class with whatever name you want. There is one constructor new, which is inherited from Object, and that can be used to write other constructors. What other answers mention as the constructor, namely the instance method initialize is not a constructor. That is the method called by the constructor method new by default.

class Foo
  def self.new1 text, name, array1
    obj = new
    # do something on obj with text, name, array1
    obj
  end
  def self.new2 text, name, number
    obj = new
    # do something on obj with text, name, number
    obj
  end
end

Foo.new1(text, name, array1)
Foo.new2(text, name, number)
sawa
  • 165,429
  • 45
  • 277
  • 381
  • I don't understand what to do with this line: obj = new – Zasito Oct 16 '13 at 21:04
  • Nothing to add to `obj = new`. And do instance variable assignments in the context of `obj` after that. – sawa Oct 16 '13 at 21:06
  • Aren't neccesary parenthesis in def self.new1 (yadda, yadda,...)? – Zasito Oct 16 '13 at 21:11
  • Although I think Ruby can do better than this, perhaps now rename these methods to something more descriptive like `from_number` and `from_array`. – zwippie Oct 16 '13 at 21:22
  • `konstructor` gem allows to add extra constructors to the class with one word declarations – snovity Jan 26 '17 at 07:18
1

There are various ways to achieve this.

Hash arguments

You could pass a hash and extract the values you're interested in:

def initialize(options={})
  @text = options.fetch(:text)        # raises KeyError if :text is missing
  @name = options.fetch(:name)        # raises KeyError if :name is missing
  @array = options.fetch(:array, [])  # returns [] if :array is missing
  @number = options.fetch(:number, 0) # returns 0 if :number is missing
end

Keyword arguments

In Ruby 2.0 you can use keyword arguments with default values:

def initialize(text: text, name: name, array: [], number: 0)
  @text = text
  @name = name
  @array = array
  @number = number
end

Switching on argument type

This makes the method harder to read, but would work, too:

def initialize(text, name, number_or_array)
  @text = text
  @name = name
  @number = 0
  @array = []
  case number_or_array
  when Integer then @number = number_or_array
  when Array then @array = number_or_array
  else
    raise TypeError, "number_or_array must be a number or an array"
  end
end
Stefan
  • 109,145
  • 14
  • 143
  • 218
0

Built into the language, no, Ruby does not give you that ability.

However, if you want that ability, I would create an initialize method which takes a hash as its parameter. Then you could create an instance of the class using any number of parameters.

E.g:

class Equipment
  attr_reader :text, :name, :array1, :number

  def initialize(options)
    [:text, :name, :array1, :number].each do |sym|
      self.send(sym) = options[sum]
    end
  end
end
David Weiser
  • 5,190
  • 4
  • 28
  • 35
0

The ruby interpreter wouldn't be able to differentiate between the constructors, as the types are not known until runtime :(

However, you can use a very nice workaround:

class Foobar
  def initialize(h)  # <-- h is a hash
    # pass combination of params into the hash, do what you like with them
  end
end

and then, using this pattern, you can pass any combination of params into the constructor:

foobar = Foobar.new(:foo => '5', :bar => 10, :baz => 'what?')
yamafontes
  • 5,552
  • 1
  • 18
  • 18