bgentry / dm-is-remixable

A rewrite of dm-is-remixable that tries to feel more dm'ish and adds desired behavior

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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 © 2009 Martin Gamsjaeger (snusnu). See LICENSE for details.

About

A rewrite of dm-is-remixable that tries to feel more dm'ish and adds desired behavior

License:MIT License