A rewrite of dm-is-remixable that tries to feel more dm'ish and adds desired behavior
Ruby
Switch branches/tags
Nothing to show
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
lib
spec
tasks
.document
.gitignore
LICENSE
README.rdoc
Rakefile
VERSION
dm-is-remixable.gemspec

README.rdoc

dm-is-remixable

A 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

Copyright

Copyright © 2009 Martin Gamsjaeger (snusnu). See LICENSE for details.