jbuilder 2.10.2 → 2.11.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 977b17be8a840c956c4043e24671792174502c57de951e215873b80b66b1031d
4
- data.tar.gz: 847725cdbcfca6ba030942fa9d63b35b0fffd729587774c2dd020eaf75b0b786
3
+ metadata.gz: 4dacba51a263fc3bcbea4471ae1557dea10c014f68657a39ab812e55a167eba9
4
+ data.tar.gz: 544f954ce6f89f7775853b91bfc99f5f1634596389f5750028e13532b314a63c
5
5
  SHA512:
6
- metadata.gz: fcf001b86052df2bf45e8040630a6c3bcb9cb5ee5fee7910a636706fc7c05350a3a86feab542541f5b8290435fd8be61c8ca9cc17c1b1a3b87fb6626aeb9b495
7
- data.tar.gz: 44d59c94049d3f76c9b3111408aabe16631deb5ef80fbde72a6e43a2a5807c2da3e47725dc8974384212cba178a48b76bb61cd114433593ccfd0dc3311e92b07
6
+ metadata.gz: a71638ae38f5755b97a40db81c2121f92788b3e4242de6d4789032f0ff7bab4f62d2dd96b7cab19e8583ee448946bb2e66e8cf5f6ab65c7b514ff88c19af1407
7
+ data.tar.gz: cd3477c065ebdbacc5da5d383973e996499cce7872d8303691376739732735441b003981a767af1bdb8ccea6648685291ff20e81c662a95ad54c87205ba233f9
@@ -0,0 +1,108 @@
1
+ name: Ruby test
2
+
3
+ on: [push, pull_request]
4
+
5
+ jobs:
6
+ test:
7
+ name: Ruby test
8
+ runs-on: ubuntu-20.04
9
+ continue-on-error: ${{ matrix.experimental }}
10
+ env:
11
+ BUNDLE_GEMFILE: ${{ github.workspace }}/gemfiles/${{ matrix.gemfile }}.gemfile
12
+ BUNDLE_JOBS: 4
13
+ BUNDLE_RETRY: 3
14
+ strategy:
15
+ fail-fast: false
16
+ matrix:
17
+ ruby: [
18
+ 2.2.10,
19
+ 2.3.8,
20
+ 2.4.10,
21
+ 2.5.8,
22
+ 2.6.6,
23
+ 2.7.1,
24
+ 3.0.0
25
+ ]
26
+ gemfile: [
27
+ "rails_5_0",
28
+ "rails_5_1",
29
+ "rails_5_2",
30
+ "rails_6_0",
31
+ "rails_6_1",
32
+ "rails_head"
33
+ ]
34
+ experimental: [false]
35
+ exclude:
36
+ - ruby: 2.7.1
37
+ gemfile: rails_5_0
38
+ - ruby: 3.0.0
39
+ gemfile: rails_5_0
40
+ - ruby: head
41
+ gemfile: rails_5_0
42
+ - ruby: 2.7.1
43
+ gemfile: rails_5_1
44
+ - ruby: 3.0.0
45
+ gemfile: rails_5_1
46
+ - ruby: head
47
+ gemfile: rails_5_1
48
+ - ruby: 2.2.10
49
+ gemfile: rails_5_2
50
+ - ruby: 2.7.1
51
+ gemfile: rails_5_2
52
+ - ruby: 3.0.0
53
+ gemfile: rails_5_2
54
+ - ruby: head
55
+ gemfile: rails_5_2
56
+ - ruby: 2.2.10
57
+ gemfile: rails_6_0
58
+ - ruby: 2.3.8
59
+ gemfile: rails_6_0
60
+ - ruby: 2.4.10
61
+ gemfile: rails_6_0
62
+ - ruby: 3.0.0
63
+ gemfile: rails_6_0
64
+ - ruby: head
65
+ gemfile: rails_6_0
66
+ - ruby: 2.2.10
67
+ gemfile: rails_6_1
68
+ - ruby: 2.3.8
69
+ gemfile: rails_6_1
70
+ - ruby: 2.4.10
71
+ gemfile: rails_6_1
72
+ - ruby: 2.2.10
73
+ gemfile: rails_head
74
+ - ruby: 2.3.8
75
+ gemfile: rails_head
76
+ - ruby: 2.4.10
77
+ gemfile: rails_head
78
+ - ruby: 2.5.8
79
+ gemfile: rails_head
80
+ - ruby: 2.6.6
81
+ gemfile: rails_head
82
+ - ruby: 2.7.1
83
+ gemfile: rails_head
84
+ experimental: false
85
+ - ruby: 3.0.0
86
+ gemfile: rails_head
87
+ experimental: false
88
+ include:
89
+ - ruby: 2.7.1
90
+ gemfile: rails_head
91
+ experimental: true
92
+ - ruby: 3.0.0
93
+ gemfile: rails_head
94
+ experimental: true
95
+ - ruby: head
96
+ gemfile: rails_head
97
+ experimental: true
98
+
99
+ steps:
100
+ - uses: actions/checkout@v2
101
+
102
+ - uses: ruby/setup-ruby@v1
103
+ with:
104
+ ruby-version: ${{ matrix.ruby }}
105
+ bundler-cache: true
106
+
107
+ - name: Ruby test
108
+ run: bundle exec rake
data/Appraisals CHANGED
@@ -15,7 +15,11 @@ if RUBY_VERSION >= "2.5.0"
15
15
  gem "rails", "~> 6.0.0"
16
16
  end
17
17
 
18
+ appraise "rails-6-1" do
19
+ gem "rails", "~> 6.1.0"
20
+ end
21
+
18
22
  appraise "rails-head" do
19
- gem "rails", github: "rails/rails"
23
+ gem "rails", github: "rails/rails", branch: "main"
20
24
  end
21
25
  end
data/CHANGELOG.md CHANGED
@@ -1,17 +1,35 @@
1
1
  # Changelog
2
2
 
