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.
Related
We had a test that found every Ruby file in our application and ran ruby -c on it. We introduced Rubocop and made it check the same list of files.
Is the test that ran ruby -c actually now useless, or is there an example of a failure mode that would be caught by ruby -c but not Rubocop?
The documentation for ruby -c says:
Causes Ruby to check the syntax of the script and exit without executing. If there are no syntax errors, Ruby will print "Syntax OK" to the standard output.
This is an example of a syntax issue that will be caught by either:
% echo "puts 'hello world" > hot_script.rb
% ruby -c hot_script.rb
hot_script.rb:1: unterminated string meets end of file
% rubocop hot_script.rb
Inspecting 1 file
F
Offenses:
hot_script.rb:1:6: F: unterminated string meets end of file
(Using Ruby 1.9 parser; configure using TargetRubyVersion parameter, under AllCops)
puts 'hello world
^
1 file inspected, 1 offense detected
Rubocop even catches some of the same warnings, though I didn't have ruby -c configured to catch these previously, and I am therefore more interested in errors. Here's an example of relative parity in handling a warning:
% cat unused_var.rb
def hot_method
a = 1
b = 2
puts b
end
% ruby -cwW2 unused_var.rb
unused_var.rb:2: warning: assigned but unused variable - a
Syntax OK
% rubocop unused_var.rb
Inspecting 1 file
W
Offenses:
unused_var.rb:2:3: W: Lint/UselessAssignment: Useless assignment to variable - a.
a = 1
^
1 file inspected, 1 offense detected
I searched using
https://www.google.com/search?q=rubocop%20syntax%20check%20superset
https://www.google.com/search?q=is%20there%20any%20reason%20to%20run%20ruby%20-c%20syntax%20check%20if%20i%20use%20rubocop
but I may be doing it wrong. The test is way slower in Ruby 1.9 than it was in Ruby 1.8, so the answer to this question is actually valuable to me. And you have to admit, you're curious, right?
The answer is "most of the time." RuboCop builds on the parser gem, which is a standalone Ruby parser which mimics, more or less, the MRI parser. RuboCop wraps parser's syntax checks and will properly report issues. However, as stated on the parser's GitHub:
Unfortunately MRI often changes syntax in patch level versions
[...] there is no simple way to track these changes.
This policy makes it all but impossible to make Parser precisely
compatible with the Ruby MRI parser.
In addition, parser supports the latest minor version of whatever release you are using, and doesn't backport minor versions. So if you use Ruby 2.4.0, RuboCop will use a parser version supporting 2.4.1 syntax.
For all intents and purposes, parser is equivalent to the official MRI parser, and unless you have a specific reason to use both, using RuboCop alone should be sufficient.
Rubocop will also identify and report syntax errors since the code cannot be properly parsed if that is the case, so there's no need for both.
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.
I upgraded ruby from 1.9.3 to 2.0.0
After upgrading, I cannot run my script anymore because there are so many errors.
UPDATE
I updated the beginning part of my script.
errors
Bareword found where operator expected at D:\ex\report.rb line 12, near "$0
def"
(Missing operator before def?)
Bareword found where operator expected at D:\ex\report.rb line 18, near "usage"
(Missing semicolon on previous line?)
Semicolon seems to be missing at D:\ex\report.rb line 19.
syntax error at D:\ex\report.rb line 5, near "Encoding::UTF_8 require "
Execution of D:\jenkins_lab_a\asap.ex\asap-report-apps.rb aborted due to compilation errors.
script
# coding: utf-8
Encoding.default_external = Encoding::UTF_8
Encoding.default_internal = Encoding::UTF_8
require './lib/utils'
require './lib/klocwork'
require './lib/td'
require 'fileutils'
require 'logger'
if __FILE__ == $0
def usage
warn 'usage: report.rb [a] [b] [c]'
warn "ex) report.rb a b c"
exit
end
puts "report.rb start"
usage if ARGV.size < 3
end
I can see errors like this all over the script.
But I never changed my script and It is working well in the previous version.
So I think that I missed any environmental settings
Could you let me know what I can check to resolve this issue?
Those aren't Ruby error messages. You aren't running your Ruby files with a Ruby interpreter. There's no concept of "bareword" in Ruby, and semicolons are entirely optional, so it wouldn't report about them either.
When you come across numbers that look like this in Ruby code, what does it mean?
1r
Or
1.0r
Tested in Ruby 1.8.6 up to 2.0.0 and it fails. with something like this:
>> 1r
SyntaxError: unexpected tIDENTIFIER, expecting end-of-input
and
>> 1.0r
SyntaxError: unexpected tIDENTIFIER, expecting end-of-input
Probably downvoted for not searching, or something, or not enough examples. Hopefully this clarifies. It is just Ruby Code, it doesn't have to be specifically anywhere, just has to be there.
That is a new feature for Decimal/Rational Literals in Ruby 2.1. See here: http://rkh.im/ruby-2.1 (search for "Decimal Literals")
0.1r #=> (1/10)
0.1r * 3 #=> (3/10)
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.