I want to run a test file:
# xxx.rb
require 'test/unit'; class XTest < Test::Unit::TestCase; def test_xxx; end; end
Until ruby 1.9.2
ruby -Itest -e "require './xxx.rb'" - -v
did the job, with 1.9.3 I suddenly get:
/usr/local/rvm/rubies/ruby-1.9.3-rc1/lib/ruby/1.9.1/test/unit.rb:167:in
`block in non_options': file not found: - (ArgumentError)
(it tries to load the file '-' which does not exist)
Any ideas how to get the verbose mode back / to pass options to test::unit ?
Correct output would look like:
Loaded suite -e
Started
test_xxx(XTest): .
Try it with a double-dash:
ruby -Itest -e "require './xxx.rb'" -- -v
Or like this (no dashes, no require):
ruby -Itest xxx.rb -v
To explain, I think that in your example you are using a single dash which commonly means 'use stdin as a file'. You could do this, for example:
cat xxx.rb | ruby -Itest - -v
Double-dashes are used to stop argument parsing and hence pass the -v to test unit. As to why your example with a single dash worked up to 1.9.3... I'm guessing that prior to 1.9.3 ruby wasn't as strict when you specify stdin but don't have anything coming in on stdin (as you don't).
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 understand what the following warning means:
-:1: warning: useless use of a variable in void context
But I don't understand why ERB in Ruby 1.8.7 generates code that uses _erbout variable in void context:
$ rvm use ruby 1.8.7
Using /Users/radeksimko/.rvm/gems/ruby-1.8.7-head
$ touch test.erb
$ erb -x test.erb
_erbout = ''; _erbout
$ erb -x test.erb | ruby -w
-:1: warning: useless use of a variable in void context
This is not a problem in ERB / Ruby 2.0.0+ though as ERB generates code from the template differently:
$ rvm use 2.0.0
Using /Users/radeksimko/.rvm/gems/ruby-2.0.0-p598
$ erb -x test.erb
#coding:ASCII-8BIT
_erbout = ''; _erbout.force_encoding(__ENCODING__)
$ erb -x test.erb | ruby -w
$
To be clear, this has nothing to do with _ (underscores) treating in variable names in between Ruby versions:
$ rvm use 2.0.0
Using /Users/radeksimko/.rvm/gems/ruby-2.0.0-p598
$ echo "erbout = ''; erbout" | ruby -w
-:1: warning: possibly useless use of a variable in void context
$ rvm use 1.8.7
Using /Users/radeksimko/.rvm/gems/ruby-1.8.7-head
$ echo "erbout = ''; erbout" | ruby -w
-:1: warning: useless use of a variable in void context
Is this a bug that should be reported to Ruby/ERB core or am I just misunderstanding something?
The warning is caused by the second line:
_erbout = '';_erbout
which does nothing (_erbout is a local variable in that scope), and it is in a context where is does not return the value of the line (like in a last line of a method).
In Ruby 2.0.0 this line is replaced with
_erbout = '';_erbout.force_encoding(__ENCODING__).
Now ruby does not know for sure if the method call has any side-effects or not, so the warning is not raised.
You can reproduce this with the following code:
useless.rb
def test_me
unused = 1
unused
3
end
p test_me
$ ruby -w useless.rb
useless.rb:3: warning: possibly useless use of a variable in void context
3
All this happens, because the output of erb -x is not supposed to be run on its own. When running a ruby script, the last line is not used as return value, unlike a method.
If you embed the code in a program, and actually use the _erbout, the warning will not be shown.
I am not a Ruby developer, but I'm trying to use 1 line of Ruby script to increment a 3-part version number for a Grails application that we're building with Jenkins. The version number is stored in a simple properties file called application.properties. I know there's tons of ways to do this, but my question here is specific to Ruby and why it's not working.
For testing, I reduced application.properties to a single line:
app.version=0.2.8
All I want to do is increment the last number. That's it. So, I found some code online and hacked it a bit:
ruby -pi.bak -e 'sub(/^app\.version=(\d+)\.(\d+)\.(-?\d+)/) { "app.version=#{$1}.#{$2}.#{$3.to_i.next}" }' application.properties
This code works perfectly on Ruby 1.8.7 on OS X, but fails on Ruby 1.9.3 on Linux:
-e:1:in `sub': wrong number of arguments (1 for 1..2) (ArgumentError)
from -e:1:in `sub'
from -e:1:in `<main>'
Note that the expression works on Linux if applied directly to a string literal:
ruby -e 'puts "app.version=0.2.8".sub(/^app\.version=(\d+)\.(\d+)\.(-?\d+)/) { "app.version=#{$1}.#{$2}.#{$3.to_i.next}" }'
I also tried gsub but that didn't work either (but for a different reason).
I must be missing something simple here. I've tried other examples using a closure with sub() and it seemed to work fine.
Since BernardK suggested that not all versions of Ruby treat -p the same, and since my code worked when applied to a string literal, then here is a solution that works on both 1.8.7 and 1.9.3. Create a file called incAppVersion.rb:
if $_ =~ /^\s*app\.version\s*=/
print $_.sub(/(\d+)\.(\d+)\.(-?\d+)/) { "#{$1}.#{$2}.#{$3.to_i.next}" }
else
print $_
end
and run it with:
ruby -ni.bak incAppVer.rb application.properties
-n is cool!
Please feel free to offer suggestions for improvement.
$ ruby -pi.bak -e'$_.chomp!; $_ = $_[0..-2] + $_[-1, 1].succ + "\n" if $_[0..11] == "app.version="' application.properties
As the Pickaxe(*) explains for -p : Places your program code within the loop while gets; ...; print; end.
gets puts the line just read into $_.
chomp! removes CRLF.
print without arguments prints $_, thus we must modify $_ : $_ = ...
$_[0..-2] is the input line except the last character
$_[-1, 1] is the last character, for a length one (needed in Ruby 1.8 to get a char, not a number)
$_[-1, 1].succ is the next character/number
+ "\n" to put CRLF again (change it to "\r\n" on Windows)
if $_[0..11] == "app.version=" to process only the desired property
$ ruby -v
ruby 1.9.2p320 (2012-04-20 revision 35421) [x86_64-darwin12.2.0]
Tested on OS X ML.
File before :
app.version=0.2.8
line2
File after two executions :
app.version=0.2.10
line2
(*) http://pragprog.com/book/ruby3/programming-ruby-1-9
I'm working on implementing Project Euler solutions as semantic Ruby one-liners. It would be extremely useful if I could coerce Ruby to automatically puts the value of the last expression. Is there a way to do this? For example:
#!/usr/bin/env ruby -Ilib -rrubygems -reuler
1.upto(100).into {|n| (n.sum.squared - n.map(&:squared).sum)
I realize I can simply puts the line, but for other reasons (I plan to eval the file in tests, to compare against the expected output) I would like to avoid an explicit puts. Also, it allots me an extra four characters for the solution. :)
Is there anything I can do?
You might try running it under irb instead of directly under a Ruby interpreter.
It seems like the options -f --noprompt --noverbose might be suitable (.
#!/usr/bin/env irb -f --noprompt --noverbose -Ilib -rrubygems -reuler
'put your one-liner here'
The options have these meanings:
-f: do not use .irbrc (or IRBRC)
--noverbose: do not display the source lines
--noprompt: do not prefix the output (e.g. with =>)
result = calculate_result
puts result if File.exist?(__FILE__)
result of eval is last executed operation just like any other code block in ruby
is doing
puts eval(file_contents)
an option for you?
EDIT
you can make use of eval's second parameter which is variables binding
try the following:
do_not_puts = true
eval(file_contents, binding)
and in the file:
....
result = final_result
if defined?(do_not_puts)
result
else
puts(result)
end
Is it an option to change the way you run scripts?
script.rb:
$_= 1.upto(100).into {|n| (n.sum.squared - n.map(&:squared).sum)
invoke with
echo nil.txt | /usr/bin/env/ruby -Ilib -rrubygems -reuler -p script.rb, where nil.txt is a file with a single newline.
How do I have my ruby script output what version of ruby is running it?
The RUBY_VERSION constant contains the version number of the ruby interpreter and RUBY_PATCHLEVEL contains the patchlevel, so this:
puts RUBY_VERSION
outputs e.g. 2.2.3, while this:
puts RUBY_PATCHLEVEL
outputs e.g. 173. Together it can be used like this:
ruby -e 'print "ruby #{ RUBY_VERSION }p#{ RUBY_PATCHLEVEL }"'
to output e.g. ruby 2.2.3p173
For reference, here's how variables and constants work, along with a list of Ruby's built-in variables and constants: Ruby Programming/Syntax/Variables and Constants and Pre-defined Variables.
You can get a list of all the global constants here, including RUBY_VERSION and friends, in the official Ruby language documentation.
For the bonus round, this will tell you some more useful info about your Ruby environment using RbConfig:
require 'rbconfig'
puts Config::CONFIG.sort_by{ |n,v| n.downcase }.map{ |n,v| "#{n} => '#{v}'" }