Having a block executed in the context of an instance

Discussion in 'Ruby' started by Mike Austin, Mar 8, 2006.

  1. Mike Austin

    Mike Austin Guest

    I'm writing a property driven ui and would like to do things like:

    button = Button.new do
    caption = 'Click Me'
    end

    I've read that 2.0 will have this feature, i.e. Class.new will execute it's
    block argument in it's own context. But how do I do it in 1.8?

    Thanks much,
    Mike
    Mike Austin, Mar 8, 2006
    #1
    1. Advertising

  2. Mike Austin

    Guest

    On Wed, 8 Mar 2006, Mike Austin wrote:

    > I'm writing a property driven ui and would like to do things like:
    >
    > button = Button.new do
    > caption = 'Click Me'
    > end
    >
    > I've read that 2.0 will have this feature, i.e. Class.new will execute it's
    > block argument in it's own context. But how do I do it in 1.8?
    >
    > Thanks much,
    > Mike


    class Button
    def initialize(*args, &block)
    instance_eval &block
    end
    end

    note that you'll need to do

    self.caption = 'Click Me'

    or else caption will be a local variable. for an elegant work around see the
    metakoan quiz or my traits library. with it a really nice syntax like this is
    possible

    button = Button.new {
    caption 'Click Me'
    colour 'Orange'
    size '42'
    }

    here's a real example from something i'm coding now:


    class Flo5 < NRT::OLSSubscription::Geotiffed
    mode "production"

    roi 47,16,39,27

    satellites %w( F15 F16 )

    extensions %w( OIS )

    solarelevations -180, -12, 10.0

    hold 0

    username "flo"

    password "xxx"

    orbital_start_direction "descending"

    start_time "2004-12-08"
    end_time "2006-12-08"

    to_keep [ %r/.tif$/, %r/.hdr$/ ]

    tmpwatch "8 days"
    end


    hth.


    -a

    --
    judge your success by what you had to give up in order to get it.
    - h.h. the 14th dali lama
    , Mar 8, 2006
    #2
    1. Advertising

  3. Mike Austin

    Mike Austin Guest

    wrote:
    > On Wed, 8 Mar 2006, Mike Austin wrote:
    >
    >> I'm writing a property driven ui and would like to do things like:
    >>
    >> button = Button.new do
    >> caption = 'Click Me'
    >> end
    >>
    >> I've read that 2.0 will have this feature, i.e. Class.new will execute
    >> it's block argument in it's own context. But how do I do it in 1.8?
    >>
    >> Thanks much,
    >> Mike

    >
    > class Button
    > def initialize(*args, &block)
    > instance_eval &block
    > end
    > end
    >
    > note that you'll need to do
    >
    > self.caption = 'Click Me'


    Thanks, that works well. But as you note, prepending 'self' kind of defeats
    the purpose ;) Is there a way to make Ruby not create local variables, but use
    'local var' or similar? Io (www.iolanguage.com) has this problem early on
    and was solved by using := for creating slots, and = for updating slots. It
    would be nice if it could be lenient when running in irb, and more strict when
    executing .rb files.

    > or else caption will be a local variable. for an elegant work around
    > see the
    > metakoan quiz or my traits library. with it a really nice syntax like
    > this is
    > possible


    Metakoan quiz didn't turn up anything. I looked at your traits library and it
    looks nice. I could use an operator instead of '=' I suppose.

    > button = Button.new {
    > caption 'Click Me'
    > colour 'Orange'
    > size '42'
    > }
    >
    > here's a real example from something i'm coding now:
    >
    >
    > class Flo5 < NRT::OLSSubscription::Geotiffed
    > mode "production"
    >
    > roi 47,16,39,27
    >
    > satellites %w( F15 F16 )
    >
    > extensions %w( OIS )
    >
    > solarelevations -180, -12, 10.0
    >
    > hold 0
    >
    > username "flo"
    >
    > password "xxx"
    >
    > orbital_start_direction "descending"
    >
    > start_time "2004-12-08"
    > end_time "2006-12-08"
    >
    > to_keep [ %r/.tif$/, %r/.hdr$/ ]
    >
    > tmpwatch "8 days"
    > end
    >
    >
    > hth.
    >
    >
    > -a


    Mike
    Mike Austin, Mar 8, 2006
    #3
  4. > button = Button.new do
    > caption = 'Click Me'
    > end


    Executing a block in another context isn't very readable. Ara's
    example is not the same as your situation. His situation is an
    example of a DSL, whereas your situation is just plain Ruby.
    So, IMHO, it should be coded in just plain Ruby:

    class Button
    def initialize
    yield(self)
    end
    end

    button = Button.new do |b|
    b.caption = 'Click Me'
    end

    Now it's obvious (by reading, not by knowing) what the block
    does.

    gegroet,
    Erik V. - http://www.erikveen.dds.nl/
    Erik Veenstra, Mar 8, 2006
    #4
  5. Mike Austin wrote:
    > Thanks, that works well. But as you note, prepending 'self' kind of
    > defeats the purpose ;) Is there a way to make Ruby not create local
    > variables, but use 'local var' or similar?


    No, there isn't. However, often using a hash as argument solves this
    problem:

    class Foo
    def initialize(h={})
    h.each {|var,val| send("#{var}=", val)}
    end
    end

    Foo.new(
    :caption => 'Click me',
    :color => :eek:range,
    :size => 42
    )

    With a bit more code you can even have default values.

    Kind regards

    robert
    Robert Klemme, Mar 8, 2006
    #5
  6. In my opinion, this is unneccesary and still a bit confusing unless the
    object has a limited lifetime (as in the case of IO resources) or will
    change state when the block is ended. You could use:

    button = Button.new
    button.caption = 'Click Me'

    Blocks are good for DSLs or management of _limited_ resources. It is a
    bad idea to use the new method to provide a limited resource as this
    will impair forward-compatability. A different method should be used
    (and new possibly made private) to enable future change.

    For button management I would use something along the lines of the DSL
    outlined above but would use additional blocks in the same scope to
    handle events.

    button = Button.new do
    caption "Click Me" # Public method, button.caption and
    button.caption= useable from outside

    on_click do
    caption "You Clicked Me!" # Can update attributes in response to
    events with very little extra work.
    end
    end
    Timothy Goddard, Mar 8, 2006
    #6
  7. Mike Austin

    Guest

    Hi --

    On Wed, 8 Mar 2006, itsme213 wrote:

    >
    > "Mike Austin" <> wrote
    >
    >> Thanks, that works well. But as you note, prepending 'self' kind of
    >> defeats the purpose ;) Is there a way to make Ruby not create local
    >> variables, but use 'local var' or similar? Io (www.iolanguage.com) has
    >> this problem early on and was solved by using := for creating slots, and =
    >> for updating slots.

    >
    > I personally would like some such distinction. I don't having to use
    > "self.att=" since
    > (a) one does not use self.method(..) in general
    > (b) self.method(..) has different privacy rules
    > (c) self.attr= is an exception to both (a) and (b)
    >
    > Ara's
    > attr(new_val)
    > works, but
    > (a) does not read like a setter, and
    > (b) is against the standard Ruby family of attr.. methods
    >
    > I wouldn't hold my breath for := or equivalent :)


    I have to say, I've been wondering for many years... is self.x = 1
    really *that* bad? It just seems like such a minor thing to me. I
    certainly wouldn't want to see new punctuation introduced just to
    avoid it.


    David

    --
    David A. Black ()
    Ruby Power and Light, LLC (http://www.rubypowerandlight.com)

    "Ruby for Rails" chapters now available
    from Manning Early Access Program! http://www.manning.com/books/black
    , Mar 8, 2006
    #7
  8. Mike Austin

    Guest

    wrote:

    > I have to say, I've been wondering for many years... is self.x = 1
    > really *that* bad? It just seems like such a minor thing to me. I
    > certainly wouldn't want to see new punctuation introduced just to
    > avoid it.


    +1
    , Mar 8, 2006
    #8
  9. Mike Austin

    Guest

    On Mar 8, 2006, at 9:56 AM, wrote:
    > I have to say, I've been wondering for many years... is self.x = 1
    > really *that* bad? It just seems like such a minor thing to me. I
    > certainly wouldn't want to see new punctuation introduced just to
    > avoid it.


    It isn't *that* bad but it stands out since the rest of Ruby is
    *that* good!

    I think it is the old battle between 'perfect' and 'good enough'.

    Gary Wright
    , Mar 8, 2006
    #9
  10. Mike Austin

    Mike Austin Guest

    wrote:
    > wrote:
    >
    >> I have to say, I've been wondering for many years... is self.x = 1
    >> really *that* bad? It just seems like such a minor thing to me. I
    >> certainly wouldn't want to see new punctuation introduced just to
    >> avoid it.

    >
    > +1


    It may be a minor syntax thing, but I think it creates unnecessary ambiguity.
    If there is a method called caption=(), I expect it to use that. I don't write
    'self' anywhere else in Ruby, so it just seems odd. Plus is helps reduce hard
    to debug locals creation by misspellings.

    class Button
    attr :caption, true

    def initialize(*args, &block)
    instance_eval &block
    end
    end

    button = Button.new do
    var :x
    caption = 'Click Me'
    end

    There is already 'attr' for classes, why not 'local' or 'var' for methods? One
    issue is that you can't assign and declare on the same line. It could be done
    with a hash but that might look funny?

    Take this all with a grain of salt. I'm always looking for different ways of
    doing things. I.e. to find good ideas you have to find bad ideas ;)


    Mike
    Mike Austin, Mar 8, 2006
    #10
  11. Mike Austin

    Guest

    Hi --

    On Thu, 9 Mar 2006, Mike Austin wrote:

    > wrote:
    >> wrote:
    >>
    >>> I have to say, I've been wondering for many years... is self.x = 1
    >>> really *that* bad? It just seems like such a minor thing to me. I
    >>> certainly wouldn't want to see new punctuation introduced just to
    >>> avoid it.

    >>
    >> +1

    >
    > It may be a minor syntax thing, but I think it creates unnecessary ambiguity.
    > If there is a method called caption=(), I expect it to use that. I don't
    > write 'self' anywhere else in Ruby, so it just seems odd. Plus is helps
    > reduce hard to debug locals creation by misspellings.


    You can look at it the other way around, though: you *always* specify
    a receiver explicitly in Ruby, except in the one case where the
    receiver is self and the syntax is such as to be unambiguously a
    method call.

    > class Button
    > attr :caption, true
    >
    > def initialize(*args, &block)
    > instance_eval &block
    > end
    > end
    >
    > button = Button.new do
    > var :x
    > caption = 'Click Me'
    > end
    >
    > There is already 'attr' for classes, why not 'local' or 'var' for methods?


    I'm not seeing the connection between the two halves of that sentence
    :) I don't think the existence of the attr_* methods implies that
    Ruby should adopt a system of variable declaration. (At least, I
    don't see how one follows from the other.) But I'm not sure I'm
    understanding you correctly.


    David

    --
    David A. Black ()
    Ruby Power and Light, LLC (http://www.rubypowerandlight.com)

    "Ruby for Rails" chapters now available
    from Manning Early Access Program! http://www.manning.com/books/black
    , Mar 8, 2006
    #11
  12. ------=_Part_13346_20782533.1141836529188
    Content-Type: text/plain; charset=ISO-8859-1
    Content-Transfer-Encoding: quoted-printable
    Content-Disposition: inline

    On 3/8/06, Mike Austin <> wrote:
    >
    > wrote:
    > > wrote:
    > >
    > >> I have to say, I've been wondering for many years... is self.x =3D 1
    > >> really *that* bad? It just seems like such a minor thing to me. I
    > >> certainly wouldn't want to see new punctuation introduced just to
    > >> avoid it.

    > >
    > > +1

    >
    > It may be a minor syntax thing, but I think it creates unnecessary
    > ambiguity.
    > If there is a method called caption=3D(), I expect it to use that. I don=

    't
    > write
    > 'self' anywhere else in Ruby, so it just seems odd. Plus is helps reduce
    > hard
    > to debug locals creation by misspellings.
    >
    > class Button
    > attr :caption, true
    >
    > def initialize(*args, &block)
    > instance_eval &block
    > end
    > end
    >
    > button =3D Button.new do
    > var :x
    > caption =3D 'Click Me'
    > end




    If you don't mind dropping the equals sign it's a pretty easy fix. At that
    point you could even do some method_missing magic and have it check for
    existing attributes and use those.


    There is already 'attr' for classes, why not 'local' or 'var' for
    > methods? One
    > issue is that you can't assign and declare on the same line. It could be
    > done
    > with a hash but that might look funny?
    >
    > Take this all with a grain of salt. I'm always looking for different way=

    s
    > of
    > doing things. I.e. to find good ideas you have to find bad ideas ;)



    And as david said, really the lack of a receiver is the exception not the
    rule.

    Mike
    >
    >



    --
    =3D=3D=3DTanner Burson=3D=3D=3D

    http://tannerburson.com <---Might even work one day...

    ------=_Part_13346_20782533.1141836529188--
    Tanner Burson, Mar 8, 2006
    #12
  13. On Wed, 08 Mar 2006 15:56:53 +0100, <> wrote:

    > Hi --
    >
    > On Wed, 8 Mar 2006, itsme213 wrote:
    >
    >> I wouldn't hold my breath for :=3D or equivalent :)

    >
    > I have to say, I've been wondering for many years... is self.x =3D 1
    > really *that* bad? It just seems like such a minor thing to me. I
    > certainly wouldn't want to see new punctuation introduced just to
    > avoid it.


    How about allowing

    attr =3D val

    as a shortcut for

    self.attr =3D val

    It's no "new" punctuation and I can't see any ambiguities with current =20
    ruby syntax (correct me if I'm wrong).

    Just an idea.

    Dominik
    Dominik Bathon, Mar 8, 2006
    #13
  14. Mike Austin

    Guest

    Hi --

    On Thu, 9 Mar 2006, Logan Capaldo wrote:

    >
    > On Mar 8, 2006, at 2:09 PM, Dominik Bathon wrote:
    >
    >> On Wed, 08 Mar 2006 15:56:53 +0100, <> wrote:
    >>
    >>> Hi --
    >>>
    >>> On Wed, 8 Mar 2006, itsme213 wrote:
    >>>
    >>>> I wouldn't hold my breath for := or equivalent :)
    >>>
    >>> I have to say, I've been wondering for many years... is self.x = 1
    >>> really *that* bad? It just seems like such a minor thing to me. I
    >>> certainly wouldn't want to see new punctuation introduced just to
    >>> avoid it.

    >>
    >> How about allowing
    >>
    >> .attr = val
    >>
    >> as a shortcut for
    >>
    >> self.attr = val
    >>
    >> It's no "new" punctuation and I can't see any ambiguities with current ruby
    >> syntax (correct me if I'm wrong).
    >>
    >> Just an idea.
    >>
    >> Dominik
    >>

    >
    > Hmmmmmm, It's shorter than self.attr, but on the other hand it's uglier IMO.
    > One question I would have to wonder is:
    >
    > self.method( ) # definitely not private
    > method( ) # definitely private
    > self.x = y # could be public or private
    > .x # probably(?) not private ???
    > .x = y # ???
    >
    > Oh wait I take the whole thing back, naked method( ) could be public too. I
    > guess throwing .x in there doesn't make the visibility any more confusing


    I wonder how the parser would handle:

    obj .x

    i.e., whether it would be:

    obj.x

    or

    obj(.x)


    David

    --
    David A. Black ()
    Ruby Power and Light, LLC (http://www.rubypowerandlight.com)

    "Ruby for Rails" chapters now available
    from Manning Early Access Program! http://www.manning.com/books/black
    , Mar 9, 2006
    #14
  15. On Mar 8, 2006, at 9:58 PM, wrote:


    >
    > I wonder how the parser would handle:
    >
    > obj .x
    >
    > i.e., whether it would be:
    >
    > obj.x
    >
    > or
    >
    > obj(.x)
    >
    >
    > David
    >
    > --
    > David A. Black ()
    > Ruby Power and Light, LLC (http://www.rubypowerandlight.com)
    >
    > "Ruby for Rails" chapters now available
    > from Manning Early Access Program! http://www.manning.com/books/black
    >


    I would imagine obj.x since that is the current behavior
    Logan Capaldo, Mar 9, 2006
    #15
  16. On Thu, 09 Mar 2006 03:58:07 +0100, <> wrote:

    > On Thu, 9 Mar 2006, Logan Capaldo wrote:
    >
    >> Hmmmmmm, It's shorter than self.attr, but on the other hand it's =20
    >> uglier IMO. One question I would have to wonder is:
    >>
    >> self.method( ) # definitely not private
    >> method( ) # definitely private
    >> self.x =3D y # could be public or private
    >> .x # probably(?) not private ???
    >> .x =3D y # ???
    >>
    >> Oh wait I take the whole thing back, naked method( ) could be public =

    =20
    >> too. I guess throwing .x in there doesn't make the visibility any mor=

    e =20
    >> confusing

    >
    > I wonder how the parser would handle:
    >
    > obj .x
    >
    > i.e., whether it would be:
    >
    > obj.x
    >
    > or
    >
    > obj(.x)


    I would say it should be obj.x, as I didn't propose to allow .meth as a =20
    general shortcut for self.meth, but only when it is a left hand side of a=
    n =20
    asignment.

    But this leads to:

    meth .attr=3D42

    I would say that would also be meth.attr=3D42 and not meth(.attr=3D42). I=
    f you =20
    want the latter, then use brackets.


    Dominik
    Dominik Bathon, Mar 9, 2006
    #16
  17. Mike Austin

    George Ogata Guest

    Anthony DeRobertis <> writes:

    > Dominik Bathon wrote:
    >
    >> meth .attr=42
    >>
    >> I would say that would also be meth.attr=42 and not meth(.attr=42).

    >
    > The spacing, though, makes it look like the latter. The spacing really
    > makes it look like 42 goes with .attr, not with meth.
    >
    > Of course, then there is:
    >
    > meth . attr = 42
    >
    > and other fun variations :-(


    It's a bit iffy, isn't it? Wouldn't it also break Matz's golden
    rules of when to use call parens? I believe it goes:

    * if there are no args, don't use parens.
    * elsif you use the return value, use parens.
    * else parens are optional.
    George Ogata, Mar 9, 2006
    #17
  18. Dominik Bathon wrote:

    > meth .attr=42
    >
    > I would say that would also be meth.attr=42 and not meth(.attr=42).


    The spacing, though, makes it look like the latter. The spacing really
    makes it look like 42 goes with .attr, not with meth.

    Of course, then there is:

    meth . attr = 42

    and other fun variations :-(
    Anthony DeRobertis, Mar 9, 2006
    #18
  19. Mike Austin

    Mike Austin Guest

    Well I found out either way I go with passing a block to Button.new(), it
    doesn't work very well because subclasses' initialize() is called afterwards
    and clobbers the changes :) So I just have another method called init().

    ....
    def init()
    yield self
    return self
    end
    ....

    button = Button.new.init do |b|
    b.caption = 'Click Me!'
    end


    Mike

    wrote:
    > On Wed, 8 Mar 2006, Mike Austin wrote:
    >
    >> I'm writing a property driven ui and would like to do things like:
    >>
    >> button = Button.new do
    >> caption = 'Click Me'
    >> end
    >>
    >> I've read that 2.0 will have this feature, i.e. Class.new will execute
    >> it's block argument in it's own context. But how do I do it in 1.8?
    >>
    >> Thanks much,
    >> Mike

    >
    > class Button
    > def initialize(*args, &block)
    > instance_eval &block
    > end
    > end
    >
    > note that you'll need to do
    >
    > self.caption = 'Click Me'
    >
    > or else caption will be a local variable. for an elegant work around
    > see the
    > metakoan quiz or my traits library. with it a really nice syntax like
    > this is
    > possible
    >
    > button = Button.new {
    > caption 'Click Me'
    > colour 'Orange'
    > size '42'
    > }
    >
    > here's a real example from something i'm coding now:
    >
    >
    > class Flo5 < NRT::OLSSubscription::Geotiffed
    > mode "production"
    >
    > roi 47,16,39,27
    >
    > satellites %w( F15 F16 )
    >
    > extensions %w( OIS )
    >
    > solarelevations -180, -12, 10.0
    >
    > hold 0
    >
    > username "flo"
    >
    > password "xxx"
    >
    > orbital_start_direction "descending"
    >
    > start_time "2004-12-08"
    > end_time "2006-12-08"
    >
    > to_keep [ %r/.tif$/, %r/.hdr$/ ]
    >
    > tmpwatch "8 days"
    > end
    >
    >
    > hth.
    >
    >
    > -a
    >
    Mike Austin, Mar 10, 2006
    #19
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. VS_NET_DEV
    Replies:
    2
    Views:
    3,790
    jenny
    May 25, 2004
  2. Neroku
    Replies:
    9
    Views:
    994
    Chris Uppal
    Feb 7, 2007
  3. morrell
    Replies:
    1
    Views:
    937
    roy axenov
    Oct 10, 2006
  4. Replies:
    2
    Views:
    471
  5. divya
    Replies:
    3
    Views:
    161
    divya
    Sep 20, 2006
Loading...

Share This Page