dekorator 1.0.0.pre.1 → 1.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/.codeclimate.yml +4 -0
  3. data/.github/workflows/test.yml +40 -0
  4. data/CHANGELOG.md +44 -4
  5. data/CODE_OF_CONDUCT.md +1 -1
  6. data/README.md +107 -40
  7. data/benchmarks/README.md +7 -0
  8. data/benchmarks/benchmark.rb +135 -0
  9. data/dekorator.gemspec +29 -15
  10. data/lib/dekorator/rails/controller.rb +17 -0
  11. data/lib/dekorator/rails/tasks/dekorator.rake +11 -0
  12. data/lib/dekorator/railtie.rb +9 -5
  13. data/lib/dekorator/version.rb +1 -1
  14. data/lib/dekorator.rb +79 -53
  15. data/lib/generators/decorator_generator.rb +7 -0
  16. data/lib/generators/{decorator → dekorator/decorator}/USAGE +1 -1
  17. data/lib/generators/dekorator/decorator/decorator_generator.rb +17 -0
  18. data/lib/generators/{decorator → dekorator/decorator}/templates/decorator.rb +0 -0
  19. data/lib/generators/dekorator/{install_generator.rb → install/install_generator.rb} +8 -6
  20. data/lib/generators/rspec/decorator_generator.rb +2 -0
  21. data/lib/generators/test_unit/decorator_generator.rb +2 -0
  22. metadata +60 -52
  23. data/.editorconfig +0 -14
  24. data/.gitignore +0 -11
  25. data/.rspec +0 -3
  26. data/.rubocop.yml +0 -114
  27. data/.simplecov +0 -5
  28. data/.travis.yml +0 -37
  29. data/Appraisals +0 -17
  30. data/Gemfile +0 -22
  31. data/Gemfile.lock +0 -157
  32. data/bin/console +0 -16
  33. data/bin/setup +0 -8
  34. data/gemfiles/.bundle/config +0 -2
  35. data/gemfiles/rails_5.0.x.gemfile +0 -21
  36. data/gemfiles/rails_5.0.x.gemfile.lock +0 -207
  37. data/gemfiles/rails_5.1.x.gemfile +0 -21
  38. data/gemfiles/rails_5.1.x.gemfile.lock +0 -207
  39. data/gemfiles/rails_5.2.x.gemfile +0 -21
  40. data/gemfiles/rails_5.2.x.gemfile.lock +0 -207
  41. data/gemfiles/rails_6.0.x.gemfile +0 -21
  42. data/gemfiles/rails_6.0.x.gemfile.lock +0 -220
  43. data/lib/dekorator/decorators_helper.rb +0 -5
  44. data/lib/dekorator/rspec.rb +0 -0
  45. data/lib/generators/decorator/decorator_generator.rb +0 -11
  46. data/lib/generators/decorator/templates/decorator_test.rb +0 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 92168b3d181e861e0c2649e7f6a56165da132af21e251ddaa92d08e6f98381b8
4
- data.tar.gz: ac455c756a54061271316b83e37025353a9371480b19f212aabdc37a72056f66
3
+ metadata.gz: 993e7223cde1fe170c2312e2a183536162e3deaa933e3dcabd0405bd1d5d1587
4
+ data.tar.gz: a4cf19afa975185a5a585d60045ced1e872ad02766bd2218091f4cdc1708ffa4
5
5
  SHA512:
6
- metadata.gz: 75e15ec204e2ce9645209582b70009c21690857df2eca9098b3d45ffc725bd92cc673d65d7ae0f2f69515a26befcaedf85dd7a80fae520b6d4b22d17982f15f7
7
- data.tar.gz: 6432e281aa9ff6dee4fb31b247f4ffa216b35fe3cc522f794e0d75040518c9cb3e318fcc3e053a9e9daa3ec346a6778b75dc906e580b66b21ae659d95e50dbe3
6
+ metadata.gz: 74e30fa63df10cc4f6a196f7fdade396e32ef202e58f1e477ca5096b709ad8166f558f55b58011043ac8f1b823f1b38dba34b0335627de57429a930b6ae1320a
7
+ data.tar.gz: 1851f7ba63d6962d298efb768d66d0c5aa88a12b6c5f2f596c6e7e9a51906ad5cf0b5d9b0db545c1aa6a0be82dadf00568d11cdadfd46269f06c103975965cab
data/.codeclimate.yml ADDED
@@ -0,0 +1,4 @@
1
+ exclude_patterns:
2
+ - "benchmarks/**/*"
3
+ - "lib/generators/**/*"
4
+ - "spec/**/*"
@@ -0,0 +1,40 @@
1
+ name: Tests
2
+
3
+ on: [push, pull_request]
4
+
5
+ jobs:
6
+ test:
7
+ name: Ruby ${{ matrix.versions.ruby }}, Rails ${{ matrix.versions.rails }}
8
+ runs-on: ubuntu-latest
9
+ strategy:
10
+ matrix:
11
+ versions:
12
+ - { ruby: "2.5", rails: "5.2.x" }
13
+ - { ruby: "2.6", rails: "5.2.x" }
14
+ - { ruby: "2.7", rails: "5.2.x" }
15
+ - { ruby: "2.5", rails: "6.0.x" }
16
+ - { ruby: "2.6", rails: "6.0.x" }
17
+ - { ruby: "2.7", rails: "6.0.x" }
18
+ - { ruby: "3.0", rails: "6.0.x" }
19
+ - { ruby: "2.5", rails: "6.1.x" }
20
+ - { ruby: "2.6", rails: "6.1.x" }
21
+ - { ruby: "2.7", rails: "6.1.x" }
22
+ - { ruby: "3.0", rails: "6.1.x" }
23
+ - { ruby: "2.7", rails: "head" }
24
+ - { ruby: "3.0", rails: "head" }
25
+
26
+
27
+ env:
28
+ BUNDLE_GEMFILE: gemfiles/rails_${{ matrix.versions.rails }}.gemfile
29
+ steps:
30
+ - uses: actions/checkout@v2
31
+
32
+ - name: Set up Ruby
33
+ uses: ruby/setup-ruby@v1
34
+ with:
35
+ ruby-version: ${{ matrix.versions.ruby }}
36
+ bundler-cache: true
37
+
38
+ - name: Test with Rake
39
+ run: |
40
+ bundle exec rake test:all_with_coverage
data/CHANGELOG.md CHANGED
@@ -1,4 +1,5 @@
1
1
  # Changelog
2
+
2
3
  All notable changes to this project will be documented in this file.
3
4
 
4
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
@@ -7,10 +8,49 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
8
  ## [Unreleased]
8
9
  Nothing yet
9
10
 
