jbuilder 2.9.0 → 2.11.0

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: 780a2d0395698145f0e1c9e96a7a2079b70def4be27846b74537ec90786b9495
4
- data.tar.gz: da6e2704a1060b023c7a78d4539ad39da447dba6e3d7c657834a81badcd47afa
3
+ metadata.gz: 8e18daf81b639ef039951269f0df24a2ffb0a4d6e93c05861eebef18c85a9039
4
+ data.tar.gz: db3ff93fbd28f3a67273b0afbae0962e5e2f49842901b3b2ade5bb3831b74d9b
5
5
  SHA512:
6
- metadata.gz: c088b1a55e41c650bccd49901ab964ac9b4b715bdab5d51d68a5b34b6a3bb18adcb37ade32548fa1f69ecd4d2cb29c8f34f747dd4af80daa4c8115e99bd80489
7
- data.tar.gz: 23e2b31830276ba589c941a484ac6d9b80dc0e3a0f4c4767f8d534f1bdfae5d9e76d1e75a31127103a045afba127c6eb2a7e87f35327860729ef7f08aafdd766
6
+ metadata.gz: b74be66e7ba0559d14c7032bfff001e9c9a49c657edab95de06c289eb3600945dea14c3efd9595b0c7da524d31f21c407c8f2b4541da308be8921951f94103e3
7
+ data.tar.gz: 8ae3e52031fd58c5de35fae022c9224c116d13a93c85990f5385511a8a914ce488f41b69676f94b54d3442942f3a30f79e460fdc78d84633261d239654505547
data/.gitignore CHANGED
@@ -1,5 +1,7 @@
1
1
  tmp
