1. `dos2unix` and `unix2dos` on Ubuntu Linux

    If you’ve got used to using dos2unix and unix2dos and you miss them in recent Ubuntu Linux distributions, here’s a recipe how to get them back:

    # apt-get install tofrodos
    # cd /usr/bin/
    # ln -s fromdos dos2unix
    # ln -s todos unix2dos
    
     
  2. `String#split` without arguments does a good job of command input parsing

    I think this example pretty much speaks for itself:

    >> "    do   \t\n  some   stuff   ".split
    => ["do", "some", "stuff"]
    

    You don’t even need to strip your input.

     
  3. Ruby 1.9’s better `Float#round`

    Try this in IRB:

    >> 1.3333333333.round(2)
    => 1.33
    

    If you care about compatibility, keep in mind that under 1.8.7 it yields nothing less but:

    >> 1.3333333333.round(2)
    ArgumentError: wrong number of arguments (1 for 0)
    
     
  4. Strange `#`-comment behaviour in multiline `eval` blocks

    I do a lot of metaprogramming, which sometimes involves multiline eval blocks. Those blocks are actually part of the program, which are subject to debugging. As we all know, one of the most accessible debugging methods is commenting stuff out.

    There’s one little feature we should be aware of when using multiline eval blocks: the #-comment might not work as we expect it to.

    Consider this example:

    eval %{
      puts "Setting name"
      @name = "Joe"
    }
    

    Fairly primitive, should obviously work. Now let’s suppose that we want to temporarily comment out the @name = line.

    eval %{
      puts "Setting name"
      #@name = "Joe"
    }
    

    Looks quite regular, but now this stuff happens:

    SyntaxError: (eval):3: syntax error, unexpected '=', expecting $end
         = "Joe"
          ^
    

    First, the workaround. Use more than one # character or put a space bar between # and @name. Both should work:

    • ##@name = "Joe"
    • # @name = "Joe"

    Second, the explanation. Try this in IRB:

    >> @s = "xys"
    >> "#@s"
    => "xyz"
    

    Aha! Ruby interpreter (both 1.8 and 1.9, by the way) treats #@var as an interpolation token. So now we know why the original example crashed: we tried to comment out @name =, put a hash sign before it, but inadvertently turned it into an interpolation statement.

    Moral:

    • Ruby isn’t to blame.
    • eval isn’t to blame.
    • String interpolation isn’t to blame.
    • Just pay a little more attention to special chars sitting next to # in string values. :)
     
  5. `File.expand_path` doesn’t always produce a real (absolute) path

    File.expand_path is one of the most useful path manipulation methods I use in almost every Ruby file. If you also use it often, please keep in mind that it doesn’t always convert symlinks to real paths.

    >> File.expand_path("~/.irbrc")     (1)
    => "/home/alexrb/.irbrc"
    >> File.expand_path(".irbrc")       (2)
    => "/.devel/home/alexrb/.irbrc"
    

    My /home/alexrb is actually a symlink to /.devel/home/alexrb:

    >> ENV["HOME"]
    => "/home/alexrb"
    >> File.realpath ENV["HOME"]
    => "/.devel/home/alexrb"
    

    Note that example (2), based on current directory, did produce an absolute path, whereas (1) didn’t.

    Conclusion: If you want real path for sure, use File.realpath on top of File.expand_path.

     
  6. Filtering RSpec examples

    A single spec file may contain hundreds of examples. What if we want to stay focused on a particular one and skip the others for now? In other words, how do we filter?

    Up to this writing RSpec (2.11) supports the following ways to filter examples:

    • By line number in the spec file (-l).
    • By description string (-e).
    • By tag (-t).

    Filtering by line number:

    $ rspec some_spec.rb -l 159
    

    Filtering by description string:

    $ rspec spec/models/user_spec.rb -e "User is admin"
    

    Filtering by tag:

    it "should generally work", :focus do
      true.should == true
    end
    
    $ rspec some_spec.rb -t focus
    

    I’ve been using all three methods for quite a while now. Filtering by line number seems to be by far the most versatile and frequently used way. Does your experience differ from mine?

     
  7. Yield control back to `EventMachine`

    Suppose we’re listening to a message queue within an EventMachine scope. Suppose we’ve got a message, but it’s not the one we’re expecting, so we’d like to skip it hassle-free. How can we pass control back to EM without having to wrap everything in a long if?

    The short answer is: use next. Example follows.

    EventMachine.run do
      queue.subscribe do |message|
        if not message.match /known_to_us/
          puts "Unknown message, skipping (message:#{message.inspect})"
    
          # Yield control back to EventMachine.
          next
        end
    
        # Proceed with reply.
        ...
      end
    end
    
     
  8. Runnning RabbitMQ’s `rabbitmqctl` as non-root

    I’ve been developing an AMQP application recently using RabbitMQ. Its control application rabbitmqctl, is allowed to be run by root and rabbitmq users only, which causes a bit of pain every time I want to list queues, exchanges etc. from my regular development shell.

    Hence this little hack to allow certain users to run rabbitmqctl. The recipe is for Ubuntu Linux, but should work for any Unix with a pinch of salt.

    There’s a group called rabbitmq. We’ll set it up the way all members of this group will be allowed to run rabbitmqctl without pain.

    • Create /etc/sudoers.d/rabbitmqctl:

      # Allow members of `rabbitmq` run `rabbitmqctl` without a password.
      %rabbitmq ALL=(ALL) NOPASSWD: /usr/sbin/rabbitmqctl
      
    • Fix permissions of this file, or sudo will carp every time we run it:

      # chmod 440 /etc/sudoers.d/rabbitmqctl
      
    • Create /etc/profile.d/rabbitmqctl.sh:

      if [ `id -u` != 0 ]; then
        alias rabbitmqctl="sudo /usr/sbin/rabbitmqctl"
      fi
      
    • Add intended members to group rabbitmq. Edit /etc/group:

      rabbitmq:x:120:alex,bob,carl
      
    • Re-login as one of group members and give it a try:

      $ rabbitmqctl list_vhosts
      

    Should work. If it doesn’t, use the “Comments” box below. :)

     
  9. Usage of `change_column_default` in a `def change` causes an `IrreversibleMigration`

    Ability to use just one method, def change in Rails 3 migrations is a neat feature, but be sure to test that your migration works in both directions before you rely on it completely.

    One of the features that sadly does not work in a def change is change_column_default. Consider an example:

    def change
      [:users, :is_special].tap do |table, column|
        add_column table, column, :boolean, null: false, default: false
        change_column_default(table, column, nil)
      end
    end
    

    Works fine when we do a db:migrate:up, but at db:migrate:down it yields:

    ==  AddIsSpecialToUsers: reverting ============================================
    rake aborted!
    ActiveRecord::IrreversibleMigration
    

    I switch to good old def up and def down in this case.

     
  10. It’s not possible to create a local variable via `eval`

    Consider this IRB snippet:

    >> eval("v = 1")
    >> v
    NameError: undefined local variable or method `v' for main:Object
    

    That’s Ruby 1.9.

    In Ruby 1.8 it was possible to create locals via eval, but that’s generally due to lack of proper optimization.

    Yakihiro explains the mechanics behind it.

    To keep it short: In Ruby 1.9 locals are created compile-time. eval is dynamic and has its own scope. If the local exists, eval will assign it. If not, it will stay private to eval's scope.