On Ranges as conditions

Discussion in 'Ruby' started by Rafael Cunha de Almeida, Oct 3, 2009.

  1. Reading a few tutorials I found this piece of code:

    while input = gets
    input = input.chomp
    puts input + " triggered" if input =~ /start/ .. input =~ /end/
    end

    I understand what it does. If I type start, end or anything in between
    it prints
    "triggered" after the input. Now, if I'm out of the start .. end block,
    the if
    fails.

    What I don't understand is how it does it. For instance, if I use the
    interpreter to do something like this:

    irb(main):038:0> input = 'fooo'
    => "fooo"
    irb(main):039:0> puts input + " triggered" if input =~ /start/ .. input
    =~ /end/
    => nil
    irb(main):040:0> input = 'start'
    => "start"
    irb(main):041:0> puts input + " triggered" if input =~ /start/ .. input
    =~ /end/
    start triggered
    => nil
    irb(main):042:0> input = 'bar'
    => "bar"
    irb(main):043:0> puts input + " triggered" if input =~ /start/ .. input
    =~ /end/
    => nil

    it doesn't work as I'd expect. I thought the if clause there would
    somehow set a
    global to say "the first regex was matched" or something like that. But it
    doesn't seem to be the way it works. It only seems to work inside of a while
    loop. I thought it might have something to do with the $_ global. But I
    made a
    test in the interpreter which ruled out that theory:

    irb(main):045:0> $_ = 'foo'
    => "foo"
    irb(main):046:0> input = 'foo'
    => "foo"
    irb(main):047:0> puts input + " triggered" if input =~ /start/ .. input
    =~ /end/
    => nil
    irb(main):048:0> $_ = input = 'start'
    => "start"
    irb(main):049:0> puts input + " triggered" if input =~ /start/ .. input
    =~ /end/
    start triggered
    => nil
    irb(main):050:0> $_ = input = 'foo'
    => "foo"
    irb(main):051:0> puts input + " triggered" if input =~ /start/ .. input
    =~ /end/
    => nil
    irb(main):052:0>

    Can anyone help me find out what's going on?
     
    Rafael Cunha de Almeida, Oct 3, 2009
    #1
    1. Advertising

  2. On Sat, Oct 3, 2009 at 1:15 PM, Rafael Cunha de Almeida
    <> wrote:
    > Reading a few tutorials I found this piece of code:
    >
    > =A0 =A0 =A0 =A0while input =3D gets
    > =A0 =A0 =A0 =A0 =A0 =A0input =3D input.chomp
    > =A0 =A0 =A0 =A0 =A0 =A0puts input + " triggered" if input =3D~ /start/ ..=

    input =3D~ /end/
    > =A0 =A0 =A0 =A0end
    >
    > I understand what it does. If I type start, end or anything in between
    > it prints
    > "triggered" after the input. Now, if I'm out of the start .. end block,
    > the if
    > fails.
    >
    > What I don't understand is how it does it. For instance, if I use the
    > interpreter to do something like this:
    >
    > =A0 =A0 =A0 =A0irb(main):038:0> input =3D 'fooo'
    > =A0 =A0 =A0 =A0=3D> "fooo"
    > =A0 =A0 =A0 =A0irb(main):039:0> puts input + " triggered" if input =3D~ /=

    start/ .. input
    > =3D~ /end/
    > =A0 =A0 =A0 =A0=3D> nil
    > =A0 =A0 =A0 =A0irb(main):040:0> input =3D 'start'
    > =A0 =A0 =A0 =A0=3D> "start"
    > =A0 =A0 =A0 =A0irb(main):041:0> puts input + " triggered" if input =3D~ /=

    start/ .. input
    > =3D~ /end/
    > =A0 =A0 =A0 =A0start triggered
    > =A0 =A0 =A0 =A0=3D> nil
    > =A0 =A0 =A0 =A0irb(main):042:0> input =3D 'bar'
    > =A0 =A0 =A0 =A0=3D> "bar"
    > =A0 =A0 =A0 =A0irb(main):043:0> puts input + " triggered" if input =3D~ /=

    start/ .. input
    > =3D~ /end/
    > =A0 =A0 =A0 =A0=3D> nil
    >
    > it doesn't work as I'd expect. I thought the if clause there would
    > somehow set a
    > global to say "the first regex was matched" or something like that. But i=

    t
    > doesn't seem to be the way it works. It only seems to work inside of a wh=

    ile
    > loop. I thought it might have something to do with the $_ global. But I
    > made a
    > test in the interpreter which ruled out that theory:
    >
    > =A0 =A0 =A0 =A0irb(main):045:0> $_ =3D 'foo'
    > =A0 =A0 =A0 =A0=3D> "foo"
    > =A0 =A0 =A0 =A0irb(main):046:0> input =3D 'foo'
    > =A0 =A0 =A0 =A0=3D> "foo"
    > =A0 =A0 =A0 =A0irb(main):047:0> puts input + " triggered" if input =3D~ /=

    start/ .. input
    > =3D~ /end/
    > =A0 =A0 =A0 =A0=3D> nil
    > =A0 =A0 =A0 =A0irb(main):048:0> $_ =3D input =3D 'start'
    > =A0 =A0 =A0 =A0=3D> "start"
    > =A0 =A0 =A0 =A0irb(main):049:0> puts input + " triggered" if input =3D~ /=

    start/ .. input
    > =3D~ /end/
    > =A0 =A0 =A0 =A0start triggered
    > =A0 =A0 =A0 =A0=3D> nil
    > =A0 =A0 =A0 =A0irb(main):050:0> $_ =3D input =3D 'foo'
    > =A0 =A0 =A0 =A0=3D> "foo"
    > =A0 =A0 =A0 =A0irb(main):051:0> puts input + " triggered" if input =3D~ /=

    start/ .. input
    > =3D~ /end/
    > =A0 =A0 =A0 =A0=3D> nil
    > =A0 =A0 =A0 =A0irb(main):052:0>
    >
    > Can anyone help me find out what's going on?


    As far as I can tell, from reading the 1.8 parse.c code, the problem
    is that conditional ranges really aren't Range instances but are
    really a kind of syntactic sugar. Every time you retype the source
    line into irb, you get an entirely new parse, and a new conditional
    range in the initial state.


    --=20
    Rick DeNatale

    Blog: http://talklikeaduck.denhaven2.com/
    Twitter: http://twitter.com/RickDeNatale
    WWR: http://www.workingwithrails.com/person/9021-rick-denatale
    LinkedIn: http://www.linkedin.com/in/rickdenatale
     
    Rick DeNatale, Oct 3, 2009
    #2
    1. Advertising

  3. It isn't a range, it's a "flip-flop" which happens to use the same
    operator ('..') as range construction.

    While useful in some sed/awk like scripts it's not a widely used
    feature.

    -- MarkusQ
     
    Markus Roberts, Oct 3, 2009
    #3
  4. Rafael Cunha de Almeida

    Josh Cheek Guest

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

    On Sat, Oct 3, 2009 at 12:15 PM, Rafael Cunha de Almeida
    <>wrote:

    > Reading a few tutorials I found this piece of code:
    >
    > while input = gets
    > input = input.chomp
    > puts input + " triggered" if input =~ /start/ .. input =~ /end/
    > end
    >
    > I understand what it does. If I type start, end or anything in between
    > it prints
    > "triggered" after the input. Now, if I'm out of the start .. end block,
    > the if
    > fails.
    >
    > What I don't understand is how it does it. For instance, if I use the
    > interpreter to do something like this:
    >
    > irb(main):038:0> input = 'fooo'
    > => "fooo"
    > irb(main):039:0> puts input + " triggered" if input =~ /start/ ..
    > input
    > =~ /end/
    > => nil
    > irb(main):040:0> input = 'start'
    > => "start"
    > irb(main):041:0> puts input + " triggered" if input =~ /start/ ..
    > input
    > =~ /end/
    > start triggered
    > => nil
    > irb(main):042:0> input = 'bar'
    > => "bar"
    > irb(main):043:0> puts input + " triggered" if input =~ /start/ ..
    > input
    > =~ /end/
    > => nil
    >
    > it doesn't work as I'd expect. I thought the if clause there would
    > somehow set a
    > global to say "the first regex was matched" or something like that. But it
    > doesn't seem to be the way it works. It only seems to work inside of a
    > while
    > loop. I thought it might have something to do with the $_ global. But I
    > made a
    > test in the interpreter which ruled out that theory:
    >
    > irb(main):045:0> $_ = 'foo'
    > => "foo"
    > irb(main):046:0> input = 'foo'
    > => "foo"
    > irb(main):047:0> puts input + " triggered" if input =~ /start/ ..
    > input
    > =~ /end/
    > => nil
    > irb(main):048:0> $_ = input = 'start'
    > => "start"
    > irb(main):049:0> puts input + " triggered" if input =~ /start/ ..
    > input
    > =~ /end/
    > start triggered
    > => nil
    > irb(main):050:0> $_ = input = 'foo'
    > => "foo"
    > irb(main):051:0> puts input + " triggered" if input =~ /start/ ..
    > input
    > =~ /end/
    > => nil
    > irb(main):052:0>
    >
    > Can anyone help me find out what's going on?
    >
    >

    # (this entire response can be directly placed into a script -- not the
    above quote, though)
    #
    # The first condition turns it on (causes it to evaluate to true)
    # the second turns it off (causes it to evaluate back to false).
    # In this example, you would get the output
    #
    # start triggered
    # instruction2 triggered
    # instruction3 triggered
    # end triggered
    # start triggered
    # instruction6 triggered
    # instruction7 triggered
    # instruction8 triggered
    # end triggered
    #
    # Give it a try

    $stdin = DATA

    while input = gets
    input = input.chomp
    puts input + " triggered" if input =~ /start/ .. input =~ /end/
    end

    __END__
    instruction0
    instruction1
    start
    instruction2
    instruction3
    end
    instruction4
    instruction5
    start
    instruction6
    instruction7
    instruction8
    end
    instruction9
     
    Josh Cheek, Oct 3, 2009
    #4
  5. Rafael Cunha de Almeida

    Xavier Noria Guest

    On Saturday, October 3, 2009, Markus Roberts <> wrote:
    > It isn't a range, it's a "flip-flop" which happens to use the same operator ('..') as range construction.
    >
    > While useful in some sed/awk like scripts it's not a widely used feature.


    Well, it is used as often as you find the problem it solves, no matter
    the language.
     
    Xavier Noria, Oct 4, 2009
    #5
  6. Rafael Cunha de Almeida

    Ken Bloom Guest

    On Sun, 04 Oct 2009 04:06:56 +0900, Rick DeNatale wrote:

    > On Sat, Oct 3, 2009 at 1:15 PM, Rafael Cunha de Almeida
    > <> wrote:
    >> Reading a few tutorials I found this piece of code:
    >>
    >>        while input = gets
    >>            input = input.chomp
    >>            puts input + " triggered" if input =~ /start/ .. input
    >>            =~ /end/
    >>        end
    >>
    >> I understand what it does. If I type start, end or anything in between
    >> it prints
    >> "triggered" after the input. Now, if I'm out of the start .. end block,
    >> the if
    >> fails.
    >>
    >> What I don't understand is how it does it. For instance, if I use the
    >> interpreter to do something like this:
    >>
    >>        irb(main):038:0> input = 'fooo'
    >>        => "fooo"
    >>        irb(main):039:0> puts input + " triggered" if input =~
    >>        /start/ .. input
    >> =~ /end/
    >>        => nil
    >>        irb(main):040:0> input = 'start'
    >>        => "start"
    >>        irb(main):041:0> puts input + " triggered" if input =~
    >>        /start/ .. input
    >> =~ /end/
    >>        start triggered
    >>        => nil
    >>        irb(main):042:0> input = 'bar'
    >>        => "bar"
    >>        irb(main):043:0> puts input + " triggered" if input =~
    >>        /start/ .. input
    >> =~ /end/
    >>        => nil
    >>
    >> it doesn't work as I'd expect. I thought the if clause there would
    >> somehow set a
    >> global to say "the first regex was matched" or something like that. But
    >> it doesn't seem to be the way it works. It only seems to work inside of
    >> a while loop. I thought it might have something to do with the $_
    >> global. But I made a
    >> test in the interpreter which ruled out that theory:
    >>
    >>        irb(main):045:0> $_ = 'foo'
    >>        => "foo"
    >>        irb(main):046:0> input = 'foo'
    >>        => "foo"
    >>        irb(main):047:0> puts input + " triggered" if input =~
    >>        /start/ .. input
    >> =~ /end/
    >>        => nil
    >>        irb(main):048:0> $_ = input = 'start' => "start"
    >>        irb(main):049:0> puts input + " triggered" if input =~
    >>        /start/ .. input
    >> =~ /end/
    >>        start triggered
    >>        => nil
    >>        irb(main):050:0> $_ = input = 'foo'
    >>        => "foo"
    >>        irb(main):051:0> puts input + " triggered" if input =~
    >>        /start/ .. input
    >> =~ /end/
    >>        => nil
    >>        irb(main):052:0>
    >>
    >> Can anyone help me find out what's going on?

    >
    > As far as I can tell, from reading the 1.8 parse.c code, the problem is
    > that conditional ranges really aren't Range instances but are really a
    > kind of syntactic sugar. Every time you retype the source line into
    > irb, you get an entirely new parse, and a new conditional range in the
    > initial state.


    Pretty cool! Thanks for pointing this syntax out! I don't recall seeing
    it in Pickaxe.

    One question:

    irb(main):013:0> a=%w{foo start bar end baz start foo bar end baz}
    => ["foo", "start", "bar", "end", "baz", "start", "foo", "bar", "end",
    "baz"]
    irb(main):014:0> a.each {|i| puts i + (if i =~ /start/ .. i =~ /end/ then
    " triggered" else "" end) }
    foo
    start triggered
    bar triggered
    end triggered
    baz
    start triggered
    foo triggered
    bar triggered
    end triggered
    baz
    => ["foo", "start", "bar", "end", "baz", "start", "foo", "bar", "end",
    "baz"]
    irb(main):015:0> a.each {|i| puts i + (if i =~ /start/ ... i =~ /end/
    then " triggered" else "" end) }
    foo
    start triggered
    bar triggered
    end triggered
    baz
    start triggered
    foo triggered
    bar triggered
    end triggered
    baz

    Shouldn't the last version (using ... instead of ..) logically omit the
    end line from the triggered section?

    --Ken

    --
    Chanoch (Ken) Bloom. PhD candidate. Linguistic Cognition Laboratory.
    Department of Computer Science. Illinois Institute of Technology.
    http://www.iit.edu/~kbloom1/
     
    Ken Bloom, Oct 7, 2009
    #6
  7. On Wed, Oct 7, 2009 at 1:08 PM, Ken Bloom <> wrote:
    > Pretty cool! Thanks for pointing this syntax out! I don't recall seeing
    > it in Pickaxe.

    It's definitely in the first (2001) edition as "Ranges as conditions":
    _A range used in a boolean expression acts as a flip-flop.
    _ It has two states, set and unset, and is initially unset.
    _ On each call, the range cycles through the state machine ...
    _ The range returns true if it is in the set state at the end of the call,
    _ and false otherwise.
    _The two-dot form of a range behaves slightly differently than the
    three-dot form.
    _ When the two-dot form first makes the transition from unset to set,
    _it immediately evaluates the end condition and makes the transition
    accordingly.
    _This means that if expr1 and expr2 both evaluate to true on the same call,
    _the two-dot form will finish the call in the unset state.
    _However, it still returns true for this call.
     
    Colin Bartlett, Oct 8, 2009
    #7
    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. valentin tihomirov

    another array ranges mystery

    valentin tihomirov, Jun 18, 2005, in forum: VHDL
    Replies:
    2
    Views:
    486
    Mike Treseler
    Jun 18, 2005
  2. C
    Replies:
    1
    Views:
    456
    Sunil TG [MVP]
    Oct 29, 2003
  3. Philip Townsend

    Determining date ranges

    Philip Townsend, Nov 6, 2003, in forum: ASP .Net
    Replies:
    0
    Views:
    329
    Philip Townsend
    Nov 6, 2003
  4. Strider76

    Excel Defined ranges

    Strider76, Apr 13, 2004, in forum: ASP .Net
    Replies:
    0
    Views:
    322
    Strider76
    Apr 13, 2004
  5. Bob Hairgrove

    Working with ranges of scalar values

    Bob Hairgrove, Jun 26, 2004, in forum: C++
    Replies:
    1
    Views:
    322
    Ivan Vecerina
    Jun 29, 2004
Loading...

Share This Page