11
+ ## [1.2.1] - 2021-10-14
12
+ - Make decorated `Enumerable` not lazy anymore ([#46](https://github.com/komposable/dekorator/pull/46))
13
+
14
+ ## [1.2.0] - 2021-10-14
15
+ ### Added
16
+ - Add Rails 7.0 support ([#43](https://github.com/komposable/dekorator/pull/43))
17
+ ### Fixes
18
+ - Avoid n+1 queries when decorate ActiveRecord::Relation ([#44](https://github.com/komposable/dekorator/pull/44))
19
+
20
+ ## [1.1.0] - 2020-12-23
21
+ ### Added
22
+ - Ruby 2.7 support ([#37](https://github.com/komposable/dekorator/pull/37))
23
+ - List decorators in Rails stats task ([#38](https://github.com/komposable/dekorator/pull/38))
24
+ - Add Rails 6.1 support and drop Rails 5.0 and 5.1 support ([#41](https://github.com/komposable/dekorator/pull/41))
25
+ ### Changed
26
+ - Refactorisation ([#39](https://github.com/komposable/dekorator/pull/39))
27
+ ### Removed
28
+ - Remove `DecoratedEnumerableProxy` ([#36](https://github.com/komposable/dekorator/pull/36))
29
+ - Drop Ruby 2.4 support ([#37](https://github.com/komposable/dekorator/pull/37))
30
+ - Drop Rails 5.0 and 5.1 support ([#41](https://github.com/komposable/dekorator/pull/41))
31
+
32
+ ## [1.0.0] - 2019-12-02
33
+ ### Added
34
+ - Avoid deep decoration ([#25](https://github.com/komposable/dekorator/pull/25))
35
+ - Make `decorate` accessible in ApplicationController ([#29](https://github.com/komposable/dekorator/pull/29))
36
+
37
+ ### Changed
38
+ - Moved to Komposable organization ([#13](https://github.com/komposable/dekorator/pull/13))
39
+ - Replace Travis CI by Github Actions and remove ruby 2.3 support ([#23](https://github.com/komposable/dekorator/pull/23))
40
+ - Update railtie to prevent triggering initialization autoloaded constant deprecation warning ([#30](https://github.com/komposable/dekorator/pull/30))
41
+ - Improve generators ([#31](https://github.com/komposable/dekorator/pull/31))
42
+
43
+ ### Fixes
44
+ - Fix DecoratedEnumerableProxy for Rails 6 ([5a656333](https://github.com/komposable/dekorator/commit/5a656333e9ca6321d0474f0e54de4332219b88d0))
45
+
10
46
  ## 1.0.0.pre.1 - 2019-01-30
11
47
  ### Added
12
- - Create Dekorator::Base the base of decorators (a2a36d66)
13
- - Create `dekorator:install` generator (a2a36d66)
14
- - Create `decorator` generator (a2a36d66)
48
+ - Create Dekorator::Base the base of decorators ([a2a36d66](https://github.com/komposable/dekorator/commit/a2a36d66c6de6cb0a00f783794cd29f899bc04b6))
49
+ - Create `dekorator:install` generator ([a2a36d66](https://github.com/komposable/dekorator/commit/a2a36d66c6de6cb0a00f783794cd29f899bc04b6))
50
+ - Create `decorator` generator ([a2a36d66](https://github.com/komposable/dekorator/commit/a2a36d66c6de6cb0a00f783794cd29f899bc04b6))
15
51
 
16
- [Unreleased]: https://github.com/pantographe/dekorator/compare/v1.0.0.pre.1...HEAD
52
+ [Unreleased]: https://github.com/komposable/dekorator/compare/v1.2.1...master
53
+ [1.2.1]: https://github.com/komposable/dekorator/compare/v1.2.0...v1.2.1
54
+ [1.2.0]: https://github.com/komposable/dekorator/compare/v1.1.0...v1.2.0
55
+ [1.1.0]: https://github.com/komposable/dekorator/compare/v1.0.0...v1.1.0
56
+ [1.0.0]: https://github.com/komposable/dekorator/compare/v1.0.0.pre.1...v1.0.0
data/CODE_OF_CONDUCT.md CHANGED
@@ -55,7 +55,7 @@ further defined and clarified by project maintainers.
55
55
  ## Enforcement
56
56
 
57
57
  Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
- reported by contacting the project team at nicolas@pantographe.studio. All
58
+ reported by contacting the project team at oss@pantographe.studio. All
59
59
  complaints will be reviewed and investigated and will result in a response that
60
60
  is deemed necessary and appropriate to the circumstances. The project team is
61
61
  obligated to maintain confidentiality with regard to the reporter of an incident.
data/README.md CHANGED
@@ -1,24 +1,24 @@
1
1
  # Dekorator
2
2
 
3
- [![Build Status](https://travis-ci.org/pantographe/dekorator.svg?branch=master)](https://travis-ci.org/pantographe/dekorator)
3
+ [![Tests](https://github.com/komposable/dekorator/workflows/Tests/badge.svg)](https://github.com/komposable/dekorator/actions)
4
4
  [![Gem Version](https://badge.fury.io/rb/dekorator.svg)](https://rubygems.org/gems/dekorator)
5
- [![Coverage Status](https://coveralls.io/repos/github/pantographe/dekorator/badge.svg)](https://coveralls.io/github/pantographe/dekorator)
6
- [![Inch CI](https://inch-ci.org/github/pantographe/dekorator.svg?branch=master)](https://inch-ci.org/github/pantographe/dekorator)
7
- [![Yardoc](https://img.shields.io/badge/doc-yardoc-blue.svg)](https://www.rubydoc.info/github/pantographe/dekorator/master)
5
+ [![Maintainability](https://api.codeclimate.com/v1/badges/f7ab08512ead00da34c0/maintainability)](https://codeclimate.com/github/komposable/dekorator/maintainability)
6
+ [![Coverage Status](https://coveralls.io/repos/github/komposable/dekorator/badge.svg)](https://coveralls.io/github/komposable/dekorator)
7
+ [![Inch CI](https://inch-ci.org/github/komposable/dekorator.svg?branch=master)](https://inch-ci.org/github/komposable/dekorator)
8
+ [![Yardoc](https://img.shields.io/badge/doc-yardoc-blue.svg)](https://www.rubydoc.info/github/komposable/dekorator/master)
8
9
 
9
- **Dekorator** is an opinionated way of organizing model-view code in Ruby on Rails, based on _decorators_.
10
+ **Dekorator** is a lightweight library to implement _presenters_ and/or _decorators_ in your Rails app. It has less features than [`draper`](https://github.com/drapergem/draper) and aims at having a lower memory footprint.
10
11
 
11
- **Not production ready**
12
+ This gem has been inspired by our Rails development practices at [Pantographe](https://pantographe.studio), and the [Ruby memory, ActiveRecord and Draper](https://medium.com/appaloosa-store-engineering/ruby-memory-activerecord-and-draper-64f06abeeb34) talk by [Benoit Tigeot](https://github.com/benoittgt).
12
13
 
13
14
  ## Compatibility
14
15
 
15
- * Ruby 2.3+
16
- * Rails 5.0+
17
-
16
+ * Ruby 2.5+
17
+ * Rails 5.2+
18
18
 
19
19
  ## Installation
20
20
 
21
- Add this line to your application's Gemfile:
21
+ Add this line to your application `Gemfile`:
22
22
 
23
23
  ```ruby
24
24
  gem "dekorator"
@@ -28,7 +28,6 @@ And then execute:
28
28
 
29
29
  $ bundle
30
30
 
31
-
32
31
  ## Getting started
33
32
 
34
33
  Run the following command to set up your project:
@@ -37,7 +36,6 @@ Run the following command to set up your project:
37
36
 
38
37
  This command will create an `ApplicationDecorator` file.
39
38
 
40
-
41
39
  ## Usage
42
40
 
43
41
  Generate a new decorator with the `decorator` generator:
@@ -48,23 +46,55 @@ This command will generate the following file:
48
46
 
49
47
  ```ruby
50
48
  class UserDecorator < ApplicationDecorator
51
- # include ActionView::Helpers::TextHelper
52
- #
53
- # decorates_association :posts
54
- #
55
- # def full_name
56
- # [first_name, last_name].join(" ")
57
- # end
58
- #
59
- # def biography_summary
60
- # truncate(biography, length: 170)
61
- # end
49
+ include ActionView::Helpers::TextHelper
50
+
51
+ decorates_association :posts
52
+
53
+ def full_name
54
+ [first_name, last_name].join(" ")
55
+ end
56
+
57
+ def biography_summary
58
+ truncate(biography, length: 170)
59
+ end
62
60
  end
63
61
  ```
64
62
 
63
+ ### Decorate from a controller
64
+
65
+ ```ruby
66
+ class UsersController < ApplicationController
67
+ def index
68
+ @users = decorate User.all
69
+ end
70
+
71
+ def show
72
+ @user = decorate User.find(params[:id])
73
+ end
74
+ end
75
+ ```
76
+
77
+ ### Decorate from a view
78
+
79
+ ```erb
80
+ # app/views/users/index.html.erb
81
+
82
+ <ul>
83
+ <% decorate(@users).each do |user| %>
84
+ <li><%= user.full_name %></li>
85
+ <% end %>
86
+ </ul>
87
+ ```
88
+
89
+ ### Decorate outside a controller/view
90
+
91
+ ```ruby
92
+ UserDecorate.decorate(User.first) # => UserDecorator
93
+ ```
94
+
65
95
  ### Associations
66
96
 
67
- If you want to automatically decorates association for a decorated object,
97
+ If you want to automatically decorate an association for a decorated object,
68
98
  you have to use `#decorates_association` as following:
69
99
 
70
100
  ```ruby
@@ -82,29 +112,34 @@ end
82
112
  In this example, `UserDecorator#posts` will be decorated.
83
113
 
84
114
  ```ruby
85
- decorated_user = decorator(User.first)
115
+ decorated_user = decorate(User.first)
86
116
  decorated_user # => UserDecorator
87
117
  decorated_user.posts.first # => PostDecorator
88
118
  ```
89
119
 
90
- ### Specify decorator
120
+ ### Custom decorator
121
+
122
+ By default, Dekorator searches for the decorator class by adding `Decorator` at the end.
123
+ For `User`, Dekorator looks for the `UserDecorator` class, and for `User::Profile`
124
+ it looks for `User::ProfileDecorator`.
91
125
 
92
- If you want to create specific decorator or sub-decorator, you could simply
93
- specify the decorator class that should be use.
126
+ If you want to create a specific decorator or sub-decorator, you can simply
127
+ specify the decorator class that should be used.
94
128
 
95
129
  ```ruby
96
130
  class AdminDecorator < ApplicationDecorator
131
+ ...
97
132
  end
98
133
 
99
- decorated_user = decorator(User.first, with: AdminDecorator)
134
+ decorated_user = decorate(User.first, with: AdminDecorator)
100
135
  decorated_user # => AdminDecorator
101
136
  ```
102
137
 
103
- You also could specify the decorator for associations:
138
+ You can also specify the decorator for associations:
104
139
 
105
140
  ```ruby
106
141
  class UserDecorator < ApplicationDecorator
107
- decorates_association :posts, ArticleDecorator
142
+ decorates_association :posts, with: ArticleDecorator
108
143
 
109
144
  ...
110
145
  end
@@ -112,7 +147,7 @@ end
112
147
  class ArticleDecorator < ApplicationDecorator
113
148
  end
114
149
 
115
- decorated_user = decorator(User.first)
150
+ decorated_user = decorate(User.first)
116
151
  decorated_user # => UserDecorator
117
152
  decorated_user.posts.first # => ArticleDecorator
118
153
  ```
@@ -121,7 +156,8 @@ decorated_user.posts.first # => ArticleDecorator
121
156
 
122
157
  ### ActiveAdmin
123
158
 
124
- This gem is compatible with [`activeadmin`][activeadmin].
159
+ This gem is compatible with [`activeadmin`][activeadmin] ([2.8+](https://github.com/activeadmin/activeadmin/pull/6249)).
160
+ For `activeadmin` before `2.8`, use `dekorator` `1.0.*`.
125
161
 
126
162
  Simply use `#decorate_with`
127
163
 
@@ -140,10 +176,10 @@ end
140
176
 
141
177
  ### Devise
142
178
 
143
- If you use [`device`][devise] gem you may have an issue if you decorate your
179
+ If you use the [`Devise`][devise] gem you may have an issue if you decorate your
144
180
  `User` model.
145
181
 
146
- You must define `#devise_scope` as following. Devise need to manage with
182
+ You must define `#devise_scope` as following. Devise needs to manage with the
147
183
  `User` model (https://github.com/plataformatec/devise/blob/369ba267efaa10d01c8dba59b09c3b94dd9e5551/lib/devise/mapping.rb#L35).
148
184
 
149
185
  ```ruby
@@ -156,24 +192,55 @@ class UserDecorator < ApplicationDecorator
156
192
  end
157
193
  ```
158
194
 
195
+ ## Testing
196
+
197
+ `rails generate decorator user` also generates a testing file based on your
198
+ configuration.
199
+
200
+ You can test a decorator the same way you do for helpers.
201
+
202
+ ### RSpec
203
+
204
+ ```ruby
205
+ describe UserDecorator, type: :decorator do
206
+ let(:object) { User.new(first_name: "John", last_name: "Doe") }
207
+ let(:decorated_user) { described_class.new(object) }
208
+
209
+ describe "#full_name" do
210
+ it { expect(decorated_user.full_name).to eq("John Doe") }
211
+ end
212
+ end
213
+ ```
159
214
 
160
215
  ## Development
161
216
 
162
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
217
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run
218
+ `rake spec` to run the tests. You can also run `bin/console` for an interactive
219
+ prompt that will allow you to experiment.
163
220
 
164
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
221
+ To install this gem onto your local machine, run `bundle exec rake install`.
222
+ To release a new version, update the version number in `version.rb`, then
223
+ run `bundle exec rake release`, which will create a git tag for the version,
224
+ push git commits and tags, and push the `.gem` file to [rubygems.org].
165
225
 
166
226
  ## Contributing
167
227
 
168
- Bug reports and pull requests are welcome on GitHub at https://github.com/pantographe/dekorator. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
228
+ Bug reports and pull requests are welcome on GitHub at
229
+ https://github.com/komposable/dekorator. This project is intended to be a safe,
230
+ welcoming space for collaboration, and contributors are expected to adhere to
231
+ the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
169
232
 
170
233
  ## License
171
234
 
172
- The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
235
+ The gem is available as open source under the terms of the [MIT License].
173
236
 
174
237
  ## Code of Conduct
175
238
 
176
- Everyone interacting in the Dekorator project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/pantographe/dekorator/blob/master/CODE_OF_CONDUCT.md).
239
+ Everyone interacting in the Dekorator project codebases, issue trackers,
240
+ chat rooms and mailing lists is expected to follow the [code of conduct].
177
241
 
178
242
  [activeadmin]: https://activeadmin.info/11-decorators.html
179
243
  [devise]: https://github.com/plataformatec/devise/
244
+ [rubygems.org]: https://rubygems.org
245
+ [MIT License]: https://opensource.org/licenses/MIT
246
+ [code of conduct]: https://github.com/komposable/dekorator/blob/master/CODE_OF_CONDUCT.md
@@ -0,0 +1,7 @@
1
+ # Benchmarks
2
+
3
+ ## Run benchmarks
4
+
5
+ ```sh
6
+ $ ruby benchmark.rb
7
+ ```
@@ -0,0 +1,135 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/inline"
4
+
5
+ gemfile(true) do
6
+ source "https://rubygems.org"
7
+
8
+ git_source(:github) { |repo| "https://github.com/#{repo}.git" }
9
+
10
+ gem "rails", "6.0.1"
11
+ gem "sqlite3"
12
+ gem "benchmark-ips"
13
+ gem "benchmark-memory"
14
+
15
+ gem "dekorator", path: "../", require: false
16
+ gem "draper", require: false
17
+ end
18
+
19
+ require "active_record"
20
+ require "logger"
21
+
22
+ ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:")
23
+ ActiveRecord::Base.logger = nil # Logger.new(STDOUT)
24
+
25
+ ActiveRecord::Schema.define do
26
+ create_table :posts, force: true do |t|
27
+ t.string :title
28
+ t.text :body
29
+ end
30
+
31
+ create_table :comments, force: true do |t|
32
+ t.integer :post_id
33
+ t.string :author
34
+ t.text :body
35
+ end
36
+ end
37
+
38
+ # Models
39
+ class Post < ActiveRecord::Base
40
+ has_many :comments
41
+
42
+ def summary
43
+ @summary ||= body&.truncate(170)
44
+ end
45
+ end
46
+
47
+ class Comment < ActiveRecord::Base
48
+ belongs_to :post
49
+ end
50
+
51
+ # Data
52
+ comments = 100.times.map { Comment.new(author: "John D.", body: "Great article") }
53
+ 10.times.each { Post.create!(title: "Our first article!", body: "", comments: comments) }
54
+
55
+ # Decorators
56
+ require "dekorator"
57
+
58
+ class PostDecorator < Dekorator::Base
59
+ decorates_association :comments
60
+
61
+ def summary
62
+ @summary ||= body&.truncate(170)
63
+ end
64
+ end
65
+
66
+ class CommentDecorator < Dekorator::Base
67
+ end
68
+
69
+ require "draper"
70
+
71
+ class CommentDraperDecorator < Draper::Decorator
72
+ end
73
+
74
+ class PostDraperDecorator < Draper::Decorator
75
+ decorates_association :comments, with: CommentDraperDecorator
76
+
77
+ def summary
78
+ @summary ||= object.body&.truncate(170)
79
+ end
80
+ end
81
+
82
+ require "delegate"
83
+
84
+ class PostDelegator < SimpleDelegator
85
+ def summary
86
+ @summary ||= body&.truncate(170)
87
+ end
88
+
89
+ def comments
90
+ @comments = __getobj__.comments.map { |comment| CommentDelegator.new(CommentDelegator) }
91
+ end
92
+ end
93
+
94
+ class CommentDelegator < SimpleDelegator
95
+ end
96
+
97
+ # Benchmark
98
+ SCENARIOS = {
99
+ "#summary" => :summary,
100
+ "#comments" => :comments,
101
+ }
102
+
103
+ SCENARIOS.each_pair do |name, method|
104
+ puts
105
+ puts " #{name} ".center(80, "=")
106
+ puts
107
+
108
+ model = Post.all
109
+
110
+ puts " ips ".center(80, "-")
111
+ puts
112
+
113
+ Benchmark.ips do |x|
114
+ x.report("In model") { model.first.public_send(method) }
115
+ x.report("Dekorator") { PostDecorator.decorate(model).first.public_send(method) }
116
+ x.report("Dekorator.new") { PostDecorator.decorate(model).first.public_send(method) }
117
+ x.report("Draper") { PostDraperDecorator.decorate_collection(model).first.public_send(method) }
118
+ x.report("SimpleDelegator") { PostDelegator.new(model.first).public_send(method) }
119
+
120
+ x.compare!
121
+ end
122
+
123
+ puts " memory ".center(80, "-")
124
+ puts
125
+
126
+ Benchmark.memory do |x|
127
+ x.report("In model") { model.first.public_send(method) }
128
+ x.report("Dekorator") { PostDecorator.decorate(model).first.public_send(method) }
129
+ x.report("Dekorator.new") { PostDecorator.decorate(model).first.public_send(method) }
130
+ x.report("Draper") { PostDraperDecorator.decorate_collection(model).first.public_send(method) }
131
+ x.report("SimpleDelegator") { PostDelegator.new(model.first).public_send(method) }
132
+
133
+ x.compare!
134
+ end
135
+ end
data/dekorator.gemspec CHANGED
@@ -1,34 +1,48 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- lib = File.expand_path("../lib", __FILE__)
3
+ lib = File.expand_path("lib", __dir__)
4
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
5
  require "dekorator/version"
6
6
 
7
7
  Gem::Specification.new do |spec|
8
- spec.name = "dekorator"
9
- spec.version = Dekorator::VERSION
10
- spec.authors = ["Nicolas Brousse"]
11
- spec.email = ["nicolas@pantographe.studio"]
12
-
13
- spec.summary = "An opinionated way of organizing model-view code in Ruby on Rails, based on decorators"
14
- spec.description = "An opinionated way of organizing model-view code in Ruby on Rails, based on decorators"
15
- spec.license = "MIT"
8
+ spec.name = "dekorator"
9
+ spec.version = Dekorator::VERSION
10
+ spec.authors = ["Pantographe"]
11
+ spec.email = ["oss@pantographe.studio"]
12
+
13
+ spec.summary = "An opinionated way of organizing model-view code in Ruby on Rails, based on decorators"
14
+ spec.description = "An opinionated way of organizing model-view code in Ruby on Rails, based on decorators"
15
+ spec.homepage = "http://komponent.io"
16
+ spec.license = "MIT"
17
+
18
+ spec.metadata = {
19
+ "homepage_uri" => "https://github.com/komposable/dekorator",
20
+ "changelog_uri" => "https://github.com/komposable/dekorator/blob/master/CHANGELOG.md",
21
+ "source_code_uri" => "https://github.com/komposable/dekorator",
22
+ "bug_tracker_uri" => "https://github.com/komposable/dekorator/issues",
23
+ }
16
24
 
17
25
  # Specify which files should be added to the gem when it is released.
18
26
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
19
- spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
20
- `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
27
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
28
+ `git ls-files -z`.split("\x0")
29
+ .reject do |f|
30
+ f.match(%r{^(test|spec|features|gemfiles|bin)/}) \
31
+ || %w[.editorconfig .gitignore .inch.yml .rspec .rubocop.yml .simplecov .travis.yml
32
+ .yardots Appraisals Gemfile Gemfile.lock].include?(f)
33
+ end
21
34
  end
22
35
 
23
36
  spec.require_paths = ["lib"]
24
37
 
25
38
  spec.required_ruby_version = ">= 2.3"
26
39
 
27
- spec.add_runtime_dependency "actionview", ">= 5.0", "< 6.1"
28
- spec.add_runtime_dependency "activesupport", ">= 5.0", "< 6.1"
29
- spec.add_runtime_dependency "railties", ">= 5.0", "< 6.1"
40
+ spec.add_runtime_dependency "actionview", ">= 5.2", "< 7.1"
41
+ spec.add_runtime_dependency "activerecord", ">= 5.2", "< 7.1"
42
+ spec.add_runtime_dependency "activesupport", ">= 5.2", "< 7.1"
43
+ spec.add_runtime_dependency "railties", ">= 5.2", "< 7.1"
30
44
 
31
45
  spec.add_development_dependency "bundler", "~> 2.0"
32
- spec.add_development_dependency "rake", "~> 10.0"
46
+ spec.add_development_dependency "rake", ">= 12.3.3"
33
47
  spec.add_development_dependency "rspec", "~> 3.0"
34
48
  end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/concern"
4
+
5
+ module Dekorator
6
+ module Controller
7
+ extend ActiveSupport::Concern
8
+
9
+ included do
10
+ helper_method :decorate
11
+ end
12
+
13
+ def decorate(object_or_enumerable, with: nil)
14
+ Dekorator::Base.decorate(object_or_enumerable, with: with)
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ task stats: "dekorator:statsetup"
4
+
5
+ namespace :dekorator do
6
+ task statsetup: :environment do
7
+ require "rails/code_statistics"
8
+
9
+ ::STATS_DIRECTORIES << ["Decorators", "app/decorators"]
10
+ end
11
+ end
@@ -1,11 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "dekorator/decorators_helper"
4
-
5
3
  module Dekorator
6
- class Railtie < Rails::Railtie
7
- initializer "decorators.helper" do |_app|
8
- ActionView::Base.send :include, DecoratorsHelper
4
+ require "dekorator/rails/controller"
5
+
6
+ class Railtie < ::Rails::Railtie
7
+ rake_tasks do
8
+ load "dekorator/rails/tasks/dekorator.rake"
9
+ end
10
+
11
+ config.to_prepare do |_app|
12
+ ActionController::Base.include Dekorator::Controller
9
13
  end
10
14
  end
11
15
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Dekorator
4
- VERSION = "1.0.0.pre.1".freeze
4
+ VERSION = "1.2.1".freeze
5
5
  end