3

I want to create an object that can be initialized in two different ways. I found 3 different way's of accomplishing the same thing, I want to know which of my methods is the best one, and if there is another better way of doing it.

Method

attr_accessor :id, :status, :dateTime
  def initialize *args
    if args.length == 1
      puts args[0]
    @id = args[0]['id']
    @status = args[0]['status']
    @dateTime = args[0]['dateTime']
    else
      @id = args[0]
      @status = args[1]
      @dateTime = args[2]
    end
  end

Method 2: (note that I need to set the parameters by hand on this one as second way)

  attr_accessor :id, :status, :dateTime
  def initialize hash = nil
    if hash != nil
    @id = hash['id']
      @status = hash['status']
      @dateTime = hash['dateTime']
    end
  end

Method 3: (note that I need to set the parameters by hand on this one as second way AND that it is almost the same as my second way, just not in the constructor)

attr_accessor :id, :status, :dateTime
  def initialize
  end

  def self.create hash
    if hash != nil
      obj = Obj3.new
      obj.id = hash['id']
      obj.status = hash['status']
      obj.dateTime = hash['dateTime']
      return obj
    end
  end

Thanks in advance!

4
  • What arguments do they take? Commented Mar 23, 2016 at 11:37
  • Method 2: (note that I need to set the parameters by hand on this one as second way) Isn't it evident that the second method/way follows the second way? Commented Mar 23, 2016 at 11:39
  • @sawa Maybe I needed to be more clear. It takes a hash with id, status and dateTime OR I could initialize an object without parameters and say object.id = "an id" etc. Commented Mar 23, 2016 at 12:08
  • Have a look at Keyword arguments Commented Mar 23, 2016 at 14:46

1 Answer 1

5

I would try using a hash for your constructor like the code below adapted from DRY Ruby Initialization with Hash Argument

class Example
  attr_accessor :id, :status, :dateTime

  def initialize args
    args.each do |k,v|
      instance_variable_set("@#{k}", v) unless v.nil?
    end
  end
end

That way setting each of your properties in the constructor becomes optional. As the instance_variable_set method will set each property if the has contains a value for it.

Which means you could support any number of ways to construct your object. The only downside is you might have to do more nil checking in your code but without more information it is hard to know.

Creating a new Object - Usage Examples

To create a new object with this technique all you need to do is pass in a hash to your initialiser:

my_new_example = Example.new :id => 1, :status => 'live'
#=> #<Example: @id=1, @status='live'>

And its flexible enough to create multiple objects without certain properties with one constructor:

my_second_new_example = Example.new :id => 1
#=> #<Example: @id=1>

my_third_new_example = Example.new :status => 'nonlive', :dateTime => DateTime.new(2001,2,3)
#=> #<Example: @id=1, @dateTime=2001-02-03T00:00:00+00:00>

You can still update your properties once the objects have been created:

my_new_example.id = 24
Sign up to request clarification or add additional context in comments.

7 Comments

But now I need to be able to set the values via hash or via interaction with the object, like initializing an object as obj = Example.new; obj.id = "an id"
Not quite - I will update the answer with some usage examples.
So if I understand correctly, I can initialize the object with any amount of parameters, the ones that are not given will be left nil, and I can set them at a later time? Also if I understand it correctly I can say my_new_example = Example.new my_new_example.id = 23
For your first point. Yes as long as your define your properties (using attr_accessor in the examples so far) then you initialise your object with a hash. The key is the name of your param and the value the value to set it to. If your hash does not contain a key / value for a property that property will be nil. Your second point. Yes you can do that as long as the my_new_example.id = 23 is on a new line!
@FalingDutchman you could also just use the OpenStruct Class which will allow you to initialize with values but also set arbitrary ones after the fact. That being said if you want to use this i would recommend adding attr_accessor to the initialize block e.g. self.class_eval { attr_accessor k} inside the args loop this will create getter/setter methods for each of those attributes.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.