jbuilder 0.9.1 → 1.0.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.
data/Gemfile CHANGED
@@ -1,6 +1,8 @@
1
- source "http://rubygems.org"
1
+ source :rubygems
2
2
 
3
3
  gemspec
4
4
 
5
- gem "actionpack"
6
- gem "rake"
5
+ git 'git://github.com/rails/rails.git' do
6
+ gem 'railties'
7
+ gem 'actionpack'
8
+ end
data/Gemfile-1.8 ADDED
@@ -0,0 +1,5 @@
1
+ source :rubygems
2
+
3
+ gemspec
4
+
5
+ gem 'actionpack', '~> 3.0'
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- Jbuilder
1
+ Jbuilder [![Build Status](https://travis-ci.org/rails/jbuilder.png)](https://travis-ci.org/rails/jbuilder)
2
2
  ========
3
3
 
4
4
  Jbuilder gives you a simple DSL for declaring JSON structures that beats massaging giant hash structures. This is particularly helpful when the generation process is fraught with conditionals and loops. Here's a simple example:
@@ -19,7 +19,7 @@ Jbuilder.encode do |json|
19
19
  end
20
20
 
21
21
  json.comments @message.comments, :content, :created_at
22
-
22
+
23
23
  json.attachments @message.attachments do |attachment|
24
24
  json.filename attachment.filename
25
25
  json.url url_for(attachment)
@@ -30,7 +30,7 @@ end
30
30
  This will build the following structure:
31
31
 
32
32
  ``` javascript
33
- {
33
+ {
34
34
  "content": "<p>This is <i>serious</i> monkey business",
35
35
  "created_at": "2011-10-29T20:45:28-05:00",
36
36
  "updated_at": "2011-10-29T20:45:28-05:00",
@@ -47,7 +47,7 @@ This will build the following structure:
47
47
  { "content": "Hello everyone!", "created_at": "2011-10-29T20:45:28-05:00" },
48
48
  { "content": "To you my good sir!", "created_at": "2011-10-29T20:47:28-05:00" }
49
49
  ],
50
-
50
+
51
51
  "attachments": [
52
52
  { "filename": "forecast.xls", "url": "http://example.com/downloads/forecast.xls" },
53
53
  { "filename": "presentation.pdf", "url": "http://example.com/downloads/presentation.pdf" }
@@ -72,19 +72,19 @@ Jbuilder objects can be directly nested inside each other. Useful for composing
72
72
  class Person
73
73
  # ... Class Definition ... #
74
74
  def to_builder
75
- person = Jbuilder.new
76
- person.(self, :name, :age)
77
- person
75
+ Jbuilder.new do |person|
76
+ person.(self, :name, :age)
77
+ end
78
78
  end
79
79
  end
80
80
 
81
81
  class Company
82
82
  # ... Class Definition ... #
83
83
  def to_builder
84
- company = Jbuilder.new
85
- company.name name
86
- company.president president.to_builder
87
- company
84
+ Jbuilder.new do |company|
85
+ company.name name
86
+ company.president president.to_builder
87
+ end
88
88
  end
89
89
  end
90
90
 
data/Rakefile CHANGED
@@ -4,7 +4,11 @@ require 'rake/testtask'
4
4
  Bundler.require
5
5
 
6
6
  Rake::TestTask.new do |test|
7
- test.test_files = FileList["test/*_test.rb"]
7
+ if ::RUBY_VERSION < '1.9'
8
+ test.test_files = %w(test/jbuilder_template_test.rb test/jbuilder_test.rb)
9
+ else
10
+ test.test_files = FileList['test/*_test.rb']
11
+ end
8
12
  end
9
13
 
10
14
  task :default => :test
data/jbuilder.gemspec CHANGED
@@ -1,11 +1,12 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'jbuilder'
3
- s.version = '0.9.1'
3
+ s.version = '1.0.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'
7
7
 
8
8
  s.add_dependency 'activesupport', '>= 3.0.0'
9
+ s.add_development_dependency 'rake', '~> 10.0.3'
9
10
 
10
11
  s.files = Dir["#{File.dirname(__FILE__)}/**/*"]
11
12
  end
@@ -0,0 +1,39 @@
1
+ require 'rails/generators/named_base'
2
+ require 'rails/generators/resource_helpers'
3
+
4
+ module Rails
5
+ module Generators
6
+ class JbuilderGenerator < NamedBase # :nodoc:
7
+ include Rails::Generators::ResourceHelpers
8
+
9
+ source_root File.expand_path('../templates', __FILE__)
10
+
11
+ argument :attributes, type: :array, default: [], banner: 'field:type field:type'
12
+
13
+ def create_root_folder
14
+ empty_directory File.join('app/views', controller_file_path)
15
+ end
16
+
17
+ def copy_view_files
18
+ %w(index show).each do |view|
19
+ filename = filename_with_extensions(view)
20
+ template filename, File.join('app/views', controller_file_path, filename)
21
+ end
22
+ end
23
+
24
+
25
+ protected
26
+ def filename_with_extensions(name)
27
+ [name, :json, :jbuilder] * '.'
28
+ end
29
+
30
+ def attributes_list_with_timestamps
31
+ attributes_list(attributes_names + %w(created_at updated_at))
32
+ end
33
+
34
+ def attributes_list(attributes = attributes_names)
35
+ attributes.map { |a| ":#{a}"} * ', '
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,11 @@
1
+ require 'rails/generators/rails/scaffold_controller/scaffold_controller_generator'
2
+
3
+ module Rails
4
+ module Generators
5
+ class JbuilderScaffoldControllerGenerator < ScaffoldControllerGenerator
6
+ source_root File.expand_path('../templates', __FILE__)
7
+
8
+ hook_for :json_template_engine, as: :scaffold
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,84 @@
1
+ <% if namespaced? -%>
2
+ require_dependency "<%= namespaced_file_path %>/application_controller"
3
+
4
+ <% end -%>
5
+ <% module_namespacing do -%>
6
+ class <%= controller_class_name %>Controller < ApplicationController
7
+ before_action :set_<%= singular_table_name %>, only: [:show, :edit, :update, :destroy]
8
+
9
+ # GET <%= route_url %>
10
+ # GET <%= route_url %>.json
11
+ def index
12
+ @<%= plural_table_name %> = <%= orm_class.all(class_name) %>
13
+ end
14
+
15
+ # GET <%= route_url %>/1
16
+ # GET <%= route_url %>/1.json
17
+ def show
18
+ end
19
+
20
+ # GET <%= route_url %>/new
21
+ def new
22
+ @<%= singular_table_name %> = <%= orm_class.build(class_name) %>
23
+ end
24
+
25
+ # GET <%= route_url %>/1/edit
26
+ def edit
27
+ end
28
+
29
+ # POST <%= route_url %>
30
+ # POST <%= route_url %>.json
31
+ def create
32
+ @<%= singular_table_name %> = <%= orm_class.build(class_name, "#{singular_table_name}_params") %>
33
+
34
+ respond_to do |format|
35
+ if @<%= orm_instance.save %>
36
+ format.html { redirect_to @<%= singular_table_name %>, notice: <%= "'#{human_name} was successfully created.'" %> }
37
+ format.json { render action: 'show', status: :created, location: <%= "@#{singular_table_name}" %> }
38
+ else
39
+ format.html { render action: 'new' }
40
+ format.json { render json: <%= "@#{orm_instance.errors}" %>, status: :unprocessable_entity }
41
+ end
42
+ end
43
+ end
44
+
45
+ # PATCH/PUT <%= route_url %>/1
46
+ # PATCH/PUT <%= route_url %>/1.json
47
+ def update
48
+ respond_to do |format|
49
+ if @<%= orm_instance.update("#{singular_table_name}_params") %>
50
+ format.html { redirect_to @<%= singular_table_name %>, notice: <%= "'#{human_name} was successfully updated.'" %> }
51
+ format.json { head :no_content }
52
+ else
53
+ format.html { render action: 'edit' }
54
+ format.json { render json: <%= "@#{orm_instance.errors}" %>, status: :unprocessable_entity }
55
+ end
56
+ end
57
+ end
58
+
59
+ # DELETE <%= route_url %>/1
60
+ # DELETE <%= route_url %>/1.json
61
+ def destroy
62
+ @<%= orm_instance.destroy %>
63
+ respond_to do |format|
64
+ format.html { redirect_to <%= index_helper %>_url }
65
+ format.json { head :no_content }
66
+ end
67
+ end
68
+
69
+ private
70
+ # Use callbacks to share common setup or constraints between actions.
71
+ def set_<%= singular_table_name %>
72
+ @<%= singular_table_name %> = <%= orm_class.find(class_name, "params[:id]") %>
73
+ end
74
+
75
+ # Never trust parameters from the scary internet, only allow the white list through.
76
+ def <%= "#{singular_table_name}_params" %>
77
+ <%- if attributes_names.empty? -%>
78
+ params[<%= ":#{singular_table_name}" %>]
79
+ <%- else -%>
80
+ params.require(<%= ":#{singular_table_name}" %>).permit(<%= attributes_names.map { |name| ":#{name}" }.join(', ') %>)
81
+ <%- end -%>
82
+ end
83
+ end
84
+ <% end -%>
@@ -0,0 +1,4 @@
1
+ json.array!(@<%= plural_table_name %>) do |<%= singular_table_name %>|
2
+ json.extract! <%= singular_table_name %>, <%= attributes_list %>
3
+ json.url <%= singular_table_name %>_url(<%= singular_table_name %>)
4
+ end
@@ -0,0 +1 @@
1
+ json.extract! @<%= singular_table_name %>, <%= attributes_list_with_timestamps %>
data/lib/jbuilder.rb CHANGED
@@ -16,7 +16,7 @@ end
16
16
  class Jbuilder < JbuilderProxy
17
17
  class KeyFormatter
18
18
  def initialize(*args)
19
- @format = {}
19
+ @format = ::ActiveSupport::OrderedHash.new
20
20
  @cache = {}
21
21
 
22
22
  options = args.extract_options!
@@ -45,19 +45,29 @@ class Jbuilder < JbuilderProxy
45
45
  end
46
46
 
47
47
  # Yields a builder and automatically turns the result into a JSON string
48
- def self.encode(*args)
49
- jbuilder = new(*args)
50
- yield jbuilder
51
- jbuilder.target!
48
+ def self.encode(*args, &block)
49
+ new(*args, &block).target!
52
50
  end
53
51
 
54
52
  @@key_formatter = KeyFormatter.new
55
53
  @@ignore_nil = false
56
54
 
57
- def initialize(key_formatter = @@key_formatter.clone, ignore_nil = @@ignore_nil)
55
+ def initialize(*args)
58
56
  @attributes = ::ActiveSupport::OrderedHash.new
59
- @key_formatter = key_formatter
60
- @ignore_nil = ignore_nil
57
+
58
+ options = args.extract_options!
59
+ @key_formatter = options.fetch(:key_formatter, @@key_formatter.clone)
60
+ @ignore_nil = options.fetch(:ignore_nil, @@ignore_nil)
61
+
62
+ # old-style initialization compatibility
63
+ if args.any?
64
+ @key_formatter = args.shift
65
+ @ignore_nil = args.shift if args.any?
66
+ ::ActiveSupport::Deprecation.warn 'Initialization with positioned ' +
67
+ 'arguments is deprecated. Use hash syntax instead.'
68
+ end
69
+
70
+ yield self if ::Kernel.block_given?
61
71
  end
62
72
 
63
73
  # Dynamically set a key value pair.
@@ -255,9 +265,12 @@ class Jbuilder < JbuilderProxy
255
265
  end
256
266
 
257
267
  private
258
- def method_missing(method, value = nil, *args)
268
+
269
+ BLANK = ::Object.new
270
+
271
+ def method_missing(method, value = BLANK, *args)
259
272
  result = if ::Kernel.block_given?
260
- if value
273
+ if BLANK != value
261
274
  # json.comments @post.comments { |comment| ... }
262
275
  # { "comments": [ { ... }, { ... } ] }
263
276
  _map_collection(value) { |element| if ::Proc.new.arity == 2 then yield self, element else yield element end }
@@ -279,7 +292,7 @@ class Jbuilder < JbuilderProxy
279
292
  value
280
293
  end
281
294
  else
282
- if value.respond_to?(:each)
295
+ if value.kind_of?(::Enumerable)
283
296
  # json.comments(@post.comments, :content, :created_at)
284
297
  # { "comments": [ { "content": "hello", "created_at": "..." }, { "content": "world", "created_at": "..." } ] }
285
298
  _map_collection(value) do |element|
@@ -298,6 +311,8 @@ class Jbuilder < JbuilderProxy
298
311
  end
299
312
 
300
313
  def _map_collection(collection)
314
+ return [] if collection.nil?
315
+
301
316
  collection.map do |element|
302
317
  _scope { yield element }
303
318
  end
@@ -322,4 +337,9 @@ class Jbuilder < JbuilderProxy
322
337
  end
323
338
  end
324
339
 
325
- require "jbuilder_template" if defined?(ActionView::Template)
340
+ require 'jbuilder_template' if defined?(ActionView::Template)
341
+
342
+ begin
343
+ require 'railtie' if Rails::VERSION::MAJOR == 4
344
+ rescue NameError
345
+ end
@@ -1,7 +1,7 @@
1
1
  class JbuilderTemplate < Jbuilder
2
- def initialize(context, *args)
2
+ def initialize(context, *args, &block)
3
3
  @context = context
4
- super(*args)
4
+ super(*args, &block)
5
5
  end
6
6
 
7
7
  def partial!(options, locals = {})
@@ -37,7 +37,7 @@ class JbuilderTemplate < Jbuilder
37
37
  if @context.respond_to?(:fragment_name_with_digest)
38
38
  @context.fragment_name_with_digest(key)
39
39
  else
40
- ::ActiveSupport::Cache.expand_cache_key(key.is_a?(::Hash) ? url_for(key).split("://").last : key, :jbuilder)
40
+ ::ActiveSupport::Cache.expand_cache_key(key.is_a?(::Hash) ? url_for(key).split('://').last : key, :jbuilder)
41
41
  end
42
42
  end
43
43
  end
@@ -53,4 +53,4 @@ class JbuilderHandler
53
53
  end
54
54
  end
55
55
 
56
- ActionView::Template.register_template_handler :jbuilder, JbuilderHandler
56
+ ActionView::Template.register_template_handler :jbuilder, JbuilderHandler
data/lib/railtie.rb ADDED
@@ -0,0 +1,8 @@
1
+ require 'rails/engine'
2
+
3
+ class Jbuilder
4
+ class Engine < ::Rails::Engine
5
+ config.app_generators.scaffold_controller = :jbuilder_scaffold_controller
6
+ config.app_generators.json_template_engine = :jbuilder
7
+ end
8
+ end
@@ -0,0 +1,32 @@
1
+ require 'rails/generators/test_case'
2
+ require 'generators/rails/jbuilder_generator'
3
+
4
+ class JbuilderGeneratorTest < Rails::Generators::TestCase
5
+ tests Rails::Generators::JbuilderGenerator
6
+ arguments %w(Post title body:text)
7
+ destination File.expand_path('../tmp', File.dirname(__FILE__))
8
+ setup :prepare_destination
9
+
10
+ test 'views are generated' do
11
+ run_generator
12
+
13
+ %w(index show).each do |view|
14
+ assert_file "app/views/posts/#{view}.json.jbuilder"
15
+ end
16
+ end
17
+
18
+ test 'index content' do
19
+ run_generator
20
+
21
+ assert_file 'app/views/posts/index.json.jbuilder' do |content|
22
+ assert_match /json\.array!\(@posts\) do \|post\|/, content
23
+ assert_match /json\.extract! post, :title, :body, :created_at, :updated_at/, content
24
+ assert_match /json\.url post_url\(post\)/, content
25
+ end
26
+
27
+ assert_file 'app/views/posts/show.json.jbuilder' do |content|
28
+ assert_match /json\.extract! @post, :title, :body, :created_at, :updated_at/, content
29
+ assert_match /json\.url post_url\(@post\)/, content
30
+ end
31
+ end
32
+ end
@@ -2,7 +2,6 @@ require 'test/unit'
2
2
  require 'action_view'
3
3
  require 'action_view/testing/resolvers'
4
4
  require 'active_support/cache'
5
-
6
5
  require 'jbuilder'
7
6
 
8
7
  module Rails
@@ -4,164 +4,171 @@ require 'active_support/inflector'
4
4
 
5
5
  require 'jbuilder'
6
6
 
7
+ class JbuilderProxy
8
+ # Faking Object#instance_eval for 1.8
9
+ def instance_eval(code)
10
+ eval code
11
+ end
12
+ end if ::RUBY_VERSION < '1.9'
13
+
7
14
  class JbuilderTest < ActiveSupport::TestCase
8
- test "single key" do
15
+ test 'single key' do
9
16
  json = Jbuilder.encode do |json|
10
- json.content "hello"
17
+ json.content 'hello'
11
18
  end
12
19
 
13
- assert_equal "hello", MultiJson.load(json)["content"]
20
+ assert_equal 'hello', MultiJson.load(json)['content']
14
21
  end
15
22
 
16
- test "single key with false value" do
23
+ test 'single key with false value' do
17
24
  json = Jbuilder.encode do |json|
18
25
  json.content false
19
26
  end
20
27
 
21
- assert_equal false, MultiJson.load(json)["content"]
28
+ assert_equal false, MultiJson.load(json)['content']
22
29
  end
23
30
 
24
- test "single key with nil value" do
31
+ test 'single key with nil value' do
25
32
  json = Jbuilder.encode do |json|
26
33
  json.content nil
27
34
  end
28
35
 
29
- assert MultiJson.load(json).has_key?("content")
30
- assert_equal nil, MultiJson.load(json)["content"]
36
+ assert MultiJson.load(json).has_key?('content')
37
+ assert_equal nil, MultiJson.load(json)['content']
31
38
  end
32
39
 
33
- test "multiple keys" do
40
+ test 'multiple keys' do
34
41
  json = Jbuilder.encode do |json|
35
- json.title "hello"
36
- json.content "world"
42
+ json.title 'hello'
43
+ json.content 'world'
37
44
  end
38
45
 
39
46
  MultiJson.load(json).tap do |parsed|
40
- assert_equal "hello", parsed["title"]
41
- assert_equal "world", parsed["content"]
47
+ assert_equal 'hello', parsed['title']
48
+ assert_equal 'world', parsed['content']
42
49
  end
43
50
  end
44
51
 
45
- test "extracting from object" do
46
- person = Struct.new(:name, :age).new("David", 32)
52
+ test 'extracting from object' do
53
+ person = Struct.new(:name, :age).new('David', 32)
47
54
 
48
55
  json = Jbuilder.encode do |json|
49
56
  json.extract! person, :name, :age
50
57
  end
51
58
 
52
59
  MultiJson.load(json).tap do |parsed|
53
- assert_equal "David", parsed["name"]
54
- assert_equal 32, parsed["age"]
60
+ assert_equal 'David', parsed['name']
61
+ assert_equal 32, parsed['age']
55
62
  end
56
63
  end
57
64
 
58
- test "extracting from object using call style for 1.9" do
59
- person = Struct.new(:name, :age).new("David", 32)
65
+ test 'extracting from object using call style for 1.9' do
66
+ person = Struct.new(:name, :age).new('David', 32)
60
67
 
61
68
  json = Jbuilder.encode do |json|
62
69
  if ::RUBY_VERSION > '1.9'
63
- instance_eval "json.(person, :name, :age)"
70
+ instance_eval 'json.(person, :name, :age)'
64
71
  else
65
- instance_eval "json.call(person, :name, :age)"
72
+ instance_eval 'json.call(person, :name, :age)'
66
73
  end
67
74
  end
68
75
 
69
76
  MultiJson.load(json).tap do |parsed|
70
- assert_equal "David", parsed["name"]
71
- assert_equal 32, parsed["age"]
77
+ assert_equal 'David', parsed['name']
78
+ assert_equal 32, parsed['age']
72
79
  end
73
80
  end
74
81
 
75
- test "extracting from hash" do
76
- person = {:name => "Jim", :age => 34}
82
+ test 'extracting from hash' do
83
+ person = {:name => 'Jim', :age => 34}
77
84
 
78
85
  json = Jbuilder.encode do |json|
79
86
  json.extract! person, :name, :age
80
87
  end
81
88
 
82
89
  MultiJson.load(json).tap do |parsed|
83
- assert_equal "Jim", parsed["name"]
84
- assert_equal 34, parsed["age"]
90
+ assert_equal 'Jim', parsed['name']
91
+ assert_equal 34, parsed['age']
85
92
  end
86
93
  end
87
94
 
88
- test "nesting single child with block" do
95
+ test 'nesting single child with block' do
89
96
  json = Jbuilder.encode do |json|
90
97
  json.author do
91
- json.name "David"
98
+ json.name 'David'
92
99
  json.age 32
93
100
  end
94
101
  end
95
102
 
96
103
  MultiJson.load(json).tap do |parsed|
97
- assert_equal "David", parsed["author"]["name"]
98
- assert_equal 32, parsed["author"]["age"]
104
+ assert_equal 'David', parsed['author']['name']
105
+ assert_equal 32, parsed['author']['age']
99
106
  end
100
107
  end
101
108
 
102
- test "nesting multiple children with block" do
109
+ test 'nesting multiple children with block' do
103
110
  json = Jbuilder.encode do |json|
104
111
  json.comments do
105
- json.child! { json.content "hello" }
106
- json.child! { json.content "world" }
112
+ json.child! { json.content 'hello' }
113
+ json.child! { json.content 'world' }
107
114
  end
108
115
  end
109
116
 
110
117
  MultiJson.load(json).tap do |parsed|
111
- assert_equal "hello", parsed["comments"].first["content"]
112
- assert_equal "world", parsed["comments"].second["content"]
118
+ assert_equal 'hello', parsed['comments'].first['content']
119
+ assert_equal 'world', parsed['comments'].second['content']
113
120
  end
114
121
  end
115
122
 
116
- test "nesting single child with inline extract" do
123
+ test 'nesting single child with inline extract' do
117
124
  person = Class.new do
118
125
  attr_reader :name, :age
119
126
 
120
127
  def initialize(name, age)
121
128
  @name, @age = name, age
122
129
  end
123
- end.new("David", 32)
130
+ end.new('David', 32)
124
131
 
125
132
  json = Jbuilder.encode do |json|
126
133
  json.author person, :name, :age
127
134
  end
128
135
 
129
136
  MultiJson.load(json).tap do |parsed|
130
- assert_equal "David", parsed["author"]["name"]
131
- assert_equal 32, parsed["author"]["age"]
137
+ assert_equal 'David', parsed['author']['name']
138
+ assert_equal 32, parsed['author']['age']
132
139
  end
133
140
  end
134
141
 
135
- test "nesting multiple children from array" do
136
- comments = [ Struct.new(:content, :id).new("hello", 1), Struct.new(:content, :id).new("world", 2) ]
142
+ test 'nesting multiple children from array' do
143
+ comments = [ Struct.new(:content, :id).new('hello', 1), Struct.new(:content, :id).new('world', 2) ]
137
144
 
138
145
  json = Jbuilder.encode do |json|
139
146
  json.comments comments, :content
140
147
  end
141
148
 
142
149
  MultiJson.load(json).tap do |parsed|
143
- assert_equal ["content"], parsed["comments"].first.keys
144
- assert_equal "hello", parsed["comments"].first["content"]
145
- assert_equal "world", parsed["comments"].second["content"]
150
+ assert_equal ['content'], parsed['comments'].first.keys
151
+ assert_equal 'hello', parsed['comments'].first['content']
152
+ assert_equal 'world', parsed['comments'].second['content']
146
153
  end
147
154
  end
148
155
 
149
- test "nesting multiple children from array when child array is empty" do
156
+ test 'nesting multiple children from array when child array is empty' do
150
157
  comments = []
151
158
 
152
159
  json = Jbuilder.encode do |json|
153
- json.name "Parent"
160
+ json.name 'Parent'
154
161
  json.comments comments, :content
155
162
  end
156
163
 
157
164
  MultiJson.load(json).tap do |parsed|
158
- assert_equal "Parent", parsed["name"]
159
- assert_equal [], parsed["comments"]
165
+ assert_equal 'Parent', parsed['name']
166
+ assert_equal [], parsed['comments']
160
167
  end
161
168
  end
162
169
 
163
- test "nesting multiple children from array with inline loop" do
164
- comments = [ Struct.new(:content, :id).new("hello", 1), Struct.new(:content, :id).new("world", 2) ]
170
+ test 'nesting multiple children from array with inline loop' do
171
+ comments = [ Struct.new(:content, :id).new('hello', 1), Struct.new(:content, :id).new('world', 2) ]
165
172
 
166
173
  json = Jbuilder.encode do |json|
167
174
  json.comments comments do |comment|
@@ -170,14 +177,24 @@ class JbuilderTest < ActiveSupport::TestCase
170
177
  end
171
178
 
172
179
  MultiJson.load(json).tap do |parsed|
173
- assert_equal ["content"], parsed["comments"].first.keys
174
- assert_equal "hello", parsed["comments"].first["content"]
175
- assert_equal "world", parsed["comments"].second["content"]
180
+ assert_equal ['content'], parsed['comments'].first.keys
181
+ assert_equal 'hello', parsed['comments'].first['content']
182
+ assert_equal 'world', parsed['comments'].second['content']
183
+ end
184
+ end
185
+
186
+ test 'handles nil-collections as empty arrays' do
187
+ json = Jbuilder.encode do |json|
188
+ json.comments nil do |comment|
189
+ json.content comment.content
190
+ end
176
191
  end
192
+
193
+ assert_equal [], MultiJson.load(json)['comments']
177
194
  end
178
195
 
179
- test "nesting multiple children from array with inline loop with old api" do
180
- comments = [ Struct.new(:content, :id).new("hello", 1), Struct.new(:content, :id).new("world", 2) ]
196
+ test 'nesting multiple children from array with inline loop with old api' do
197
+ comments = [ Struct.new(:content, :id).new('hello', 1), Struct.new(:content, :id).new('world', 2) ]
181
198
 
182
199
  json = Jbuilder.encode do |json|
183
200
  json.comments comments do |json, comment|
@@ -186,14 +203,14 @@ class JbuilderTest < ActiveSupport::TestCase
186
203
  end
187
204
 
188
205
  MultiJson.load(json).tap do |parsed|
189
- assert_equal ["content"], parsed["comments"].first.keys
190
- assert_equal "hello", parsed["comments"].first["content"]
191
- assert_equal "world", parsed["comments"].second["content"]
206
+ assert_equal ['content'], parsed['comments'].first.keys
207
+ assert_equal 'hello', parsed['comments'].first['content']
208
+ assert_equal 'world', parsed['comments'].second['content']
192
209
  end
193
210
  end
194
211
 
195
- test "nesting multiple children from array with inline loop on root" do
196
- comments = [ Struct.new(:content, :id).new("hello", 1), Struct.new(:content, :id).new("world", 2) ]
212
+ test 'nesting multiple children from array with inline loop on root' do
213
+ comments = [ Struct.new(:content, :id).new('hello', 1), Struct.new(:content, :id).new('world', 2) ]
197
214
 
198
215
  json = Jbuilder.encode do |json|
199
216
  json.call(comments) do |comment|
@@ -202,13 +219,13 @@ class JbuilderTest < ActiveSupport::TestCase
202
219
  end
203
220
 
204
221
  MultiJson.load(json).tap do |parsed|
205
- assert_equal "hello", parsed.first["content"]
206
- assert_equal "world", parsed.second["content"]
222
+ assert_equal 'hello', parsed.first['content']
223
+ assert_equal 'world', parsed.second['content']
207
224
  end
208
225
  end
209
226
 
210
- test "nesting multiple children from array with inline loop on root with old api" do
211
- comments = [ Struct.new(:content, :id).new("hello", 1), Struct.new(:content, :id).new("world", 2) ]
227
+ test 'nesting multiple children from array with inline loop on root with old api' do
228
+ comments = [ Struct.new(:content, :id).new('hello', 1), Struct.new(:content, :id).new('world', 2) ]
212
229
 
213
230
  json = Jbuilder.encode do |json|
214
231
  json.call(comments) do |json, comment|
@@ -217,47 +234,47 @@ class JbuilderTest < ActiveSupport::TestCase
217
234
  end
218
235
 
219
236
  MultiJson.load(json).tap do |parsed|
220
- assert_equal "hello", parsed.first["content"]
221
- assert_equal "world", parsed.second["content"]
237
+ assert_equal 'hello', parsed.first['content']
238
+ assert_equal 'world', parsed.second['content']
222
239
  end
223
240
  end
224
241
 
225
- test "array nested inside nested hash" do
242
+ test 'array nested inside nested hash' do
226
243
  json = Jbuilder.encode do |json|
227
244
  json.author do
228
- json.name "David"
245
+ json.name 'David'
229
246
  json.age 32
230
247
 
231
248
  json.comments do
232
- json.child! { json.content "hello" }
233
- json.child! { json.content "world" }
249
+ json.child! { json.content 'hello' }
250
+ json.child! { json.content 'world' }
234
251
  end
235
252
  end
236
253
  end
237
254
 
238
255
  MultiJson.load(json).tap do |parsed|
239
- assert_equal "hello", parsed["author"]["comments"].first["content"]
240
- assert_equal "world", parsed["author"]["comments"].second["content"]
256
+ assert_equal 'hello', parsed['author']['comments'].first['content']
257
+ assert_equal 'world', parsed['author']['comments'].second['content']
241
258
  end
242
259
  end
243
260
 
244
- test "array nested inside array" do
261
+ test 'array nested inside array' do
245
262
  json = Jbuilder.encode do |json|
246
263
  json.comments do
247
264
  json.child! do
248
265
  json.authors do
249
266
  json.child! do
250
- json.name "david"
267
+ json.name 'david'
251
268
  end
252
269
  end
253
270
  end
254
271
  end
255
272
  end
256
273
 
257
- assert_equal "david", MultiJson.load(json)["comments"].first["authors"].first["name"]
274
+ assert_equal 'david', MultiJson.load(json)['comments'].first['authors'].first['name']
258
275
  end
259
276
 
260
- test "directly set an array nested in another array" do
277
+ test 'directly set an array nested in another array' do
261
278
  data = [ { :department => 'QA', :not_in_json => 'hello', :names => ['John', 'David'] } ]
262
279
  json = Jbuilder.encode do |json|
263
280
  json.array! data do |object|
@@ -272,7 +289,7 @@ class JbuilderTest < ActiveSupport::TestCase
272
289
  assert_not_equal 'hello', MultiJson.load(json)[0]['not_in_json']
273
290
  end
274
291
 
275
- test "directly set an array nested in another array with old api" do
292
+ test 'directly set an array nested in another array with old api' do
276
293
  data = [ { :department => 'QA', :not_in_json => 'hello', :names => ['John', 'David'] } ]
277
294
  json = Jbuilder.encode do |json|
278
295
  json.array! data do |json, object|
@@ -287,20 +304,20 @@ class JbuilderTest < ActiveSupport::TestCase
287
304
  assert_not_equal 'hello', MultiJson.load(json)[0]['not_in_json']
288
305
  end
289
306
 
290
- test "nested jbuilder objects" do
307
+ test 'nested jbuilder objects' do
291
308
  to_nest = Jbuilder.new
292
- to_nest.nested_value "Nested Test"
309
+ to_nest.nested_value 'Nested Test'
293
310
  json = Jbuilder.encode do |json|
294
- json.value "Test"
311
+ json.value 'Test'
295
312
  json.nested to_nest
296
313
  end
297
314
  parsed = MultiJson.load(json)
298
- assert_equal "Test", parsed['value']
299
- assert_equal "Nested Test", parsed["nested"]["nested_value"]
315
+ assert_equal 'Test', parsed['value']
316
+ assert_equal 'Nested Test', parsed['nested']['nested_value']
300
317
  end
301
318
 
302
- test "top-level array" do
303
- comments = [ Struct.new(:content, :id).new("hello", 1), Struct.new(:content, :id).new("world", 2) ]
319
+ test 'top-level array' do
320
+ comments = [ Struct.new(:content, :id).new('hello', 1), Struct.new(:content, :id).new('world', 2) ]
304
321
 
305
322
  json = Jbuilder.encode do |json|
306
323
  json.array!(comments) do |comment|
@@ -309,12 +326,12 @@ class JbuilderTest < ActiveSupport::TestCase
309
326
  end
310
327
 
311
328
  MultiJson.load(json).tap do |parsed|
312
- assert_equal "hello", parsed.first["content"]
313
- assert_equal "world", parsed.second["content"]
329
+ assert_equal 'hello', parsed.first['content']
330
+ assert_equal 'world', parsed.second['content']
314
331
  end
315
332
  end
316
333
 
317
- test "empty top-level array" do
334
+ test 'empty top-level array' do
318
335
  comments = []
319
336
 
320
337
  json = Jbuilder.encode do |json|
@@ -326,29 +343,29 @@ class JbuilderTest < ActiveSupport::TestCase
326
343
  assert_equal [], MultiJson.load(json)
327
344
  end
328
345
 
329
- test "dynamically set a key/value" do
346
+ test 'dynamically set a key/value' do
330
347
  json = Jbuilder.encode do |json|
331
- json.set!(:each, "stuff")
348
+ json.set!(:each, 'stuff')
332
349
  end
333
350
 
334
- assert_equal "stuff", MultiJson.load(json)["each"]
351
+ assert_equal 'stuff', MultiJson.load(json)['each']
335
352
  end
336
353
 
337
- test "dynamically set a key/nested child with block" do
354
+ test 'dynamically set a key/nested child with block' do
338
355
  json = Jbuilder.encode do |json|
339
356
  json.set!(:author) do
340
- json.name "David"
357
+ json.name 'David'
341
358
  json.age 32
342
359
  end
343
360
  end
344
361
 
345
362
  MultiJson.load(json).tap do |parsed|
346
- assert_equal "David", parsed["author"]["name"]
347
- assert_equal 32, parsed["author"]["age"]
363
+ assert_equal 'David', parsed['author']['name']
364
+ assert_equal 32, parsed['author']['age']
348
365
  end
349
366
  end
350
367
 
351
- test "query like object" do
368
+ test 'query like object' do
352
369
  class Person
353
370
  attr_reader :name, :age
354
371
 
@@ -360,7 +377,7 @@ class JbuilderTest < ActiveSupport::TestCase
360
377
  include Enumerable
361
378
 
362
379
  def each(&block)
363
- [Person.new("Bob", 30), Person.new("Frank", 50)].each(&block)
380
+ [Person.new('Bob', 30), Person.new('Frank', 50)].each(&block)
364
381
  end
365
382
  def empty?
366
383
  false
@@ -372,94 +389,108 @@ class JbuilderTest < ActiveSupport::TestCase
372
389
  end
373
390
 
374
391
  parsed = MultiJson.load(result)
375
- assert_equal 2, parsed["relations"].length
376
- assert_equal "Bob", parsed["relations"][0]["name"]
377
- assert_equal 50, parsed["relations"][1]["age"]
392
+ assert_equal 2, parsed['relations'].length
393
+ assert_equal 'Bob', parsed['relations'][0]['name']
394
+ assert_equal 50, parsed['relations'][1]['age']
395
+ end
396
+
397
+ test 'initialize with positioned arguments (deprecated)' do
398
+ ::ActiveSupport::Deprecation.silence do
399
+ jbuilder = Jbuilder.new(1, 2)
400
+ assert_equal 1, jbuilder.instance_eval('@key_formatter')
401
+ assert_equal 2, jbuilder.instance_eval('@ignore_nil')
402
+ end
403
+ end
404
+
405
+ test 'initialize via options hash' do
406
+ jbuilder = Jbuilder.new(:key_formatter => 1, :ignore_nil => 2)
407
+ assert_equal 1, jbuilder.instance_eval('@key_formatter')
408
+ assert_equal 2, jbuilder.instance_eval('@ignore_nil')
378
409
  end
379
410
 
380
- test "key_format! with parameter" do
411
+ test 'key_format! with parameter' do
381
412
  json = Jbuilder.new
382
413
  json.key_format! :camelize => [:lower]
383
- json.camel_style "for JS"
414
+ json.camel_style 'for JS'
384
415
 
385
416
  assert_equal ['camelStyle'], json.attributes!.keys
386
417
  end
387
418
 
388
- test "key_format! with parameter not as an array" do
419
+ test 'key_format! with parameter not as an array' do
389
420
  json = Jbuilder.new
390
421
  json.key_format! :camelize => :lower
391
- json.camel_style "for JS"
422
+ json.camel_style 'for JS'
392
423
 
393
424
  assert_equal ['camelStyle'], json.attributes!.keys
394
425
  end
395
426
 
396
- test "key_format! propagates to child elements" do
427
+ test 'key_format! propagates to child elements' do
397
428
  json = Jbuilder.new
398
429
  json.key_format! :upcase
399
- json.level1 "one"
430
+ json.level1 'one'
400
431
  json.level2 do
401
- json.value "two"
432
+ json.value 'two'
402
433
  end
403
434
 
404
435
  result = json.attributes!
405
- assert_equal "one", result["LEVEL1"]
406
- assert_equal "two", result["LEVEL2"]["VALUE"]
436
+ assert_equal 'one', result['LEVEL1']
437
+ assert_equal 'two', result['LEVEL2']['VALUE']
407
438
  end
408
439
 
409
- test "key_format! resets after child element" do
440
+ test 'key_format! resets after child element' do
410
441
  json = Jbuilder.new
411
442
  json.level2 do
412
443
  json.key_format! :upcase
413
- json.value "two"
444
+ json.value 'two'
414
445
  end
415
- json.level1 "one"
446
+ json.level1 'one'
416
447
 
417
448
  result = json.attributes!
418
- assert_equal "two", result["level2"]["VALUE"]
419
- assert_equal "one", result["level1"]
449
+ assert_equal 'two', result['level2']['VALUE']
450
+ assert_equal 'one', result['level1']
420
451
  end
421
452
 
422
- test "key_format! with no parameter" do
453
+ test 'key_format! with no parameter' do
423
454
  json = Jbuilder.new
424
455
  json.key_format! :upcase
425
- json.lower "Value"
456
+ json.lower 'Value'
426
457
 
427
458
  assert_equal ['LOWER'], json.attributes!.keys
428
459
  end
429
460
 
430
- test "key_format! with multiple steps" do
461
+ test 'key_format! with multiple steps' do
431
462
  json = Jbuilder.new
432
463
  json.key_format! :upcase, :pluralize
433
- json.pill ""
464
+ json.pill ''
434
465
 
435
- assert_equal ["PILLs"], json.attributes!.keys
466
+ assert_equal ['PILLs'], json.attributes!.keys
436
467
  end
437
468
 
438
- test "key_format! with lambda/proc" do
469
+ test 'key_format! with lambda/proc' do
439
470
  json = Jbuilder.new
440
- json.key_format! lambda { |key| key + " and friends" }
441
- json.oats ""
471
+ json.key_format! lambda { |key| key + ' and friends' }
472
+ json.oats ''
442
473
 
443
- assert_equal ["oats and friends"], json.attributes!.keys
474
+ assert_equal ['oats and friends'], json.attributes!.keys
444
475
  end
445
476
 
446
- test "default key_format!" do
477
+ test 'default key_format!' do
447
478
  Jbuilder.key_format :camelize => :lower
448
479
  json = Jbuilder.new
449
- json.camel_style "for JS"
480
+ json.camel_style 'for JS'
450
481
 
451
482
  assert_equal ['camelStyle'], json.attributes!.keys
452
- Jbuilder.send(:class_variable_set, "@@key_formatter", Jbuilder::KeyFormatter.new)
483
+ Jbuilder.send(:class_variable_set, '@@key_formatter', Jbuilder::KeyFormatter.new)
453
484
  end
454
485
 
455
- test "don't use default key formatter directly" do
486
+ test 'do not use default key formatter directly' do
456
487
  json = Jbuilder.new
457
- json.key "value"
488
+ json.key 'value'
458
489
 
459
- assert_equal [], Jbuilder.send(:class_variable_get, "@@key_formatter").instance_variable_get("@cache").keys
490
+ assert_equal [], Jbuilder.send(:class_variable_get, '@@key_formatter').instance_variable_get('@cache').keys
460
491
  end
461
492
 
462
- test "ignore_nil! without a parameter" do
493
+ test 'ignore_nil! without a parameter' do
463
494
  json = Jbuilder.new
464
495
  json.ignore_nil!
465
496
  json.test nil
@@ -467,29 +498,29 @@ class JbuilderTest < ActiveSupport::TestCase
467
498
  assert_equal [], json.attributes!.keys
468
499
  end
469
500
 
470
- test "ignore_nil! with parameter" do
501
+ test 'ignore_nil! with parameter' do
471
502
  json = Jbuilder.new
472
503
  json.ignore_nil! true
473
- json.name "Bob"
504
+ json.name 'Bob'
474
505
  json.dne nil
475
506
 
476
- assert_equal ["name"], json.attributes!.keys
507
+ assert_equal ['name'], json.attributes!.keys
477
508
 
478
509
  json = Jbuilder.new
479
510
  json.ignore_nil! false
480
- json.name "Bob"
511
+ json.name 'Bob'
481
512
  json.dne nil
482
513
 
483
- assert_equal ["name", "dne"], json.attributes!.keys
514
+ assert_equal ['name', 'dne'], json.attributes!.keys
484
515
  end
485
516
 
486
- test "default ignore_nil!" do
517
+ test 'default ignore_nil!' do
487
518
  Jbuilder.ignore_nil
488
519
  json = Jbuilder.new
489
- json.name "Bob"
520
+ json.name 'Bob'
490
521
  json.dne nil
491
522
 
492
- assert_equal ["name"], json.attributes!.keys
493
- Jbuilder.send(:class_variable_set, "@@ignore_nil", false)
523
+ assert_equal ['name'], json.attributes!.keys
524
+ Jbuilder.send(:class_variable_set, '@@ignore_nil', false)
494
525
  end
495
526
  end
@@ -0,0 +1,56 @@
1
+ require 'rails/generators/test_case'
2
+ require 'generators/rails/jbuilder_scaffold_controller_generator'
3
+
4
+ class JbuilderScaffoldControllerGeneratorTest < Rails::Generators::TestCase
5
+ tests Rails::Generators::JbuilderScaffoldControllerGenerator
6
+ arguments %w(Post title body:text)
7
+ destination File.expand_path('../tmp', File.dirname(__FILE__))
8
+ setup :prepare_destination
9
+
10
+ test 'controller content' do
11
+ run_generator
12
+
13
+ assert_file 'app/controllers/posts_controller.rb' do |content|
14
+ assert_instance_method :index, content do |m|
15
+ assert_match /@posts = Post\.all/, m
16
+ end
17
+
18
+ assert_instance_method :show, content do |m|
19
+ assert m.blank?
20
+ end
21
+
22
+ assert_instance_method :new, content do |m|
23
+ assert_match /@post = Post\.new/, m
24
+ end
25
+
26
+ assert_instance_method :edit, content do |m|
27
+ assert m.blank?
28
+ end
29
+
30
+ assert_instance_method :create, content do |m|
31
+ assert_match /@post = Post\.new\(post_params\)/, m
32
+ assert_match /@post\.save/, m
33
+ assert_match /format\.html \{ redirect_to @post, notice: 'Post was successfully created\.' \}/, m
34
+ assert_match /format\.json \{ render action: 'show', status: :created, location: @post \}/, m
35
+ assert_match /format\.html \{ render action: 'new' \}/, m
36
+ assert_match /format\.json \{ render json: @post\.errors, status: :unprocessable_entity \}/, m
37
+ end
38
+
39
+ assert_instance_method :update, content do |m|
40
+ assert_match /format\.html \{ redirect_to @post, notice: 'Post was successfully updated\.' \}/, m
41
+ assert_match /format\.json \{ head :no_content \}/, m
42
+ assert_match /format\.html \{ render action: 'edit' \}/, m
43
+ assert_match /format\.json \{ render json: @post.errors, status: :unprocessable_entity \}/, m
44
+ end
45
+
46
+ assert_instance_method :destroy, content do |m|
47
+ assert_match /@post\.destroy/, m
48
+ assert_match /format\.html { redirect_to posts_url \}/, m
49
+ assert_match /format\.json \{ head :no_content \}/, m
50
+ end
51
+
52
+ assert_match(/def post_params/, content)
53
+ assert_match(/params\.require\(:post\)\.permit\(:title, :body\)/, content)
54
+ end
55
+ end
56
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jbuilder
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.1
4
+ version: 1.0.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-12-20 00:00:00.000000000 Z
12
+ date: 2013-01-10 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport
@@ -27,6 +27,22 @@ dependencies:
27
27
  - - ! '>='
28
28
  - !ruby/object:Gem::Version
29
29
  version: 3.0.0
30
+ - !ruby/object:Gem::Dependency
31
+ name: rake
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: 10.0.3
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: 10.0.3
30
46
  description:
31
47
  email: david@37signals.com
32
48
  executables: []
@@ -34,16 +50,24 @@ extensions: []
34
50
  extra_rdoc_files: []
35
51
  files:
36
52
  - ./Gemfile
37
- - ./Gemfile.lock
53
+ - ./Gemfile-1.8
38
54
  - ./jbuilder-0.9.0.gem
39
55
  - ./jbuilder.gemspec
56
+ - ./lib/generators/rails/jbuilder_generator.rb
57
+ - ./lib/generators/rails/jbuilder_scaffold_controller_generator.rb
58
+ - ./lib/generators/rails/templates/controller.rb
59
+ - ./lib/generators/rails/templates/index.json.jbuilder
60
+ - ./lib/generators/rails/templates/show.json.jbuilder
40
61
  - ./lib/jbuilder.rb
41
62
  - ./lib/jbuilder_template.rb
63
+ - ./lib/railtie.rb
42
64
  - ./MIT-LICENSE
43
65
  - ./Rakefile
44
66
  - ./README.md
67
+ - ./test/jbuilder_generator_test.rb
45
68
  - ./test/jbuilder_template_test.rb
46
69
  - ./test/jbuilder_test.rb
70
+ - ./test/scaffold_controller_generator_test.rb
47
71
  homepage:
48
72
  licenses: []
49
73
  post_install_message:
data/Gemfile.lock DELETED
@@ -1,50 +0,0 @@
1
- PATH
2
- remote: .
3
- specs:
4
- jbuilder (0.9.1)
5
- activesupport (>= 3.0.0)
6
-
7
- GEM
8
- remote: http://rubygems.org/
9
- specs:
10
- actionpack (3.2.8)
11
- activemodel (= 3.2.8)
12
- activesupport (= 3.2.8)
13
- builder (~> 3.0.0)
14
- erubis (~> 2.7.0)
15
- journey (~> 1.0.4)
16
- rack (~> 1.4.0)
17
- rack-cache (~> 1.2)
18
- rack-test (~> 0.6.1)
19
- sprockets (~> 2.1.3)
20
- activemodel (3.2.8)
21
- activesupport (= 3.2.8)
22
- builder (~> 3.0.0)
23
- activesupport (3.2.8)
24
- i18n (~> 0.6)
25
- multi_json (~> 1.0)
26
- builder (3.0.0)
27
- erubis (2.7.0)
28
- hike (1.2.1)
29
- i18n (0.6.1)
30
- journey (1.0.4)
31
- multi_json (1.3.6)
32
- rack (1.4.1)
33
- rack-cache (1.2)
34
- rack (>= 0.4)
35
- rack-test (0.6.1)
36
- rack (>= 1.0)
37
- rake (0.9.2.2)
38
- sprockets (2.1.3)
39
- hike (~> 1.2)
40
- rack (~> 1.0)
41
- tilt (~> 1.1, != 1.3.0)
42
- tilt (1.3.3)
43
-
44
- PLATFORMS
45
- ruby
46
-
47
- DEPENDENCIES
48
- actionpack
49
- jbuilder!
50
- rake