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

Wednesday, December 16, 2009

A Simple Ruby Pattern

By being a multi-paradigm language, Ruby provides numerous possible styles to write your programs with. I am a big fan of metaprogramming in Ruby, and one style strikes my fancy especially. By defining methods in your Class instances, your subclasses start to act like a domain specific language. You end up setting up a structural framework for how your subclasses behave, then declare the behaviors specific to each specific subclass.

To illustrate this, consider a simple calculator application. You could tackle such an application any number of ways, but we can come up with an interesting solution using class methods.

For starters, we need our base CalculatorBase class, which will provide the plumbing for dealing with input, handling if the input is numeric versus operations, and overall flow. I am not interested in these details for this post, so I will leave them as a homework problem for you to play with. Don't worry, it's fun!

First, your base calculator needs to expose a way to define operations:

class CalculatorBase
def self.operation(op, arity, &block)
define_method(op.to_sym) { |*args|
unless args.size == arity
raise "Wrong number of arguments"
end
block.call *args
}
end
end


From this, you can declaratively define what operations your calculator may support:

class Calculator < CalculatorBase
operation(:+, 2) { |x, y| x + y }
operation(:-, 2) { |x, y| x - y }
operation(:/, 2) { |x, y| x / y }
operation(:*, 2) { |x, y| x * y }
operation(:sin, 1) { |x| Math.sin x }
operation(:cos, 1) { |x| Math.cos x }
operation(:tan, 1) { |x| Math.tan x }
end


Now, you can invoke operations with ease:

calc = Calculator.new
calc.+ 2, 3
calc.sin 3.14159


However, I feel we can do better than this. There is a lot of repetition going on with the arity. To make our calculator implementation more domain specific, let's allow binary and unary operators to be defined easier:

class CalculatorBase
def self.operation(op, arity, &block)
define_method(op.to_sym) { |*args|
unless args.size == arity
raise "Wrong number of arguments"
end
block.call *args
}
end

def self.binary(op, &block)
operation op, 2, &block
end

def self.unary(op, &block)
operation op, 1, &block
end
end


With these new methods, we can make our operation declarations a bit easier:

class Calculator < CalculatorBase
binary(:+) { |x, y| x + y }
binary(:-) { |x, y| x - y }
binary(:/) { |x, y| x / y }
binary(:*) { |x, y| x * y }
unary(:sin) { |x| Math.sin x }
unary(:cos) { |x| Math.cos x }
unary(:tan) { |x| Math.tan x }
end


This isn't a particularly difficult approach in Ruby, but I really like the results whenever I am able to employ it. It can remove a lot of repetitive method declaration, and make your main class very clearly declare the behaviors it employs.

Of course, with great power comes great responsibility. It is easy to obfuscate the behavior you are creating with this pattern. Used appropriately, you can design an API and then speak the language of your domain in a much easier to comprehend fashion.

Sunday, November 22, 2009

Smart XML Processing with Regexes

Recently, Jeff Atwood wrote about parsing HTML with regular expressions. I want to speak about it briefly, because I came across this issue last week. I gathered from his post that the lesson is to consider your options with an open mind, and only block a possible solution if you really understand the alternatives. Use facts and knowledge to choose your implementation details, not superstition and theoretical best practices. Best practices usually are created for a reason, but that's not to say there's never a reason to turn your head on them.

This post hit home with me because I had an XML file to parse that was over a gigabyte. From this XML file, I needed a very small handful of the data, and it was very regular XML. XML parsing is a solved problem, but most XML libraries I've used would easily choke on such a file.

Instead of even considering attempting to process this data with a normal XML processor, I wrote a simple Ruby script to extract the information. It looped over each line, looking for key parts of the data with lines like:

if line["<expectedTag>"]
# deal with this tag
end


Then, I processed the key tags and data I was looking for with regular expressions, such as:

data = line[/<expectedTag>(.+)</expectedTag>/, 1]


The above was done within the if blocks. The key point being regexes would have been too slow alone, so I used the simple indexer method to quickly determine if the line contained something that mattered to me. Then I used the regex to pull the data that I actually wanted.

