draper 3.0.0 → 3.0.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6f2c896cc71e7e4e654a5d65907dd0ec4cefed7f
4
- data.tar.gz: ce50051cf161e9416483a40797d38ae2d2da3384
3
+ metadata.gz: cc23ed0f81227aa958510ecb67676453d97b40cc
4
+ data.tar.gz: ed8a159772bafb7df87cc5c767757e8b697f55b3
5
5
  SHA512:
6
- metadata.gz: 527adb1c71ce28f23bb9be4186fe857c543a26edd8d20404f1e2a6db51e819143dd9c7973f7735746457c2a8a392e7a6d5b8a79232d26a1694035e09441a98f4
7
- data.tar.gz: 0ed34d19d3b0300ea733392aab2c4cceaa1b284efc71e84452331fea4c9c11c68c7dc00baa7802a864d60f69bfb42beb8f5cecf959ed5ebf01b8a24c7e676f3f
6
+ metadata.gz: 466c609e53461c1e1f260f9e2bf6a0eb522238e5bdae8a2f37a88c1cd22d22665bf18293ba497f9f64d27faa0e12f0dbb9e3d906bae569f324c6124c02ad6b7e
7
+ data.tar.gz: db229fe0cf5daf0acc2e52834c599a21e9ba85782458a8fd3a0520574e77f1857ec30c57c81dceb75561016170c941f8da3593d3a58fd395137c01ce57322cf0
@@ -1,9 +1,16 @@
1
1
  language: ruby
2
+ sudo: false
3
+ cache: bundler
2
4
 
3
5
  services:
4
6
  - mongodb
5
7
 
6
8
  rvm:
7
- - 2.2.6
8
- - 2.3.3
9
+ - 2.2.7
10
+ - 2.3.4
9
11
  - 2.4.1
12
+ - ruby-head
13
+
14
+ matrix:
15
+ allow_failures:
16
+ - rvm: ruby-head
@@ -1,5 +1,10 @@
1
1
  # Draper Changelog
2
2
 
