draper 4.0.1 → 4.0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +71 -0
- data/.rspec +1 -2
- data/CHANGELOG.md +29 -0
- data/Gemfile +27 -4
- data/README.md +24 -2
- data/bin/bundle +114 -0
- data/bin/rake +29 -0
- data/draper.gemspec +4 -4
- data/lib/draper/automatic_delegation.rb +16 -6
- data/lib/draper/decoratable/collection_proxy.rb +15 -0
- data/lib/draper/decoratable.rb +2 -2
- data/lib/draper/helper_proxy.rb +2 -1
- data/lib/draper/lazy_helpers.rb +1 -1
- data/lib/draper/query_methods.rb +2 -2
- data/lib/draper/railtie.rb +8 -4
- data/lib/draper/version.rb +1 -1
- data/lib/draper/view_context/build_strategy.rb +1 -9
- data/lib/draper/view_helpers.rb +1 -1
- data/lib/draper.rb +2 -6
- data/spec/draper/collection_decorator_spec.rb +5 -4
- data/spec/draper/decoratable_spec.rb +1 -1
- data/spec/draper/decorator_spec.rb +4 -4
- data/spec/draper/factory_spec.rb +8 -8
- data/spec/draper/query_methods_spec.rb +10 -0
- data/spec/draper/view_context/build_strategy_spec.rb +1 -18
- data/spec/dummy/.rspec +0 -1
- data/spec/dummy/app/decorators/comment_decorator.rb +13 -0
- data/spec/dummy/app/decorators/mongoid_post_decorator.rb +1 -3
- data/spec/dummy/app/models/admin.rb +2 -4
- data/spec/dummy/app/models/comment.rb +3 -0
- data/spec/dummy/app/models/mongoid_post.rb +2 -4
- data/spec/dummy/app/models/post.rb +4 -0
- data/spec/dummy/app/models/user.rb +2 -4
- data/spec/dummy/config/application.rb +22 -51
- data/spec/dummy/config/environments/development.rb +66 -21
- data/spec/dummy/config/environments/production.rb +77 -32
- data/spec/dummy/config/environments/test.rb +56 -20
- data/spec/dummy/config/initializers/draper.rb +4 -2
- data/spec/dummy/config/storage.yml +7 -0
- data/spec/dummy/db/migrate/20240907041839_create_comments.rb +9 -0
- data/spec/dummy/db/schema.rb +16 -9
- data/spec/dummy/spec/decorators/active_model_serializers_spec.rb +1 -1
- data/spec/dummy/spec/decorators/post_decorator_spec.rb +1 -1
- data/spec/dummy/spec/jobs/publish_post_job_spec.rb +2 -0
- data/spec/dummy/spec/models/post_spec.rb +41 -5
- data/spec/dummy/spec/rails_helper.rb +69 -0
- data/spec/dummy/spec/spec_helper.rb +90 -5
- data/spec/generators/decorator/decorator_generator_spec.rb +1 -1
- data/spec/performance/benchmark.rb +1 -1
- data/spec/support/dummy_app.rb +1 -1
- metadata +40 -13
- data/.travis.yml +0 -28
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 78c5e444690de191d46a5be87ed46a3f9be6ec0ffd59fed6dcd1d63e5d527b85
|
4
|
+
data.tar.gz: f92be8ee42d8ce2e48c1743077f758eef779296593fcbcdef9a82fd5937a03ae
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2b2d10594f175019d7cbee9b7af7f811c8978349abae3cdce746abd94f24501d81b519c9da9ae350658265dd5aa0b33cdd9b3f18e26df922363227df8f57c4a4
|
7
|
+
data.tar.gz: 81565fd7b8034294a41c49b557f48619e6cee814056d2d4bff4c0e6f17c024877b250b421d4a185310f6b6fa3dee14b51d954b6ee3cef39100d3cfb4c9582af7
|
@@ -0,0 +1,71 @@
|
|
1
|
+
---
|
2
|
+
name: CI
|
3
|
+
|
4
|
+
on:
|
5
|
+
push:
|
6
|
+
branches:
|
7
|
+
- master
|
8
|
+
pull_request:
|
9
|
+
|
10
|
+
permissions:
|
11
|
+
contents: read
|
12
|
+
|
13
|
+
jobs:
|
14
|
+
rspec:
|
15
|
+
name: >-
|
16
|
+
rspec (${{ matrix.ruby }})
|
17
|
+
|
18
|
+
runs-on: ubuntu-latest
|
19
|
+
|
20
|
+
strategy:
|
21
|
+
fail-fast: false
|
22
|
+
matrix:
|
23
|
+
ruby:
|
24
|
+
- 3.3
|
25
|
+
- 3.2
|
26
|
+
- 3.1
|
27
|
+
rails:
|
28
|
+
- 7.2
|
29
|
+
include:
|
30
|
+
# Edge
|
31
|
+
- { ruby: 'head', rails: 'edge', allow-fail: true }
|
32
|
+
# Outdated
|
33
|
+
- { ruby: '3.0', rails: '7.1' }
|
34
|
+
- { ruby: '2.7', rails: '6' } # RSpec AR Expectations support Rails 7.1 since Ruby 3.0
|
35
|
+
- { ruby: '2.6', rails: '6' }
|
36
|
+
- { ruby: '2.5', rails: '6' }
|
37
|
+
- { ruby: '2.4', rails: '5' }
|
38
|
+
|
39
|
+
env:
|
40
|
+
RAILS_VERSION: "${{ matrix.rails }}"
|
41
|
+
|
42
|
+
services:
|
43
|
+
mongodb:
|
44
|
+
image: mongo
|
45
|
+
ports:
|
46
|
+
- 27017:27017
|
47
|
+
|
48
|
+
steps:
|
49
|
+
- uses: actions/checkout@v4
|
50
|
+
|
51
|
+
- name: Setup Ruby
|
52
|
+
uses: ruby/setup-ruby@v1
|
53
|
+
with:
|
54
|
+
ruby-version: ${{ matrix.ruby }}
|
55
|
+
rubygems: latest
|
56
|
+
bundler-cache: true
|
57
|
+
|
58
|
+
- name: RSpec & publish code coverage
|
59
|
+
uses: paambaati/codeclimate-action@v8
|
60
|
+
env:
|
61
|
+
CC_TEST_REPORTER_ID: b7ba588af2a540fa96c267b3655a2afe31ea29976dc25905a668dd28d5e88915
|
62
|
+
with:
|
63
|
+
coverageCommand: bin/rake
|
64
|
+
continue-on-error: ${{ matrix.allow-fail }}
|
65
|
+
id: test
|
66
|
+
|
67
|
+
- name: >-
|
68
|
+
Test ${{ steps.test.outcome }}
|
69
|
+
run: |
|
70
|
+
echo Ruby ${{ matrix.ruby }}
|
71
|
+
echo Rails ${{ matrix.rails }}
|
data/.rspec
CHANGED
@@ -1,2 +1 @@
|
|
1
|
-
--
|
2
|
-
--order rand
|
1
|
+
--format progress
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,34 @@
|
|
1
1
|
# Draper Changelog
|
2
2
|
|
3
|
+
## 4.0.4 - 2025-01-28
|
4
|
+
|
5
|
+
### Fixes
|
6
|
+
* Fix a `LoadError` caused by a cherry-pick issue in version 4.0.3
|
7
|
+
|
8
|
+
## 4.0.3 - 2025-01-27
|
9
|
+
|
10
|
+
Added support for latest Ruby (upto 3.4) and Rails (upto 8) versions.
|
11
|
+
|
12
|
+
### Fixes
|
13
|
+
* Fix `CollectionDecorator#respond_to?` for non-ORM collections [#920](https://github.com/drapergem/draper/pull/920)
|
14
|
+
* Fix issues with using Draper outside of controller scope [#927](https://github.com/drapergem/draper/pull/927)
|
15
|
+
* Fix decoration of AR associations [#932](https://github.com/drapergem/draper/pull/932)
|
16
|
+
|
17
|
+
### Other Changes
|
18
|
+
* Improve performance of delegation via `delegate_all` [#911](https://github.com/drapergem/draper/pull/911)
|
19
|
+
* Improve README [#878](https://github.com/drapergem/draper/pull/878), [#922](https://github.com/drapergem/draper/pull/922), [#934](https://github.com/drapergem/draper/pull/934)
|
20
|
+
|
21
|
+
## 4.0.2 - 2021-05-27
|
22
|
+
|
23
|
+
### Fixes
|
24
|
+
* Fix kwargs usage for Ruby 3 compatibility [#885](https://github.com/drapergem/draper/pull/885)
|
25
|
+
* Fix ruby warnings for "ambiguous first argument" [#881](https://github.com/drapergem/draper/pull/881)
|
26
|
+
* Fix rake warnings in CI [#897](https://github.com/drapergem/draper/pull/897)
|
27
|
+
* Fix decoration spec [#895](https://github.com/drapergem/draper/pull/895)
|
28
|
+
|
29
|
+
### Other Changes
|
30
|
+
* 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)
|
31
|
+
|
3
32
|
## 4.0.1 - 2020-03-25
|
4
33
|
|
5
34
|
### Fixes
|
data/Gemfile
CHANGED
@@ -2,6 +2,8 @@ source "https://rubygems.org"
|
|
2
2
|
|
3
3
|
gemspec
|
4
4
|
|
5
|
+
gem 'puma'
|
6
|
+
|
5
7
|
platforms :ruby do
|
6
8
|
if RUBY_VERSION >= "2.5.0"
|
7
9
|
gem 'sqlite3'
|
@@ -15,9 +17,30 @@ platforms :jruby do
|
|
15
17
|
gem "activerecord-jdbcsqlite3-adapter"
|
16
18
|
end
|
17
19
|
|
18
|
-
|
19
|
-
|
20
|
+
case rails_version = ENV['RAILS_VERSION']
|
21
|
+
when nil
|
22
|
+
gem 'rails'
|
23
|
+
when 'edge'
|
24
|
+
gem 'rails', github: 'rails/rails'
|
20
25
|
else
|
21
|
-
gem
|
26
|
+
gem 'rails', "~> #{rails_version}.0"
|
27
|
+
end
|
28
|
+
|
29
|
+
gem 'mongoid' unless
|
30
|
+
rails_version == 'edge'
|
31
|
+
gem 'active_model_serializers'
|
32
|
+
|
33
|
+
case RUBY_VERSION
|
34
|
+
when '2.6'...'3.0'
|
35
|
+
gem "turbo-rails", "<= 2.0.7"
|
36
|
+
gem "redis", "~> 4.0"
|
37
|
+
when '3.0'...'4'
|
38
|
+
gem 'turbo-rails'
|
39
|
+
gem 'redis', '~> 4.0'
|
40
|
+
end
|
41
|
+
|
42
|
+
if RUBY_VERSION < "2.5.0"
|
43
|
+
gem 'rspec-activerecord-expectations', '~> 1.2.0'
|
44
|
+
gem 'simplecov', '0.17.1'
|
45
|
+
gem "loofah", "< 2.21.0" # Workaround for `uninitialized constant Nokogiri::HTML4`
|
22
46
|
end
|
23
|
-
gem "mongoid", github: "mongodb/mongoid"
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# Draper: View Models for Rails
|
2
2
|
|
3
|
-
[![
|
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
5
|
[![Test Coverage](https://api.codeclimate.com/v1/badges/0d40c43951d516bf6985/test_coverage)](https://codeclimate.com/github/drapergem/draper/test_coverage)
|
6
6
|
[![Inline docs](http://inch-ci.org/github/drapergem/draper.svg?branch=master)](http://inch-ci.org/github/drapergem/draper)
|
@@ -131,6 +131,17 @@ class ArticleDecorator < Draper::Decorator
|
|
131
131
|
end
|
132
132
|
```
|
133
133
|
|
134
|
+
|
135
|
+
To decorate a model in a namespace e.g. `Admin::Catalogue` place the decorator under the
|
136
|
+
directory `app/decorators/admin` in the same way you would with views and models.
|
137
|
+
|
138
|
+
```ruby
|
139
|
+
# app/decorators/admin/catalogue_decorator.rb
|
140
|
+
class Admin::CatalogueDecorator < Draper::Decorator
|
141
|
+
# ...
|
142
|
+
end
|
143
|
+
```
|
144
|
+
|
134
145
|
### Generators
|
135
146
|
|
136
147
|
To create an `ApplicationDecorator` that all generated decorators inherit from, run...
|
@@ -155,6 +166,15 @@ rails generate decorator Article
|
|
155
166
|
|
156
167
|
...to create the `ArticleDecorator`.
|
157
168
|
|
169
|
+
If you don't want Rails to generate decorator files when generating a new controller,
|
170
|
+
you can add the following configuration to your `config/application.rb` file:
|
171
|
+
|
172
|
+
```ruby
|
173
|
+
config.generators do |g|
|
174
|
+
g.decorator false
|
175
|
+
end
|
176
|
+
```
|
177
|
+
|
158
178
|
### Accessing Helpers
|
159
179
|
|
160
180
|
Normal Rails helpers are still useful for lots of tasks. Both Rails' provided
|
@@ -664,7 +684,8 @@ great community of open source
|
|
664
684
|
|
665
685
|
### Current maintainers
|
666
686
|
|
667
|
-
*
|
687
|
+
* Alexander Senko (Alexander.Senko@gmail.com)
|
688
|
+
* Yuji Yaginuma (yuuji.yaginuma@gmail.com)
|
668
689
|
|
669
690
|
### Historical maintainers
|
670
691
|
|
@@ -673,3 +694,4 @@ great community of open source
|
|
673
694
|
* Vasiliy Ermolovich
|
674
695
|
* Andrew Haines
|
675
696
|
* Sean Linsley
|
697
|
+
* Cliff Braton (cliff.braton@gmail.com)
|
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,18 +1,17 @@
|
|
1
|
-
|
1
|
+
require_relative 'lib/draper/version'
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = "draper"
|
5
5
|
s.version = Draper::VERSION
|
6
6
|
s.authors = ["Jeff Casimir", "Steve Klabnik"]
|
7
7
|
s.email = ["jeff@casimircreative.com", "steve@steveklabnik.com"]
|
8
|
-
s.homepage = "
|
8
|
+
s.homepage = "https://github.com/drapergem/draper"
|
9
9
|
s.summary = "View Models for Rails"
|
10
10
|
s.description = "Draper adds an object-oriented layer of presentation logic to your Rails apps."
|
11
11
|
s.license = "MIT"
|
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,13 +21,14 @@ 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'
|
28
28
|
s.add_development_dependency 'rspec-rails'
|
29
|
+
s.add_development_dependency 'rspec-activerecord-expectations'
|
29
30
|
s.add_development_dependency 'minitest-rails'
|
30
31
|
s.add_development_dependency 'capybara'
|
31
|
-
s.add_development_dependency 'active_model_serializers', '>= 0.10'
|
32
32
|
s.add_development_dependency 'rubocop'
|
33
33
|
s.add_development_dependency 'simplecov'
|
34
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)
|
@@ -18,16 +18,26 @@ module Draper
|
|
18
18
|
super || delegatable?(method)
|
19
19
|
end
|
20
20
|
|
21
|
-
#
|
22
|
-
|
23
|
-
|
21
|
+
# The inherit argument for `private_method_defined?` is supported since Ruby 2.6.
|
22
|
+
if RUBY_VERSION >= "2.6"
|
23
|
+
# @private
|
24
|
+
def delegatable?(method)
|
25
|
+
return if self.class.private_method_defined?(method, false)
|
24
26
|
|
25
|
-
|
27
|
+
object.respond_to?(method)
|
28
|
+
end
|
29
|
+
else
|
30
|
+
# @private
|
31
|
+
def delegatable?(method)
|
32
|
+
return if private_methods(false).include?(method)
|
33
|
+
|
34
|
+
object.respond_to?(method)
|
35
|
+
end
|
26
36
|
end
|
27
37
|
|
28
38
|
module ClassMethods
|
29
39
|
# Proxies missing class methods to the source class.
|
30
|
-
def method_missing(method, *args, &block)
|
40
|
+
ruby2_keywords def method_missing(method, *args, &block)
|
31
41
|
return super unless delegatable?(method)
|
32
42
|
|
33
43
|
object_class.send(method, *args, &block)
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Draper
|
2
|
+
module Decoratable
|
3
|
+
module CollectionProxy
|
4
|
+
# Decorates a collection of objects. Used at the end of a scope chain.
|
5
|
+
#
|
6
|
+
# @example
|
7
|
+
# company.products.popular.decorate
|
8
|
+
# @param [Hash] options
|
9
|
+
# see {Decorator.decorate_collection}.
|
10
|
+
def decorate(options = {})
|
11
|
+
decorator_class.decorate_collection(load_target, options.reverse_merge(with: nil))
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/lib/draper/decoratable.rb
CHANGED
@@ -11,6 +11,8 @@ module Draper
|
|
11
11
|
extend ActiveSupport::Concern
|
12
12
|
include Draper::Decoratable::Equality
|
13
13
|
|
14
|
+
autoload :CollectionProxy, 'draper/decoratable/collection_proxy'
|
15
|
+
|
14
16
|
# Decorates the object using the inferred {#decorator_class}.
|
15
17
|
# @param [Hash] options
|
16
18
|
# see {Decorator#initialize}
|
@@ -87,8 +89,6 @@ module Draper
|
|
87
89
|
def ===(other)
|
88
90
|
super || (other.is_a?(Draper::Decorator) && super(other.object))
|
89
91
|
end
|
90
|
-
|
91
92
|
end
|
92
|
-
|
93
93
|
end
|
94
94
|
end
|
data/lib/draper/helper_proxy.rb
CHANGED
@@ -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
|
data/lib/draper/lazy_helpers.rb
CHANGED
@@ -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
|
data/lib/draper/query_methods.rb
CHANGED
@@ -3,14 +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
9
|
object.send(method, *args, &block).decorate(with: decorator_class, context: context)
|
10
10
|
end
|
11
11
|
|
12
12
|
def respond_to_missing?(method, include_private = false)
|
13
|
-
strategy.allowed?(method) || super
|
13
|
+
object.respond_to?(method) && strategy.allowed?(method) || super
|
14
14
|
end
|
15
15
|
|
16
16
|
private
|
data/lib/draper/railtie.rb
CHANGED
@@ -33,10 +33,14 @@ module Draper
|
|
33
33
|
end
|
34
34
|
|
35
35
|
initializer 'draper.setup_orm' do
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
36
|
+
ActiveSupport.on_load :active_record do
|
37
|
+
include Draper::Decoratable
|
38
|
+
|
39
|
+
ActiveRecord::Associations::CollectionProxy.include Draper::Decoratable::CollectionProxy
|
40
|
+
end
|
41
|
+
|
42
|
+
ActiveSupport.on_load :mongoid do
|
43
|
+
include Draper::Decoratable
|
40
44
|
end
|
41
45
|
end
|
42
46
|
|
data/lib/draper/version.rb
CHANGED
@@ -38,17 +38,9 @@ module Draper
|
|
38
38
|
def controller
|
39
39
|
Draper::ViewContext.controller ||= Draper.default_controller.new
|
40
40
|
Draper::ViewContext.controller.tap do |controller|
|
41
|
-
controller.request ||=
|
41
|
+
controller.request ||= ActionDispatch::TestRequest.create
|
42
42
|
end
|
43
43
|
end
|
44
|
-
|
45
|
-
def new_test_request(controller)
|
46
|
-
is_above_rails_5_1 ? ActionController::TestRequest.create(controller) : ActionController::TestRequest.create
|
47
|
-
end
|
48
|
-
|
49
|
-
def is_above_rails_5_1
|
50
|
-
ActionController::TestRequest.method(:create).parameters.first == [:req, :controller_class]
|
51
|
-
end
|
52
44
|
end
|
53
45
|
end
|
54
46
|
end
|
data/lib/draper/view_helpers.rb
CHANGED
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'
|
@@ -49,12 +51,6 @@ module Draper
|
|
49
51
|
end
|
50
52
|
end
|
51
53
|
|
52
|
-
def self.setup_orm(base)
|
53
|
-
base.class_eval do
|
54
|
-
include Draper::Decoratable
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
54
|
class UninferrableDecoratorError < NameError
|
59
55
|
def initialize(klass)
|
60
56
|
super("Could not infer a decorator for #{klass}.")
|
@@ -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
|
-
|
63
|
+
decorated = CollectionDecorator.new([]).tap(&:to_a)
|
64
|
+
undecorated = CollectionDecorator.new([])
|
64
65
|
|
65
|
-
expect(
|
66
|
-
|
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
|
221
|
+
expect(decorator.to_s).to match(/ProductsDecorator/)
|
221
222
|
end
|
222
223
|
end
|
223
224
|
end
|
@@ -147,7 +147,7 @@ module Draper
|
|
147
147
|
scoped = [Product.new]
|
148
148
|
allow(Product).to receive(:all).and_return(scoped)
|
149
149
|
|
150
|
-
expect(Product.decorator_class).to receive(:decorate_collection).with(scoped, with: nil).and_return(:decorated_collection)
|
150
|
+
expect(Product.decorator_class).to receive(:decorate_collection).with(scoped, {with: nil}).and_return(:decorated_collection)
|
151
151
|
expect(Product.decorate).to be :decorated_collection
|
152
152
|
end
|
153
153
|
|