Mark Needham

Thoughts on Software Development

Archive for the ‘Ruby’ tag

Ruby: Refactoring from hash to object

without comments

Something I’ve noticed when I play around with Ruby in my own time is that I nearly always end up with the situation where I’m passing hashes all over my code and to start with it’s not a big deal.

Unfortunately I eventually get to the stage where I’m effectively modelling an object inside a hash and it all gets very difficult to understand.

I’ve written a few times before about incrementally refactoring code so this seemed like a pretty good chance for me to try that out.

The code in the view looked something like this:

<% @tweets.each do |tweet| %>
  <%= tweet[:key] %>  <%= tweet[:value][:something_else] %>
<% end %>

@tweets was being populated directly from a call to CouchDB so to start with I needed to change it from being a collection of hashes to a collection of objects:

I changed the Sinatra calling code from:

get '/' do
  @tweets = get_the_couchdb_tweets_hash
end

to:

get '/' do
  tweets_hash = get_the_couchdb_tweets_hash
  @tweets = tweets_hash.map { |tweet| TweetViewModel.new(tweet) }
end

where TweetViewModel is defined like so:

class TweetViewModel
  attr_accessor :key, :value
 
  def initialize(tweet_hash)
    @key = tweet_hash[:key]
    @value = tweet_hash[:value]
  end
 
  def get(lookup)
    if lookup == :key
      key
    else
      value
    end
  end
 
  alias_method :[], :get
end

The next step was to get rid of the get method and rename those attr_accessor methods to something more intention revealing.

class TweetViewModel
  attr_accessor :url, :messages
 
  def initialize(tweet_hash)
    @url = tweet_hash[:key]
    @messages = tweet_hash[:value]
  end
end
<% @tweets.each do |tweet| %>
  <%= tweet.url %>  <%= tweet.messages[:something_else] %>
<% end %>

I originally didn’t realise how easy it would be to make the TweetViewModel pretend to temporarily be a Hash but it actually made it really easy for me to change the code and know that it was working the whole way.

For someone with more Ruby experience perhaps it wouldn’t be necessary to break out the refactoring like this because they could fairly confidently do it in one go.

Written by Mark Needham

February 27th, 2011 at 8:10 pm

Posted in Incremental Refactoring,Ruby

Tagged with

Ruby: Where to define the method?

with 5 comments

In our application we deal with items which can be put into a shopping cart.

An item is defined like so:

class Item < ActiveRecord::Base
 
end

One problem that we had to solve recently was working out how to display a message to the user if the item they wanted to buy was out of stock.

We can find out if items are out of stock by making a call to an external service:

1
2
3
4
5
6
7
def out_of_stock_items
  items_from_external_service_call.map do |i|
    item = look_up_item_by(i[:id])
    item.number_available = i[:number_available]
    ...
  end
end

Line 5 is the interesting one because we needed to work out where to define the ‘number_available’ method.

The easiest way to do it is this:

class Item < ActiveRecord::Base
  attr_accessor :number_available
end

But it seems a bit misleading because the concept of availability doesn’t exist in every context that we use the ‘Item’ object.

Another approach could be to add an instance method to each of the cart items in that context which is a bit more complicated:

def out_of_stock_items
  items_from_external_service_call.map do |i|
    item = look_up_item_by(i[:id])
 
    def item.number_available=(value)
      @number_available = value
    end
 
    def item.number_available
      @number_available
    end
 
    item.number_available = i[:number_available]
    ...
  end
end

Right now we’ve gone for the easier option and put the method onto the ‘Item’ class but I’d be curious how others would solve this problem…

Written by Mark Needham

February 3rd, 2011 at 7:37 pm

Posted in Ruby

Tagged with

Ruby: Sorting by boolean fields

with one comment

We were doing a bit of work on RapidFTR in the ThoughtWorks Pune office today and one problem my pair and I were trying to solve was how to sort a collection of objects by a boolean field.

Therefore given the following array of values:

form_sections = [FormSection.new(:enabled => false, :name => "a", :order => 1), 
                 FormSection.new(:enabled => true, :name => "b", :order => 2)]

