Ruby - end pattern with unmatched parenthesis: / - ruby

I'm getting different error based on space between after divide(/) operator. Lets consider following example.
$ ruby -e "a /100"
-e:1: unterminated string meets end of file
-e:1: syntax error, unexpected tSTRING_END, expecting tSTRING_CONTENT or tREGEXP_END or tSTRING_DBEG or tSTRING_DVAR
$ ruby -e "a / 100"
-e:1: undefined local variable or method `a' for main:Object (NameError)
The second example gives proper error message while the first one gives weird error. I did some research, but couldn't find out the reasons behind it. Is there anyway to fix this to give proper error messge?

If I try this with Ruby 2.3.1, I get this message: -e:1: unterminated regexp meets end of file Which seems valid since "/" is normally a regex marker...
And in the second line of your error message it says it is expecting a tREGEXP_END.
So, I think, everything is fine.

I tried this in the terminal and got the same regexp error:
$ ruby -e "a /100"
-e:1: unterminated regexp meets end of file
It seems like the /100 was interpreted as a regexp. The simple solution is to follow the correct ruby syntax (i.e. your second example: $ ruby -e "a / 100" ). Normally, it is recommended to add spaces around ruby operators, as suggest by the ruby style guide.

Related

Ruby: Why do I get warning "regex literal in condition" here?

A simple Ruby program, which works well (using Ruby 2.0.0):
#!/usr/bin/ruby
while gets
print if /foo/../bar/
end
However, Ruby also outputs the warning warning: regex literal in condition. It seems that Ruby considers my flip-flop-expression /foo/../bar/ as dangerous.
My question: Where lies the danger in this program? And: Can I turn off this warning (ideally only for this statement, keeping other warnings active)?
BTW, I found on the net several discussions of this kind of code, also mentioning the warning, but never found a good explanation why we get warned.
You can avoid the warning by using an explicit match:
while gets
print if ~/foo/..~/bar/
end
Regexp#~ matches against $_.
I don't know why the warning is shown (to be honest, I wasn't even aware that Ruby matches regexp literals against $_ implicitly), but according to the parser's source code, it is shown unless you provide the -e option when invoking Ruby, i.e. passing the script as an argument:
$ ruby -e "while gets; print if /foo/../bar/ end"
I would avoid using $_ as an implicit parameter and instead use something like:
while line = gets
print line if line=~/foo/..line=~/bar/
end
I think Neil Slater is right: It looks like a bug in a parser. If I change the code to
#!/usr/bin/ruby
while gets
print if $_=~/foo/..$_=~/bar/
end
the warning disappears.
I'll file a bug report.

ruby: method_missing backtick typo?

I was building a method to send me an email through mutt when my ruby scripts fail. It looks something like this:
begin
UnknownFunction()
rescue
subject = 'Error'
to_array = ['email#email.com','email2#email.com']
body = "An error occurred:\n#{$!}"
%x[echo "#{body}" | mutt -s "#{subject}" #{to_array.join(",")}]
end
the command was throwing the following error:
sh: -c: line 1: unexpected EOF while looking for matching ``'
sh: -c: line 2: syntax error: unexpected end of file
I finally looked closely enough to see that $! contains a backtick before the undefined method's name followed by a single quote:
undefined method `UnknownFunction' for main:Object
I dug into the code and verified the method_missing method has a backtick before and single quote afterwards. Should the backtick be a single quote or vice versa? If not, what's the reasoning behind it?
raise NoMethodError, "undefined method `#{mid}' for #{self}", caller(1)
It's a substitute for an open single quote (‘) in plain text/pre-Unicode environments. See: Why do plain-text technical articles often enclose terms within backticks and single quotes?
The description of the NoMethodError is not meant to be code, so the use of a backtick there is purely for aesthetic reasons. If you want to pass an arbitrary string to the shell, use Shellwords.shellescape.
backticks are fine for simple commands, but once you start throwing data at the child process I think its better to use something more sophisticated than piping the text via echo. I'd use IO.popen:
IO.popen(
"mutt -s '%s' %s" % [ subject, to_array.join(',') ],
'w'
) do |mutt|
mutt.puts body
end
That's untested but is what I'd start with. It's more readable because it gets rid of the backtick jungle of interpolated variables. It also avoids potential problems of the sub-shell trying to help by interpreting variables or looking for embedded backticks in the text being sent to mutt.

Weird syntax error when comparing x with x.method

Why this works fine:
t="
"+$<.read;puts t.reverse==t ?"YES":"NO"
but this:
t="
"+$<.read;puts t==t.reverse ?"YES":"NO"
says:
A.rb:2: syntax error, unexpected tCHAR, expecting $end
"+$<.read;puts t==t.reverse ?"YES":"NO"
^
I use ruby 1.9.2p290 (2011-07-09) [i386-mingw32].
Sample STDIN string is XX.\n...\n.XX\n.
Looks like Ruby is parsing the latter as a potential call to #reverse?. That ambiguity is removed when switched the other way. Adding parentheses around the conditional should allow it to go both ways.

Is there a quick way to find missing end’s in Ruby?

syntax error, unexpected $end, expecting keyword_end
We’ve all been there! Assuming enough code changed that a quick glance at git diff or the like doesn’t make it obvious, is there an easy way to find that missing end (short of switching to an indentation-based language like Python)?
FWIW, I use Sublime Text 2 as my editor.
If you're using Ruby 1.9, try the -w flag when running your ruby program.
# t.rb
class Example
def meth1
if Time.now.hours > 12
puts "Afternoon"
end
def meth2
# ...
end
end
ruby t.rb
=> t.rb:10: syntax error, unexpected $end, expecting keyword_end
ruby -w t.rb
=> t.rb:5: warning: mismatched indentations at 'end' with 'if' at 3
t.rb:9: warning: mismatched indentations at 'end' with 'def' at 2
t.rb:10: syntax error, unexpected $end, expecting keyword_end
Source:
http://pragdave.blogs.pragprog.com/pragdave/2008/12/ruby-19-can-check-your-indentation.html
Edit (2023): this is now part of Ruby 3.2 and doesn‘t need to be required separately!
————————————
Edit (2022): the gem is now called syntax_suggest and is part of the Ruby standard library!
————————————
Since December 2020, there is also the dead_end gem which helps you detect missing ends.
The easiest way to get started is to install the gem:
gem install dead_end
and run it directly from your console, providing the file name to scan:
dead_end myfile.rb
This will provide you with a more helpful error message:
43 if (col_idx - 1) % 3 == 0
50 if !contains?(doc, node)
❯ 51 doc.add_child(node)
❯ 52 tree.
53 end
54 end
See the documentation for more options.
If you're using rails, you can run the problematic file specifically with the -w flag.
If you still can't find the offending mismatch, then my go-to way of solving this problem is just commenting out chunks of code until I can isolate the problematic area.
On OS X you can use command + / to comment out the highlighted piece of text.

SyntaxError for strings "#$" and "##"

Can someone explain this behavior to me?
>> "#$"
SyntaxError: (irb):3: unterminated string meets end of file
from /Users/milan/.rvm/rubies/ruby-1.9.2-head/bin/irb:16:in `<main>'
>> "##"
SyntaxError: (irb):4: syntax error, unexpected $undefined
(irb):4: unterminated string meets end of file
from /Users/milan/.rvm/rubies/ruby-1.9.2-head/bin/irb:16:in `<main>'
>> "#$$"
"10994"
Did I miss some new feature of 1.9.2? Confused.
As you probably know you can use #{ expression } inside a double quoted value to insert the value of expression into the string at that position. A little known sub-feature is that if the expression is just a global or instance variable, you can leave out the braces. I.e. #$foo inside a double quoted string will insert the value of the global variable $foo and ##foo will do the same for instance variables.
So your first two examples error out, because it thinks you want to get the variables $" or #" respectively (the latter of which is not a variable name - though the first one is - which is why you get two error messages for the second and just one for the first), leaving the string unclosed. And the third example simply gives you the value of the variable $$.
If you don't want this to happen you can escape the # with a backslash in front of it (or simply use single quotes instead of double quotes if you don't need any double-quote-specific behavior).
This behavior is not specific to ruby 1.9 - it has always been like this.

Resources