Categories
About

Nodeta is a software development company that focuses on web software. We employ a highly agile and effective process. We have worked both on light independent projects and in the environment of large global enterprises.

Archives

APIdock in Textmate

Mikael Roos February 23rd, 2009

First came Vim, and next Gaizka added APIdock integration to Emacs. Now perhaps the biggest favorite of most Ruby and Rails developers, myself included: Textmate! Courtesy of one of Nodeta’s own, Ville Lautanala aka Lautis, you can get the Textmate bundles with APIdock goodness for Ruby and Rails from github with just a couple of simple git commands:

% mkdir -p ~/Library/Application\ Support/Textmate/Bundles
% cd ~/Library/Application\ Support/Textmate/Bundles
% git clone git://github.com/lautis/ruby-on-rails-tmbundle.git "Ruby on Rails.tmbundle"
% git clone git://github.com/lautis/ruby-tmbundle.git "Ruby.tmbundle"
% osascript -e 'tell app "TextMate" to reload bundles'

Now, the keyboard shortcut

Control+h

gets you the page for the current word from APIdock.

Ruby 1.8.7 imported

Otto Hilska January 16th, 2009

I just finished importing Ruby 1.8.7 to APIdock. It’s also the new default version, because usually it is better documented. However, there’re some incompatibilities between 1.8.6 and 1.8.7, so be sure to check the older documentation when something seems to be wrong.

Ruby 1.8.6 is not compatible with Ruby 1.8.6

Otto Hilska May 29th, 2008

In Euruko 2008 Matz was participating in a panel discussion about Ruby/Win32 support. That’s where we heard one of the best Matz quotes: “I don’t use Windows, so I don’t care”

We already had this picture on our scrum board to remind us about the driving forces of Ruby programming language, but today it hit my face again: it’s not guaranteed that all Ruby 1.8.6 installations are compatible with other Ruby 1.8.6 installations.

The first release of 1.8.6 is quite old now, but there’re already 114 patches silently added to the release. None of these made it to the news section of ruby-lang.org.

This was concretized today when I was deploying rails-doc.org to a new server: the REXML library (which is a part of standard Ruby library) didn’t have REXML::Formatters available. The whole REXML library had gone through some major refactoring between different 1.8.6 patch releases. Well, “I don’t use XML, so I don’t care”.

By the way, JRuby 1.1.2 was released a couple of days ago. Go grab it. They even seem to have some kind of a release process. :)

Living on the edge: JRuby + Merb + Glassfish

Otto Hilska May 22nd, 2008

I spent practically my whole evening setting up JRuby + Merb + Glassfish, so I thought I’d share my experience with those of you who are wondering if JRuby (with real threading) + Merb could be what you’re looking for in terms of scalability and ease of deployment.

Btw, everything was done on a pretty standard Ubuntu server. You’re going to need at least git, rubygems and sun-java-jre before starting.

Setting up JRuby

This is the easiest part. Just download it from JRuby.org and extract it somewhere:

vodka:~% tar zxvf jruby-bin-1.1.1.tar.gz
vodka:~% mv jruby-1.1.1 jruby
vodka:~% export PATH="/home/mutru/jruby/bin:$PATH"
vodka:~% jirb
irb(main):001:0> puts "This must be JRuby"
This must be JRuby

Setting up Merb

This was not as straight-forward as it could’ve been. I had no luck with Merb 0.9.3 (gem), so I had to get it manually. But first, some dependencies:

vodka:~% jruby -S gem install erubis rake json_pure rspec rack hpricot mime-types rubigen
JRuby limited openssl loaded. gem install jruby-openssl for full support.
http://wiki.jruby.org/wiki/JRuby_Builtin_OpenSSL
Updating metadata for 380 gems from http://gems.rubyforge.org/
complete
Successfully installed abstract-1.0.0
Successfully installed erubis-2.6.0
Successfully installed rake-0.8.1
Successfully installed json_pure-1.1.2
Successfully installed rspec-1.1.3
Successfully installed rack-0.3.0
Successfully installed hpricot-0.6-java
Successfully installed mime-types-1.15
Successfully installed activesupport-2.0.2
Successfully installed rubigen-1.3.2
10 gems installed

Now let’s get to the beef:

vodka:~% git clone git://github.com/wycats/merb-core.git
vodka:~% cd merb-core
vodka:merb-core% jruby -S rake package
vodka:merb-core% jruby -S gem install --local pkg/merb-core-0.9.4.gem

That was core. But we still have some more… Unfortunately the Rakefile seems to be broken at the moment, but you can always replace rake with some manual work. :)

