draper 3.1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c323d66ea5eafcb8aac1d70bdbf02335a7460939bf6dc24a801a37a7c75f6691
4
- data.tar.gz: ebd93feddfba45e9c1596b320278bc3ae0886579dbfc6637f7025a6df6e3994c
3
+ metadata.gz: 6b009279cf28737a6fcf4027fc26f3dc2a955741c7c5e5d2220c8dcb383490e3
4
+ data.tar.gz: 22455a3a7126650483af269d6a0e432a5a4465a59c762518ce78f40bcecb4286
5
5
  SHA512:
6
- metadata.gz: 5977d38ab1436a7dd00cb9e6e8854abdd78d2d21e2a15c00d1b40dade4490909a5d66c73fe64cbea610074096d7ece893fc70b16403fa9090b5de62a2eed2ff6
7
- data.tar.gz: b1d4f7faf5afafc5b4820b30bb8f2650fe8c8f936fdde22aedc3198d6b6c21d3299f067da23d96f23a835081bdbef2d71263725f72dce843723f14be3e7216f8
6
+ metadata.gz: 2fd6c0b87227c23320e9ee211b4b2001c81cbf76d103a12e5076f427954febdb2d0366d5182f16b27f5155717ad878f08671098f8b1f9986c137ec053e1637bf
7
+ data.tar.gz: 260d4eccd57c623c966422cd256ab1485e1ce4bbaea05d2c6f615cdb644ab0147f00e8917b8165eba78651f279b66cde0a13da38b1c5cc9dc6a0e49822db2361
@@ -0,0 +1,55 @@
1
+ ---
2
+ name: CI
3
+
4
+ on:
5
+ - push
6
+ - pull_request
7
+
8
+ jobs:
9
+ rspec:
10
+ runs-on: ubuntu-20.04
11
+ strategy:
12
+ fail-fast: false
13
+ matrix:
14
+ ruby:
15
+ - '3.0'
16
+ - '2.7'
17
+ - '2.6'
18
+ - '2.5'
19
+ - '2.4'
20
+
21
+ services:
22
+ mongodb:
23
+ image: mongo
24
+ ports:
25
+ - 27017:27017
26
+
27
+ steps:
28
+ - name: Checkout
29
+ uses: actions/checkout@v2
30
+
31
+ - name: Setup Ruby
32
+ uses: ruby/setup-ruby@v1
33
+ with:
34
+ ruby-version: ${{ matrix.ruby }}
35
+
36
+ - name: Setup Ruby cache
37
+ uses: actions/cache@v2
38
+ with:
39
+ path: vendor/bundle
40
+ key: ${{ runner.os }}-gems-${{ matrix.ruby }}-${{ hashFiles('**/Gemfile.lock') }}
41
+ restore-keys: |
42
+ ${{ runner.os }}-gems-${{ matrix.ruby }}-
43
+
44
+ - name: Bundle
45
+ run: |
46
+ gem install bundler
47
+ bundle config path vendor/bundle
48
+ bundle install --jobs 4 --retry 3
49
+
50
+ - name: RSpec & publish code coverage
51
+ uses: paambaati/codeclimate-action@v2.7.5
52
+ env:
53
+ CC_TEST_REPORTER_ID: b7ba588af2a540fa96c267b3655a2afe31ea29976dc25905a668dd28d5e88915
54
+ with:
55
+ coverageCommand: bin/rake
data/CHANGELOG.md CHANGED
@@ -1,5 +1,41 @@
1
1
  # Draper Changelog
2
2
 
