• Home
  • About
  • Contact
  • Archives
Site Logo

Agile Web Development & Operations

Shaping and Evangelizing DevOps since 2008

  • Our Books
  • DevOps
  • Kanban & Agile
  • Tools & Technology

Rethinking code reuse with Modularity for Ruby

by Matthias Marschall on March 26, 2010 · 2 comments

Creative Commons License Trondheim Byarkiv

This is a guest post by our friends over at makandra, a cool Ruby on Rails development shop. Today they announce a great new Ruby gem for dealing with separating concerns in your ActiveRecord models.

Reusing code is hard. But although we knew that high-level components don’t work, we found ourselves rewriting similar code again and again for different projects. Was there maybe another angle from which to slice our code into reusable pieces?

We sat down and looked at what was truly worth sharing. Here are some of the many things we found:

  • Flag: A boolean attribute must be either true or false (not nil). The attribute has a default value. Also there is a named scope Model.flag which finds records for which the flag is true.

  • Searchable model: The records of a model can be searched, matching the query against the concatenation of some text attributes.

  • Booking sum: A numeric field is the sum of many bookings. A booking adds or substracts an amount from the sum. There are also absolute correction bookings, which overshadow all previous bookings.

These are all behaviors of individual classes, or as we call them, traits. They are different from components in that they do not provide the glue between classes or application layers. Traits are isolated building blocks. You bring the glue.

We field tested the trait pattern in some of our projects and it deeply transformed the way we work and reuse code. We extracted it all into a gem, Modularity,

Using and defining traits

Let’s look at the Flag trait in the list above. We would like to use it like we would use has_many or validates_presence_of, as a macro. For this Modularity defines a new keyword does, which includes a trait in a class:

class User < ActiveRecord::Base
  does 'flag', :admin, :default => false
end

class User < ActiveRecord::Base does 'flag', :admin, :default => false end

Implementing the flag trait with vanilla Ruby would be awkward. Modules are a bad fit here because we want to define stuff dependent on the flag’s name (include takes no arguments). Also our trait will have to call some ActiveRecord macros for the including class in order to define the validation and the scope. This is not how modules work in Ruby.

This is how traits are defined in Modularity:

module FlagTrait
  as_trait do |name, options|
    validates_inclusion_of name, :in => [true, false]
    has_defaults name => options[:default]
    named_scope name, :conditions => { name => true }        
  end
end

module FlagTrait as_trait do |name, options| validates_inclusion_of name, :in => [true, false] has_defaults name => options[:default] named_scope name, :conditions => { name => true } end end

Think of the as_trait block as a partial that renders itself into whatever class that does 'flag'. It defines the validation, sets the defaults (using the delicious has_defaults plugin and then defines a named scope, all based on the flag’s name.

Modularity has changed the way we do Ruby at makandra. No longer are macros something that only your framework can provide for your classes. Defined as traits, macros become a basic building block of your own application.

You can find more examples and use cases for traits on Modularity’s github page.

Filed Under: Tools & Technology Tagged With: ActiveRecord, Ruby, Ruby on Rails

Comments

  1. Tim says

    March 29, 2010 at 2:00 pm

    hey, cool idea …

    Reply

Trackbacks

  1. Tweets that mention Rethinking code reuse with Modularity for Ruby — Agile Web Operations -- Topsy.com says:
    March 27, 2010 at 5:06 pm

    […] This post was mentioned on Twitter by Matthias Marschall. Matthias Marschall said: New blog post: Rethinking code reuse with Modularity for Ruby http://bit.ly/97JlQD […]

    Reply

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Related Posts

  • Chef: RVM + Ruby Enterprise Edition as Default Ruby
  • How to Deploy Ruby on Rails With The Opscode Chef Application Cookbook
  • Far Future Expires Headers For Ruby On Rails With Nginx
  • RSpec Tips & Tricks
  • Real World Example: Using factory_girl to simplify our test setup
  • Aegis: Role-based Permissions for your Ruby on Rails application
  • Setting up a test database on a ruby on rails continuous integration server using SQL instead of schema.rb
  • webrat: Automated Acceptance Testing with RSpec or Cucumber
  • Seed Data In Ruby On Rails

Copyright © 2008 – 2018 · Agile Web Development & Operations