¶ ↑
dm-is-remixableA rewrite of the wonderful dm-is-remixable gem by Cory O’Daniel.
¶ ↑
Features# API that closely matches that of datamapper's +has+ method. # Relationships can be declared directly inside the remixable module. # Full support for remixing models as intermediates in m:m relationships (multiple times in the same class) # A small, readable and easy to understand codebase.
¶ ↑
Goals (roughly in that order)# [NEEDS SPECS] Allow to pass additional query options to the generated relationships to/through remixables # [NEEDS SPECS] Allow to remix other remixables inside the remixable module # Think about how best to include/extend functionality into the remixed and the remixing model # Allow to remix target or intermediate models without establishing any relationships # This will allow to naturally define different relationships to the same remixed model without calling remix # Full support for CPKs (by allowing to declare full FK property options in :source_key and :target_key options) # Allow remixing a parent model (i.e. the remixer belongs_to the remixed model) # Add back support for enhance (although it shouldn't be needed that often anymore) # think about possibilities to integrate with Cory O'Daniel's dm-property-manager (to get that polymorphic feeling)
¶ ↑
Status# 136 examples, 0 failures # 97.2% 3 file(s) 259 Lines 176 LOC
¶ ↑
API usage (not cut into stone, but promising)module Addressable extend DataMapper::Model is :remixable property :id, Serial property :address, String, :nullable => false belongs_to :country has n, :phone_numbers end module Linkable extend DataMapper::Model is :remixable property :id, Serial property :created_at, DateTime property :updated_at, DateTime end class Link include DataMapper::Resource property :id, Serial property :uri, URI end class Country include DataMapper::Resource property :id, Serial property :name, String has n, :person_addresses end class PhoneNumber include DataMapper::Resource property :id, Serial property :number, String belongs_to :person_address end class Person include DataMapper::Resource property :id, Serial property :name, String end # # Relate a remixable module to the receiving class. # # @param [Fixnum] cardinality # @param [Symbol,String] relationship_name # @param [Hash] options # # @option options [Symbol,String,Model] :remixable # @option options [Symbol,String,Model] :model # @option options [Symbol,String,Model,Hash] :through # # # @example 1:1 remixable with default naming conventions # # Person.remix 1, :address, 'PersonAddress', :remixable => :addressable # OR # Person.remix 1, :address, 'PersonAddress', :remixable => 'Addressable' # OR # Person.remix 1, :address, 'PersonAddress', :remixable => Addressable # # 1) Defines the PersonAddress model and includes the Addressable module. # 2) Establishes the following relationships on the participating models. # # Person.has 1, :address, 'PersonAddress', :target_key => [:person_id] # PersonAddress.belongs_to :person, 'Person' # # # # @example 1:1 remixable with explicit options # # Person.remix 1, :address, 'PersonAddress', # :remixable => :addressable, # :target_key => [:human_id] # # OR # # Person.remix 1, :address, 'PersonAddress', # :remixable => 'Addressable', # :target_key => [:human_id] # # OR # # Person.remix 1, :address, 'PersonAddress', # :remixable => Addressable, # :target_key => [:human_id] # # 1) Defines the PersonAddress model and includes the Addressable module. # 2) Establishes the following relationships on the participating models. # # Person.has 1, :address, 'PersonAddress', :target_key => [:human_id] # PersonAddress.belongs_to :human, 'Person' # # # # @example 1:m remixables with default naming conventions # # Person.remix n, :addresses, 'PersonAddress', :remixable => :addressable # OR # Person.remix n, :addresses, 'PersonAddress', :remixable => 'Addressable' # OR # Person.remix n, :addresses, 'PersonAddress', :remixable => Addressable # # 1) Defines the PersonAddress model and includes the Addressable module. # 2) Establishes the following relationships on the participating models. # # Person.has n, :addresses, 'PersonAddress', :target_key => [:person_id] # PersonAddress.belongs_to :person, 'Person' # # # # @example 1:m remixables with explicit options # # Person.remix n, :addresses, 'PersonAddress', # :remixable => :addressable, # :target_key => [:human_id] # # OR # # Person.remix n, :addresses, 'PersonAddress', # :remixable => 'Addressable', # :target_key => [:human_id] # # OR # # Person.remix n, :addresses, 'PersonAddress', # :remixable => Addressable, # :target_key => [:human_id] # # 1) Defines the PersonAddress model and includes the Addressable module. # 2) Establishes the following relationships on the participating models. # # Person.has n, :addresses, 'PersonAddress', :target_key => [:human_id] # PersonAddress.belongs_to :human, 'Person' # # # # @example m:m through remixable with default naming conventions # # Person.remix n, :references, 'Link', :through => :linkable # OR # Person.remix n, :references, 'Link', :through => 'Linkable' # OR # Person.remix n, :references, 'Link', :through => Linkable # # 1) Defines the PersonReference model and includes the Linkable module. # 2) Establishes the following relationships on the participating models. # # PersonReference.belongs_to :person # PersonReference.belongs_to :link # # Person.has n, :person_references, 'PersonReference' # Link.has n, :person_references, 'PersonReference' # # Person.has n, :references, 'Link', :through => :person_references, :via => :link # # # # @example m:m through remixable with explicit options # # Person.remix n, :references, 'Link', # :through => [ :person_references, { # :remixable => :linkable, # :model => 'PersonReferenceLink', # defaults to 'PersonReference' # :source_key => [:human_id], # defaults to :person_id # :target_key => [:reference_id] # defaults to :link_id # }] # # OR # # Person.remix n, :references, 'Link', # :through => [ :person_references, { # :remixable => 'Linkable', # :model => 'PersonReferenceLink', # defaults to 'PersonReference' # :source_key => [:human_id], # defaults to :person_id # :target_key => [:reference_id] # defaults to :link_id # }] # # OR # # Person.remix n, :references, 'Link', # :through => [ :person_references, { # :remixable => Linkable, # :model => 'PersonReferenceLink', # defaults to 'PersonReference' # :source_key => [:human_id], # defaults to :person_id # :target_key => [:reference_id] # defaults to :link_id # }] # # 1) Defines the PersonReference model and includes the Linkable module. # 2) Establishes the following relationships on the participating models. # # PersonReferenceLink.belongs_to :human, 'Person' # PersonReferenceLink.belongs_to :reference, 'Link' # # Person.has n, :person_links, 'PersonReferenceLink', :target_key => [:human_id] # Link.has n, :person_links, 'PersonReferenceLink', :target_key => [:reference_id] # # Person.has n, :references, 'Link', :through => :person_references, :via => :reference # # # # @example self referential m:m through remixable (probably needs more work) # # Person.remix n, :friends, 'Person', # :through => [ :social_contacts, { # :remixable => :social_contact, # :model => 'Friendship', # defaults to 'PersonReference' # :source_key => [:person_id], # defaults to :person_id # :target_key => [:other_person_id] # defaults to :person_id # }] # # OR # # Person.remix n, :friends, 'Person', # :through => [ :social_contacts, { # :remixable => 'SocialContact', # :model => 'Friendship', # defaults to 'PersonReference' # :source_key => [:person_id], # defaults to :person_id # :target_key => [:other_person_id] # defaults to :person_id # }] # # OR # # Person.remix n, :friends, 'Person', # :through => [ :social_contacts, { # :remixable => SocialContact, # :model => 'Friendship', # defaults to 'PersonReference' # :source_key => [:person_id], # defaults to :person_id # :target_key => [:other_person_id] # defaults to :person_id # }] # # 1) Defines the PersonReference model and includes the Linkable module. # 2) Establishes the following relationships on the participating models. # # Friendship.belongs_to :person, 'Person' # Friendship.belongs_to :other_person, 'Person' # # Person.has n, :friendships, :model => 'Friendship', :target_key => [:person_id] # Link.has n, :friendships, :model => 'Friendship', :target_key => [:other_person_id] # # Person.has n, :friends, :model => 'Person', :through => :friendships, :via => :other_person # def remix(cardinality, relationship_name, *args) # ... end
¶ ↑
CopyrightCopyright © 2009 Martin Gamsjaeger (snusnu). See LICENSE for details.