Skip to content

Instantly share code, notes, and snippets.

@ybart
Created July 27, 2012 18:18
Show Gist options
  • Save ybart/3189549 to your computer and use it in GitHub Desktop.
Save ybart/3189549 to your computer and use it in GitHub Desktop.
Depth Coding inline code
module Associations # :nodoc:
extend ActiveSupport::Concern
module ClassMethods
def has_many(name, options = {}, &extension)
Builder::HasMany.build(self, name, options, &extension)
end
end
end
module ActiveRecord::Associations::Builder
class Association #:nodoc:
class_attribute :valid_options
self.valid_options = [:class_name, :foreign_key, :select, :conditions, :include, :extend, :readonly, :validate]
# Set by subclasses
class_attribute :macro
attr_reader :model, :name, :options, :reflection
def self.build(model, name, options)
new(model, name, options).build
end
def initialize(model, name, options)
@model, @name, @options = model, name, options
end
def build
validate_options
reflection = model.create_reflection(self.class.macro, name, options, model)
define_accessors
reflection
end
end
end
module ActiveRecord::Associations::Builder
class Association #:nodoc:
attr_reader :model, :name, :scope, :options, :reflection
def mixin
@model.generated_feature_methods
end
private
def define_accessors
define_readers
define_writers
end
def define_readers
name = self.name
mixin.redefine_method(name) do |*params|
association(name).reader(*params)
end
end
def define_writers
name = self.name
mixin.redefine_method("#{name}=") do |value|
association(name).writer(value)
end
end
end
end
module ActiveRecord::Associations::Builder
class CollectionAssociation < Association #:nodoc:
CALLBACKS = [:before_add, :after_add, :before_remove, :after_remove]
self.valid_options += [
:table_name, :order, :group, :having, :limit, :offset, :uniq, :finder_sql,
:counter_sql, :before_add, :after_add, :before_remove, :after_remove
]
def self.build(model, name, options, &extension)
new(model, name, options, &extension).build
end
def initialize(model, name, options, &extension)
super(model, name, options)
@block_extension = extension
end
def build
wrap_block_extension
reflection = super
CALLBACKS.each { |callback_name| define_callback(callback_name) }
reflection
end
require 'active_support/core_ext/object/inclusion'
module ActiveRecord::Associations::Builder
class HasMany < CollectionAssociation #:nodoc:
self.macro = :has_many
self.valid_options += [:primary_key, :dependent, :as, :through, :source, :source_type, :inverse_of]
def build
reflection = super
configure_dependency
reflection
end
module ActiveRecord #:nodoc:
class Base
include Associations
end
end
module ActiveRecord
module Core
extend ActiveSupport::Concern
module ClassMethods
def generated_feature_methods
@generated_feature_methods ||= begin
mod = const_set(:GeneratedFeatureMethods, Module.new)
include mod
mod
end
end
end
end
module ActiveRecord
module Reflection # :nodoc:
extend ActiveSupport::Concern
included do
class_attribute :reflections
self.reflections = {}
end
# Reflection enables to interrogate Active Record classes and objects
# about their associations and aggregations. This information can,
# for example, be used in a form builder that takes an Active Record object
# and creates input fields for all of the attributes depending on their type
# and displays the associations to other objects.
#
# MacroReflection class has info for AggregateReflection and AssociationReflection
# classes.
module ClassMethods
def create_reflection(macro, name, scope, options, active_record)
case macro
when :has_many, :belongs_to, :has_one, :has_and_belongs_to_many
klass = options[:through] ? ThroughReflection : AssociationReflection
reflection = klass.new(macro, name, scope, options, active_record)
when :composed_of
reflection = AggregateReflection.new(macro, name, scope, options, active_record)
end
self.reflections = self.reflections.merge(name => reflection)
reflection
end
end
# Abstract base class for AggregateReflection and AssociationReflection. Objects of
# AggregateReflection and AssociationReflection are returned by the Reflection::ClassMethods.
class MacroReflection
def initialize(macro, name, scope, options, active_record)
@macro = macro
@name = name
@scope = scope
@options = options
@active_record = active_record
@plural_name = active_record.pluralize_table_names ?
name.to_s.pluralize : name.to_s
end
# Holds all the meta-data about an association as it was specified in the
# Active Record class.
class AssociationReflection < MacroReflection #:nodoc:
def initialize(*args)
super
@collection = [:has_many, :has_and_belongs_to_many].include?(macro)
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment