Showing posts with label ruby. Show all posts
Showing posts with label ruby. Show all posts

Tuesday, February 12, 2008

Toronto Summer: Agile 2008, RubyFringe

Wow - Summer 2008 is going to be a killer Toronto summer for Conferences. We've got:

  • Agile 2008: August 4th-8th, the best-known conference on Agile.
  • RubyFringe: July 18th-20th. A new conference dedicated to the fringe of Ruby, everything but Ruby on Rails, really. This presumably covers 'waves' and 'merb' and many other things. Just announced.

Wednesday, January 30, 2008

Can Hibernate Learn from Edge Rails?

Just finished reading about some eager-loading options for edge rails, and how they've moved away from the outer-join approach and into a multi-query approach because they believe it to be faster.

Last I saw, Hibernate used the outer-join approach in its internals for eager-fetches, so I wonder, is this an instance where Hibernate can learn from edge rails? I'd be curious to evaluate the two approaches across all the databases Hibernate supports with different data sets and see which wins out.

Tuesday, December 25, 2007

Ruby 1.9.0 - Released

Ruby 1.9 has been released, a little later than estimated. There are a lot of changes for Rubyists to absorb, and if you're using Ruby on Rails, Ruby 1.9 with Rails 2.0 is a pretty novel, but powerful, combination. We'll be seeing the impact of those changes in 2008.

Will YARV give Ruby the performance it needs, or will JRuby storm the enterprise? Time will tell. Maybe 2008 will be the rise of Erlang, JavaScript/EcmaScript 4.X, or some other new and powerful language.

In the meantime, if you haven't given Ruby or Rails a chance, maybe this is your chance.

The Windows download is slightly harder to find than most, so I'll link to it here.

Thursday, December 6, 2007

Mocking Methods that Don't Exist with RSpec

I've done some tests/specs using RSpec in Ruby with Mock Objects, but until I read this message on the RSpec List it hadn't occurred to me that you could mock methods (messages) that aren't present in the class itself.

I guess you could see that as a natural consequence of the kind of duck-typing system that dynamic languages offer, but it's a little awkward. You can end up, as the poster suggests, with a view that's out of sync with your model, and tests that don't pick it up.

As a result, not only do dynamic languages make testing more important, they make integration testing more important. Interesting.

