Can this Ruby error be caught with NeoVim/ALE/RuboCop/Syntastic? - ruby

I'm new to Ruby and doing some experimenting with NeoVim/ALE which I'm also new to. I'm coming from Perl using the syntastic plugin and I'm trying to figure out how to best set up NeoVim/ALE/RuboCop. I've never used a delinter before.
My confusion stems from this bit of code:
#!/usr/bin/env ruby
r = Array() # Improper array initialization, should be Array.new()
puts r
When run, I get:
Traceback (most recent call last):
1: from /Users/me/ruby/workshop/dink.rb:3:in `<main>'
/Users/me/ruby/workshop/dink.rb:3:in `Array': wrong number of arguments (given
0, expected 1) (ArgumentError)
RuboCop didn't catch this error. I turned syntastic on and it didn't catch the error either. I assume because it's a runtime error and not a compile time error like I thought it would be. Running ruby -c on the script yields no errors either. But perhaps I'm wrong and aren't using the syntax checking tools properly. Can someone please confirm that this is indeed a runtime error and that it's impossible to catch before executing the script?
I have a second question as well: Do I need syntastic with Ruby? Does it do anything more that RuboCop doesn't?
Thanks.

Both tools are correct, because there is the Array() method defined in Kernel.
That means this is not a syntax but a runtime error because that method expects at least one argument.
From the docs:
Array(arg) → array
Returns arg as an Array.
First tries to call to_ary on arg, then to_a. If arg does not respond to to_ary or to_a, returns an Array of length 1 containing arg.

Related

The called method `...' is defined here

Ruby 2.7 was just released and it comes with these new warnings for "Separation of positional and keyword arguments" (see their Release Post).
I was playing around with it and discovered that there's another warning, which I don't understand.
Example:
def multiply(x:, y:)
x * y
end
args = { x: 2, y: 3 }
multiply(args)
# ./warning.rb:7: warning: Using the last argument as keyword parameters is deprecated; maybe ** should be added to the call
# ./warning.rb:1: warning: The called method `multiply' is defined here
I think the first warning about the deprecation is clear, but the second warning The called method `multiply' is defined here is confusing to me.
What does the second warning mean? Is it related to the first warning?
Both warnings disappear when adding ** to the call (multiply(**args)).
What does the second warning mean? Is it related to the first warning?
There is a single warning with a text split into two lines. It literally says: args should be converted to **args, here is the call that produced this warning, here is its definition for your convenience.

Is Rubocop a superset of the "ruby -c" syntax check?

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.

Ruby Mocha expect the first argument to be a symbol

I'm trying to assert a method call happens where the first argument is a symbol like so:
Foo.bar(:some_key, {})
I don't really care what the second argument is at this stage.
I've tried:
Foo.expects(:bar).with(includes(:some_key))
and other variations found in the documentation here. The test passes when I expect the method call with any arguments.
Any ideas?
Have you tried this :
Foo.expects(:bar).with(:some_key, anything)
If you need to be more specific you can also use a block :
Foo.expects(:bar).with do |first_arg, second_arg|
first_arg == :some_key
end

Why is `a (b.c do;end)` not a syntactically correct Ruby program?

Why gives this code in ruby18 and ruby19 a syntax error:
a (b.c do;end)
I would have expected it to mean the following. A call to the method a with one argument. The parentheses after the space are not method argument parentheses, but only normal parentheses like you can put almost everywhere. The argument is the return value of the call to the method c on the object b with a block.
All of the following are however interpreted as syntactically correct by ruby18. Only the first of these examples is treated as syntactically incorrect by ruby19.
a (b do;end)
and:
a (b.c {})
and:
(b.c do;end)
Remove the space in between the method name and the (. Ruby used to warn that this was dodgy and it does seem to throw ruby 1.9 off in some cases.

trying to find a file/line for: .(eval):289: warning: don't put space before argument parentheses

So, I get this warning when I'm running my tests in ruby/RoR
.(eval):289: warning: don't put space before argument parentheses
I've checked every where (but obvoiusly not) and I can't find the origin of this error.
The above error just pops up inbetween the unit tests ...
Can someone clue me in onto how to find the location of this error?
The file and line number are contained in the backtrace. However, in your case, the warning is inside a string being evaled at runtime. Which means there is no file. (Actually, the eval method does take optional arguments for the file name and line number that should be displayed in a backtrace, but in this case whoever wrote the code in question unfortunately forgot to pass those arguments.)
I fear that you have no other choice than to manually examine every single call to eval in your entire codebase, and that includes Rails, your testing framework, your entire application, your tests, your plugins, your helpers, the ruby standard library, ...
Of course, you should be aware that the problem might not be obvious as in
eval 'foo (bar, baz)'
It could also be something like
def foo(*args)
puts args.join
end
bar = 'Hello'
baz = 'World'
foostr = 'foo' # in one file
barstr = 'bar' # in another file in a different directory
bazstr = 'baz' # in another file in a different directory
argstr = "(#{barstr}, #{bazstr})" # in yet another file
$, = ' ' # in some third-party plugin
str = [foostr, argstr].join # in a fourth file
eval str # somewhere else entirely
eval str, binding, __FILE__, __LINE__ # this is how it *should* be done
Note the difference between the two warning messages: the first one reads exactly like the one you posted, but the second one has the filename instead of (eval) and the line number inside the file instead of the line number inside the eval string.
By the way: the line number 289 in the warning message is the line number inside the evald string! In other words: somewhere in your application there is a string being evald, which is at least 289 lines long! (Actually, it is more likely that this done not in your application but rather in Rails. The Rails router used to be a particularly bad offender, I don't know if this is still the case.)
It sounds to me that there is a rule which forbids a space between a function name and the parentheses enclosing the arguments of the function.
In many languages this would be considered a permissible stylistic variation.
Is the eval mentioned in the warning message, the 'function' being complained about?
Does the number 289 mean anything as a line number?
Could you search your source files for a parenthesis preceded by a space?
Incidentally, the message says warning. What happens if you ignore it?
If it's happening in between the unit tests it might be in a setup or teardown method. Try searching for eval or try reducing the code you are running until the error goes away. Then you'll know where to look (the code you just removed).

Resources