draper 1.0.0.beta6 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +6 -0
- data/.yardopts +1 -1
- data/CHANGELOG.md +20 -0
- data/Gemfile +11 -0
- data/README.md +14 -17
- data/Rakefile +5 -3
- data/draper.gemspec +2 -2
- data/lib/draper.rb +2 -1
- data/lib/draper/automatic_delegation.rb +50 -0
- data/lib/draper/collection_decorator.rb +26 -7
- data/lib/draper/decoratable.rb +71 -32
- data/lib/draper/decorated_association.rb +11 -7
- data/lib/draper/decorator.rb +114 -148
- data/lib/draper/delegation.rb +13 -0
- data/lib/draper/finders.rb +9 -6
- data/lib/draper/helper_proxy.rb +4 -3
- data/lib/draper/lazy_helpers.rb +10 -6
- data/lib/draper/railtie.rb +5 -4
- data/lib/draper/tasks/test.rake +22 -0
- data/lib/draper/test/devise_helper.rb +34 -0
- data/lib/draper/test/minitest_integration.rb +2 -3
- data/lib/draper/test/rspec_integration.rb +4 -59
- data/lib/draper/test_case.rb +33 -0
- data/lib/draper/version.rb +1 -1
- data/lib/draper/view_helpers.rb +4 -3
- data/lib/generators/decorator/templates/decorator.rb +7 -25
- data/lib/generators/mini_test/decorator_generator.rb +20 -0
- data/lib/generators/mini_test/templates/decorator_spec.rb +4 -0
- data/lib/generators/mini_test/templates/decorator_test.rb +4 -0
- data/lib/generators/test_unit/templates/decorator_test.rb +1 -1
- data/spec/draper/collection_decorator_spec.rb +25 -3
- data/spec/draper/decorated_association_spec.rb +18 -7
- data/spec/draper/decorator_spec.rb +125 -165
- data/spec/draper/finders_spec.rb +0 -13
- data/spec/dummy/app/controllers/localized_urls.rb +1 -1
- data/spec/dummy/app/controllers/posts_controller.rb +3 -9
- data/spec/dummy/app/decorators/post_decorator.rb +4 -1
- data/spec/dummy/config/application.rb +3 -3
- data/spec/dummy/config/environments/development.rb +4 -4
- data/spec/dummy/config/environments/test.rb +2 -2
- data/spec/dummy/lib/tasks/test.rake +10 -0
- data/spec/dummy/mini_test/mini_test_integration_test.rb +46 -0
- data/spec/dummy/spec/decorators/post_decorator_spec.rb +2 -2
- data/spec/dummy/spec/decorators/rspec_integration_spec.rb +19 -0
- data/spec/dummy/spec/mailers/post_mailer_spec.rb +2 -2
- data/spec/dummy/spec/spec_helper.rb +0 -1
- data/spec/generators/decorator/decorator_generator_spec.rb +43 -2
- data/spec/integration/integration_spec.rb +2 -2
- data/spec/spec_helper.rb +17 -21
- data/spec/support/active_record.rb +0 -13
- data/spec/support/dummy_app.rb +4 -3
- metadata +26 -23
- data/lib/draper/security.rb +0 -48
- data/lib/draper/tasks/tu.rake +0 -5
- data/lib/draper/test/test_unit_integration.rb +0 -18
- data/spec/draper/security_spec.rb +0 -158
- data/spec/dummy/config/initializers/wrap_parameters.rb +0 -14
- data/spec/dummy/lib/tasks/spec.rake +0 -5
- data/spec/minitest-rails/spec_type_spec.rb +0 -63
data/.travis.yml
CHANGED
data/.yardopts
CHANGED
@@ -1 +1 @@
|
|
1
|
-
yardoc 'lib/draper/**/*.rb' -m markdown
|
1
|
+
yardoc 'lib/draper/**/*.rb' -m markdown --no-private
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,25 @@
|
|
1
1
|
# Draper Changelog
|
2
2
|
|
3
|
+
## 1.0.0
|
4
|
+
|
5
|
+
* Infer collection decorators. [https://github.com/drapergem/draper/commit/e8253df7dc6c90a542444c0f4ef289909fce4f90](https://github.com/drapergem/draper/commit/e8253df7dc6c90a542444c0f4ef289909fce4f90)
|
6
|
+
|
7
|
+
* Prevent calls to `scoped` on decorated associations. [https://github.com/drapergem/draper/commit/5dcc6c31ecf408753158d15fed9fb23fbfdc3734](https://github.com/drapergem/draper/commit/5dcc6c31ecf408753158d15fed9fb23fbfdc3734)
|
8
|
+
|
9
|
+
* Add `helper` method to tests. [https://github.com/drapergem/draper/commit/551961e72ee92355bc9c848bedfcc573856d12b0](https://github.com/drapergem/draper/commit/551961e72ee92355bc9c848bedfcc573856d12b0)
|
10
|
+
|
11
|
+
* Inherit method security. [https://github.com/drapergem/draper/commit/1865ed3e3b2b34853689a60b59b8ce9145674d1d](https://github.com/drapergem/draper/commit/1865ed3e3b2b34853689a60b59b8ce9145674d1d)
|
12
|
+
|
13
|
+
* Test against all versions of Rails 3. [https://github.com/drapergem/draper/commit/1865ed3e3b2b34853689a60b59b8ce9145674d1d](https://github.com/drapergem/draper/commit/1865ed3e3b2b34853689a60b59b8ce9145674d1d)
|
14
|
+
|
15
|
+
* Pretend to be `instance_of?(source.class)` [https://github.com/drapergem/draper/commit/30d209f990847e84b221ac798e84b976f5775cc0](https://github.com/drapergem/draper/commit/30d209f990847e84b221ac798e84b976f5775cc0)
|
16
|
+
|
17
|
+
* Remove security from `Decorator`. Do manual delegation with `:delegate`. [https://github.com/drapergem/draper/commit/c6f8aaa2b2bd4679738050aede2503aa8e9db130](https://github.com/drapergem/draper/commit/c6f8aaa2b2bd4679738050aede2503aa8e9db130)
|
18
|
+
|
19
|
+
* Add generators for MiniTest. [https://github.com/drapergem/draper/commit/1fac02b65b15e32f06e8292cb858c97cb1c1da2c](https://github.com/drapergem/draper/commit/1fac02b65b15e32f06e8292cb858c97cb1c1da2c)
|
20
|
+
|
21
|
+
* Test against edge rails. [https://github.com/drapergem/draper/commit/e9b71e3cf55a800b48c083ff257a7c1cbe1b601b](https://github.com/drapergem/draper/commit/e9b71e3cf55a800b48c083ff257a7c1cbe1b601b)
|
22
|
+
|
3
23
|
## 1.0.0.beta6
|
4
24
|
|
5
25
|
* Fix up README to include changes made. [https://github.com/drapergem/draper/commit/5e6e4d11b1e0c07c12b6b1e87053bc3f50ef2ab6](https://github.com/drapergem/draper/commit/5e6e4d11b1e0c07c12b6b1e87053bc3f50ef2ab6)
|
data/Gemfile
CHANGED
@@ -10,3 +10,14 @@ platforms :jruby do
|
|
10
10
|
gem "minitest", ">= 3.0"
|
11
11
|
gem "activerecord-jdbcsqlite3-adapter", "~> 1.2.2.1"
|
12
12
|
end
|
13
|
+
|
14
|
+
case ENV["RAILS_VERSION"]
|
15
|
+
when "master"
|
16
|
+
gem "rails", github: "rails/rails"
|
17
|
+
when "3.2", nil
|
18
|
+
gem "rails", "~> 3.2.0"
|
19
|
+
when "3.1"
|
20
|
+
gem "rails", "~> 3.1.0"
|
21
|
+
when "3.0"
|
22
|
+
gem "rails", "~> 3.0.0"
|
23
|
+
end
|
data/README.md
CHANGED
@@ -35,6 +35,8 @@ could be better written as:
|
|
35
35
|
```ruby
|
36
36
|
# app/decorators/article_decorator.rb
|
37
37
|
class ArticleDecorator < Draper::Decorator
|
38
|
+
delegate_all
|
39
|
+
|
38
40
|
def publication_status
|
39
41
|
if published?
|
40
42
|
"Published at #{published_at}"
|
@@ -49,7 +51,7 @@ class ArticleDecorator < Draper::Decorator
|
|
49
51
|
end
|
50
52
|
```
|
51
53
|
|
52
|
-
Notice that the `published?` method can be called even though `ArticleDecorator` doesn't define it - the decorator delegates methods to the source model. However, we can override methods like `published_at` to add presentation-specific formatting, in which case we access the underlying model using the `source` method.
|
54
|
+
Notice that the `published?` method can be called even though `ArticleDecorator` doesn't define it - thanks to `delegate_all`, the decorator delegates missing methods to the source model. However, we can override methods like `published_at` to add presentation-specific formatting, in which case we access the underlying model using the `source` method.
|
53
55
|
|
54
56
|
You might have heard this sort of decorator called a "presenter", an "exhibit", a "view model", or even just a "view" (in that nomenclature, what Rails calls "views" are actually "templates"). Whatever you call it, it's a great way to replace procedural helpers like the one above with "real" object-oriented programming.
|
55
57
|
|
@@ -64,7 +66,7 @@ Decorators are the ideal place to:
|
|
64
66
|
Add Draper to your Gemfile:
|
65
67
|
|
66
68
|
```ruby
|
67
|
-
gem 'draper', '~> 1.0'
|
69
|
+
gem 'draper', '~> 1.0.0.beta6'
|
68
70
|
```
|
69
71
|
|
70
72
|
And run `bundle install` within your app's directory.
|
@@ -105,6 +107,8 @@ Decorators will delegate methods to the model where possible, which means in mos
|
|
105
107
|
|
106
108
|
```ruby
|
107
109
|
class ArticleDecorator < Draper::Decorator
|
110
|
+
delegate_all
|
111
|
+
|
108
112
|
def published_at
|
109
113
|
source.published_at.strftime("%A, %B %e")
|
110
114
|
end
|
@@ -158,14 +162,16 @@ end
|
|
158
162
|
|
159
163
|
Draper guesses the decorator used for each item from the name of the collection decorator (`ArticlesDecorator` becomes `ArticleDecorator`). If that fails, it falls back to using each item's `decorate` method. Alternatively, you can specify a decorator by overriding the collection decorator's `decorator_class` method.
|
160
164
|
|
161
|
-
Some pagination gems add methods to `ActiveRecord::Relation`. For example, [Kaminari](https://github.com/amatsuda/kaminari)'s `paginate` helper method requires the collection to implement `current_page`, `total_pages`, and `limit_value`. To expose these on a collection decorator, you can simply delegate to `source`:
|
165
|
+
Some pagination gems add methods to `ActiveRecord::Relation`. For example, [Kaminari](https://github.com/amatsuda/kaminari)'s `paginate` helper method requires the collection to implement `current_page`, `total_pages`, and `limit_value`. To expose these on a collection decorator, you can simply delegate to the `source`:
|
162
166
|
|
163
167
|
```ruby
|
164
168
|
class PaginatingDecorator < Draper::CollectionDecorator
|
165
|
-
delegate :current_page, :total_pages, :limit_value
|
169
|
+
delegate :current_page, :total_pages, :limit_value
|
166
170
|
end
|
167
171
|
```
|
168
172
|
|
173
|
+
The `delegate` method used here is the same as that added by [Active Support](http://api.rubyonrails.org/classes/Module.html#method-i-delegate), except that the `:to` option is not required; it defaults to `:source` when omitted.
|
174
|
+
|
169
175
|
### Handy shortcuts
|
170
176
|
|
171
177
|
You can automatically decorate associated models:
|
@@ -193,7 +199,7 @@ so that you can do:
|
|
193
199
|
|
194
200
|
## Testing
|
195
201
|
|
196
|
-
Draper supports RSpec and
|
202
|
+
Draper supports RSpec, MiniTest::Rails, and Test::Unit, and will add the appropriate tests when you generate a decorator.
|
197
203
|
|
198
204
|
### RSpec
|
199
205
|
|
@@ -229,25 +235,16 @@ and inherit from it instead of directly from `Draper::Decorator`.
|
|
229
235
|
|
230
236
|
### Enforcing an interface between controllers and views
|
231
237
|
|
232
|
-
If you want to strictly control which methods are called in your views, you can
|
238
|
+
The `delegate_all` call at the top of your decorator means that all missing methods will delegated to the source. If you want to strictly control which methods are called in your views, you can choose to only delegate certain methods.
|
233
239
|
|
234
240
|
```ruby
|
235
241
|
class ArticleDecorator < Draper::Decorator
|
236
|
-
|
237
|
-
denies :title, :author
|
242
|
+
delegate :title, :author
|
238
243
|
end
|
239
244
|
```
|
240
245
|
|
241
|
-
|
242
|
-
|
243
|
-
```ruby
|
244
|
-
class ArticleDecorator < Draper::Decorator
|
245
|
-
# only allow `title` and `author` to be delegated to the model
|
246
|
-
allows :title, :author
|
247
|
-
end
|
248
|
-
```
|
246
|
+
As mentioned above for `CollectionDecorator`, the `delegate` method defaults to using `:source` if the `:to` option is omitted.
|
249
247
|
|
250
|
-
You can prevent method delegation altogether using `denies_all`.
|
251
248
|
|
252
249
|
### Adding context
|
253
250
|
|
data/Rakefile
CHANGED
@@ -16,7 +16,7 @@ desc "Run all specs"
|
|
16
16
|
task "spec" => "spec:all"
|
17
17
|
|
18
18
|
namespace "spec" do
|
19
|
-
task "all" => ["draper", "generators", "
|
19
|
+
task "all" => ["draper", "generators", "integration"]
|
20
20
|
|
21
21
|
def spec_task(name)
|
22
22
|
desc "Run #{name} specs"
|
@@ -27,7 +27,6 @@ namespace "spec" do
|
|
27
27
|
|
28
28
|
spec_task "draper"
|
29
29
|
spec_task "generators"
|
30
|
-
spec_task "minitest-rails"
|
31
30
|
|
32
31
|
desc "Run integration specs"
|
33
32
|
task "integration" => ["db:setup", "integration:all"]
|
@@ -51,6 +50,8 @@ namespace "spec" do
|
|
51
50
|
end
|
52
51
|
|
53
52
|
task "test" do
|
53
|
+
puts "Running rake in dummy app"
|
54
|
+
ENV["RAILS_ENV"] = "test"
|
54
55
|
run_in_dummy_app "rake"
|
55
56
|
end
|
56
57
|
end
|
@@ -60,7 +61,8 @@ namespace "db" do
|
|
60
61
|
desc "Set up databases for integration testing"
|
61
62
|
task "setup" do
|
62
63
|
run_in_dummy_app "rm -f db/*.sqlite3"
|
63
|
-
run_in_dummy_app "RAILS_ENV=development rake db:schema:load db:seed
|
64
|
+
run_in_dummy_app "RAILS_ENV=development rake db:schema:load db:seed"
|
64
65
|
run_in_dummy_app "RAILS_ENV=production rake db:schema:load db:seed"
|
66
|
+
run_in_dummy_app "RAILS_ENV=test rake db:schema:load"
|
65
67
|
end
|
66
68
|
end
|
data/draper.gemspec
CHANGED
@@ -21,10 +21,10 @@ Gem::Specification.new do |s|
|
|
21
21
|
s.add_dependency 'request_store', '~> 1.0.3'
|
22
22
|
|
23
23
|
s.add_development_dependency 'ammeter'
|
24
|
-
s.add_development_dependency 'rake', '
|
24
|
+
s.add_development_dependency 'rake', '>= 0.9.2'
|
25
25
|
s.add_development_dependency 'rspec', '~> 2.12'
|
26
26
|
s.add_development_dependency 'rspec-mocks', '>= 2.12.1'
|
27
|
-
s.add_development_dependency '
|
27
|
+
s.add_development_dependency 'rspec-rails', '~> 2.12'
|
28
28
|
s.add_development_dependency 'minitest-rails', '~> 0.2'
|
29
29
|
s.add_development_dependency 'capybara'
|
30
30
|
end
|
data/lib/draper.rb
CHANGED
@@ -2,13 +2,14 @@ require 'action_view'
|
|
2
2
|
|
3
3
|
require 'draper/version'
|
4
4
|
require 'draper/view_helpers'
|
5
|
+
require 'draper/delegation'
|
6
|
+
require 'draper/automatic_delegation'
|
5
7
|
require 'draper/finders'
|
6
8
|
require 'draper/decorator'
|
7
9
|
require 'draper/helper_proxy'
|
8
10
|
require 'draper/lazy_helpers'
|
9
11
|
require 'draper/decoratable'
|
10
12
|
require 'draper/decorated_association'
|
11
|
-
require 'draper/security'
|
12
13
|
require 'draper/helper_support'
|
13
14
|
require 'draper/view_context'
|
14
15
|
require 'draper/collection_decorator'
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Draper
|
2
|
+
module AutomaticDelegation
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
# Delegates missing instance methods to the source object.
|
6
|
+
def method_missing(method, *args, &block)
|
7
|
+
return super unless delegatable?(method)
|
8
|
+
|
9
|
+
self.class.delegate method
|
10
|
+
send(method, *args, &block)
|
11
|
+
end
|
12
|
+
|
13
|
+
# Checks if the decorator responds to an instance method, or is able to
|
14
|
+
# proxy it to the source object.
|
15
|
+
def respond_to?(method, include_private = false)
|
16
|
+
super || delegatable?(method)
|
17
|
+
end
|
18
|
+
|
19
|
+
# @private
|
20
|
+
def delegatable?(method)
|
21
|
+
source.respond_to?(method)
|
22
|
+
end
|
23
|
+
|
24
|
+
module ClassMethods
|
25
|
+
# Proxies missing class methods to the source class.
|
26
|
+
def method_missing(method, *args, &block)
|
27
|
+
return super unless delegatable?(method)
|
28
|
+
|
29
|
+
source_class.send(method, *args, &block)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Checks if the decorator responds to a class method, or is able to proxy
|
33
|
+
# it to the source class.
|
34
|
+
def respond_to?(method, include_private = false)
|
35
|
+
super || delegatable?(method)
|
36
|
+
end
|
37
|
+
|
38
|
+
# @private
|
39
|
+
def delegatable?(method)
|
40
|
+
source_class? && source_class.respond_to?(method)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
included do
|
45
|
+
private :delegatable?
|
46
|
+
private_class_method :delegatable?
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
@@ -1,16 +1,26 @@
|
|
1
1
|
module Draper
|
2
2
|
class CollectionDecorator
|
3
3
|
include Enumerable
|
4
|
-
include ViewHelpers
|
4
|
+
include Draper::ViewHelpers
|
5
|
+
extend Draper::Delegation
|
5
6
|
|
7
|
+
# @return [Hash] extra data to be used in user-defined methods, and passed
|
8
|
+
# to each item's decorator.
|
6
9
|
attr_accessor :context
|
7
10
|
|
8
11
|
array_methods = Array.instance_methods - Object.instance_methods
|
9
12
|
delegate :==, :as_json, *array_methods, to: :decorated_collection
|
10
13
|
|
11
|
-
# @param source
|
12
|
-
#
|
13
|
-
# @option options [
|
14
|
+
# @param [Enumerable] source
|
15
|
+
# collection to decorate.
|
16
|
+
# @option options [Class, nil] :with (nil)
|
17
|
+
# the decorator class used to decorate each item. When `nil`, it is
|
18
|
+
# inferred from the collection decorator class if possible (e.g.
|
19
|
+
# `ProductsDecorator` maps to `ProductDecorator`), otherwise each item's
|
20
|
+
# {Decoratable#decorate decorate} method will be used.
|
21
|
+
# @option options [Hash] :context ({})
|
22
|
+
# extra data to be stored in the collection decorator and used in
|
23
|
+
# user-defined methods, and passed to each item's decorator.
|
14
24
|
def initialize(source, options = {})
|
15
25
|
options.assert_valid_keys(:with, :context)
|
16
26
|
@source = source
|
@@ -22,10 +32,14 @@ module Draper
|
|
22
32
|
alias_method :decorate, :new
|
23
33
|
end
|
24
34
|
|
35
|
+
# @return [Array] the decorated items.
|
25
36
|
def decorated_collection
|
26
37
|
@decorated_collection ||= source.map{|item| decorate_item(item)}
|
27
38
|
end
|
28
39
|
|
40
|
+
# Delegated to the decorated collection when using the block form
|
41
|
+
# (`Enumerable#find`) or to the decorator class if not
|
42
|
+
# (`ActiveRecord::FinderMethods#find`)
|
29
43
|
def find(*args, &block)
|
30
44
|
if block_given?
|
31
45
|
decorated_collection.find(*args, &block)
|
@@ -41,7 +55,7 @@ module Draper
|
|
41
55
|
"inferred decorators"
|
42
56
|
end
|
43
57
|
|
44
|
-
"
|
58
|
+
"#<#{self.class.name} of #{klass} for #{source.inspect}>"
|
45
59
|
end
|
46
60
|
|
47
61
|
def context=(value)
|
@@ -49,18 +63,25 @@ module Draper
|
|
49
63
|
each {|item| item.context = value } if @decorated_collection
|
50
64
|
end
|
51
65
|
|
66
|
+
# @return [Class] the decorator class used to decorate each item, as set by
|
67
|
+
# {#initialize} or as inferred from the collection decorator class (e.g.
|
68
|
+
# `ProductsDecorator` maps to `ProductDecorator`).
|
52
69
|
def decorator_class
|
53
70
|
@decorator_class ||= self.class.inferred_decorator_class
|
54
71
|
end
|
55
72
|
|
56
73
|
protected
|
57
74
|
|
75
|
+
# @return the collection being decorated.
|
58
76
|
attr_reader :source
|
59
77
|
|
78
|
+
# Decorates the given item.
|
60
79
|
def decorate_item(item)
|
61
80
|
item_decorator.call(item, context: context)
|
62
81
|
end
|
63
82
|
|
83
|
+
private
|
84
|
+
|
64
85
|
def self.inferred_decorator_class
|
65
86
|
decorator_name = "#{name.chomp("Decorator").singularize}Decorator"
|
66
87
|
decorator_uninferrable if decorator_name == name
|
@@ -75,8 +96,6 @@ module Draper
|
|
75
96
|
raise Draper::UninferrableDecoratorError.new(self)
|
76
97
|
end
|
77
98
|
|
78
|
-
private
|
79
|
-
|
80
99
|
def item_decorator
|
81
100
|
@item_decorator ||= begin
|
82
101
|
decorator_class.method(:decorate)
|
data/lib/draper/decoratable.rb
CHANGED
@@ -1,44 +1,83 @@
|
|
1
|
-
module Draper
|
2
|
-
|
1
|
+
module Draper
|
2
|
+
# Provides shortcuts to decorate objects directly, so you can do
|
3
|
+
# `@product.decorate` instead of `ProductDecorator.new(@product)`.
|
4
|
+
#
|
5
|
+
# This module is included by default into `ActiveRecord::Base` and
|
6
|
+
# `Mongoid::Document`, but you're using another ORM, or want to decorate
|
7
|
+
# plain old Ruby objects, you can include it manually.
|
8
|
+
module Decoratable
|
9
|
+
extend ActiveSupport::Concern
|
3
10
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
end
|
11
|
-
|
12
|
-
def applied_decorators
|
13
|
-
[]
|
14
|
-
end
|
11
|
+
# Decorates the object using the inferred {#decorator_class}.
|
12
|
+
# @param [Hash] options
|
13
|
+
# see {Decorator#initialize}
|
14
|
+
def decorate(options = {})
|
15
|
+
decorator_class.decorate(self, options)
|
16
|
+
end
|
15
17
|
|
16
|
-
|
17
|
-
|
18
|
-
|
18
|
+
# (see ClassMethods#decorator_class)
|
19
|
+
def decorator_class
|
20
|
+
self.class.decorator_class
|
21
|
+
end
|
19
22
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
+
# The list of decorators that have been applied to the object.
|
24
|
+
#
|
25
|
+
# @return [Array<Class>] `[]`
|
26
|
+
def applied_decorators
|
27
|
+
[]
|
28
|
+
end
|
23
29
|
|
24
|
-
|
25
|
-
|
26
|
-
|
30
|
+
# (see Decorator#decorated_with?)
|
31
|
+
# @return [false]
|
32
|
+
def decorated_with?(decorator_class)
|
33
|
+
false
|
34
|
+
end
|
27
35
|
|
28
|
-
|
29
|
-
|
30
|
-
|
36
|
+
# Checks if this object is decorated.
|
37
|
+
#
|
38
|
+
# @return [false]
|
39
|
+
def decorated?
|
40
|
+
false
|
31
41
|
end
|
32
42
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
43
|
+
# Compares with possibly-decorated objects.
|
44
|
+
#
|
45
|
+
# @return [Boolean]
|
46
|
+
def ==(other)
|
47
|
+
super || (other.respond_to?(:source) && self == other.source)
|
38
48
|
end
|
39
49
|
|
40
|
-
|
41
|
-
|
50
|
+
module ClassMethods
|
51
|
+
|
52
|
+
# Decorates a collection of objects. Used at the end of a scope chain.
|
53
|
+
#
|
54
|
+
# @example
|
55
|
+
# Product.popular.decorate
|
56
|
+
# @param [Hash] options
|
57
|
+
# see {Decorator.decorate_collection}.
|
58
|
+
def decorate(options = {})
|
59
|
+
decorator_class.decorate_collection(self.scoped, options)
|
60
|
+
end
|
61
|
+
|
62
|
+
# Infers the decorator class to be used by {Decoratable#decorate} (e.g.
|
63
|
+
# `Product` maps to `ProductDecorator`).
|
64
|
+
#
|
65
|
+
# @return [Class] the inferred decorator class.
|
66
|
+
def decorator_class
|
67
|
+
prefix = respond_to?(:model_name) ? model_name : name
|
68
|
+
"#{prefix}Decorator".constantize
|
69
|
+
rescue NameError
|
70
|
+
raise Draper::UninferrableDecoratorError.new(self)
|
71
|
+
end
|
72
|
+
|
73
|
+
# Compares with possibly-decorated objects.
|
74
|
+
#
|
75
|
+
# @return [Boolean]
|
76
|
+
def ===(other)
|
77
|
+
super || (other.respond_to?(:source) && super(other.source))
|
78
|
+
end
|
79
|
+
|
42
80
|
end
|
81
|
+
|
43
82
|
end
|
44
83
|
end
|