Replacement for rdoc usage - ruby

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

Related

How to show only the matching portions (mimicing the "-o, --only-matching" grep option) in Ruby?

Unix grep has a simple -o, --only-matching option to show only the part of a matching line that matches PATTERN.
What is the simplest way to mimic that behaviour in Ruby, either using the grep method or any other standard method (without exec or gems)?
Example given:
File.open('test.css','r') do |file|
file.each_line do |line|
match=/p[A-Z]+/.match(line)
puts match.to_s unless match.nil?
end
end
would mimic grep -oE "p[A-Z]+" test.css.
I suppose there are better (cleaner and more concise) ways.
Taking advantage of #avinash-raj, I ended up with this:
puts File.open('test.css','r'){|f| f.read.scan(/p[A-Z]+/)}
It seems a good deal for file that doesn't take up too much memory space.
Still open to other solutions.
Use String#scan to get an array of all matches:
File.foreach('test.css') do |line|
line.scan(/p[A-Z]+/).each do |match|
puts match
end
end

Update var in ini file using bash

I am attempting to write a bash script to configure various aspects of a server. The context here is replacing a value of a variable in a conf file (ini format) with another value.
The context is
[ssh-iptables]
enabled = false
And I simply need to change false to true.
Typically I'd just do this with a simple bit of sed
sed -i 's/^enabled = false/enabled = true/g' /etc/fail2ban/jail.conf
But enabled = false exists in multiple places.
I've tried using awk with no success
awk -F ":| " -v v1="true" -v opt="enabled" '$1 == "[ssh-iptables]" && !f {f=1}f && $1 == opt{sub("=.*","= "v1);f=0}1' /etc/fail2ban/jail.conf
The above was sourced from this forum thread but I don't really have enough understanding of how to use it in scripts to make it work. All it seems to do is the equivalent of cat /etc/fail2ban/jail.conf
I have found a few other scripts which are considerably longer which isn't ideal as this will happen to loads of ini files so I'm hoping someone can help me correct the above code or point me in the right direction.
Apologies if this belongs on ServerFault, but as it's scripting rather than the intricacies of server configuration itself I figured here might be more apt.
Assuming your format is that there are no square-bracket lines (like [ssh-iptables]) within sections, I would use your solution above (with sed) but restrict the query to within that block like so:
sed -i '/^\[ssh-iptables\]$/,/^\[/ s/^enabled = false/enabled = true/' /etc/fail2ban/jail.conf
The extra part at the beginning tells the following substitution statement to only run between the line that is [ssh-iptables] and the next one that starts with a [. It uses two regular expressions separated by a comma which indicate the bounds.
If you are open to use external applications, you could be interested into the use of crudini.
Example:
[oauth2provider]
module = SippoServiceOAuth2Provider
backend[] = none
wiface = public
; [calldirection]
; module = SippoServiceCallDirection
; backend[] = none
; wiface = internal
A standard grep will not filter commented exceptions.
With crudini things for consulting, setting and modify are easier:
$ crudini --get /myproject/config/main.ini oauth2provider wiface
public
$ crudini --get /myproject/config/main.ini calldirection wiface
Section not found: calldirection
I was on a bash-only app and moved to this approach. Just a suggestion.
Regards,
You might consider using m4 instead of sed in this case. This uses variable replacement and I think keeps the file looking readable. Your m4 template might look like this:
[ssh-iptables]
enabled=SSH_IPTABLES_ENABLED
Now, you call m4 with the following parameters (which can be called from a bash script):
m4 -DSSH_IPTABLES_ENABLED=true input.m4 > output.ini
or:
m4 -DSSH_IPTABLES_ENABLED=false input.m4 > output.ini
This is an overly simple way of using m4, if you read about it you'll find you can do some really nifty things (this is the infrastructure upon which autoconf/automake was initially designed).
awk '/^[ssh-iptables/ {ok=1}
ok==1 && $0="enabled = false" {print " enabled = true"; ok=0 ; next}
{print $0} ' infile > tmp
mv tmp infile

How to get latest stable Ruby version from command line?

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...

Sed Issues in Ruby

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.

Any way to automagically `puts` the last expression in a Ruby script?

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.

Resources