0

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 :)

6 Answers 6

4

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}" 
Sign up to request clarification or add additional context in comments.

5 Comments

+1. yield self if block_given? :). Anyway this is not the way Ruby works. Actionscript has got its with method wich allows to work, you know, "in context" of its object. And you can't do this kind of job in Ruby.
Sure, but this is the way I see most often to achieve more or less the same. Besides with should be fairly easy to implement too :-)
I believe almost everything can be implemented with eval ;)
Also without eval it's really trivial: gist.github.com/2146609 Of course having to use the self receiver is a bit ugly, but I don't have time to hack around that at the moment.
Funny, I just saw something similar is implemented in Facets, but without returning the object.
2

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?

1 Comment

Well, there's something similar to what OP wants, with the yield self idiom that gemspec files or Rake uses. See my answer :-)
1

It may be set like this:

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

Comments

1

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.

Comments

0

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">

Comments

-1

@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"

1 Comment

-1, this isn't even valid Ruby. Unless the Person class specifies a []= method, you'll get a NoMethodError.

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.