Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Failed attempt at a Logical ActiveRecord layer
# modeled off the Physical / Service / Logical layers
# advocated by http://enterpriserails.chak.org/full-text/chapter-3-organizing-with-modules
module Logical
class ARModelName
PHYSICAL = ARModel
attr_accessor :physical
private :physical
def initialize(physical)
@physical = physical.is_a?(PHYSICAL) ? physical : PHYSICAL.new
end
# first choice way to delegate attributes to PHYSICAL
# require 'forwardable'
# extend Forwardable
# def_delegators :@physical, :create, :create!
# def_delegators :@physical, :email, :email=, :normalized_email, :normalized_email=, :create!
#
# other possible ways to delegate attributes, for consideration
# delegate :email, :email=, :normalized_email, :normalized_email=, :to => @physical #active_support
# [:email, :normalized_email].each do |attribute|
# define_delegated_attribute(attribute)
# end
#
# Pass along the method to @physical if it responds_to? the method
# if so, define the method to avoid another method missing call, and call the method on @physical
# delegate :create!, :to => :@physical.class #active_support
# delegating specified PHYSICAL class methods
class << self
# delegate :create!, :to => PHYSICAL
[:create!, :create].each do |method|
define_method(method) do |*args|
result = PHYSICAL.send(method, *args)
if result.is_a?(PHYSICAL)
new_result = new(result)
new_result
else
result
end
end
end
end
# delegate all physical attributes, and define methods for them here as needed
def method_missing(method, *args, &block)
attribute_name = method.to_s[/^[^?!=]+/]
if PHYSICAL.column_names.include?(attribute_name)
define_delegated_attribute(attribute_name)
@physical.send(method, *args, &block)
elsif delegated_ar_methods.include?(method)
define_ar_method(method)
@physical.send(method, *args, &block)
else
super
end
end
def delegated_ar_methods
[:destroy, :save, :save!]
end
def define_ar_method(method)
class_eval do
define_method(method) do |*args,&block|
@physical.send(method,*args,&block)
end
end
end
def define_delegated_attribute(attribute)
# accessible attributes
unless PHYSICAL.accessible_attributes.include?(attribute.to_s)
class_eval do
define_method(attribute) do
@physical.attribute
end
end
# read only attributes
unless PHYSICAL.readonly_attributes.include?(attribute.to_s)
attribute_setter = "#{attribute}=".to_sym
class_eval do
define_method(attribute_setter) do |new_attribute|
@physical.send(attribute_setter, new_attribute)
end
end
end
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment