draper 0.8.1 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Guardfile +1 -1
- data/Readme.markdown +1 -1
- data/lib/draper/base.rb +38 -22
- data/lib/draper/version.rb +1 -1
- data/lib/draper/view_context.rb +1 -1
- data/lib/generators/draper/decorator/decorator_generator.rb +3 -1
- data/lib/generators/rspec/decorator_generator.rb +17 -0
- data/lib/generators/rspec/templates/application_decorator_spec.rb +5 -0
- data/lib/generators/rspec/templates/decorator_spec.rb +5 -0
- data/spec/base_spec.rb +32 -7
- data/spec/generators/rspec/decorator_generator_spec.rb +28 -0
- data/spec/view_context_spec.rb +10 -0
- metadata +7 -2
data/Guardfile
CHANGED
data/Readme.markdown
CHANGED
@@ -198,7 +198,7 @@ Hate seeing that `h.` proxy all over? Willing to mix a bazillion methods into yo
|
|
198
198
|
```ruby
|
199
199
|
class ArticleDecorator < ApplicationDecorator
|
200
200
|
decorates :article
|
201
|
-
|
201
|
+
include Draper::LazyHelpers
|
202
202
|
|
203
203
|
def published_at
|
204
204
|
date = content_tag(:span, model.published_at.strftime("%A, %B %e").squeeze(" "), :class => 'date')
|
data/lib/draper/base.rb
CHANGED
@@ -5,7 +5,7 @@ module Draper
|
|
5
5
|
attr_accessor :context, :model
|
6
6
|
|
7
7
|
DEFAULT_DENIED = Object.new.methods << :method_missing
|
8
|
-
FORCED_PROXY = [:to_param]
|
8
|
+
FORCED_PROXY = [:to_param, :id]
|
9
9
|
FORCED_PROXY.each do |method|
|
10
10
|
define_method method do |*args, &block|
|
11
11
|
model.send method, *args, &block
|
@@ -93,7 +93,7 @@ module Draper
|
|
93
93
|
# @param [Object] instance(s) to wrap
|
94
94
|
# @param [Object] context (optional)
|
95
95
|
def self.decorate(input, context = {})
|
96
|
-
input.respond_to?(:each) ?
|
96
|
+
input.respond_to?(:each) ? DecoratedEnumerableProxy.new(input, self, context) : new(input, context)
|
97
97
|
end
|
98
98
|
|
99
99
|
# Access the helpers proxy to call built-in and user-defined
|
@@ -105,16 +105,6 @@ module Draper
|
|
105
105
|
end
|
106
106
|
alias :h :helpers
|
107
107
|
|
108
|
-
# Calling `lazy_helpers` will make the built-in and
|
109
|
-
# user-defined Rails helpers accessible as class methods
|
110
|
-
# in the decorator without using the `h.` or `helpers.` proxy.
|
111
|
-
#
|
112
|
-
# The drawback is that you dump many methods into your decorator's
|
113
|
-
# namespace and collisions could create unexpected results.
|
114
|
-
def self.lazy_helpers
|
115
|
-
self.send(:include, Draper::LazyHelpers)
|
116
|
-
end
|
117
|
-
|
118
108
|
# Fetch the original wrapped model.
|
119
109
|
#
|
120
110
|
# @return [Object] original_model
|
@@ -130,16 +120,16 @@ module Draper
|
|
130
120
|
end
|
131
121
|
|
132
122
|
def respond_to?(method, include_private = false)
|
133
|
-
|
134
|
-
model.respond_to?(method)
|
135
|
-
else
|
136
|
-
super
|
137
|
-
end
|
123
|
+
super || (allow?(method) && model.respond_to?(method))
|
138
124
|
end
|
139
125
|
|
140
126
|
def method_missing(method, *args, &block)
|
141
|
-
if
|
142
|
-
|
127
|
+
if allow?(method)
|
128
|
+
begin
|
129
|
+
model.send(method, *args, &block)
|
130
|
+
rescue NoMethodError
|
131
|
+
super
|
132
|
+
end
|
143
133
|
else
|
144
134
|
super
|
145
135
|
end
|
@@ -154,9 +144,35 @@ module Draper
|
|
154
144
|
end
|
155
145
|
|
156
146
|
private
|
157
|
-
def
|
158
|
-
|
159
|
-
(specified - self.public_methods.map{|s| s.to_sym}) + FORCED_PROXY
|
147
|
+
def allow?(method)
|
148
|
+
(!allowed? || allowed.include?(method) || FORCED_PROXY.include?(method)) && !denied.include?(method)
|
160
149
|
end
|
150
|
+
|
151
|
+
class DecoratedEnumerableProxy
|
152
|
+
include Enumerable
|
153
|
+
|
154
|
+
def initialize(collection, klass, context)
|
155
|
+
@wrapped_collection, @klass, @context = collection, klass, context
|
156
|
+
end
|
157
|
+
|
158
|
+
# Implementation of Enumerable#each that proxyes to the wrapped collection
|
159
|
+
def each(&block)
|
160
|
+
@wrapped_collection.each { |member| block.call(@klass.new(member, @context)) }
|
161
|
+
end
|
162
|
+
|
163
|
+
# Implement to_arry so that render @decorated_collection is happy
|
164
|
+
def to_ary
|
165
|
+
@wrapped_collection.to_ary
|
166
|
+
end
|
167
|
+
|
168
|
+
def method_missing (meth, *args, &block)
|
169
|
+
@wrapped_collection.send(meth, *args, &block)
|
170
|
+
end
|
171
|
+
|
172
|
+
def to_s
|
173
|
+
"#<DecoratedEnumerableProxy of #{@klass} for #{@wrapped_collection.inspect}>"
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
161
177
|
end
|
162
178
|
end
|
data/lib/draper/version.rb
CHANGED
data/lib/draper/view_context.rb
CHANGED
@@ -0,0 +1,17 @@
|
|
1
|
+
module Rspec
|
2
|
+
class DecoratorGenerator < ::Rails::Generators::NamedBase
|
3
|
+
source_root File.expand_path('../templates', __FILE__)
|
4
|
+
|
5
|
+
SPEC_ROOT = 'spec/decorators/'
|
6
|
+
APPLICATION_DECORATOR_SPEC = 'application_decorator_spec.rb'
|
7
|
+
APPLICATION_DECORATOR_SPEC_PATH = SPEC_ROOT + APPLICATION_DECORATOR_SPEC
|
8
|
+
|
9
|
+
def build_model_and_application_decorator_specs
|
10
|
+
empty_directory SPEC_ROOT
|
11
|
+
unless File.exists?(APPLICATION_DECORATOR_SPEC_PATH)
|
12
|
+
template APPLICATION_DECORATOR_SPEC, APPLICATION_DECORATOR_SPEC_PATH
|
13
|
+
end
|
14
|
+
template 'decorator_spec.rb', "#{SPEC_ROOT}#{singular_name}_decorator_spec.rb"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/spec/base_spec.rb
CHANGED
@@ -26,13 +26,6 @@ describe Draper::Base do
|
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
29
|
-
context(".lazy_helpers") do
|
30
|
-
it "makes Rails helpers available without using the h. proxy" do
|
31
|
-
Draper::Base.lazy_helpers
|
32
|
-
subject.send(:pluralize, 5, "cat").should == "5 cats"
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
29
|
context(".decorates") do
|
37
30
|
it "sets the model class for the decorator" do
|
38
31
|
ProductDecorator.new(source).model_class.should == Product
|
@@ -74,6 +67,11 @@ describe Draper::Base do
|
|
74
67
|
Draper::Base.new(source).to_param.should == 1
|
75
68
|
end
|
76
69
|
|
70
|
+
it "should always proxy id" do
|
71
|
+
source.send :class_eval, "def id; 123456789; end"
|
72
|
+
Draper::Base.new(source).id.should == 123456789
|
73
|
+
end
|
74
|
+
|
77
75
|
it "should not copy the .class, .inspect, or other existing methods" do
|
78
76
|
source.class.should_not == subject.class
|
79
77
|
source.inspect.should_not == subject.inspect
|
@@ -150,6 +148,7 @@ describe Draper::Base do
|
|
150
148
|
its(:context) { should eq(context) }
|
151
149
|
end
|
152
150
|
end
|
151
|
+
|
153
152
|
end
|
154
153
|
|
155
154
|
context('.==') do
|
@@ -159,6 +158,32 @@ describe Draper::Base do
|
|
159
158
|
end
|
160
159
|
end
|
161
160
|
|
161
|
+
describe "collection decoration" do
|
162
|
+
|
163
|
+
# Implementation of #decorate that returns an array
|
164
|
+
# of decorated objects is insufficient to deal with
|
165
|
+
# situations where the original collection has been
|
166
|
+
# expanded with the use of modules (as often the case
|
167
|
+
# with paginator gems) or is just more complex then
|
168
|
+
# an array.
|
169
|
+
module Paginator; def page_number; "magic_value"; end; end
|
170
|
+
Array.send(:include, Paginator)
|
171
|
+
let(:paged_array) { [Product.new, Product.new] }
|
172
|
+
subject { ProductDecorator.decorate(paged_array) }
|
173
|
+
|
174
|
+
it "should proxy all calls to decorated collection" do
|
175
|
+
paged_array.page_number.should == "magic_value"
|
176
|
+
subject.page_number.should == "magic_value"
|
177
|
+
end
|
178
|
+
|
179
|
+
it "should support Rails partial lookup for a collection" do
|
180
|
+
# to support Rails render @collection the returned collection
|
181
|
+
# (or its proxy) should implement #to_ary.
|
182
|
+
subject.respond_to?(:to_ary).should be true
|
183
|
+
subject.to_a.first.should == ProductDecorator.decorate(paged_array.first)
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
162
187
|
describe "a sample usage with denies" do
|
163
188
|
let(:subject_with_denies){ DecoratorWithDenies.new(source) }
|
164
189
|
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
# Generators are not automatically loaded by Rails
|
4
|
+
require 'generators/rspec/decorator_generator'
|
5
|
+
|
6
|
+
describe Rspec::DecoratorGenerator do
|
7
|
+
# Tell the generator where to put its output (what it thinks of as Rails.root)
|
8
|
+
destination File.expand_path("../../../../tmp", __FILE__)
|
9
|
+
|
10
|
+
before { prepare_destination }
|
11
|
+
|
12
|
+
describe 'no arguments' do
|
13
|
+
before { run_generator %w(products) }
|
14
|
+
|
15
|
+
describe 'spec/decorators/application_decorator_spec.rb' do
|
16
|
+
subject { file('spec/decorators/application_decorator_spec.rb') }
|
17
|
+
it { should exist }
|
18
|
+
it { should contain "describe ApplicationDecorator do" }
|
19
|
+
end
|
20
|
+
|
21
|
+
describe 'spec/decorators/products_decorator_spec.rb' do
|
22
|
+
subject { file('spec/decorators/products_decorator_spec.rb') }
|
23
|
+
it { should exist }
|
24
|
+
it { should contain "describe ProductsDecorator" }
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
data/spec/view_context_spec.rb
CHANGED
@@ -22,4 +22,14 @@ describe Draper::ViewContext do
|
|
22
22
|
Thread.current[:current_view_context] = nil
|
23
23
|
expect {app_controller.current_view_context}.should raise_exception(Exception)
|
24
24
|
end
|
25
|
+
|
26
|
+
it "sets view_context every time" do
|
27
|
+
app_controller_instance.stub(:view_context) { 'first' }
|
28
|
+
app_controller_instance.set_current_view_context
|
29
|
+
Thread.current[:current_view_context].should == 'first'
|
30
|
+
|
31
|
+
app_controller_instance.stub(:view_context) { 'second' }
|
32
|
+
app_controller_instance.set_current_view_context
|
33
|
+
Thread.current[:current_view_context].should == 'second'
|
34
|
+
end
|
25
35
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: draper
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.9.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2011-10-
|
12
|
+
date: 2011-10-20 00:00:00.000000000Z
|
13
13
|
dependencies: []
|
14
14
|
description: Draper reimagines the role of helpers in the view layer of a Rails application,
|
15
15
|
allowing an object-oriented approach rather than procedural.
|
@@ -60,9 +60,13 @@ files:
|
|
60
60
|
- lib/generators/draper/decorator/templates/application_decorator.rb
|
61
61
|
- lib/generators/draper/decorator/templates/decorator.rb
|
62
62
|
- lib/generators/rails/decorator_generator.rb
|
63
|
+
- lib/generators/rspec/decorator_generator.rb
|
64
|
+
- lib/generators/rspec/templates/application_decorator_spec.rb
|
65
|
+
- lib/generators/rspec/templates/decorator_spec.rb
|
63
66
|
- spec/base_spec.rb
|
64
67
|
- spec/draper/model_support_spec.rb
|
65
68
|
- spec/generators/draper/decorator/decorator_generator_spec.rb
|
69
|
+
- spec/generators/rspec/decorator_generator_spec.rb
|
66
70
|
- spec/samples/active_record.rb
|
67
71
|
- spec/samples/application_controller.rb
|
68
72
|
- spec/samples/application_helper.rb
|
@@ -102,6 +106,7 @@ test_files:
|
|
102
106
|
- spec/base_spec.rb
|
103
107
|
- spec/draper/model_support_spec.rb
|
104
108
|
- spec/generators/draper/decorator/decorator_generator_spec.rb
|
109
|
+
- spec/generators/rspec/decorator_generator_spec.rb
|
105
110
|
- spec/samples/active_record.rb
|
106
111
|
- spec/samples/application_controller.rb
|
107
112
|
- spec/samples/application_helper.rb
|