3
+ ## 3.0.1
4
+ * Let `decorator_class` infer anonymous class decorator from superclass [#820](https://github.com/drapergem/draper/pull/820)
5
+ * When inferring decorator fails, show original class instead of `ActiveRecord::Base` [#821](https://github.com/drapergem/draper/pull/821)
6
+ * ActiveJob compatibility and documentation [#817](https://github.com/drapergem/draper/pull/817)
7
+
3
8
  ## 3.0.0 - 2017
4
9
 
5
10
  ### Breaking Changes
data/README.md CHANGED
@@ -618,6 +618,15 @@ is included in `ActiveRecord::Base` and `Mongoid::Document` by default. If
618
618
  you're using another ORM, or want to decorate plain old Ruby objects,
619
619
  you can include this module manually.
620
620
 
621
+ ### Active Job Integration
622
+
623
+ [Active Job](http://edgeguides.rubyonrails.org/active_job_basics.html) allows you to pass ActiveRecord
624
+ objects to background tasks directly and performs the necessary serialization and deserialization. In
625
+ order to do this, arguments to a background job must implement [Global ID](https://github.com/rails/globalid).
626
+ Decorated objects implement Global ID by delegating to the object they are decorating. This means
627
+ you can pass decorated objects to background jobs, however, the object won't be decorated when it is
628
+ deserialized.
629
+
621
630
  ## Contributors
622
631
 
623
632
  Draper was conceived by Jeff Casimir and heavily refined by Steve Klabnik and a
@@ -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
@@ -69,16 +69,16 @@ module Draper
69
69
  # `Product` maps to `ProductDecorator`).
70
70
  #
71
71
  # @return [Class] the inferred decorator class.
72
- def decorator_class
72
+ def decorator_class(called_on = self)
73
73
  prefix = respond_to?(:model_name) ? model_name : name
74
74
  decorator_name = "#{prefix}Decorator"
75
- decorator_name.constantize
76
- rescue NameError => error
77
- raise unless error.missing_name?(decorator_name)
75
+ decorator_name_constant = decorator_name.safe_constantize
76
+ return decorator_name_constant unless decorator_name_constant.nil?
77
+
78
78
  if superclass.respond_to?(:decorator_class)
79
- superclass.decorator_class
79
+ superclass.decorator_class(called_on)
80
80
  else
81
- raise Draper::UninferrableDecoratorError.new(self)
81
+ raise Draper::UninferrableDecoratorError.new(called_on)
82
82
  end
83
83
  end
84
84
 
@@ -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
@@ -222,9 +225,9 @@ module Draper
222
225
  # @return [Class] the class created by {decorate_collection}.
223
226
  def self.collection_decorator_class
224
227
  name = collection_decorator_name
225
- name.constantize
226
- rescue NameError
227
- Draper::CollectionDecorator
228
+ name_constant = name && name.safe_constantize
229
+
230
+ name_constant || Draper::CollectionDecorator
228
231
  end
229
232
 
230
233
  private
@@ -239,22 +242,23 @@ module Draper
239
242
  end
240
243
 
241
244
  def self.object_class_name
242
- raise NameError if name.nil? || name.demodulize !~ /.+Decorator$/
245
+ return nil if name.nil? || name.demodulize !~ /.+Decorator$/
243
246
  name.chomp("Decorator")
244
247
  end
245
248
 
246
249
  def self.inferred_object_class
247
250
  name = object_class_name
248
- name.constantize
249
- rescue NameError => error
250
- raise if name && !error.missing_name?(name)
251
+ name_constant = name && name.safe_constantize
252
+ return name_constant unless name_constant.nil?
253
+
251
254
  raise Draper::UninferrableObjectError.new(self)
252
255
  end
253
256
 
254
257
  def self.collection_decorator_name
255
- plural = object_class_name.pluralize
256
- raise NameError if plural == object_class_name
257
- "#{plural}Decorator"
258
+ singular = object_class_name
259
+ plural = singular && singular.pluralize
260
+
261
+ "#{plural}Decorator" unless plural == singular
258
262
  end
259
263
 
260
264
  def handle_multiple_decoration(options)
@@ -1,3 +1,3 @@
1
1
  module Draper
2
- VERSION = '3.0.0'
2
+ VERSION = '3.0.1'
3
3
  end
@@ -1,7 +1,7 @@
1
1
  module Draper
2
2
  module Generators
3
3
  class InstallGenerator < Rails::Generators::Base
4
- source_root File.expand_path('../templates', __FILE__)
4
+ source_root File.expand_path("templates", __dir__)
5
5
 
6
6
  desc 'Creates an ApplicationDecorator, if none exists.'
7
7
 
@@ -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('../templates', __FILE__)
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("../templates", __FILE__)
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
- class DecoratorGenerator < ::Rails::Generators::NamedBase
3
- source_root File.expand_path('../templates', __FILE__)
2
+ module Generators
3
+ class DecoratorGenerator < ::Rails::Generators::NamedBase
4
+ source_root File.expand_path("templates", __dir__)
4
5
 
5
- def create_spec_file
6
- template 'decorator_spec.rb', File.join('spec/decorators', class_path, "#{singular_name}_decorator_spec.rb")
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
@@ -1,9 +1,12 @@
1
1
  module TestUnit
2
- class DecoratorGenerator < ::Rails::Generators::NamedBase
3
- source_root File.expand_path('../templates', __FILE__)
2
+ module Generators
3
+ class DecoratorGenerator < ::Rails::Generators::NamedBase
4
+ source_root File.expand_path("templates", __dir__)
5
+ check_class_collision suffix: "DecoratorTest"
4
6
 
5
- def create_test_file
6
- template 'decorator_test.rb', File.join('test/decorators', class_path, "#{singular_name}_decorator_test.rb")
7
+ def create_test_file
8
+ template 'decorator_test.rb', File.join('test/decorators', class_path, "#{singular_name}_decorator_test.rb")
9
+ end
7
10
  end
8
11
  end
9
12
  end
@@ -73,6 +73,16 @@ module Draper
73
73
  expect(Product).to receive(:decorator_class).and_return(:some_decorator)
74
74
  expect(product.decorator_class).to be :some_decorator
75
75
  end
76
+
77
+ it "specifies the class that #decorator_class was first called on (superclass)" do
78
+ person = Person.new
79
+ expect { person.decorator_class }.to raise_error(Draper::UninferrableDecoratorError, 'Could not infer a decorator for Person.')
80
+ end
81
+
82
+ it "specifies the class that #decorator_class was first called on (subclass)" do
83
+ child = Child.new
84
+ expect { child.decorator_class }.to raise_error(Draper::UninferrableDecoratorError, 'Could not infer a decorator for Child.')
85
+ end
76
86
  end
77
87
 
78
88
  describe "#==" do
@@ -205,10 +215,22 @@ module Draper
205
215
 
206
216
  context "when an unrelated NameError is thrown" do
207
217
  it "re-raises that error" do
208
- allow_any_instance_of(String).to receive(:constantize) { Draper::Base }
218
+ # Not related to safe_constantize behavior, we just want to raise a NameError inside the function
219
+ allow_any_instance_of(String).to receive(:safe_constantize) { Draper::Base }
209
220
  expect{Product.decorator_class}.to raise_error NameError, /Draper::Base/
210
221
  end
211
222
  end
223
+
224
+ context "when an anonymous class is given" do
225
+ it "infers the decorator from a superclass" do
226
+ anonymous_class = Class.new(Product) do
227
+ def self.name
228
+ to_s
229
+ end
230
+ end
231
+ expect(anonymous_class.decorator_class).to be ProductDecorator
232
+ end
233
+ end
212
234
  end
213
235
 
214
236
  end
@@ -202,7 +202,8 @@ module Draper
202
202
 
203
203
  context "when an unrelated NameError is thrown" do
204
204
  it "re-raises that error" do
205
- allow_any_instance_of(String).to receive(:constantize) { SomethingThatDoesntExist }
205
+ # Not related to safe_constantize behavior, we just want to raise a NameError inside the function
206
+ allow_any_instance_of(String).to receive(:safe_constantize) { SomethingThatDoesntExist }
206
207
  expect{ProductDecorator.object_class}.to raise_error NameError, /SomethingThatDoesntExist/
207
208
  end
208
209
  end
@@ -225,7 +226,7 @@ module Draper
225
226
 
226
227
  describe '.collection_decorator_class' do
227
228
  it 'defaults to CollectionDecorator' do
228
- allow_any_instance_of(String).to receive(:constantize) { SomethingThatDoesntExist }
229
+ allow_any_instance_of(String).to receive(:safe_constantize) { nil }
229
230
  expect(ProductDecorator.collection_decorator_class).to be Draper::CollectionDecorator
230
231
  end
231
232
 
@@ -0,0 +1,7 @@
1
+ class PublishPostJob < ActiveJob::Base
2
+ queue_as :default
3
+
4
+ def perform(post)
5
+ post.save!
6
+ end
7
+ end
@@ -0,0 +1,3 @@
1
+ class ApplicationRecord < ActiveRecord::Base
2
+ self.abstract_class = true
3
+ end
@@ -1,3 +1,3 @@
1
- class Post < ActiveRecord::Base
1
+ class Post < ApplicationRecord
2
2
  # attr_accessible :title, :body
3
3
  end
@@ -38,9 +38,6 @@ module Dummy
38
38
  # Configure the default encoding used in templates for Ruby 1.9.
39
39
  config.encoding = "utf-8"
40
40
 
41
- # Configure sensitive parameters which will be filtered from the log file.
42
- config.filter_parameters += [:password]
43
-
44
41
  # Enable escaping HTML in JSON.
45
42
  config.active_support.escape_html_entities_in_json = true
46
43
 
@@ -28,4 +28,6 @@ Dummy::Application.configure do
28
28
  config.active_support.deprecation = :stderr
29
29
 
30
30
  config.eager_load = false
31
+
32
+ config.active_job.queue_adapter = :test
31
33
  end
@@ -0,0 +1,4 @@
1
+ # Be sure to restart your server when you modify this file.
2
+
3
+ # Configure sensitive parameters which will be filtered from the log file.
4
+ Rails.application.config.filter_parameters += [:password]
@@ -1,4 +1,4 @@
1
- class CreatePosts < ActiveRecord::Migration
1
+ class CreatePosts < ActiveRecord::Migration[4.2]
2
2
  def change
3
3
  create_table :posts do |t|
4
4
 
@@ -0,0 +1,9 @@
1
+ RSpec.describe PublishPostJob, type: :job do
2
+ let(:post) { Post.create.decorate }
3
+
4
+ subject(:job) { described_class.perform_later(post) }
5
+
6
+ it 'queues the job' do
7
+ expect { job }.to have_enqueued_job(described_class).with(post.object)
8
+ end
9
+ end
@@ -0,0 +1,7 @@
1
+ require 'spec_helper'
2
+
3
+ describe ApplicationRecord do
4
+ it { expect(described_class.superclass).to eq ActiveRecord::Base }
5
+
6
+ it { expect(described_class.abstract_class).to be_truthy }
7
+ end
@@ -1,6 +1,15 @@
1
1
  require 'spec_helper'
2
2
  require 'shared_examples/decoratable'
3
3
 
4
- describe Post do
5
- it_behaves_like "a decoratable model"
4
+ RSpec.describe Post do
5
+ it_behaves_like 'a decoratable model'
6
+
7
+ it { should be_a ApplicationRecord }
8
+
9
+ describe '#to_global_id' do
10
+ let(:post) { Post.create }
11
+ subject { post.to_global_id }
12
+
13
+ it { is_expected.to eq post.decorate.to_global_id }
14
+ end
6
15
  end
@@ -16,6 +16,8 @@ class Model; include Draper::Decoratable; end
16
16
  class Product < Model; end
17
17
  class SpecialProduct < Product; end
18
18
  class Other < Model; end
19
+ class Person < Model; end
20
+ class Child < Person; end
19
21
  class ProductDecorator < Draper::Decorator; end
20
22
  class ProductsDecorator < Draper::CollectionDecorator; end
21
23
 
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: 3.0.0
4
+ version: 3.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeff Casimir
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2017-05-08 00:00:00.000000000 Z
12
+ date: 2017-10-12 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport
@@ -207,6 +207,7 @@ files:
207
207
  - lib/draper/automatic_delegation.rb
208
208
  - lib/draper/collection_decorator.rb
209
209
  - lib/draper/compatibility/api_only.rb
210
+ - lib/draper/compatibility/global_id.rb
210
211
  - lib/draper/configuration.rb
211
212
  - lib/draper/decoratable.rb
212
213
  - lib/draper/decoratable/equality.rb
@@ -267,9 +268,11 @@ files:
267
268
  - spec/dummy/app/decorators/mongoid_post_decorator.rb
268
269
  - spec/dummy/app/decorators/post_decorator.rb
269
270
  - spec/dummy/app/helpers/application_helper.rb
271
+ - spec/dummy/app/jobs/publish_post_job.rb
270
272
  - spec/dummy/app/mailers/application_mailer.rb
271
273
  - spec/dummy/app/mailers/post_mailer.rb
272
274
  - spec/dummy/app/models/admin.rb
275
+ - spec/dummy/app/models/application_record.rb
273
276
  - spec/dummy/app/models/mongoid_post.rb
274
277
  - spec/dummy/app/models/post.rb
275
278
  - spec/dummy/app/models/user.rb
@@ -288,6 +291,7 @@ files:
288
291
  - spec/dummy/config/environments/test.rb
289
292
  - spec/dummy/config/initializers/backtrace_silencers.rb
290
293
  - spec/dummy/config/initializers/draper.rb
294
+ - spec/dummy/config/initializers/filter_parameter_logging.rb
291
295
  - spec/dummy/config/initializers/inflections.rb
292
296
  - spec/dummy/config/initializers/mime_types.rb
293
297
  - spec/dummy/config/initializers/secret_token.rb
@@ -312,7 +316,9 @@ files:
312
316
  - spec/dummy/spec/decorators/post_decorator_spec.rb
313
317
  - spec/dummy/spec/decorators/spec_type_spec.rb
314
318
  - spec/dummy/spec/decorators/view_context_spec.rb
319
+ - spec/dummy/spec/jobs/publish_post_job_spec.rb
315
320
  - spec/dummy/spec/mailers/post_mailer_spec.rb
321
+ - spec/dummy/spec/models/application_spec.rb
316
322
  - spec/dummy/spec/models/mongoid_post_spec.rb
317
323
  - spec/dummy/spec/models/post_spec.rb
318
324
  - spec/dummy/spec/shared_examples/decoratable.rb
@@ -389,9 +395,11 @@ test_files:
389
395
  - spec/dummy/app/decorators/mongoid_post_decorator.rb
390
396
  - spec/dummy/app/decorators/post_decorator.rb
391
397
  - spec/dummy/app/helpers/application_helper.rb
398
+ - spec/dummy/app/jobs/publish_post_job.rb
392
399
  - spec/dummy/app/mailers/application_mailer.rb
393
400
  - spec/dummy/app/mailers/post_mailer.rb
394
401
  - spec/dummy/app/models/admin.rb
402
+ - spec/dummy/app/models/application_record.rb
395
403
  - spec/dummy/app/models/mongoid_post.rb
396
404
  - spec/dummy/app/models/post.rb
397
405
  - spec/dummy/app/models/user.rb
@@ -410,6 +418,7 @@ test_files:
410
418
  - spec/dummy/config/environments/test.rb
411
419
  - spec/dummy/config/initializers/backtrace_silencers.rb
412
420
  - spec/dummy/config/initializers/draper.rb
421
+ - spec/dummy/config/initializers/filter_parameter_logging.rb
413
422
  - spec/dummy/config/initializers/inflections.rb
414
423
  - spec/dummy/config/initializers/mime_types.rb
415
424
  - spec/dummy/config/initializers/secret_token.rb
@@ -434,7 +443,9 @@ test_files:
434
443
  - spec/dummy/spec/decorators/post_decorator_spec.rb
435
444
  - spec/dummy/spec/decorators/spec_type_spec.rb
436
445
  - spec/dummy/spec/decorators/view_context_spec.rb
446
+ - spec/dummy/spec/jobs/publish_post_job_spec.rb
437
447
  - spec/dummy/spec/mailers/post_mailer_spec.rb
448
+ - spec/dummy/spec/models/application_spec.rb
438
449
  - spec/dummy/spec/models/mongoid_post_spec.rb
439
450
  - spec/dummy/spec/models/post_spec.rb
440
451
  - spec/dummy/spec/shared_examples/decoratable.rb