draper 3.0.0 → 4.0.2
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.
- checksums.yaml +5 -5
- data/.github/workflows/ci.yml +55 -0
- data/CHANGELOG.md +46 -0
- data/Gemfile +11 -2
- data/README.md +43 -5
- data/bin/bundle +114 -0
- data/bin/rake +29 -0
- data/draper.gemspec +9 -8
- data/lib/draper.rb +3 -0
- data/lib/draper/automatic_delegation.rb +4 -2
- data/lib/draper/collection_decorator.rb +4 -2
- data/lib/draper/compatibility/global_id.rb +22 -0
- data/lib/draper/configuration.rb +8 -0
- data/lib/draper/decoratable.rb +6 -7
- data/lib/draper/decorated_association.rb +0 -2
- data/lib/draper/decorator.rb +19 -13
- data/lib/draper/delegation.rb +1 -1
- data/lib/draper/finders.rb +0 -1
- data/lib/draper/helper_proxy.rb +2 -2
- data/lib/draper/lazy_helpers.rb +1 -3
- data/lib/draper/query_methods.rb +23 -0
- data/lib/draper/query_methods/load_strategy.rb +21 -0
- data/lib/draper/test_case.rb +3 -3
- data/lib/draper/undecorate.rb +1 -1
- data/lib/draper/version.rb +1 -1
- data/lib/draper/view_context/build_strategy.rb +1 -3
- data/lib/draper/view_helpers.rb +5 -5
- data/lib/generators/draper/install_generator.rb +1 -1
- data/lib/generators/mini_test/decorator_generator.rb +1 -1
- data/lib/generators/rails/decorator_generator.rb +1 -1
- data/lib/generators/rspec/decorator_generator.rb +6 -4
- data/lib/generators/test_unit/decorator_generator.rb +7 -4
- data/spec/draper/collection_decorator_spec.rb +5 -6
- data/spec/draper/configuration_spec.rb +32 -8
- data/spec/draper/decoratable_spec.rb +24 -4
- data/spec/draper/decorated_association_spec.rb +0 -2
- data/spec/draper/decorator_spec.rb +36 -3
- data/spec/draper/draper_spec.rb +1 -0
- data/spec/draper/factory_spec.rb +0 -4
- data/spec/draper/query_methods/load_strategy_spec.rb +26 -0
- data/spec/draper/query_methods_spec.rb +70 -0
- data/spec/dummy/app/assets/config/manifest.js +3 -0
- data/spec/dummy/app/controllers/application_controller.rb +2 -0
- data/spec/dummy/app/jobs/publish_post_job.rb +7 -0
- data/spec/dummy/app/models/application_record.rb +3 -0
- data/spec/dummy/app/models/post.rb +1 -1
- data/spec/dummy/config/application.rb +0 -3
- data/spec/dummy/config/environments/development.rb +2 -0
- data/spec/dummy/config/environments/production.rb +2 -0
- data/spec/dummy/config/environments/test.rb +4 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/dummy/config/storage.yml +7 -0
- data/spec/dummy/db/migrate/20121019115657_create_posts.rb +1 -1
- data/spec/dummy/spec/jobs/publish_post_job_spec.rb +9 -0
- data/spec/dummy/spec/models/application_spec.rb +7 -0
- data/spec/dummy/spec/models/post_spec.rb +11 -2
- data/spec/generators/controller/controller_generator_spec.rb +1 -0
- data/spec/generators/decorator/decorator_generator_spec.rb +1 -1
- data/spec/integration/integration_spec.rb +1 -0
- data/spec/spec_helper.rb +9 -0
- metadata +72 -20
- data/.travis.yml +0 -9
@@ -2,6 +2,7 @@ module Draper
|
|
2
2
|
class CollectionDecorator
|
3
3
|
include Enumerable
|
4
4
|
include Draper::ViewHelpers
|
5
|
+
include Draper::QueryMethods
|
5
6
|
extend Draper::Delegation
|
6
7
|
|
7
8
|
# @return the collection being decorated.
|
@@ -34,7 +35,7 @@ module Draper
|
|
34
35
|
end
|
35
36
|
|
36
37
|
class << self
|
37
|
-
|
38
|
+
alias :decorate :new
|
38
39
|
end
|
39
40
|
|
40
41
|
# @return [Array] the decorated items.
|
@@ -58,11 +59,12 @@ module Draper
|
|
58
59
|
true
|
59
60
|
end
|
60
61
|
|
61
|
-
|
62
|
+
alias :decorated_with? :instance_of?
|
62
63
|
|
63
64
|
def kind_of?(klass)
|
64
65
|
decorated_collection.kind_of?(klass) || super
|
65
66
|
end
|
67
|
+
|
66
68
|
alias_method :is_a?, :kind_of?
|
67
69
|
|
68
70
|
def replace(other)
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Draper
|
2
|
+
module Compatibility
|
3
|
+
# [Active Job](http://edgeguides.rubyonrails.org/active_job_basics.html) allows you to pass
|
4
|
+
# ActiveRecord objects to background tasks directly and performs the necessary serialization
|
5
|
+
# and deserialization. In order to do this, arguments to a background job must implement
|
6
|
+
# [Global ID](https://github.com/rails/globalid).
|
7
|
+
#
|
8
|
+
# This compatibility patch implements Global ID for decorated objects by delegating to the object
|
9
|
+
# that is decorated. This means you can pass decorated objects to background jobs, but
|
10
|
+
# the object won't be decorated when it is deserialized. This patch is meant as an intermediate
|
11
|
+
# fix until we can find a way to deserialize the decorated object correctly.
|
12
|
+
module GlobalID
|
13
|
+
extend ActiveSupport::Concern
|
14
|
+
|
15
|
+
included do
|
16
|
+
include ::GlobalID::Identification
|
17
|
+
|
18
|
+
delegate :to_global_id, :to_signed_global_id, to: :object
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/lib/draper/configuration.rb
CHANGED
@@ -11,5 +11,13 @@ module Draper
|
|
11
11
|
def default_controller=(controller)
|
12
12
|
@@default_controller = controller
|
13
13
|
end
|
14
|
+
|
15
|
+
def default_query_methods_strategy
|
16
|
+
@@default_query_methods_strategy ||= :active_record
|
17
|
+
end
|
18
|
+
|
19
|
+
def default_query_methods_strategy=(strategy)
|
20
|
+
@@default_query_methods_strategy = strategy
|
21
|
+
end
|
14
22
|
end
|
15
23
|
end
|
data/lib/draper/decoratable.rb
CHANGED
@@ -48,7 +48,6 @@ module Draper
|
|
48
48
|
end
|
49
49
|
|
50
50
|
module ClassMethods
|
51
|
-
|
52
51
|
# Decorates a collection of objects. Used at the end of a scope chain.
|
53
52
|
#
|
54
53
|
# @example
|
@@ -69,16 +68,16 @@ module Draper
|
|
69
68
|
# `Product` maps to `ProductDecorator`).
|
70
69
|
#
|
71
70
|
# @return [Class] the inferred decorator class.
|
72
|
-
def decorator_class
|
71
|
+
def decorator_class(called_on = self)
|
73
72
|
prefix = respond_to?(:model_name) ? model_name : name
|
74
73
|
decorator_name = "#{prefix}Decorator"
|
75
|
-
decorator_name.
|
76
|
-
|
77
|
-
|
74
|
+
decorator_name_constant = decorator_name.safe_constantize
|
75
|
+
return decorator_name_constant unless decorator_name_constant.nil?
|
76
|
+
|
78
77
|
if superclass.respond_to?(:decorator_class)
|
79
|
-
superclass.decorator_class
|
78
|
+
superclass.decorator_class(called_on)
|
80
79
|
else
|
81
|
-
raise Draper::UninferrableDecoratorError.new(
|
80
|
+
raise Draper::UninferrableDecoratorError.new(called_on)
|
82
81
|
end
|
83
82
|
end
|
84
83
|
|
@@ -1,7 +1,6 @@
|
|
1
1
|
module Draper
|
2
2
|
# @private
|
3
3
|
class DecoratedAssociation
|
4
|
-
|
5
4
|
def initialize(owner, association, options)
|
6
5
|
options.assert_valid_keys(:with, :scope, :context)
|
7
6
|
|
@@ -30,6 +29,5 @@ module Draper
|
|
30
29
|
|
31
30
|
@decorated = factory.decorate(associated, context_args: owner.context)
|
32
31
|
end
|
33
|
-
|
34
32
|
end
|
35
33
|
end
|
data/lib/draper/decorator.rb
CHANGED
@@ -1,6 +1,9 @@
|
|
1
|
+
require 'draper/compatibility/global_id'
|
2
|
+
|
1
3
|
module Draper
|
2
4
|
class Decorator
|
3
5
|
include Draper::ViewHelpers
|
6
|
+
include Draper::Compatibility::GlobalID if defined?(GlobalID)
|
4
7
|
extend Draper::Delegation
|
5
8
|
|
6
9
|
include ActiveModel::Serialization
|
@@ -9,7 +12,8 @@ module Draper
|
|
9
12
|
|
10
13
|
# @return the object being decorated.
|
11
14
|
attr_reader :object
|
12
|
-
|
15
|
+
|
16
|
+
alias :model :object
|
13
17
|
|
14
18
|
# @return [Hash] extra data to be used in user-defined methods.
|
15
19
|
attr_accessor :context
|
@@ -33,7 +37,7 @@ module Draper
|
|
33
37
|
end
|
34
38
|
|
35
39
|
class << self
|
36
|
-
|
40
|
+
alias :decorate :new
|
37
41
|
end
|
38
42
|
|
39
43
|
# Automatically delegates instance methods to the source object. Class
|
@@ -187,7 +191,8 @@ module Draper
|
|
187
191
|
def kind_of?(klass)
|
188
192
|
super || object.kind_of?(klass)
|
189
193
|
end
|
190
|
-
|
194
|
+
|
195
|
+
alias :is_a? :kind_of?
|
191
196
|
|
192
197
|
# Checks if `self.instance_of?(klass)` or `object.instance_of?(klass)`
|
193
198
|
#
|
@@ -222,9 +227,9 @@ module Draper
|
|
222
227
|
# @return [Class] the class created by {decorate_collection}.
|
223
228
|
def self.collection_decorator_class
|
224
229
|
name = collection_decorator_name
|
225
|
-
name
|
226
|
-
|
227
|
-
Draper::CollectionDecorator
|
230
|
+
name_constant = name&.safe_constantize
|
231
|
+
|
232
|
+
name_constant || Draper::CollectionDecorator
|
228
233
|
end
|
229
234
|
|
230
235
|
private
|
@@ -239,22 +244,23 @@ module Draper
|
|
239
244
|
end
|
240
245
|
|
241
246
|
def self.object_class_name
|
242
|
-
|
247
|
+
return nil if name.nil? || name.demodulize !~ /.+Decorator$/
|
243
248
|
name.chomp("Decorator")
|
244
249
|
end
|
245
250
|
|
246
251
|
def self.inferred_object_class
|
247
252
|
name = object_class_name
|
248
|
-
name
|
249
|
-
|
250
|
-
|
253
|
+
name_constant = name&.safe_constantize
|
254
|
+
return name_constant unless name_constant.nil?
|
255
|
+
|
251
256
|
raise Draper::UninferrableObjectError.new(self)
|
252
257
|
end
|
253
258
|
|
254
259
|
def self.collection_decorator_name
|
255
|
-
|
256
|
-
|
257
|
-
|
260
|
+
singular = object_class_name
|
261
|
+
plural = singular&.pluralize
|
262
|
+
|
263
|
+
"#{plural}Decorator" unless plural == singular
|
258
264
|
end
|
259
265
|
|
260
266
|
def handle_multiple_decoration(options)
|
data/lib/draper/delegation.rb
CHANGED
data/lib/draper/finders.rb
CHANGED
data/lib/draper/helper_proxy.rb
CHANGED
@@ -2,14 +2,13 @@ module Draper
|
|
2
2
|
# Provides access to helper methods - both Rails built-in helpers, and those
|
3
3
|
# defined in your application.
|
4
4
|
class HelperProxy
|
5
|
-
|
6
5
|
# @overload initialize(view_context)
|
7
6
|
def initialize(view_context)
|
8
7
|
@view_context = view_context
|
9
8
|
end
|
10
9
|
|
11
10
|
# Sends helper methods to the view context.
|
12
|
-
def method_missing(method, *args, &block)
|
11
|
+
ruby2_keywords def method_missing(method, *args, &block)
|
13
12
|
self.class.define_proxy method
|
14
13
|
send(method, *args, &block)
|
15
14
|
end
|
@@ -32,6 +31,7 @@ module Draper
|
|
32
31
|
define_method name do |*args, &block|
|
33
32
|
view_context.send(name, *args, &block)
|
34
33
|
end
|
34
|
+
ruby2_keywords name
|
35
35
|
end
|
36
36
|
end
|
37
37
|
end
|
data/lib/draper/lazy_helpers.rb
CHANGED
@@ -3,13 +3,11 @@ module Draper
|
|
3
3
|
# so that you can stop typing `h.` everywhere, at the cost of mixing in a
|
4
4
|
# bazillion methods.
|
5
5
|
module LazyHelpers
|
6
|
-
|
7
6
|
# Sends missing methods to the {HelperProxy}.
|
8
|
-
def method_missing(method, *args, &block)
|
7
|
+
ruby2_keywords def method_missing(method, *args, &block)
|
9
8
|
helpers.send(method, *args, &block)
|
10
9
|
rescue NoMethodError
|
11
10
|
super
|
12
11
|
end
|
13
|
-
|
14
12
|
end
|
15
13
|
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require_relative 'query_methods/load_strategy'
|
2
|
+
|
3
|
+
module Draper
|
4
|
+
module QueryMethods
|
5
|
+
# Proxies missing query methods to the source class if the strategy allows.
|
6
|
+
ruby2_keywords def method_missing(method, *args, &block)
|
7
|
+
return super unless strategy.allowed? method
|
8
|
+
|
9
|
+
object.send(method, *args, &block).decorate(with: decorator_class, context: context)
|
10
|
+
end
|
11
|
+
|
12
|
+
def respond_to_missing?(method, include_private = false)
|
13
|
+
strategy.allowed?(method) || super
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
# Configures the strategy used to proxy the query methods, which defaults to `:active_record`.
|
19
|
+
def strategy
|
20
|
+
@strategy ||= LoadStrategy.new(Draper.default_query_methods_strategy)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Draper
|
2
|
+
module QueryMethods
|
3
|
+
module LoadStrategy
|
4
|
+
def self.new(name)
|
5
|
+
const_get(name.to_s.camelize).new
|
6
|
+
end
|
7
|
+
|
8
|
+
class ActiveRecord
|
9
|
+
def allowed?(method)
|
10
|
+
::ActiveRecord::Relation::VALUE_METHODS.include? method
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class Mongoid
|
15
|
+
def allowed?(method)
|
16
|
+
raise NotImplementedError
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/draper/test_case.rb
CHANGED
@@ -3,9 +3,9 @@ module Draper
|
|
3
3
|
|
4
4
|
class TestCase < ::ActiveSupport::TestCase
|
5
5
|
module ViewContextTeardown
|
6
|
-
def
|
7
|
-
super
|
6
|
+
def before_setup
|
8
7
|
Draper::ViewContext.clear!
|
8
|
+
super
|
9
9
|
end
|
10
10
|
end
|
11
11
|
|
@@ -21,7 +21,7 @@ module Draper
|
|
21
21
|
end
|
22
22
|
|
23
23
|
include Draper::ViewHelpers::ClassMethods
|
24
|
-
|
24
|
+
alias :helper :helpers
|
25
25
|
end
|
26
26
|
|
27
27
|
include Behavior
|
data/lib/draper/undecorate.rb
CHANGED
data/lib/draper/version.rb
CHANGED
@@ -2,7 +2,6 @@ module Draper
|
|
2
2
|
module ViewContext
|
3
3
|
# @private
|
4
4
|
module BuildStrategy
|
5
|
-
|
6
5
|
def self.new(name, &block)
|
7
6
|
const_get(name.to_s.camelize).new(&block)
|
8
7
|
end
|
@@ -13,7 +12,7 @@ module Draper
|
|
13
12
|
end
|
14
13
|
|
15
14
|
def call
|
16
|
-
view_context_class.new
|
15
|
+
view_context_class.respond_to?(:empty) ? view_context_class.empty : view_context_class.new
|
17
16
|
end
|
18
17
|
|
19
18
|
private
|
@@ -51,7 +50,6 @@ module Draper
|
|
51
50
|
ActionController::TestRequest.method(:create).parameters.first == [:req, :controller_class]
|
52
51
|
end
|
53
52
|
end
|
54
|
-
|
55
53
|
end
|
56
54
|
end
|
57
55
|
end
|
data/lib/draper/view_helpers.rb
CHANGED
@@ -5,7 +5,6 @@ module Draper
|
|
5
5
|
extend ActiveSupport::Concern
|
6
6
|
|
7
7
|
module ClassMethods
|
8
|
-
|
9
8
|
# Access the helpers proxy to call built-in and user-defined
|
10
9
|
# Rails helpers from a class context.
|
11
10
|
#
|
@@ -13,8 +12,8 @@ module Draper
|
|
13
12
|
def helpers
|
14
13
|
Draper::ViewContext.current
|
15
14
|
end
|
16
|
-
alias_method :h, :helpers
|
17
15
|
|
16
|
+
alias :h :helpers
|
18
17
|
end
|
19
18
|
|
20
19
|
# Access the helpers proxy to call built-in and user-defined
|
@@ -24,14 +23,15 @@ module Draper
|
|
24
23
|
def helpers
|
25
24
|
Draper::ViewContext.current
|
26
25
|
end
|
27
|
-
|
26
|
+
|
27
|
+
alias :h :helpers
|
28
28
|
|
29
29
|
# Alias for `helpers.localize`, since localize is something that's used
|
30
30
|
# quite often. Further aliased to `l` for convenience.
|
31
|
-
def localize(*args)
|
31
|
+
ruby2_keywords def localize(*args)
|
32
32
|
helpers.localize(*args)
|
33
33
|
end
|
34
|
-
alias_method :l, :localize
|
35
34
|
|
35
|
+
alias :l :localize
|
36
36
|
end
|
37
37
|
end
|
@@ -4,7 +4,7 @@ module MiniTest
|
|
4
4
|
module Generators
|
5
5
|
class DecoratorGenerator < Base
|
6
6
|
def self.source_root
|
7
|
-
File.expand_path(
|
7
|
+
File.expand_path("templates", __dir__)
|
8
8
|
end
|
9
9
|
|
10
10
|
class_option :spec, type: :boolean, default: false, desc: "Use MiniTest::Spec DSL"
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module Rails
|
2
2
|
module Generators
|
3
3
|
class DecoratorGenerator < NamedBase
|
4
|
-
source_root File.expand_path("
|
4
|
+
source_root File.expand_path("templates", __dir__)
|
5
5
|
check_class_collision suffix: "Decorator"
|
6
6
|
|
7
7
|
class_option :parent, type: :string, desc: "The parent class for the generated decorator"
|
@@ -1,9 +1,11 @@
|
|
1
1
|
module Rspec
|
2
|
-
|
3
|
-
|
2
|
+
module Generators
|
3
|
+
class DecoratorGenerator < ::Rails::Generators::NamedBase
|
4
|
+
source_root File.expand_path("templates", __dir__)
|
4
5
|
|
5
|
-
|
6
|
-
|
6
|
+
def create_spec_file
|
7
|
+
template 'decorator_spec.rb', File.join('spec/decorators', class_path, "#{singular_name}_decorator_spec.rb")
|
8
|
+
end
|
7
9
|
end
|
8
10
|
end
|
9
11
|
end
|