attr_writers within blocks

Discussion in 'Ruby' started by Wijnand Wiersma, Jun 29, 2009.

  1. Hi all,

    It seems writer methods don't work within blocks, the names are
    resolved to new local variable names I guess.
    It is funny however the reader method does seem to work fine.
    Is it possible to make it work anyway without changing the syntax
    within the block?

    My example gist: http://gist.github.com/137741

    Kind regards,
    Wijnand
     
    Wijnand Wiersma, Jun 29, 2009
    #1
    1. Advertisements

  2. Hi,

    Am Dienstag, 30. Jun 2009, 03:44:48 +0900 schrieb Wijnand Wiersma:
    You don't even need an instance_eval. It won't work in a module
    definition either:

    module M
    class <<self
    def x= val
    puts "Hi, here is C.x=(#{val.inspect})."
    @x = val
    end
    end
    @x = "X0"
    x = "X1"
    self.x = "X2"
    end

    Maybe you prefer the self.-construction. I surely don't.

    Bertram
     
    Bertram Scharpf, Jun 29, 2009
    #2
    1. Advertisements

  3. Wijnand Wiersma

    Mike Sassak Guest

    [Note: parts of this message were removed to make it a legal post.]

    You can override the getter method for a DSL-ish syntax:

    class Foo
    attr_accessor :bar

    def initialize(&block)
    instance_eval(&block)
    end

    def bar(v=nil)
    v ? @bar = v : @bar
    end
    end

    f = Foo.new { bar 2 }
    f.bar # => 2
    f.bar 3
    f.bar # => 3
    f.bar = 4
    f.bar # => 4

    HTH
    Mike
     
    Mike Sassak, Jun 29, 2009
    #3
  4. Hi --

    It's not a block thing. Writer methods always need an explicit
    receiver. You always have to write:

    obj.x = y

    because the parser always sees this:

    x = y

    as a local variable assignment, even if there's a method around called
    x=.


    David

    --
    David A. Black / Ruby Power and Light, LLC
    Ruby/Rails consulting & training: http://www.rubypal.com
    Now available: The Well-Grounded Rubyist (http://manning.com/black2)
    "Ruby 1.9: What You Need To Know" Envycasts with David A. Black
    http://www.envycasts.com
     
    David A. Black, Jun 29, 2009
    #4
  5. Thank you for your answers, I was too block focussed to see the
    obvious real reason.

    Kind regards,
    Wijnand
     
    Wijnand Wiersma, Jun 29, 2009
    #5
  6. Hi,

    Am Dienstag, 30. Jun 2009, 04:37:55 +0900 schrieb Mike Sassak:
    Sorry, but I cannot leave this as it is (untested):

    def set_bar v = nil
    @bar ||= v
    end

    Bertram
     
    Bertram Scharpf, Jun 30, 2009
    #6
  7. Well, on that note... After using metaid, I hate the class << self
    construction.

    module M
    meta_eval do
    def x= val
    ...
    end
    end
    ...
    end

    For what it's worth, attr_accessor does work inside meta_eval.
     
    David Masover, Jun 30, 2009
    #7
  8. [Note: parts of this message were removed to make it a legal post.]

    I can only recommend this thread: http://www.ruby-forum.com/topic/190337
    We had a nice discussion there on those kind of DSLish attr setters and
    what would be the best way to implement them

    Greetz,
    k

    P.S: metaid rocks!
     
    Fabian Streitel, Jun 30, 2009
    #8
  9. Hi --

    That only sets @bar if @bar hasn't be set (to a true value) already.

    class C
    attr_reader :bar
    def set_bar(v = nil)
    @bar ||= v
    end
    end

    c = C.new
    c.set_bar(3)
    puts c.bar # 3

    c.set_bar(4)
    puts c.bar # 3


    David

    --
    David A. Black / Ruby Power and Light, LLC
    Ruby/Rails consulting & training: http://www.rubypal.com
    Now available: The Well-Grounded Rubyist (http://manning.com/black2)
    "Ruby 1.9: What You Need To Know" Envycasts with David A. Black
    http://www.envycasts.com
     
    David A. Black, Jun 30, 2009
    #9
  10. Hi --

    Assuming your DSL depends on the lack of equal-signs :) There's
    nothing inherent in the concept of a DSL that disallows =-terminated
    methods or explicit receivers.
    No point defining #bar if you don't want it -- just use attr_writer.
    That won't allow you to (re)set @bar to nil or false, though. You
    might want something like:

    def bar(*v)
    unless v.empty?
    @bar, = v
    end
    @bar
    end


    David

    --
    David A. Black / Ruby Power and Light, LLC
    Ruby/Rails consulting & training: http://www.rubypal.com
    Now available: The Well-Grounded Rubyist (http://manning.com/black2)
    "Ruby 1.9: What You Need To Know" Envycasts with David A. Black
    http://www.envycasts.com
     
    David A. Black, Jun 30, 2009
    #10
  11. Wijnand Wiersma

    Mike Sassak Guest

    [Note: parts of this message were removed to make it a legal post.]

    Hi David,

    Of course! I was thinking of ActiveRecord's macro method syntax--not the
    most apropos when the original question was about variable assignment, I
    know. :)

    Ahh, yes. Thanks for pointing that out. I was really more concerned at the
    time with giving an (admittedly idiosyncratic) example of assignment without
    an explicit receiver as food for the OP's thought. I'd never thought to use
    @bar, = v in order to grab only the first element of an array though. Cool!

    Thanks again,
    Mike
     
    Mike Sassak, Jun 30, 2009
    #11
  12. Hi,

    Am Dienstag, 30. Jun 2009, 20:48:33 +0900 schrieb David A. Black:
    You're right. Sorry!

    Bertram
     
    Bertram Scharpf, Jun 30, 2009
    #12
  13. Op 30 jun 2009, om 09:29 heeft Fabian Streitel het volgende geschreven:
    I actually like one of the proposed ways in that topic.
    Using a method that is both getter and setter.
    I decided to create a attr_accessor_special like this:
    def attr_accessor_special(*syms)
    syms.each do | sym |
    name=sym.to_s
    send:)define_method, name) do | *args |
    value = args[0]
    self.instance_variable_set("@#{name}", value) if value
    self.instance_variable_get("@#{name}")
    end
    end
    end

    No way to make a value nil again but I don't think that will be needed
    in my case.

    Thank you for your replies!

    Kind regards,
    Wijnand
     
    Wijnand Wiersma, Jul 1, 2009
    #13
  14. Hi --

    You could test to see whether args is empty (see my earlier post).


    David

    --
    David A. Black / Ruby Power and Light, LLC
    Ruby/Rails consulting & training: http://www.rubypal.com
    Now available: The Well-Grounded Rubyist (http://manning.com/black2)
    "Ruby 1.9: What You Need To Know" Envycasts with David A. Black
    http://www.envycasts.com
     
    David A. Black, Jul 1, 2009
    #14
    1. Advertisements

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.