A Snippet for declaring ruby class in vim

•March 13, 2009 • Leave a Comment

I create a new file with vim, I want to define a class within it. In Ruby world, a lot of time I want to name my class as file_name.classify. So it will be nice to let vim generates this automatically for me.

I open up ruby.vim in ftplugin, a lot of snippets has already been defined there. Now I just need to add one more:


Snippet cla class ``ClassName()``<CR><{}><CR>end

What this does is when you enter “cla” and press <Tab> key (or whatever key you define for snippet expansion), it will call ClassName method and write down return value along with remaining string. Nothing fancy here.

Now let’s look at the most interesting part of this post: function ClassName()

function! ClassName()
  return substitute(expand("%:t:r"), '\(\%^\|_\)\(.\)', '\U\2', "g")
endfunction

Basically what this function does is to convert underscored_word into UnderscoredWord.

Run Rspec within vim and seeing result in your Firefox2

•March 11, 2009 • Leave a Comment

Thanks to cassiomarques, we can run rspec from within vim and see the results in FF.

You might be surprised though, when you run it and wait and wait, and nothing seems happening. Mostly likely it just that the running code raise an exception and no output to either FF or you vim. If you look at the terminal window where you started you vim, you will see the backtrace though. So why not display the backtrace in FF then, just like the image below?

A failure message window

A failure message window

Here is the part of the script modified from his original one:

begin
  ::Spec::Runner::CommandLine.run(::Spec::Runner::OptionParser.parse(argv, STDERR, STDOUT))
rescue Exception => e
  File.open("#{report_file}", "w") do |file|
    file.write("#{e.message} <br />")
    file.write e.backtrace.join("<br />")
  end
end

Another thing worth to mention is that handling vim type of links doesn’t work with his approach in either FF3 and FF2. I had to install a plugin called Mozex. My experience is that it only works for FF2. Once you install it and restart your FF2, go to Add-Ons and click on “Preference” of this plugin. goto “Universal” tab. type “vim” into the first textbox and /path/to/open_vim to the second one just like the image shown below:

Mozex plugin setup

Mozex plugin setup

Speaking of open_vim, since Mozex pass the whole URL (vim://Users/blah/blah.rb?line_number) back, so the regex for parsing it should be changed to:

 /vim:\/\/(.+)\?(\d+)/

List Presenter

•October 28, 2008 • Leave a Comment

In a typical Rails app, we have a lot of “index” action in almost every controllers. And in most cases, an index is a list of same type of objects. There are a lot of similar features we need to present these lists. So it makes sense to have a concept as ListPresenter and each individual presenter who presents a list should extend from it.

Of course, in Ruby, we don’t have to actually have a class called ListPresenter and do all the stuff that are not necessarily related to each other. We can have as many modules as we need. Each module does one particular task. and all presenters for list can mixin those modules.

Why it is good to do things this way? Let’s take an example: If all lists are HTML tables, and all tables have table headers with title of columns. Now we decide to use title case (such as ‘Column Name’) for these headers, we could manually type in these texts into your HTML template. The approach is straightforward, but bearing three potential problems.

  1. Since developers generally do not know how to type, one could easily have typos
  2. Two developers may develop two lists and one may think, wrongly, that title should be humanized (such as “Column name”). Then we end up with inconsistent UI. This inconsistency could also happen when a developer produced lists before the team decided title case. So he used humanized words back then. He had to come back fix them one by one, even with the best IDE ever – Windows notepad’s help, it still a tedious and boring task.
  3. Later on, the business doesn’t like title case, they want humanized case. Well, 4 boring hours, again!

In this case, a simple method can help, all it takes is a module which provides a html_table_columns method, as the following:

module HtmlTableColumns
  def html_table_columns(*args)
    self.send :define_method, :columns do
      returning([]) do |columns_hash|
        args.each do |arg|
          case arg
            when String, Symbol
              columns_hash << arg.to_s.titlecase})
            when Hash
              columns_hash << HashWithIndifferentAccess.new(arg)
            else
              raise ArgumentError.new("The params must be Hash, String or Symbols")
          end
        end
      end
    end
  end
