Difference answers from Terminal, TextMate, and BBEdit


#1

A newbie here trying to develop one of Pine’s tutorial scripts. Ruby
v1.8.6

I get different results from my script in Terminal, TextMate, and
BBEdit. How is this possible?

TextMate seems to be the closest to what I’d expect. I’d buy it if the
undo’s were better. Plus I already own BBEdit. I realize BBEdit doesn’t
profess to support Ruby script running that much, but I expected
Terminal to be consistent.

I’ve driven myself crazy trying to debug my script, stalled in BBEdit,
so went to Terminal, but after putting in all kinds of puts to figure
out what was going on, tried my demo TextMate and it ran better. In all
cases exactly the same file.

Thanks for any clues.


#2

Greg wrote:

I’ve driven myself crazy trying to debug my script, stalled in BBEdit,
so went to Terminal, but after putting in all kinds of puts to figure
out what was going on, tried my demo TextMate and it ran better. In
all cases exactly the same file.

Thanks for any clues.

It would help if you’d post your script, what answers you expected, and
what answers you got.


#3

On 2007-05-07 18:16:38 -0700, Tim H. removed_email_address@domain.invalid said:

I’ve driven myself crazy trying to debug my script, stalled in BBEdit,
so went to Terminal, but after putting in all kinds of puts to figure
out what was going on, tried my demo TextMate and it ran better. In all
cases exactly the same file.

Thanks for any clues.

It would help if you’d post your script, what answers you expected, and
what answers you got.

Thanks for answering. Here it goes:

#!/usr/bin/env ruby

class OrangeTree

MSG_GROW = “Type “year” to grow your tree.”
MSG_PICK = "Type a number to pick some more fruit. "
EXIT_TXT = “Something went wrong.”

def initialize # we have one tree, does it need a name?
@heightInches = 0 # at year zero
@age = 0
@fruit = 0 # inches, work out feet and inches later
puts "Congratulations, you planted an orange tree. In a few years it
will start bearing fruit. #{@age} " # Age only for debugging. Can take
it out.
puts MSG_GROW
end

