jbuilder 1.4.2 → 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
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