Skip to content

Commit

Permalink
rework definition of methods
Browse files Browse the repository at this point in the history
  • Loading branch information
jackdempsey committed Dec 7, 2008
1 parent fa3dd4f commit 8d5e96a
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 62 deletions.
120 changes: 70 additions & 50 deletions lib/sequel_polymorphic/sequel_polymorphic.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,63 +3,83 @@ module Plugins
module Polymorphic
# Apply the plugin to the model.
def self.apply(model, options = {})
raise "You must pass in an options hash!" if options.blank?
plural_model = model.to_s.downcase.pluralize
singular_model = model.to_s.downcase.singularize
if as_variable = (options[:belongs_to] or options[:many_to_one])
# defining the polymorphic model
model.class_eval %{associate(:many_to_one, :#{as_variable}, :reciprocal=>:#{plural_model},
:dataset=>(proc { klass = #{as_variable}_type.constantize; klass.filter(klass.primary_key=>#{as_variable}_id) }),
:eager_loader=>(proc do |key_hash, #{plural_model}, associations|
id_map = {}
#{plural_model}.each { |#{singular_model}| #{singular_model}.associations[:#{as_variable}] = nil; ((id_map[#{singular_model}.#{as_variable}_type] ||= {})[#{singular_model}.#{as_variable}_id] ||= []) << #{singular_model} }
id_map.each do |klass_name, id_map|
klass = klass_name.constantize
klass.filter(klass.primary_key=>id_map.keys).all do |related_obj|
id_map[related_obj.pk].each { |#{singular_model}| #{singular_model}.associations[:#{as_variable}] = related_obj }
end
end
end))
private
def _#{as_variable}=(#{as_variable})
self[:#{as_variable}_id] = (#{as_variable}.pk if #{as_variable})
self[:#{as_variable}_type] = (#{as_variable}.class.name if #{as_variable})
end
}
elsif one_to_many_variable = (options[:one_to_many] or options[:has_many])
raise "You must pass in an :as key-value pair!" unless as_variable = options[:as]
singular_one_to_many_variable = one_to_many_variable.to_s.singularize
model.class_eval %{
associate(:one_to_many, :#{one_to_many_variable}, :key=>:#{as_variable}_id) do |ds|
ds.filter(:#{as_variable}_type=>'#{model}')
end
private
def _add_#{singular_one_to_many_variable}(#{singular_one_to_many_variable})
#{singular_one_to_many_variable}.#{as_variable}_id = pk
#{singular_one_to_many_variable}.#{as_variable}_type = '#{model}'
#{singular_one_to_many_variable}.save
end
def _remove_#{singular_one_to_many_variable}(#{singular_one_to_many_variable})
#{singular_one_to_many_variable}.#{as_variable}_id = nil
#{singular_one_to_many_variable}.#{as_variable}_type = nil
#{singular_one_to_many_variable}.save
end
def _remove_all_#{one_to_many_variable}
#{singular_one_to_many_variable.capitalize}.filter(:#{as_variable}_id=>pk, :#{as_variable}_type=>'Post').update(:#{as_variable}_id=>nil, :#{as_variable}_type=>nil)
end
}
end
end

module InstanceMethods

end

module ClassMethods
def many_to_one(*args, &block)
able, options = *args
if options[:polymorphic]
model = self.class.to_s.downcase
plural_model = model.pluralize
singular_model = model.singularize
self.class_eval %{
associate(:many_to_one, :#{able}, :reciprocal=>:#{plural_model},
:dataset=>(proc { klass = #{able}_type.constantize; klass.filter(klass.primary_key=>#{able}_id) }),
:eager_loader=>(proc do |key_hash, #{plural_model}, associations|
id_map = {}
#{plural_model}.each do |#{singular_model}|
#{singular_model}.associations[:#{able}] = nil;
((id_map[#{singular_model}.#{able}_type] ||= {})[#{singular_model}.#{able}_id] ||= []) << #{singular_model}
end
id_map.each do |klass_name, id_map|
klass = klass_name.constantize
klass.filter(klass.primary_key=>id_map.keys).all do |related_obj|
id_map[related_obj.pk].each { |#{singular_model}| #{singular_model}.associations[:#{able}] = related_obj }
end
end
end)
)
private
def _#{able}=(#{able})
self[:#{able}_id] = (#{able}.pk if #{able})
self[:#{able}_type] = (#{able}.class.name if #{able})
end
}
else
associate(:many_to_one, *args, &block)
end
end

alias :belongs_to :many_to_one

def one_to_many(*args, &block)
one_to_many_variable, options = *args
many_class = one_to_many_variable.to_s.singularize
if able = options[:as]
self.class_eval %{
associate(:one_to_many, :#{one_to_many_variable}, :key=>:#{able}_id) do |ds|
ds.filter(:#{able}_type=>'#{self}')
end
private
def _add_#{many_class}(#{many_class})
#{many_class}.#{able}_id = pk
#{many_class}.#{able}_type = '#{self}'
#{many_class}.save
end
def _remove_#{many_class}(#{many_class})
#{many_class}.#{able}_id = nil
#{many_class}.#{able}_type = nil
#{many_class}.save
end
def _remove_all_#{one_to_many_variable}
#{many_class.capitalize}.filter(:#{able}_id=>pk, :#{able}_type=>'#{self}').update(:#{able}_id=>nil, :#{able}_type=>nil)
end
}
else
associate(:one_to_many, *args, &block)
end
end

alias :has_many :one_to_many

end # ClassMethods
end # Polymorphic
end # Plugins
Expand Down
16 changes: 4 additions & 12 deletions spec/sequel_polymorphic/sequel_polymorphic_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,11 @@

# Models we have: Post(name), Note(name), Asset(name)
describe Sequel::Plugins::Polymorphic do
it "should raise an error if you call :has_many without providing an :as" do
lambda do
class Blowup < Sequel::Model
is :polymorphic, :has_many => :items
end
end.should raise_error
it "should add :as to has_many/one_to_many" do

end

it "should raise an error if you call 'is :polymorphic' without any args" do
lambda do
class Blowup < Sequel::Model
is :polymorphic
end
end.should raise_error
it "should add :polymorphic => true to belongs_to" do

end
end

0 comments on commit 8d5e96a

Please sign in to comment.