bldr 0.3.0 → 0.5.2

Sign up to get free protection for your applications and to get access to all the features.
data/.rvmrc CHANGED
@@ -1 +1 @@
1
- rvm 1.9.2
1
+ rvm 1.9.3
data/HISTORY.md CHANGED
@@ -1,3 +1,6 @@
1
+ ## 0.5.0 (2012-02-08)
2
+ * Add support "partials" (@ihunter)
3
+
1
4
  ## 0.2.0 (2011-09-09)
2
5
  * Add new `attribute` inferred object syntax (@ihunter)
3
6
 
@@ -1,4 +1,4 @@
1
- Copyright (c) 2011 Alex Sharp
1
+ Copyright (c) 2011-2012 Alex Sharp
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -9,11 +9,19 @@ the box -- Rails 3 support is planned for the near future.
9
9
 
10
10
  If you would like to contribute, pull requests with specs are warmly accepted :)
11
11
 
12
+ ## Why
13
+
14
+ If you're building an API, `Model#to_json` just doesn't cut it. Besides the JSON
15
+ representation of your models arguably being a presentation concern, trying
16
+ to cram all of this logic into an `#as_json` method quickly turns into pure chaos.
17
+
18
+ There are other json templating libraries available -- [rabl](http://github.com/nesquena/rabl) being the most popular -- but I wasn't satisfied with any of the DSL's, so I created Bldr.
19
+
12
20
  ## Features
13
21
 
14
22
  * Simple json templating DSL
15
- * Uses Tilt's built-in rendering and template caching for better
16
- performance
23
+ * Uses Tilt's built-in rendering and template caching for better performance
24
+ * Partials
17
25
 
18
26
  ## Installation
19
27
 
@@ -42,271 +50,7 @@ end
42
50
 
43
51
  ## Usage
44
52
 
45
- In your sinatra endpoints/actions, use the `bldr` helper method to
46
- render templates.
47
-
48
- ```ruby
49
- get "/posts" do
50
- # ...
51
- posts = Post.all
52
- bldr :'template.json', :locals => {:posts => posts}
53
- end
54
-
55
- # views/template.json.bldr
56
- collection :posts => posts do
57
- attributes :title
58
- attribute :comment_count { |post| post.comments.count }
59
-
60
- collection :comments => current_object.comments do
61
- attributes :body, :author, :email
62
- end
63
- end
64
- ```
65
-
66
- ## Examples
67
-
68
- ### Rendering a basic object
69
-
70
- ```ruby
71
- object do
72
- attribute :title, "my title"
73
- end
74
- ```
75
-
76
- Output:
77
-
78
- ```javascript
79
- {
80
- "title": "my title"
81
- }
82
- ```
83
-
84
- ### Rendering a simple list of attributes
85
-
86
- ```ruby
87
- object :post do
88
- attribute :title, "my title"
89
- end
90
- ```
91
-
92
- Output:
93
-
94
- ```javascript
95
- {
96
- "post": {
97
- "title": "my title"
98
- }
99
- }
100
- ```
101
-
102
- ### Rendering a simple list of attributes from an object
103
-
104
- ```ruby
105
- object :post => post do
106
- attributes :title, :body
107
- end
108
- ```
109
-
110
- Output:
111
-
112
- ```javascript
113
- {
114
- "post": {
115
- "title": "my title",
116
- "body": "..."
117
- }
118
- }
119
- ```
120
-
121
- ### Dynamic attributes
122
-
123
- ```ruby
124
- object :post => post do
125
- attribute :comment_count do |post|
126
- post.comments.count
127
- end
128
- end
129
- ```
130
-
131
- Output:
132
-
133
- ```javascript
134
- {
135
- "post": {
136
- "comment_count": 1
137
- }
138
- }
139
-
140
- ```
141
-
142
- ### Attribute aliases
143
-
144
- ```ruby
145
- object :post => post do
146
- attributes :title, :body
147
-
148
- object :author => post.author do
149
- attribute :surname => :last_name
150
- end
151
- end
152
- ```
153
-
154
- Output:
155
-
156
- ```javascript
157
- {
158
- "post": {
159
- "title": "my title",
160
- "body": "...",
161
- "author": {
162
- "surname": "Doe"
163
- }
164
- }
165
- }
166
- ```
167
-
168
- ### Nested objects
169
-
170
- ```ruby
171
- object :post => post do
172
- attributes :title, :body
173
-
174
- object :author => post.author do
175
- attributes :first_name, :last_name, :email
176
-
177
- attribute(:full_name) { |author| "#{author.first_name} #{author.last_name}" }
178
- end
179
- end
180
- ```
181
-
182
- Output:
183
-
184
- ```javascript
185
- {
186
- "post": {
187
- "title": "my title",
188
- "body": "...",
189
- "author": {
190
- "first_name": "John",
191
- "last_name": "Doe",
192
- "email": "john@doe.com",
193
- "full_name": "John Doe"
194
- }
195
- }
196
- }
197
- ```
198
-
199
- ### Root-level attributes
200
-
201
- ```ruby
202
- get '/redirector' do
203
- url = params['redirect_url']
204
- bldr :'redirect.json', :locals => {:url => url}
205
- end
206
-
207
- # views/redirect.json.bldr
208
- object do
209
- attribute(:redirect_to) { url }
210
- end
211
- ```
212
-
213
- Output:
214
-
215
- ```javascript
216
- {"redirect_to": "http://example.org"}
217
- ```
218
-
219
- ### Collections
220
-
221
- All the examples above can be used inside a collection block. Here we
222
- assume a Post model which has many Comments. You might use the below
223
- code to render an action which returns a collection of posts, where
224
- each post has a collection of comments.
225
-
226
- ```ruby
227
- collection :posts => posts do
228
- attributes :title
229
- attribute :comment_count { |post| post.comments.count }
230
-
231
- # current_object
232
- collection :comments => current_object.comments do
233
- attributes :body, :author_name, :author_email
234
- end
235
- end
236
- ```
237
-
238
- Output:
239
-
240
- ```javascript
241
- {
242
- "posts": [
243
- {
244
- "title": "my title",
245
- "comment_count": 2,
246
- "comments": [
247
- {
248
- "body": "...",
249
- "author_name": "Comment Troll",
250
- "email": "troll@trolling.edu"
251
- },
252
- {
253
- "body": "...",
254
- "author_name": "Uber Troll",
255
- "email": "uber.troll@earthlink.net"
256
- }
257
- ]
258
- }
259
- ]
260
- }
261
- ```
262
-
263
- When inside of a collection block, you can use the `current_object`
264
- method to access the member of the collection currently being iterated
265
- over. This allows you to do nested collections, as in the example above.
266
-
267
- ### Templates
268
-
269
- It is recommended to name your templates with the content type extension before
270
- the .bldr extension. For example: `my_template.json.bldr`.
271
-
272
- The templates themselves are just plain ruby code. They are evaluated in the context of a
273
- `Bldr::Node` instance, which provides the bldr DSL. The DSL is comprised
274
- primarily of 3 simple methods:
275
-
276
- + `object` - Creates an object
277
- + `collection` - Iterates over a collection of objects
278
- + `attributes` - Add attributes to the current object.
279
-
280
- ### Local Variables
281
-
282
- You may pass local variables from your sinatra actions to bldr templates
283
- by passing the `bldr` method a `:locals` hash, like so:
284
-
285
- ```ruby
286
- get '/posts' do
287
- posts = Post.all.recent
288
-
289
- bldr :'posts/index.json', :locals => {:posts => posts}
290
- end
291
- ```
292
-
293
- ### Custom Handlers
294
-
295
- Bldr supports the definition of custom handlers, based on the class of specific
296
- values in the result. You would make use of this to define how specific classes
297
- are rendered by Bldr at a global level.
298
-
299
- For example, the `BSON::ObjectId` class defines `to_json` and `as_json` methods
300
- that produce a result like the following: `{"$oid": "4e77a682364141ecf5000002"}`.
301
- If you wanted to over-ride this default format, you could do so by defining a
302
- custom handler:
303
-
304
- ```ruby
305
- # place in a file that get's loaded before your application code
306
- Bldr.handler BSON::ObjectId do |val|
307
- val.to_s # => "4e77a682364141ecf5000002"
308
- end
309
- ```
53
+ See the [Documentation & Examples](https://github.com/ajsharp/bldr/wiki/Documentation-&-Examples) page on the wiki.
310
54
 
311
55
  ## Editor Syntax Support
312
56
 
@@ -318,20 +62,21 @@ au BufRead,BufNewFile *.bldr set filetype=ruby
318
62
 
319
63
  ## TODO
320
64
 
321
- * Rails 3 support
65
+ * Rails 3 support. An attempt for this was made for this but was reverted in e1cfd7fcbe130b316d95773d8c73ece4e247200e. Feel free to take a shot.
322
66
  * Replace current_object with a block param for collection methods
323
67
  * XML support
324
68
 
325
69
  ## Acknowledgements
326
70
 
327
71
  * [RABL](http://github.com/nesquena/rabl) - Inspiration
328
- * [Tilt](https://github.com/rtomayko/tilt) - Mega awesome goodness
72
+ * [Tilt](https://github.com/rtomayko/tilt) - Mega awesome templating goodness
329
73
 
330
74
  ## Contributors
331
75
 
332
76
  * Ian Hunter (@ihunter)
77
+ * Justin Smestad (@jsmestad)
333
78
 
334
79
  ## Copyright
335
80
 
336
- Copyright (c) 2011 Alex Sharp. See the MIT-LICENSE file for full
81
+ Copyright (c) 2011-2012 Alex Sharp. See the MIT-LICENSE file for full
337
82
  copyright information.
@@ -24,5 +24,6 @@ Gem::Specification.new do |s|
24
24
  s.add_development_dependency 'json_pure'
25
25
  s.add_development_dependency 'sinatra', '~>1.2.6'
26
26
  s.add_development_dependency 'tilt', '~>1.3.2'
27
- s.add_development_dependency 'yajl-ruby'
27
+ s.add_development_dependency 'yajl-ruby', '>= 1.0'
28
+ s.add_development_dependency 'actionpack', '~> 3.0.7'
28
29
  end
@@ -1,11 +1,17 @@
1
-
2
1
  $:.unshift(File.dirname(File.expand_path(__FILE__)))
3
2
 
3
+ begin
4
+ require 'tilt'
5
+ rescue LoadError
6
+ end
7
+
4
8
  require 'multi_json'
5
- require 'bldr/engine'
6
- require 'bldr/template'
7
9
  require 'bldr/node'
8
10
 
11
+ if defined?(Tilt)
12
+ require 'bldr/template'
13
+ end
14
+
9
15
  module Bldr
10
16
  class << self
11
17
 
@@ -3,7 +3,7 @@ module Bldr
3
3
 
4
4
  class Node
5
5
 
6
- attr_reader :current_object, :result, :parent
6
+ attr_reader :current_object, :result, :parent, :opts, :views
7
7
 
8
8
  # Initialize a new Node instance.
9
9
  #
@@ -19,28 +19,15 @@ module Bldr
19
19
  # @param [Object] value an object to serialize.
20
20
  def initialize(value = nil, opts = {}, &block)
21
21
  @current_object = value
22
+ @opts = opts
22
23
  @parent = opts[:parent]
23
-
24
+ @views = opts[:views]
24
25
  # Storage hash for all descendant nodes
25
26
  @result = {}
26
27
 
27
28
  instance_eval(&block) if block_given?
28
29
  end
29
-
30
- # Merge the local results into the ancestor result hash.
31
- #
32
- # @return [Hash]
33
- def render!
34
- result
35
- end
36
-
37
- # Return the json-encoded result hash.
38
- #
39
- # @return [String] the json-encoded result hash
40
- def to_json
41
- MultiJson.encode(result)
42
- end
43
-
30
+
44
31
  # Create and render a node.
45
32
  #
46
33
  # @example A keyed object
@@ -84,23 +71,36 @@ module Bldr
84
71
  value = nil
85
72
  end
86
73
 
87
- node = Node.new(value, :parent => self, &block)
88
- merge_result!(key, node.render!)
89
- self.to_json
74
+ return nil if value.nil? and base.kind_of? Hash
75
+ node = Node.new(value, opts.merge(:parent => self), &block)
76
+ merge_result!(key, node.result)
77
+
78
+ self
90
79
  end
91
80
 
92
81
  def collection(items, &block)
93
- key = items.keys.first
94
- values = items.values.to_a.first
95
82
 
96
- vals = if values
97
- values.map{|item| Node.new(item, :parent => self, &block).render!}
83
+ if items.respond_to?('keys')
84
+ key = items.keys.first
85
+ values = items.values.to_a.first
98
86
  else
99
- []
87
+ key = nil
88
+ values = items
100
89
  end
101
- merge_result! key, vals
90
+
91
+ vals = if values
92
+ values.map{|item| Node.new(item, opts.merge(:parent => self), &block).result}
93
+ else
94
+ []
95
+ end
102
96
 
103
- self.to_json
97
+ if items.respond_to?('keys')
98
+ merge_result! key, vals
99
+ else
100
+ @result = massage_value(vals)
101
+ end
102
+
103
+ self
104
104
  end
105
105
 
106
106
  # Add attributes to the result hash in a variety of ways
@@ -138,7 +138,10 @@ module Bldr
138
138
  #
139
139
  # @return [Nil]
140
140
  def attributes(*args, &block)
141
- raise(ArgumentError, "You cannot use #attributes when inferred object is not present.") if current_object.nil?
141
+ if current_object.nil?
142
+ raise(ArgumentError, "No current_object to apply #attributes to.")
143
+ end
144
+
142
145
  args.each do |arg|
143
146
  if arg.is_a?(Hash)
144
147
  merge_result!(arg.keys.first, current_object.send(arg.values.first))
@@ -146,18 +149,17 @@ module Bldr
146
149
  merge_result!(arg, current_object.send(arg))
147
150
  end
148
151
  end
149
- nil
150
152
  end
151
153
 
152
154
  def attribute(*args,&block)
153
155
  if block_given?
154
156
  raise(ArgumentError, "You may only pass one argument to #attribute when using the block syntax.") if args.size > 1
155
- raise(ArgumentError, "You cannot use a block of arity > 0 if inferred object is not present.") if block.arity > 0 and current_object.nil?
157
+ raise(ArgumentError, "You cannot use a block of arity > 0 if current_object is not present.") if block.arity > 0 and current_object.nil?
156
158
  merge_result!(args.first, (block.arity == 1) ? block.call(current_object) : current_object.instance_eval(&block))
157
159
  else
158
160
  case args.size
159
161
  when 1 # inferred object
160
- raise(ArgumentError, "You cannot pass one argument to #attribute when inferred object is not present.") if current_object.nil?
162
+ raise(ArgumentError, "#attribute can't be used when there is no current_object.") if current_object.nil?
161
163
  if args[0].is_a?(Hash)
162
164
  merge_result!(args[0].keys.first, current_object.send(args[0].values.first))
163
165
  else
@@ -169,10 +171,33 @@ module Bldr
169
171
  raise(ArgumentError, "You cannot pass more than two arguments to #attribute.")
170
172
  end
171
173
  end
172
- nil
174
+ end
175
+
176
+ # Render a template inline within a view
177
+ #
178
+ # @example Simple render
179
+ # object :person => dude do
180
+ # template "path/to/template"
181
+ # end
182
+ #
183
+ # @example Using locals
184
+ # object :person => dude do
185
+ # template "path/to/template", :locals => {:foo => 'bar'}
186
+ # end
187
+ def template(template,options={})
188
+ locals = options[:locals] || options['locals']
189
+ merge_result! nil, Bldr::Template.new(find_template(template)).render(self, locals).result
173
190
  end
174
191
 
175
192
  private
193
+
194
+ def find_template(template)
195
+ path = []
196
+ path << views if views
197
+ template += ".json.bldr" unless template =~ /\.json\.bldr$/
198
+ path << template
199
+ File.join(*path)
200
+ end
176
201
 
177
202
  # Merges values into the "local" result hash.
178
203
  def merge_result!(key, val)
@@ -183,10 +208,6 @@ module Bldr
183
208
  end
184
209
  end
185
210
 
186
- def append_result!(key, val)
187
- result[key] << massage_value(val)
188
- end
189
-
190
211
  # put any specializations in here
191
212
  # @todo: add config handlers to specify your own overridable Class->lambda methods of serialization
192
213
  def massage_value(val)
@@ -196,6 +217,6 @@ module Bldr
196
217
  val
197
218
  end
198
219
  end
199
-
220
+
200
221
  end
201
222
  end
@@ -3,8 +3,8 @@ require 'tilt'
3
3
  module Bldr
4
4
 
5
5
  class Template < Tilt::Template
6
- # attr_reader :engine
7
- # self.default_mime_type = 'application/json'
6
+
7
+ self.default_mime_type = 'application/json'
8
8
 
9
9
  def initialize_engine
10
10
  require_template_library 'bldr'
@@ -15,13 +15,12 @@ module Bldr
15
15
  end
16
16
 
17
17
  def prepare
18
- @engine = Bldr::Engine.new(data, options)
18
+ # We get NotImplementedError by Tilt when we don't have this method
19
19
  end
20
20
 
21
21
  def precompiled_template(locals)
22
22
  data.to_s
23
23
  end
24
-
25
24
  end
26
25
 
27
26
  Tilt.register 'bldr', Bldr::Template
@@ -1,4 +1,4 @@
1
1
 
2
2
  module Bldr
3
- VERSION = '0.3.0'
3
+ VERSION = '0.5.2'
4
4
  end
@@ -5,18 +5,30 @@ module Sinatra
5
5
  module Bldr
6
6
  module Helpers
7
7
 
8
+ # Wrapper for Tilt's `render` method
9
+ #
10
+ # We use this to properly set the scope the template gets rendered
11
+ # within to a `Bldr::Node` object and pass in local variables.
12
+ #
8
13
  # @param [String, Symbol] template the template to render
9
14
  # Can be a relative file location or a string template.
10
15
  # The template may also be passed in as the block argument
11
16
  # to this method, in which case, template argument is nil.
12
17
  #
18
+ # @example Render a template in a file
19
+ # get '/users/:id' do
20
+ # user = User.find(params['id'])
21
+ # bldr :'users/public.bldr', :locals => {:user => user}
22
+ # end
23
+ #
13
24
  # @param [Hash] opts a hash of options
14
25
  # @option opts [Hash] :locals a hash of local variables to be used in the template
15
26
  # @option
16
27
  def bldr(template, opts = {}, &block)
17
- opts[:scope] = ::Bldr::Node.new
28
+ opts[:scope] = ::Bldr::Node.new(nil,opts.merge(:views => (settings.views || "./views")))
18
29
  locals = opts.delete(:locals)
19
- render(:bldr, template, opts, locals, &block)
30
+ MultiJson.encode render(:bldr, template, opts, locals, &block).result
31
+ # @todo add support for alternate formats, like plist
20
32
  end
21
33
  end
22
34
 
@@ -0,0 +1,3 @@
1
+ object do
2
+ attribute(:foo) { "bar" }
3
+ end
@@ -0,0 +1,3 @@
1
+ object :name => obj do
2
+ attribute :foo
3
+ end
@@ -0,0 +1,3 @@
1
+ object do
2
+ attribute(:foo) { "bar" }
3
+ end
@@ -8,12 +8,12 @@ describe "Defining different types of handlers" do
8
8
  "bar"
9
9
  end
10
10
 
11
- output = "{\"foo\":\"bar\"}"
11
+ output = {:foo => 'bar'}
12
12
  node = Bldr::Node.new do
13
13
  object { attribute(:foo) { Time.now } }
14
14
  end
15
15
 
16
- node.to_json.should == output
16
+ node.result.should == output
17
17
  end
18
18
  end
19
19
 
@@ -10,7 +10,7 @@ describe "evaluating a tilt template" do
10
10
  alex.name = 'alex'
11
11
 
12
12
  tpl = Bldr::Template.new { "object(:person => alex) { attribute(:name) }" }
13
- tpl.render(Bldr::Node.new, :alex => alex).should == jsonify({:person => {:name => 'alex'}})
13
+ tpl.render(Bldr::Node.new, :alex => alex).result.should == {:person => {:name => 'alex'}}
14
14
  end
15
15
 
16
16
  it "works when render two top-level objects" do
@@ -24,11 +24,11 @@ describe "evaluating a tilt template" do
24
24
  RUBY
25
25
  }
26
26
 
27
- result = tpl.render(Bldr::Node.new, :alex => alex, :john => john)
28
- result.should == jsonify({
27
+ result = tpl.render(Bldr::Node.new, :alex => alex, :john => john).result
28
+ result.should == {
29
29
  :person_1 => {:name => 'alex'},
30
30
  :person_2 => {:name => 'john'}
31
- })
31
+ }
32
32
  end
33
33
 
34
34
  it "renders nil -> null correctly" do
@@ -38,8 +38,8 @@ describe "evaluating a tilt template" do
38
38
  object(:person_1 => alex) { attributes(:age) }
39
39
  RUBY
40
40
  }
41
- result = tpl.render(Bldr::Node.new, :alex => alex)
42
- result.should == %%{"person_1":{"age":null}}%
41
+ result = tpl.render(Bldr::Node.new, :alex => alex).result
42
+ result.should == {:person_1 => {:age => nil}}
43
43
  end
44
44
 
45
45
  describe "root Object nodes" do
@@ -55,8 +55,8 @@ describe "evaluating a tilt template" do
55
55
  end
56
56
  RUBY
57
57
  }
58
- result = tpl.render(Bldr::Node.new, :alex => alex, :ian => ian)
59
- parse_json(result).should == {'person' => {'name' => 'alex', 'age' => 25}}
58
+ result = tpl.render(Bldr::Node.new, :alex => alex, :ian => ian).result
59
+ result.should == {:person => {:name => 'alex', :age => 25}}
60
60
  end
61
61
 
62
62
  it "returns json for root object templates with nested collections" do
@@ -71,9 +71,9 @@ describe "evaluating a tilt template" do
71
71
  end
72
72
  RUBY
73
73
  }
74
- result = tpl.render(Bldr::Node.new, :alex => alex, :friends => [ian])
75
- parse_json(result).should == {
76
- 'person'=> {'name' => 'alex', 'age' => 25, 'friends' => [{'name' => 'ian', 'age' => 32}]}
74
+ result = tpl.render(Bldr::Node.new, :alex => alex, :friends => [ian]).result
75
+ result.should == {
76
+ :person=> {:name => 'alex', :age => 25, :friends => [{:name => 'ian', :age => 32}]}
77
77
  }
78
78
  end
79
79
 
@@ -86,8 +86,8 @@ describe "evaluating a tilt template" do
86
86
  end
87
87
  RUBY
88
88
  }
89
- result = tpl.render(Bldr::Node.new, :alex => alex)
90
- result.should == %%{"person_1":{"age":null}}%
89
+ result = tpl.render(Bldr::Node.new, :alex => alex).result
90
+ result.should == {:person_1 => {:age => nil}}
91
91
  end
92
92
 
93
93
  end
@@ -105,9 +105,9 @@ describe "evaluating a tilt template" do
105
105
  end
106
106
  RUBY
107
107
  }
