mirror of
https://github.com/drapergem/draper
synced 2023-03-27 23:21:17 -04:00
Merge branch 'active_model_support' of https://github.com/kurko/draper
This commit is contained in:
commit
b516bda9c5
9 changed files with 101 additions and 36 deletions
|
@ -1,5 +1,6 @@
|
||||||
require "draper/version"
|
require "draper/version"
|
||||||
require 'draper/system'
|
require 'draper/system'
|
||||||
|
require 'draper/active_model_support'
|
||||||
require 'draper/base'
|
require 'draper/base'
|
||||||
require 'draper/lazy_helpers'
|
require 'draper/lazy_helpers'
|
||||||
require 'draper/model_support'
|
require 'draper/model_support'
|
||||||
|
|
24
lib/draper/active_model_support.rb
Normal file
24
lib/draper/active_model_support.rb
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
module Draper::ActiveModelSupport
|
||||||
|
module Proxies
|
||||||
|
def create_proxies
|
||||||
|
# These methods (as keys) will be created only if the correspondent
|
||||||
|
# model descends from a specific class (as value)
|
||||||
|
proxies = {}
|
||||||
|
proxies[:to_param] = ActiveModel::Conversion if defined?(ActiveModel::Conversion)
|
||||||
|
proxies[:errors] = ActiveModel::Validations if defined?(ActiveModel::Validations)
|
||||||
|
proxies[:id] = ActiveRecord::Base if defined?(ActiveRecord::Base)
|
||||||
|
|
||||||
|
proxies.each do |method_name, dependency|
|
||||||
|
if model.kind_of?(dependency) || dependency.nil?
|
||||||
|
class << self
|
||||||
|
self
|
||||||
|
end.class_eval do
|
||||||
|
self.send(:define_method, method_name) do |*args, &block|
|
||||||
|
model.send(method_name, *args, &block)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -8,15 +8,11 @@ module Draper
|
||||||
|
|
||||||
DEFAULT_DENIED = Object.instance_methods << :method_missing
|
DEFAULT_DENIED = Object.instance_methods << :method_missing
|
||||||
DEFAULT_ALLOWED = []
|
DEFAULT_ALLOWED = []
|
||||||
FORCED_PROXY = [:to_param, :id]
|
|
||||||
FORCED_PROXY.each do |method|
|
|
||||||
define_method method do |*args, &block|
|
|
||||||
model.send method, *args, &block
|
|
||||||
end
|
|
||||||
end
|
|
||||||
self.denied = DEFAULT_DENIED
|
self.denied = DEFAULT_DENIED
|
||||||
self.allowed = DEFAULT_ALLOWED
|
self.allowed = DEFAULT_ALLOWED
|
||||||
|
|
||||||
|
include Draper::ActiveModelSupport::Proxies
|
||||||
|
|
||||||
# Initialize a new decorator instance by passing in
|
# Initialize a new decorator instance by passing in
|
||||||
# an instance of the source class. Pass in an optional
|
# an instance of the source class. Pass in an optional
|
||||||
# context inside the options hash is stored for later use.
|
# context inside the options hash is stored for later use.
|
||||||
|
@ -28,6 +24,7 @@ module Draper
|
||||||
self.class.model_class = input.class if model_class.nil?
|
self.class.model_class = input.class if model_class.nil?
|
||||||
@model = input.kind_of?(Draper::Base) ? input.model : input
|
@model = input.kind_of?(Draper::Base) ? input.model : input
|
||||||
self.options = options
|
self.options = options
|
||||||
|
create_proxies
|
||||||
end
|
end
|
||||||
|
|
||||||
# Proxies to the class specified by `decorates` to automatically
|
# Proxies to the class specified by `decorates` to automatically
|
||||||
|
@ -260,7 +257,7 @@ module Draper
|
||||||
private
|
private
|
||||||
|
|
||||||
def allow?(method)
|
def allow?(method)
|
||||||
(allowed.empty? || allowed.include?(method) || FORCED_PROXY.include?(method)) && !denied.include?(method)
|
(allowed.empty? || allowed.include?(method)) && !denied.include?(method)
|
||||||
end
|
end
|
||||||
|
|
||||||
def find_association_reflection(association)
|
def find_association_reflection(association)
|
||||||
|
|
|
@ -4,6 +4,7 @@ describe Draper::Base do
|
||||||
before(:each){ ApplicationController.new.set_current_view_context }
|
before(:each){ ApplicationController.new.set_current_view_context }
|
||||||
subject{ Decorator.new(source) }
|
subject{ Decorator.new(source) }
|
||||||
let(:source){ Product.new }
|
let(:source){ Product.new }
|
||||||
|
let(:non_active_model_source){ NonActiveModelProduct.new }
|
||||||
|
|
||||||
context("proxying class methods") do
|
context("proxying class methods") do
|
||||||
it "should pass missing class method calls on to the wrapped class" do
|
it "should pass missing class method calls on to the wrapped class" do
|
||||||
|
@ -195,7 +196,7 @@ describe Draper::Base do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context("selecting methods") do
|
describe "method selection" do
|
||||||
it "echos the methods of the wrapped class except default exclusions" do
|
it "echos the methods of the wrapped class except default exclusions" do
|
||||||
source.methods.each do |method|
|
source.methods.each do |method|
|
||||||
unless Draper::Base::DEFAULT_DENIED.include?(method)
|
unless Draper::Base::DEFAULT_DENIED.include?(method)
|
||||||
|
@ -208,27 +209,48 @@ describe Draper::Base do
|
||||||
DecoratorWithApplicationHelper.new(source).length.should == "overridden"
|
DecoratorWithApplicationHelper.new(source).length.should == "overridden"
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should always proxy to_param" do
|
|
||||||
source.send :class_eval, "def to_param; 1; end"
|
|
||||||
Draper::Base.new(source).to_param.should == 1
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should always proxy id" do
|
|
||||||
source.send :class_eval, "def id; 123456789; end"
|
|
||||||
Draper::Base.new(source).id.should == 123456789
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should not copy the .class, .inspect, or other existing methods" do
|
it "should not copy the .class, .inspect, or other existing methods" do
|
||||||
source.class.should_not == subject.class
|
source.class.should_not == subject.class
|
||||||
source.inspect.should_not == subject.inspect
|
source.inspect.should_not == subject.inspect
|
||||||
source.to_s.should_not == subject.to_s
|
source.to_s.should_not == subject.to_s
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context "when an ActiveModel descendant" do
|
||||||
|
it "should always proxy to_param" do
|
||||||
|
source.stub(:to_param).and_return(1)
|
||||||
|
Draper::Base.new(source).to_param.should == 1
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should always proxy id" do
|
||||||
|
source.stub(:id).and_return(123456789)
|
||||||
|
Draper::Base.new(source).id.should == 123456789
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should always proxy errors" do
|
||||||
|
Draper::Base.new(source).errors.should be_an_instance_of ActiveModel::Errors
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when not an ActiveModel descendant" do
|
||||||
|
it "does not proxy to_param" do
|
||||||
|
non_active_model_source.stub(:to_param).and_return(1)
|
||||||
|
Draper::Base.new(non_active_model_source).to_param.should_not == 1
|
||||||
|
end
|
||||||
|
|
||||||
|
it "does not proxy errors" do
|
||||||
|
Draper::Base.new(non_active_model_source).should_not respond_to :errors
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'the decorated model' do
|
context 'the decorated model' do
|
||||||
it 'receives the mixin' do
|
it 'receives the mixin' do
|
||||||
source.class.ancestors.include?(Draper::ModelSupport)
|
source.class.ancestors.include?(Draper::ModelSupport)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'includes ActiveModel support' do
|
||||||
|
source.class.ancestors.include?(Draper::ActiveModelSupport)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should wrap source methods so they still accept blocks" do
|
it "should wrap source methods so they still accept blocks" do
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
require 'spec_helper'
|
require 'spec_helper'
|
||||||
|
|
||||||
describe Draper::ModelSupport do
|
describe Draper::ActiveModelSupport do
|
||||||
subject { Product.new }
|
subject { Product.new }
|
||||||
|
|
||||||
describe '#decorator' do
|
describe '#decorator' do
|
||||||
|
|
|
@ -4,20 +4,22 @@ require 'rails'
|
||||||
|
|
||||||
Bundler.require
|
Bundler.require
|
||||||
|
|
||||||
require './spec/support/samples/active_record.rb'
|
require './spec/support/samples/active_model'
|
||||||
require './spec/support/samples/application_controller.rb'
|
require './spec/support/samples/active_record'
|
||||||
require './spec/support/samples/application_helper.rb'
|
require './spec/support/samples/application_controller'
|
||||||
require './spec/support/samples/decorator.rb'
|
require './spec/support/samples/application_helper'
|
||||||
require './spec/support/samples/decorator_with_allows.rb'
|
require './spec/support/samples/decorator'
|
||||||
require './spec/support/samples/decorator_with_multiple_allows.rb'
|
require './spec/support/samples/decorator_with_allows'
|
||||||
require './spec/support/samples/decorator_with_application_helper.rb'
|
require './spec/support/samples/decorator_with_multiple_allows'
|
||||||
require './spec/support/samples/decorator_with_denies.rb'
|
require './spec/support/samples/decorator_with_application_helper'
|
||||||
require './spec/support/samples/namespaced_product.rb'
|
require './spec/support/samples/decorator_with_denies'
|
||||||
require './spec/support/samples/namespaced_product_decorator.rb'
|
require './spec/support/samples/namespaced_product'
|
||||||
require './spec/support/samples/product.rb'
|
require './spec/support/samples/namespaced_product_decorator'
|
||||||
require './spec/support/samples/product_decorator.rb'
|
require './spec/support/samples/non_active_model_product'
|
||||||
require './spec/support/samples/specific_product_decorator.rb'
|
require './spec/support/samples/product'
|
||||||
require './spec/support/samples/some_thing.rb'
|
require './spec/support/samples/product_decorator'
|
||||||
require './spec/support/samples/some_thing_decorator.rb'
|
require './spec/support/samples/specific_product_decorator'
|
||||||
require './spec/support/samples/widget.rb'
|
require './spec/support/samples/some_thing'
|
||||||
require './spec/support/samples/widget_decorator.rb'
|
require './spec/support/samples/some_thing_decorator'
|
||||||
|
require './spec/support/samples/widget'
|
||||||
|
require './spec/support/samples/widget_decorator'
|
||||||
|
|
9
spec/support/samples/active_model.rb
Normal file
9
spec/support/samples/active_model.rb
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
module ActiveModel
|
||||||
|
module Conversion; end
|
||||||
|
module Validations; end
|
||||||
|
|
||||||
|
class Errors
|
||||||
|
def initialize(params = nil)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,5 +1,13 @@
|
||||||
module ActiveRecord
|
module ActiveRecord
|
||||||
class Base
|
class Base
|
||||||
|
include ActiveModel::Validations
|
||||||
|
include ActiveModel::Conversion
|
||||||
|
|
||||||
|
attr_reader :errors, :to_model
|
||||||
|
|
||||||
|
def initialize
|
||||||
|
@errors = ActiveModel::Errors.new(self)
|
||||||
|
end
|
||||||
|
|
||||||
def self.limit
|
def self.limit
|
||||||
self
|
self
|
||||||
|
|
2
spec/support/samples/non_active_model_product.rb
Normal file
2
spec/support/samples/non_active_model_product.rb
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
class NonActiveModelProduct
|
||||||
|
end
|
Loading…
Reference in a new issue