简体   繁体   中英

Assign class variables in a do block with ruby?

I'm having a problem in ruby and I can't seem to find the solution even though I know it's somehow possible. I have a class and I want to assign some variables to it in a do block like so:

tester = Person.new
tester do
    :name => 'Andy'
    :example => 'Example'
end

puts "#{tester.name}:#{tester.example}" #Should output 'Andy:Example'

Has anyone got any ideas? I apologise for my terrible way of explaining. I'm new to Ruby :)

There's the good old yield self idiom for that too:

class Person 
  attr_accessor :name, :example

  def initialize 
    yield self if block_given?
  end
end

tester = Person.new do |p|
  p.name = 'Andy'
  p.example = 'Example'
end

puts "#{tester.name}:#{tester.example}" 

You can't do it in Ruby this way. You should specify reciever

tester = Person.new
tester.name = "Andy"
tester.example = "Example"

PS

Here is related topic:

In Ruby, is there a way to accomplish what `with` does in Actionscript?

It may be set like this:

tester = Person.new.tap do |person|
person.name = 'John'
end

It is not possible to call a method whose name ends in = without a receiver, because doing so will create a new local variable . I suggest allowing new values to be passed to your reader methods:

class Person
  def initialize(&block)
    if block.arity.zero? then instance_eval &block
    else block.call self end
  end

  def name(new_name = nil)
    @name = new_name unless new_name.nil?
    @name
  end
end

Now you can write:

Person.new do
  name 'Andy'
end

The only drawback to this approach is that it is impossible to set the attribute back to nil , so consider providing a conventional writer method as well.

do is refers to the object yielded from an iteration, which doesn't allow you to write code as above. I'd suggest a different approach:

class Person
    attr_accessor :name, :example

    def assign(props = {})
        props.each{|prop, value| self.send("#{prop.to_s}=", value)}
        self
    end
end

x = Person.new
x.assign :name => "test", :example => "test_example"
=> #<Person:0x27a4760 @name="test", @example="test_example">

@fl00r's suggestion is right or you may do it this way which is most similar to him:

tester = Person.new
tester[:name] = "Andy"
tester[:example] = "Example"

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM