jbuilder 0.9.1 → 1.0.0

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