Can you write XML to break my processing? Of course! The question is... does it matter? And that answer was no. I only need to process this data once, maybe another time sometime in the distant future, but the XML is so regular that I know it will work for all the data. On top of this, if I missed some data, it wouldn't matter in the slightest for my purposes. So, in short, proper XML processing would have severely slowed me down (ignoring all lines that don't contain a keyword is much faster), and it would have produced no real benefit.

I ended up processing all the data in little over a minute or two, and I considered it a huge success. Over a gigabyte of XML to process seemed a rather daunting task initially!

Thursday, November 5, 2009

Easy Partials in Rails

I created something at my job that has proven to be extremely useful that I think many people could benefit from. I like to call it Easy Partials, and the goal is to make using partials a bit easier (in case the name didn't make that glaringly obvious). The problem is that rendering a partial requires method calls when a little extra work will allow simpler and more readable partial invocation via convention.

You are probably lost, so let me give you some examples. As it stands today, to render a partial you would do:

<%= render :partial => "my_partial" %>


Which would take the partial "_my_partial.erb" from the same directory and render it.

It works, but what if you could take the whole "convention over configuration" idea and change it into:

<% _my_partial %>


A lot simpler, and pretty intuitive, right? Since partials by Rails conventions start with "_", it makes sense to just name a method as such to render the partial. Note that there is no "=" in the scriptlet, the _my_partial method will concat the partial, so you won't obtain a string to render.

We could create a helper method for every single partial we want to render like that, but that's rather cumbersome, isn't it? It's also not very DRY. You won't have exactly the same code, but you will find yourself with a lot of helpers that look rather similar. Instead, let's try overriding method_missing in our application_helper so we can avoid all those repeated helpers!

module ApplicationHelper
alias_method :method_missing_without_easy_partials, :method_missing

def method_missing_with_easy_partials(method_name, *args, &block)
method_str = method_name.to_s

if method_str =~ /^_.+$/
partial_name = method_str[/^_(.+)$/, 1]
concat_partial partial_name
else
method_missing_without_easy_partials method_name, *args, &block
end
end

alias_method :method_missing, :method_missing_with_easy_partials

# Concat the given partial.
def concat_partial(partial_name)
content = render :partial => partial_name
concat content
nil
end
end


What we've done here is check on method_missing to see if the method name starts with "_", and, if so, treat it as a partial and concat it. If the method doesn't start with "_", we fall back to the original method_missing implementation.

This works, but what if the partial needs some local variables? Before you would do:

<%= render :partial => "my_partial", :locals => { :var => "123" } %>


Instead, let's do:

<% _my_partial :var => "123" %>


Again, a lot simpler, and quite intuitive. To achieve this, our code will look like this:

module ApplicationHelper
alias_method :method_missing_without_easy_partials, :method_missing

def method_missing_with_easy_partials(method_name, *args, &block)
method_str = method_name.to_s

if method_str =~ /^_.+$/
partial_name = method_str[/^_(.+)$/, 1]
concat_partial partial_name, *args
else
method_missing_without_easy_partials method_name, *args, &block
end
end

alias_method :method_missing, :method_missing_with_easy_partials

# Concat the given partial.
def concat_partial(partial_name, options = {})
content = render :partial => partial_name, :locals => options
concat content
nil
end
end


Now we are passing the Hash passed in from the view on to concat_partial so we can specify the locals we want to render. We could check that there is no more than 1 argument passed into method_missing, but I prefer not to (feel free to use and improve anything you see here, in case that wasn't clear).

The next improvement we can make is to allow blocks to be passed in. There is no direct correlation for this next part, that I know of, except to build it yourself with helper methods. It was inspired by Ilya Grigorik.

Here is an example of what we will build:

<% _my_partial :var => "123" do %>
<p>
Some block content.
</p>
<% end %>


This will allow us to effectively pass in a block to the partial, so we can abstract some of the content in the partial so that the caller can define it. And now for the code:

module ApplicationHelper
alias_method :method_missing_without_easy_partials, :method_missing

def method_missing_with_easy_partials(method_name, *args, &block)
method_str = method_name.to_s

if method_str =~ /^_.+$/
partial_name = method_str[/^_(.+)$/, 1]
concat_partial partial_name, *args, &block
else
method_missing_without_easy_partials method_name, *args, &block
end
end

alias_method :method_missing, :method_missing_with_easy_partials

# Concat the given partial.
def concat_partial(partial_name, options = {}, &block)
unless block.nil?
options.merge! :body => capture(&block)
end

content = render :partial => partial_name, :locals => options
concat content
nil
end
end


Within your partial, you will use a "body" variable to output the contents of the block passed in. If you try to use a variable named "body" along with partial blocks, the block will override the body variable, so keep that in mind.

For the final improvement, consider a partial that belongs to more than one controller. What do we do then? Well, how about we maintain a shared directory that we pull from if the partial cannot be found within the local directory. Thus:

module ApplicationHelper
alias_method :method_missing_without_easy_partials, :method_missing

def method_missing_with_easy_partials(method_name, *args, &block)
method_str = method_name.to_s

if method_str =~ /^_.+$/
partial_name = method_str[/^_(.+)$/, 1]

begin
concat_partial partial_name, *args, &block
rescue ActionView::MissingTemplate
partial_name = "shared/#{partial_name}"
concat_partial partial_name, *args, &block
end
else
method_missing_without_easy_partials method_name, *args, &block
end
end

alias_method :method_missing, :method_missing_with_easy_partials

# Concat the given partial.
def concat_partial(partial_name, options = {}, &block)
unless block.nil?
options.merge! :body => capture(&block)
end

content = render :partial => partial_name, :locals => options
concat content
nil
end
end


So, if you use the _my_partial examples from above within the views for "person_controller", but there is no views/person/_my_partial.erb, it will fall back on views/shared/_my_partial.erb.

Using Easy Partials, you can avoid redundant helper methods, keep html in easy to access ERB templates, improve the readability of your views that use partials, and make your code more accessible for your non-programmer UI designers. Note that you can even invoke Easy Partials from within helper methods.

Special thanks to Ilya Grigorik's post on block helpers, which planted the seeds for Easy Partials.

Wednesday, October 21, 2009

Quick Lesson from DevDays

Ok, so I went to Stack Overflow DevDays in San Francisco this last Monday, and it was a lot of fun. I went with a friend from work, and we both walked away happy, stickers in hand.

I took some notes, and I would like to share what I thought of all the speakers and their presentations, but we'll save that for another day... if I actually end up writing it (post a comment if you are interested, and hopefully that will push me to write it up).

What I want to talk about is a small bit I learned from one of the presenters. If you don't know me, I'm a big Linux fan, I heart Google, I have an Android G1, I love open source and Ruby and Rails, and Microsoft is practically the devil. Given that, you might find it interesting that the thing that struck me most... enough to actually write about it... came from Microsoft. That's right, it came from the near-devil. Well, it came from Scott Hanselman, who was a pretty good speaker.

Scott talked about Microsoft .NET MVC. It seems like a relatively cool product, if you can bear to be in the Microsoft world, and if you can bear to deal with such a clunky language as C#. Ok, I gotta give props that C# is a decent language... for a statically typed language... but the platform restrictions (excluding Mono), and it not being nearly as awesome as Ruby, will keep me from ever dealing with it again (I worked in C# professionally for a few years). Yes, .NET provides access to a fleet of languages, but C# is still their flagship. Anyway, from the discussion, MVC seems like it does a decent job at mimicking Rails, though it still didn't seem nearly as elegant.

That was a long lead-up for a simple point I extracted from the Big M... <%: value %>. That's it. I have wished the default of scriptlets was to sanitize html output for a long time, and I'm pretty sure Jeff Atwood had a post on it at one point. That tag, if I understood Scott right, differs from <%= value %> in that it will sanitize the output automatically.

On the train ride back to the south bay, I set it upon myself to implement this auto sanitization in Rails for my current side project. Initially I thought I could do something like:

def :(arg)
h arg
end


But alas, that doesn't work. Ruby won't let you define ":" as a method... it throws a syntax error... drat!

So, I figured, maybe I could monkeypatch the ERB handling so that <%: value %> works as I want, so I looked around the Rails source for how ERB compiles the views. It didn't take long to find erb.rb, which deals with the compilation. I inspected it for a bit, and toyed with some ways to deal with the problem, and ultimately came up with:

class ERB::Compiler::Scanner
alias_method :initialize_without_sanitize, :initialize

def initialize_with_sanitize(src, trim_mode, percent)
initialize_without_sanitize src, trim_mode, percent
@src.gsub! /<%:(.*?)%>/, "<%= h(\\1) %>"
end

alias_method :initialize, :initialize_with_sanitize
end


If the above code is cryptic for you, it basically overrides the initialize method (which is the constructor method for all you non-Rubyists) and uses a regex to replace all of the new sanitizing scriptlets with what would actually work to sanitize it. So, <%: value %> gets transformed to <%= h( value ) %>. I can't vouch for the performance (because I haven't done any performance testing), but it works.

Put the above snippet wherever you put your monkeypatches that you want run once. I have mine in a monkeypatches.rb file set to load after Rails has initialized (so it runs just once, at startup time).

Go forth in sanitized goodness.

Friday, April 17, 2009

Dealing with Errors in Rails

Jeff Atwood's recent blog post on "Exception-Driven Development" has driven me to write a post that I've been thinking about writing for the last couple weeks.

I'm working on a Rails application in my spare time, and one of the concepts I wanted to drill into the codebase from the beginning was easy management of the system from within the system. This means I can log in and, given that I have the proper access, view errors that have happened in the site, migrate the database, restart the application, and perform various other actions that would otherwise require tedious activities like digging in log files, or obtaining shell access and executing various commands. While I am quite comfortable on the shell (I run Linux on all the machines that I use with any regularity), I would much rather have an easy to use GUI that gives me access in the context of when I need it (ie, when I am actually checking up on the website... from within it).

So, this post will basically show you how to add error logging within your Rails application, as I've done in mine.

First up: the database. Here's the database migration script you will need:

class CreateErrors < ActiveRecord::Migration
def self.up
create_table :errors do |t|
t.string :level
t.string :title
t.boolean :handled
t.text :description

t.timestamps
end
end

def self.down
drop_table :errors
end
end


The level column is so you can keep track of errors vs warnings, or have informational messages as well. It's not strictly necessary, but I want the flexibility, plus I'm used to the concept from all the logging frameworks that support multiple levels of messages.

The title and description should be self explanatory. In case you are slow though, the title is just a header so you can at a glance see what errors have cropped up, and the description provides a detailed look at the error (such as a backtrace).

The handled column is critical so you can keep track of which errors you have dealt with, and which need looking at. It acts as a soft delete.

Since you've seen the database end, you might as well peak at the model next:

class Error < ActiveRecord::Base
def self.error(title, description)
log :error, title, description
end

def self.warn(title, description)
log :warn, title, description
end

def self.info(title, description)
log :info, title, description
end

def self.log(level, title, description)
Error.new(:level => level.to_s, :title => title,
:description => description, :handled => false).save
end
end


The error, warn and info methods are to easily log something at the given level, much like a typical logging library. All of those methods use the one logging method which will actually save the error as a row in the database. Pretty simple, as is the usual case with ActiveRecord classes! You could make a case for making the log method private, but I don't really want to, so I won't.

Next up, the errors controller:

class ErrorsController < ApplicationController
title "Errors"
require_admin

def index
@total = Error.count :all, :conditions => ["handled = ?", false]
@errors = Error.find :all,
:conditions => ["handled = ?", false],
:order => "created_at DESC", :limit => 50
@start = [1, @total].min
@amount = @errors.size
end

def show
@error = Error.find params[:id]
end

def handle
@error = Error.find params[:id]
@error.update_attributes :handled => true
redirect_to errors_url
end
end


The title and require_admin methods are some utility methods I baked into the base controller... I may publish those at some point, but they aren't the focus of this post, so not now. If I get any comments requesting the code, I will probably follow up with the code, so let me know if it is intriguing you! Their purpose are to set the title on all views associated with this controller, and check for administrator privileges respectively.

If you will notice, the index will only load the most recent 50 errors... I figured it would be possible for the application to get in a weird loop where you trigger tons and tons of errors. I wouldn't want to haplessly check out the current list of errors, only to watch in horror as I am downloading a list of 100,000 errors. The handle method is the only means to update an error... and it simple turns on the soft delete so the error won't show anymore. It might make sense to set up a mass handled action which would handle a group of selected errors all at once... but I don't really need that yet... I will build it when the need arises.

The rest in index should make sense as you check out the index.html.erb view:

<h1>Listing errors</h1>

<p>
<%= @start %> - <%= @amount %> of <%= @total %> errors.
</p>

<table>
<tr>
<th>Date</th>
<th>Level</th>
<th>Title</th>
</tr>

<% @errors.each do |error| %>
<tr>
<td><%= h format_datetime(error.created_at) %></td>
<td><%= h error.level %></td>
<td><%= h truncate(error.title, :length => 100) %></td>
<td><%= h error.handled %></td>
<td><%= link_to "Show", error %></td>
<td><a href="/errors/handle/<%= error.id %>">Handled</a></td>
</tr>
<% end %>
</table>


Pretty straightforward, huh? Well, here's show.html.erb

<p>
<b>Title:</b>
<%= h @error.title %>
</p>

<p>
<b>Time:</b>
<%= h format_datetime(@error.created_at) %>
</p>

<p>
<b>Level:</b>
<%= h @error.level %>
</p>

<p>
<b>Description:</b>

<br/>

<%= format_multilines h(@error.description) %>
</p>

<a href="/errors">Back</a>


Also pretty simple. If you are curious about format_datetime and format_multilines, they are simple helpers I created to respectively format a date as I want them formatted, and take a string with newlines and convert the newlines to <br/> elements. Pretty simple helpers, but I like keeping as much logic off my views as possible.

That's it! Or wait... that's all the stuff that rails practically generates for you (tweaked for simplicity, but still). How can this stuff get put into practice? Well, I'll give you that code too... since you've gotten this far. In your base application controller:

class ApplicationController < ActionController::Base
RENDER_LIMIT = 0.5
around_filter :time_page

...

private
def time_page
before = Time.new
yield
after = Time.new
delta = after - before

if delta >= RENDER_LIMIT
title = "Page took #{delta} seconds to render"
description = "Execution of #{request.path} took #{delta} seconds to render."
Error.warn title, description
end
end

def rescue_action(e)
title = "Caught exception '#{e}'"
description = "Exception was caught: '#{e}'\n\nBacktrace:\n#{e.backtrace.join("\n")}"
Error.error title, description
super
end
end


With this addition, your new in-site error reporting mechanism will report any page that takes over half a second to load, or absolutely any exception that crops up. This includes failing to parse a Ruby file, actions or controllers that were browsed to that don't exist, or any random exception the user encounters. You may want to adjust the RENDER_LIMIT constant to the threshold of your liking. At some point I would like to add a separate timer for all database queries, but I haven't had the time or interest to do it yet... and besides, the render limit should encompass all queries anyways, so it would be slightly redundant (though I would like to have a much lower threshold of query time than render time).

And as a caveat, this will not report a failure to parse the application controller Ruby file... because... well... think about it and you should realize why it can't :-)

Go forth and practice Exception-Driven Development in Rails.

Monday, June 30, 2008

Singleton Methods

Ruby has a neat feature called Singleton Methods. The idea behind them is that you can define a method on an instance of an object, and that method only exists for that instance. Sounds pretty crazy the first time you learn about it, but it can prove quite powerful. This feature only makes sense in conjunction with duck typing (which I would like to dedicate another post about at some point). Don't expect a JSR for Singleton Methods for Java any time soon! Actually, you can do something similar using an anonymous class, but it would be rather hard to invoke, and you would have to define the method at the point of creation.

How could Singleton Methods possibly be useful? Well, my personal favorite is for unit tests. I prefer testing with actual classes, but sometimes that is not feasible. The object in question may not be built yet. It may be a legacy object that you don't want to touch because there aren't all that many tests for it, and it would just be easier to pretend that you have an instance of it. Perhaps the most likely scenario is that you are using a framework, and it is just plain annoying or infeasible to construct the real version of the object in question. Sockets are a prime candidate for this exact situation. Whatever the reason, you want to mock an object. What do you do in Java? You either construct an anonymous class, or you define a mock class which extends the object in question (or implements the required interface), and voila!

Except... anonymous classes are rather cumbersome, and an actual mock class separates your mock logic with the test that requires it. You could of course have a general purpose mock that is used everywhere, but you will have to go back and forth between the mock definition and your test class definition whenever you are developing tests that use the mock.

In comes Singleton Methods to the rescue! Your method only connects, and then does some extra work once it is connected, so you just need to mock the connect method. The following code would accomplish this goal:

mock = Object.new
def mock.connect()
end
invoke_my_method_with mock
# assert some conditions

Then, you should have a test in case the connect fails, right? Your object needs to do some other logic when the connection doesn't actually connect! So, the next test mocks the object differently:

mock = Object.new
def mock.connect()
raise "Some exception"
end
invoke_my_method_with mock
# assert some other conditions

Because of duck typing, your method doesn't know that it didn't get an actual Socket, but you were able to keep the mock logic near the test logic (in a clean and concise manner), which makes it a lot clearer what the test is testing.

Making mocking easier is nice, but ever since I learned Singleton Methods, I have been itching to use it in another way. Let's say we have an entity in our system that has a set of actions possible. My favorite case is a character in a game. There are many possible actions, but our character is only able to use a few of these actions. He can kick, but he can't punch. Each command could be a different Singleton Method! Now, whenever the character wants to punch, just invoke punch with the actual character instance. Of course, this means you have to be prepared that the character can't ACTUALLY punch, so you must catch a method missing error and inform the character that it tried to do an action it didn't know how to do (or perhaps didn't even exist). I don't know how this type of design would actually pan out, but it sure seems like the perfect fit for the feature.

I bet there are other good uses for Singleton Methods, so don't let these ideas limit the possibilities!

Thursday, June 26, 2008

Thoughts on Groovy

So I have been working with Groovy for the last few weeks on a for fun project at home. Nothing special, just a game... one that will probably never see the light of day, but I will nonetheless have fun with it for a while. I am a bit disappointed with Groovy, probably because I came at it having first learned Ruby. Groovy is very heavily influenced from Ruby, but not quite enough in my opinion.

Before I get into some issues I have with it, I guess I should note that it isn't ALL bad. Namely, they did a great job of making (mostly) seamless Java and Groovy integration possible... in BOTH directions. This is the 1 thing I wish JRuby would borrow from Groovy. What is the problem you ask? Well, with Groovy, you compile down to classes, and the resulting class is more or less exactly how you would expect it to work. That is, you can construct the object from Java directly, then call methods directly on it, exactly as you defined in your Groovy code. If you specified types, you will have access to those type declarations from Java. This is really good if you have an existing code base you want to integrate with. If you are starting an application from scratch with no dependencies, well, you might as well just stick with JRuby or Ruby (or whatever inferior language you like), since you can control whether integrating with your language from the Java end is a big deal. I played a TINY bit with Rhino, and they seem to have a similar type if integration possible, but Groovy seemed a lot cleaner... with Rhino you have to compile the class to a given object or interface... so the code itself doesn't really have a definition of the type in this case. Seemed like a bit of a hack to me, but if you are primarily using it from the JavaScript side, it is really a non-issue. Oh, and I decompiled the results of all 3 of these languages (Rhino, JRuby and Groovy), and Groovy seemed to add the lease baggage in the code, but it still had baggage.

Also... if you are a big fan of static typing, then Groovy will be a good transition to dynamic typing because you can fall back on static typing whenever you want. Personally, I see no reason to, but I am one who loves dynamic typing.

Now some bad things. Perhaps as a direct consequence of the apparent design goal to integrate seamlessly in both directions with Java, the language feels very... inconsistent. They TRY to do things in a nice dynamic way, but then fall short in some cases that I think Ruby shines in. This leading to my biggest gripe... the distinction between fields and methods. If you are going to support fields of varying scope, you essentially can't have the kind of clean design you have in Ruby. What do I mean by this? Well, let's look at an example.

In Ruby, if you have a property named "property" then you would define it as such:

attr_accessor :property

Which is equivalent to:

def property()
@property
end

def property=(value)
@property = value
end

So what is going on here? Well... we still have the distinction of fields and methods, but in Ruby, your fields are ALWAYS private. You can't make them public, so when you call a method, it will never be ambiguous with accessing a field. This means, invoking a method with no arguments, you can just drop the parenthesis because they are redundant. In fact, you can even drop them when there ARE arguments, as long as it doesn't make it ambiguous in conjunction with other method calls or whatever. I think this makes Ruby as clean as it is, and makes it really look like you are reading English... almost.

What about Groovy though? Well, they support a similar paradigm. Defining the same property is 1 line as well, but it looks like this:

def property

And it is essentially equivalent to creating getProperty() and setProperty(value). BUT! The consequence of seamless integration with Java means you can't drop the parenthesis in every method case. They too support dropping them when there are arguments, and it doesn't make it ambiguous, except when there are no arguments and it isn't a getter. Thus, in Ruby you could have "stream.close" but in Groovy it would have to be "stream.close()". This may seem minor, but every time I have to add those parens in Groovy, I'm reminded that Ruby's grammar feels so much more internally consistent.

I guess I wrote a lot about that, but for some reason that minor detail really irks me. Before I just end with only a single gripe, I better add a couple more for good measure. I haven't tried nested classes in Ruby yet (though I've read they are possible), but Groovy definitely doesn't support them, at least not now. I think this is something they will eventually get to, but as it stands, this is a major limitation. This seriously cuts short the "seamless integration" with Java that I feel is one of the significant strengths of Groovy. Not much more I can say about that, but maybe it's also because it is getting late and I am tired.

One more issue? Null. Groovy tried so hard to be like Ruby, but they missed yet another thing that I really like about Ruby. In Ruby, nil (Java and Groovy's null) is an object, just like any other object. What does this mean? Well, null pointer exceptions... no such thing. Instead they become a method missing error. This was a very cool concept to me the first time I saw it. I'm not sure if it allows significantly more concise code, but it does seem to pretty up the code, at least to me. A list of method calls as conditionals is a lot easier for me to parse than a mix of == and method conditionals. Visually, calling methods makes each condition a single entity, unlike with an == or != conditional. For example:

if connection != null && !connection.is_connected

vs

if !connection.nil? && !connection.connected?

Which brings me to another point that I won't go into too much details... but being able to add question marks and exclamation points to my method names has got me wishing I could do it in every language. Beyond cutting a couple characters from the method length, they allow you to add meta info about the method that is visible at a glance... such as question mark for asking a boolean question, and exclamation for indicating state will be changed (which are essentially the Ruby standards for their usage).

Ok, I have ranted enough. I haven't proofread this, because it is late. If anyone happens to read this, just enjoy or hate it as it is.

Mike

Monday, June 23, 2008

A JRuby Swing Library

Well, I haven't really posted anything yet, mostly because there is always something else to do. So, in an effort to actually start writing something, I have decided to post a little Ruby "library" I wrote a while ago. I put in the sarcastic quotes because it's quite a tiny library, if you can even call it that, but I think it has potential to be quite useful. I recently ported it to groovy for another personal project, and maybe I will post that next.

At any rate, before I list the code, I just wanted to say what its purpose is. Call me crazy (I probably am), but I like Java's Swing. Why? Well, it's portable in the sense that Java is portable... that is, you can easily install Java anwhere and thus have Swing at your fingertips... you can't really say that for most other UI libraries I have used (admittedly a small list). Either your window library of choice is X platform only (I'm looking at you Microsoft), or is just not nearly as pervasive as Java. Swing also does an OK job of looking decent, in my non-graphical-arts-critical eye (so take that with a grain of salt), and it can mostly look like your native platform with a special toggling (somewhere buried in the API that I end up always looking up, even though it is 1 or 2 lines of code).

So, with the good comes bad. I'm sure you can site many other bad things that I just don't have the experience or interest to point out, but the leading problem I am aware of, both in experience writing Swing GUIs and in reading other people mention the problem, is that it is an inherently tree structure being expressed in a non-tree syntax. The solution? XML! Well, there are many other options besides XML that provide a tree structure and don't make you want to gouge your eyes out, but XML happens to be pretty easy to parse in that most languages have a pre-packaged XML library. Thus, XML! Besides, XML is a lowest common denominator, everyone basically understands it, right? Isn't that what the XML enthusiasts try to shove down our throats?

Thus SwingXML was born, my tiny "library" that will take an XML definition, and load it into memory as a Swing component tree. Beyond representing the components in their inherent tree structure, it has the added benefit of separating your view definition from your view logic. In the groovy version I added a feature that I have not yet added to the Ruby version.

Without further ado:

require "java"
require "rexml/document"

class SwingXml
def initialize(xml)
document = REXML::Document.new(xml)
@widget_hash = {}
@widget = handle document.root, nil
end

attr_reader :widget

def [](widget_symbol)
@widget_hash[widget_symbol.to_sym]
end

private
def handle(element, parent)
raise ArgumentError, "Element #{element.name} does not have an sxmlId!" unless element.attributes.has_key? "sxmlId"
raise ArgumentError, "Duplicate key found on #{element.name} (#{element.attributes['sxmlId']})!" if @widget_hash.has_key? element.attributes["sxmlId"].to_sym

widget = eval "#{element.name}.new"
@widget_hash[element.attributes["sxmlId"].to_sym] = widget

element.attributes.each do |name, value|
eval "widget.set_#{name} #{value}" unless name.index("sxml") == 0
end

element.elements.each do |child|
handle child, widget
end

if element.attributes.has_key? "sxmlAction"
eval "parent.#{element.attributes['sxmlAction']} widget" unless parent.nil?
else
parent.add widget unless parent.nil?
end

widget
end
end

So, that's it! Pretty small for doing seemingly quite a bit, right? If you are wondering how to use the above "library", think of the SwingXml object as the root of your Swing component tree, while it is also a hash of the contained components. Typically, you would have a JFrame at the root, but you could even break them up more fine grained and have them be a panel or canvas of some sort. The components contained within the tree are accessible via their sxmlId values as indexes, which are an attribute you must specify on each xml element. You can even add more complicated things like layouts and whatnot with an sxmlAction which specifies how the object should be added to its parent.

As a simple example:

frame = SwingXml.new "<javax.swing.JFrame sxmlId=\"frame\" default_close_operation=\"javax.swing.JFrame::EXIT_ON_CLOSE\"><java.awt.FlowLayout sxmlId=\"frameLayout\" sxmlAction=\"set_layout\"/><javax.swing.JButton sxmlId=\"helloButton\" text=\"'Hello World!'\"/><javax.swing.JButton sxmlId=\"goodbyeButton\" text=\"'Goodby World!'\"/></javax.swing.JFrame>"

listener = java.awt.event.ActionListener.new
def listener.actionPerformed(e)
puts "Hello world!"
end
frame[:helloButton].add_action_listener listener

listener = java.awt.event.ActionListener.new
def listener.actionPerformed(e)
puts "Goodbye world!"
end
frame[:goodbyeButton].add_action_listener listener

frame[:frame].pack
frame[:frame].set_visible true

For easier reading, here is the XML but not embedded in the Ruby code:

<javax.swing.JFrame sxmlId=\"frame\" default_close_operation=\"javax.swing.JFrame::EXIT_ON_CLOSE\">
<java.awt.FlowLayout sxmlId=\"frameLayout\" sxmlAction=\"set_layout\"/>
<javax.swing.JButton sxmlId=\"helloButton\" text=\"'Hello World!'\"/>
<javax.swing.JButton sxmlId=\"goodbyeButton\" text=\"'Goodby World!'\"/>
</javax.swing.JFrame>

In the groovy port, I added some code to remove the need for javax.swing.JXXX and java.awt.XXX, but I didn't add this enhancement to the Ruby code, but it should be pretty trivial to add. That small addition makes the XML a lot less of a pain to deal with. Well... less of a pain anyways.

I hope you enjoyed this, and I hope to make these posts more frequent!

Mike