2011-06-30 22:19:48 +00:00
|
|
|
require 'spec_helper'
|
|
|
|
|
|
|
|
describe Draper::Base do
|
2011-10-08 05:06:19 +00:00
|
|
|
before(:each){ ApplicationController.new.set_current_view_context }
|
2011-10-09 02:47:08 +00:00
|
|
|
subject{ Decorator.new(source) }
|
2011-07-30 18:25:45 +00:00
|
|
|
let(:source){ Product.new }
|
2011-07-23 15:39:48 +00:00
|
|
|
|
2011-10-09 02:47:08 +00:00
|
|
|
context("proxying class methods") do
|
|
|
|
it "should pass missing class method calls on to the wrapped class" do
|
|
|
|
subject.class.sample_class_method.should == "sample class method"
|
|
|
|
end
|
2011-10-20 19:03:48 +00:00
|
|
|
|
2011-10-09 02:47:08 +00:00
|
|
|
it "should respond_to a wrapped class method" do
|
|
|
|
subject.class.should respond_to(:sample_class_method)
|
|
|
|
end
|
2011-10-20 19:03:48 +00:00
|
|
|
|
2011-10-09 02:47:08 +00:00
|
|
|
it "should still respond_to it's own class methods" do
|
|
|
|
subject.class.should respond_to(:own_class_method)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2011-10-08 05:37:33 +00:00
|
|
|
context(".helpers") do
|
|
|
|
it "should have a valid view_context" do
|
|
|
|
subject.helpers.should be
|
2011-10-20 06:17:05 +00:00
|
|
|
end
|
2011-10-20 19:03:48 +00:00
|
|
|
|
2011-10-20 06:17:05 +00:00
|
|
|
it "should be aliased to .h" do
|
|
|
|
subject.h.should == subject.helpers
|
2011-10-20 19:03:48 +00:00
|
|
|
end
|
2011-10-08 05:06:19 +00:00
|
|
|
end
|
2011-10-20 19:03:48 +00:00
|
|
|
|
2011-10-20 06:17:05 +00:00
|
|
|
context("#helpers") do
|
|
|
|
it "should have a valid view_context" do
|
|
|
|
Decorator.helpers.should be
|
|
|
|
end
|
2011-10-20 19:03:48 +00:00
|
|
|
|
2011-10-20 06:17:05 +00:00
|
|
|
it "should be aliased to #h" do
|
|
|
|
Decorator.h.should == Decorator.helpers
|
|
|
|
end
|
|
|
|
end
|
2011-10-08 05:06:19 +00:00
|
|
|
|
2011-07-23 15:39:48 +00:00
|
|
|
context(".decorates") do
|
|
|
|
it "sets the model class for the decorator" do
|
2011-08-28 03:34:33 +00:00
|
|
|
ProductDecorator.new(source).model_class.should == Product
|
|
|
|
end
|
2011-10-20 19:03:48 +00:00
|
|
|
|
2011-08-28 03:34:33 +00:00
|
|
|
it "should handle plural-like words properly'" do
|
|
|
|
class Business; end
|
|
|
|
expect do
|
|
|
|
class BusinessDecorator < Draper::Base
|
|
|
|
decorates:business
|
|
|
|
end
|
|
|
|
BusinessDecorator.model_class.should == Business
|
|
|
|
end.should_not raise_error
|
2011-07-23 15:39:48 +00:00
|
|
|
end
|
2011-10-20 19:03:48 +00:00
|
|
|
|
2011-10-20 03:26:00 +00:00
|
|
|
it "creates a named accessor for the wrapped model" do
|
|
|
|
pd = ProductDecorator.new(source)
|
|
|
|
pd.send(:product).should == source
|
|
|
|
end
|
2011-07-23 15:39:48 +00:00
|
|
|
end
|
2011-07-30 18:25:45 +00:00
|
|
|
|
2011-07-23 15:49:18 +00:00
|
|
|
context(".model / .to_model") do
|
|
|
|
it "should return the wrapped object" do
|
|
|
|
subject.to_model.should == source
|
|
|
|
subject.model.should == source
|
|
|
|
end
|
2011-07-23 14:48:14 +00:00
|
|
|
end
|
2011-07-30 18:25:45 +00:00
|
|
|
|
2011-07-23 15:49:18 +00:00
|
|
|
context("selecting methods") do
|
2011-07-23 17:15:53 +00:00
|
|
|
it "echos the methods of the wrapped class except default exclusions" do
|
2011-07-23 15:49:18 +00:00
|
|
|
source.methods.each do |method|
|
2011-10-20 19:03:48 +00:00
|
|
|
unless Draper::Base::DEFAULT_DENIED.include?(method)
|
2011-10-07 18:26:51 +00:00
|
|
|
subject.should respond_to(method.to_sym)
|
2011-07-23 17:15:53 +00:00
|
|
|
end
|
2011-07-23 15:49:18 +00:00
|
|
|
end
|
|
|
|
end
|
2011-07-30 18:25:45 +00:00
|
|
|
|
2011-07-23 15:49:18 +00:00
|
|
|
it "should not override a defined method with a source method" do
|
|
|
|
DecoratorWithApplicationHelper.new(source).length.should == "overridden"
|
|
|
|
end
|
2011-07-30 18:25:45 +00:00
|
|
|
|
2011-07-23 15:49:18 +00:00
|
|
|
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
|
2011-07-30 18:25:45 +00:00
|
|
|
|
2011-10-16 17:53:58 +00:00
|
|
|
it "should always proxy id" do
|
|
|
|
source.send :class_eval, "def id; 123456789; end"
|
|
|
|
Draper::Base.new(source).id.should == 123456789
|
|
|
|
end
|
|
|
|
|
2011-07-23 15:49:18 +00:00
|
|
|
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
|
2011-07-30 18:25:45 +00:00
|
|
|
end
|
2011-07-23 15:49:18 +00:00
|
|
|
|
2011-08-08 02:07:40 +00:00
|
|
|
context 'the decorated model' do
|
|
|
|
it 'receives the mixin' do
|
|
|
|
source.class.ancestors.include?(Draper::ModelSupport)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2011-07-01 19:50:57 +00:00
|
|
|
it "should wrap source methods so they still accept blocks" do
|
2011-07-23 16:16:52 +00:00
|
|
|
subject.block{"marker"}.should == "marker"
|
2011-07-01 19:50:57 +00:00
|
|
|
end
|
2011-07-30 18:25:45 +00:00
|
|
|
|
2011-07-23 16:16:52 +00:00
|
|
|
context ".find" do
|
2011-07-23 15:39:48 +00:00
|
|
|
it "should lookup the associated model when passed an integer" do
|
2011-07-23 16:16:52 +00:00
|
|
|
pd = ProductDecorator.find(1)
|
|
|
|
pd.should be_instance_of(ProductDecorator)
|
|
|
|
pd.model.should be_instance_of(Product)
|
|
|
|
end
|
2011-07-30 18:25:45 +00:00
|
|
|
|
2011-07-23 16:16:52 +00:00
|
|
|
it "should lookup the associated model when passed a string" do
|
|
|
|
pd = ProductDecorator.find("1")
|
2011-07-23 15:39:48 +00:00
|
|
|
pd.should be_instance_of(ProductDecorator)
|
|
|
|
pd.model.should be_instance_of(Product)
|
|
|
|
end
|
2011-10-20 19:03:48 +00:00
|
|
|
|
2011-10-03 22:10:25 +00:00
|
|
|
it "should accept and store a context" do
|
|
|
|
pd = ProductDecorator.find(1, :admin)
|
|
|
|
pd.context.should == :admin
|
|
|
|
end
|
2011-07-23 15:39:48 +00:00
|
|
|
end
|
2011-07-30 18:25:45 +00:00
|
|
|
|
2011-07-23 15:12:26 +00:00
|
|
|
context ".decorate" do
|
2011-08-09 01:01:31 +00:00
|
|
|
context "without any context" do
|
|
|
|
subject { Draper::Base.decorate(source) }
|
2011-08-08 23:32:22 +00:00
|
|
|
|
2011-08-09 01:01:31 +00:00
|
|
|
context "when given a collection of source objects" do
|
|
|
|
let(:source) { [Product.new, Product.new] }
|
2011-08-08 23:32:22 +00:00
|
|
|
|
2011-08-09 01:01:31 +00:00
|
|
|
its(:size) { should == source.size }
|
2011-08-08 23:32:22 +00:00
|
|
|
|
2011-08-09 01:01:31 +00:00
|
|
|
it "returns a collection of wrapped objects" do
|
|
|
|
subject.each{ |decorated| decorated.should be_instance_of(Draper::Base) }
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context "when given a single source object" do
|
|
|
|
let(:source) { Product.new }
|
|
|
|
|
|
|
|
it { should be_instance_of(Draper::Base) }
|
2011-08-08 23:32:22 +00:00
|
|
|
end
|
2011-07-11 01:46:30 +00:00
|
|
|
end
|
2011-07-30 18:25:45 +00:00
|
|
|
|
2011-08-09 01:01:31 +00:00
|
|
|
context "with a context" do
|
|
|
|
let(:context) {{ :some => 'data' }}
|
|
|
|
|
|
|
|
subject { Draper::Base.decorate(source, context) }
|
|
|
|
|
|
|
|
context "when given a collection of source objects" do
|
|
|
|
let(:source) { [Product.new, Product.new] }
|
2011-08-08 23:32:22 +00:00
|
|
|
|
2011-08-09 01:01:31 +00:00
|
|
|
it "returns a collection of wrapped objects with the context" do
|
|
|
|
subject.each{ |decorated| decorated.context.should eq(context) }
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context "when given a single source object" do
|
|
|
|
let(:source) { Product.new }
|
|
|
|
|
|
|
|
its(:context) { should eq(context) }
|
|
|
|
end
|
2011-07-11 01:46:30 +00:00
|
|
|
end
|
2011-10-10 06:09:16 +00:00
|
|
|
|
2011-07-01 19:50:57 +00:00
|
|
|
end
|
2011-07-30 18:25:45 +00:00
|
|
|
|
2011-09-19 17:44:16 +00:00
|
|
|
context('.==') do
|
|
|
|
it "should compare the decorated models" do
|
|
|
|
other = Draper::Base.new(source)
|
|
|
|
subject.should == other
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2011-10-10 06:09:16 +00:00
|
|
|
describe "collection decoration" do
|
2011-10-20 19:03:48 +00:00
|
|
|
|
2011-10-10 06:09:16 +00:00
|
|
|
# Implementation of #decorate that returns an array
|
2011-10-20 19:03:48 +00:00
|
|
|
# of decorated objects is insufficient to deal with
|
|
|
|
# situations where the original collection has been
|
2011-10-10 06:09:16 +00:00
|
|
|
# expanded with the use of modules (as often the case
|
2011-10-20 19:03:48 +00:00
|
|
|
# with paginator gems) or is just more complex then
|
|
|
|
# an array.
|
2011-10-10 06:09:16 +00:00
|
|
|
module Paginator; def page_number; "magic_value"; end; end
|
|
|
|
Array.send(:include, Paginator)
|
|
|
|
let(:paged_array) { [Product.new, Product.new] }
|
2011-10-20 21:22:05 +00:00
|
|
|
let(:empty_collection) { [] }
|
2011-10-10 06:09:16 +00:00
|
|
|
subject { ProductDecorator.decorate(paged_array) }
|
|
|
|
|
|
|
|
it "should proxy all calls to decorated collection" do
|
|
|
|
paged_array.page_number.should == "magic_value"
|
|
|
|
subject.page_number.should == "magic_value"
|
|
|
|
end
|
|
|
|
|
|
|
|
it "should support Rails partial lookup for a collection" do
|
2011-10-20 19:03:48 +00:00
|
|
|
# to support Rails render @collection the returned collection
|
|
|
|
# (or its proxy) should implement #to_ary.
|
2011-10-10 06:09:16 +00:00
|
|
|
subject.respond_to?(:to_ary).should be true
|
2011-10-20 19:03:48 +00:00
|
|
|
subject.to_ary.first.should == ProductDecorator.decorate(paged_array.first)
|
2011-10-10 06:09:16 +00:00
|
|
|
end
|
2011-10-20 21:22:05 +00:00
|
|
|
|
|
|
|
it "should delegate respond_to? to the wrapped collection" do
|
|
|
|
decorator = ProductDecorator.decorate(paged_array)
|
|
|
|
paged_array.should_receive(:respond_to?).with(:whatever)
|
|
|
|
decorator.respond_to?(:whatever)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "should return blank for a decorated empty collection" do
|
|
|
|
# This tests that respond_to? is defined for the DecoratedEnumerableProxy
|
|
|
|
# since activesupport calls respond_to?(:empty) in #blank
|
|
|
|
decorator = ProductDecorator.decorate(empty_collection)
|
|
|
|
decorator.should be_blank
|
|
|
|
end
|
2011-10-27 15:42:23 +00:00
|
|
|
|
2011-10-26 17:27:58 +00:00
|
|
|
it "should return whether the member is in the array for a decorated wrapped collection" do
|
|
|
|
# This tests that include? is defined for the DecoratedEnumerableProxy
|
|
|
|
member = paged_array.first
|
2011-10-26 18:49:38 +00:00
|
|
|
subject.respond_to?(:include?)
|
|
|
|
subject.include?(member).should == true
|
|
|
|
subject.include?(subject.first).should == true
|
|
|
|
subject.include?(Product.new).should == false
|
2011-10-26 17:27:58 +00:00
|
|
|
end
|
2011-10-27 15:42:23 +00:00
|
|
|
|
|
|
|
it "should equal each other when decorating the same collection" do
|
|
|
|
subject_one = ProductDecorator.decorate(paged_array)
|
|
|
|
subject_two = ProductDecorator.decorate(paged_array)
|
|
|
|
subject_one.should == subject_two
|
|
|
|
end
|
|
|
|
|
|
|
|
it "should not equal each other when decorating different collections" do
|
|
|
|
subject_one = ProductDecorator.decorate(paged_array)
|
|
|
|
new_paged_array = paged_array + [Product.new]
|
|
|
|
subject_two = ProductDecorator.decorate(new_paged_array)
|
|
|
|
subject_one.should_not == subject_two
|
|
|
|
end
|
|
|
|
|
2011-10-10 06:09:16 +00:00
|
|
|
end
|
|
|
|
|
2011-07-30 18:25:45 +00:00
|
|
|
describe "a sample usage with denies" do
|
2011-06-30 22:45:37 +00:00
|
|
|
let(:subject_with_denies){ DecoratorWithDenies.new(source) }
|
2011-07-30 18:25:45 +00:00
|
|
|
|
2011-07-23 17:15:53 +00:00
|
|
|
it "should proxy methods not listed in denies" do
|
|
|
|
subject_with_denies.should respond_to(:hello_world)
|
|
|
|
end
|
2011-07-30 18:25:45 +00:00
|
|
|
|
2011-06-30 22:45:37 +00:00
|
|
|
it "should not echo methods specified with denies" do
|
2011-07-23 17:15:53 +00:00
|
|
|
subject_with_denies.should_not respond_to(:goodnight_moon)
|
2011-06-30 22:19:48 +00:00
|
|
|
end
|
|
|
|
|
2011-06-30 22:45:37 +00:00
|
|
|
it "should not clobber other decorators' methods" do
|
2011-07-23 16:16:52 +00:00
|
|
|
subject.should respond_to(:hello_world)
|
2011-07-30 18:25:45 +00:00
|
|
|
end
|
|
|
|
|
2011-07-23 17:15:53 +00:00
|
|
|
it "should not allow method_missing to circumvent a deny" do
|
|
|
|
expect{subject_with_denies.title}.to raise_error(NoMethodError)
|
2011-07-30 18:25:45 +00:00
|
|
|
end
|
2011-06-30 22:19:48 +00:00
|
|
|
end
|
2011-07-30 18:25:45 +00:00
|
|
|
|
2011-06-30 22:19:48 +00:00
|
|
|
describe "a sample usage with allows" do
|
|
|
|
let(:subject_with_allows){ DecoratorWithAllows.new(source) }
|
2011-07-30 18:25:45 +00:00
|
|
|
|
2011-06-30 22:19:48 +00:00
|
|
|
it "should echo the allowed method" do
|
2011-09-29 18:57:49 +00:00
|
|
|
subject_with_allows.should respond_to(:goodnight_moon)
|
2011-06-30 22:19:48 +00:00
|
|
|
end
|
2011-07-30 18:25:45 +00:00
|
|
|
|
2011-06-30 22:19:48 +00:00
|
|
|
it "should echo _only_ the allowed method" do
|
2011-09-29 18:57:49 +00:00
|
|
|
subject_with_allows.should_not respond_to(:hello_world)
|
2011-06-30 22:19:48 +00:00
|
|
|
end
|
|
|
|
end
|
2011-07-30 18:25:45 +00:00
|
|
|
|
2011-06-30 22:45:37 +00:00
|
|
|
describe "invalid usages of allows and denies" do
|
2011-06-30 22:19:48 +00:00
|
|
|
let(:blank_allows){
|
2011-07-30 18:25:45 +00:00
|
|
|
class DecoratorWithInvalidAllows < Draper::Base
|
2011-06-30 22:19:48 +00:00
|
|
|
allows
|
|
|
|
end
|
|
|
|
}
|
2011-07-30 18:25:45 +00:00
|
|
|
|
2011-06-30 22:45:37 +00:00
|
|
|
let(:blank_denies){
|
2011-07-30 18:25:45 +00:00
|
|
|
class DecoratorWithInvalidDenies < Draper::Base
|
2011-06-30 22:45:37 +00:00
|
|
|
denies
|
2011-06-30 22:19:48 +00:00
|
|
|
end
|
|
|
|
}
|
2011-07-30 18:25:45 +00:00
|
|
|
|
2011-06-30 22:45:37 +00:00
|
|
|
let(:using_allows_then_denies){
|
2011-07-30 18:25:45 +00:00
|
|
|
class DecoratorWithAllowsAndDenies < Draper::Base
|
2011-07-23 17:15:53 +00:00
|
|
|
allows :hello_world
|
|
|
|
denies :goodnight_moon
|
2011-06-30 22:19:48 +00:00
|
|
|
end
|
2011-07-30 18:25:45 +00:00
|
|
|
}
|
|
|
|
|
2011-06-30 22:45:37 +00:00
|
|
|
let(:using_denies_then_allows){
|
2011-07-30 18:25:45 +00:00
|
|
|
class DecoratorWithDeniesAndAllows < Draper::Base
|
2011-07-23 17:15:53 +00:00
|
|
|
denies :goodnight_moon
|
2011-07-30 18:25:45 +00:00
|
|
|
allows :hello_world
|
2011-06-30 22:19:48 +00:00
|
|
|
end
|
|
|
|
}
|
|
|
|
|
|
|
|
it "should raise an exception for a blank allows" do
|
|
|
|
expect {blank_allows}.should raise_error(ArgumentError)
|
|
|
|
end
|
2011-07-30 18:25:45 +00:00
|
|
|
|
2011-06-30 22:45:37 +00:00
|
|
|
it "should raise an exception for a blank denies" do
|
|
|
|
expect {blank_denies}.should raise_error(ArgumentError)
|
2011-06-30 22:19:48 +00:00
|
|
|
end
|
2011-07-30 18:25:45 +00:00
|
|
|
|
2011-06-30 22:45:37 +00:00
|
|
|
it "should raise an exception for calling allows then denies" do
|
|
|
|
expect {using_allows_then_denies}.should raise_error(ArgumentError)
|
2011-06-30 22:19:48 +00:00
|
|
|
end
|
2011-07-30 18:25:45 +00:00
|
|
|
|
2011-06-30 22:45:37 +00:00
|
|
|
it "should raise an exception for calling denies then allows" do
|
|
|
|
expect {using_denies_then_allows}.should raise_error(ArgumentError)
|
2011-06-30 22:19:48 +00:00
|
|
|
end
|
|
|
|
end
|
2011-07-30 18:25:45 +00:00
|
|
|
|
2011-07-11 01:46:30 +00:00
|
|
|
context "in a Rails application" do
|
2011-07-23 13:59:09 +00:00
|
|
|
let(:decorator){ DecoratorWithApplicationHelper.decorate(Object.new) }
|
2011-07-30 18:25:45 +00:00
|
|
|
|
2011-07-23 13:59:09 +00:00
|
|
|
it "should have access to ApplicationHelper helpers" do
|
|
|
|
decorator.uses_hello_world == "Hello, World!"
|
|
|
|
end
|
2011-07-30 18:25:45 +00:00
|
|
|
|
2011-07-23 13:59:09 +00:00
|
|
|
it "should be able to use the content_tag helper" do
|
|
|
|
decorator.sample_content.to_s.should == "<span>Hello, World!</span>"
|
|
|
|
end
|
2011-07-30 18:25:45 +00:00
|
|
|
|
2011-07-23 13:59:09 +00:00
|
|
|
it "should be able to use the link_to helper" do
|
|
|
|
decorator.sample_link.should == "<a href=\"/World\">Hello</a>"
|
|
|
|
end
|
2011-07-30 18:25:45 +00:00
|
|
|
|
2011-07-23 13:59:09 +00:00
|
|
|
it "should be able to use the pluralize helper" do
|
|
|
|
decorator.sample_truncate.should == "Once..."
|
|
|
|
end
|
2011-07-11 01:46:30 +00:00
|
|
|
end
|
2011-07-30 18:25:45 +00:00
|
|
|
end
|