2
+ gemfiles/.bundle
2
3
  gemfiles/*.lock
3
4
  Gemfile.lock
4
5
  .ruby-version
5
6
  pkg
7
+ *.gem
@@ -3,55 +3,47 @@ language: ruby
3
3
  cache: bundler
4
4
 
5
5
  before_install:
6
- - "gem update --system 2.7.9"
7
6
  - "gem install bundler -v '<2'"
8
7
 
9
8
  rvm:
10
9
  - 2.2.10
11
10
  - 2.3.8
12
- - 2.4.6
13
- - 2.5.5
14
- - 2.6.2
11
+ - 2.4.10
12
+ - 2.5.8
13
+ - 2.6.6
14
+ - 2.7.1
15
15
  - ruby-head
16
- - rbx-3.107
17
16
 
18
17
  gemfile:
19
- - gemfiles/rails_4_2.gemfile
20
18
  - gemfiles/rails_5_0.gemfile
21
19
  - gemfiles/rails_5_1.gemfile
22
20
  - gemfiles/rails_5_2.gemfile
21
+ - gemfiles/rails_6_0.gemfile
23
22
  - gemfiles/rails_head.gemfile
24
23
 
25
24
  matrix:
26
- include:
27
- - rvm: 1.9
28
- gemfile: gemfiles/rails_4_2.gemfile
29
- - rvm: 2.0
30
- gemfile: gemfiles/rails_4_2.gemfile
31
- - rvm: 2.1
32
- gemfile: gemfiles/rails_4_2.gemfile
33
- - rvm: 2.3
34
- gemfile: gemfiles/rails_4_2.gemfile
35
- - rvm: jruby-19mode
36
- gemfile: gemfiles/rails_4_2.gemfile
37
- - rvm: rbx-3.107
38
- gemfile: gemfiles/rails_4_2.gemfile
39
25
  exclude:
40
- - rvm: 2.4.6
41
- gemfile: gemfiles/rails_4_2.gemfile
42
- - rvm: 2.5.5
43
- gemfile: gemfiles/rails_4_2.gemfile
44
- - rvm: 2.6.2
45
- gemfile: gemfiles/rails_4_2.gemfile
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
46
40
  - rvm: 2.2.10
47
41
  gemfile: gemfiles/rails_head.gemfile
48
42
  - rvm: 2.3.8
49
43
  gemfile: gemfiles/rails_head.gemfile
50
- - rvm: 2.4.6
44
+ - rvm: 2.4.10
51
45
  gemfile: gemfiles/rails_head.gemfile
52
46
  allow_failures:
53
- - rvm: jruby-19mode
54
- - rvm: rbx-3.107
55
47
  - rvm: ruby-head
56
48
  - gemfile: gemfiles/rails_head.gemfile
57
49
  fast_finish: true
data/Appraisals CHANGED
@@ -1,22 +1,20 @@
1
- appraise "rails-4-2" do
2
- gem "rails", "~> 4.2.0"
1
+ appraise "rails-5-0" do
2
+ gem "rails", "~> 5.0.0"
3
3
  end
4
4
 
5
- if RUBY_VERSION >= "2.2.2"
6
- appraise "rails-5-0" do
7
- gem "rails", "~> 5.0.0"
8
- end
9
-
10
- appraise "rails-5-1" do
11
- gem "rails", "~> 5.1.0"
12
- end
5
+ appraise "rails-5-1" do
6
+ gem "rails", "~> 5.1.0"
7
+ end
13
8
 
14
- appraise "rails-5-2" do
15
- gem "rails", "~> 5.2.0"
16
- end
9
+ appraise "rails-5-2" do
10
+ gem "rails", "~> 5.2.0"
17
11
  end
18
12
 
19
13
  if RUBY_VERSION >= "2.5.0"
14
+ appraise "rails-6-0" do
15
+ gem "rails", "~> 6.0.0"
16
+ end
17
+
20
18
  appraise "rails-head" do
21
19
  gem "rails", github: "rails/rails"
22
20
  end
@@ -1,5 +1,44 @@
1
1
  # Changelog
2
2
 
3
+ 2.11.0
4
+ ------
5
+
6
+ * [Allow jbuilder instance to be passed to #merge!](https://github.com/rails/jbuilder/pull/485)
7
+ * [Fix for key_format! when using nested hashes](https://github.com/rails/jbuilder/pull/486)
8
+ * [Include rich_text, attachment, and attachments fields in json partial](https://github.com/rails/jbuilder/pull/459)
9
+
10
+ 2.10.2
11
+ ------
12
+
13
+ * Update scaffold generator to use double quotes, 422 form error responds, and modern string-of-arrays syntax [DHH]
14
+
15
+ 2.10.1
16
+ ------
17
+
18
+ * Fix keyword arguments warning on Ruby 2.7
19
+
20
+ 2.10.0
21
+ ------
22
+
23
+ * Requires Rails 5+ and Ruby 2.2+
24
+ * Nested hashes are deep-merged
25
+
26
+ 2.9.1
27
+ -----
28
+
29
+ * [Respect JSON encoding customizations](https://github.com/rails/jbuilder/commit/e2e8623b08078ad6a2323ce8ecaf642b7afe1166)
30
+
31
+ 2.9.0
32
+ -----
33
+
34
+ * [Fix passing object with partial without locals](https://github.com/rails/jbuilder/pull/435)
35
+ * [Fix deprecation warning in Rails 6.0](https://github.com/rails/jbuilder/pull/453)
36
+ * [Use quotes consistently in generated templates](https://github.com/rails/jbuilder/pull/455)
37
+ * [Allow omitting timestamps from generated partials](https://github.com/rails/jbuilder/pull/448)
38
+ * [Respect changing scaffold generator](https://github.com/rails/jbuilder/pull/458)
39
+ * [Use a symbolic default format for Rails 6.0 forward compatibility](https://github.com/rails/jbuilder/commit/3895a7243f3db292b0bf15513fc05494e6e50576)
40
+ * [Drop MultiJSON in favor of Ruby standard library JSON](https://github.com/rails/jbuilder/commit/b952ae096eb1828b0fcfde06e6ba62311494ec49)
41
+
3
42
  2.8.0
4
43
  -----
5
44
 
@@ -4,18 +4,16 @@ Contributing to Jbuilder
4
4
  [![Build Status](https://api.travis-ci.org/rails/jbuilder.svg?branch=master)][travis]
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
- [![Dependencies Status](https://gemnasium.com/rails/jbuilder.svg)][gemnasium]
8
7
 
9
8
  [travis]: https://travis-ci.org/rails/jbuilder
10
9
  [gem]: https://rubygems.org/gems/jbuilder
11
10
  [codeclimate]: https://codeclimate.com/github/rails/jbuilder
12
- [gemnasium]: https://gemnasium.com/rails/jbuilder
13
11
 
14
12
  Jbuilder is work of [many contributors](https://github.com/rails/jbuilder/graphs/contributors). You're encouraged to submit [pull requests](https://github.com/rails/jbuilder/pulls), [propose features and discuss issues](https://github.com/rails/jbuilder/issues).
15
13
 
16
14
  #### Fork the Project
17
15
 
18
- 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.
19
17
 
20
18
  ```
21
19
  git clone https://github.com/contributor/jbuilder.git
@@ -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", "~> 4.2.0"
8
+ gem "rails", "~> 6.0.0"
9
9
 
10
10
  gemspec path: "../"
@@ -1,15 +1,21 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'jbuilder'
3
- s.version = '2.9.0'
3
+ s.version = '2.11.0'
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'
7
7
  s.homepage = 'https://github.com/rails/jbuilder'
8
8
  s.license = 'MIT'
9
9
 
10
- s.required_ruby_version = '>= 1.9.3'
10
+ s.required_ruby_version = '>= 2.2.2'
11
11
 
12
- s.add_dependency 'activesupport', '>= 4.2.0'
12
+ s.add_dependency 'activesupport', '>= 5.0.0'
13
+
14
+ if RUBY_ENGINE == 'rbx'
15
+ s.add_development_dependency('racc')
16
+ s.add_development_dependency('json')
17
+ s.add_development_dependency('rubysl')
18
+ end
13
19
 
14
20
  s.files = `git ls-files`.split("\n")
15
21
  s.test_files = `git ls-files -- test/*`.split("\n")
@@ -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
@@ -1,10 +1,10 @@
1
1
  <% if namespaced? -%>
2
- require_dependency "<%= namespaced_file_path %>/application_controller"
2
+ require_dependency "<%= namespaced_path %>/application_controller"
3
3
 
4
4
  <% end -%>
5
5
  <% module_namespacing do -%>
6
6
  class <%= controller_class_name %>Controller < ApplicationController
7
- before_action :set_<%= singular_table_name %>, only: [:show, :update, :destroy]
7
+ before_action :set_<%= singular_table_name %>, only: %w[ show update destroy ]
8
8
 
9
9
  # GET <%= route_url %>
10
10
  # GET <%= route_url %>.json
@@ -51,7 +51,7 @@ class <%= controller_class_name %>Controller < ApplicationController
51
51
  @<%= singular_table_name %> = <%= orm_class.find(class_name, "params[:id]") %>
52
52
  end
53
53
 
54
- # Never trust parameters from the scary internet, only allow the white list through.
54
+ # Only allow a list of trusted parameters through.
55
55
  def <%= "#{singular_table_name}_params" %>
56
56
  <%- if attributes_names.empty? -%>
57
57
  params.fetch(<%= ":#{singular_table_name}" %>, {})
@@ -1,10 +1,10 @@
1
1
  <% if namespaced? -%>
2
- require_dependency "<%= namespaced_file_path %>/application_controller"
2
+ require_dependency "<%= namespaced_path %>/application_controller"
3
3
 
4
4
  <% end -%>
5
5
  <% module_namespacing do -%>
6
6
  class <%= controller_class_name %>Controller < ApplicationController
7
- before_action :set_<%= singular_table_name %>, only: [:show, :edit, :update, :destroy]
7
+ before_action :set_<%= singular_table_name %>, only: %w[ show edit update destroy ]
8
8
 
9
9
  # GET <%= route_url %>
10
10
  # GET <%= route_url %>.json
@@ -33,10 +33,10 @@ class <%= controller_class_name %>Controller < ApplicationController
33
33
 
34
34
  respond_to do |format|
35
35
  if @<%= orm_instance.save %>
36
- format.html { redirect_to @<%= singular_table_name %>, notice: <%= "'#{human_name} was successfully created.'" %> }
36
+ format.html { redirect_to @<%= singular_table_name %>, notice: <%= %("#{human_name} was successfully created.") %> }
37
37
  format.json { render :show, status: :created, location: <%= "@#{singular_table_name}" %> }
38
38
  else
39
- format.html { render :new }
39
+ format.html { render :new, status: :unprocessable_entity }
40
40
  format.json { render json: <%= "@#{orm_instance.errors}" %>, status: :unprocessable_entity }
41
41
  end
42
42
  end
@@ -47,10 +47,10 @@ class <%= controller_class_name %>Controller < ApplicationController
47
47
  def update
48
48
  respond_to do |format|
49
49
  if @<%= orm_instance.update("#{singular_table_name}_params") %>
50
- format.html { redirect_to @<%= singular_table_name %>, notice: <%= "'#{human_name} was successfully updated.'" %> }
50
+ format.html { redirect_to @<%= singular_table_name %>, notice: <%= %("#{human_name} was successfully updated.") %> }
51
51
  format.json { render :show, status: :ok, location: <%= "@#{singular_table_name}" %> }
52
52
  else
53
- format.html { render :edit }
53
+ format.html { render :edit, status: :unprocessable_entity }
54
54
  format.json { render json: <%= "@#{orm_instance.errors}" %>, status: :unprocessable_entity }
55
55
  end
56
56
  end
@@ -61,7 +61,7 @@ class <%= controller_class_name %>Controller < ApplicationController
61
61
  def destroy
62
62
  @<%= orm_instance.destroy %>
63
63
  respond_to do |format|
64
- format.html { redirect_to <%= index_helper %>_url, notice: <%= "'#{human_name} was successfully destroyed.'" %> }
64
+ format.html { redirect_to <%= index_helper %>_url, notice: <%= %("#{human_name} was successfully destroyed.") %> }
65
65
  format.json { head :no_content }
66
66
  end
67
67
  end
@@ -72,7 +72,7 @@ class <%= controller_class_name %>Controller < ApplicationController
72
72
  @<%= singular_table_name %> = <%= orm_class.find(class_name, "params[:id]") %>
73
73
  end
74
74
 
75
- # Never trust parameters from the scary internet, only allow the white list through.
75
+ # Only allow a list of trusted parameters through.
76
76
  def <%= "#{singular_table_name}_params" %>
77
77
  <%- if attributes_names.empty? -%>
78
78
  params.fetch(<%= ":#{singular_table_name}" %>, {})
@@ -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 -%>
@@ -4,6 +4,7 @@ require 'jbuilder/key_formatter'
4
4
  require 'jbuilder/errors'
5
5
  require 'json'
6
6
  require 'ostruct'
7
+ require 'active_support/core_ext/hash/deep_merge'
7
8
 
8
9
  class Jbuilder
9
10
  @@key_formatter = nil
@@ -26,12 +27,12 @@ class Jbuilder
26
27
  BLANK = Blank.new
27
28
  NON_ENUMERABLES = [ ::Struct, ::OpenStruct ].to_set
28
29
 
29
- def set!(key, value = BLANK, *args)
30
+ def set!(key, value = BLANK, *args, &block)
30
31
  result = if ::Kernel.block_given?
31
32
  if !_blank?(value)
32
33
  # json.comments @post.comments { |comment| ... }
33
34
  # { "comments": [ { ... }, { ... } ] }
34
- _scope{ array! value, &::Proc.new }
35
+ _scope{ array! value, &block }
35
36
  else
36
37
  # json.comments { ... }
37
38
  # { "comments": ... }
@@ -42,11 +43,11 @@ class Jbuilder
42
43
  # json.age 32
43
44
  # json.person another_jbuilder
44
45
  # { "age": 32, "person": { ... }
45
- value.attributes!
46
+ _format_keys(value.attributes!)
46
47
  else
47
48
  # json.age 32
48
49
  # { "age": 32 }
49
- value
50
+ _format_keys(value)
50
51
  end
51
52
  elsif _is_collection?(value)
52
53
  # json.comments @post.comments, :content, :created_at
@@ -61,9 +62,9 @@ class Jbuilder
61
62
  _set_value key, result
62
63
  end
63
64
 
64
- def method_missing(*args)
65
+ def method_missing(*args, &block)
65
66
  if ::Kernel.block_given?
66
- set!(*args, &::Proc.new)
67
+ set!(*args, &block)
67
68
  else
68
69
  set!(*args)
69
70
  end
@@ -163,7 +164,7 @@ class Jbuilder
163
164
  #
164
165
  # [ { "name": David", "age": 32 }, { "name": Jamie", "age": 31 } ]
165
166
  #
166
- # If you are using Ruby 1.9+, you can use the call syntax instead of an explicit extract! call:
167
+ # You can use the call syntax instead of an explicit extract! call:
167
168
  #
168
169
  # json.(@people) { |person| ... }
169
170
  #
@@ -181,11 +182,11 @@ class Jbuilder
181
182
  # json.array! [1, 2, 3]
182
183
  #
183
184
  # [1,2,3]
184
- def array!(collection = [], *attributes)
185
+ def array!(collection = [], *attributes, &block)
185
186
  array = if collection.nil?
186
187
  []
187
188
  elsif ::Kernel.block_given?
188
- _map_collection(collection, &::Proc.new)
189
+ _map_collection(collection, &block)
189
190
  elsif attributes.any?
190
191
  _map_collection(collection) { |element| extract! element, *attributes }
191
192
  else
@@ -220,9 +221,9 @@ class Jbuilder
220
221
  end
221
222
  end
222
223
 
223
- def call(object, *attributes)
224
+ def call(object, *attributes, &block)
224
225
  if ::Kernel.block_given?
225
- array! object, &::Proc.new
226
+ array! object, &block
226
227
  else
227
228
  extract! object, *attributes
228
229
  end
@@ -240,14 +241,15 @@ class Jbuilder
240
241
  @attributes
241
242
  end
242
243
 
243
- # Merges hash or array into current builder.
244
- def merge!(hash_or_array)
244
+ # Merges hash, array, or Jbuilder instance into current builder.
245
+ def merge!(object)
246
+ hash_or_array = ::Jbuilder === object ? object.attributes! : object
245
247
  @attributes = _merge_values(@attributes, hash_or_array)
246
248
  end
247
249
 
248
250
  # Encodes the current builder as JSON.
249
251
  def target!
250
- ::JSON.dump(@attributes)
252
+ @attributes.to_json
251
253
  end
252
254
 
253
255
  private
@@ -271,11 +273,11 @@ class Jbuilder
271
273
  if _blank?(updates)
272
274
  current_value
273
275
  elsif _blank?(current_value) || updates.nil? || current_value.empty? && ::Array === updates
274
- updates
276
+ _format_keys(updates)
275
277
  elsif ::Array === current_value && ::Array === updates
276
- current_value + updates
278
+ current_value + _format_keys(updates)
277
279
  elsif ::Hash === current_value && ::Hash === updates
278
- current_value.merge(updates)
280
+ current_value.deep_merge(_format_keys(updates))
279
281
  else
280
282
  raise MergeError.build(current_value, updates)
281
283
  end
@@ -285,6 +287,16 @@ class Jbuilder
285
287
  @key_formatter ? @key_formatter.format(key) : key.to_s
286
288
  end
287
289
 
290
+ def _format_keys(hash_or_array)
291
+ if ::Array === hash_or_array
292
+ hash_or_array.map { |value| _format_keys(value) }
293
+ elsif ::Hash === hash_or_array
294
+ ::Hash[hash_or_array.collect { |k, v| [_key(k), _format_keys(v)] }]
295
+ else
296
+ hash_or_array
297
+ end
298
+ end
299
+
288
300
  def _set_value(key, value)
289
301
  raise NullError.build(key) if @attributes.nil?
290
302
  raise ArrayError.build(key) if ::Array === @attributes
@@ -73,8 +73,8 @@ class JbuilderTemplate < Jbuilder
73
73
  # json.cache_if! !admin?, @person, expires_in: 10.minutes do
74
74
  # json.extract! @person, :name, :age
75
75
  # end
76
- def cache_if!(condition, *args)
77
- condition ? cache!(*args, &::Proc.new) : yield
76
+ def cache_if!(condition, *args, &block)
77
+ condition ? cache!(*args, &block) : yield
78
78
  end
79
79
 
80
80
  def target!
@@ -164,7 +164,7 @@ class JbuilderTemplate < Jbuilder
164
164
  if @context.respond_to?(:cache_fragment_name)
165
165
  # Current compatibility, fragment_name_with_digest is private again and cache_fragment_name
166
166
  # should be used instead.
167
- @context.cache_fragment_name(key, options)
167
+ @context.cache_fragment_name(key, **options)
168
168
  elsif @context.respond_to?(:fragment_name_with_digest)
169
169
  # Backwards compatibility for period of time when fragment_name_with_digest was made public.
170
170
  @context.fragment_name_with_digest(key)
@@ -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
@@ -99,7 +99,7 @@ class JbuilderTest < ActiveSupport::TestCase
99
99
  assert_equal 32, result['age']
100
100
  end
101
101
 
102
- test 'extracting from object using call style for 1.9' do
102
+ test 'extracting from object using call style' do
103
103
  person = Struct.new(:name, :age).new('David', 32)
104
104
 
105
105
  result = jbuild do |json|
@@ -159,6 +159,25 @@ class JbuilderTest < ActiveSupport::TestCase
159
159
  assert_equal 32, result['author']['age']
160
160
  end
161
161
 
162
+ test 'nested blocks are additive' do
163
+ result = jbuild do |json|
164
+ json.author do
165
+ json.name do
166
+ json.first 'David'
167
+ end
168
+ end
169
+
170
+ json.author do
171
+ json.name do
172
+ json.last 'Heinemeier Hansson'
173
+ end
174
+ end
175
+ end
176
+
177
+ assert_equal 'David', result['author']['name']['first']
178
+ assert_equal 'Heinemeier Hansson', result['author']['name']['last']
179
+ end
180
+
162
181
  test 'support merge! method' do
163
182
  result = jbuild do |json|
164
183
  json.merge! 'foo' => 'bar'
@@ -177,6 +196,18 @@ class JbuilderTest < ActiveSupport::TestCase
177
196
  assert_equal 'Pavel', result['author']['name']
178
197
  end
179
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
+
180
211
  test 'blocks are additive via extract syntax' do
181
212
  person = Person.new('Pavel', 27)
182
213
 
@@ -562,6 +593,58 @@ class JbuilderTest < ActiveSupport::TestCase
562
593
  assert_equal ['oats and friends'], result.keys
563
594
  end
564
595
 
596
+ test 'key_format! with merge!' do
597
+ hash = { camel_style: 'for JS' }
598
+ result = jbuild do |json|
599
+ json.key_format! camelize: :lower
600
+ json.merge! hash
601
+ end
602
+
603
+ assert_equal ['camelStyle'], result.keys
604
+ end
605
+
606
+ test 'key_format! with merge! deep' do
607
+ hash = { camel_style: { sub_attr: 'for JS' } }
608
+ result = jbuild do |json|
609
+ json.key_format! camelize: :lower
610
+ json.merge! hash
611
+ end
612
+
613
+ assert_equal ['subAttr'], result['camelStyle'].keys
614
+ end
615
+
616
+ test 'key_format! with set! array of hashes' do
617
+ names = [{ first_name: 'camel', last_name: 'case' }]
618
+ result = jbuild do |json|
619
+ json.key_format! camelize: :lower
620
+ json.set! :names, names
621
+ end
622
+
623
+ assert_equal %w[firstName lastName], result['names'][0].keys
624
+ end
625
+
626
+ test 'key_format! with array! of hashes' do
627
+ names = [{ first_name: 'camel', last_name: 'case' }]
628
+ result = jbuild do |json|
629
+ json.key_format! camelize: :lower
630
+ json.array! names
631
+ end
632
+
633
+ assert_equal %w[firstName lastName], result[0].keys
634
+ end
635
+
636
+ test 'key_format! with merge! array of hashes' do
637
+ names = [{ first_name: 'camel', last_name: 'case' }]
638
+ new_names = [{ first_name: 'snake', last_name: 'case' }]
639
+ result = jbuild do |json|
640
+ json.key_format! camelize: :lower
641
+ json.array! names
642
+ json.merge! new_names
643
+ end
644
+
645
+ assert_equal %w[firstName lastName], result[1].keys
646
+ end
647
+
565
648
  test 'default key_format!' do
566
649
  Jbuilder.key_format camelize: :lower
567
650
  result = jbuild{ |json| json.camel_style 'for JS' }
@@ -713,4 +796,13 @@ class JbuilderTest < ActiveSupport::TestCase
713
796
  end
714
797
  end
715
798
  end
799
+
800
+ if RUBY_VERSION >= "2.2.10"
801
+ test "respects JSON encoding customizations" do
802
+ # Active Support overrides Time#as_json for custom formatting.
803
+ # Ensure we call #to_json on the final attributes instead of JSON.dump.
804
+ result = JSON.load(Jbuilder.encode { |json| json.time Time.parse("2018-05-13 11:51:00.485 -0400") })
805
+ assert_equal "2018-05-13T11:51:00.485-04:00", result["time"]
806
+ end
807
+ end
716
808
  end
@@ -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
@@ -31,22 +31,22 @@ class ScaffoldControllerGeneratorTest < Rails::Generators::TestCase
31
31
  assert_instance_method :create, content do |m|
32
32
  assert_match %r{@post = Post\.new\(post_params\)}, m
33
33
  assert_match %r{@post\.save}, m
34
- assert_match %r{format\.html \{ redirect_to @post, notice: 'Post was successfully created\.' \}}, m
34
+ assert_match %r{format\.html \{ redirect_to @post, notice: "Post was successfully created\." \}}, m
35
35
  assert_match %r{format\.json \{ render :show, status: :created, location: @post \}}, m
36
- assert_match %r{format\.html \{ render :new \}}, m
36
+ assert_match %r{format\.html \{ render :new, status: :unprocessable_entity \}}, m
37
37
  assert_match %r{format\.json \{ render json: @post\.errors, status: :unprocessable_entity \}}, m
38
38
  end
39
39
 
40
40
  assert_instance_method :update, content do |m|
41
- assert_match %r{format\.html \{ redirect_to @post, notice: 'Post was successfully updated\.' \}}, m
41
+ assert_match %r{format\.html \{ redirect_to @post, notice: "Post was successfully updated\." \}}, m
42
42
  assert_match %r{format\.json \{ render :show, status: :ok, location: @post \}}, m
43
- assert_match %r{format\.html \{ render :edit \}}, m
43
+ assert_match %r{format\.html \{ render :edit, status: :unprocessable_entity \}}, m
44
44
  assert_match %r{format\.json \{ render json: @post.errors, status: :unprocessable_entity \}}, m
45
45
  end
46
46
 
47
47
  assert_instance_method :destroy, content do |m|
48
48
  assert_match %r{@post\.destroy}, m
49
- assert_match %r{format\.html \{ redirect_to posts_url, notice: 'Post was successfully destroyed\.' \}}, m
49
+ assert_match %r{format\.html \{ redirect_to posts_url, notice: "Post was successfully destroyed\." \}}, m
50
50
  assert_match %r{format\.json \{ head :no_content \}}, m
51
51
  end
52
52
 
@@ -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
@@ -3,6 +3,7 @@ require "bundler/setup"
3
3
  require "active_support"
4
4
  require "active_support/core_ext/array/access"
5
5
  require "active_support/cache/memory_store"
6
+ require "active_support/json"
6
7
  require "active_model"
7
8
  require "action_view"
8
9
  require "rails/version"
@@ -10,7 +11,7 @@ require "rails/version"
10
11
  require "jbuilder"
11
12
 
12
13
  require "active_support/testing/autorun"
13
- require "mocha/setup"
14
+ require "mocha/minitest"
14
15
 
15
16
  ActiveSupport.test_order = :random
16
17
 
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.9.0
4
+ version: 2.11.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Heinemeier Hansson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-05-13 00:00:00.000000000 Z
11
+ date: 2021-01-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 4.2.0
19
+ version: 5.0.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: 4.2.0
26
+ version: 5.0.0
27
27
  description:
28
28
  email: david@basecamp.com
29
29
  executables: []
@@ -39,10 +39,10 @@ files:
39
39
  - MIT-LICENSE
40
40
  - README.md
41
41
  - Rakefile
42
- - gemfiles/rails_4_2.gemfile
43
42
  - gemfiles/rails_5_0.gemfile
44
43
  - gemfiles/rails_5_1.gemfile
45
44
  - gemfiles/rails_5_2.gemfile
45
+ - gemfiles/rails_6_0.gemfile
46
46
  - gemfiles/rails_head.gemfile
47
47
  - jbuilder.gemspec
48
48
  - lib/generators/rails/jbuilder_generator.rb
@@ -79,14 +79,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - ">="
81
81
  - !ruby/object:Gem::Version
82
- version: 1.9.3
82
+ version: 2.2.2
83
83
  required_rubygems_version: !ruby/object:Gem::Requirement
84
84
  requirements:
85
85
  - - ">="
86
86
  - !ruby/object:Gem::Version
87
87
  version: '0'
88
88
  requirements: []
89
- rubygems_version: 3.0.3
89
+ rubygems_version: 3.1.2
90
90
  signing_key:
91
91
  specification_version: 4
92
92
  summary: Create JSON structures via a Builder-style DSL