We wanted to display those form sections which were disabled at the bottom of the page.

We originally tried the following:

form_sections.sort_by { |row| [row.enabled, row.order] }

But got the following error:

undefined method `<=>' for true:TrueClass

We figured we’d need to convert the true and false values to equivalent values which is demonstrated on this Stack Overflow post:

form_sections.sort_by { |row| [row.enabled ? 0 : 1, row.order] }

I didn’t realise it would be that simple to do – it’s pretty neat.

Written by Mark Needham

January 8th, 2011 at 1:15 pm

Posted in Ruby

Tagged with

Ruby: One method, two parameter types

with 2 comments

One interesting thing that I’ve noticed while coding in Ruby is that due to the dynamicness of the language it’s possible to pass values of different types into a given method as parameters.

For example, I’ve recently come across a few examples of methods designed like this:

1
2
3
4
5
6
def calculate_foo_prices(foos)
   ...
   [foos].flatten.each do |foo|
      # do something
   end
end

This allows us to use the method like this:

# foos would come in as an array from the UI
foos = [Foo.new, Foo.new, Foo.new]
calculate_foo_prices(foos)

Or like this:

calculate_foo_prices(Foo.new)

It becomes quite confusing to understand why what is supposedly already a collection is being put inside an array on line 3 of the first example when you first read it.

An alternative would be to pull out a different method for calculating the price of the single Foo:

def calculate_foo_price(foo)
   calculate_foo_prices([foo])
end

And then simplify the original method:

1
2
3
4
5
6
def calculate_foo_prices(foos)
   ...
   foos.each do |foo|
      # do something
   end
end

While writing this I was thinking that another way could be to change the original method to look like this by using the splat operator:

1
2
3
4
5
6
def calculate_foo_prices(*foos)
   ...
   foos.each do |foo|
      # do something
   end
end

Which means that we can use the same method for both situations:

calculate_foo_prices(Foo.new)
# foos would come in as an array from the UI
foos = [Foo.new, Foo.new, Foo.new]
calculate_foo_prices(*foos)

I’m guessing the latter is more idiomatic Ruby or perhaps there’s another way I’m not aware of yet?

Written by Mark Needham

December 7th, 2010 at 5:01 am

Posted in Ruby

Tagged with

Ruby: Exiting a ‘loop’ early

with 6 comments

We recently had a problem to solve which at its core required us to iterate through a collection, look up a value for each key and then exit as soon as we’d found a value.

The original solution looped through the collection and then explicitly returned once a value had been found:

def iterative_version
  v = nil
  [1,2,3,4,5].each do |i|
    v = long_running_method i
    return v unless v.nil?
  end
  v
end
def long_running_method(value)
  puts "inside the long running method with #{value}"
  return nil if value > 3
  value
end

Which we run like so:

p "iterative value is #{iterative_version.to_s}"

This prints the following when we run it:

inside the long running method with 1
"iterative value is 1"

I figured there must be a more functional way to solve the problem and I eventually came up with this:

def functional_version
  [1,2,3,4,5].map {|i| long_running_method i }.find { |i| !i.nil? }
end

Which prints the following when we run it:

inside the long running method with 1
inside the long running method with 2
inside the long running method with 3
inside the long running method with 4
inside the long running method with 5
"functional value is 1"

The problem is that collections in Ruby are eager evaluated so we evaluate every single item in the collection before we get the first non nil value.

Luckily the lazylist gem comes to our rescue and allows us to solve the problem in a functional way:

require 'lazylist'
def lazy_version
  lazy_list([1,2,3,4,5]).find { |i| !i.nil? }
end
 
def lazy_list(values)
  list(long_running_method(values.first)) { lazy_list(values - [values.first]) } 
end

Running that gives us this:

inside the long running method with 1
"lazy value is 1"

I’ve never come across a problem where I needed to use a lazy list but finally I have and I think the version which uses it is pretty neat.

Written by Mark Needham

December 1st, 2010 at 5:56 pm

Posted in Ruby

Tagged with

Ruby: Checking for environment variables in a script

with 2 comments

I’ve been working on a Ruby script to allow us to automate part of our Solr data setup and part of the task was to check that some environment variables were set and throw an exception if not.

I got a bit stuck initially trying to work out how to return a message showing only the missing environment variables but it turned out to be pretty simple when I came back to it a couple of hours later.

So for my future reference than anything else, this is what I ended up with:

1
2
3
4
5
  variables = %w{VARIABLE_1 VARIABLE_2}
  missing = variables.find_all { |v| ENV[v] == nil }
  unless missing.empty?
    raise "The following variables are missing and are needed to run this script: #{missing.join(', ')}."
  end

I recently came across ‘%w’ which creates a string array out of the values that we specify.

In this case we therefore end up with…

> %w{VARIABLE_1 VARIABLE_2}
["VARIABLE_1", "VARIABLE_2"]

…which I think is pretty neat!

The other neat method is ‘join’ on line 4 which concatenates all the elements of an array while putting the provided separator in between each element.

In this case if we had neither of the variables specified we’d end up with the following:

> ["VARIABLE_1", "VARIABLE_2"].join(', ')
"VARIABLE_1, VARIABLE2"

Written by Mark Needham

November 24th, 2010 at 6:34 pm

Posted in Ruby

Tagged with

Capistrano, sed, escaping forward slashes and ‘p’ is not ‘puts’!

without comments

Priyank and I have been working on automating part of our deployment process and one task we needed to do as part of this is replace some variables used in one of our shell scripts.

All the variables in the script refer to production specific locations but we needed to change a couple of them in order to run the script in our QA environment.

We’re therefore written a sed command, which we call from Capistrano, to allow us to do this.

The Capistrano script looks a little like this:

task :replace_in_shell do
	directory = "/my/directory/path"
	sed_command = "sed 's/^some_key.*$/#{directory}/' shell_script.sh > shell_script_with_qa_variables.sh"
	run sed_command
end

Unfortunately this creates the following sed command which isn’t actually valid syntactically:

sed 's/^some_key.*$//my/directory/path/' shell_script.sh > shell_script_with_qa_variables.sh

We decided to use ‘gsub’ to escape all the forward slashes in the directory path and to work out which parameters we needed to pass to ‘gsub’ we started using irb.

Executing gsub with the appropriate parameters leads us to believe that 2 backslashes will be added:

ruby-1.8.7-p299 > "/my/directory/path".gsub("/", "\\/")
 => "\\/my\\/directory\\/path"

This is because there IRB is implicitly called ‘inspect’ on the result which shows a different string than what we would actually get.

While writing this blog post I’ve also learnt (thanks to Ashwin) that ‘p’ is not the same as ‘puts’ which is what I originally thought and has been driving me crazy as I try to understand why everything I print includes an extra backslash!

The following code:

p "/mark/dir/".gsub("/", "\\/")

is the same as typing:

puts "/mark/dir/".gsub("/", "\\/").inspect

We were able to change our Capistrano script to escape forward slashes like so:

task :replace_in_shell do
	directory = "/my/directory/path"
	sed_command = "sed 's/^some_key.*$/#{directory.gsub("/", "\\/"}/' shell_script.sh > shell_script_with_qa_variables.sh"
	run sed_command
end

Written by Mark Needham

November 18th, 2010 at 6:40 pm

Posted in Ruby

Tagged with , ,

Rails: A slightly misleading error

without comments

We recently created a new project to handle the reporting part of our application and as with all our projects we decided not to checkin any configuration “.yml’ files but rather ‘.yml.example’ files which people can then customise for their own environments.

So in our config directory would look something like this when you first checkout the project:

  • config
    • database.yml.example
    • some.yml.example

And we’d need to copy those files to get ‘.yml’ versions, changing any parameters that we need to for our local environment.

The disadvantage of this approach is that you have an extra step on using a project for the first time, a step that I’ve been meaning to automate.

Several people ran into a somewhat confusing error message when running our rake file after forgetting to create these ‘.yml’ files which looked like this:

> rake db:migrate
(in /Users/mneedham/SandBox/project)
rake aborted!
uninitialized constant ActiveRecord
 
(See full trace by running task with --trace)

Running with –trace didn’t reveal our mistake but interestingly launching ‘script/console’ did!

script/console
Loading development environment (Rails 2.3.5)
/Users/mneedham/SandBox/project/config/environment.rb:4:in `initialize':Errno::ENOENT: No such file or directory - /Users/mneedham/SandBox/project/config/some.yml
/Users/mneedham/SandBox/project/vendor/rails/railties/lib/rails/backtrace_cleaner.rb:2:NameError: uninitialized constant ActiveSupport::BacktraceCleaner
/Users/mneedham/SandBox/project/vendor/rails/railties/lib/console_with_helpers.rb:5:NameError: uninitialized constant ApplicationController
ruby-1.8.7-p299 >

