jbuilder 1.4.2 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- MzM1MDNlYmI1ZTFkYWRiN2ViYmI4MjM5YTY1Yjk5ZGU3YjcyOGRmNw==
4
+ NGYyYTk2NWM1ZjkxN2Q1YWYxNmM1MWI2YWZhZWFlODY4YWJiNjZjYw==
5
5
  data.tar.gz: !binary |-
6
- OTVlNmY0ODBmNGZmY2M4NGE2Zjc5NTYyN2M2MzQyYzA2NzY1YzQ3YQ==
6
+ ZGM3Mjg1NGYxODFjNGU4NGYwZWRkYmNkNTZmMjJjMmFjMzk3NTUxZA==
7
7
  !binary "U0hBNTEy":
8
8
  metadata.gz: !binary |-
9
- YWVkODM4Zjg5YTYxN2Y0NTJkMjA3N2JjMTFhN2U2ZmU0MWQ3NjlhMDFiMTk1
10
- ODFkMmNmYmE4NTIzNDc1MGVkNzdkMTQzYjE4YmRhOWM0Y2IzZDQ5MGE2NWM0
11
- MzA4OTYxOTYwNWFhNDJlYzkxZDIzNTcyNDQ1MzlkY2UxNjQzYTQ=
9
+ OGFkMmYzYWM0MjQ5OWM5ZmU4ZjU1ODBhZmVkMzQ3ZjRjNjg0YmE2N2VmY2Rm
10
+ M2YyNDIwY2FlZTNhMzBmNDk4MDljNGMxNWVkNzMwYTMyOTRiYTEwYzE2Mjc4
11
+ NjE0ODZlZTU2MjczZjgxMDg5ZTVmZmIxZWQ0OGQ1NTI5M2FhNmQ=
12
12
  data.tar.gz: !binary |-
13
- MzgwMDcwNGFkMTI5OWI4YzE3NmQzMTUwZDk2Yzg0YmExYjE0NjEyZjE4ZWY0
14
- NWIwOTBlN2NkZjk3NzI2ODNmZWY2ZGIwMmMzYWU0M2RmNTZjZTZhMmY4OWJm
15
- MzNjYTgzZjUxNWE1NjI1YWE0OWMwMjZkZjdlZjVlOTczN2Q5ZTg=
13
+ ODc3OGEwYTkxMGFlNTdhODdmOGEzYWM1YzZiYTEyOTk5MjFmZjM4M2I5ZTU1
14
+ ZTU4Y2ViYTFhMTA1NzFmZGFlMTc5OTljYTk1OTA2MTk0MDVmOTVhZGYyMzZl
15
+ Y2Y1ZTlmOWU0OTQ2NTY1MmY1ODQ2YmY2YjdiYTEwYTA2NTYwYmE=
@@ -1,6 +1,5 @@
1
1
  language: ruby
2
- before_install:
3
- - gem install bundler
2
+
4
3
  rvm:
5
4
  - 1.8.7
6
5
  - 1.9.2
@@ -12,12 +11,14 @@ rvm:
12
11
  - jruby-19mode
13
12
  - rbx-18mode
14
13
  - rbx-19mode
14
+
15
15
  gemfile:
16
16
  - Gemfile
17
17
  - Gemfile.edge
18
+
18
19
  matrix:
19
20
  exclude:
20
- # Edge Rails is only compatible with 1.9.3
21
+ # Edge Rails is only compatible with 1.9.3+
21
22
  - gemfile: Gemfile.edge
22
23
  rvm: 1.8.7
23
24
  - gemfile: Gemfile.edge
@@ -28,6 +29,10 @@ matrix:
28
29
  rvm: jruby-18mode
29
30
  - gemfile: Gemfile.edge
30
31
  rvm: rbx-18mode
32
+ allow_failures:
33
+ - rvm: ruby-head
34
+ - rvm: rbx-18mode
35
+ - rvm: rbx-19mode
31
36
 
32
37
  notifications:
33
38
  email: false
@@ -3,9 +3,6 @@ source 'https://rubygems.org'
3
3
  gemspec
4
4
 
5
5
  gem 'rake'
6
- gem 'mocha', require: false
7
-
8
- git 'git://github.com/rails/rails.git', branch: '4-0-stable' do
9
- gem 'railties', require: 'rails/railtie'
10
- gem 'actionpack'
11
- end
6
+ gem 'railties', '~> 4.0.0'
7
+ gem 'actionpack', '~> 4.0.0'
8
+ gem 'mocha', require: false
data/README.md CHANGED
@@ -131,12 +131,30 @@ end
131
131
  if current_user.admin?
