I'm interested in querying the latest stable version of Ruby from the command line. I'm primarily interested in a string of the form "1.9.3p327".
Update #1
To clarify, the goal is to consistently query the latest stable version, whether that be 1.9.3p327 or 3.0.2p392.
Something like:
curl 'http://ftp.ruby-lang.org/pub/ruby/1.9/' | ruby ./extract-and-print-max-patchlevel.rb
Where the implementation of extract-and-print-max-patchlevel.rb script is an exercise for the reader but here's a start:
#!/usr/bin/env ruby
maxpatch=0
maxstr=nil
STDIN.each_line do |line|
next unless line =~ /1\.9\.3-p(\d+)\b/
patch = $1.to_i
if patch > maxpatch
maxpatch = patch
maxstr = $&
end
end
puts maxstr
Note that it assumes Ruby 1.9.3 is the latest, so you might want to revisit that.
Came back to this after starting to use rbenv. If you have rbenv installed, the following one-liner does the trick:
#!/usr/bin/env ruby
puts `~/.rbenv/bin/rbenv install --list`.split("\n").map{|item| item.strip}.select{|item| item[/^\d*\.\d*\.\d*/]}.reject{|item| (item.include? '-') && !(item =~ /-p\d*$/)}.last
You can play with sed or awk. For example:
curl "http://ftp.ruby-lang.org/pub/ruby/1.9/" | sed -E 's/^.*"(ruby-)(1.9.3-p[0-9]+)(.*)".*$/\2/' | sed -e '/^1.*/!d' | sort | sed '$!d'
I'm not sed expert and here could be better solution but this line works.
Choosing between #maerics' and #YevgeniyAnfilofyev's answers, I found the Ruby one more authentic and turned it into one-liner, assuming that the list from curl is already sorted, so we simply need the last line meeting the condition:
curl 'http://ftp.ruby-lang.org/pub/ruby/1.9/' 2> /dev/null | ruby -e "puts STDIN.lines.map { |x| /1\.9\.3-p\d+\b/.match(x) }.compact.last[0]"
Or, Ruby part expanded:
puts STDIN.lines.map do |x|
/1\.9\.3-p\d+\b/.match(x) # After such map we will get an array of MatchData or nils
end.compact.last[0] # Then we remove nils using Array#compact,
# get last MatchData and retrieve matched string with [0]
Following a good tradition, adding sorting to this script left as an excercise for the reader :)
UPD: Of course, hard-coded 1.9.3 is bad, but if we replace each digit 1, 9 and 3 with \d, the regex seems to become more or less independent. The other problem is that we only look into .../ruby/1.9 folder of that ftp. This may be fixed if we, instead, look into .../ruby folder first, and find all version-numbered folders with regex /\d\.\d\//. Then repeat the above query, joining results from all folders. But, of course, this already cannot made into a one-liner...
Related
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 trying to update a site generator at work. One of the things that must be done is editing the gitosis.conf file to add the repo to the right group. This is how that block is currently set up in my gitosis.conf file.
[group sites]
writable = site1 site2 site3 randomsite awesomeness
members = #devs
So after countless tries, I've made a few "advancements" and then some steps back.
sed -i"" -e"/sites/,\$s/writable.*/& PROJECTNAME/" gitosis.conf
I was finally able to get the code to work on the CentOS command line, but now if I try to run it in irb (running it in a ruby script with backticks, so this has to work) I get this error:
sed: -e expression #1, char 22: unknown command: `&'
=> ""
"char 22" may be incorrect because I've edited some of the words a little bit to make the example more vanilla.
This is what is actually in the ruby script.
gitosis = `sed -i"" -e"/sites/,\$s/writable.*/& PROJECTNAME/" gitosis.conf`
I've been searching everywhere to try to fix this, but so far I've come up with nothing. I've read various places that a better option is ruby -pe in order to keep it ruby, but I don't even know where to start with that. Any advice/input would be awesome. Thank you!
Well you don't really need to escape the $ variable. Try using this -
gitosis = sed -i"" -e "/70/,/$/s/75/& #{p}/" gitosis.conf
OR
gitosis = sed -i"" -e "/70/,$ s/75/& #{p}/" gitosis.conf
Though I am not too sure what are you planning to do with the variable that you are assigning this sed one-liner to. Since it is an in-line substitution, you will get a variable with nothing in it.
Well you can do it with sed, if you can't do it other way, you can always go without & like:
gitosis = `sed -i"" -e"/plexus/,\$s/\(writable.*\)/\1 #{projectname}/" gitosis.conf`
But with ruby you can parse and write .ini files and your ruby script will work without sed!
This is untested code, written on the fly, but should get you started toward using a pure-Ruby solution:
# [group sites]
# writable = site1 site2 site3 randomsite awesomeness
# members = #devs
FILENAME = 'gitosis.conf'
# bail if the group is missing from the command line
abort('Missing group to add') if (ARGV.empty?)
# read the file
contents = File.read(FILENAME)
# find and extract the "writable" line
writable = contents[/^writable.+$/]
# open the new file. This will automagically close it when done.
File.open("#{FILENAME}.new", 'w') do |fo|
# output the current file, replacing the current writable line with one containing the old
# contents with the added new group followed by a line-ending.
fo.print contents.sub(writable, writable + ' ' + ARGV.shift + "\n")
end
# add code here to handle moving/deleting/something with the old file and
# moving the new file into place.
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.
I'm trying to strip the version out of a package name using only Bash. I have one solution but I don't think that's the best one available, so I'd like to know if there's a better way to do it. by better I mean cleaner, easier to understand.
suppose I have the string "my-program-1.0" and I want only "my-program". my current solution is:
#!/bin/bash
PROGRAM_FULL="my-program-1.0"
INDEX_OF_LAST_CHARACTER=`awk '{print match($0, "[A-Za-z0-9]-[0-9]")} <<< $PROGRAM_FULL`
PROGRAM_NAME=`cut -c -$INDEX_OF_LAST_CHARACTER <<< $PROGRAM_FULL`
actually, the "package name" syntax is an RPM file name, if it matters.
thanks!
Pretty well-suited to sed:
# Using your matching criterion (first hyphen with a number after it
PROGRAM_NAME=$(echo "$PROGRAM_FULL" | sed 's/-[0-9].*//')
# Using a stronger match
PROGRAM_NAME=$(echo "$PROGRAM_FULL" | sed 's/-[0-9]\+\(\.[0-9]\+\)*$//')
The second match ensures that the version number is a sequence of numbers separated by dots (e.g. X, X.X, X.X.X, ...).
Edit: So there are comments all over based on the fact that the notion of version number isn't very well-defined. You'll have to write a regex for the input you expect. Hopefully you won't have anything as awful as "program-name-1.2.3-a". Absent any additional request from the OP though, I think all the answers here are good enough.
Bash:
program_full="my-program-1.0"
program_name=${program_full%-*} # remove the last hyphen and everything after
Produces "my-program"
Or
program_full="alsa-lib-1.0.17-1.el5.i386.rpm"
program_name=${program_full%%-[0-9]*} # remove the first hyphen followed by a digit and everything after
Produces "alsa-lib"
How about:
$ echo my-program-1.0 | perl -pne 's/-[0-9]+(\.[0-9]+)+$//'
my-program
According to this post, RDoc::usage is not currently available in ruby 1.9. Are there any good replacements available?
I'd be interested to hear what's available from the standard install as well as what's available from gems.
I like OptionParser (the thing that the article mentions that RDoc::usage is useful to complement).
It looks like any 1.9 bugs have been patched.
In feature request 2713, the rdoc maintainer has stated that he won't add rdoc/usage or any similar feature back to rdoc, saying that OptionParser should be used instead.
We use OptionParser for all new scripts,but had about 100+ that used RDoc. Instead of rewrite each one I wrote this method (BB is our company's namespace. change that to whatever you like ). It works great. The syntax is slightly different, but its help text so we don't mind. Hope it helps!
I then used sed to find all the scripts and change them.
grep -rl "RDoc::usage" * | xargs sed -i "/rdoc\/usage/ s/RDoc/BB/"
grep -rl "BB::usage" * | xargs sed -i "/rdoc\/usage/ s/rdoc/lib\/bb/"
-
module BB
def BB::usage( exit_code )
File::open( $0, 'r').readlines.each_with_index do | line, idx |
next if idx == 0
if( line =~ /^#/ )
puts line.gsub(/^#\ ?/,'')
else
puts #RDoc adds extra line so we do too
exit( exit_code )
end
end
end
end