Concerns is powerfull method of object decomposition:
http://37signals.com/svn/posts/3372-put-chubby-models-on-a-diet-with-concerns
But this pattern is easilly can be abused: when you just spliting object behavior physicaly, not logicaly, you've got messy code.
The core point is tracking the internal interface between an object and a concern! Minimal & explicit interface force you to craft more clean and reusable concerns. The ideal concern is ruby's Enumerable, which require only one method to be implemented in hosting class.
Gem strong_concerns is technically helping you to create concerns in a right way.
For dependency tracing you should turn on role before usage (DCI inspired)!
Add this line to your application's Gemfile:
gem 'strong_concerns'
And then execute:
$ bundle
Or install it yourself as:
$ gem install strong_concerns
module Old
# list methods required for concern
def self.require_methods
%w[bith_date]
end
def age
((Date.today - bith_date)/365.0).to_i
end
def young?
age < options[:young]
end
def reproductive?
(options[:young]..options[:old]).include?(age)
end
def old?
age > options[:old]
end
end
module Searchable
def self.require_methods
%w[all]
end
def find_by_name(name)
all.select {|item| item.first_name =~ /#{name}/}
end
end
class Person < Struct.new(:name, :bith_date)
def self.all
[new('nicola', 33), new('ivan', 33)]
end
extend StrongConcerns
concern Old,
exports_methods: %w[age young? reproductive?],
old: 70,
young: 14
class_concern Searchable,
exports_methods: %w[find_by_name]
end
nicola = Person.new('nicola', Date.parse('1980-03-05'))
nicola.reproductive? #=> raise RoleNotActive error
nicola.as(Old)
if nicola.reproductive?
puts "Cool, make me a child!"
end
Person.as(Searchable)
.find_by_name('nicola') #=> Person(name: 'nicola')
- Fork it
- Create your feature branch (
git checkout -b my-new-feature
) - Commit your changes (
git commit -am 'Add some feature'
) - Push to the branch (
git push origin my-new-feature
) - Create new Pull Request