end

This method defines a columns for class who calls this method. A call like:

  table_columns('name', "last_connected"
  {'user_login' => "User"}, 'status')

will generate a method like this (in RSpec):

      presenter.columns.should ==
      [{'name' => 'Name'},
       {"last_connected"=>"Last Connected"},
        {'user_login' => "User"}, {'status' => "Status"}]

As long as every developer uses this method, there will be no typo, no inconsistency. And if people ever want to change from title case to humanized words, there is only one place that needs to be changed and I believe readers know where.

This is just an example how group similar features into one place is nice. In general I believe if I can find a feature that is across more than one places, it’s worth my effort to group them into one place, use whatever pattern that is applicable. So after all, I guess this post is not about List Presenter, it is about a case study of DRY.

Intergrate RSpec Story Runner into CruiseControl.rb build process with HTML report

•June 25, 2008 • 2 Comments

Although still a work in progress, RSpec story runner is gaining popularity rapidly. I use it because I use Webrat for acceptance tests and Webrat integrates with the story runner seamlessly.

Then next thing I need is to create a task to integrate stories into CC.rb build process. And here it is:

desc "Run all stories"
task :all_stories do
    if out = ENV['CC_BUILD_ARTIFACTS']
        spec_out = "#{out}/Stories"
        mkdir_p spec_out unless File.directory? spec_out
        report_file_name = "#{spec_out}/index.html"
    else
        report_file_name = 'stories.html'
    end
    if ! spec_out.blank?
        sh "cp -r #{RAILS_ROOT}/vendor/plugins/rspec/story_server/prototype/javascripts/ #{spec_out}"
        sh "cp -r #{RAILS_ROOT}/vendor/plugins/rspec/story_server/prototype/stylesheets/ #{spec_out}"
    end
    sh "ruby #{RAILS_ROOT}/stories/all.rb -f html > #{report_file_name}"
end

Yes, ruby a_story.rb -f html will generate an html report instead of a plain text. That’s neat. But I also need to copy javascripts and stylesheets directories to #{spec_out} directory because the generated html report uses css and js files in these two directories.

Once you run this task as part of cruise task, you should see a Stories link under Custom Build Artifacts section. And once you click on it, you should see a page much like #{RAILS_ROOT}/vendor/plugins/rspec/story_server/prototype/stories.html.

The HTML report looks nice. But imagining when we have 100 stories all cozily live in this same single HTML file. It will take forever to load the page and it will be very difficult to find any useful information within it. My proposal is we actually generate a real index which contains just story names, and a color to indicate if they failed or not. Of course each story name is clickable which leads to another page for the detailed story report.

Textmate Colbalt color theme for IntelliJ

•May 15, 2008 • 6 Comments

I spent half hour making this xml file so that my IntelliJ looks like a textmate color theme, which is cool. It’s meant just for Ruby, not for Java. And it’s no way to be perfect. But at least I hope this can provide a start point for further tuning.

I used Monaco font, which feel free to use your own. But the truth is: Monaco is probably the best monospace font.

Due to wordpress’s uploading policy, the file ends with a pdf, but it’s a xml file (colbalt.xml). You need to remove pdf part give it “xml” as the suffix. Enjoy

Earthquake in SiChuan, China

•May 14, 2008 • 1 Comment

My experience with Presenter Pattern

•April 6, 2008 • 1 Comment

Default MVC layers handles one model, one form mode pretty well, but in reality, a lot of forms are not that simple. There are two classic examples:

  1. Multiple models are created/updated in one form
  2. One model is created/updated in one form, but in several different ways

