module Sequel::Plugins::Composition::ClassMethods

Attributes

compositions[R]

A hash with composition name keys and composition reflection hash values.

Public Instance Methods

composition(name, opts=OPTS) click to toggle source

Define a composition for this model, with name being the name of the composition. You must provide either a :mapping option or both the :composer and :decomposer options.

Options:

:class

if using the :mapping option, the class to use, as a Class, String or Symbol.

:composer

A proc used to define the method that the composition getter method will call to create the composition.

:decomposer

A proc used to define the method called before saving the model object, if the composition object exists, which sets the columns in the model object based on the value of the composition object.

:mapping

An array where each element is either a symbol or an array of two symbols. A symbol is treated like an array of two symbols where both symbols are the same. The first symbol represents the getter method in the model, and the second symbol represents the getter method in the composition object. Example:

# Uses columns year, month, and day in the current model
# Uses year, month, and day methods in the composition object
{mapping: [:year, :month, :day]}
# Uses columns year, month, and day in the current model
# Uses y, m, and d methods in the composition object where
# for example y in the composition object represents year
# in the model object.
{mapping: [[:year, :y], [:month, :m], [:day, :d]]}
# File lib/sequel/plugins/composition.rb, line 94
def composition(name, opts=OPTS)
  opts = opts.dup
  compositions[name] = opts
  if mapping = opts[:mapping]
    keys = mapping.map{|k| k.is_a?(Array) ? k.first : k}
    if !opts[:composer]              
      late_binding_class_option(opts, name)
      klass = opts[:class]
      class_proc = proc{klass || constantize(opts[:class_name])}
      opts[:composer] = proc do
        if values = keys.map{|k| get_column_value(k)} and values.any?{|v| !v.nil?}
          class_proc.call.new(*values)
        else
          nil
        end
      end
    end
    if !opts[:decomposer]
      setter_meths = keys.map{|k| :"#{k}="}
      cov_methods = mapping.map{|k| k.is_a?(Array) ? k.last : k}
      setters = setter_meths.zip(cov_methods)
      opts[:decomposer] = proc do
        if (o = compositions[name]).nil?
          setter_meths.each{|sm| set_column_value(sm, nil)}
        else
          setters.each{|sm, cm| set_column_value(sm, o.public_send(cm))}
        end
      end
    end
  end
  raise(Error, "Must provide :composer and :decomposer options, or :mapping option") unless opts[:composer] && opts[:decomposer]
  define_composition_accessor(name, opts)
end
define_composition_accessor(name, opts=OPTS) click to toggle source

Define getter and setter methods for the composition object.

# File lib/sequel/plugins/composition.rb, line 131
def define_composition_accessor(name, opts=OPTS)
  composer_meth = opts[:composer_method] = Plugins.def_sequel_method(@composition_module, "#{name}_composer", 0, &opts[:composer])
  opts[:decomposer_method] = Plugins.def_sequel_method(@composition_module, "#{name}_decomposer", 0, &opts[:decomposer])
  @composition_module.class_eval do
    define_method(name) do 
      if compositions.has_key?(name)
        compositions[name]
      elsif frozen?
        # composer_meth is private
        send(composer_meth)
      else
        compositions[name] = send(composer_meth)
      end
    end
    alias_method(name, name)

    meth = :"#{name}="
    define_method(meth) do |v|
      modified!
      compositions[name] = v
    end
    alias_method(meth, meth)
  end
end
freeze() click to toggle source

Freeze composition information when freezing model class.

Calls superclass method
# File lib/sequel/plugins/composition.rb, line 157
def freeze
  compositions.freeze.each_value(&:freeze)
  @composition_module.freeze

  super
end