This is the environment.rb file in which we were loading that yml file:

config/environment.rb

....
require 'yaml'
some_file = File.join(File.dirname(__FILE__), "some.yml")
...

It’s a relatively simple mistake to make so I was surprised that rake didn’t tell us that the file didn’t exist rather than failing when trying to require ActiveRecord.

Written by Mark Needham

November 16th, 2010 at 9:17 pm

Posted in Ruby

Tagged with ,

Active Record: Nested attributes

without comments

I recently learnt about quite a neat feature of Active Record called nested attributes which allows you to save attributes on associated records of a parent model.

It’s been quite useful for us as we have a few pages in our application where the user is able to update models like this.

We would typically end up with parameters coming into the controller like this:

class FoosController < ApplicationController
   def update
      # params = { :id => "1", :foo => { :baz => "new_baz", :bar_attributes => { :value => "something" } } }
      Foo.update_instance(params[:id], params[:foo])
      ...
   end
end

Our original implementation of ‘update_instance’ looked like this:

class Foo < ActiveRecord::Base
   has_one :bar
 
   class << self
      def update_instance(id, attributes_to_update)
         instance = Foo.find(id)
         instance.attributes = attributes_to_update
         instance
      end
   end
end

Unfortunately when we execute that code the ‘bar’ association gets completely removed because we didn’t specify the id of ‘bar’ when we were updating the attributes.

