Plough => Ruby Journey through ruby

Mina, the deployer

I recently decided to setup a dedicated website for my company as opposed to just using my personal one. It’s a static site, with barely any content right now.

Now, I usually rely on capistrano for deployment, but since capistrano had recently undergone a major facelift, I sensed it as an opportunity to try Mina. I have known about the gem since it’s very beginning, but the pressures of modern web developer life means less time for playing around, and more for getting things done. In other words, don’t change the deployer, if it ain’t broken.

Mina is very similar to Capistrano, except one small yet pivotal fact. Instead of running commands one-by-one over SSH, it creates a bash script from your configuration and executes it remotely as one SSH command. Sounds astute to me. It has the same configuration and deploy setup as Capistrano, and anyone with some Capistrano experience will pick it up pretty quickly.

One thing that really stuck out for me and propelled me to write this post is it’s reliance on the existing SSH set-up on your machine. For example, in Capistrano, one has to explicitly set up the ssh forward agent in the deploy script itself. But, in Mina, one just needs to specify forward agent in their SSH config, and Mina will pick that up. It’s quite logical, no idea why it wasn’t the case for Capistrano.

Anyways, hope this will motivate you guys to try Mina as well.

DTrace probes in Ruby 2 and a startling discovery

DTrace is a static and dynamic instrumentation framework. I did a talk at LRUG back in October on DTrace and it’s addition in Ruby 2. There’s not much content in the presentation, but it will give you a little pointers to the present situation of DTrace in general, and in Ruby.

The more I look into DTrace, the more I find it intriguing, challenging, surprising, and yet thoroughly enjoyable. Recently, I was refactoring some of the tests for a project, and the test suite takes forever to run, therefore, I decided to use Object.new for creating an instance of the interested object (stub the requests). Another colleague came along and commented…“Oh, why are you not using OpenStruct”. OpenStruct is handy, as it has a hash like structre, which means a method call that hasn’t been stubbed or instantiated will just return nil, just like a hash call when the key is absent from the hash.

I ran some quick benchmarks and here are the results:

Calculating -------------------------------------
         Struct.new       7341 i/100ms
         Object.new      57600 i/100ms
     OpenStruct.new       5462 i/100ms
-------------------------------------------------
         Struct.new     90353.5 (±10.0%) i/s -     447801 in   5.017170s
         Object.new   2335283.3 (±3.2%) i/s -   11692800 in   5.012149s
     OpenStruct.new     65014.7 (±4.9%) i/s -     327720 in   5.053209s

One thing is obvious, if you don’t need the dynamic nature of an OpenStruct, just use Object.new. This led me to think, why Object.new is superfast as compared to Struct or OpenStruct. I wanted to see what method calls is Struct or OpenStruct making, you know, just for my own knowledge. I decided to use DTrace for that purpose. DTrace has been added to Ruby 2, but I still couldn’t find any documentation. However, probes.d file gives a details of all the probe names, arguments in the probe and so on. Please look at that file if you’d like to use DTrace with ruby.

I created a simple ruby file called test.rb, like this:

Object.new

and ran the following dtrace command on a Mac OS X:

sudo dtrace -c 'ruby test.rb' -Zn 'ruby*::method-entry { @[copyinstr(arg0)] = count(); }'

to receive the following output:

dtrace: description 'ruby*::method-entry ' matched 2 probes
dtrace: pid 14009 has exited

  Gem                                                              12
  Gem::Requirement                                                 23
  Gem::Version                                                     36
  Gem::Specification                                              267
  RbConfig                                                        309

Here column 1 is the Class name and the column 2 is the number of times that class was accessed while running this ruby file. This was quite surprising that RbConfig was accessed 309 times. Why? After much thinking, I thought may be RVM has got a hand in this. I haven’t found a solution yet.

I leave you here with this startling discovery and hope to solve it for my next post. I’m planning to run the same dtrace command with ruby installed via rbenv and see what I get and then go from there.

OpenStruct to hash

OpenStruct is a handy class in ruby’s stdlib. I’ve used it in the past for creating test data, instead of using factory girl. It’s fast, and the fact that it behaves like a Hash, makes it super easy for stubbing object behaviours.

The other day, I had this requirement to convert an open struct instance into a hash. I foolishly tried to_hash call, considering that it acts as a hash, so there must be a to_hash call on it. But, unfortunately, there isn’t any to_hash methods on OpenStruct. However, there are other ways to convert an open struct instance to a hash quite easily. Here’s how:

