Notes posted by Mange

RSS feed
February 3, 2009
3 thanks

Nothing here

You’re probably looking for I18n::Backend::Simple.

January 22, 2009
2 thanks

Correct way to quote for the shell

A followup for my previous comment;

I actually found a good way to handle quoting for the shell in Ruby 1.9 in case you really need to (for example to pipe the output from the examples I gave below).

require 'shellwords'

escape = lambda { |str| Shellwords.shellescape(str) }
file = %(Peter "Smiley" McGraw.txt)
puts "grep foobar #{escape[file]} > foobars"
  # => grep foobar "Peter \"Smiley\" McGraw.txt" > foobars

Do note that I have not tested this since I do not have Ruby 1.9 installed, but from what I have read, this should work properly there.

I still do not know a good way to do this in Ruby 1.8.

January 15, 2009
4 thanks

Convert String to Class in Rails

ncancelliere gave us a very useful tip below, and I just want to make an addendum for it:

If you are using Rails, there is a CoreExtension for this called String#constantize.

"Foo::BarKeeper".constantize #=> Foo::BarKeeper

You can use it with String#camelize if you have to convert the name too

"foo/bar_keeper".camelize             #=> "Foo::BarKeeper"
"foo/bar_keeper".camelize.constantize #=> Foo::BarKeeper

Don’t forget to rescue NameError in case there was an invalid class name. :-)

January 12, 2009
2 thanks

A word of warning

This method returns the supplied string with double quotes around it if it has a space in it, otherwise leaves it alone.

This is useful when sending paths to the shell or any similar operations. Here is a small demonstration of how it works and why it would be useful:

def cat(term)
  puts "cat #{term}"

def cat_q(term)
  puts "cat #{term.quote}"

# No difference without whitespace
cat   "hello.txt"       #=> cat hello.txt    -- OK!
cat_q "hello.txt"       #=> cat hello.txt    -- OK!

# With whitespace
cat   "hello world.txt" #=> cat hello world.txt    -- Error
                        #   trying to find "hello" or "world.txt"

cat_q "hello world.txt" #=> cat "hello world.txt"   -- OK!

Watch out if you want to do things securely, since this method does not escape quotes that are already there!

cat_q 'Peter "Smiley" McGraw.txt' #=> cat "Peter "Smiley" McGraw.txt" -- ERROR!

It is possible to insert fork bombs and other dangerous stuff by taking advantage of this, and that might take down the whole machine, steal data or delete data depending on the rights of the user executing the script.

The insecurity might also transfer into other areas in case you are not using this method for the shell, but for something else.

Please do note that most of these problems can be avoided if you just split the arguments in Ruby when doing system calls, which is easier to do most of the time.

quoted_files = file_list.collect { |f| f.quote }  
system("grep #{search.quote} #{quoted_files.join(' ')}")

system("grep", search, *file_list) # Much easier!

So, in summary: You should only use this method if you know what you’re doing! It’s neither secure nor needed in most (but not all) cases.

January 8, 2009
10 thanks

Refactoring excessive code for selects

@garg: It is not recommended to have excessive code in the views. You should refactor your code a bit.

<%= f.select(:manufacturer_id, Manufacturer.find(:all).collect {|u| [u.name, u.id]}, :prompt => 'Select') %>

could be changed to this:

# in app/helpers/manufacturer_helper.rb
def manufacturers_for_select
  Manufacturer.all.collect { |m| [m.name, m.id] }

# in the view
<%= f.select(:manufacturer_id, manufacturers_for_select, :prompt => 'Select') %>

I would look into collection_select though:

<%= f.collection_select(:manufacturer_id, Manufacturer.all, :id, :name, :prompt => 'Select') %>

It’s much more clean and you don’t have to define a helper for it to be readable (altough it’s still quite long).

If you have to do this often, you should define a FormBuilder extension, so you get methods like f.manufacturer_select:

<%= f.manufacturer_select(:manufacturer_id, Manufacturer.all) %>

IMO, most projects should have a custom form builder anyway, so the addition would be very small. This is my personal opinion, so you don’t have to listen to it. :-)

January 8, 2009
5 thanks

Watch out for syntax errors

Watch out when you are using returning with hashes. If you would write code like

def foo(bars)
  returning {} do |map|
    bars.each { |bar| map[bar.first] = bar }

you will get a syntax error since it looks like you tried to supply two blocks! Instead you should write it with parenthesis around the hash:

def foo(bars)
  returning({}) do |map|
    bars.each { |bar| map[bar.first] = bar }