3
+ 2.11.2
4
+ ------
5
+
6
+ * [Improve key formatting for nested hashes and disable by default](https://github.com/rails/jbuilder/pull/497)
7
+
8
+ 2.11.1
9
+ ------
10
+
11
+ * Use symbols instead of strings for before_action filters [DHH]
12
+ * Slim down comments in generated scaffold code [DHH]
13
+
14
+ 2.11.0
15
+ ------
16
+
17
+ * [Allow jbuilder instance to be passed to #merge!](https://github.com/rails/jbuilder/pull/485)
18
+ * [Fix for key_format! when using nested hashes](https://github.com/rails/jbuilder/pull/486)
19
+ * [Include rich_text, attachment, and attachments fields in json partial](https://github.com/rails/jbuilder/pull/459)
20
+
3
21
  2.10.2
4
- ----------
22
+ ------
5
23
 
6
24
  * Update scaffold generator to use double quotes, 422 form error responds, and modern string-of-arrays syntax [DHH]
7
25
 
8
26
  2.10.1
9
- ----------
27
+ ------
10
28
 
11
29
  * Fix keyword arguments warning on Ruby 2.7
12
30
 
13
31
  2.10.0
14
- ----------
32
+ ------
15
33
 
16
34
  * Requires Rails 5+ and Ruby 2.2+
17
35
  * Nested hashes are deep-merged
data/CONTRIBUTING.md CHANGED
@@ -1,11 +1,11 @@
1
1
  Contributing to Jbuilder
2
2
  =====================
3
3
 
4
- [![Build Status](https://api.travis-ci.org/rails/jbuilder.svg?branch=master)][travis]
4
+ [![Build Status](https://github.com/rails/jbuilder/workflows/Ruby%20test/badge.svg)][test]
5
5
  [![Gem Version](https://badge.fury.io/rb/jbuilder.svg)][gem]
6
6
  [![Code Climate](https://codeclimate.com/github/rails/jbuilder/badges/gpa.svg)][codeclimate]
7
7
 
8
- [travis]: https://travis-ci.org/rails/jbuilder
8
+ [test]: https://github.com/rails/jbuilder/actions?query=branch%3Amaster
9
9
  [gem]: https://rubygems.org/gems/jbuilder
10
10
  [codeclimate]: https://codeclimate.com/github/rails/jbuilder
11
11
 
@@ -13,7 +13,7 @@ Jbuilder is work of [many contributors](https://github.com/rails/jbuilder/graphs
13
13
 
14
14
  #### Fork the Project
15
15
 
16
- Fork the [project on Github](https://github.com/rails/jbuilder) and check out your copy.
16
+ Fork the [project on GitHub](https://github.com/rails/jbuilder) and check out your copy.
17
17
 
18
18
  ```
19
19
  git clone https://github.com/contributor/jbuilder.git
@@ -95,7 +95,7 @@ git push origin my-feature-branch -f
95
95
 
96
96
  #### Check on Your Pull Request
97
97
 
98
- Go back to your pull request after a few minutes and see whether it passed muster with Travis-CI. Everything should look green, otherwise fix issues and amend your commit as described above.
98
+ Go back to your pull request after a few minutes and see whether it passed muster with GitHub Actions. Everything should look green, otherwise fix issues and amend your commit as described above.
99
99
 
100
100
  #### Be Patient
101
101
 
data/README.md CHANGED
@@ -108,6 +108,32 @@ json.array! @people, :id, :name
108
108
  # => [ { "id": 1, "name": "David" }, { "id": 2, "name": "Jamie" } ]
109
109
  ```
110
110
 
111
+ To make a plain array without keys, construct and pass in a standard Ruby array.
112
+
113
+ ``` ruby
114
+ my_array = %w(David Jamie)
115
+
116
+ json.people my_array
117
+
118
+ # => "people": [ "David", "Jamie" ]
119
+
120
+ You don't always have or need a collection when building an array.
121
+
122
+ ```ruby
123
+ json.people do
124
+ json.child! do
125
+ json.id 1
126
+ json.name 'David'
127
+ end
128
+ json.child! do
129
+ json.id 2
130
+ json.name 'Jamie'
131
+ end
132
+ end
133
+
134
+ # => { "people": [ { "id": 1, "name": "David" }, { "id": 2, "name": "Jamie" } ] }
135
+ ```
136
+
111
137
  Jbuilder objects can be directly nested inside each other. Useful for composing objects.
112
138
 
113
139
  ``` ruby
@@ -137,7 +163,7 @@ company.to_builder.target!
137
163
  ```
138
164
 
139
165
  You can either use Jbuilder stand-alone or directly as an ActionView template
140
- language. When required in Rails, you can create views a la show.json.jbuilder
166
+ language. When required in Rails, you can create views à la show.json.jbuilder
141
167
  (the json is already yielded):
142
168
 
143
169
  ``` ruby
@@ -171,19 +197,19 @@ It's also possible to render collections of partials:
171
197
  json.array! @posts, partial: 'posts/post', as: :post
172
198
 
173
199
  # or
174
-
175
200
  json.partial! 'posts/post', collection: @posts, as: :post
176
201
 
177
202
  # or
178
-
179
203
  json.partial! partial: 'posts/post', collection: @posts, as: :post
180
204
 
181
205
  # or
182
-
183
206
  json.comments @post.comments, partial: 'comments/comment', as: :comment
184
207
  ```
185
208
 
186
- The `as: :some_symbol` is used with partials. It will take care of mapping the passed in object to a variable for the partial. If the value is a collection (either implicitly or explicitly by using the `collection:` option, then each value of the collection is passed to the partial as the variable `some_symbol`. If the value is a singular object, then the object is passed to the partial as the variable `some_symbol`.
209
+ The `as: :some_symbol` is used with partials. It will take care of mapping the passed in object to a variable for the
210
+ partial. If the value is a collection either implicitly or explicitly by using the `collection:` option, then each
211
+ value of the collection is passed to the partial as the variable `some_symbol`. If the value is a singular object,
212
+ then the object is passed to the partial as the variable `some_symbol`.
187
213
 
188
214
  Be sure not to confuse the `as:` option to mean nesting of the partial. For example:
189
215
 
@@ -193,7 +219,7 @@ Be sure not to confuse the `as:` option to mean nesting of the partial. For exam
193
219
  json.partial! @comment, as: :comment
194
220
  ```
195
221
 
196
- is quite different than:
222
+ is quite different from:
197
223
 
198
224
  ```ruby
199
225
  # comment attributes are nested under a "comment" property
@@ -236,6 +262,8 @@ json.bar "bar"
236
262
  # => { "bar": "bar" }
237
263
  ```
238
264
 
265
+ ## Caching
266
+
239
267
  Fragment caching is supported, it uses `Rails.cache` and works like caching in
240
268
  HTML templates:
241
269
 
@@ -253,9 +281,17 @@ json.cache_if! !admin?, ['v1', @person], expires_in: 10.minutes do
253
281
  end
254
282
  ```
255
283
 
256
- If you are rendering fragments for a collection of objects, have a look at
257
- `jbuilder_cache_multi` gem. It uses fetch_multi (>= Rails 4.1) to fetch
258
- multiple keys at once.
284
+ Aside from that, the `:cached` options on collection rendering is available on Rails >= 6.0. This will cache the
285
+ rendered results effectively using the multi fetch feature.
286
+
287
+ ```
288
+ json.array! @posts, partial: "posts/post", as: :post, cached: true
289
+
290
+ # or:
291
+ json.comments @post.comments, partial: "comments/comment", as: :comment, cached: true
292
+ ```
293
+
294
+ ## Formatting Keys
259
295
 
260
296
  Keys can be auto formatted using `key_format!`, this can be used to convert
261
297
  keynames from the standard ruby_format to camelCase:
@@ -274,6 +310,25 @@ environment.rb for example):
274
310
  Jbuilder.key_format camelize: :lower
275
311
  ```
276
312
 
313
+ By default, key format is not applied to keys of hashes that are
314
+ passed to methods like `set!`, `array!` or `merge!`. You can opt into
315
+ deeply transforming these as well:
316
+
317
+ ``` ruby
318
+ json.key_format! camelize: :lower
319
+ json.deep_format_keys!
320
+ json.settings([{some_value: "abc"}])
321
+
322
+ # => { "settings": [{ "someValue": "abc" }]}
323
+ ```
324
+
325
+ You can set this globally with the class method `deep_format_keys` (from inside your
326
+ environment.rb for example):
327
+
328
+ ``` ruby
329
+ Jbuilder.deep_format_keys true
330
+ ```
331
+
277
332
  ## Contributing to Jbuilder
278
333
 
279
334
  Jbuilder is the work of many contributors. You're encouraged to submit pull requests, propose
data/Rakefile CHANGED
@@ -2,7 +2,7 @@ require "bundler/setup"
2
2
  require "bundler/gem_tasks"
3
3
  require "rake/testtask"
4
4
 
5
- if !ENV["APPRAISAL_INITIALIZED"] && !ENV["TRAVIS"]
5
+ if !ENV["APPRAISAL_INITIALIZED"] && !ENV["CI"]
6
6
  require "appraisal/task"
7
7
  Appraisal::Task.new
8
8
  task default: :appraisal
@@ -0,0 +1,10 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "rake"
6
+ gem "mocha", :require => false
7
+ gem "appraisal"
8
+ gem "rails", "~> 6.1.0"
9
+
10
+ gemspec :path => "../"
@@ -5,6 +5,6 @@ source "https://rubygems.org"
5
5
  gem "rake"
6
6
  gem "mocha", require: false
7
7
  gem "appraisal"
8
- gem "rails", github: "rails/rails"
8
+ gem "rails", github: "rails/rails", branch: "main"
9
9
 
10
10
  gemspec path: "../"
data/jbuilder.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'jbuilder'
3
- s.version = '2.10.2'
3
+ s.version = '2.11.3'
4
4
  s.authors = 'David Heinemeier Hansson'
5
5
  s.email = 'david@basecamp.com'
6
6
  s.summary = 'Create JSON structures via a Builder-style DSL'
@@ -50,6 +50,10 @@ module Rails
50
50
 
51
51
  attributes.map { |a| ":#{a}"} * ', '
52
52
  end
53
+
54
+ def virtual_attributes
55
+ attributes.select {|name| name.respond_to?(:virtual?) && name.virtual? }
56
+ end
53
57
  end
54
58
  end
55
59
  end
@@ -4,7 +4,7 @@ require_dependency "<%= namespaced_path %>/application_controller"
4
4
  <% end -%>
5
5
  <% module_namespacing do -%>
6
6
  class <%= controller_class_name %>Controller < ApplicationController
7
- before_action :set_<%= singular_table_name %>, only: %w[ show update destroy ]
7
+ before_action :set_<%= singular_table_name %>, only: %i[ show update destroy ]
8
8
 
9
9
  # GET <%= route_url %>
10
10
  # GET <%= route_url %>.json
@@ -4,16 +4,14 @@ require_dependency "<%= namespaced_path %>/application_controller"
4
4
  <% end -%>
5
5
  <% module_namespacing do -%>
6
6
  class <%= controller_class_name %>Controller < ApplicationController
7
- before_action :set_<%= singular_table_name %>, only: %w[ show edit update destroy ]
7
+ before_action :set_<%= singular_table_name %>, only: %i[ show edit update destroy ]
8
8
 
9
- # GET <%= route_url %>
10
- # GET <%= route_url %>.json
9
+ # GET <%= route_url %> or <%= route_url %>.json
11
10
  def index
12
11
  @<%= plural_table_name %> = <%= orm_class.all(class_name) %>
13
12
  end
14
13
 
15
- # GET <%= route_url %>/1
16
- # GET <%= route_url %>/1.json
14
+ # GET <%= route_url %>/1 or <%= route_url %>/1.json
17
15
  def show
18
16
  end
19
17
 
@@ -26,8 +24,7 @@ class <%= controller_class_name %>Controller < ApplicationController
26
24
  def edit
27
25
  end
28
26
 
29
- # POST <%= route_url %>
30
- # POST <%= route_url %>.json
27
+ # POST <%= route_url %> or <%= route_url %>.json
31
28
  def create
32
29
  @<%= singular_table_name %> = <%= orm_class.build(class_name, "#{singular_table_name}_params") %>
33
30
 
@@ -42,8 +39,7 @@ class <%= controller_class_name %>Controller < ApplicationController
42
39
  end
43
40
  end
44
41
 
45
- # PATCH/PUT <%= route_url %>/1
46
- # PATCH/PUT <%= route_url %>/1.json
42
+ # PATCH/PUT <%= route_url %>/1 or <%= route_url %>/1.json
47
43
  def update
48
44
  respond_to do |format|
49
45
  if @<%= orm_instance.update("#{singular_table_name}_params") %>
@@ -56,8 +52,7 @@ class <%= controller_class_name %>Controller < ApplicationController
56
52
  end
57
53
  end
58
54
 
59
- # DELETE <%= route_url %>/1
60
- # DELETE <%= route_url %>/1.json
55
+ # DELETE <%= route_url %>/1 or <%= route_url %>/1.json
61
56
  def destroy
62
57
  @<%= orm_instance.destroy %>
63
58
  respond_to do |format|
@@ -1,2 +1,16 @@
1
1
  json.extract! <%= singular_table_name %>, <%= full_attributes_list %>
2
2
  json.url <%= singular_table_name %>_url(<%= singular_table_name %>, format: :json)
3
+ <%- virtual_attributes.each do |attribute| -%>
4
+ <%- if attribute.type == :rich_text -%>
5
+ json.<%= attribute.name %> <%= singular_table_name %>.<%= attribute.name %>.to_s
6
+ <%- elsif attribute.type == :attachment -%>
7
+ json.<%= attribute.name %> url_for(<%= singular_table_name %>.<%= attribute.name %>)
8
+ <%- elsif attribute.type == :attachments -%>
9
+ json.<%= attribute.name %> do
10
+ json.array!(<%= singular_table_name %>.<%= attribute.name %>) do |<%= attribute.singular_name %>|
11
+ json.id <%= attribute.singular_name %>.id
12
+ json.url url_for(<%= attribute.singular_name %>)
13
+ end
14
+ end
15
+ <%- end -%>
16
+ <%- end -%>
@@ -0,0 +1,108 @@
1
+ require 'delegate'
2
+ require 'active_support/concern'
3
+
4
+ begin
5
+ require 'action_view/renderer/collection_renderer'
6
+ rescue LoadError
7
+ require 'action_view/renderer/partial_renderer'
8
+ end
9
+
10
+ class Jbuilder
11
+ module CollectionRenderable # :nodoc:
12
+ extend ActiveSupport::Concern
13
+
14
+ class_methods do
15
+ def supported?
16
+ superclass.private_method_defined?(:build_rendered_template) && self.superclass.private_method_defined?(:build_rendered_collection)
17
+ end
18
+ end
19
+
20
+ private
21
+
22
+ def build_rendered_template(content, template, layout = nil)
23
+ super(content || json.attributes!, template)
24
+ end
25
+
26
+ def build_rendered_collection(templates, _spacer)
27
+ json.merge!(templates.map(&:body))
28
+ end
29
+
30
+ def json
31
+ @options[:locals].fetch(:json)
32
+ end
33
+
34
+ class ScopedIterator < ::SimpleDelegator # :nodoc:
35
+ include Enumerable
36
+
37
+ def initialize(obj, scope)
38
+ super(obj)
39
+ @scope = scope
40
+ end
41
+
42
+ # Rails 6.0 support:
43
+ def each
44
+ return enum_for(:each) unless block_given?
45
+
46
+ __getobj__.each do |object|
47
+ @scope.call { yield(object) }
48
+ end
49
+ end
50
+
51
+ # Rails 6.1 support:
52
+ def each_with_info
53
+ return enum_for(:each_with_info) unless block_given?
54
+
55
+ __getobj__.each_with_info do |object, info|
56
+ @scope.call { yield(object, info) }
57
+ end
58
+ end
59
+ end
60
+
61
+ private_constant :ScopedIterator
62
+ end
63
+
64
+ if defined?(::ActionView::CollectionRenderer)
65
+ # Rails 6.1 support:
66
+ class CollectionRenderer < ::ActionView::CollectionRenderer # :nodoc:
67
+ include CollectionRenderable
68
+
69
+ def initialize(lookup_context, options, &scope)
70
+ super(lookup_context, options)
71
+ @scope = scope
72
+ end
73
+
74
+ private
75
+ def collection_with_template(view, template, layout, collection)
76
+ super(view, template, layout, ScopedIterator.new(collection, @scope))
77
+ end
78
+ end
79
+ else
80
+ # Rails 6.0 support:
81
+ class CollectionRenderer < ::ActionView::PartialRenderer # :nodoc:
82
+ include CollectionRenderable
83
+
84
+ def initialize(lookup_context, options, &scope)
85
+ super(lookup_context)
86
+ @options = options
87
+ @scope = scope
88
+ end
89
+
90
+ def render_collection_with_partial(collection, partial, context, block)
91
+ render(context, @options.merge(collection: collection, partial: partial), block)
92
+ end
93
+
94
+ private
95
+ def collection_without_template(view)
96
+ @collection = ScopedIterator.new(@collection, @scope)
97
+
98
+ super(view)
99
+ end
100
+
101
+ def collection_with_template(view, template)
102
+ @collection = ScopedIterator.new(@collection, @scope)
103
+
104
+ super(view, template)
105
+ end
106
+ end
107
+ end
108
+ end
@@ -1,4 +1,5 @@
1
1
  require 'jbuilder/jbuilder'
2
+ require 'jbuilder/collection_renderer'
2
3
  require 'action_dispatch/http/mime_type'
3
4
  require 'active_support/cache'
4
5
 
@@ -15,6 +16,38 @@ class JbuilderTemplate < Jbuilder
15
16
  super(*args)
16
17
  end
17
18
 
19
+ # Generates JSON using the template specified with the `:partial` option. For example, the code below will render
20
+ # the file `views/comments/_comments.json.jbuilder`, and set a local variable comments with all this message's
21
+ # comments, which can be used inside the partial.
22
+ #
23
+ # Example:
24
+ #
25
+ # json.partial! 'comments/comments', comments: @message.comments
26
+ #
27
+ # There are multiple ways to generate a collection of elements as JSON, as ilustrated below:
28
+ #
29
+ # Example:
30
+ #
31
+ # json.array! @posts, partial: 'posts/post', as: :post
32
+ #
33
+ # # or:
34
+ # json.partial! 'posts/post', collection: @posts, as: :post
35
+ #
36
+ # # or:
37
+ # json.partial! partial: 'posts/post', collection: @posts, as: :post
38
+ #
39
+ # # or:
40
+ # json.comments @post.comments, partial: 'comments/comment', as: :comment
41
+ #
42
+ # Aside from that, the `:cached` options is available on Rails >= 6.0. This will cache the rendered results
43
+ # effectively using the multi fetch feature.
44
+ #
45
+ # Example:
46
+ #
47
+ # json.array! @posts, partial: "posts/post", as: :post, cached: true
48
+ #
49
+ # json.comments @post.comments, partial: "comments/comment", as: :comment, cached: true
50
+ #
18
51
  def partial!(*args)
19
52
  if args.one? && _is_active_model?(args.first)
20
53
  _render_active_model_partial args.first
@@ -104,11 +137,30 @@ class JbuilderTemplate < Jbuilder
104
137
  private
105
138
 
106
139
  def _render_partial_with_options(options)
107
- options.reverse_merge! locals: options.except(:partial, :as, :collection)
140
+ options.reverse_merge! locals: options.except(:partial, :as, :collection, :cached)
108
141
  options.reverse_merge! ::JbuilderTemplate.template_lookup_options
109
142
  as = options[:as]
110
143
 
111
- if as && options.key?(:collection)
144
+ if options.key?(:collection) && (options[:collection].nil? || options[:collection].empty?)
145
+ array!
146
+ elsif as && options.key?(:collection) && CollectionRenderer.supported?
147
+ collection = options.delete(:collection) || []
148
+ partial = options.delete(:partial)
149
+ options[:locals].merge!(json: self)
150
+
151
+ if options.has_key?(:layout)
152
+ raise ::NotImplementedError, "The `:layout' option is not supported in collection rendering."
153
+ end
154
+
155
+ if options.has_key?(:spacer_template)
156
+ raise ::NotImplementedError, "The `:spacer_template' option is not supported in collection rendering."
157
+ end
158
+
159
+ CollectionRenderer
160
+ .new(@context.lookup_context, options) { |&block| _scope(&block) }
161
+ .render_collection_with_partial(collection, partial, @context, nil)
162
+ elsif as && options.key?(:collection) && !CollectionRenderer.supported?
163
+ # For Rails <= 5.2:
112
164
  as = as.to_sym
113
165
  collection = options.delete(:collection)
114
166
  locals = options.delete(:locals)
@@ -162,12 +214,7 @@ class JbuilderTemplate < Jbuilder
162
214
 
163
215
  def _fragment_name_with_digest(key, options)
164
216
  if @context.respond_to?(:cache_fragment_name)
165
- # Current compatibility, fragment_name_with_digest is private again and cache_fragment_name
166
- # should be used instead.
167
217
  @context.cache_fragment_name(key, **options)
168
- elsif @context.respond_to?(:fragment_name_with_digest)
169
- # Backwards compatibility for period of time when fragment_name_with_digest was made public.
170
- @context.fragment_name_with_digest(key)
171
218
  else
172
219
  key
173
220
  end
data/lib/jbuilder.rb CHANGED
@@ -9,12 +9,14 @@ require 'active_support/core_ext/hash/deep_merge'
9
9
  class Jbuilder
10
10
  @@key_formatter = nil
11
11
  @@ignore_nil = false
12
+ @@deep_format_keys = false
12
13
 
13
14
  def initialize(options = {})
14
15
  @attributes = {}
15
16
 
16
17
  @key_formatter = options.fetch(:key_formatter){ @@key_formatter ? @@key_formatter.clone : nil}
17
18
  @ignore_nil = options.fetch(:ignore_nil, @@ignore_nil)
19
+ @deep_format_keys = options.fetch(:deep_format_keys, @@deep_format_keys)
18
20
 
19
21
  yield self if ::Kernel.block_given?
20
22
  end
@@ -43,11 +45,11 @@ class Jbuilder
43
45
  # json.age 32
44
46
  # json.person another_jbuilder
45
47
  # { "age": 32, "person": { ... }
46
- value.attributes!
48
+ _format_keys(value.attributes!)
47
49
  else
48
50
  # json.age 32
49
51
  # { "age": 32 }
50
- value
52
+ _format_keys(value)
51
53
  end
52
54
  elsif _is_collection?(value)
53
55
  # json.comments @post.comments, :content, :created_at
@@ -131,6 +133,31 @@ class Jbuilder
131
133
  @@ignore_nil = value
132
134
  end
133
135
 
136
+ # Deeply apply key format to nested hashes and arrays passed to
137
+ # methods like set!, merge! or array!.
138
+ #
139
+ # Example:
140
+ #
141
+ # json.key_format! camelize: :lower
142
+ # json.settings({some_value: "abc"})
143
+ #
144
+ # { "settings": { "some_value": "abc" }}
145
+ #
146
+ # json.key_format! camelize: :lower
147
+ # json.deep_format_keys!
148
+ # json.settings({some_value: "abc"})
149
+ #
150
+ # { "settings": { "someValue": "abc" }}
151
+ #
152
+ def deep_format_keys!(value = true)
153
+ @deep_format_keys = value
154
+ end
155
+
156
+ # Same as instance method deep_format_keys! except sets the default.
157
+ def self.deep_format_keys(value = true)
158
+ @@deep_format_keys = value
159
+ end
160
+
134
161
  # Turns the current element into an array and yields a builder to add a hash.
135
162
  #
136
163
  # Example:
@@ -190,10 +217,10 @@ class Jbuilder
190
217
  elsif attributes.any?
191
218
  _map_collection(collection) { |element| extract! element, *attributes }
192
219
  else
193
- collection.to_a
220
+ _format_keys(collection.to_a)
194
221
  end
195
222
 
196
- merge! array
223
+ @attributes = _merge_values(@attributes, array)
197
224
  end
198
225
 
199
226
  # Extracts the mentioned attributes or hash elements from the passed object and turns them into attributes of the JSON.
@@ -241,9 +268,10 @@ class Jbuilder
241
268
  @attributes
242
269
  end
243
270
 
244
- # Merges hash or array into current builder.
245
- def merge!(hash_or_array)
246
- @attributes = _merge_values(@attributes, hash_or_array)
271
+ # Merges hash, array, or Jbuilder instance into current builder.
272
+ def merge!(object)
273
+ hash_or_array = ::Jbuilder === object ? object.attributes! : object
274
+ @attributes = _merge_values(@attributes, _format_keys(hash_or_array))
247
275
  end
248
276
 
249
277
  # Encodes the current builder as JSON.
@@ -254,11 +282,11 @@ class Jbuilder
254
282
  private
255
283
 
256
284
  def _extract_hash_values(object, attributes)
257
- attributes.each{ |key| _set_value key, object.fetch(key) }
285
+ attributes.each{ |key| _set_value key, _format_keys(object.fetch(key)) }
258
286
  end
259
287
 
260
288
  def _extract_method_values(object, attributes)
261
- attributes.each{ |key| _set_value key, object.public_send(key) }
289
+ attributes.each{ |key| _set_value key, _format_keys(object.public_send(key)) }
262
290
  end
263
291
 
264
292
  def _merge_block(key)
@@ -286,6 +314,18 @@ class Jbuilder
286
314
  @key_formatter ? @key_formatter.format(key) : key.to_s
287
315
  end
288
316
 
317
+ def _format_keys(hash_or_array)
318
+ return hash_or_array unless @deep_format_keys
319
+
320
+ if ::Array === hash_or_array
321
+ hash_or_array.map { |value| _format_keys(value) }
322
+ elsif ::Hash === hash_or_array
323
+ ::Hash[hash_or_array.collect { |k, v| [_key(k), _format_keys(v)] }]
324
+ else
325
+ hash_or_array
326
+ end
327
+ end
328
+
289
329
  def _set_value(key, value)
290
330
  raise NullError.build(key) if @attributes.nil?
291
331
  raise ArrayError.build(key) if ::Array === @attributes
@@ -301,12 +341,12 @@ class Jbuilder
301
341
  end
302
342
 
303
343
  def _scope
304
- parent_attributes, parent_formatter = @attributes, @key_formatter
344
+ parent_attributes, parent_formatter, parent_deep_format_keys = @attributes, @key_formatter, @deep_format_keys
305
345
  @attributes = BLANK
306
346
  yield
307
347
  @attributes
308
348
  ensure
309
- @attributes, @key_formatter = parent_attributes, parent_formatter
349
+ @attributes, @key_formatter, @deep_format_keys = parent_attributes, parent_formatter, parent_deep_format_keys
310
350
  end
311
351
 
312
352
  def _is_collection?(object)
@@ -61,7 +61,7 @@ class JbuilderDependencyTrackerTest < ActiveSupport::TestCase
61
61
  assert_equal %w[comments/comment], dependencies
62
62
  end
63
63
 
64
- test 'detects explicit depedency' do
64
+ test 'detects explicit dependency' do
65
65
  dependencies = track_dependencies <<-RUBY
66
66
  # Template Dependency: path/to/partial
67
67
  json.foo 'bar'
@@ -43,4 +43,16 @@ class JbuilderGeneratorTest < Rails::Generators::TestCase
43
43
  assert_no_match %r{:created_at, :updated_at}, content
44
44
  end
45
45
  end
46
+
47
+ if Rails::VERSION::MAJOR >= 6
48
+ test 'handles virtual attributes' do
49
+ run_generator %w(Message content:rich_text video:attachment photos:attachments)
50
+
51
+ assert_file 'app/views/messages/_message.json.jbuilder' do |content|
52
+ assert_match %r{json\.content message\.content\.to_s}, content
53
+ assert_match %r{json\.video url_for\(message\.video\)}, content
54
+ assert_match %r{json\.photos do\n json\.array!\(message\.photos\) do \|photo\|\n json\.id photo\.id\n json\.url url_for\(photo\)\n end\nend}, content
55
+ end
56
+ end
57
+ end
46
58
  end
@@ -159,7 +159,7 @@ class JbuilderTemplateTest < ActiveSupport::TestCase
159
159
  end
160
160
 
161
161
  test "object fragment caching with expiry" do
162
- travel_to "2018-05-12 11:29:00 -0400"
162
+ travel_to Time.iso8601("2018-05-12T11:29:00-04:00")
163
163
 
164
164
  render <<-JBUILDER
165
165
  json.cache! "cache-key", expires_in: 1.minute do
@@ -283,6 +283,58 @@ class JbuilderTemplateTest < ActiveSupport::TestCase
283
283
  assert_equal "David", result["firstName"]
284
284
  end
285
285
 
286
+ if JbuilderTemplate::CollectionRenderer.supported?
287
+ test "returns an empty array for an empty collection" do
288
+ result = render('json.array! @posts, partial: "post", as: :post, cached: true', posts: [])
289
+
290
+ # Do not use #assert_empty as it is important to ensure that the type of the JSON result is an array.
291
+ assert_equal [], result
292
+ end
293
+
294
+ test "supports the cached: true option" do
295
+ result = render('json.array! @posts, partial: "post", as: :post, cached: true', posts: POSTS)
296
+
297
+ assert_equal 10, result.count
298
+ assert_equal "Post #5", result[4]["body"]
299
+ assert_equal "Heinemeier Hansson", result[2]["author"]["last_name"]
300
+ assert_equal "Pavel", result[5]["author"]["first_name"]
301
+
302
+ expected = {
303
+ "id" => 1,
304
+ "body" => "Post #1",
305
+ "author" => {
306
+ "first_name" => "David",
307
+ "last_name" => "Heinemeier Hansson"
308
+ }
309
+ }
310
+
311
+ assert_equal expected, Rails.cache.read("post-1")
312
+
313
+ result = render('json.array! @posts, partial: "post", as: :post, cached: true', posts: POSTS)
314
+
315
+ assert_equal 10, result.count
316
+ assert_equal "Post #5", result[4]["body"]
317
+ assert_equal "Heinemeier Hansson", result[2]["author"]["last_name"]
318
+ assert_equal "Pavel", result[5]["author"]["first_name"]
319
+ end
320
+
321
+ test "raises an error on a render call with the :layout option" do
322
+ error = assert_raises NotImplementedError do
323
+ render('json.array! @posts, partial: "post", as: :post, layout: "layout"', posts: POSTS)
324
+ end
325
+
326
+ assert_equal "The `:layout' option is not supported in collection rendering.", error.message
327
+ end
328
+
329
+ test "raises an error on a render call with the :spacer_template option" do
330
+ error = assert_raises NotImplementedError do
331
+ render('json.array! @posts, partial: "post", as: :post, spacer_template: "template"', posts: POSTS)
332
+ end
333
+
334
+ assert_equal "The `:spacer_template' option is not supported in collection rendering.", error.message
335
+ end
336
+ end
337
+
286
338
  private
287
339
  def render(*args)
288
340
  JSON.load render_without_parsing(*args)
@@ -290,7 +342,7 @@ class JbuilderTemplateTest < ActiveSupport::TestCase
290
342
 
291
343
  def render_without_parsing(source, assigns = {})
292
344
  view = build_view(fixtures: PARTIALS.merge("source.json.jbuilder" => source), assigns: assigns)
293
- view.render(template: "source.json.jbuilder")
345
+ view.render(template: "source")
294
346
  end
295
347
 
296
348
  def build_view(options = {})
@@ -306,6 +358,9 @@ class JbuilderTemplateTest < ActiveSupport::TestCase
306
358
  end
307
359
 
308
360
  def view.view_cache_dependencies; []; end
361
+ def view.combined_fragment_cache_key(key) [ key ] end
362
+ def view.cache_fragment_name(key, *) key end
363
+ def view.fragment_name_with_digest(key) key end
309
364
 
310
365
  view
311
366
  end
@@ -196,6 +196,18 @@ class JbuilderTest < ActiveSupport::TestCase
196
196
  assert_equal 'Pavel', result['author']['name']
197
197
  end
198
198
 
199
+ test 'support merge! method with Jbuilder instance' do
200
+ obj = jbuild do |json|
201
+ json.foo 'bar'
202
+ end
203
+
204
+ result = jbuild do |json|
205
+ json.merge! obj
206
+ end
207
+
208
+ assert_equal 'bar', result['foo']
209
+ end
210
+
199
211
  test 'blocks are additive via extract syntax' do
200
212
  person = Person.new('Pavel', 27)
201
213
 
@@ -300,7 +312,7 @@ class JbuilderTest < ActiveSupport::TestCase
300
312
  assert_equal 'world', result['comments'].second['content']
301
313
  end
302
314
 
303
- test 'nesting multiple chilren from a non-Enumerable that responds to #map with inline loop' do
315
+ test 'nesting multiple children from a non-Enumerable that responds to #map with inline loop' do
304
316
  comments = NonEnumerable.new([ Comment.new('hello', 1), Comment.new('world', 2) ])
305
317
 
306
318
  result = jbuild do |json|
@@ -554,6 +566,36 @@ class JbuilderTest < ActiveSupport::TestCase
554
566
  assert_equal 'one', result['level1']
555
567
  end
556
568
 
569
+ test 'key_format! can be changed in child elements' do
570
+ result = jbuild do |json|
571
+ json.key_format! camelize: :lower
572
+
573
+ json.level_one do
574
+ json.key_format! :upcase
575
+ json.value 'two'
576
+ end
577
+ end
578
+
579
+ assert_equal ['levelOne'], result.keys
580
+ assert_equal ['VALUE'], result['levelOne'].keys
581
+ end
582
+
583
+ test 'key_format! can be changed in array!' do
584
+ result = jbuild do |json|
585
+ json.key_format! camelize: :lower
586
+
587
+ json.level_one do
588
+ json.array! [{value: 'two'}] do |object|
589
+ json.key_format! :upcase
590
+ json.value object[:value]
591
+ end
592
+ end
593
+ end
594
+
595
+ assert_equal ['levelOne'], result.keys
596
+ assert_equal ['VALUE'], result['levelOne'][0].keys
597
+ end
598
+
557
599
  test 'key_format! with no parameter' do
558
600
  result = jbuild do |json|
559
601
  json.key_format! :upcase
@@ -581,6 +623,161 @@ class JbuilderTest < ActiveSupport::TestCase
581
623
  assert_equal ['oats and friends'], result.keys
582
624
  end
583
625
 
626
+ test 'key_format! is not applied deeply by default' do
627
+ names = { first_name: 'camel', last_name: 'case' }
628
+ result = jbuild do |json|
629
+ json.key_format! camelize: :lower
630
+ json.set! :all_names, names
631
+ end
632
+
633
+ assert_equal %i[first_name last_name], result['allNames'].keys
634
+ end
635
+
636
+ test 'applying key_format! deeply can be enabled per scope' do
637
+ names = { first_name: 'camel', last_name: 'case' }
638
+ result = jbuild do |json|
639
+ json.key_format! camelize: :lower
640
+ json.scope do
641
+ json.deep_format_keys!
642
+ json.set! :all_names, names
643
+ end
644
+ json.set! :all_names, names
645
+ end
646
+
647
+ assert_equal %w[firstName lastName], result['scope']['allNames'].keys
648
+ assert_equal %i[first_name last_name], result['allNames'].keys
649
+ end
650
+
651
+ test 'applying key_format! deeply can be disabled per scope' do
652
+ names = { first_name: 'camel', last_name: 'case' }
653
+ result = jbuild do |json|
654
+ json.key_format! camelize: :lower
655
+ json.deep_format_keys!
656
+ json.set! :all_names, names
657
+ json.scope do
658
+ json.deep_format_keys! false
659
+ json.set! :all_names, names
660
+ end
661
+ end
662
+
663
+ assert_equal %w[firstName lastName], result['allNames'].keys
664
+ assert_equal %i[first_name last_name], result['scope']['allNames'].keys
665
+ end
666
+
667
+ test 'applying key_format! deeply can be enabled globally' do
668
+ names = { first_name: 'camel', last_name: 'case' }
669
+
670
+ Jbuilder.deep_format_keys true
671
+ result = jbuild do |json|
672
+ json.key_format! camelize: :lower
673
+ json.set! :all_names, names
674
+ end
675
+
676
+ assert_equal %w[firstName lastName], result['allNames'].keys
677
+ Jbuilder.send(:class_variable_set, '@@deep_format_keys', false)
678
+ end
679
+
680
+ test 'deep key_format! with merge!' do
681
+ hash = { camel_style: 'for JS' }
682
+ result = jbuild do |json|
683
+ json.key_format! camelize: :lower
684
+ json.deep_format_keys!
685
+ json.merge! hash
686
+ end
687
+
688
+ assert_equal ['camelStyle'], result.keys
689
+ end
690
+
691
+ test 'deep key_format! with merge! deep' do
692
+ hash = { camel_style: { sub_attr: 'for JS' } }
693
+ result = jbuild do |json|
694
+ json.key_format! camelize: :lower
695
+ json.deep_format_keys!
696
+ json.merge! hash
697
+ end
698
+
699
+ assert_equal ['subAttr'], result['camelStyle'].keys
700
+ end
701
+
702
+ test 'deep key_format! with set! array of hashes' do
703
+ names = [{ first_name: 'camel', last_name: 'case' }]
704
+ result = jbuild do |json|
705
+ json.key_format! camelize: :lower
706
+ json.deep_format_keys!
707
+ json.set! :names, names
708
+ end
709
+
710
+ assert_equal %w[firstName lastName], result['names'][0].keys
711
+ end
712
+
713
+ test 'deep key_format! with set! extracting hash from object' do
714
+ comment = Struct.new(:author).new({ first_name: 'camel', last_name: 'case' })
715
+ result = jbuild do |json|
716
+ json.key_format! camelize: :lower
717
+ json.deep_format_keys!
718
+ json.set! :comment, comment, :author
719
+ end
720
+
721
+ assert_equal %w[firstName lastName], result['comment']['author'].keys
722
+ end
723
+
724
+ test 'deep key_format! with array! of hashes' do
725
+ names = [{ first_name: 'camel', last_name: 'case' }]
726
+ result = jbuild do |json|
727
+ json.key_format! camelize: :lower
728
+ json.deep_format_keys!
729
+ json.array! names
730
+ end
731
+
732
+ assert_equal %w[firstName lastName], result[0].keys
733
+ end
734
+
735
+ test 'deep key_format! with merge! array of hashes' do
736
+ names = [{ first_name: 'camel', last_name: 'case' }]
737
+ new_names = [{ first_name: 'snake', last_name: 'case' }]
738
+ result = jbuild do |json|
739
+ json.key_format! camelize: :lower
740
+ json.deep_format_keys!
741
+ json.array! names
742
+ json.merge! new_names
743
+ end
744
+
745
+ assert_equal %w[firstName lastName], result[1].keys
746
+ end
747
+
748
+ test 'deep key_format! is applied to hash extracted from object' do
749
+ comment = Struct.new(:author).new({ first_name: 'camel', last_name: 'case' })
750
+ result = jbuild do |json|
751
+ json.key_format! camelize: :lower
752
+ json.deep_format_keys!
753
+ json.extract! comment, :author
754
+ end
755
+
756
+ assert_equal %w[firstName lastName], result['author'].keys
757
+ end
758
+
759
+ test 'deep key_format! is applied to hash extracted from hash' do
760
+ comment = {author: { first_name: 'camel', last_name: 'case' }}
761
+ result = jbuild do |json|
762
+ json.key_format! camelize: :lower
763
+ json.deep_format_keys!
764
+ json.extract! comment, :author
765
+ end
766
+
767
+ assert_equal %w[firstName lastName], result['author'].keys
768
+ end
769
+
770
+ test 'deep key_format! is applied to hash extracted directly from array' do
771
+ comments = [Struct.new(:author).new({ first_name: 'camel', last_name: 'case' })]
772
+ result = jbuild do |json|
773
+ json.key_format! camelize: :lower
774
+ json.deep_format_keys!
775
+ json.array! comments, :author
776
+ end
777
+
778
+ assert_equal %w[firstName lastName], result[0]['author'].keys
779
+ end
780
+
584
781
  test 'default key_format!' do
585
782
  Jbuilder.key_format camelize: :lower
586
783
  result = jbuild{ |json| json.camel_style 'for JS' }
@@ -47,7 +47,7 @@ if Rails::VERSION::MAJOR > 4
47
47
  end
48
48
  end
49
49
 
50
- test 'dont use require and permit if there are no attributes' do
50
+ test "don't use require and permit if there are no attributes" do
51
51
  run_generator %w(Post --api)
52
52
 
53
53
  assert_file 'app/controllers/posts_controller.rb' do |content|
@@ -55,5 +55,16 @@ if Rails::VERSION::MAJOR > 4
55
55
  assert_match %r{params\.fetch\(:post, \{\}\)}, content
56
56
  end
57
57
  end
58
+
59
+
60
+ if Rails::VERSION::MAJOR >= 6
61
+ test 'handles virtual attributes' do
62
+ run_generator ["Message", "content:rich_text", "video:attachment", "photos:attachments"]
63
+
64
+ assert_file 'app/controllers/messages_controller.rb' do |content|
65
+ assert_match %r{params\.require\(:message\)\.permit\(:content, :video, photos: \[\]\)}, content
66
+ end
67
+ end
68
+ end
58
69
  end
59
70
  end
@@ -59,7 +59,7 @@ class ScaffoldControllerGeneratorTest < Rails::Generators::TestCase
59
59
  end
60
60
  end
61
61
 
62
- test 'dont use require and permit if there are no attributes' do
62
+ test "don't use require and permit if there are no attributes" do
63
63
  run_generator %w(Post)
64
64
 
65
65
  assert_file 'app/controllers/posts_controller.rb' do |content|
@@ -67,4 +67,14 @@ class ScaffoldControllerGeneratorTest < Rails::Generators::TestCase
67
67
  assert_match %r{params\.fetch\(:post, \{\}\)}, content
68
68
  end
69
69
  end
70
+
71
+ if Rails::VERSION::MAJOR >= 6
72
+ test 'handles virtual attributes' do
73
+ run_generator %w(Message content:rich_text video:attachment photos:attachments)
74
+
75
+ assert_file 'app/controllers/messages_controller.rb' do |content|
76
+ assert_match %r{params\.require\(:message\)\.permit\(:content, :video, photos: \[\]\)}, content
77
+ end
78
+ end
79
+ end
70
80
  end
data/test/test_helper.rb CHANGED
@@ -21,7 +21,13 @@ class << Rails
21
21
  end
22
22
  end
23
23
 
24
- class Post < Struct.new(:id, :body, :author_name); end
24
+ Jbuilder::CollectionRenderer.collection_cache = Rails.cache
25
+
26
+ class Post < Struct.new(:id, :body, :author_name)
27
+ def cache_key
28
+ "post-#{id}"
29
+ end
30
+ end
25
31
 
26
32
  class Racer < Struct.new(:id, :name)
27
33
  extend ActiveModel::Naming
@@ -29,6 +35,3 @@ class Racer < Struct.new(:id, :name)
29
35
  end
30
36
 
31
37
  ActionView::Template.register_template_handler :jbuilder, JbuilderHandler
32
-
33
- ActionView::Base.remove_possible_method :fragment_name_with_digest
34
- ActionView::Base.remove_possible_method :cache_fragment_name
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jbuilder
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.10.2
4
+ version: 2.11.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Heinemeier Hansson
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-01-22 00:00:00.000000000 Z
11
+ date: 2021-11-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -24,14 +24,14 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: 5.0.0
27
- description:
27
+ description:
28
28
  email: david@basecamp.com
29
29
  executables: []
30
30
  extensions: []
31
31
  extra_rdoc_files: []
32
32
  files:
33
+ - ".github/workflows/ruby.yml"
33
34
  - ".gitignore"
34
- - ".travis.yml"
35
35
  - Appraisals
36
36
  - CHANGELOG.md
37
37
  - CONTRIBUTING.md
@@ -43,6 +43,7 @@ files:
43
43
  - gemfiles/rails_5_1.gemfile
44
44
  - gemfiles/rails_5_2.gemfile
45
45
  - gemfiles/rails_6_0.gemfile
46
+ - gemfiles/rails_6_1.gemfile
46
47
  - gemfiles/rails_head.gemfile
47
48
  - jbuilder.gemspec
48
49
  - lib/generators/rails/jbuilder_generator.rb
@@ -54,6 +55,7 @@ files:
54
55
  - lib/generators/rails/templates/show.json.jbuilder
55
56
  - lib/jbuilder.rb
56
57
  - lib/jbuilder/blank.rb
58
+ - lib/jbuilder/collection_renderer.rb
57
59
  - lib/jbuilder/dependency_tracker.rb
58
60
  - lib/jbuilder/errors.rb
59
61
  - lib/jbuilder/jbuilder.rb
@@ -71,7 +73,7 @@ homepage: https://github.com/rails/jbuilder
71
73
  licenses:
72
74
  - MIT
73
75
  metadata: {}
74
- post_install_message:
76
+ post_install_message:
75
77
  rdoc_options: []
76
78
  require_paths:
77
79
  - lib
@@ -86,8 +88,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
86
88
  - !ruby/object:Gem::Version
87
89
  version: '0'
88
90
  requirements: []
89
- rubygems_version: 3.1.2
90
- signing_key:
91
+ rubygems_version: 3.2.22
92
+ signing_key:
91
93
  specification_version: 4
92
94
  summary: Create JSON structures via a Builder-style DSL
93
95
  test_files:
data/.travis.yml DELETED
@@ -1,52 +0,0 @@
1
- language: ruby
2
-
3
- cache: bundler
4
-
5
- before_install:
6
- - "gem install bundler -v '<2'"
7
-
8
- rvm:
9
- - 2.2.10
10
- - 2.3.8
11
- - 2.4.10
12
- - 2.5.8
13
- - 2.6.6
14
- - 2.7.1
15
- - ruby-head
16
-
17
- gemfile:
18
- - gemfiles/rails_5_0.gemfile
19
- - gemfiles/rails_5_1.gemfile
20
- - gemfiles/rails_5_2.gemfile
21
- - gemfiles/rails_6_0.gemfile
22
- - gemfiles/rails_head.gemfile
23
-
24
- matrix:
25
- exclude:
26
- - rvm: 2.7.1
27
- gemfile: gemfiles/rails_5_0.gemfile
28
- - rvm: 2.7.1
29
- gemfile: gemfiles/rails_5_1.gemfile
30
- - rvm: 2.2.10
31
- gemfile: gemfiles/rails_5_2.gemfile
32
- - rvm: 2.7.1
33
- gemfile: gemfiles/rails_5_2.gemfile
34
- - rvm: 2.2.10
35
- gemfile: gemfiles/rails_6_0.gemfile
36
- - rvm: 2.3.8
37
- gemfile: gemfiles/rails_6_0.gemfile
38
- - rvm: 2.4.10
39
- gemfile: gemfiles/rails_6_0.gemfile
40
- - rvm: 2.2.10
41
- gemfile: gemfiles/rails_head.gemfile
42
- - rvm: 2.3.8
43
- gemfile: gemfiles/rails_head.gemfile
44
- - rvm: 2.4.10
45
- gemfile: gemfiles/rails_head.gemfile
46
- allow_failures:
47
- - rvm: ruby-head
48
- - gemfile: gemfiles/rails_head.gemfile
49
- fast_finish: true
50
-
51
- notifications:
52
- email: false