Archive for September, 2010
Ruby: Random Observations
I thought it’d be interesting to write down some of my observations after working with Ruby and Rails for a couple more weeks so here are some more things I’ve come across and others that I’ve got confused with…
The :: operator
(apparently also known as the leading double colon operator)
I came across this while looking at some of the rails_warden code to try to understand how that gem opens the ActionController::Base class to add helper methods to it.
The code reads as follows:
77 78 79 80 81 82 83 84 85 86 | Rails.configuration.after_initialize do class ::ActionController::Base include RailsWarden::Mixins::HelperMethods include RailsWarden::Mixins::ControllerOnlyMethods end module ::ApplicationHelper include RailsWarden::Mixins::HelperMethods end end |
The ‘::’ operator is used on line 78 and it means that Ruby will look in the global scope for the constant which follows the operator – in this case ActionController::Base. Marcos Ricardo explains this in more detail on his blog.
In this case I’m not entirely sure why the operator is necessary since there doesn’t seem to be another constant defined with the same name in the local scope.
The !! operator
This is another operator that I came across while reading the Warden code.
97 98 99 | def halted? !!@halted end |
Sidu explained that this operator ensures that true or false will be returned rather than a truish/falish value.
For example:
ruby-1.8.7-p299 > !!nil => false
ruby-1.8.7-p299 > !!1 => true
Single ‘=’ in if statements
A mistake I’ve made a few times now is using ‘=’ in if statements instead of ‘==’ which means that the code tends to fail in a somewhat confusing way.
I’m not sure if this is because I’ve been playing around with Clojure a bit recently and in Clojure you use ‘=’ for comparison or if I do this anyway and usually get saved by the compiler.
Either way it’s very frustrating!
Open classes
I’m used to being able to see exactly what is defined on a class in one place but in Ruby it’s possible to open a class from anywhere and add to it or change the existing behaviour.
I still don’t know all of the hooks that Rails provides for opening classes so it’s still a big magical for me at the moment.
Ruby: Testing declarative_authorization
As I mentioned in a post earlier in the week we’re using the declarative_authorization gem to control access to various parts of our application and as we’ve been migrating parts of the code base over to use that framework one thing we’ve noticed is that there seems to be a diminishing return in how much value we get from writing specs to cover each rule that we create.
We found that while it is possible to write a spec to cover every single rule it sometimes seems like the spec is just duplicating what the rule already describes.
This is especially the case if the rule just describes access to a particular controller action.
For example we had something similar to the following:
role :x do has_permission_on :some, :to => [:action_1, :action_2, :action_3] end
For which we wrote specs similar to this (which make use of the test helpers provided with the framework):
context "user with role x" do before(:each) do @some_user = Factory.build(:user_with_role_x) Authorization.current_user=@some_user end context "some controller" do [:action_1, :action_2, :action_3].each do |action| it "should be allow to view #{action}" do should_be_allowed_to action, :some end end end end
It certainly seems to me that if the code we’re writing uses a DSL then we lose the value of testing as a documentation feature and to an extent our tests are another slightly different DSL.
There is certainly still value in writing specs for more complicated rules where it is quite easy to write the code wrong but otherwise it seems like we’re just increasing the build time (albeit slightly) without necessarily getting much value.
Another approach that we’re using to test authorisation more indirectly is to ensure that we have automated tests at a higher level covering pieces of functionality which make use of the declarative authorization rules.
It doesn’t make sense to cover every single rule with this type of test because they take longer to run but I think there is still some value in ensuring that everything is ‘glued’ together correctly.
SICP: Iterative process vs Recursive process functions
I was working my way through some of the exercises in SICP over the weekend and one that I found particularly interesting was 1.11 where you have to write a function by means of a recursive process and then by means of an iterative process.
A function f is defined by the rule that f(n) = n if n<3 and f(n) = f(n - 1) + 2f(n - 2) + 3f(n - 3) if n> 3. Write a procedure that computes f by means of a recursive process. Write a procedure that computes f by means of an iterative process.
To write that function recursively is relatively straight forward:
(in Clojure)
(defn f [n] (if (< n 3) n (+ (f (- n 1)) (* 2 (f (- n 2))) (* 3 (f (- n 3))))))
The solution to this problem by means of an iterative process will still use recursion but we won’t need to keep a track of all the previous calls to the function on the stack because we will keep the current state of the calculation in parameters that we pass to the function.
This will also mean that the second function is tail recursive.
I was initially a bit stuck about how to write this function but luckily Shishir was around and had a better idea.
The solution we eventually ended up with looks like this:
(defn g [n a b c count] (cond (< n 3) n (> count (- n 3)) a :else (g n (+ a (* 2 b) (* 3 c)) a b (+ count 1)))) (defn f [n] (g n 2 1 0 0))
I think there should be a way to get rid of the first condition but I’m not sure exactly how to do that – the solution on the wiki is a bit better.
The difference in the approach to writing the iterative version is that we needed to think about solving the problem from the bottom down rather than from the top down.
In this case that meant that we needed to pass around parameters for the first 3 values of n i.e. 1, 2 and 3 which had values of 0, 1 and 2 respectively.
The way we’ve passed the parameters through the function means that ‘a’ represents the value that we’ll eventually want to return when we reach the exit condition of the function.
We pass ‘a’ and ‘b’ into the next function call as ‘b’ and ‘c’ which means that we lose the current f(n-3) value on the next recursion of the function.
I still find writing these types of functions quite tricky so I’d be interested in any advice that people have about this.
Ruby: Caught out by no type checking
I got caught out for a little while today when comparing a value coming into a controller from ‘params’ which we were then comparing with a collection of numbers.
The code was roughly like this…
class SomeController def some_action some_collection = [1,2,3,4,5] selected_item = some_collection.find { |item| item == params[:id] } end end
…and since the ‘id’ being passed in was ’1′ I was expected that we should have a selected item but we didn’t.
The actual code being executed would be…
[1,2,3,4,5].find { |item| item == "1" }
…which of course doesn’t match any values since we’re comparing a string to an integer.
The fix is relatively simple…
class SomeController def some_action some_collection = [1,2,3,4,5] selected_item = some_collection.find { |item| item == params[:id].to_i } end end
…but I found it interesting that this is the type of thing that would have been caught if we had static type checking but is something you’d aim to cover with a test with a dynamic language.
In this case we had been refactoring the code and having slightly changed the way it worked internally our interaction tests didn’t quite cover this scenario properly so we had to go and update those.
So far I’ve certainly seen that Ruby/Rails can make you more productive and this is the first time I’ve seen a situation where I wished for C#’s static typing…if just for a little while.
Ruby: FactoryGirl & declarative_authorization – Random thoughts
Two other gems that we’re using on my current project are FactoryGirl and declarative_authorization.
We use declarative_authorization for controlling access to various parts of the application and FactoryGirl allows us to build objects for use in our tests.
We wanted to be able to deactivate the authorization when creating test objects because otherwise our test wouldn’t have permission to create certain objects.
Our original approach was to create a ‘God’ role which we could assign to the ‘current_user’ in our tests therefore allowing us to create whatever objects we wanted.
The problem with this approach is that it means we end up creating this role as part of the production data.
One way to get around this is to put an if statement into the seed data where the role creation happens and only allow that role to be created in test/development environments but that’s a bit of a hack.
In any case declarative_authorization provides a function to get around this problem and if we pass a block to that function any code executed within the block will be free of the authorization rules setup:
require 'declarative_authorization/maintenance' include Authorization::TestHelper without_access_control do Factory(:foo, :bar => "myBar") end
This works pretty well and there is more documentation on the github page.
Unfortunately we already had 400 or so usages of the Factory throughout the code base which weren’t wrapped with ‘without_access_control’ and had been relying on the ‘God’ role.
We’d have the same problem if we created a ‘create_without_access_control’ method on Factory as well so came up with the idea of overriding the ‘create’ method of FactoryGirl to always be called inside the ‘without_access_block’:
require 'declarative_authorization/maintenance' include Authorization::TestHelper class Factory class << self alias_method :original_create, :create def create(name, overrides = {}) without_access_control do original_create(name, overrides) end end end end
This helps solve the problem although I guess it could be quite misleading since the ‘create’ method being called would be a different one than you might expect.
On the other hand FactoryGirl is only being used to create tests objects and we never directly test our authorization functionality using FactoryGirl so it doesn’t seem to be too much of a problem to change it in this way.
Learning: Study habits
I came across an interesting article from the New York Times that Michael Feathers originally linked to on twitter which discusses some of the common ideas that we have about good study habits, pointing out the flaws in them and suggesting alternative approaches.
The author starts out by making some interesting observations about spacing out our learning:
An hour of study tonight, an hour on the weekend, another session a week from now: such so-called spacing improves later recall, without requiring students to put in more overall study effort or pay more attention, dozens of studies have found.
No one knows for sure why. It may be that the brain, when it revisits material at a later time, has to relearn some of what it has absorbed before adding new stuff — and that that process is itself self-reinforcing.
I’ve written previously about re-reading books and how we seem to notice different things when we process information the second time around.
I’ve also found that when I don’t understand something immediately that if I leave it for a while and come back to it later on it often makes more sense even though I haven’t deliberately tried to make sense of it.
For example I was playing with Clojure in November and December last year but then didn’t look at it again until quite recently.
Looking at it the second time the syntax and style of programming felt more natural to me which I think is because I’d played around with J a bit which is slightly similar.
This time I’m also using emacs and Swank instead of La Clojure and that combination of tools also feels more natural than it did when I tried last year. I don’t have any explanation for why that is!
I found the following section related to the type of material studied quite interesting:
Varying the type of material studied in a single sitting — alternating, for example, among vocabulary, reading and speaking in a new language — seems to leave a deeper impression on the brain than does concentrating on just one skill at a time.
I don’t do this intentionally but I find that my interest in something rarely lasts more than a couple of hours so I tend to switch between coding, blogging and reading when I’m doing anything software related in my own time.
The article also goes on to talk about the value of testing ourself on material, suggesting that the harder it is to remember something the harder it is to later forget.
The only correlation I can think of with respect to my own learning style is that I find it easier to remember information if I write about it or explain it to someone else.
It’s a very interesting article and well worth reading.
Rails: Polymorphism through ‘constantize’
One interesting feature of Rails which Shishir pointed out the other day is the ability to take a user provided value and make use of Active Support’s ‘constantize’ method to effectively achieve polymorphism directly from the user’s input.
As an example if we were creating different types of widgets from the same web page we might have several different forms that the user could submit.
We could have a hidden field representing the type of the widget like so:
<%= hidden_field_tag :widget_name, :foo %>
And then when the form is submitted we can instantiate the appropriate widget class.
class WidgetController def some_action widget_name.constantize.new(params) end def widget_name "#{params[:widget_name]}_widget".camelize end end
Where the individual widget classes would be like this:
class FooWidget end
class BarWidget end
The closest we’d get to doing this with C#/associated frameworks would be to create a dictionary with the widget name as the key and a function representing the object instantiation as the value.
Therefore if we wanted to add a new widget we’d still have to change the WidgetController whereas with the Rails solution we’d just have to change the HTML and add a new report which would then be automatically hooked up.
I’m sure there’s some other clever things you can do with Rails that I don’t yet know about but this struck me as one of those things that helps explain why it’s possible to develop some web applications much more quickly with Rails than with other frameworks.
Ruby: Checking an array contains an item
A couple of times in the past few days I’ve wanted to check if a particular item exists in an array and presumably influenced by working for too long with the .NET/Java APIs I keep expecting there to be a ‘contains’ method that I can call on the array!
More as an attempt to help myself remember than anything else, the method we want is actually called ‘include?’.
Therefore…
[1,2,3].include?(2) => true
[1,2,3,4].include?(5) => false
One other quite neat thing is that we can use that in tests when we want to check that an array contains one item that we’re expecting.
This is much better than having to specify a specific index which is what we often seem to end up doing in Java/C#.
We therefore end up with (RSpec) tests similar to this:
response.flash[:error].include?("Some error message").should be_true
jQuery UI Tabs: Changing selected tab
We’re using the tabs part of the jQuery UI library on the project I’m currently working on and one thing we wanted to do was change the default tab that was being selected.
The documentation suggested that one way to do this was to give the index of the tab we wanted selected when calling the tabs function:
$( ".selector" ).tabs({ selected: 3 });
Since we wanted to select the tab by name based on a value from the query string we thought it would probably be simpler if we could just set the selected tab using a css class.
Our initial thought was that we could put the ‘ui-tabs-hide’ class on the divs that we wanted to hide and then not put that class on the one that we wanted to show.
Unfortunately that didn’t work and the first tab was still being selected…
We downloaded version 1.8.2 of the library via Google’s CDN (which seems really cool!) and were able to see that our class was actually intentionally being removed!
10523 10524 | if (o.selected >= 0 && this.anchors.length) { // check for length avoids error when initializing empty list this.panels.eq(o.selected).removeClass('ui-tabs-hide'); |
Luckily a little further down the file there is a comment which explains some other ways to manipulate the selected tab:
10749 10750 10751 10752 10753 | // Selected tab // use "selected" option or try to retrieve: // 1. from fragment identifier in url // 2. from cookie // 3. from selected class attribute on <li> |
We need to put the class ‘ui-tabs-selected’ on the appropriate <li> and then that will be the one that gets selected.
Ruby: Hash ordering
The application that I’m working on at the moment is deployed into production on JRuby but we also use the C Ruby 1.8.7 interpreter when developing locally since this allows us much quicker feedback.
As a result we sometimes come across interesting differences in the way that the two runtimes work.
One that we noticed yesterday is that if you create a hash, the order of the keys in the hash will be preserved when interpreted on JRuby but not with the C Ruby interpreter.
For example if we create the following hash in Ruby 1.8.7 it will be resorted into alphabetical order:
ruby-1.8.7 > a_hash = { :a => 1, :d => 2, :c => 3 }
=> {:a=>1, :c=>3, :d=>2}Whereas in JRuby it will maintain its order:
jruby-1.5.1 > a_hash = { :a => 1, :d => 2, :c => 3 }
=> {:a=>1, :d=>2, :c=>3}We found a post on the Ruby mailing list from a couple of years ago which pointed out that from Ruby 1.9 the order is in fact maintained.
However, Gregory Seidman also pointed out that…
Hashes are inherently unordered. Hashes provide amortized O(1) insertion and retrieval of elements by key, and that’s it. If you need an ordered set of pairs, use an array of arrays. Yes, this is a pet peeve of mine.
Since that is indeed what we want we’ve created an array of arrays in our code instead. The code to retrieve values from the array of arrays is a bit more verbose but at least the order is now guaranteed!