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 CHANGED
@@ -1,5 +1,5 @@
1
1
  guard 'rspec', :version => 2, :notification => false do
2
2
  watch(%r{^spec/.+_spec\.rb$})
3
- watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
3
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
4
4
  watch('spec/spec_helper.rb') { "spec" }
5
5
  end
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
- lazy_helpers
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) ? input.map{|i| new(i, context)} : new(input, context)
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
- if select_methods.include?(method)
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 select_methods.include?(method)
142
- model.send(method, *args, &block)
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 select_methods
158
- specified = self.allowed || (model.public_methods.map{|s| s.to_sym} - denied.map{|s| s.to_sym})
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
@@ -1,3 +1,3 @@
1
1
  module Draper
2
- VERSION = "0.8.1"
2
+ VERSION = "0.9.0"
3
3
  end
@@ -1,7 +1,7 @@
1
1
  module Draper
2
2
  module ViewContext
3
3
  def set_current_view_context
4
- Thread.current[:current_view_context] ||= self.view_context
4
+ Thread.current[:current_view_context] = self.view_context
5
5
  end
6
6
 
7
7
  def self.included(source)
@@ -13,5 +13,7 @@ module Draper
13
13
  end
14
14
  template 'decorator.rb', "#{DECORATORS_ROOT}#{singular_name}_decorator.rb"
15
15
  end
16
+
17
+ hook_for :test_framework
16
18
  end
17
- end
19
+ end
@@ -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
@@ -0,0 +1,5 @@
1
+ require 'spec_helper'
2
+
3
+ describe ApplicationDecorator do
4
+ before { ApplicationController.new.set_current_view_context }
5
+ end
@@ -0,0 +1,5 @@
1
+ require 'spec_helper'
2
+
3
+ describe <%= singular_name.camelize %>Decorator do
4
+ before { ApplicationController.new.set_current_view_context }
5
+ 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
@@ -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.8.1
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-09 00:00:00.000000000Z
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