Traits for Ruby 2.0: like mixins, but better
Ruby
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
lib
test
.gitignore
.travis.yml
LICENSE
README.md
Rakefile
traitor.gemspec

README.md

traitor Build Status

Traitor is a basic implementation of [Traits](http://en.wikipedia.org/wiki/Trait_(computer_programming) (duh) for Ruby 2.0.

Also, it might be the only library in the world that needs refinements. </troll>

Installation

Add this line to your application's Gemfile:

rvm install ruby-2.0.0-preview1
gem 'traitor'

And then execute:

$ bundle

Or install it yourself as:

$ gem install traitor

Behavior reusability through Traits

Traits are like Ruby modules in the sense that they can be used to define composable units of behavior, but they are not included hierarchically. They are truly composable, meaning that are pieces that must either fit perfectly or the host object must provide a way for them to do it, normally resolving conflicts by explicitly redefining the conflicting methods.

Say we have a Colorable trait:

Colorable = Trait.new do
  attr_accessor :color

  def ==(other)
    other.color == color
  end
end

And a Shapeable trait:

Shapeable = Trait.new do
  attr_accessor :sides

  def ==(other)
    other.sides == sides
  end
end

Now we would like an object composed of those two traits:

class Rectangle
  uses Shapeable
  uses Colorable
end

This obviously doesn't work -- if we try to call #== on a Rectangle, it doesn't know which implementation should it call. Colorable or Shapeable? See the error:

Rectangle.new == Rectangle.new
# TraitConflict: Conflicting methods: #==

Traits have no hierarchy, so no one prevails over the others. The only way to use both traits is to provide an explicit conflict resolution:

class Rectangle
  uses Shapeable
  uses Colorable

  def ==(other)
    colorable_equal = trait_send(Colorable, :==, other)
    shapeable_equal = trait_send(Shapeable, :==, other)
    colorable_equal && shapeable_equal
  end
end

Now we can use #== safely because we control how conflicts are resolved. Note that we have access to either implementation via trait_send.

Contributing

  1. Fork it
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Added some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create new Pull Request

Who's this

This was made by Josep M. Bach (Txus) under the MIT license. I'm @txustice on twitter (where you should probably follow me!).