Option 1

os = OpenStruct.new(:id => 12)
os.marshal_dump # returns the hash {:id=>12}

Option 2

os = OpenStruct.new(:id => 12)
os.instance_variable_get(:@table) # returns the hash {:id=>12}

In Ruby2, inspect independent of to_s

Ruby 2.0.0 has been released and there are a lot of new things, for example, keyword arguments, TracePoint API, DTrace and so on. Here’s Ruby NEWS file, and some new features in Ruby 2.

One thing to add to that list is that the behaviour of inspect is no longer dependent on to_s. In Ruby 1.9, if to_s was overridden inspect would just execute that code. But in Ruby 2.0, to_s overriding doesn’t affect inspect anymore. Here’s code example for Ruby 1.9.3 and Ruby 2

Installing any Ruby source on your local machine with RVM

Update: This approach doesn’t work with the latest version of rvm (1.17.0 stable)

Now, if you are like me you probably have ruby source checked out on your machine to ensure that you stay informed with the newest features and ponder through the ruby source at will. I started wondering what if I want to install the ruby from the source and test my gems out and test it against well-known libraries to see how they fare. Firstly, I thought of doing the ./configure -> make -> make install dance but then I realised…yes you’re absolutely right, why not use RVM.

What RVM? I must be out of mind.

But, hey, RVM downloads ruby source code and installs it on your machine. The only difference is that I have got the ruby source checked-out on my machine and I want to use that as the source. And yes, RVM is awesome. I have spoken to Wayne (via IRC) and the man is an absolute genius, very polite and helpful.

So, somehow, I need to accomplish the following:

  • Hey RVM, don’t download the ruby source.
  • Here’s the location of the ruby source, use that and install it.
  • Voila!

But, how do I do that? I started looking at RVM source code and I am not an expert at bash scripting, so I figured why not just mail RVM mailing list. I got the following helpful response from Micheal Papis.

it's not yet supported to use sources/rubies provided by user, but it
will be in rvm 2.0

as for using it now, you could use $rvm_path/src - and provide your
sources there ... not sure how it will work, you have to experiment a
bit

That clue was enough for me and like he said, I experimented a little bit. When you run something like:

rvm install ruby-1.9.2

RVM downloads the source code into $rvm_path/repos, moves it over to $rvm_path/src and then does the configure, compile dance. I created a symlink in $rvm_path/repos pointing at the local ruby git repository on my machine. And, then I ran the install command. Here’s the output I get:

~/.rvm/src$ rvm install ruby-head
Installing Ruby from source to: /Users/andhapp/.rvm/rubies/ruby-head, this may take a while depending on your cpu(s)...

ruby-head - #fetching 
HEAD is now at 02035ba Merge branch 'trunk' of git://github.com/ruby/ruby into trunk

From github.com:andhapp/ruby
 * branch            trunk      -> FETCH_HEAD
Already up-to-date.
Copying from repo to src path...
ruby-head - #configuring 
ruby-head - #compiling 
ruby-head - #installing 
Retrieving rubygems-1.8.10
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  243k  100  243k    0     0   456k      0 --:--:-- --:--:-- --:--:--  540k

Extracting rubygems-1.8.10 ...
Removing old Rubygems files...
-e:1: Use RbConfig instead of obsolete and deprecated Config.
Installing rubygems-1.8.10 for ruby-head ...
Installation of rubygems completed successfully.
ruby-head - adjusting #shebangs for (gem irb erb ri rdoc testrb rake).
ruby-head - #importing default gemsets (/Users/andhapp/.rvm/gemsets/)
Install of ruby-head - #complete 

This line ‘HEAD is now at 02035ba Merge branch ‘trunk’ of git://github.com/ruby/ruby into trunk’ is the last commit message on my local ruby git repository.

This line ‘From github.com:andhapp/ruby’ reflects the fact that rvm is using my git repository and not ruby’s repository and updating the local source to the latest before installing.

I decided to call the ruby installation ruby-head. You can call it anything you fancy.

Here’s the version on my machine now:

~/.rvm/src$ rvm use ruby-head
Using /Users/andhapp/.rvm/gems/ruby-head
~/.rvm/src$ ruby -v
ruby 2.0.0dev (2011-12-03 trunk 33936) [x86_64-darwin10.8.0]

Awesome!

PS: I am sure there are other details about RVM’s installation procedure that I have missed out and Wayne or Micheal will be kind enough to enlighten me.