def ageOneYear
@heightInches = @heightInches +1
puts 'Height: ’ + @height.to_s
@age += 1
# @age = @age + 1
puts “Got to ageOneYear. Age: #{@age}”
case( @age )
when (1…3) : puts(“Your #{@age} year old tree is too young to
bear fruit yet. #{MSG_GROW}” )
when (4…29) : puts(" Age: #{@age}. Place holder until get 1…3
working." )
when (30) : puts(“Your tree was very fruitful, but it
reached
old age and died.”)
else puts( " Something went wrong. #{EXIT_TXT}" )
end
end # def ageOneYear

def height
# returns the height
end

def pick_an_orange
puts ‘Got to pick_an_orange, but haven’t defined yet’
# reduce this year count by one
end

end # class OrangeTree

here we go

countLoop = 0
tree = OrangeTree.new # assume we need to initialize it. Does it need a
name?

while countLoop < 100
countLoop += 1
puts “countLoop = #{countLoop}” # debugging.
if gets.to_s==‘year’
puts ‘In the gets.to_s if clause’ # debugging.
tree.ageOneYear
end

gets case
when ‘year’ : tree.ageOneYear # , y as shortcut?
when (1…100) : tree.pick_an_orange
else puts(‘Don’t be greedy, don’t try to pick more than 100
oranges’)
end

end # while

TextMate response. I answered ‘year’ to each request for input:
RubyMate r6354 running Ruby r1.8.6 (/usr/local/bin/ruby)

OrangeTree.post.rb

Congratulations, you planted an orange tree. In a few years it will
start bearing fruit. 0
Type “year” to grow your tree.
countLoop = 1
Height:
Got to ageOneYear. Age: 1
Your 1 year old tree is too young to bear fruit yet. Type “year” to
grow your tree.
countLoop = 2
Height:
Got to ageOneYear. Age: 2
Your 2 year old tree is too young to bear fruit yet. Type “year” to
grow your tree.
countLoop = 3
Height:
Got to ageOneYear. Age: 3
Your 3 year old tree is too young to bear fruit yet. Type “year” to
grow your tree.
countLoop = 4
Height:
Got to ageOneYear. Age: 4
Age: 4. Place holder until get 1…3 working.
NoMethodError: undefined method `+’ for nil:NilClass
method gets
in stdin_dialog.rb at line 6
method gets
in stdin_dialog.rb at line 13
at top level
in OrangeTree.post.rb at line 58
==END TextMate response

Terminal response. All ‘year’ are my responses. I stopped after two
none reponses.
new-host-2:~ xxxxxx$ ruby -v
ruby 1.8.6 (2007-03-13 patchlevel 0) [powerpc-darwin8.9.0]
new-host-2:~ xxxxxx$ ruby
“/Volumes/share/Greg/Ruby++/OrangeTree.post.rb”
Congratulations, you planted an orange tree. In a few years it will
start bearing fruit. 0
Type “year” to grow your tree.
countLoop = 1
year
Height:
Got to ageOneYear. Age: 1
Your 1 year old tree is too young to bear fruit yet. Type “year” to
grow your tree.
year
year
===End Terminal

BBEdit output. I only Cmd-R to run the script. I was never asked for
input.

Congratulations, you planted an orange tree. In a few years it will
start bearing fruit. 0
Type “year” to grow your tree.
countLoop = 1
Height:
Got to ageOneYear. Age: 1
Your 1 year old tree is too young to bear fruit yet. Type “year” to
grow your tree.
countLoop = 2
Height:
Got to ageOneYear. Age: 2
Your 2 year old tree is too young to bear fruit yet. Type “year” to
grow your tree.
countLoop = 3
Height:
Got to ageOneYear. Age: 3
Your 3 year old tree is too young to bear fruit yet. Type “year” to
grow your tree.
countLoop = 4
Height:
Got to ageOneYear. Age: 4
Age: 4. Place holder until get 1…3 working.
countLoop = 5
Height:
Got to ageOneYear. Age: 5
Age: 5. Place holder until get 1…3 working.

countLoop = 100
Height:
Got to ageOneYear. Age: 100
Something went wrong. Something went wrong.
===END BBEdit

TextMate was close, but I expected values for @heightInches to
increase with each iteration.

I would like it to work in BBEdit, but realize BareBones support for
this is weak. But at least Terminal should get it right. I own BBEdit,
so am reluctant to buy TextMate, particularly since it has significant
features I would like missing.

Thanks for any help.

I hope this isn’t a double posting. My original was via Usenet, then I
found the Google G. and tried to post there, but I am not sure I am
a member there. This version may be somewhat different as I had to
recreate it after realizing Google G. wasn’t working for me.


#4

Greg wrote:

the undo’s were better. Plus I already own BBEdit. I realize BBEdit

MSG_PICK = “Type a number to pick some more fruit. "
end
when (4…29) : puts(” Age: #{@age}. Place holder until
def pick_an_orange
while countLoop < 100
end
Height: Got to ageOneYear. Age: 1
countLoop = 4

Your 1 year old tree is too young to bear fruit yet. Type “year” to grow
Height: Got to ageOneYear. Age: 1
countLoop = 4

I hope this isn’t a double posting. My original was via Usenet, then I
found the Google G. and tried to post there, but I am not sure I am
a member there. This version may be somewhat different as I had to
recreate it after realizing Google G. wasn’t working for me.

Greg,

I saw two clear mistakes. First, you didn’t end height().

Second, your later “case” statement should be:
case gets.chomp

because gets() usually includes a newline. Perhaps that is the root of
your problem–different methods of input may or may not have a newline
at the end. calling chomp() removes any present newlines at the end. (I
also removed the “if gets.to_s==‘year’” line because it didn’t seem
helpful.)

I didn’t test it that much after seeing those, but I hope this helps.
Good luck,

Dan


#5

Thank you Dan and Morton

I knew about chomp, but forgot (typical beginners mistake). That helped
the script. BTW the end was there in height, but got lost in the
posting (actually it’s tacked to the end of the previous line).

I haven’t tried Morton’s suggestions, but sure they’ll help as putting
in the chomp brought up some other problems.

The chomp addition eliminates one “problem” as BBEdit can’t handle
chomp. (And BareBones has no plans to add the feature.)

Thanks again.


#6

On May 7, 2007, at 10:05 PM, Greg wrote:

but I expected Terminal to be consistent.
#!/usr/bin/env ruby
@fruit = 0 # inches, work out feet and inches later

# @age = @age + 1

end # def ageOneYear

OrangeTree.post.rb
grow your tree.
method gets
OrangeTree.post.rb"

Height: Got to ageOneYear. Age: 2
Height: Got to ageOneYear. Age: 5
BBEdit, so am reluctant to buy TextMate, particularly since it has
significant features I would like missing.
Thanks for any help.
I hope this isn’t a double posting. My original was via Usenet,
then I found the Google G. and tried to post there, but I am
not sure I am a member there. This version may be somewhat
different as I had to recreate it after realizing Google G.
wasn’t working for me.

There seems to be too problems with your code.

  1. You use @height in one place where really want @heightInches.
  2. Your case statement in the your while loop just doesn’t do what
    you think it should. And actually it would be hard make a case work
    in the situation you have set up.

Here is a modification of your code that I think will do what you
were trying to achieve:

#!/usr/bin/env ruby

class OrangeTree

MSG_GROW = "Type \"year\" to grow your tree."
MSG_PICK = "Type a number to pick some more fruit. "
EXIT_TXT = "Something went wrong."

def initialize
   @heightInches = 0
   @age = 0
   @fruit = 0
   puts MSG_GROW
end

def ageOneYear
   @heightInches = @heightInches +1
   puts 'Height: ' + @heightInches.to_s # <= not '@height'
   @age += 1
   # @age = @age + 1
   puts "Got to ageOneYear. Age: #{@age}"
   case @age
   when (1..3) :  puts("Your #{@age} year old tree is too young

to bear fruit yet. #{MSG_GROW}" )
when (4…29) : puts(" Age: #{@age}. Place holder until get
1…3 working." )
when (30) : puts(“Your tree was very fruitful, but it
reached old age and died.”)
else puts( " Something went wrong. #{EXIT_TXT}" )
end
end

def height
   # returns the height
end

def pick_an_orange
   puts 'Got to pick_an_orange, but haven\'t defined yet'
   # reduce this year count by one
end

end

countLoop = 0
tree = OrangeTree.new

while countLoop < 100
countLoop += 1
puts “countLoop = #{countLoop}”
# case statement not really appropriate for this loop.
# Note: gets always returns a string terminated with a newline.
user_input = gets.chomp
if user_input == ‘year’
tree.ageOneYear
elsif (1…100).include?(user_input.to_i) # need to convert string
to integer
tree.pick_an_orange
else puts(‘Don’t be greedy, don’t try to pick more than 100
oranges’)
end
end

Regards, Morton


#7

On 2007-05-07 20:37:31 -0700, Morton G. removed_email_address@domain.invalid
said:

doesn’t profess to support Ruby script running that much, but I
def initialize # we have one tree, does it need a name?
@heightInches = @heightInches +1
old age and died.")
end
debugging. tree.ageOneYear
There seems to be two problems with your code.

  1. You use @height in one place where really want @heightInches.

Duh. Thanks.

class OrangeTree
end
when (4…29) : puts(" Age: #{@age}. Place holder until get 1…3

while countLoop < 100
else puts(‘Don’t be greedy, don’t try to pick more than 100 oranges’)
end
end

Regards, Morton

No it’s not working like I want. But I don’t understand why case isn’t
appropriate. But your method works right and mine doesn’t, so I don’t
think I’ll worry about it now.

One question. How is

elsif (1…100).include?(user_input.to_i)
working? I understand it up through “elsif(1…100)” Is the user_input
changed to integer before the elsif is evaluated. What does the
include? do? (The don’t be greedy part was just placeholder until I
worked out the whole orange picking and growing logic.)

BTW, the while loop seemed like a crude work around to keep asking for
inputs. I would like it to stop at 30 in the class (at least that seems
more elegant as that is where the age decisions are made).

Thanks again. Lots to learn (and remember).


#8

Greg wrote:

One question. How is

elsif (1…100).include?(user_input.to_i)

working? I understand it up through “elsif(1…100)” Is the user_input
changed to integer before the elsif is evaluated.

Yes. The to_i method is called on user_input, its result is passed as an
argument to the include? methods of (1…100) and the result of that is
used for the elsif.

What does the include? do?

blubb.include?(bla) returns true if bla can be found inside blubb and
false
otherwise. In this case it returns true if user_input.to_i is inside the
range
1…100, i.e. if it’s a number between one and one hundred (inclusive).


#9

On May 8, 2007, at 12:30 AM, Greg wrote:

class OrangeTree
@heightInches = @heightInches +1
reached old age and died.")
end
elsif (1…100).include?(user_input.to_i) # need to convert
isn’t appropriate. But your method works right and mine doesn’t, so
I don’t think I’ll worry about it now.

You could use a case here, but it would have to be considerably
more complicated than the simple case form you wrote. I thought (and
still think) an if-elsif-else statement is better for sorting out the
user input in this case. A case statement like

case when 'year' : tree.ageOneYear # , y as shortcut? when (1..100) : tree.pick_an_orange else puts('Don\'t be greedy, don\'t try to pick more than 100 oranges') end

just looks for the first true when-clause. In this case that will
always be ‘year’ because everything but false and nil is true in Ruby.

One question. How is

elsif (1…100).include?(user_input.to_i)
working? I understand it up through “elsif(1…100)” Is the
user_input changed to integer before the elsif is evaluated. What
does the include? do? (The don’t be greedy part was just
placeholder until I worked out the whole orange picking and growing
logic.)

user_input is converted to a integer during the evaluation of the
elsif. This code is roughly equivalent to:

num = user_input.to_i
in_range = (1…100).include?(num)
elsif in_range

BTW, the while loop seemed like a crude work around to keep asking
for inputs. I would like it to stop at 30 in the class (at least
that seems more elegant as that is where the age decisions are made).

Do you want to stop after 30 loops (that’s easy) or when @age reaches
30 (that’s just a little harder)? For the first:

tree = OrangeTree.new 30.times do user_input = gets.chomp if user_input == 'year' tree.ageOneYear elsif (1..100).include?(user_input.to_i) # need to convert string to integer tree.pick_an_orange else puts('Don\'t be greedy, don\'t try to pick more than 100 oranges') end end

For the second:

class OrangeTree attr_reader :age # <= add this to OrangeTree so @age can be queried outside of class def end tree = OrangeTree.new loop do user_input = gets.chomp if user_input == 'year' tree.ageOneYear break if tree.age >= 30 elsif (1..100).include?(user_input.to_i) # need to convert string to integer tree.pick_an_orange else puts('Don\'t be greedy, don\'t try to pick more than 100 oranges') end end

Regards, Morton


#10

On May 7, 2007, at 11:45 PM, Greg wrote:

The chomp addition eliminates one “problem” as BBEdit can’t handle
chomp. (And BareBones has no plans to add the feature.)

That’s really strange. But I checked it and it’s true. However, you
can still test your code by saving it to a file and choosing Run in
Terminal from the #! menu.

I must admit that after using TextMate for Ruby coding for sometime
now, going back to BBEdit seems clunky. But one thing BBEdit does
better than TextMate is printing out source code with a printer.

Regards, Morton


#11

On Tue, May 08, 2007 at 07:22:39PM +0900, Morton G. wrote:

just looks for the first true when-clause. In this case that will
always be ‘year’ because everything but false and nil is true in Ruby.

That’s incorrect. Case doesn’t check if ‘year’ is true; it checks
whether
‘year’ === obj is true.

Try this:

foo = “Hello”
case foo
when “year”
puts “xxx”
when /ell/
puts “yyy” # this line is run
end


#12

On May 8, 2007, at 8:34 AM, Brian C. wrote:

foo = “Hello”
case foo
when “year”
puts “xxx”
when /ell/
puts “yyy” # this line is run
end

Beg to differ with you. This is a case with no argument. It doesn’t
have any obj to do a ‘year’ === obj on.

Regards, Morton


#13

Thanks all for your answers. Much to learn.


#14

On May 8, 2007, at 12:52 PM, Brian C. wrote:

Ugh, you’re right. It doesn’t even compare against $_.
That seems rather pointless, as it’s just the same as if …
elsif … end

AFAIK, a case statement without a target can always be rewritten as a
if-elsif-else statement, but I don’t think that makes a target-less
case pointless. When there are many conditions to be handled, I find
the target-less case more readable. A matter of taste, I suppose.

OTOH, the point I wanted to make with the OP was, in his case, with
only two conditions to be handled, an if-elsif-else statement would
be more readable and the better way to go.

And what about

case
when (1…100)
# whatever
end

That would be the flipflop operator borrowed from Perl? But with
both ends
true as well?

I think it would work exactly the same as

if (1..100)
   # whatever
end

But I haven’t tried it. And probably never will – the flip-flop
behavior of ranges in a boolean expression is something I avoid as a
little too tricky.

Regards, Morton


#15

On Tue, May 08, 2007 at 11:47:28PM +0900, Morton G. wrote:

foo = “Hello”
case foo
when “year”
puts “xxx”
when /ell/
puts “yyy” # this line is run
end

Beg to differ with you. This is a case with no argument. It doesn’t
have any obj to do a ‘year’ === obj on.

Ugh, you’re right. It doesn’t even compare against $_.
That seems rather pointless, as it’s just the same as if … elsif … end

And what about

case
when (1…100)
# whatever
end

That would be the flipflop operator borrowed from Perl? But with both
ends
true as well?