3
+ ## 4.0.2 - 2021-05-27
4
+
5
+ ### Fixes
6
+ * Fix kwargs usage for Ruby 3 compatibility [#885](https://github.com/drapergem/draper/pull/885)
7
+ * Fix ruby warnings for "ambiguous first argument" [#881](https://github.com/drapergem/draper/pull/881)
8
+ * Fix rake warnings in CI [#897](https://github.com/drapergem/draper/pull/897)
9
+ * Fix decoration spec [#895](https://github.com/drapergem/draper/pull/895)
10
+
11
+ ### Other Changes
12
+ * Migration from Travis CI to GitHub Actions [#893](https://github.com/drapergem/draper/pull/893), [#896](https://github.com/drapergem/draper/pull/896), [#903](https://github.com/drapergem/draper/pull/903)
13
+
14
+ ## 4.0.1 - 2020-03-25
15
+
16
+ ### Fixes
17
+ * Check only object's private methods when preventing delegation [#875](https://github.com/drapergem/draper/pull/875)
18
+
19
+ ### Other Changes
20
+ * Use `alias` over `alias_method` [#877](https://github.com/drapergem/draper/pull/877)
21
+
22
+ ## 4.0.0 - 2020-02-05
23
+
24
+ ### Breaking Changes
25
+ * Drop support for Ruby < 2.4 [#852](https://github.com/drapergem/draper/pull/852), [#872](https://github.com/drapergem/draper/pull/872)
26
+ * Don't delegate public methods overridden by a private method in the decorator [#849](https://github.com/drapergem/draper/pull/849)
27
+
28
+ ### Fixes
29
+ * Add preservation of decorator options on QueryMethods [#868](https://github.com/drapergem/draper/pull/868)
30
+ * Add `#respond_to_missing?` to `CollectionDecorator` so it correctly responds to ORM methods [#850](https://github.com/drapergem/draper/pull/850)
31
+ * Fix deprecation warning with the new Rails 6 `ActionView::Base` constructor [#866](https://github.com/drapergem/draper/pull/866)
32
+ * Fix deprecation warning with Ruby 2.7 [#870](https://github.com/drapergem/draper/pull/870)
33
+
34
+ ### Other Changes
35
+ * Add SimpleCov for code coverage analysis [#851](https://github.com/drapergem/draper/pull/851)
36
+ * Update RSpec syntax in the README [#855](https://github.com/drapergem/draper/pull/855)
37
+ * Update continuous integration configuration [#861](https://github.com/drapergem/draper/pull/861), [#862](https://github.com/drapergem/draper/pull/862), [#863](https://github.com/drapergem/draper/pull/863), [#872](https://github.com/drapergem/draper/pull/872)
38
+
3
39
  ## 3.1.0
4
40
  * Rails 6 support [#841](https://github.com/drapergem/draper/pull/841)
5
41
  * Include ORM query methods in `CollectionDecorator` (e.g. `includes`) [#845](https://github.com/drapergem/draper/pull/845)
data/Gemfile CHANGED
@@ -3,7 +3,11 @@ source "https://rubygems.org"
3
3
  gemspec
4
4
 
5
5
  platforms :ruby do
6
- gem 'sqlite3', '~> 1.3.6'
6
+ if RUBY_VERSION >= "2.5.0"
7
+ gem 'sqlite3'
8
+ else
9
+ gem 'sqlite3', '~> 1.3.6'
10
+ end
7
11
  end
8
12
 
9
13
  platforms :jruby do
@@ -11,5 +15,10 @@ platforms :jruby do
11
15
  gem "activerecord-jdbcsqlite3-adapter"
12
16
  end
13
17
 
14
- gem "rails", "~> 5.0"
18
+ if RUBY_VERSION >= "2.5.0"
19
+ gem "rails", "~> 6.0"
20
+ gem 'webrick'
21
+ else
22
+ gem "rails", "~> 5.0"
23
+ end
15
24
  gem "mongoid", github: "mongodb/mongoid"
data/README.md CHANGED
@@ -1,7 +1,8 @@
1
1
  # Draper: View Models for Rails
2
2
 
3
- [![TravisCI Build Status](https://travis-ci.org/drapergem/draper.svg?branch=master)](http://travis-ci.org/drapergem/draper)
3
+ [![Actions Status](https://github.com/drapergem/draper/workflows/CI/badge.svg?branch=master)](https://github.com/drapergem/draper/actions?query=workflow%3Aci+branch%3Amaster)
4
4
  [![Code Climate](https://codeclimate.com/github/drapergem/draper.svg)](https://codeclimate.com/github/drapergem/draper)
5
+ [![Test Coverage](https://api.codeclimate.com/v1/badges/0d40c43951d516bf6985/test_coverage)](https://codeclimate.com/github/drapergem/draper/test_coverage)
5
6
  [![Inline docs](http://inch-ci.org/github/drapergem/draper.svg?branch=master)](http://inch-ci.org/github/drapergem/draper)
6
7
 
7
8
  Draper adds an object-oriented layer of presentation logic to your Rails
@@ -107,7 +108,7 @@ Decorators are the ideal place to:
107
108
 
108
109
  ## Installation
109
110
 
110
- As of version 3.0.0, Draper is only compatible with Rails 5 / Ruby 2.2 and later. Add Draper to your Gemfile.
111
+ As of version 4.0.0, Draper only officially supports Rails 5.2 / Ruby 2.4 and later. Add Draper to your Gemfile.
111
112
 
112
113
  ```ruby
113
114
  gem 'draper'
@@ -379,7 +380,7 @@ can continue to use the `@article` instance variable to manipulate the model -
379
380
  for example, `@article.comments.build` to add a new blank comment for a form.
380
381
 
381
382
  ## Configuration
382
- Draper works out the box well, but also provides a hook for you to configure its
383
+ Draper works out the box well, but also provides a hook for you to configure its
383
384
  default functionality. For example, Draper assumes you have a base `ApplicationController`.
384
385
  If your base controller is named something different (e.g. `BaseController`),
385
386
  you can tell Draper to use it by adding the following to an initializer:
@@ -468,10 +469,13 @@ end
468
469
  ```
469
470
 
470
471
  Then you can stub the specific route helper functions you need using your
471
- preferred stubbing technique (this example uses RSpec's `stub` method):
472
+ preferred stubbing technique. This examples uses Rspec currently recommended API
473
+ available in RSpec 3.6+
472
474
 
473
475
  ```ruby
474
- helpers.stub(users_path: '/users')
476
+ without_partial_double_verification do
477
+ allow(helpers).to receive(:users_path).and_return('/users')
478
+ end
475
479
  ```
476
480
 
477
481
  ### View context leakage
@@ -645,7 +649,7 @@ you can include this module manually.
645
649
 
646
650
  ### Active Job Integration
647
651
 
648
- [Active Job](http://edgeguides.rubyonrails.org/active_job_basics.html) allows you to pass ActiveRecord
652
+ [Active Job](http://edgeguides.rubyonrails.org/active_job_basics.html) allows you to pass ActiveRecord
649
653
  objects to background tasks directly and performs the necessary serialization and deserialization. In
650
654
  order to do this, arguments to a background job must implement [Global ID](https://github.com/rails/globalid).
651
655
  Decorated objects implement Global ID by delegating to the object they are decorating. This means
data/bin/bundle ADDED
@@ -0,0 +1,114 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'bundle' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ require "rubygems"
12
+
13
+ m = Module.new do
14
+ module_function
15
+
16
+ def invoked_as_script?
17
+ File.expand_path($0) == File.expand_path(__FILE__)
18
+ end
19
+
20
+ def env_var_version
21
+ ENV["BUNDLER_VERSION"]
22
+ end
23
+
24
+ def cli_arg_version
25
+ return unless invoked_as_script? # don't want to hijack other binstubs
26
+ return unless "update".start_with?(ARGV.first || " ") # must be running `bundle update`
27
+ bundler_version = nil
28
+ update_index = nil
29
+ ARGV.each_with_index do |a, i|
30
+ if update_index && update_index.succ == i && a =~ Gem::Version::ANCHORED_VERSION_PATTERN
31
+ bundler_version = a
32
+ end
33
+ next unless a =~ /\A--bundler(?:[= ](#{Gem::Version::VERSION_PATTERN}))?\z/
34
+ bundler_version = $1
35
+ update_index = i
36
+ end
37
+ bundler_version
38
+ end
39
+
40
+ def gemfile
41
+ gemfile = ENV["BUNDLE_GEMFILE"]
42
+ return gemfile if gemfile && !gemfile.empty?
43
+
44
+ File.expand_path("../../Gemfile", __FILE__)
45
+ end
46
+
47
+ def lockfile
48
+ lockfile =
49
+ case File.basename(gemfile)
50
+ when "gems.rb" then gemfile.sub(/\.rb$/, gemfile)
51
+ else "#{gemfile}.lock"
52
+ end
53
+ File.expand_path(lockfile)
54
+ end
55
+
56
+ def lockfile_version
57
+ return unless File.file?(lockfile)
58
+ lockfile_contents = File.read(lockfile)
59
+ return unless lockfile_contents =~ /\n\nBUNDLED WITH\n\s{2,}(#{Gem::Version::VERSION_PATTERN})\n/
60
+ Regexp.last_match(1)
61
+ end
62
+
63
+ def bundler_version
64
+ @bundler_version ||=
65
+ env_var_version || cli_arg_version ||
66
+ lockfile_version
67
+ end
68
+
69
+ def bundler_requirement
70
+ return "#{Gem::Requirement.default}.a" unless bundler_version
71
+
72
+ bundler_gem_version = Gem::Version.new(bundler_version)
73
+
74
+ requirement = bundler_gem_version.approximate_recommendation
75
+
76
+ return requirement unless Gem::Version.new(Gem::VERSION) < Gem::Version.new("2.7.0")
77
+
78
+ requirement += ".a" if bundler_gem_version.prerelease?
79
+
80
+ requirement
81
+ end
82
+
83
+ def load_bundler!
84
+ ENV["BUNDLE_GEMFILE"] ||= gemfile
85
+
86
+ activate_bundler
87
+ end
88
+
89
+ def activate_bundler
90
+ gem_error = activation_error_handling do
91
+ gem "bundler", bundler_requirement
92
+ end
93
+ return if gem_error.nil?
94
+ require_error = activation_error_handling do
95
+ require "bundler/version"
96
+ end
97
+ return if require_error.nil? && Gem::Requirement.new(bundler_requirement).satisfied_by?(Gem::Version.new(Bundler::VERSION))
98
+ warn "Activating bundler (#{bundler_requirement}) failed:\n#{gem_error.message}\n\nTo install the version of bundler this project requires, run `gem install bundler -v '#{bundler_requirement}'`"
99
+ exit 42
100
+ end
101
+
102
+ def activation_error_handling
103
+ yield
104
+ nil
105
+ rescue StandardError, LoadError => e
106
+ e
107
+ end
108
+ end
109
+
110
+ m.load_bundler!
111
+
112
+ if m.invoked_as_script?
113
+ load Gem.bin_path("bundler", "bundle")
114
+ end
data/bin/rake ADDED
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'rake' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ require "pathname"
12
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
13
+ Pathname.new(__FILE__).realpath)
14
+
15
+ bundle_binstub = File.expand_path("../bundle", __FILE__)
16
+
17
+ if File.file?(bundle_binstub)
18
+ if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
19
+ load(bundle_binstub)
20
+ else
21
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
22
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
23
+ end
24
+ end
25
+
26
+ require "rubygems"
27
+ require "bundler/setup"
28
+
29
+ load Gem.bin_path("rake", "rake")
data/draper.gemspec CHANGED
@@ -1,4 +1,4 @@
1
- require File.join(__dir__, "lib", "draper", "version")
1
+ require_relative 'lib/draper/version'
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = "draper"
@@ -12,7 +12,6 @@ Gem::Specification.new do |s|
12
12
 
13
13
  s.files = `git ls-files`.split("\n")
14
14
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
15
- s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
16
15
  s.require_paths = ["lib"]
17
16
 
18
17
  s.required_ruby_version = '>= 2.2.2'
@@ -22,6 +21,7 @@ Gem::Specification.new do |s|
22
21
  s.add_dependency 'request_store', '>= 1.0'
23
22
  s.add_dependency 'activemodel', '>= 5.0'
24
23
  s.add_dependency 'activemodel-serializers-xml', '>= 1.0'
24
+ s.add_dependency 'ruby2_keywords'
25
25
 
26
26
  s.add_development_dependency 'ammeter'
27
27
  s.add_development_dependency 'rake'
@@ -30,4 +30,5 @@ Gem::Specification.new do |s|
30
30
  s.add_development_dependency 'capybara'
31
31
  s.add_development_dependency 'active_model_serializers', '>= 0.10'
32
32
  s.add_development_dependency 'rubocop'
33
+ s.add_development_dependency 'simplecov', '0.17.1'
33
34
  end
@@ -6,7 +6,7 @@ module Draper
6
6
  # method calls to `object` as well. Calling `super` will first try to call the method on
7
7
  # the parent decorator class. If no method exists on the parent class, it will then try
8
8
  # to call the method on the `object`.
9
- def method_missing(method, *args, &block)
9
+ ruby2_keywords def method_missing(method, *args, &block)
10
10
  return super unless delegatable?(method)
11
11
 
12
12
  object.send(method, *args, &block)
@@ -20,12 +20,14 @@ module Draper
20
20
 
21
21
  # @private
22
22
  def delegatable?(method)
23
+ return if private_methods(false).include?(method)
24
+
23
25
  object.respond_to?(method)
24
26
  end
25
27
 
26
28
  module ClassMethods
27
29
  # Proxies missing class methods to the source class.
28
- def method_missing(method, *args, &block)
30
+ ruby2_keywords def method_missing(method, *args, &block)
29
31
  return super unless delegatable?(method)
30
32
 
31
33
  object_class.send(method, *args, &block)
@@ -35,7 +35,7 @@ module Draper
35
35
  end
36
36
 
37
37
  class << self
38
- alias_method :decorate, :new
38
+ alias :decorate :new
39
39
  end
40
40
 
41
41
  # @return [Array] the decorated items.
@@ -59,11 +59,12 @@ module Draper
59
59
  true
60
60
  end
61
61
 
62
- alias_method :decorated_with?, :instance_of?
62
+ alias :decorated_with? :instance_of?
63
63
 
64
64
  def kind_of?(klass)
65
65
  decorated_collection.kind_of?(klass) || super
66
66
  end
67
+
67
68
  alias_method :is_a?, :kind_of?
68
69
 
69
70
  def replace(other)
@@ -12,7 +12,8 @@ module Draper
12
12
 
13
13
  # @return the object being decorated.
14
14
  attr_reader :object
15
- alias_method :model, :object
15
+
16
+ alias :model :object
16
17
 
17
18
  # @return [Hash] extra data to be used in user-defined methods.
18
19
  attr_accessor :context
@@ -36,7 +37,7 @@ module Draper
36
37
  end
37
38
 
38
39
  class << self
39
- alias_method :decorate, :new
40
+ alias :decorate :new
40
41
  end
41
42
 
42
43
  # Automatically delegates instance methods to the source object. Class
@@ -190,7 +191,8 @@ module Draper
190
191
  def kind_of?(klass)
191
192
  super || object.kind_of?(klass)
192
193
  end
193
- alias_method :is_a?, :kind_of?
194
+
195
+ alias :is_a? :kind_of?
194
196
 
195
197
  # Checks if `self.instance_of?(klass)` or `object.instance_of?(klass)`
196
198
  #
@@ -225,7 +227,7 @@ module Draper
225
227
  # @return [Class] the class created by {decorate_collection}.
226
228
  def self.collection_decorator_class
227
229
  name = collection_decorator_name
228
- name_constant = name && name.safe_constantize
230
+ name_constant = name&.safe_constantize
229
231
 
230
232
  name_constant || Draper::CollectionDecorator
231
233
  end
@@ -248,7 +250,7 @@ module Draper
248
250
 
249
251
  def self.inferred_object_class
250
252
  name = object_class_name
251
- name_constant = name && name.safe_constantize
253
+ name_constant = name&.safe_constantize
252
254
  return name_constant unless name_constant.nil?
253
255
 
254
256
  raise Draper::UninferrableObjectError.new(self)
@@ -256,7 +258,7 @@ module Draper
256
258
 
257
259
  def self.collection_decorator_name
258
260
  singular = object_class_name
259
- plural = singular && singular.pluralize
261
+ plural = singular&.pluralize
260
262
 
261
263
  "#{plural}Decorator" unless plural == singular
262
264
  end
@@ -7,7 +7,7 @@ module Draper
7
7
  # @return [void]
8
8
  def delegate(*methods)
9
9
  options = methods.extract_options!
10
- super *methods, options.reverse_merge(to: :object)
10
+ super(*methods, **options.reverse_merge(to: :object))
11
11
  end
12
12
  end
13
13
  end
@@ -8,7 +8,7 @@ module Draper
8
8
  end
9
9
 
10
10
  # Sends helper methods to the view context.
11
- def method_missing(method, *args, &block)
11
+ ruby2_keywords def method_missing(method, *args, &block)
12
12
  self.class.define_proxy method
13
13
  send(method, *args, &block)
14
14
  end
@@ -31,6 +31,7 @@ module Draper
31
31
  define_method name do |*args, &block|
32
32
  view_context.send(name, *args, &block)
33
33
  end
34
+ ruby2_keywords name
34
35
  end
35
36
  end
36
37
  end
@@ -4,7 +4,7 @@ module Draper
4
4
  # bazillion methods.
5
5
  module LazyHelpers
6
6
  # Sends missing methods to the {HelperProxy}.
7
- def method_missing(method, *args, &block)
7
+ ruby2_keywords def method_missing(method, *args, &block)
8
8
  helpers.send(method, *args, &block)
9
9
  rescue NoMethodError
10
10
  super
@@ -3,10 +3,14 @@ require_relative 'query_methods/load_strategy'
3
3
  module Draper
4
4
  module QueryMethods
5
5
  # Proxies missing query methods to the source class if the strategy allows.
6
- def method_missing(method, *args, &block)
6
+ ruby2_keywords def method_missing(method, *args, &block)
7
7
  return super unless strategy.allowed? method
8
8
 
9
- object.send(method, *args, &block).decorate
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
10
14
  end
11
15
 
12
16
  private
@@ -21,7 +21,7 @@ module Draper
21
21
  end
22
22
 
23
23
  include Draper::ViewHelpers::ClassMethods
24
- alias_method :helper, :helpers
24
+ alias :helper :helpers
25
25
  end
26
26
 
27
27
  include Behavior
@@ -1,3 +1,3 @@
1
1
  module Draper
2
- VERSION = '3.1.0'
2
+ VERSION = '4.0.2'
3
3
  end
@@ -12,7 +12,7 @@ module Draper
12
12
  end
13
13
 
14
14
  def call
15
- view_context_class.new
15
+ view_context_class.respond_to?(:empty) ? view_context_class.empty : view_context_class.new
16
16
  end
17
17
 
18
18
  private
@@ -12,7 +12,8 @@ module Draper
12
12
  def helpers
13
13
  Draper::ViewContext.current
14
14
  end
15
- alias_method :h, :helpers
15
+
16
+ alias :h :helpers
16
17
  end
17
18
 
18
19
  # Access the helpers proxy to call built-in and user-defined
@@ -22,13 +23,15 @@ module Draper
22
23
  def helpers
23
24
  Draper::ViewContext.current
24
25
  end
25
- alias_method :h, :helpers
26
+
27
+ alias :h :helpers
26
28
 
27
29
  # Alias for `helpers.localize`, since localize is something that's used
28
30
  # quite often. Further aliased to `l` for convenience.
29
- def localize(*args)
31
+ ruby2_keywords def localize(*args)
30
32
  helpers.localize(*args)
31
33
  end
32
- alias_method :l, :localize
34
+
35
+ alias :l :localize
33
36
  end
34
37
  end
data/lib/draper.rb CHANGED
@@ -8,6 +8,8 @@ require 'active_support/core_ext/hash/keys'
8
8
  require 'active_support/core_ext/hash/reverse_merge'
9
9
  require 'active_support/core_ext/name_error'
10
10
 
11
+ require 'ruby2_keywords'
12
+
11
13
  require 'draper/version'
12
14
  require 'draper/configuration'
13
15
  require 'draper/view_helpers'
@@ -60,10 +60,11 @@ module Draper
60
60
 
61
61
  context "when the collection has not yet been decorated" do
62
62
  it "does not trigger decoration" do
63
- decorator = CollectionDecorator.new([])
63
+ decorated = CollectionDecorator.new([]).tap(&:to_a)
64
+ undecorated = CollectionDecorator.new([])
64
65
 
65
- expect(decorator).not_to receive(:decorated_collection)
66
- decorator.context = {other: "context"}
66
+ expect(decorated.instance_variable_defined?(:@decorated_collection)).to be_truthy
67
+ expect(undecorated.instance_variable_defined?(:@decorated_collection)).to be_falsy
67
68
  end
68
69
 
69
70
  it "sets context after decoration is triggered" do
@@ -217,7 +218,7 @@ module Draper
217
218
  it "uses the custom class name" do
218
219
  decorator = ProductsDecorator.new([])
219
220
 
220
- expect(decorator.to_s).to match /ProductsDecorator/
221
+ expect(decorator.to_s).to match(/ProductsDecorator/)
221
222
  end
222
223
  end
223
224
  end
@@ -439,7 +439,7 @@ module Draper
439
439
  it "returns a detailed description of the decorator" do
440
440
  decorator = ProductDecorator.new(double)
441
441
 
442
- expect(decorator.inspect).to match /#<ProductDecorator:0x\h+ .+>/
442
+ expect(decorator.inspect).to match(/#<ProductDecorator:0x\h+ .+>/)
443
443
  end
444
444
 
445
445
  it "includes the object" do
@@ -664,6 +664,38 @@ module Draper
664
664
  expect{decorator.hello_world}.to raise_error NoMethodError
665
665
  expect(decorator.methods).not_to include :hello_world
666
666
  end
667
+
668
+ context 'when decorator overrides a public method defined on the object with a private' do
669
+ let(:decorator_class) do
670
+ Class.new(Decorator) do
671
+ private
672
+
673
+ def hello_world
674
+ 'hello world'
675
+ end
676
+ end
677
+ end
678
+
679
+ let(:object) { Class.new { def hello_world; end }.new }
680
+
681
+ it 'does not delegate the public method defined on the object' do
682
+ decorator = decorator_class.new(object)
683
+
684
+ expect{ decorator.hello_world }.to raise_error NoMethodError
685
+ end
686
+ end
687
+
688
+ context 'when delegated method has the same name as private method defined on another object' do
689
+ let(:decorator_class) { Class.new(Decorator) }
690
+ let(:object) { Class.new { def print; end }.new }
691
+
692
+ it 'delegates the public method defined on the object' do
693
+ decorator = decorator_class.new(object)
694
+
695
+ # `print` private method is defined on `Object`
696
+ expect{ decorator.print }.not_to raise_error
697
+ end
698
+ end
667
699
  end
668
700
 
669
701
  context ".method_missing" do
@@ -1,5 +1,6 @@
1
1
  require 'spec_helper'
2
2
  require 'support/shared_examples/view_helpers'
3
+ SimpleCov.command_name 'test:unit'
3
4
 
4
5
  module Draper
5
6
  describe Draper do
@@ -5,12 +5,14 @@ Post = Struct.new(:id) { }
5
5
 
6
6
  module Draper
7
7
  describe QueryMethods do
8
+ let(:fake_strategy) { instance_double(QueryMethods::LoadStrategy::ActiveRecord) }
9
+
10
+ before { allow(QueryMethods::LoadStrategy).to receive(:new).and_return(fake_strategy) }
11
+
8
12
  describe '#method_missing' do
9
13
  let(:collection) { [ Post.new, Post.new ] }
10
- let(:collection_decorator) { PostDecorator.decorate_collection(collection) }
11
- let(:fake_strategy) { instance_double(QueryMethods::LoadStrategy::ActiveRecord) }
12
-
13
- before { allow(QueryMethods::LoadStrategy).to receive(:new).and_return(fake_strategy) }
14
+ let(:collection_context) { { user: 'foo' } }
15
+ let(:collection_decorator) { PostDecorator.decorate_collection(collection, context: collection_context) }
14
16
 
15
17
  context 'when strategy allows collection to call the method' do
16
18
  let(:results) { spy(:results) }
@@ -25,6 +27,12 @@ module Draper
25
27
 
26
28
  expect(results).to have_received(:decorate)
27
29
  end
30
+
31
+ it 'calls the method on the collection and keeps the decoration options' do
32
+ collection_decorator.some_query_method
33
+
34
+ expect(results).to have_received(:decorate).with({ context: collection_context, with: PostDecorator })
35
+ end
28
36
  end
29
37
 
30
38
  context 'when strategy does not allow collection to call the method' do
@@ -35,5 +43,28 @@ module Draper
35
43
  end
36
44
  end
37
45
  end
46
+
47
+ describe "#respond_to?" do
48
+ let(:collection) { [ Post.new, Post.new ] }
49
+ let(:collection_decorator) { PostDecorator.decorate_collection(collection) }
50
+
51
+ subject { collection_decorator.respond_to?(:some_query_method) }
52
+
53
+ context 'when strategy allows collection to call the method' do
54
+ before do
55
+ allow(fake_strategy).to receive(:allowed?).with(:some_query_method).and_return(true)
56
+ end
57
+
58
+ it { is_expected.to eq(true) }
59
+ end
60
+
61
+ context 'when strategy does not allow collection to call the method' do
62
+ before do
63
+ allow(fake_strategy).to receive(:allowed?).with(:some_query_method).and_return(false)
64
+ end
65
+
66
+ it { is_expected.to eq(false) }
67
+ end
68
+ end
38
69
  end
39
70
  end
@@ -0,0 +1,3 @@
1
+ //= link_tree ../images
2
+ //= link_directory ../javascripts .js
3
+ //= link_directory ../stylesheets .css
@@ -0,0 +1,2 @@
1
+ class ApplicationController < ActionController::Base
2
+ end
@@ -30,4 +30,6 @@ Dummy::Application.configure do
30
30
 
31
31
  # Expands the lines which load the assets
32
32
  # config.assets.debug = true
33
+
34
+ config.active_storage.service = :local
33
35
  end
@@ -54,4 +54,6 @@ Dummy::Application.configure do
54
54
  # Log the query plan for queries taking more than this (works
55
55
  # with SQLite, MySQL, and PostgreSQL)
56
56
  # config.active_record.auto_explain_threshold_in_seconds = 0.5
57
+
58
+ config.active_storage.service = :local
57
59
  end
@@ -30,4 +30,6 @@ Dummy::Application.configure do
30
30
  config.eager_load = false
31
31
 
32
32
  config.active_job.queue_adapter = :test
33
+
34
+ config.active_storage.service = :test
33
35
  end
@@ -0,0 +1,7 @@
1
+ test:
2
+ service: Disk
3
+ root: <%= Rails.root.join("tmp/storage") %>
4
+
5
+ local:
6
+ service: Disk
7
+ root: <%= Rails.root.join("storage") %>
@@ -3,6 +3,7 @@ require 'dummy/config/environment'
3
3
  require 'ammeter/init'
4
4
  require 'generators/controller_override'
5
5
  require 'generators/rails/decorator_generator'
6
+ SimpleCov.command_name 'test:generator'
6
7
 
7
8
  describe Rails::Generators::ControllerGenerator do
8
9
  destination File.expand_path("../tmp", __FILE__)
@@ -40,7 +40,7 @@ describe Rails::Generators::DecoratorGenerator do
40
40
 
41
41
  context "with an ApplicationDecorator" do
42
42
  before do
43
- allow_any_instance_of(Object).to receive(:require)
43
+ allow_any_instance_of(Object).to receive(:require).and_call_original
44
44
  allow_any_instance_of(Object).to receive(:require).with("application_decorator").and_return(
45
45
  stub_const "ApplicationDecorator", Class.new
46
46
  )
@@ -1,6 +1,7 @@
1
1
  require 'spec_helper'
2
2
  require 'support/dummy_app'
3
3
  require 'support/matchers/have_text'
4
+ SimpleCov.command_name 'test:integration'
4
5
 
5
6
  app = DummyApp.new(ENV["RAILS_ENV"])
6
7
  spec_types = {
data/spec/spec_helper.rb CHANGED
@@ -1,3 +1,10 @@
1
+ require 'simplecov'
2
+ SimpleCov.start do
3
+ add_filter 'spec'
4
+ add_group 'Draper', 'lib/draper'
5
+ add_group 'Generators', 'lib/generators'
6
+ end
7
+
1
8
  require 'bundler/setup'
2
9
  require 'draper'
3
10
  require 'action_controller'
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: draper
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.1.0
4
+ version: 4.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeff Casimir
8
8
  - Steve Klabnik
9
- autorequire:
9
+ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2019-03-14 00:00:00.000000000 Z
12
+ date: 2021-05-27 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport
@@ -81,6 +81,20 @@ dependencies:
81
81
  - - ">="
82
82
  - !ruby/object:Gem::Version
83
83
  version: '1.0'
84
+ - !ruby/object:Gem::Dependency
85
+ name: ruby2_keywords
86
+ requirement: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ type: :runtime
92
+ prerelease: false
93
+ version_requirements: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
84
98
  - !ruby/object:Gem::Dependency
85
99
  name: ammeter
86
100
  requirement: !ruby/object:Gem::Requirement
@@ -179,6 +193,20 @@ dependencies:
179
193
  - - ">="
180
194
  - !ruby/object:Gem::Version
181
195
  version: '0'
196
+ - !ruby/object:Gem::Dependency
197
+ name: simplecov
198
+ requirement: !ruby/object:Gem::Requirement
199
+ requirements:
200
+ - - '='
201
+ - !ruby/object:Gem::Version
202
+ version: 0.17.1
203
+ type: :development
204
+ prerelease: false
205
+ version_requirements: !ruby/object:Gem::Requirement
206
+ requirements:
207
+ - - '='
208
+ - !ruby/object:Gem::Version
209
+ version: 0.17.1
182
210
  description: Draper adds an object-oriented layer of presentation logic to your Rails
183
211
  apps.
184
212
  email:
@@ -190,10 +218,10 @@ extra_rdoc_files: []
190
218
  files:
191
219
  - ".codeclimate.yml"
192
220
  - ".github/PULL_REQUEST_TEMPLATE.md"
221
+ - ".github/workflows/ci.yml"
193
222
  - ".gitignore"
194
223
  - ".rspec"
195
224
  - ".rubocop.yml"
196
- - ".travis.yml"
197
225
  - ".yardopts"
198
226
  - CHANGELOG.md
199
227
  - CONTRIBUTING.md
@@ -202,6 +230,8 @@ files:
202
230
  - LICENSE
203
231
  - README.md
204
232
  - Rakefile
233
+ - bin/bundle
234
+ - bin/rake
205
235
  - draper.gemspec
206
236
  - lib/draper.rb
207
237
  - lib/draper/automatic_delegation.rb
@@ -266,6 +296,8 @@ files:
266
296
  - spec/draper/view_helpers_spec.rb
267
297
  - spec/dummy/.rspec
268
298
  - spec/dummy/Rakefile
299
+ - spec/dummy/app/assets/config/manifest.js
300
+ - spec/dummy/app/controllers/application_controller.rb
269
301
  - spec/dummy/app/controllers/base_controller.rb
270
302
  - spec/dummy/app/controllers/localized_urls.rb
271
303
  - spec/dummy/app/controllers/posts_controller.rb
@@ -303,6 +335,7 @@ files:
303
335
  - spec/dummy/config/locales/en.yml
304
336
  - spec/dummy/config/mongoid.yml
305
337
  - spec/dummy/config/routes.rb
338
+ - spec/dummy/config/storage.yml
306
339
  - spec/dummy/db/migrate/20121019115657_create_posts.rb
307
340
  - spec/dummy/db/schema.rb
308
341
  - spec/dummy/db/seeds.rb
@@ -353,7 +386,7 @@ homepage: http://github.com/drapergem/draper
353
386
  licenses:
354
387
  - MIT
355
388
  metadata: {}
356
- post_install_message:
389
+ post_install_message:
357
390
  rdoc_options: []
358
391
  require_paths:
359
392
  - lib
@@ -368,8 +401,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
368
401
  - !ruby/object:Gem::Version
369
402
  version: '0'
370
403
  requirements: []
371
- rubygems_version: 3.0.2
372
- signing_key:
404
+ rubygems_version: 3.0.8
405
+ signing_key:
373
406
  specification_version: 4
374
407
  summary: View Models for Rails
375
408
  test_files:
@@ -394,6 +427,8 @@ test_files:
394
427
  - spec/draper/view_helpers_spec.rb
395
428
  - spec/dummy/.rspec
396
429
  - spec/dummy/Rakefile
430
+ - spec/dummy/app/assets/config/manifest.js
431
+ - spec/dummy/app/controllers/application_controller.rb
397
432
  - spec/dummy/app/controllers/base_controller.rb
398
433
  - spec/dummy/app/controllers/localized_urls.rb
399
434
  - spec/dummy/app/controllers/posts_controller.rb
@@ -431,6 +466,7 @@ test_files:
431
466
  - spec/dummy/config/locales/en.yml
432
467
  - spec/dummy/config/mongoid.yml
433
468
  - spec/dummy/config/routes.rb
469
+ - spec/dummy/config/storage.yml
434
470
  - spec/dummy/db/migrate/20121019115657_create_posts.rb
435
471
  - spec/dummy/db/schema.rb
436
472
  - spec/dummy/db/seeds.rb
data/.travis.yml DELETED
@@ -1,17 +0,0 @@
1
- language: ruby
2
- sudo: false
3
- cache: bundler
4
-
5
- services:
6
- - mongodb
7
-
8
- rvm:
9
- - 2.3.5
10
- - 2.4.3
11
- - 2.5.4
12
- - 2.6.2
13
- - ruby-head
14
-
15
- matrix:
16
- allow_failures:
17
- - rvm: ruby-head