Skip to content

Instantly share code, notes, and snippets.

@chrishunt
Created October 13, 2012 17:50
Show Gist options
  • Save chrishunt/3885528 to your computer and use it in GitHub Desktop.
Save chrishunt/3885528 to your computer and use it in GitHub Desktop.
Relations in Ruby
require 'relations'
class Employee
extend Relations
belongs_to :manager
end
require 'manager'
require 'employee'
describe Employee do
let(:manager) { Manager.new }
it 'belongs to a manager' do
subject.manager.should be_nil
subject.manager = manager
subject.manager.should == manager
end
it "adds itself to the manager's list of employees" do
manager.employees.should be_empty
subject.manager = manager
manager.employees.should include subject
end
end
require 'relations'
class Manager
extend Relations
has_many :employees
end
require 'employee'
require 'manager'
describe Manager do
let(:employee) { Employee.new }
it 'has many employees' do
subject.employees.should be_empty
subject.employees << employee
subject.employees.size.should == 1
subject.employees.should include employee
end
it "updates the employee's manager" do
employee.manager.should be_nil
subject.employees << employee
employee.manager.should == subject
end
end
module Relations
require 'active_support/inflector'
class RelationCollection < Array
def initialize(parent, parent_name, child_name)
@parent = parent
@parent_name = parent_name
@child_name = child_name
end
def <<(child)
unless child.send(@parent_name) == @parent
child.send "#{@parent_name}=", @parent
end
super unless include?(child)
end
end
def belongs_to(parent)
send(:attr_reader, parent)
define_method "#{parent}=" do |p|
instance_variable_set("@#{parent}", p)
p.send(self.class.name.underscore.pluralize) << self
end
end
def has_many(children)
define_method children do
collection = instance_variable_get "@#{children}"
unless collection
parent_name = self.class.name.underscore
collection = RelationCollection.new(self, parent_name, children)
instance_variable_set "@#{children}", collection
end
collection
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment