draper 0.18.0 → 1.0.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|