draper 0.8.1 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|