I'd be interested to see a large codebase written entirely in Ruby and get a sense for the comprehensiveness and duration of a test run -- within three months of writing tests and specs on a Ruby/Rest project, we'd already racked up a five-minute test run (but, hey, we were Ruby newbies, so I'd be surprised to discover that people who've been at it longer have good strategies for maximizing test comprehensiveness and minimizing test-run time.

Tuesday, November 27, 2007

Performance: Groovy/Grails vs. Ruby/Rails?

So, in the comment thread that followed: The Pain of Java after Ruby, I off-handedly commented that I'd been given the impression that Groovy or Grails' performance was worse than that of Ruby or Rails. I was inevitably challenged on that point.

Let me back up a little and cover some of the ground I covered in that comment: I haven't attempted to benchmark Groovy and/or Grails at all; Grails didn't have great support for REST services when I last looked at it, so I didn't include it in some of my performance explorations at the time. We were able to get 600 requests per second from Restlet, and were able to get something on the order of 40 requests per second on the same hardware using Ruby on Rails. I'm sure both of those results could be improved upon. (At the time, JRuby was scoring about 28 requests per second; I gather performance has improved since then).

So, it begs the question: Does Groovy and/or Grails outperform Ruby and/or Rails? You'd certainly like to think so, given the Java VM underneath it, but what have people said?

Well, the Grails folks would probably argue that their solution performs better although it's still clearly a tight race. There's a little grumbling from some people with more Rails expertise, but there doesn't seem to be any outright disagreements.

That said, if you compare either of those solutions back to a Java equivalent, the results are usually pretty striking. There's a few examples of that out there.

So for now, I'll say that it seems like Groovy may have the edge on performance compared to Ruby, although it's still very much a two-horse race, and both have many further opportunities to gain ground.

However, it's also clear that both of these two solutions are, in the overall spectrum of development platforms, relatively slow. Depending on what you're building, that may not be a big deal, but it can certainly be a concern.

Monday, November 26, 2007

The Pain of Java after Ruby

Having done several months of Ruby in the past year, I occasionally find myself looking at a page of Java code and thinking to myself, "Wow, that's Java alright."

For instance, within the past few weeks, I needed a URI for testing. I made it a constant (private static final). Since it can throw an exception, I had to put the constant in a static initializer. Since the exception might be thrown, the variable might not be initialized, and so on and so forth. Eventually, you end up with this:


private static final URI SOURCE;

static {
URI uri = null;
try {
uri = new URI("/");
} catch (URISyntaxException e) {
Assert.fail("Couldn't create a URI for testing; please fix the test. This shouldn't happen.");
}
SOURCE = uri;
}


Although I understand the rationale behind each of the steps that gets you here, it's a bit of a boiled frog syndrome. By solving one problem with slightly more complex code, and repeating that pattern a few times, you eventually end up with pretty horrific code. Thanks, Java!

Now, to be fair, there are other ways around this code. For instance, I could easily create this as an instance variable in the test setup code, which in many ways would be a more normal approach, and it'd take all the above code away. That's probably the most obvious resolution for the problem at hand, but there are certainly others.

In any case -- because there are alternate solutions, this isn't really a problem, but having painted yourself into this particular corner it's easy to think to yourself, "Wow, this code would be much nicer in Ruby."

Thursday, November 8, 2007

QCon November 6th: DSL Tutorial

For those not following my more stream-of-consciousness reporting on QCon via Tumblr, I thought I'd summarize on a daily basis here.

On November 6th, I attended the Domain Specific Languages tutorial put on by Martin Fowler and Kent Beck. They started the presentation by letting us know they were only prepared for a half-day tutorial and had only recently realized they were scheduled for a full day. They then proceeded to get through the first 'hour' of material by lunch, and took the afternoon for the rest, so all in all it seems like the content was well-suited to the timeframe.

They did a good job of describing the kinds of domain specific languages (they used the terms internal and external, rather than the 'embedded' term that's been used elsewhere), showed some good examples of DSLs in Java and Ruby as well as completely custom DSLs, the tiny languages that the Pragmatic Programmers talk about. They also spent some time describing the boundaries of DSLs: What's a DSL vs. an API; a DSL is usually a thin veneer over a framework; the hardest part in writing a DSL is writing the framework beneath it.

The last portion focused on those external DSLs, using Antlr as an example on how you might build and use a parser for a domain-specific language. This was the most interesting to me, because although I've read a little on the subject, including some of Martin Fowler's exploration of Antlr already, it's the area that I knew the least about (having used jMock's Java DSL for years, and having done a few months of Ruby in anger).

There were a few interesting moments:

  • Charlie Poole indicated that some domain specific languages make it harder for non-english speakers to use the API, because they lack the common use of the idioms of the language. For instance, is "2.days.from.tomorrow" easier than Calendar.getInstance().add(Calendar.DAY,2).getTime() for a german speaker? (I dunno, I'm not German).
  • Neal Ford, describing the muddy boundary between an API and a DSL, said, "DSLs are like pornography: Hard to define, but I know it when I see it."
  • Martin Fowler and Neal Ford have slightly different takes on open classes, the ability to add methods and behavior to classes you don't control, easy to do in Ruby. Martin argued that it was reasonable within the context of an application you control, but riskier in a library that will be integrated with someone else's application (and other libraries). Neal Ford argued that experienced Rubyists find this conflict arises very rarely, and that the benefits outweigh the risks.
In the end, I don't know that I actually learned that much, but that's to be expected when you already know a fair bit about the area. I expect that when they release a book on the subject, it'll be a good one, with the kind of detail you can't stuff into a day-long presentation, and particularly valuable to those of you who are interested in, but have little experience with, DSLs.

I ended the day by having some Mexican food from Mijita Cocina Mexicana, possibly the food highlight of my trip (so far).

Thursday, August 30, 2007

Rails: Resource Links in Resource List

Navigating a REST application should not require a deep understanding of the namespace of the application's addressable resources. As much as possible, one REST query should lead to another.

The most obvious case of this is when one has a resource that is a list or collection (e.g. /customers) of the available resources (e.g. /customers/1), e.g.:


<customers>
<customer>
<name>The Customer</name>
<a href="myserver/customers/1.xml" />
</customer>
</customers>


And yet, it's surprisingly difficult to put these kind of links into Rails resources, particularly if you use the approach that resource_scaffold suggests.

Resource scaffold generates the XML representation of the collection as by calling the to_xml method that Rails adds to Array, which in turn calls to_xml on the model classes, something like this:

@customers = Customers.find(:all)
render :xml => @customers.to_xml


In order to add links to the XML representation, you'd need two pieces of information: the URL structure for resource and the id of the resource. The ActionController has the most understanding of the URL structure (as it can use
url_for and named resource helpers like customer_path), but the model class knows its id and is responsible for generating the XML.

This awkward split in the available information makes adding these links to the XML somewhat painful; perhaps no more painful than building the XML by hand would normally be, but it's a departure from the usual ease of accomplishing common tasks in Rails.

After trying a number of alternatives, we settled on approach. In the controller, we do:

# GET /customers.xml
def index
@customers = Customer.find(:all)
respond_to do |format|
format.xml do
render :xml => @customers.to_xml( :format => :summary, :base=>url_for(:controller=>'customers') )
end
end
end

# GET /customers/1.xml
def show
@customer = Customer.find(params[:id])
respond_to do |format|
format.xml { render :xml => @customer.to_xml( :format => :full ) }
end
rescue ActiveRecord::RecordNotFound
head 404
end


This relies on some model code, like this:

def to_xml( options = {} )
case options[:format]
when :summary
resource_url = proc { |options| options[:builder].a(:href=>"#{options[:base]}/#{id}.xml") }
super( options.merge!( :only => [:id, :name], :procs => [resource_url] ) )
when :full
super( options.merge!( :include => [ :main_contact_info, :billing_contact_info ],
:except => [ :main_contact_id, :billing_contact_id ] ) )
else
super( options )
end
end


It's still a little awkward, and I'm hopeful that we'll find a better alternative, but it does the job and is less ugly than some of the other alternatives we considered.

The only other option we looked at that seems reasonable is to generate all the XML within the controller, which means reproducing the work done by Array.to_xml, but is otherwise relatively sensible.

Friday, August 24, 2007

Rails Plugins: Globalize

Imagine that you've built yourself a small application in Ruby on Rails. Here's the good news: there are all sorts of ways to simply add significant functionality to your Rails applications through plugins. Let me introduce you to a few.

I've been investigating the Globalize and Acts As Audited (acts_as_audited) and Acts As Versioned (acts_as_versioned) plugins for Ruby on Rails over the past few days. I've got a lot to share, so I'll break it up into a few posts.

Let's start by imagining that you've built yourself a really, really simple model:
You've cut a customer model class with a unique identifier and a name. Now, let's add to that.

Globalize
If your application needs to operate in a multilingual or global environment, you'll be pleased to discover that not only is Globalize a general-purpose internationalization and localization (i18n/l10n) mechanism for Ruby on Rails, but it can even translate your model classes.

If you're going to translate fields within your model, you should be aware that it has two storage models for the translated information. Historically, it did this by storing the translated text in a separate table, globalize_translations. I'll call this the external storage model.

Using our model from above, the name field corresponds to the name in the base language (whatever you decide that is; en-US is a common choice in this part of the world), and all other translations are stored in the globalize_translations table as follows:

When you load or save your model class within the context of a particular Locale, Globalize does its magic behind the scenes to make sure that the text is loaded from or saved to the appropriate spot -- base language text goes to the primary table, and text from any other language goes to the translated-text table.

As often seems to be true, this magic interferes with some of ActiveRecord's default mechanisms, and :select and :include clauses stop working as advertised. There are workarounds, apparently.

However, in recent versions of Globalize, you have another choice - you can store the translations directly in your model, as follows:

This interferes less with ActiveRecord, although it's better-suited to applications that need to work with a known number of languages up front, rather than an unknown and changing set of languages, as each language addition requires new columns for every translatable field. It has a few caveats of its own.

Thursday, August 23, 2007

Globalize 'Internal Storage', First Look

I took a moment this morning to examine the new internal storage model for Globalize, wherein translations are kept within the original table. It seems to have a few more caveats:

  • Rails doesn't instinctively understand that the translated column names are not otherwise normal attributes; that means that any "iterate over all fields" code may have the translated columns show up as well. (e.g. scaffold show html).
  • If you haven't inserted the translation column for a locale to which the user can set, rather than using the base language, the user will not see any value. So, for instance, I turned on internal-storage on an example class with a single translated 'name' field. I created an example record (e.g. name='Hello') and switched to an 'fr' locale; instead of getting the contents of the name field ('Hello'), I got an empty string ('').
It's an interesting choice, mostly because it breaks less of Rails than Globalize's other model. I prefer the 'external storage' approach in many cases, particularly if you're dealing with a product or SaaS application where the number of supported languages is not clearly known up-front.

Wednesday, August 15, 2007

CodeGear: Red Diamond Non-Disclosable

Well, in order to download a Beta for CodeGear's Ruby IDE (based on DLTK, code-named Red Diamond), I have to agree not to disclose information about it, including its existence and features. So instead of telling you about it, and how much it adds on top of DLTK, I will, instead, pretend it doesn't exist. If you ask me to suggest an IDE for Ruby code, I will not mention this one, even if it's better. That's what they want.

Wednesday, August 8, 2007

Ruby on Rails on Bamboo: Unit Tests

In my previous post about Continuously Integrating Ruby on Rails with Bamboo, I walked through a simple setup for a Ruby on Rails project in Bamboo. That setup is a good starting point, but it's missing useful elements, like understanding the unit tests within the project, and test coverage:


Unit Testing Ruby on Rails with Bamboo
Let's start with unit tests. Bamboo understands the JUnit XML format, which Ruby doesn't normally emit (what with not using JUnit and all). Fortunately, someone's written a Rails plugin called ci_reporter that emits these files for us.


$ gem install ci_reporter
Bulk updating Gem source index for: http://gems.rubyforge.org
Successfully installed ci_reporter-1.3.3
Installing ri documentation for ci_reporter-1.3.3...
Installing RDoc documentation for ci_reporter-1.3.3...
$ script/plugin install http://svn.caldersphere.net/svn/main/plugins/ci_reporter
+ ./ci_reporter/tasks/ci_reporter.rake
$ svn add vendor/plugins/ci_reporter/
A vendor/plugins/ci_reporter
A vendor/plugins/ci_reporter/tasks
A vendor/plugins/ci_reporter/tasks/ci_reporter.rake
$ svn ci -m "Added CI reporter to project."
Adding vendor/plugins/ci_reporter
Adding vendor/plugins/ci_reporter/tasks
Adding vendor/plugins/ci_reporter/tasks/ci_reporter.rake
Transmitting file data .
Committed revision 411.


You'll probably have to ensure the ci_reporter gem is installed on your instance of Bamboo as well. Once this is complete, you'll want to modify your Plan:



And build the project:


See? Tests! Bamboo can find the XML files generated in test/reports, and use them to understand the testing of your Ruby on Rails application. Now, in a Java/JUnit project, Bamboo does a fine job of turning the test methods into readable names, but for now that's not true with Test::Unit test names, but they're working on it.


Next step: Coverage. But that'll be another day.

Tuesday, August 7, 2007

Hpricot Limitations

Well, after fighting with Cygwin and Hpricot for a few days, I've given in and dropped Cygwin from my stack for the Ruby/Windows testing for now.

Within five minutes of doing that, I was able to get something done with Hpricot, and bump into its limitations within a minute or so after that.

For example:


irb(main):001:0> require 'rubygems'
=> false

irb(main):002:0> require 'hpricot'
=> true

irb(main):003:0> require 'open-uri'
=> true

irb(main):004:0> doc = Hpricot(open("http://code.whytheluckystiff.net/hpricot/wi
ki/HpricotBasics"))
=> #<Hpricot::Doc {doctype "<!DOCTYPE html\n" " PUBLIC \"-//W3C//DTD XHTML 1.

...

"> "http://trac.edgewall.com/" </a>} "\n " </p>} "\n" </div>} "\n\n\n\n "} </bod
y>} "\n" </html>} "\n\n">

irb(main):005:0> (doc/"//img")
=> #<Hpricot::Elements[{emptyelem <img src="/hpricot/chrome/site/images/hpricot-
small.png" alt="hpricot">}, {emptyelem <img src="/hpricot/chrome/common/trac_log
o_mini.png" height="30" alt="Trac Powered" width="107">}]>

irb(main):006:0> (doc/"//img[@alt='hpricot'")
=> #<Hpricot::Elements[{emptyelem <img src="/hpricot/chrome/site/images/hpricot-
small.png" alt="hpricot">}, {emptyelem <img src="/hpricot/chrome/common/trac_log
o_mini.png" height="30" alt="Trac Powered" width="107">}]>

irb(main):007:0> (doc/"//img[@alt='hpricot']")
=> #<Hpricot::Elements[{emptyelem <img src="/hpricot/chrome/site/images/hpricot-
small.png" alt="hpricot">}]>

irb(main):008:0> (doc/"//a/img[@alt='hpricot']")
=> #<Hpricot::Elements[{emptyelem <img src="/hpricot/chrome/site/images/hpricot-
small.png" alt="hpricot">}]>

irb(main):009:0> (doc/"//a[img/@alt='hpricot']")
=> #<Hpricot::Elements[]>


There's nothing wrong with the second query; it's a valid XPath expression, it's just not supported by jQuery, which means it isn't supported by Hpricot. Too bad; I guess i'll have to work around the syntax limitations.

Friday, July 13, 2007

JRuby Goldspike in Context Root

If you're using JRuby's Goldspike plugin to create a WAR for deployment, you might discover that rake war:standalone:run puts the application into a named context (e.g. http://localhost:8080/myapplication). Since most Ruby applications run at the root, this might disrupt your application if it wasn't built to handle a changing path (or your remote tests, which might have the same problem).

Fortunately, it's very easy to modify Goldspike to use the root:

  1. Open vendor/plugins/goldspike/lib/run.rb
  2. Find the WebAppContext definition
  3. Adjust the second argument from
    <Arg>/<%= config.name %></Arg>
    to:
    <Arg>/</Arg>
You're done. When Jetty boots up, you'll see something like "NO JSP Support for /, did not ...". The "/" is the context, so you're in good shape.

Ruby on Rails continuously integrated with Bamboo

Since I tripped over a few things setting up Bamboo for Rails, I thought it would be good to share my approach. After my last post, someone from Atlassian thought that would be a good idea as well, so, what the heck.

Creating a Simple Rails Project


In order to demonstrate configuring a project on Bamboo, it's easiest for me just to create a simple rails project, with a model and scaffold. This'll come with tests, albeit useless ones. But if you wanted a tutorial on how to use Rails, you've come to the wrong place.


geoffrey@paraietta:~/projects$ rails bamboo-rails
create
create app/controllers
create app/helpers
create app/models
...
create log/production.log
create log/development.log
create log/test.log
geoffrey@paraietta:~/projects$ cd bamboo-rails/
geoffrey@paraietta:~/projects/bamboo-rails$ mysql -u root
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 8
Server version: 5.0.38-Ubuntu_0ubuntu1-log Ubuntu 7.04 distribution

Type 'help;' or '\h' for help. Type '\c' to clear the buffer.

mysql> create database `bamboo-rails_development`;
Query OK, 1 row affected (0.01 sec)

mysql> create database `bamboo-rails_test`;
Query OK, 1 row affected (0.00 sec)

mysql> quit
Bye
geoffrey@paraietta:~/projects/bamboo-rails$ script/generate model foo bar:string baz:string
exists app/models/
exists test/unit/
exists test/fixtures/
create app/models/foo.rb
create test/unit/foo_test.rb
create test/fixtures/foos.yml
create db/migrate
create db/migrate/001_create_foos.rb
geoffrey@paraietta:~/projects/bamboo-rails$ rake db:migrate
(in /mnt/home/geoffrey/projects/bamboo-rails)
== CreateFoos: migrating ======================================================
-- create_table(:foos)
-> 0.0040s
== CreateFoos: migrated (0.0041s) =============================================

geoffrey@paraietta:~/projects/bamboo-rails$ script/generate scaffold foo
exists app/controllers/
exists app/helpers/
create app/views/foos
...
create app/views/layouts/foos.rhtml
create public/stylesheets/scaffold.css


Add the Project to Source Control


Once the project's created, it has to be somewhere that Bamboo can reach it. The usual practice is a source control system. In this case, I'm using Subversion.

geoffrey@paraietta:~/projects$ svn import bamboo-rails http://messis/svn/spikes/bamboo-rails -m "A simple Rails/Bamboo integration project."
Adding bamboo-rails/test
Adding bamboo-rails/test/unit
Adding bamboo-rails/test/unit/foo_test.rb
...
Adding bamboo-rails/public/stylesheets
Adding bamboo-rails/public/stylesheets/scaffold.css
Adding bamboo-rails/public/favicon.ico

Committed revision 190.

Configure Bamboo for Ruby



In order to build anything in Bamboo/Ruby, you're going to want to configure a builder in Bamboo. There may be a way to use one of the existing builders, but this is what worked for me. Just add a builder for Ruby and point it to your ruby executable.

Create a Plan for your Ruby Project


You're going to want to create a Project and Plan for your Ruby project. Bamboo projects are umbrellas for related Plans:

Plans tell Bamboo what you're trying to build, where to find the source code:

They also tell Bamboo how to build what it finds:

They also tell Bamboo what to do with the results, and whom to notify, but those steps aren't unique to Rails in any way, so I'm going to leave them out. At this point, you have a project and plan defined in Bamboo, so you can check to see if it worked:
It didn't. I didn't create the database on the build server. Once I've done that:

Et Voila

You've got a basic Ruby on Rails project building in Bamboo. This is the bare minimum setup. There's a lot of things you can add from here. In my next post, I'll cover getting Bamboo to recognize your test results and calculate coverage.

Thursday, July 5, 2007

Bamboo, Ruby on Rails, Test Reports and RCov

Over the last day, I've had an opportunity to integrate Atlassian's bamboo with a Ruby on Rails project, which has been fruitful. It was actually pretty easy. Create a builder that runs Ruby (rather than Bash or Maven), point it at 'rake' with the appropriate target, and it builds.

Tests
If you want your test reports to be visible as test reports, you might want to look up the ci_reporter plugin and gem. This simply ensures that when your tests run, they generate JUnit-style XML files that many CI servers can pick up, including Bamboo.

Coverage
If you add the rails_rcov plugin to your project, you can run the test:test:coverage goal in order to generate a coverage report. All you need to do then is tell Bamboo to treat it as an artifact, scoop up all the contents of coverage/test. Then, from your build results, you can go to the artifact tab, and pick up the resulting coverage report, nicely viewable in your web browser.

See Also
If you want to find out more about integrating Atlassian's Bamboo with Ruby on Rails, I recommend you not search for 'bamboo rails' or 'bamboo rake', both of which are likely to take you elsewhere. ;)

Are any of you using Bamboo and Rails together, and if so, do you have more interesting tips to add?

Tuesday, July 3, 2007

Mark Occurrences in Aptana/Ruby

I've been using Aptana's Ruby/Rails editors in Eclipse 3.3. It has a 'mark ocurrences' feature that isn't working too well for me. It highlights things well, but the highlights don't go away, and when you save, they often move around, end up highlighting mid-word, including whitespace, and otherwise being incredibly confusing.

Happily, I've learned that they can be turned off here:

Preferences > Ruby > Editor > Mark Occurrences

Maybe this will save some of you the same pain.

Monday, July 2, 2007

In Review: Late June, Early July

Tuesday, February 27, 2007

POCOs, POROs, POGOs, Oh my!

In reading this ServerSide.NET article about Gigaspaces extending itself to "plain C# objects", I realized that Plain Old C-sharp Objects (POCOs) or Plain Old C-Sharp Objects (POCSOs) hadn't passed into .NET vernacular yet.

Far be it from me to stop progress. So unless one of you can show me some prior art (Google search didn't turn up anything obvious), I hearby coin POCOs and POCSOs, for .Netians everywhere.

And while I'm at it, I think I'll swing for the fences and coin Plain Old Ruby Objects (POROs). Take that, Parsons, Mackenzie and Fowler!

I'm tempted to go for a hat-trick and choose a third language. How about POGOs for Groovy?

UPDATE: I've had to cancel the patent applications. Looks like POGOs and POROs have prior art, and POCOs are just PONOs revisited. Clearly I'm just not hep to the language you kids are talkin'.