132
132
  json.visitors calculate_visitors(@message)
133
133
  end
134
+ ```
135
+
136
+
137
+ You can use partials as well. The following will render the file
138
+ `views/comments/_comments.json.jbuilder`, and set a local variable
139
+ `comments` with all this message's comments, which you can use inside
140
+ the partial.
141
+
142
+ ```ruby
143
+ json.partial! 'comments/comments', comments: @message.comments
144
+ ```
145
+
146
+ It's also possible to render collections of partials:
147
+
148
+ ```ruby
149
+ json.array! @posts, partial: 'posts/post', as: :post
150
+
151
+ # or
152
+
153
+ json.partial! 'posts/post', collection: @posts, as: :post
154
+
155
+ # or
134
156
 
135
- # You can use partials as well. The following line will render the file
136
- # RAILS_ROOT/app/views/api/comments/_comments.json.jbuilder, and set a local variable
137
- # 'comments' with all this message's comments, which you can use inside
138
- # the partial.
139
- json.partial! 'api/comments/comments', comments: @message.comments
157
+ json.partial! partial: 'posts/post', collection: @posts, as: :post
140
158
  ```
141
159
 
142
160
  You can explicitly make Jbuilder object return null if you want:
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'jbuilder'
3
- s.version = '1.4.2'
3
+ s.version = '1.5.0'
4
4
  s.author = 'David Heinemeier Hansson'
5
5
  s.email = 'david@37signals.com'
6
6
  s.summary = 'Create JSON structures via a Builder-style DSL'
@@ -252,9 +252,9 @@ class Jbuilder < JbuilderProxy
252
252
  # json.(@person, :name, :age)
253
253
  def extract!(object, *attributes)
254
254
  if ::Hash === object
255
- attributes.each { |attribute| _set_value attribute, object.fetch(attribute) }
255
+ _extract_hash_values(object, *attributes)
256
256
  else
257
- attributes.each { |attribute| _set_value attribute, object.send(attribute) }
257
+ _extract_method_values(object, *attributes)
258
258
  end
259
259
  end
260
260
 
@@ -285,6 +285,22 @@ class Jbuilder < JbuilderProxy
285
285
 
286
286
  private
287
287
 
288
+ def _extract_hash_values(object, *attributes)
289
+ attributes.each{ |key| _set_value key, object.fetch(key) }
290
+ end
291
+
292
+ def _extract_method_values(object, *attributes)
293
+ attributes.each do |method_name|
294
+ unless object.respond_to?(method_name)
295
+ message = "Private method #{method_name.inspect} was used to " +
296
+ 'extract value. This will be an error in future versions of Jbuilder'
297
+ end
298
+
299
+ _set_value method_name, object.send(method_name)
300
+ ::ActiveSupport::Deprecation.warn message if message
301
+ end
302
+ end
303
+
288
304
  def _set_value(key, value)
289
305
  raise NullError, key if @attributes.nil?
290
306
  unless @ignore_nil && value.nil?
@@ -6,14 +6,29 @@ class JbuilderTemplate < Jbuilder
6
6
  super(*args, &block)
7
7
  end
8
8
 
9
- def partial!(options, locals = {})
10
- case options
9
+ def partial!(name_or_options, locals = {})
10
+ case name_or_options
11
11
  when ::Hash
12
- options[:locals] ||= {}
13
- options[:locals].merge!(:json => self)
14
- @context.render(options.reverse_merge(:handlers => [:jbuilder]))
15
- else # String
16
- @context.render(:partial => options, :locals => locals.merge(:json => self), :handlers => [:jbuilder])
12
+ # partial! partial: 'name', locals: { foo: 'bar' }
13
+ options = name_or_options
14
+ else
15
+ # partial! 'name', foo: 'bar'
16
+ options = { :partial => name_or_options, :locals => locals }
17
+ as = locals.delete(:as)
18
+ options[:as] = as if as.present?
19
+ options[:collection] = locals[:collection]
20
+ end
21
+
22
+ _handle_partial_options options
23
+ end
24
+
25
+ def array!(collection, *attributes, &block)
26
+ options = attributes.extract_options!
27
+
28
+ if options.key?(:partial)
29
+ partial! options[:partial], options.merge(:collection => collection)
30
+ else
31
+ super
17
32
  end
18
33
  end
19
34
 
@@ -26,15 +41,38 @@ class JbuilderTemplate < Jbuilder
26
41
  # json.extract! @person, :name, :age
27
42
  # end
28
43
  def cache!(key=nil, options={}, &block)
29
- options[:force] = true unless @context.controller.perform_caching
30
- value = ::Rails.cache.fetch(_cache_key(key), options) do
31
- _scope { yield self }
32
- end
44
+ if @context.controller.perform_caching
45
+ value = ::Rails.cache.fetch(_cache_key(key), options) do
46
+ _scope { yield self }
47
+ end
33
48
 
34
- _merge(value)
49
+ _merge(value)
50
+ else
51
+ yield
52
+ end
35
53
  end
36
54
 
37
55
  protected
56
+ def _handle_partial_options(options)
57
+ options.reverse_merge!(:locals => {}, :handlers => [:jbuilder])
58
+ collection = options.delete(:collection)
59
+ as = options[:as]
60
+
61
+ if collection && as
62
+ array!(collection) do |member|
63
+ options[:locals].merge!(as => member, :collection => collection)
64
+ _render_partial options
65
+ end
66
+ else
67
+ _render_partial options
68
+ end
69
+ end
70
+
71
+ def _render_partial(options)
72
+ options[:locals].merge!(:json => self)
73
+ @context.render options
74
+ end
75
+
38
76
  def _cache_key(key)
39
77
  if @context.respond_to?(:cache_fragment_name)
40
78
  # Current compatibility, fragment_name_with_digest is private again and cache_fragment_name
@@ -5,6 +5,20 @@ require 'action_view/testing/resolvers'
5
5
  require 'active_support/cache'
6
6
  require 'jbuilder'
7
7
 
8
+
9
+ BLOG_POST_PARTIAL = <<-JBUILDER
10
+ json.extract! blog_post, :id, :body
11
+ json.author do
12
+ name = blog_post.author_name.split(nil, 2)
13
+ json.first_name name[0]
14
+ json.last_name name[1]
15
+ end
16
+ JBUILDER
17
+
18
+ BlogPost = Struct.new(:id, :body, :author_name)
19
+ blog_authors = [ 'David Heinemeier Hansson', 'Pavel Pravosud' ].cycle
20
+ BLOG_POST_COLLECTION = 10.times.map{ |i| BlogPost.new(i+1, "post body #{i+1}", blog_authors.next) }
21
+
8
22
  module Rails
9
23
  def self.cache
10
24
  @cache ||= ActiveSupport::Cache::MemoryStore.new
@@ -18,7 +32,10 @@ class JbuilderTemplateTest < ActionView::TestCase
18
32
  end
19
33
 
20
34
  def partials
21
- { '_partial.json.jbuilder' => 'json.content "hello"' }
35
+ {
36
+ '_partial.json.jbuilder' => 'json.content "hello"',
37
+ '_blog_post.json.jbuilder' => BLOG_POST_PARTIAL
38
+ }
22
39
  end
23
40
 
24
41
  def render_jbuilder(source)
@@ -35,6 +52,16 @@ class JbuilderTemplateTest < ActionView::TestCase
35
52
  end
36
53
  end
37
54
 
55
+ def assert_collection_rendered(json)
56
+ result = MultiJson.load(json)
57
+
58
+ assert_equal 10, result.length
59
+ assert_equal Array, result.class
60
+ assert_equal 'post body 5', result[4]['body']
61
+ assert_equal 'Heinemeier Hansson', result[2]['author']['last_name']
62
+ assert_equal 'Pavel', result[5]['author']['first_name']
63
+ end
64
+
38
65
  test 'rendering' do
39
66
  json = render_jbuilder <<-JBUILDER
40
67
  json.content 'hello'
@@ -74,6 +101,30 @@ class JbuilderTemplateTest < ActionView::TestCase
74
101
  assert_equal 'hello', MultiJson.load(json)['content']
75
102
  end
76
103
 
104
+ test 'partial! renders collections' do
105
+ json = render_jbuilder <<-JBUILDER
106
+ json.partial! 'blog_post', :collection => BLOG_POST_COLLECTION, :as => :blog_post
107
+ JBUILDER
108
+
109
+ assert_collection_rendered json
110
+ end
111
+
112
+ test 'partial! renders collection (alt. syntax)' do
113
+ json = render_jbuilder <<-JBUILDER
114
+ json.partial! :partial => 'blog_post', :collection => BLOG_POST_COLLECTION, :as => :blog_post
115
+ JBUILDER
116
+
117
+ assert_collection_rendered json
118
+ end
119
+
120
+ test 'render array of partials' do
121
+ json = render_jbuilder <<-JBUILDER
122
+ json.array! BLOG_POST_COLLECTION, :partial => 'blog_post', :as => :blog_post
123
+ JBUILDER
124
+
125
+ assert_collection_rendered json
126
+ end
127
+
77
128
  test 'fragment caching a JSON object' do
78
129
  undef_context_methods :fragment_name_with_digest, :cache_fragment_name
79
130
 
@@ -136,6 +187,17 @@ class JbuilderTemplateTest < ActionView::TestCase
136
187
  JBUILDER
137
188
  end
138
189
 
190
+ test 'does not perform caching when controller.perform_caching is false' do
191
+ controller.perform_caching = false
192
+ render_jbuilder <<-JBUILDER
193
+ json.cache! 'cachekey' do
194
+ json.name 'Cache'
195
+ end
196
+ JBUILDER
197
+
198
+ assert_equal Rails.cache.inspect[/entries=(\d+)/, 1], '0'
199
+ end
200
+
139
201
  test 'fragment caching falls back on ActiveSupport::Cache.expand_cache_key' do
140
202
  undef_context_methods :fragment_name_with_digest, :cache_fragment_name
141
203
 
@@ -5,12 +5,14 @@ require 'jbuilder'
5
5
 
6
6
  Comment = Struct.new(:content, :id)
7
7
 
8
- class JbuilderProxy
9
- # Faking Object#instance_eval for 1.8
10
- def instance_eval(code)
11
- eval code
8
+ unless JbuilderProxy.method_defined? :instance_eval
9
+ # Faking Object#instance_eval for 1.8 and some newer JRubies
10
+ class JbuilderProxy
11
+ def instance_eval(code)
12
+ eval code
13
+ end
12
14
  end
13
- end if ::RUBY_VERSION < '1.9'
15
+ end
14
16
 
15
17
  class NonEnumerable
16
18
  def initialize(collection)
@@ -71,6 +73,23 @@ class JbuilderTest < ActiveSupport::TestCase
71
73
  assert_equal 32, parsed['age']
72
74
  end
73
75
 
76
+ test 'extracting from object using private method' do
77
+ person = Struct.new(:name) do
78
+ private
79
+ def age
80
+ 32
81
+ end
82
+ end.new('David')
83
+
84
+ message = 'Private method :age was used to extract value. This will be' +
85
+ ' an error in future versions of Jbuilder'
86
+
87
+ ::ActiveSupport::Deprecation.expects(:warn).with(message)
88
+ json = Jbuilder.encode do |json|
89
+ json.extract! person, :name, :age
90
+ end
91
+ end
92
+
74
93
  test 'extracting from object using call style for 1.9' do
75
94
  person = Struct.new(:name, :age).new('David', 32)
76
95
 
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: 1.4.2
4
+ version: 1.5.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: 2013-06-05 00:00:00.000000000 Z
11
+ date: 2013-07-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  requirement: !ruby/object:Gem::Requirement
@@ -16,28 +16,28 @@ dependencies:
16
16
  - - ! '>='
17
17
  - !ruby/object:Gem::Version
18
18
  version: 3.0.0
19
+ type: :runtime
20
+ prerelease: false
21
+ name: activesupport
19
22
  version_requirements: !ruby/object:Gem::Requirement
20
23
  requirements:
21
24
  - - ! '>='
22
25
  - !ruby/object:Gem::Version
23
26
  version: 3.0.0
24
- type: :runtime
25
- prerelease: false
26
- name: activesupport
27
27
  - !ruby/object:Gem::Dependency
28
28
  requirement: !ruby/object:Gem::Requirement
29
29
  requirements:
30
30
  - - ! '>='
31
31
  - !ruby/object:Gem::Version
32
32
  version: 1.2.0
33
+ type: :runtime
34
+ prerelease: false
35
+ name: multi_json
33
36
  version_requirements: !ruby/object:Gem::Requirement
34
37
  requirements:
35
38
  - - ! '>='
36
39
  - !ruby/object:Gem::Version
37
40
  version: 1.2.0
38
- type: :runtime
39
- prerelease: false
40
- name: multi_json
41
41
  description:
42
42
  email: david@37signals.com
43
43
  executables: []
@@ -84,7 +84,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
84
84
  version: '0'
85
85
  requirements: []
86
86
  rubyforge_project:
87
- rubygems_version: 2.0.3
87
+ rubygems_version: 2.0.6
88
88
  signing_key:
89
89
  specification_version: 4
90
90
  summary: Create JSON structures via a Builder-style DSL