When these scenarios happen, MVC framework becomes awkward. We have to either leak business logic into controllers, even views, or put view logic into models, or both. In this post, I want to talk about how to use Presenter Pattern to avoid putting view logic into the models.

Basically Presenter is one layer sitting between Controller and View layer, which should include all of your view logic. The first advantage we gain is that we can unit test view logic easily. Secondly, we can move all helper methods into presenters so that we can have a more elegant way to implement these methods. The third and the most important advantage we gain is that now the model is free from view logic, make its intention much more clear.

Now let’s see an example.

I have a model House, on creation form of House, there are some fields about this house. Some of them are required, some of them are optional. The form has two submit buttons, if a user click on button 1, she will become the owner of this house; if she clicks on button 2, she assigns another person to the owner of this house. When she assigns another person, she needs to pick a person before assigning, for the sake of simplicity, let’s assume she can pick a person from a drop-down list with all eligible person names.

Now if she clicks on button 1, she doesn’t need to choose any person from the drop-down list. But if she clicks on the button 2, she must select a person from that list, and if she doesn’t choose a person, she should get an error message to prompt her to do so. So we see a validation here, but this validation is totally view-specific, nothing to do with either House or Person models. In this situation, a presenter is a natural place to put this logic.

To implement this validation, one tool you absolutely need is the Validatable gem. Once a class includes a Validatable module, it has a lot of ActiveRecord-like validation logic such as validates_presence_of.

I will name my presenter after the form, in this case, NewHousePresenter, but if I know I will reuse this form in edit/update, I will simply name the presenter as HousePresenter.

Inside the presenter, I can have:

	validates_presence_of :owner_id, :if => lambda {|presenter|presenter.assign_owner?}

How to implement assign_owner? is just a matter of implementation of your view, I like to just set a hidden field with value “assign_owner” when clicking on the button 2 and “take_owner” when clicking on the button 1. Then the assign_owner? is just checking if the hidden field is string of “assign_owner”.

Isn’t it cool?

In my previous post More on form_for(@non_arb), I showed a trick to get polymorphic routes working so that the form can be

<% form(@presenter) %>

In my HousePresenter, I can just say:

	polymorphic_routes_for :house, :create_path => "house_owner_path", :update_path => "house_owner_path"

Not only is it for the sake of coolness, but also for the simplicity of the view and easiness to use the form in both create and update actions.

In my Presenter class, I also have an initialize declared as:

def initialize(params={})
  params.each_pair do |key, value|
    instance_variable_set("@#{key}", value)
  end
end

All this does is just blindly set instance variables for all params passed in. The reason for doing this is that I can easily setup a presenter for unit testing. The subclass of Presenter should implement a build class method to take params from the controller, and parse it into a hash that is sensible to the presenter and initialize. So the “constructor” remains simple for convenient construction while build can do complex logic that can be unit tested.

A build method can look like:

def self.build(house_params = {}, operation = "take_owner")
	
	presenter_params = {:house => House.new(house_params), :operation => operation}
	HousePresenter.new presenter_params
end

After all this, my HousesController#new and create can be as simple as:

def new
	@house_presenter = HousePresenter.build
end

def create
	@house_presenter = HousePresenter.build(params[:house], params[:operation])
	if @house_presenter.valid? && @house_presenter.house.save
		redirect_to(@house_presenter.house)
	else
		render :new
	end
end

Don’t they look like controller actions again? You can infer the edit/update code from here fairly easy.

But for the perfectionist, this line:

if @house_presenter.valid? && @house_presenter.house.save

is a little bit smelly. Bigger thing is: if the creation/update require more then just a save, then we need something else. I almost want to be able to say:

if @house_presenter.save!
...

and in save! I do whatever I need. I actually did that and Marcel Molina looked ultimately confused and I agree with him: Presenters are not meant for business transactions. hmm. well, it’s a long enough post, I would like to talk about this issue in my next post, if it eventually comes out.

 
Follow

Get every new post delivered to your Inbox.