vodka:~% git clone git://github.com/wycats/merb-more.git
vodka:~% cd merb-more
vodka:merb-more% for i in merb-*; do cd $i; jruby -S rake package; cd ..; done
vodka:merb-more% jruby -S rake package
vodka:merb-more% jruby -S gem install --local **/*.gem

Some of the gems depend on other libraries. Consult the error message if you want to install everything.

Anyways, now you should have merb installed:

vodka:merb-core% jruby -S merb help
Usage: merb [uGdcIpPhmailLerkKX] [argument]
Merb. Pocket rocket web framework

Creating a Merb project

Now let’s create our very own Hello world wannabe.

vodka:tmp% jruby -S merb-gen app hello_nodeta
RubiGen::Scripts::Generate
      create  log
      create  gems
      create  autotest
      create  config
      create  app
      create  spec
      create  public
      create  config/environments
      create  app/helpers
      create  app/views
      create  app/controllers
      create  app/views/layout
      create  app/views/exceptions
      create  public/images
      create  public/stylesheets
      create  autotest/merb.rb
      create  autotest/discover.rb
      create  autotest/merb_rspec.rb
      create  config/rack.rb
      create  config/router.rb
      create  config/init.rb
      create  spec/spec_helper.rb
      create  spec/spec.opts
      create  public/merb.fcgi
      create  config/environments/production.rb
      create  config/environments/test.rb
      create  config/environments/rake.rb
      create  config/environments/development.rb
      create  app/helpers/global_helpers.rb
      create  app/controllers/application.rb
      create  app/controllers/exceptions.rb
      create  app/views/layout/application.html.erb
      create  app/views/exceptions/not_found.html.erb
      create  app/views/exceptions/internal_server_error.html.erb
      create  app/views/exceptions/not_acceptable.html.erb
      create  public/images/merb.jpg
      create  public/stylesheets/master.css
      create  /Rakefile

Generating controllers works the same way as in Rails:

vodka:hello_nodeta% jruby -S merb-gen controller testing

After that we can add our greetings to app/views/testing/index.html.erb.

That’s it, now let’s get it running.

Installing Glassfish

You can use whatever application server you want. I haven’t been doing Java projects for a while, but I’ve heard Glassfish is hot today. So let’s use it.

I downloaded the Linux installer:

vodka:tmp% java -Xmx256m -jar glassfish-installer-v2ur2-b04-linux.jar

Somehow Ruby software is never this easy to install… Anyways, we’re going to need ant before going to the next step. You can usually find it using your package manager. Let’s continue:

vodka:tmp% cd glassfish
vodka:glassfish% ant -f setup.xml
...
create.domain:
     [exec] Using port 4848 for Admin.
     [exec] Using port 8080 for HTTP Instance.
     [exec] Using port 7676 for JMS.
     [exec] Using port 3700 for IIOP.
     [exec] Using port 8181 for HTTP_SSL.
     [exec] Using default port 3820 for IIOP_SSL.
     [exec] Using default port 3920 for IIOP_MUTUALAUTH.
     [exec] Using default port 8686 for JMX_ADMIN.
     [exec] Domain being created with profile:developer, as specified by variable
AS_ADMIN_PROFILE in configuration file.
     [exec] Security Store uses: JKS
     [exec] Domain domain1 created.
     [exec] Login information relevant to admin user name [admin] for this domain [domain1]
stored at [/home/mutru/.asadminpass] successfully.
     [exec] Make sure that this file remains protected. Information stored in this file will be
used by asadmin commands to manage this domain.
   [delete] Deleting: /home/mutru/tmp/glassfish/passfile

BUILD SUCCESSFUL
Total time: 31 seconds

There it is. We can already start the server:

vodka:glassfish% ./bin/asadmin start-domain domain1

We can leave it running when preparing the next step.

Deploying your Merb application to Glassfish

The key here is a gem called Warbler. It comes bundled with JRuby-Rack. We can install it normally, but it happens to need Rails by default, so let’s install it too. And ActiveRecord with JRuby of course needs a JDBC adapter.

vodka:~% jruby -S gem install rails warbler activerecord-jdbc-adapter

Now we can start setting up our project. First we can create a Warble configuration file and try to build our first WAR archive:

vodka:hello_nodeta% jruby -S warble config
vodka:hello_nodeta% jruby -S warble war
jar cf hello_nodeta.war -C tmp/war .

Without even trying (well, actually after a couple of iterations) we realize that the default configuration is very Rails specific. So let’s edit the configuration file:

vodka:hello_nodeta% cp tmp/war/WEB-INF/web.xml config/web.xml

At the bottom of the file there’s something that seems to be tied to Rails. Use this instead:

  <listener>
    <listener-class>org.jruby.rack.merb.MerbServletContextListener</listener-class>
  </listener>

config/warble.rb also needs to know about our gems.

config.gems = ["activerecord-jdbc-adapter", "merb-core"]

Before deploying, let’s add one more route to your config/router.rb:

  r.match("/hello_nodeta/testing").to(:controller => "testing", :action => "index")

Now we’re ready to deploy:

vodka:hello_nodeta% cp hello_nodeta.war ~/tmp/glassfish/domains/domain1/autodeploy/

You can see that Java is starting to eat all of your CPU time. It means that Glassfish has noticed your WAR file and is deploying it.

You can take your browser to http://127.0.0.1:8080/hello_nodeta/testing and see the fancy index.html.erb you wrote earlier.

I’ll do some benchmarking later when I can set up a real benchmarking environment, but at least Glassfish seems to handle concurrent connections nicely out-of-the-box:

vodka:~% ab -c 400 -n 5000 http://127.0.0.1:8080/hello_nodeta/testing
This is ApacheBench, Version 2.0.40-dev <$Revision: 1.146 $> apache-2.0
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Copyright 2006 The Apache Software Foundation, http://www.apache.org/

Benchmarking 127.0.0.1 (be patient)
Completed 500 requests
Completed 1000 requests
Completed 1500 requests
Completed 2000 requests
Completed 2500 requests
Completed 3000 requests
Completed 3500 requests
Completed 4000 requests
Completed 4500 requests
Finished 5000 requests

Server Software:
Server Hostname:        127.0.0.1
Server Port:            8080

Document Path:          /hello_nodeta/testing
Document Length:        495 bytes

Concurrency Level:      400
Time taken for tests:   13.471622 seconds
Complete requests:      5000
Failed requests:        0
Write errors:           0
Total transferred:      3150000 bytes
HTML transferred:       2475000 bytes
Requests per second:    371.15 [#/sec] (mean)
Time per request:       1077.730 [ms] (mean)
Time per request:       2.694 [ms] (mean, across all concurrent requests)
Transfer rate:          228.33 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    2  10.5      0      64
Processing:    32 1043 302.5    982    1893
Waiting:       31 1042 302.6    982    1893
Total:         36 1046 299.3    984    1893

Percentage of the requests served within a certain time (ms)
  50%    984
  66%   1067
  75%   1111
  80%   1151
  90%   1551
  95%   1685
  98%   1743
  99%   1759
 100%   1893 (longest request)

Stay tuned. :)

Why you really need to let your tests fail first

Otto Hilska May 13th, 2008

Test-driven development (or even Behaviour-driven development) is increasingly popular, but sometimes old habits make you write tests afterwards – just to keep your test coverage up.

This is just plain wrong.

If you’ve never seen your test fail, how can you know that you’re testing the right thing? Let’s imagine we were trying out XMLBuilder for the first time:

module Demo
  def self.build_xml(xml)
    xml.parent do
      xml.child :id => 1
    end
  end
end

Could it get any easier. We already have a parent tag. Now let’s write the test afterwards:

require 'demo'

require 'rubygems'
gem 'builder'
require 'builder'

describe Demo do
  before(:each) do
    @xml = Builder::XmlMarkup.new(:indent => 2, :encoding => 'UTF-8')

    Demo::build_xml(@xml)
  end

  it 'should have a parent' do
    @xml.should match(/

Indeed, it seems that we have a parent. And our test coverage is blasting 100%.

However, just out of curiosity, let's try writing an invalid test:

it 'should not behave like this' do
  @xml.should match(/THIS WAS NOT IN MY XML/)
end

It still passes. Why? Well, XMLBuilder's method_missing happens to catch RSpec's should method. All possible matchers just pass. When outputting XML everything could seem to be in order.

And this is not the only problem. I've even seen cases, where someone is using a clever do_as(:user_name) helper to run tests under a certain user. Too bad that the helper method itself happened to be broken and even the craziest tests passed.

I pretty much assume that if a certain code block is not unit tested, it's broken. The same goes with tests: if you haven't seen a spec failing before implementing the feature, there's usually something wrong with the spec.

Nodeta at Euruko 2008

Mikael Roos April 9th, 2008


Nodeta at EURUKO 2008

Nodeta was a silver sponsor at this year’s European Ruby Conference, EURUKO 2008. The event was a hit success and the turnout was almost double the expected at over 300 rubyists. Huge thanks goes to the organizers, the guys from CSRUG. The event garnered the biggest names in the Ruby world ranging form the creator of Ruby, Yukihiro “Matz” Matsumoto to David Heinemeier Hansson, the creator of Rails.

Six Nodetans where on location when the bleeding edge of the Ruby world was divulged. In fact, the Euruko crowd was the first to learn about the publication of JRuby 1.1. All of the presentations are going to be available as video on the Euruko web site.