108
- result = tpl.render(Bldr::Node.new, :people => [alex,ian])
109
- parse_json(result).should == {
110
- 'people'=> [{'name' => 'alex', 'age' => 25},{'name' => 'ian', 'age' => 32}]
108
+ result = tpl.render(Bldr::Node.new, :people => [alex,ian]).result
109
+ result.should == {
110
+ :people => [{:name => 'alex', :age => 25}, {:name => 'ian', :age => 32}]
111
111
  }
112
112
  end
113
113
 
@@ -122,16 +122,16 @@ describe "evaluating a tilt template" do
122
122
  end
123
123
  RUBY
124
124
  }
125
- result = tpl.render(Bldr::Node.new, :people => [alex,ian])
126
- parse_json(result).should == {
127
- 'people'=> [{
128
- 'name' => 'alex',
129
- 'age' => 25,
130
- "friends" => [{"name" => 'bo', "age" => 33}]
125
+ result = tpl.render(Bldr::Node.new, :people => [alex,ian]).result
126
+ result.should == {
127
+ :people=> [{
128
+ :name => 'alex',
129
+ :age => 25,
130
+ :friends => [{:name => 'bo', :age => 33}]
131
131
  },{
132
- 'name' => 'ian',
133
- 'age' => 32,
134
- "friends" => [{"name" => 'eric', "age" => 34}]
132
+ :name => 'ian',
133
+ :age => 32,
134
+ :friends => [{:name => 'eric', :age => 34}]
135
135
  }]
136
136
  }
137
137
  end
@@ -1,10 +1,10 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  ERROR_MESSAGES = { :attribute_lambda_one_argument => "You may only pass one argument to #attribute when using the block syntax.",
4
- :attribute_inferred_missing_one_argument => "You cannot pass one argument to #attribute when inferred object is not present.",
4
+ :attribute_inferred_missing_one_argument => "#attribute can't be used when there is no current_object.",
5
5
  :attribute_more_than_two_arg => "You cannot pass more than two arguments to #attribute.",
6
- :attribute_inferred_missing_arity_too_large => "You cannot use a block of arity > 0 if inferred object is not present.",
7
- :attributes_inferred_missing => "You cannot use #attributes when inferred object is not present." }
6
+ :attribute_inferred_missing_arity_too_large => "You cannot use a block of arity > 0 if current_object is not present.",
7
+ :attributes_inferred_missing => "No current_object to apply #attributes to." }
8
8
 
9
9
  describe "Node#object" do
10
10
 
@@ -52,7 +52,7 @@ describe "Node#object" do
52
52
  end
53
53
  it "renders 2 arguments statically" do
54
54
  node = wrap { attribute(:name, "alex") }
55
- node.render!.should == {:name => 'alex'}
55
+ node.result.should == {:name => 'alex'}
56
56
  end
57
57
  it "renders 1 argument and one lambda with zero arity" do
58
58
  node = wrap {
@@ -60,7 +60,7 @@ describe "Node#object" do
60
60
  "alex"
61
61
  end
62
62
  }
63
- node.render!.should == {:name => 'alex'}
63
+ node.result.should == {:name => 'alex'}
64
64
  end
65
65
  it "errors on 1 argument and one lambda with arity 1" do
66
66
  expect {
@@ -73,7 +73,7 @@ describe "Node#object" do
73
73
  end
74
74
  it "should render null attributes to null, not 'null'" do
75
75
  node = wrap { attribute(:name, nil) }
76
- node.render!.should == {:name => nil}
76
+ node.result.should == {:name => nil}
77
77
  end
78
78
 
79
79
  end
@@ -136,7 +136,7 @@ describe "Node#object" do
136
136
  end
137
137
  it "renders 2 arguments statically" do
138
138
  node = wrap { attribute(:name, "alex") }
139
- node.render!.should == {:person => {:name => 'alex'}}
139
+ node.result.should == {:person => {:name => 'alex'}}
140
140
  end
141
141
  it "renders 1 argument and one lambda with zero arity" do
142
142
  node = wrap {
@@ -144,7 +144,7 @@ describe "Node#object" do
144
144
  "alex"
145
145
  end
146
146
  }
147
- node.render!.should == {:person => {:name => 'alex'}}
147
+ node.result.should == {:person => {:name => 'alex'}}
148
148
  end
149
149
  it "errors on 1 argument and one lambda with arity 1" do
150
150
  expect {
@@ -200,23 +200,23 @@ describe "Node#object" do
200
200
  end
201
201
  it "renders 1 argument to the inferred object" do
202
202
  node = wrap { attribute(:name) }
203
- node.render!.should == {:person => {:name => 'alex'}}
203
+ node.result.should == {:person => {:name => 'alex'}}
204
204
  end
205
205
  it "renders 1 argument hash to the inferred object as the different key" do
206
206
  node = wrap { attribute(:fake => :name) }
207
- node.render!.should == {:person => {:fake => 'alex'}}
207
+ node.result.should == {:person => {:fake => 'alex'}}
208
208
  end
209
209
  it "renders 2 arguments statically" do
210
210
  node = wrap { attribute(:name, "ian") }
211
- node.render!.should == {:person => {:name => 'ian'}}
211
+ node.result.should == {:person => {:name => 'ian'}}
212
212
  end
213
213
  it "renders 1 argument and one lambda with zero arity" do
214
214
  node = wrap { attribute(:name){"ian"} }
215
- node.render!.should == {:person => {:name => 'ian'}}
215
+ node.result.should == {:person => {:name => 'ian'}}
216
216
  end
217
217
  it "renders 1 argument and one lambda with arity 1" do
218
218
  node = wrap { attribute(:name){|person| person.name} }
219
- node.render!.should == {:person => {:name => 'alex'}}
219
+ node.result.should == {:person => {:name => 'alex'}}
220
220
  end
221
221
  it "renders nil attributes" do
222
222
  node = node_wrap do
@@ -225,15 +225,14 @@ describe "Node#object" do
225
225
  end
226
226
  end
227
227
 
228
- node.render!.should == {:person => {:age => nil}}
228
+ node.result.should == {:person => {:age => nil}}
229
229
  end
230
230
 
231
231
  end
232
232
 
233
233
  describe "#attributes" do
234
-
235
- it "errors if the current_object is nil" do
236
- expect {
234
+ describe "when an object key is passed a null value" do
235
+ subject {
237
236
  node = node_wrap do
238
237
  object(:person => nil) do
239
238
  attributes(:one, :two) do |person|
@@ -241,11 +240,20 @@ describe "Node#object" do
241
240
  end
242
241
  end
243
242
  end
244
- }.to raise_error(ArgumentError, ERROR_MESSAGES[:attributes_inferred_missing])
243
+ }
244
+
245
+ it "does not raise an inferred object error" do
246
+ expect {
247
+ subject
248
+ }.not_to raise_error(ArgumentError, ERROR_MESSAGES[:attributes_inferred_missing])
249
+ end
250
+
251
+ its(:result) { should == {} }
245
252
  end
253
+
246
254
  it "renders each argument against the inferred object" do
247
255
  node = wrap { attributes(:name, :age) }
248
- node.render!.should == {:person => {:name => 'alex', :age => 25}}
256
+ node.result.should == {:person => {:name => 'alex', :age => 25}}
249
257
  end
250
258
  it "renders nil attributes" do
251
259
  node = node_wrap do
@@ -254,7 +262,7 @@ describe "Node#object" do
254
262
  end
255
263
  end
256
264
 
257
- node.render!.should == {:person => {:name => 'alex', :age => nil}}
265
+ node.result.should == {:person => {:name => 'alex', :age => nil}}
258
266
  end
259
267
 
260
268
  end
@@ -263,26 +271,25 @@ describe "Node#object" do
263
271
 
264
272
  describe "embedded objects" do
265
273
  it "evaluates the block and returns json" do
266
- node = Bldr::Node.new
267
- result = node.object(:dude => Person.new("alex")) do
268
- attributes :name
269
-
270
- object(:bro => Person.new("john")) do
274
+ node = node_wrap do
275
+ object(:dude => Person.new("alex")) do
271
276
  attributes :name
277
+
278
+ object(:bro => Person.new("john")) do
279
+ attributes :name
280
+ end
272
281
  end
273
282
  end
274
283
 
275
- result.should == jsonify({
276
- :dude => {:name => 'alex', :bro => {:name => 'john'}}
277
- })
284
+ node.result.should == {:dude => {:name => 'alex', :bro => {:name => 'john'}}}
278
285
  end
279
286
  end
280
287
 
281
288
  end
282
289
 
283
- describe "Node#render!" do
290
+ describe "Node#result" do
284
291
  it "returns an empty hash when not passed an object" do
285
- Bldr::Node.new.render!.should == {}
292
+ Bldr::Node.new.result.should == {}
286
293
  end
287
294
 
288
295
  it "a document with a single node with no nesting" do
@@ -292,7 +299,7 @@ describe "Node#render!" do
292
299
  end
293
300
  end
294
301
 
295
- node.render!.should == {:person => {:name => 'alex'}}
302
+ node.result.should == {:person => {:name => 'alex'}}
296
303
  end
297
304
 
298
305
  it "works for multiple top-level objects" do
@@ -308,7 +315,7 @@ describe "Node#render!" do
308
315
  end
309
316
  end
310
317
 
311
- node.render!.should == {:alex => {:name => 'alex'}, :john => {:name => 'john'}}
318
+ node.result.should == {:alex => {:name => 'alex'}, :john => {:name => 'john'}}
312
319
  end
313
320
 
314
321
  it "recursively renders nested objects" do
@@ -322,7 +329,7 @@ describe "Node#render!" do
322
329
  end
323
330
  end
324
331
 
325
- node.render!.should == {
332
+ node.result.should == {
326
333
  :alex => {
327
334
  :name => 'alex',
328
335
  :friend => {:name => 'john'}
@@ -343,7 +350,7 @@ describe "Node#render!" do
343
350
  end
344
351
  end
345
352
 
346
- node.render!.should == {:person => {:surname => 'alex', :age => 25}}
353
+ node.result.should == {:person => {:surname => 'alex', :age => 25}}
347
354
  end
348
355
  end
349
356
  end
@@ -360,12 +367,12 @@ describe "Node#to_json" do
360
367
  end
361
368
  end
362
369
 
363
- node.to_json.should == jsonify({
370
+ node.result.should == {
364
371
  :person => {
365
372
  :name => 'alex',
366
373
  :friend => {:name => 'pete', :age => 30}
367
374
  }
368
- })
375
+ }
369
376
  end
370
377
 
371
378
  it "returns null values for nil attributes" do
@@ -375,8 +382,8 @@ describe "Node#to_json" do
375
382
  end
376
383
  end
377
384
 
378
- parse_json(node.to_json)['person'].should have_key('age')
379
- parse_json(node.to_json)['person']['age'].should be_nil
385
+ node.result[:person].should have_key(:age)
386
+ node.result[:person][:age].should be_nil
380
387
  end
381
388
  end
382
389
 
@@ -392,7 +399,7 @@ describe "Node#collection" do
392
399
  end
393
400
  end
394
401
 
395
- node.render!.should == {
402
+ node.result.should == {
396
403
  :person => {
397
404
  :name => 'alex', :age => 26,
398
405
  :friends => [{:name => 'john', :age => 24}, {:name => 'jeff', :age => 25}]
@@ -401,14 +408,24 @@ describe "Node#collection" do
401
408
  end
402
409
 
403
410
  # @todo fix this
404
- it "renders properly when a collection is the root node" do
411
+ it "renders properly when a collection is the named root node" do
405
412
  nodes = node_wrap do
406
413
  collection :people => [Person.new('bert'), Person.new('ernie')] do
407
414
  attributes :name
408
415
  end
409
416
  end
410
417
 
411
- nodes.render!.should == {:people => [{:name => 'bert'}, {:name => 'ernie'}]}
418
+ nodes.result.should == {:people => [{:name => 'bert'}, {:name => 'ernie'}]}
419
+ end
420
+
421
+ it "renders properly when a collection is the root node" do
422
+ nodes = node_wrap do
423
+ collection [Person.new('bert'), Person.new('ernie')] do
424
+ attributes :name
425
+ end
426
+ end
427
+
428
+ nodes.result.should == [{:name => 'bert'}, {:name => 'ernie'}]
412
429
  end
413
430
 
414
431
  it "gracefully handles empty collections" do
@@ -418,7 +435,7 @@ describe "Node#collection" do
418
435
  end
419
436
  end
420
437
 
421
- nodes.render!.should == {:people => []}
438
+ nodes.result.should == {:people => []}
422
439
  end
423
440
 
424
441
  it "gracefully handles nil collections" do
@@ -428,7 +445,7 @@ describe "Node#collection" do
428
445
  end
429
446
  end
430
447
 
431
- nodes.render!.should == {:people => []}
448
+ nodes.result.should == {:people => []}
432
449
  end
433
450
 
434
451
  it "renders nested collections properly" do
@@ -446,7 +463,7 @@ describe "Node#collection" do
446
463
  end
447
464
  end
448
465
 
449
- nodes.render!.should == {
466
+ nodes.result.should == {
450
467
  :posts => [
451
468
  {:title => 'my post', :comment_count => 1, :comments => [{:body => 'my comment'}]}
452
469
  ]
@@ -471,7 +488,7 @@ describe "Node#collection" do
471
488
  end
472
489
  end
473
490
 
474
- nodes.render!.should == {
491
+ nodes.result.should == {
475
492
  :posts => [
476
493
  {
477
494
  :title => 'post 1',
@@ -498,7 +515,104 @@ describe "Node#collection" do
498
515
  end
499
516
  end
500
517
 
501
- node.render!.should == {:name => 'john doe', :age => 25}
518
+ node.result.should == {:name => 'john doe', :age => 25}
502
519
  end
503
520
 
504
521
  end
522
+
523
+ describe "Node#partial" do
524
+ it "includes the partial as a top level" do
525
+ nodes = node_wrap do
526
+ template "spec/fixtures/partial.json.bldr"
527
+ end
528
+
529
+ nodes.result.should == {:foo => "bar"}
530
+ end
531
+
532
+ it "includes the partial on a top level object" do
533
+ nodes = node_wrap do
534
+ object :container do
535
+ attribute(:blah) { "baz" }
536
+ template "spec/fixtures/partial.json.bldr"
537
+ end
538
+ end
539
+
540
+ nodes.result.should == {:container => {:blah => "baz", :foo => "bar"}}
541
+ end
542
+
543
+ it "includes the partial on a top level collection" do
544
+ nodes = node_wrap do
545
+ collection :people => [Person.new('bert'), Person.new('ernie')] do
546
+ attribute(:blah) { "baz" }
547
+ template "spec/fixtures/partial.json.bldr"
548
+ end
549
+ end
550
+
551
+ nodes.result.should == {:people => [{:blah => "baz", :foo => 'bar'}, {:blah => "baz", :foo => 'bar'}]}
552
+ end
553
+
554
+ it "includes the partial on a sub object" do
555
+ nodes = node_wrap do
556
+ object :container do
557
+ object :sub do
558
+ attribute(:blah) { "baz" }
559
+ template "spec/fixtures/partial.json.bldr"
560
+ end
561
+ end
562
+ end
563
+
564
+ nodes.result.should == {:container => {:sub => {:blah => "baz", :foo => "bar"}}}
565
+ end
566
+
567
+ it "includes the partial on a sub collection" do
568
+ nodes = node_wrap do
569
+ object :container do
570
+ collection :people => [Person.new('bert'), Person.new('ernie')] do
571
+ attribute(:blah) { "baz" }
572
+ template "spec/fixtures/partial.json.bldr"
573
+ end
574
+ end
575
+ end
576
+
577
+ nodes.result.should == {:container => {:people => [{:blah => "baz", :foo => 'bar'}, {:blah => "baz", :foo => 'bar'}]}}
578
+ end
579
+
580
+ it "includes both the partials" do
581
+ nodes = node_wrap do
582
+ object :container do
583
+ template "spec/fixtures/partial.json.bldr"
584
+ object :sub do
585
+ attribute(:blah) { "baz" }
586
+ template "spec/fixtures/partial.json.bldr"
587
+ end
588
+ end
589
+ end
590
+
591
+ nodes.result.should == {:container => {:foo => "bar", :sub => {:blah => "baz", :foo => "bar"}}}
592
+ end
593
+
594
+ it "includes the partial with the locals" do
595
+ Obj = Struct.new(:foo)
596
+ nodes = node_wrap do
597
+ template "spec/fixtures/partial_with_locals.json.bldr", :locals => {:obj => Obj.new('test')}
598
+ end
599
+
600
+ nodes.result.should == {:name => {:foo => 'test'}}
601
+ end
602
+
603
+ it "raises an error when the partial isn't found" do
604
+ expect {
605
+ nodes = node_wrap do
606
+ template "unknown/path"
607
+ end
608
+ }.to raise_error(Errno::ENOENT)
609
+ end
610
+
611
+ it "doesn't raise an error when with a base path option specified and the right file" do
612
+ nodes = node_wrap nil, :views => 'spec/fixtures/some' do
613
+ object :foo do
614
+ template "include"
615
+ end
616
+ end
617
+ end
618
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bldr
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.5.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-09-19 00:00:00.000000000Z
12
+ date: 2012-02-21 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: multi_json
16
- requirement: &2153229880 !ruby/object:Gem::Requirement
16
+ requirement: &70126171949220 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: 1.0.3
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *2153229880
24
+ version_requirements: *70126171949220
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: json_pure
27
- requirement: &2153229460 !ruby/object:Gem::Requirement
27
+ requirement: &70126171948780 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: '0'
33
33
  type: :development
34
34
  prerelease: false
35
- version_requirements: *2153229460
35
+ version_requirements: *70126171948780
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: sinatra
38
- requirement: &2153228920 !ruby/object:Gem::Requirement
38
+ requirement: &70126171948200 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ~>
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: 1.2.6
44
44
  type: :development
45
45
  prerelease: false
46
- version_requirements: *2153228920
46
+ version_requirements: *70126171948200
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: tilt
49
- requirement: &2153228420 !ruby/object:Gem::Requirement
49
+ requirement: &70126171947660 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ~>
@@ -54,18 +54,29 @@ dependencies:
54
54
  version: 1.3.2
55
55
  type: :development
56
56
  prerelease: false
57
- version_requirements: *2153228420
57
+ version_requirements: *70126171947660
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: yajl-ruby
60
- requirement: &2153228040 !ruby/object:Gem::Requirement
60
+ requirement: &70126171947160 !ruby/object:Gem::Requirement
61
61
  none: false
62
62
  requirements:
63
63
  - - ! '>='
64
64
  - !ruby/object:Gem::Version
65
- version: '0'
65
+ version: '1.0'
66
+ type: :development
67
+ prerelease: false
68
+ version_requirements: *70126171947160
69
+ - !ruby/object:Gem::Dependency
70
+ name: actionpack
71
+ requirement: &70126171946680 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ~>
75
+ - !ruby/object:Gem::Version
76
+ version: 3.0.7
66
77
  type: :development
67
78
  prerelease: false
68
- version_requirements: *2153228040
79
+ version_requirements: *70126171946680
69
80
  description: Provides a simple and intuitive templating DSL for serializing objects
70
81
  to JSON.
71
82
  email:
@@ -84,7 +95,6 @@ files:
84
95
  - Rakefile
85
96
  - bldr.gemspec
86
97
  - lib/bldr.rb
87
- - lib/bldr/engine.rb
88
98
  - lib/bldr/node.rb
89
99
  - lib/bldr/template.rb
90
100
  - lib/bldr/version.rb
@@ -93,7 +103,10 @@ files:
93
103
  - perf/benchmark.rb
94
104
  - perf/results.txt
95
105
  - spec/fixtures/nested_objects.json.bldr
106
+ - spec/fixtures/partial.json.bldr
107
+ - spec/fixtures/partial_with_locals.json.bldr
96
108
  - spec/fixtures/root_template.json.bldr
109
+ - spec/fixtures/some/include.json.bldr
97
110
  - spec/functional/handlers_spec.rb
98
111
  - spec/functional/tilt_template_spec.rb
99
112
  - spec/integration/sinatra_spec.rb
@@ -123,13 +136,16 @@ required_rubygems_version: !ruby/object:Gem::Requirement
123
136
  version: '0'
124
137
  requirements: []
125
138
  rubyforge_project: bldr
126
- rubygems_version: 1.8.6
139
+ rubygems_version: 1.8.15
127
140
  signing_key:
128
141
  specification_version: 3
129
142
  summary: Templating library with a simple, minimalist DSL.
130
143
  test_files:
131
144
  - spec/fixtures/nested_objects.json.bldr
145
+ - spec/fixtures/partial.json.bldr
146
+ - spec/fixtures/partial_with_locals.json.bldr
132
147
  - spec/fixtures/root_template.json.bldr
148
+ - spec/fixtures/some/include.json.bldr
133
149
  - spec/functional/handlers_spec.rb
134
150
  - spec/functional/tilt_template_spec.rb
135
151
  - spec/integration/sinatra_spec.rb
@@ -1,15 +0,0 @@
1
-
2
- module Bldr
3
-
4
- class Engine
5
- attr_reader :template, :options, :result
6
-
7
- def initialize(template, options = {})
8
- @template, @options = template, options
9
- @result = {}
10
- @handlers = {}
11
- end
12
-
13
- end
14
-
15
- end