# Ruby problem with conditional ranges

**URL:** <https://www.ruby-forum.com/t/ruby-problem-with-conditional-ranges/105879>\
**Category:** Ruby\
**Created:** [June 4, 2007, 8:57am UTC](https://www.ruby-forum.com/t/ruby-problem-with-conditional-ranges/105879 "2007-06-04T08:57:46Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![Todd\_ASJacobs](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/f17d59/32.png) [@Todd\_ASJacobs](https://www.ruby-forum.com/u/Todd_ASJacobs)\
**Post date:** [June 4, 2007, 8:57am UTC](https://www.ruby-forum.com/t/ruby-problem-with-conditional-ranges/105879/1 "2007-06-04T08:57:46Z")

</div>

I’m running into a problem doing a conditional range in ruby. The sample  
code is:

```
#!/usr/bin/ruby

## one
## two
## three
## four
## five

File.open($0, 'r') { |f|

```

while f.gets  
print $\_.sub(/^##/, ‘’) if /^## two/ … /^## four/  
end  
}

I’m expecting:

```
two
three
four

```

but I get the whole file with the leading pound signs stripped off.  
What’s wrong here?

---

<div class="post-metadata">

**Author:** ![Todd\_ASJacobs](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/f17d59/32.png) [@Todd\_ASJacobs](https://www.ruby-forum.com/u/Todd_ASJacobs)\
**Post date:** [June 4, 2007, 9:20am UTC](https://www.ruby-forum.com/t/ruby-problem-with-conditional-ranges/105879/2 "2007-06-04T09:20:48Z")

</div>

Hi,

At Mon, 4 Jun 2007 15:56:31 +0900,  
Todd A. Jacobs wrote in [ruby-talk:254228]:

> ```
> print $_.sub(/^##/, '') if /^## two/ .. /^## four/
> 
> ```

```
   print $_.sub(/^##/, '') if ~/^## two/ .. ~/^## four/

```

> but I get the whole file with the leading pound signs stripped off.  
> What’s wrong here?

Because Range object isn’t nil nor false, and you’d see a  
warning if you run with -w option.

warning: range literal in condition

---

<div class="post-metadata">

**Author:** ![Todd\_ASJacobs](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/f17d59/32.png) [@Todd\_ASJacobs](https://www.ruby-forum.com/u/Todd_ASJacobs)\
**Post date:** [June 4, 2007, 9:36am UTC](https://www.ruby-forum.com/t/ruby-problem-with-conditional-ranges/105879/3 "2007-06-04T09:36:51Z")

</div>

Hi,

Implicit match against “$\_” is not anymore supported in version 1.8.  
You cas still use it in command line form (with “-e” option).

In regular file, you have to write the match explicitly :

## one

## two

## three

## four

## five

File.open($0, ‘r’) { |f|  
while f.gets  
print $_.sub(/^##/, ‘’) if ($_ =~ /^## two/) … ($\_ =~ /^## four/)  
end  
}

On 4 juin, 08:56, “Todd A. Jacobs” [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)

---

<div class="post-metadata">

**Author:** ![Todd\_ASJacobs](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/f17d59/32.png) [@Todd\_ASJacobs](https://www.ruby-forum.com/u/Todd_ASJacobs)\
**Post date:** [June 5, 2007, 6:56am UTC](https://www.ruby-forum.com/t/ruby-problem-with-conditional-ranges/105879/4 "2007-06-05T06:56:18Z")

</div>

On Jun 4, 9:51 pm, “Todd A. Jacobs” \<tjacobs-  
removed\_email\_address@domain.invalid\> wrote:

> On Mon, Jun 04, 2007 at 04:35:25PM +0900, come wrote:
> 
> prints up to “four” when (as I understand it) it should stop at “three”  
> since “## four” would make the if-statement false. Am I still missing  
> something obvious?

Yes. That will never work, as this is not Perl nor are you creating a  
range of regexp (which cannot be done, btw).  
See what happens when the match does happen as you want:

irb\> a = ‘four’  
irb\> (a =~ /two/)…(a =~ /four/)  
ArgumentError: bad value for range

[result is: (nil…‘four’)]

Plus the uncommented # in the regex are probably making ruby assume a  
comment.

This is another way of writing what you want to do:

#!/usr/bin/ruby -w

## one

## two

## three

## four

## five

File.open($0) do |file|  
range = [‘$\_ =~ /^## two/’, ‘$\_ !~ /^## four/’]  
while file.gets  
if eval("#{range[0]}")  
print $\_.sub(/^## /, ‘’);  
range.shift  
end  
end  
end

---

<div class="post-metadata">

**Author:** ![Todd\_ASJacobs](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/f17d59/32.png) [@Todd\_ASJacobs](https://www.ruby-forum.com/u/Todd_ASJacobs)\
**Post date:** [June 5, 2007, 2:52am UTC](https://www.ruby-forum.com/t/ruby-problem-with-conditional-ranges/105879/5 "2007-06-05T02:52:24Z")

</div>

On Mon, Jun 04, 2007 at 04:35:25PM +0900, come wrote:

> Implicit match against “$\_” is not anymore supported in version 1.8.

Thanks. Your explanation was very helpful. It works better now, but the  
range operator _still_ catches more than it should. For example:

```
#!/usr/bin/ruby -w

## one
## two
## three
## four
## five

File.open($0) do |file|

```

while file.gets  
print $_.sub(/^## /, ‘’) if  
($_ =~ /^## two/)…($\_ =~ /^## four/)  
end  
end

prints up to “four” when (as I understand it) it should stop at “three”  
since “## four” would make the if-statement false. Am I still missing  
something obvious?

---

<div class="post-metadata">

**Author:** ![Todd\_ASJacobs](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/f17d59/32.png) [@Todd\_ASJacobs](https://www.ruby-forum.com/u/Todd_ASJacobs)\
**Post date:** [June 5, 2007, 7:11am UTC](https://www.ruby-forum.com/t/ruby-problem-with-conditional-ranges/105879/6 "2007-06-05T07:11:19Z")

</div>

Sorry. Buggy code posted. Here’s a correct implementation.

#!/usr/bin/ruby -w

## one

## two

## three

## five

## six

## four

## five

File.open($0) do |file|  
while file.gets  
if $\_ =~ /^## two/  
loop {  
print $_.sub(/^## /, ‘’)  
file.gets  
break if not $_ or $\_ =~ /^## four/  
}  
end  
end  
end

---

<div class="post-metadata">

**Author:** ![Todd\_ASJacobs](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/f17d59/32.png) [@Todd\_ASJacobs](https://www.ruby-forum.com/u/Todd_ASJacobs)\
**Post date:** [June 5, 2007, 9:36am UTC](https://www.ruby-forum.com/t/ruby-problem-with-conditional-ranges/105879/7 "2007-06-05T09:36:33Z")

</div>

Yes, because (as with Perl) there are two forms of conditional range:  
“…” and “…”.

The three dots form evaluate the condition after the code. Therefore,  
the “four” is printed, then the condition is evaluated to false.

The two dots form evaluates the condition before the code. So it  
should works as you expect : “($\_ =~ /^## two/)…($\_ =~ /^## four/)”.

On 5 juin, 02:51, “Todd A. Jacobs”
