How Can One Set Property Values When Initializing an Object in Ruby

Initializing attributes in Ruby objects

You want to use instance variables inside an instance of a class to define attributes, not a local variable. local variables will go out of scope as soon as the method is finished executing. the code below should be more along the lines of what you need:

module Test
class Spam
attr_accessor :hooray, :name

def initialize
@hooray = []
@name = "Whammy"
end
end
end

Ruby class initialization

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

How to cleanly initialize attributes in Ruby with new?

def initialize(params)
params.each do |key, value|
instance_variable_set("@#{key}", value)
end
end

What is the most efficient way to initialize a Class in Ruby with different parameters and default values?

The typical way to solve this problem is with a hash that has a default value. Ruby has a nice syntax for passing hash values, if the hash is the last parameter to a method.

class Fruit
attr_accessor :color, :type

def initialize(params = {})
@color = params.fetch(:color, 'green')
@type = params.fetch(:type, 'pear')
end

def to_s
"#{color} #{type}"
end
end

puts(Fruit.new) # prints: green pear
puts(Fruit.new(:color => 'red', :type => 'grape')) # prints: red grape
puts(Fruit.new(:type => 'pomegranate')) # prints: green pomegranate

A good overview is here: http://deepfall.blogspot.com/2008/08/named-parameters-in-ruby.html

Initialize an object using a block instead of constructor arguments

It's actually really easy to add this functionality to most classes provided they already have attr_writer and/or attr_accessor in place:

class Grammar
attr_accessor :rules, :start, ...

def initialize(rules, start)
@rules = rules
@start = start
...

yield self if block_given?
end
end

Where you can now do exactly what you wanted. The yield self part will supply the object being initialized to the block, and block_given? is only true if you've supplied a block to the new call. You'll want to run this after setting all your defaults.

Initialize an object with a block

Of course, you can yield from within initialize, there's nothing special about it:

class Foo
attr_accessor :bar, :baz
def initialize
yield self
end
end

Foo.new do |f|
f.bar = 123
f.baz = 456
end
#=> <Foo:0x007fed8287b3c0 @bar=123, @baz=456>

You could also evaluate the block in the context of the receiver using instance_eval:

class Foo
attr_accessor :bar, :baz
def initialize(&block)
instance_eval(&block)
end
end

Foo.new do
@bar = 123
@baz = 456
end
#=> #<Foo:0x007fdd0b1ef4c0 @bar=123, @baz=456>

Initialize class object variable in Ruby

In Ruby, @@ before a variable means it's a class variable. What you need is the single @ before the variable to create an instance variable. When you do Result.new(..), you are creating an instance of the class Result.

You don't need to create default values like this:

@@min = 0
@@max = 0

You can do it in the initialize method

def initialize(min = 0, max = 0)

This will initialize min and max to be zero if no values are passed in.

So now, your initialize method should like something like

def initialize(min=0, max=0)
@min = min
@max = max
end

Now, if you want to be able to call .min or .max methods on the instance of the class, you need to create those methods (called setters and getters)

def min # getter method
@min
end

def min=(val) # setter method
@min = val
end

Now, you can do this:

result.min     #=> 1
result.min = 5 #=> 5

Ruby has shortcuts for these setters and getters:

  • attr_accessor: creates the setter and getter methods.
  • attr_reader: create the getter method.
  • attr_writer: create the setter method.

To use those, you just need to do attr_accessor :min. This will create both methods for min, so you can call and set min values directly via the instance object.

Now, you code should look like this

class Result
attr_accessor :min, :max
def initialize(min=0, max=0)
@min = min
@max = max
end
end

result = Result.new(1, 10)
result.max #=> 10

Rails: Initializing attributes that are dependent on one another

Oh jeeezzzz... this is insanely simple, now that I puzzled on it a little more. I just need to override the "initialize(attributes = {})" method on the PropertyValue class like so:

def initialize(attributes = {})
property = Property.find(attributes[:property_id]) unless attributes[:property_id].blank?
super(attributes)
end

Now I'm always sure that the property association is filled before the other attributes are set. I just didn't realize soon enough that Rails' "build(attributes = {})" and "create(attributes = {})" operations eventually boil down to "new(attributes = {})".



Related Topics



Leave a reply



Submit