draper 0.18.0 → 1.0.0.beta1
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/.gitignore +3 -0
- data/.travis.yml +5 -0
- data/CHANGELOG.markdown +8 -0
- data/Gemfile +4 -0
- data/Rakefile +50 -31
- data/Readme.markdown +42 -48
- data/draper.gemspec +2 -1
- data/lib/draper.rb +42 -7
- data/lib/draper/collection_decorator.rb +88 -0
- data/lib/draper/decoratable.rb +44 -0
- data/lib/draper/decorated_association.rb +55 -0
- data/lib/draper/decorator.rb +208 -0
- data/lib/draper/finders.rb +44 -0
- data/lib/draper/helper_proxy.rb +16 -0
- data/lib/draper/railtie.rb +17 -21
- data/lib/draper/security.rb +48 -0
- data/lib/draper/tasks/tu.rake +5 -0
- data/lib/draper/test/minitest_integration.rb +1 -1
- data/lib/draper/test/test_unit_integration.rb +9 -0
- data/lib/draper/version.rb +1 -1
- data/lib/draper/view_context.rb +6 -13
- data/lib/draper/view_helpers.rb +36 -0
- data/lib/generators/decorator/decorator_generator.rb +1 -1
- data/lib/generators/decorator/templates/decorator.rb +0 -1
- data/spec/draper/collection_decorator_spec.rb +240 -0
- data/spec/draper/decoratable_spec.rb +164 -0
- data/spec/draper/decorated_association_spec.rb +130 -0
- data/spec/draper/decorator_spec.rb +497 -0
- data/spec/draper/finders_spec.rb +156 -0
- data/spec/draper/helper_proxy_spec.rb +12 -0
- data/spec/draper/security_spec.rb +158 -0
- data/spec/draper/view_helpers_spec.rb +41 -0
- data/spec/dummy/.rspec +2 -0
- data/spec/dummy/README.rdoc +261 -0
- data/spec/dummy/Rakefile +7 -0
- data/spec/dummy/app/controllers/application_controller.rb +4 -0
- data/spec/dummy/app/controllers/localized_urls.rb +5 -0
- data/spec/dummy/app/controllers/posts_controller.rb +17 -0
- data/spec/dummy/app/decorators/post_decorator.rb +25 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/mailers/application_mailer.rb +3 -0
- data/spec/dummy/app/mailers/post_mailer.rb +9 -0
- data/spec/dummy/app/models/post.rb +3 -0
- data/spec/dummy/app/views/layouts/application.html.erb +11 -0
- data/spec/dummy/app/views/post_mailer/decorated_email.html.erb +1 -0
- data/spec/dummy/app/views/posts/_post.html.erb +19 -0
- data/spec/dummy/app/views/posts/show.html.erb +1 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +64 -0
- data/spec/dummy/config/boot.rb +10 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +34 -0
- data/spec/dummy/config/environments/production.rb +55 -0
- data/spec/dummy/config/environments/test.rb +32 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/inflections.rb +15 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/secret_token.rb +7 -0
- data/spec/dummy/config/initializers/session_store.rb +8 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +5 -0
- data/spec/dummy/config/routes.rb +7 -0
- data/spec/dummy/db/migrate/20121019115657_create_posts.rb +8 -0
- data/spec/dummy/db/schema.rb +21 -0
- data/spec/dummy/db/seeds.rb +2 -0
- data/spec/dummy/lib/tasks/spec.rake +5 -0
- data/spec/dummy/public/404.html +26 -0
- data/spec/dummy/public/422.html +26 -0
- data/spec/dummy/public/500.html +25 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/script/rails +6 -0
- data/spec/dummy/spec/decorators/post_decorator_spec.rb +23 -0
- data/spec/dummy/spec/mailers/post_mailer_spec.rb +29 -0
- data/spec/dummy/spec/spec_helper.rb +9 -0
- data/spec/generators/decorator/decorator_generator_spec.rb +3 -4
- data/spec/integration/integration_spec.rb +33 -0
- data/{performance → spec/performance}/active_record.rb +0 -0
- data/{performance/bechmark.rb → spec/performance/benchmark.rb} +0 -0
- data/{performance → spec/performance}/decorators.rb +2 -4
- data/{performance → spec/performance}/models.rb +0 -0
- data/spec/spec_helper.rb +20 -41
- data/spec/support/action_controller.rb +12 -0
- data/spec/support/active_model.rb +7 -0
- data/spec/support/{samples/active_record.rb → active_record.rb} +5 -0
- data/spec/support/{samples → decorators}/decorator_with_application_helper.rb +1 -1
- data/spec/support/decorators/namespaced_product_decorator.rb +5 -0
- data/spec/support/decorators/non_active_model_product_decorator.rb +2 -0
- data/spec/support/decorators/product_decorator.rb +19 -0
- data/spec/support/{samples → decorators}/products_decorator.rb +1 -1
- data/spec/support/decorators/some_thing_decorator.rb +2 -0
- data/spec/support/{samples → decorators}/specific_product_decorator.rb +0 -2
- data/spec/support/{samples → decorators}/widget_decorator.rb +0 -0
- data/spec/support/dummy_app.rb +84 -0
- data/spec/support/matchers/have_text.rb +50 -0
- data/spec/support/{samples → models}/namespaced_product.rb +1 -3
- data/spec/support/{samples → models}/non_active_model_product.rb +1 -0
- data/spec/support/{samples → models}/product.rb +13 -2
- data/spec/support/models/some_thing.rb +5 -0
- data/spec/support/models/uninferrable_decorator_model.rb +3 -0
- data/spec/support/{samples → models}/widget.rb +0 -0
- metadata +185 -68
- data/lib/draper/active_model_support.rb +0 -27
- data/lib/draper/base.rb +0 -312
- data/lib/draper/decorated_enumerable_proxy.rb +0 -90
- data/lib/draper/model_support.rb +0 -25
- data/lib/draper/rspec_integration.rb +0 -2
- data/lib/draper/system.rb +0 -18
- data/spec/draper/base_spec.rb +0 -873
- data/spec/draper/decorated_enumerable_proxy_spec.rb +0 -45
- data/spec/draper/model_support_spec.rb +0 -48
- data/spec/support/samples/decorator.rb +0 -5
- data/spec/support/samples/decorator_with_allows.rb +0 -3
- data/spec/support/samples/decorator_with_denies.rb +0 -3
- data/spec/support/samples/decorator_with_denies_all.rb +0 -3
- data/spec/support/samples/decorator_with_multiple_allows.rb +0 -4
- data/spec/support/samples/decorator_with_special_methods.rb +0 -13
- data/spec/support/samples/enumerable_proxy.rb +0 -3
- data/spec/support/samples/namespaced_product_decorator.rb +0 -7
- data/spec/support/samples/product_decorator.rb +0 -7
- data/spec/support/samples/sequel_product.rb +0 -13
- data/spec/support/samples/some_thing.rb +0 -2
- data/spec/support/samples/some_thing_decorator.rb +0 -3
@@ -1,27 +0,0 @@
|
|
1
|
-
module Draper::ActiveModelSupport
|
2
|
-
module Proxies
|
3
|
-
def self.extended(base)
|
4
|
-
# These methods (as keys) will be created only if the correspondent
|
5
|
-
# model responds to the method
|
6
|
-
proxies = [:to_param, :errors, :id]
|
7
|
-
|
8
|
-
proxies.each do |method_name|
|
9
|
-
if base.model.respond_to?(method_name)
|
10
|
-
base.singleton_class.class_eval do
|
11
|
-
if !base.class.instance_methods.include?(method_name) || base.class.instance_method(method_name).owner === Draper::Base
|
12
|
-
define_method(method_name) do |*args, &block|
|
13
|
-
model.send(method_name, *args, &block)
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
base.class_eval do
|
21
|
-
def to_model
|
22
|
-
self
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
data/lib/draper/base.rb
DELETED
@@ -1,312 +0,0 @@
|
|
1
|
-
module Draper
|
2
|
-
class Base
|
3
|
-
require 'active_support/core_ext/class/attribute'
|
4
|
-
require 'active_support/core_ext/array/extract_options'
|
5
|
-
|
6
|
-
class_attribute :denied, :allowed, :model_class
|
7
|
-
attr_accessor :model, :options
|
8
|
-
|
9
|
-
DEFAULT_DENIED = Object.instance_methods << :method_missing
|
10
|
-
DEFAULT_ALLOWED = []
|
11
|
-
self.denied = DEFAULT_DENIED
|
12
|
-
self.allowed = DEFAULT_ALLOWED
|
13
|
-
|
14
|
-
# Initialize a new decorator instance by passing in
|
15
|
-
# an instance of the source class. Pass in an optional
|
16
|
-
# context inside the options hash is stored for later use.
|
17
|
-
#
|
18
|
-
# @param [Object] instance to wrap
|
19
|
-
# @param [Hash] options (optional)
|
20
|
-
def initialize(input, options = {})
|
21
|
-
input.to_a if input.respond_to?(:to_a) # forces evaluation of a lazy query from AR
|
22
|
-
self.class.model_class = input.class if model_class.nil?
|
23
|
-
@model = input.kind_of?(Draper::Base) ? input.model : input
|
24
|
-
self.options = options
|
25
|
-
self.extend Draper::ActiveModelSupport::Proxies
|
26
|
-
end
|
27
|
-
|
28
|
-
# Proxies to the class specified by `decorates` to automatically
|
29
|
-
# lookup an object in the database and decorate it.
|
30
|
-
#
|
31
|
-
# @param [Symbol or String] id to lookup
|
32
|
-
# @return [Object] instance of this decorator class
|
33
|
-
def self.find(input, options = {})
|
34
|
-
self.new(model_class.find(input), options)
|
35
|
-
end
|
36
|
-
|
37
|
-
# Typically called within a decorator definition, this method
|
38
|
-
# specifies the name of the wrapped object class.
|
39
|
-
#
|
40
|
-
# For instance, a `ProductDecorator` class might call `decorates :product`
|
41
|
-
#
|
42
|
-
# But they don't have to match in name, so a `EmployeeDecorator`
|
43
|
-
# class could call `decorates :person` to wrap instances of `Person`
|
44
|
-
#
|
45
|
-
# This is primarilly set so the `.find` method knows which class
|
46
|
-
# to query.
|
47
|
-
#
|
48
|
-
# @param [Symbol] class_name snakecase name of the decorated class, like `:product`
|
49
|
-
def self.decorates(input, options = {})
|
50
|
-
self.model_class = options[:class] || options[:class_name] || input.to_s.camelize
|
51
|
-
self.model_class = model_class.constantize if model_class.respond_to?(:constantize)
|
52
|
-
model_class.send :include, Draper::ModelSupport
|
53
|
-
define_method(input){ @model }
|
54
|
-
end
|
55
|
-
|
56
|
-
# Typically called within a decorator definition, this method causes
|
57
|
-
# the assocation to be decorated when it is retrieved.
|
58
|
-
#
|
59
|
-
# @param [Symbol] name of association to decorate, like `:products`
|
60
|
-
# @option options [Hash] :with The decorator to decorate the association with
|
61
|
-
# :scope The scope to apply to the association
|
62
|
-
def self.decorates_association(association_symbol, options = {})
|
63
|
-
define_method(association_symbol) do
|
64
|
-
orig_association = model.send(association_symbol)
|
65
|
-
|
66
|
-
return orig_association if orig_association.nil?
|
67
|
-
return decorated_associations[association_symbol] if decorated_associations[association_symbol]
|
68
|
-
|
69
|
-
orig_association = orig_association.send(options[:scope]) if options[:scope]
|
70
|
-
|
71
|
-
return options[:with].decorate(orig_association) if options[:with]
|
72
|
-
|
73
|
-
klass = if options[:polymorphic]
|
74
|
-
orig_association.class
|
75
|
-
elsif association_reflection = find_association_reflection(association_symbol)
|
76
|
-
association_reflection.klass
|
77
|
-
elsif orig_association.respond_to?(:first)
|
78
|
-
orig_association.first.class
|
79
|
-
else
|
80
|
-
orig_association.class
|
81
|
-
end
|
82
|
-
|
83
|
-
decorated_associations[association_symbol] = "#{klass}Decorator".constantize.decorate(orig_association, options)
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
|
-
# A convenience method for decorating multiple associations. Calls
|
88
|
-
# decorates_association on each of the given symbols.
|
89
|
-
#
|
90
|
-
# @param [Symbols*] name of associations to decorate
|
91
|
-
def self.decorates_associations(*association_symbols)
|
92
|
-
options = association_symbols.extract_options!
|
93
|
-
association_symbols.each{ |sym| decorates_association(sym, options) }
|
94
|
-
end
|
95
|
-
|
96
|
-
# Specifies a black list of methods which may *not* be proxied to
|
97
|
-
# to the wrapped object.
|
98
|
-
#
|
99
|
-
# Do not use both `.allows` and `.denies` together, either write
|
100
|
-
# a whitelist with `.allows` or a blacklist with `.denies`
|
101
|
-
#
|
102
|
-
# @param [Symbols*] methods to deny like `:find, :find_by_name`
|
103
|
-
def self.denies(*input_denied)
|
104
|
-
raise ArgumentError, "Specify at least one method (as a symbol) to exclude when using denies" if input_denied.empty?
|
105
|
-
raise ArgumentError, "Use either 'allows' or 'denies', but not both." unless (self.allowed == DEFAULT_ALLOWED)
|
106
|
-
self.denied += input_denied
|
107
|
-
end
|
108
|
-
|
109
|
-
# Specifies that all methods may *not* be proxied to
|
110
|
-
# to the wrapped object.
|
111
|
-
#
|
112
|
-
# Do not use `.allows` and `.denies` in combination with '.denies_all'
|
113
|
-
def self.denies_all
|
114
|
-
raise ArgumentError, "Use either 'allows' or 'denies', but not both." unless ((self.allowed == DEFAULT_ALLOWED && self.denied == DEFAULT_DENIED) || (self.allowed != DEFAULT_ALLOWED && self.denied != DEFAULT_DENIED))
|
115
|
-
self.denied += [nil] # Add dummy value to denied to prevent calls to #allows. Hacky???
|
116
|
-
self.allowed += [nil] # Add dummy value to allowed to prevent calls to #denies
|
117
|
-
end
|
118
|
-
|
119
|
-
# Specifies a white list of methods which *may* be proxied to
|
120
|
-
# to the wrapped object. When `allows` is used, only the listed
|
121
|
-
# methods and methods defined in the decorator itself will be
|
122
|
-
# available.
|
123
|
-
#
|
124
|
-
# Do not use both `.allows` and `.denies` together, either write
|
125
|
-
# a whitelist with `.allows` or a blacklist with `.denies`
|
126
|
-
#
|
127
|
-
# @param [Symbols*] methods to allow like `:find, :find_by_name`
|
128
|
-
def self.allows(*input_allows)
|
129
|
-
raise ArgumentError, "Specify at least one method (as a symbol) to allow when using allows" if input_allows.empty?
|
130
|
-
raise ArgumentError, "Use either 'allows' or 'denies', but not both." unless (self.denied == DEFAULT_DENIED)
|
131
|
-
self.allowed += input_allows
|
132
|
-
end
|
133
|
-
|
134
|
-
# Initialize a new decorator instance by passing in
|
135
|
-
# an instance of the source class. Pass in an optional
|
136
|
-
# context into the options hash is stored for later use.
|
137
|
-
#
|
138
|
-
# When passing in a single object, using `.decorate` is
|
139
|
-
# identical to calling `.new`. However, `.decorate` can
|
140
|
-
# also accept a collection and return a collection of
|
141
|
-
# individually decorated objects.
|
142
|
-
#
|
143
|
-
# @param [Object] instance(s) to wrap
|
144
|
-
# @param [Hash] options (optional)
|
145
|
-
# @option options [Boolean] :infer If true, each model will be
|
146
|
-
# wrapped by its inferred decorator.
|
147
|
-
def self.decorate(input, options = {})
|
148
|
-
if input.instance_of?(self)
|
149
|
-
input.options = options unless options.empty?
|
150
|
-
return input
|
151
|
-
elsif input.respond_to?(:each) && !input.is_a?(Struct) && (!defined?(Sequel) || !input.is_a?(Sequel::Model))
|
152
|
-
Draper::DecoratedEnumerableProxy.new(input, self, options)
|
153
|
-
elsif options[:infer]
|
154
|
-
input.decorator(options)
|
155
|
-
else
|
156
|
-
new(input, options)
|
157
|
-
end
|
158
|
-
end
|
159
|
-
|
160
|
-
# Fetch all instances of the decorated class and decorate them.
|
161
|
-
#
|
162
|
-
# @param [Hash] options (optional)
|
163
|
-
# @return [Draper::DecoratedEnumerableProxy]
|
164
|
-
def self.all(options = {})
|
165
|
-
Draper::DecoratedEnumerableProxy.new(model_class.all, self, options)
|
166
|
-
end
|
167
|
-
|
168
|
-
def self.first(options = {})
|
169
|
-
decorate(model_class.first, options)
|
170
|
-
end
|
171
|
-
|
172
|
-
def self.last(options = {})
|
173
|
-
decorate(model_class.last, options)
|
174
|
-
end
|
175
|
-
|
176
|
-
# Some helpers are private, for example html_escape... as a workaround
|
177
|
-
# we are wrapping the helpers in a delegator that passes the methods
|
178
|
-
# along through a send, which will ignore private/public distinctions
|
179
|
-
class HelpersWrapper
|
180
|
-
def initialize(helpers)
|
181
|
-
@helpers = helpers
|
182
|
-
end
|
183
|
-
|
184
|
-
def method_missing(method, *args, &block)
|
185
|
-
@helpers.send(method, *args, &block)
|
186
|
-
end
|
187
|
-
|
188
|
-
#needed for tests
|
189
|
-
def ==(other)
|
190
|
-
other.instance_variable_get(:@helpers) == @helpers
|
191
|
-
end
|
192
|
-
end
|
193
|
-
|
194
|
-
# Access the helpers proxy to call built-in and user-defined
|
195
|
-
# Rails helpers. Aliased to `.h` for convenience.
|
196
|
-
#
|
197
|
-
# @return [Object] proxy
|
198
|
-
def helpers
|
199
|
-
HelpersWrapper.new self.class.helpers
|
200
|
-
end
|
201
|
-
alias :h :helpers
|
202
|
-
|
203
|
-
# Localize is something that's used quite often. Even though
|
204
|
-
# it's available through helpers, that's annoying. Aliased
|
205
|
-
# to `.l` for convenience.
|
206
|
-
def localize(object, options = {})
|
207
|
-
self.class.helpers.localize(object, options)
|
208
|
-
end
|
209
|
-
alias :l :localize
|
210
|
-
|
211
|
-
# Access the helpers proxy to call built-in and user-defined
|
212
|
-
# Rails helpers from a class context.
|
213
|
-
#
|
214
|
-
# @return [Object] proxy
|
215
|
-
class << self
|
216
|
-
def helpers
|
217
|
-
Draper::ViewContext.current
|
218
|
-
end
|
219
|
-
alias :h :helpers
|
220
|
-
end
|
221
|
-
|
222
|
-
# Fetch the original wrapped model.
|
223
|
-
#
|
224
|
-
# @return [Object] original_model
|
225
|
-
def wrapped_object
|
226
|
-
@model
|
227
|
-
end
|
228
|
-
|
229
|
-
# Delegates == to the decorated models
|
230
|
-
#
|
231
|
-
# @return [Boolean] true if other's model == self's model
|
232
|
-
def ==(other)
|
233
|
-
@model == (other.respond_to?(:model) ? other.model : other)
|
234
|
-
end
|
235
|
-
|
236
|
-
def kind_of?(klass)
|
237
|
-
super || model.kind_of?(klass)
|
238
|
-
end
|
239
|
-
alias :is_a? :kind_of?
|
240
|
-
|
241
|
-
def respond_to?(method, include_private = false)
|
242
|
-
super || (allow?(method) && model.respond_to?(method, include_private))
|
243
|
-
end
|
244
|
-
|
245
|
-
# We always want to delegate present, in case we decorate a nil object.
|
246
|
-
#
|
247
|
-
# I don't like the idea of decorating a nil object, but we'll deal with
|
248
|
-
# that later.
|
249
|
-
def present?
|
250
|
-
model.present?
|
251
|
-
end
|
252
|
-
|
253
|
-
def method_missing(method, *args, &block)
|
254
|
-
super unless allow?(method)
|
255
|
-
|
256
|
-
if model.respond_to?(method)
|
257
|
-
self.class.send :define_method, method do |*args, &blokk|
|
258
|
-
model.send method, *args, &blokk
|
259
|
-
end
|
260
|
-
|
261
|
-
send method, *args, &block
|
262
|
-
else
|
263
|
-
super
|
264
|
-
end
|
265
|
-
|
266
|
-
rescue NoMethodError => no_method_error
|
267
|
-
super if no_method_error.name == method
|
268
|
-
raise no_method_error
|
269
|
-
end
|
270
|
-
|
271
|
-
def self.method_missing(method, *args, &block)
|
272
|
-
if method.to_s.match(/^find_((all_|last_)?by_|or_(initialize|create)_by_).*/)
|
273
|
-
self.decorate(model_class.send(method, *args, &block), :context => args.dup.extract_options!)
|
274
|
-
else
|
275
|
-
model_class.send(method, *args, &block)
|
276
|
-
end
|
277
|
-
end
|
278
|
-
|
279
|
-
def self.respond_to?(method, include_private = false)
|
280
|
-
super || model_class.respond_to?(method)
|
281
|
-
end
|
282
|
-
|
283
|
-
def context
|
284
|
-
options.fetch(:context, {})
|
285
|
-
end
|
286
|
-
|
287
|
-
def context=(input)
|
288
|
-
options[:context] = input
|
289
|
-
end
|
290
|
-
|
291
|
-
def source
|
292
|
-
model
|
293
|
-
end
|
294
|
-
alias_method :to_source, :model
|
295
|
-
|
296
|
-
private
|
297
|
-
|
298
|
-
def allow?(method)
|
299
|
-
(allowed.empty? || allowed.include?(method)) && !denied.include?(method)
|
300
|
-
end
|
301
|
-
|
302
|
-
def find_association_reflection(association)
|
303
|
-
if model.class.respond_to?(:reflect_on_association)
|
304
|
-
model.class.reflect_on_association(association)
|
305
|
-
end
|
306
|
-
end
|
307
|
-
|
308
|
-
def decorated_associations
|
309
|
-
@decorated_associations ||= {}
|
310
|
-
end
|
311
|
-
end
|
312
|
-
end
|
@@ -1,90 +0,0 @@
|
|
1
|
-
require 'active_support/core_ext/object/blank'
|
2
|
-
module Draper
|
3
|
-
class DecoratedEnumerableProxy
|
4
|
-
include Enumerable
|
5
|
-
|
6
|
-
delegate :as_json, :collect, :map, :each, :[], :all?, :include?, :first, :last, :shift, :in_groups_of, :to => :decorated_collection
|
7
|
-
|
8
|
-
# Initialize a new collection decorator instance by passing in
|
9
|
-
# an instance of a collection. Pass in an optional
|
10
|
-
# context into the options hash is stored for later use.
|
11
|
-
#
|
12
|
-
#
|
13
|
-
# @param [Object] instances to wrap
|
14
|
-
# @param [Hash] options (optional)
|
15
|
-
# @option options [Class] :class The decorator class to use
|
16
|
-
# for each item in the collection.
|
17
|
-
# @option options all other options are passed to Decorator
|
18
|
-
# class for each item.
|
19
|
-
|
20
|
-
def self.decorate(collection, options = {})
|
21
|
-
new( collection, discern_class_from_my_class(options.delete(:class)), options)
|
22
|
-
end
|
23
|
-
class << self
|
24
|
-
alias_method :decorates, :decorate
|
25
|
-
end
|
26
|
-
|
27
|
-
def initialize(collection, klass, options = {})
|
28
|
-
@wrapped_collection, @klass, @options = collection, klass, options
|
29
|
-
end
|
30
|
-
|
31
|
-
def decorated_collection
|
32
|
-
@decorated_collection ||= @wrapped_collection.collect { |member| @klass.decorate(member, @options) }
|
33
|
-
end
|
34
|
-
alias_method :to_ary, :decorated_collection
|
35
|
-
|
36
|
-
def find(ifnone_or_id = nil, &blk)
|
37
|
-
if block_given?
|
38
|
-
source.find(ifnone_or_id, &blk)
|
39
|
-
else
|
40
|
-
obj = decorated_collection.first
|
41
|
-
return nil if obj.blank?
|
42
|
-
obj.class.find(ifnone_or_id)
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
def method_missing (method, *args, &block)
|
47
|
-
@wrapped_collection.send(method, *args, &block)
|
48
|
-
end
|
49
|
-
|
50
|
-
def respond_to?(method, include_private = false)
|
51
|
-
super || @wrapped_collection.respond_to?(method, include_private)
|
52
|
-
end
|
53
|
-
|
54
|
-
def kind_of?(klass)
|
55
|
-
@wrapped_collection.kind_of?(klass) || super
|
56
|
-
end
|
57
|
-
alias :is_a? :kind_of?
|
58
|
-
|
59
|
-
def ==(other)
|
60
|
-
@wrapped_collection == (other.respond_to?(:source) ? other.source : other)
|
61
|
-
end
|
62
|
-
|
63
|
-
def to_s
|
64
|
-
"#<DecoratedEnumerableProxy of #{@klass} for #{@wrapped_collection.inspect}>"
|
65
|
-
end
|
66
|
-
|
67
|
-
def context=(input)
|
68
|
-
self.map { |member| member.context = input }
|
69
|
-
end
|
70
|
-
|
71
|
-
def source
|
72
|
-
@wrapped_collection
|
73
|
-
end
|
74
|
-
alias_method :to_source, :source
|
75
|
-
|
76
|
-
def helpers
|
77
|
-
Draper::ViewContext.current
|
78
|
-
end
|
79
|
-
alias_method :h, :helpers
|
80
|
-
|
81
|
-
private
|
82
|
-
def self.discern_class_from_my_class default_class
|
83
|
-
return default_class if default_class
|
84
|
-
name = self.to_s.gsub("Decorator", "")
|
85
|
-
"#{name.singularize}Decorator".constantize
|
86
|
-
rescue NameError
|
87
|
-
raise NameError("You must supply a class (as the klass option) for the members of your collection or the class must be inferable from the name of this class ('#{new.class}')")
|
88
|
-
end
|
89
|
-
end
|
90
|
-
end
|
data/lib/draper/model_support.rb
DELETED
@@ -1,25 +0,0 @@
|
|
1
|
-
module Draper::ModelSupport
|
2
|
-
extend ActiveSupport::Concern
|
3
|
-
|
4
|
-
def decorator(options = {})
|
5
|
-
@decorator ||= decorator_class.decorate(self, options.merge(:infer => false))
|
6
|
-
block_given? ? yield(@decorator) : @decorator
|
7
|
-
end
|
8
|
-
|
9
|
-
def decorator_class
|
10
|
-
"#{self.class.name}Decorator".constantize
|
11
|
-
end
|
12
|
-
|
13
|
-
alias :decorate :decorator
|
14
|
-
|
15
|
-
module ClassMethods
|
16
|
-
def decorate(options = {})
|
17
|
-
decorator_proxy = decorator_class.decorate(self.scoped, options)
|
18
|
-
block_given? ? yield(decorator_proxy) : decorator_proxy
|
19
|
-
end
|
20
|
-
|
21
|
-
def decorator_class
|
22
|
-
"#{model_name}Decorator".constantize
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|