We need to change the code slightly to make sure it doesn’t do that:

class Foo < ActiveRecord::Base
   has_one :bar
 
   class << self
      def update_instance(id, attributes_to_update)
         instance = Foo.find(id)
         attributes_to_update[:bar_attributes][:id] = instance.bar.id
         instance.attributes = attributes_to_update
         instance
      end
   end
end

It now works as we’d expect.

There’s other cool stuff that you can do with nested attributes described on the documentation page if you have ‘has_many’ associations but for now we’re just using the simpler ‘has_one’.

Written by Mark Needham

November 9th, 2010 at 6:37 pm

Posted in Ruby

Tagged with ,

Ruby: Getting Active Record validation errors twice

without comments

I managed to create an interesting problem for myself while playing around with some code whereby I was ending up with validation errors appearing twice every time I called ‘valid?’ on a specific model.

I figured I was probably doing something stupid and in fact a few replies by Aaron Baldwin on a mailing list thread on ‘rubyonrails-talk’ helped explain exactly what I’d done:

Are you calling require ‘employee’ anywhere? If so you are likely
causing the model to load twice which causes duplicate errors because
the validates_presence_of method gets called twice.

I’d put the following code into a controller elsewhere somewhat unnecessarily since it didn’t seem to be picking up the location of my model at the time:

code_submissions_controller.rb

require 'models/code_submission'
 
class CodeSubmissionsController < ApplicationController
  def new
    CodeSubmission.new  
  end
end

require doesn’t load a file if it’s already been included but Aaron points out why it does on this occasion:

You are right that “require” will only load the file once. But if you load the class another way calling “require” will load it again.

As I understand it that controller code would also implicitly require ‘code_submission’ by the convention of inserting an underscore between the ‘CodeSubmission’ constant’s names.

We therefore effectively have the following two requires:

require 'code_submission'
require 'models/code_submission'

Which explain how the file gets loaded twice and therefore why the validation method fires twice and therefore creates two errors!

Written by Mark Needham

October 29th, 2010 at 4:27 am

Posted in Ruby

Tagged with ,