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/system'
|
||||
require 'draper/active_model_support'
|
||||
require 'draper/base'
|
||||
require 'draper/lazy_helpers'
|
||||
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_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.allowed = DEFAULT_ALLOWED
|
||||
|
||||
include Draper::ActiveModelSupport::Proxies
|
||||
|
||||
# Initialize a new decorator instance by passing in
|
||||
# an instance of the source class. Pass in an optional
|
||||
# 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?
|
||||
@model = input.kind_of?(Draper::Base) ? input.model : input
|
||||
self.options = options
|
||||
create_proxies
|
||||
end
|
||||
|
||||
# Proxies to the class specified by `decorates` to automatically
|
||||
|
@ -260,7 +257,7 @@ module Draper
|
|||
private
|
||||
|
||||
def allow?(method)
|
||||
(allowed.empty? || allowed.include?(method) || FORCED_PROXY.include?(method)) && !denied.include?(method)
|
||||
(allowed.empty? || allowed.include?(method)) && !denied.include?(method)
|
||||
end
|
||||
|
||||
def find_association_reflection(association)
|
||||
|
|
|
@ -4,6 +4,7 @@ describe Draper::Base do
|
|||
before(:each){ ApplicationController.new.set_current_view_context }
|
||||
subject{ Decorator.new(source) }
|
||||
let(:source){ Product.new }
|
||||
let(:non_active_model_source){ NonActiveModelProduct.new }
|
||||
|
||||
context("proxying class methods") do
|
||||
it "should pass missing class method calls on to the wrapped class" do
|
||||
|
@ -195,7 +196,7 @@ describe Draper::Base do
|
|||
end
|
||||
end
|
||||
|
||||
context("selecting methods") do
|
||||
describe "method selection" do
|
||||
it "echos the methods of the wrapped class except default exclusions" do
|
||||
source.methods.each do |method|
|
||||
unless Draper::Base::DEFAULT_DENIED.include?(method)
|
||||
|
@ -208,27 +209,48 @@ describe Draper::Base do
|
|||
DecoratorWithApplicationHelper.new(source).length.should == "overridden"
|
||||
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
|
||||
source.class.should_not == subject.class
|
||||
source.inspect.should_not == subject.inspect
|
||||
source.to_s.should_not == subject.to_s
|
||||
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
|
||||
|
||||
context 'the decorated model' do
|
||||
it 'receives the mixin' do
|
||||
source.class.ancestors.include?(Draper::ModelSupport)
|
||||
end
|
||||
|
||||
it 'includes ActiveModel support' do
|
||||
source.class.ancestors.include?(Draper::ActiveModelSupport)
|
||||
end
|
||||
end
|
||||
|
||||
it "should wrap source methods so they still accept blocks" do
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Draper::ModelSupport do
|
||||
describe Draper::ActiveModelSupport do
|
||||
subject { Product.new }
|
||||
|
||||
describe '#decorator' do
|
||||
|
|
|
@ -4,20 +4,22 @@ require 'rails'
|
|||
|
||||
Bundler.require
|
||||
|
||||
require './spec/support/samples/active_record.rb'
|
||||
require './spec/support/samples/application_controller.rb'
|
||||
require './spec/support/samples/application_helper.rb'
|
||||
require './spec/support/samples/decorator.rb'
|
||||
require './spec/support/samples/decorator_with_allows.rb'
|
||||
require './spec/support/samples/decorator_with_multiple_allows.rb'
|
||||
require './spec/support/samples/decorator_with_application_helper.rb'
|
||||
require './spec/support/samples/decorator_with_denies.rb'
|
||||
require './spec/support/samples/namespaced_product.rb'
|
||||
require './spec/support/samples/namespaced_product_decorator.rb'
|
||||
require './spec/support/samples/product.rb'
|
||||
require './spec/support/samples/product_decorator.rb'
|
||||
require './spec/support/samples/specific_product_decorator.rb'
|
||||
require './spec/support/samples/some_thing.rb'
|
||||
require './spec/support/samples/some_thing_decorator.rb'
|
||||
require './spec/support/samples/widget.rb'
|
||||
require './spec/support/samples/widget_decorator.rb'
|
||||
require './spec/support/samples/active_model'
|
||||
require './spec/support/samples/active_record'
|
||||
require './spec/support/samples/application_controller'
|
||||
require './spec/support/samples/application_helper'
|
||||
require './spec/support/samples/decorator'
|
||||
require './spec/support/samples/decorator_with_allows'
|
||||
require './spec/support/samples/decorator_with_multiple_allows'
|
||||
require './spec/support/samples/decorator_with_application_helper'
|
||||
require './spec/support/samples/decorator_with_denies'
|
||||
require './spec/support/samples/namespaced_product'
|
||||
require './spec/support/samples/namespaced_product_decorator'
|
||||
require './spec/support/samples/non_active_model_product'
|
||||
require './spec/support/samples/product'
|
||||
require './spec/support/samples/product_decorator'
|
||||
require './spec/support/samples/specific_product_decorator'
|
||||
require './spec/support/samples/some_thing'
|
||||
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
|
||||
class Base
|
||||
include ActiveModel::Validations
|
||||
include ActiveModel::Conversion
|
||||
|
||||
attr_reader :errors, :to_model
|
||||
|
||||
def initialize
|
||||
@errors = ActiveModel::Errors.new(self)
|
||||
end
|
||||
|
||||
def self.limit
|
||||
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