enhance
Enhance a remix; allows nesting remixables, adding columns & functions to a remixed resource
remixable <Symbol> Name of remixable to enhance (plural or singular name of is :remixable module) model_class <Class, symbol, String> Name of the remixable generated Model Class. block <Proc> Enhancements to perform
When you have one remixable:
class Video
include DataMapper::Resource
remix Comment
enhance :comments do
remix n, :votes #This would result in something like YouTubes Voting comments up/down
property :updated_at, DateTime
def backwards; self.test.reverse; end;
end
When you remixe the same remixable modules twice:
class Article
include DataMapper::Resource
remix n, :taggings, :for => User, :model => "UserArticleTagging"
remix n, :taggings, :for => Bot, :model => "BotArticleTagging"
enhance :taggings, "UserArticleTagging" do
property :updated_at, DateTime
belongs_to :user
belongs_to :tag
end
enhance :taggings, "BotArticleTagging" do
belongs_to :bot
belongs_to :tag
end
# File lib/dm-is-remixable/is/remixable.rb, line 260 def enhance(remixable,remixable_model=nil, &block) inflector = DataMapper::Inflector # always use innermost singular underscored constant name remixable_name = inflector.singularize(remixable.to_s) remixable_name = inflector.underscore(remixable_name).to_sym class_name = if remixable_model.nil? @remixables[remixable_name].keys.first else name = inflector.demodulize(remixable_model.to_s) inflector.underscore(name).to_sym end model = @remixables[remixable_name][class_name][:model] unless @remixables[remixable_name][class_name].nil? unless model.nil? model.class_eval &block else raise Exception, "#{remixable} must be remixed with :model option as #{remixable_model} before it can be enhanced" end end
# File lib/dm-is-remixable/is/remixable.rb, line 75 def is_remixable? @is_remixable ||= false end
remix
Remixes a Remixable Module
cardinality <~Fixnum> 1, n, x ...
remixable <Symbol> plural of remixable; i.e. Comment => :comments
options <Hash> options hash
:model <String> Remixed Model name (Also creates a storage_name as tableize(:model))
This is the class that will be created from the Remixable Module
The storage_name can be changed via 'enhance' in the class that is remixing
Default: self.name.downcase + "_" + remixable.suffix.pluralize
:as <String> Alters the name that the remixable items will be available through, this WILL NOT
create the standard accessor
Default: tableize(:class_name)
:for|:on <String> Class name to join to through Remixable
This will create a M:M relationship THROUGH the remixable, rather than
a 1:M with the remixable
:via <String> changes the name of the second id in a unary relationship
see example below; only used when remixing a module between the same class twice
ie: self.class.to_s == options[:for||:on]
:unique <Boolean> Only works with :for|:on; creates a unique composite key
over the two table id's
Given: User (Class), Addressable (Module)
One-To-Many; Class-To-Remixable remix n, :addressables, :model => "UserAddress", :as => "addresses" Tables: users, user_addresses Classes: User, UserAddress User.user_addresses << UserAddress.new => Raise No Method Exception since it was alias with :as User.addresses << UserAddress.new -------------------------------------------- --------------------------------------------
Given: User (Class), Video (Class), Commentable (Module)
Many-To-Many; Class-To-Class through RemixableIntermediate (Video allows Commentable for User) Video.remix n, :commentables :for => 'User' #:for & :on have same effect, just a choice of wording... -------------------------------------------- --------------------------------------------
Given: User (Class), User (Class), Commentable (Module)
Many-To-Many Unary relationship between User & User through comments User.remix n, :commentables, :as => "comments", :for => 'User', :via => "commentor" => This would create user_id and commentor_id as the
# File lib/dm-is-remixable/is/remixable.rb, line 139 def remix(cardinality, remixable, options={}) assert_kind_of 'remixable', Symbol, String, Module #A map for remixable names to Remixed Models @remixables = {} if @remixables.nil? # Allow nested modules to be remixable to better support using dm-is-remixable in gems # Example (from my upcoming dm-is-rateable gem) # remix n, "DataMapper::Is::Rateable::Rating", :as => :ratings remixable_module = case remixable when Symbol then DataMapper::Ext::Object.full_const_get(Object, DataMapper::Inflector.classify(remixable)) when String then DataMapper::Ext::Object.full_const_get(Object, remixable) when Module then remixable end unless remixable_module.is_remixable? raise Exception, "#{remixable_module} is not remixable" end if options[:class_name] warn '+options[:class_name]+ is deprecated, use :model instead' options[:model] = options.delete(:class_name) end inflector = DataMapper::Inflector model = inflector.underscore(self.name) model = inflector.camelize(model + '_' + remixable_module.suffix) #Merge defaults/options options = { :as => nil, :model => model, :for => nil, :on => nil, :unique => false, :via => nil, :connect => false }.update(options) #Make sure the class hasn't been remixed already unless DataMapper::Ext::Object.full_const_defined?(inflector.classify(options[:model])) #Storage name of our remixed model options[:table_name] = DataMapper::Inflector.tableize(inflector.demodulize(options[:model])) #Other model to mix with in case of M:M through Remixable options[:other_model] = options[:for] || options[:on] DataMapper.logger.info "Generating Remixed Model: #{options[:model]}" model = generate_remixed_model(remixable_module, options) # map the remixable to the remixed model # since this will be used from 'enhance api' i think it makes perfect sense to # always refer to a remixable by its demodulized underscored constant name remixable_key = inflector.demodulize(remixable_module.name) remixable_key = inflector.underscore(remixable_key).to_sym populate_remixables_mapping(model, options.merge(:remixable_key => remixable_key)) # attach RemixerClassMethods and RemixerInstanceMethods to remixer if defined by remixee if DataMapper::Ext::Object.full_const_defined? "#{remixable_module}::RemixerClassMethods" extend DataMapper::Ext::Object.full_const_get("#{remixable_module}::RemixerClassMethods") end if DataMapper::Ext::Object.full_const_defined? "#{remixable_module}::RemixerInstanceMethods" include DataMapper::Ext::Object.full_const_get("#{remixable_module}::RemixerInstanceMethods") end #Create relationships between Remixer and remixed class if options[:other_model] # M:M Class-To-Class w/ Remixable Module as intermediate table # has n and belongs_to (or One-To-Many) remix_many_to_many cardinality, model, options else # 1:M Class-To-Remixable # has n and belongs_to (or One-To-Many) remix_one_to_many cardinality, model, options end else DataMapper.logger.warn "#{__FILE__}:#{__LINE__} warning: already remixed constant #{options[:model]}" end end
Generated with the Darkfish Rdoc Generator 2.