rabl 0.6.10 → 0.6.11

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,5 +1,13 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## 0.6.11
4
+
5
+ * Changes send to __send__ (Thanks @alindeman)
6
+ * Change object/collection checks to :map instead of :each
7
+ * Adds support for auto-escaping attribute configuration (Thanks @databyte)
8
+ * Adds support for configuration of view_paths (Thanks @ivanvanderbyl)
9
+ * Fix issue with helpers caching check
10
+
3
11
  ## 0.6.10
4
12
 
5
13
  * Fixes expected behavior with nil and collection keyword
data/README.md CHANGED
@@ -101,6 +101,7 @@ Rabl.configure do |config|
101
101
  # Commented as these are defaults
102
102
  # config.cache_all_output = false
103
103
  # config.cache_sources = false
104
+ # config.escape_all_output = false
104
105
  # config.json_engine = nil # Any multi\_json engines
105
106
  # config.msgpack_engine = nil # Defaults to ::MessagePack
106
107
  # config.bson_engine = nil # Defaults to ::BSON
@@ -112,6 +113,7 @@ Rabl.configure do |config|
112
113
  # config.include_xml_root = false
113
114
  # config.enable_json_callbacks = false
114
115
  # config.xml_options = { :dasherize => true, :skip_types => false }
116
+ # config.view_paths = []
115
117
  end
116
118
  ```
117
119
 
@@ -122,10 +124,16 @@ output if the incoming request has a 'callback' parameter.
122
124
  If `cache_sources` is set to `true`, template lookups will be cached for improved performance.
123
125
  The cache can be reset manually by running `Rabl.reset_source_cache!` within your application.
124
126
 
125
- If `cache_all_output` is set to `true` then every template including each individual template used as part of a collection will be cached separately.
127
+ If `cache_all_output` is set to `true`, every template including each individual template used as part of a collection will be cached separately.
126
128
  Additionally, anything within child, glue and partial will also be cached separately.
127
129
  To cache just a single template, see the section titled 'Caching' below.
128
130
 
131
+ If `escape_all_output` is set to `true` and ActiveSupport is available, attribute output will be escaped using [ERB::Util.html_escape](http://corelib.rubyonrails.org/classes/ERB/Util.html).
132
+ Custom nodes will not be escaped, use `ERB::Util.h(value)`.
133
+
134
+ If `view_paths` is set to a path, this view path will be checked for every rabl template within your application.
135
+ Add to this path especially when including Rabl in an engine and using view paths within a another Rails app.
136
+
129
137
  Note that the `json_engine` option uses [multi_json](http://intridea.com/2010/6/14/multi-json-the-swappable-json-handler) engine
130
138
  defaults so that in most cases you **don't need to configure this** directly. If you wish to use yajl as
131
139
  the primary JSON encoding engine simply add that to your Gemfile:
@@ -139,7 +147,7 @@ and RABL will automatically start using that engine for encoding your JSON respo
139
147
 
140
148
  ### Format Configuration ###
141
149
 
142
- RABL supports configuration for MessagePack, BSON, and Plist. Check the
150
+ RABL supports configuration for MessagePack, BSON, and Plist. Check the
143
151
  [Format Configuration](https://github.com/nesquena/rabl/wiki/Configuring-Formats) page for more details.
144
152
 
145
153
  ## Usage ##
@@ -380,7 +388,7 @@ Note that RABL can be nested arbitrarily deep within child nodes to allow for th
380
388
 
381
389
  ### Caching ###
382
390
 
383
- RABL has built-in caching support for templates leveraging fragment caching strategies. Note that caching is currently **only available** for but support for other frameworks is planned in a future release. Simplest caching usage is:
391
+ RABL has built-in caching support for templates leveraging fragment caching strategies. Note that caching is currently **only available** for Rails but support for other frameworks is planned in a future release. Simplest caching usage is:
384
392
 
385
393
  ```ruby
386
394
  # app/views/users/show.json.rabl
@@ -490,7 +498,7 @@ Thanks to [Miso](http://gomiso.com) for allowing me to create this for our appli
490
498
  * [Nathan Esquenazi](https://github.com/nesquena) - Creator of the project
491
499
  * [Arthur Chiu](https://github.com/achiu) - Core Maintainer, Riot Testing Guru
492
500
  * [Tim Lee](https://github.com/timothy1ee) - RABL was a great name chosen by the Miso CTO.
493
- * [David Sommers](https://github.com/databyte) - Enhanced template resolution and added caching support
501
+ * [David Sommers](https://github.com/databyte) - Template resolution, caching support, and much more
494
502
  * [Rick Thomas](https://github.com/rickthomasjr) - Added options for extends and Sinatra testing
495
503
  * [Benjamin Yu](https://github.com/byu) - Added msgpack format support
496
504
  * [Chris Kimpton](https://github.com/kimptoc) - Helping with documentation and wiki
@@ -21,7 +21,7 @@ context "PostsController" do
21
21
 
22
22
  context "for index action" do
23
23
  setup do
24
- get "/posts", format: :json
24
+ get "/posts", :format => :json
25
25
  end
26
26
 
27
27
  # Attributes (regular)
@@ -74,7 +74,7 @@ context "PostsController" do
74
74
 
75
75
  context "for show action" do
76
76
  setup do
77
- get "/posts/#{@post1.id}", format: :json
77
+ get "/posts/#{@post1.id}", :format => :json
78
78
  json_output['post']
79
79
  end
80
80
 
@@ -21,7 +21,7 @@ context "PostsController" do
21
21
 
22
22
  context "for index action" do
23
23
  setup do
24
- get "/posts", format: :json
24
+ get "/posts", :format => :json
25
25
  end
26
26
 
27
27
  # Attributes (regular)
@@ -74,7 +74,7 @@ context "PostsController" do
74
74
 
75
75
  context "for show action" do
76
76
  setup do
77
- get "/posts/#{@post1.id}", format: :json
77
+ get "/posts/#{@post1.id}", :format => :json
78
78
  json_output['post']
79
79
  end
80
80
 
@@ -21,7 +21,7 @@ context "PostsController" do
21
21
 
22
22
  context "for index action" do
23
23
  setup do
24
- get "/posts", format: :json
24
+ get "/posts", :format => :json
25
25
  end
26
26
 
27
27
  # Attributes (regular)
@@ -74,7 +74,7 @@ context "PostsController" do
74
74
 
75
75
  context "for show action" do
76
76
  setup do
77
- get "/posts/#{@post1.id}", format: :json
77
+ get "/posts/#{@post1.id}", :format => :json
78
78
  json_output['post']
79
79
  end
80
80
 
@@ -17,7 +17,7 @@ context "PostsController" do
17
17
  Post.delete_all
18
18
  @post1 = Post.create(:title => "Foo", :body => "Bar", :user_id => @user1.id)
19
19
  @post2 = Post.create(:title => "Baz", :body => "Bah", :user_id => @user2.id)
20
- @post3 = Post.create(:title => "Kaz", :body => "Paz", :user_id => @user3.id)
20
+ @post3 = Post.create(:title => "Kaz", :body => "<script>alert('xss & test');</script>", :user_id => @user3.id)
21
21
  @posts = [@post1, @post2, @post3]
22
22
  end
23
23
 
@@ -74,6 +74,32 @@ context "PostsController" do
74
74
  end.includes(:created_by_admin)
75
75
  end # index action, json
76
76
 
77
+ context "escaping output in index action" do
78
+ context "for first post" do
79
+ setup do
80
+ Rabl.configuration.escape_all_output = true
81
+ get "/posts/#{@post1.id}", format: :json
82
+ json_output['post']
83
+ end
84
+
85
+ # Attributes (regular)
86
+ asserts("contains post title") { topic['title'] }.equals { @post1.title }
87
+ asserts("contains post body") { topic['body'] }.equals { @post1.body }
88
+ end
89
+
90
+ context "for third post with script tags" do
91
+ setup do
92
+ Rabl.configuration.escape_all_output = true
93
+ get "/posts/#{@post3.id}", format: :json
94
+ json_output['post']
95
+ end
96
+
97
+ # Attributes (regular)
98
+ asserts("contains post title") { topic['title'] }.equals { @post3.title }
99
+ asserts("contains escaped post body") { topic['body'] }.equals { ERB::Util.h(@post3.body) }
100
+ end
101
+ end # escaping output
102
+
77
103
  context "for show action" do
78
104
  setup do
79
105
  get "/posts/#{@post1.id}", format: :json
@@ -85,7 +111,7 @@ context "PostsController" do
85
111
  asserts("contains post body") { topic['body'] }.equals { @post1.body }
86
112
 
87
113
  # Attributes (custom name)
88
- asserts("contains post posted_at") { topic['posted_at'] }.equals { @post1.created_at.iso8601 }
114
+ asserts("contains post posted_at") { topic['posted_at'] }.equals { @post1.created_at.utc.to_s }
89
115
 
90
116
  # Child
91
117
  asserts("contains post user child username") { topic["user"]["username"] }.equals { @post1.user.username }
@@ -35,7 +35,7 @@ context "UsersController" do
35
35
  # Attributes (custom name)
36
36
  asserts("contains registered_at") do
37
37
  json_output.map { |u| u["user"]["registered_at"] }
38
- end.equals { @users.map(&:created_at).map(&:iso8601) }
38
+ end.equals { @users.map(&:created_at).map(&:utc).map(&:to_s) }
39
39
 
40
40
  # Node (renders based on attribute)
41
41
  asserts("contains role") do
@@ -64,7 +64,7 @@ context "UsersController" do
64
64
  asserts("contains email") { json_output["person"]["email"] }.equals { @user1.email }
65
65
  asserts("contains location") { json_output["person"]["location"] }.equals { @user1.location }
66
66
  # Attributes (custom name)
67
- asserts("contains registered_at") { json_output["person"]["registered_at"] }.equals { @user1.created_at.iso8601 }
67
+ asserts("contains registered_at") { json_output["person"]["registered_at"] }.equals { @user1.created_at.utc.to_s }
68
68
  # Node (renders based on attribute)
69
69
  asserts("contains role node") { json_output["person"]["role"] }.equals "normal"
70
70
 
@@ -21,7 +21,7 @@ context "PostsController" do
21
21
 
22
22
  context "for index action" do
23
23
  setup do
24
- get "/posts", format: :json
24
+ get "/posts", :format => :json
25
25
  end
26
26
 
27
27
  # Attributes (regular)
@@ -74,7 +74,7 @@ context "PostsController" do
74
74
 
75
75
  context "for show action" do
76
76
  setup do
77
- get "/posts/#{@post1.id}", format: :json
77
+ get "/posts/#{@post1.id}", :format => :json
78
78
  json_output['post']
79
79
  end
80
80
 
@@ -63,7 +63,7 @@ module Rabl
63
63
  # Indicates an attribute or method should be included in the json output
64
64
  # attribute :foo, :as => "bar"
65
65
  def attribute(name, options={})
66
- @_result[options[:as] || name] = @_object.send(name) if @_object && @_object.respond_to?(name)
66
+ @_result[options[:as] || name] = data_object_attribute(name) if @_object && @_object.respond_to?(name)
67
67
  end
68
68
  alias_method :attributes, :attribute
69
69
 
@@ -36,6 +36,8 @@ module Rabl
36
36
  attr_writer :xml_options
37
37
  attr_accessor :cache_sources
38
38
  attr_accessor :cache_all_output
39
+ attr_accessor :escape_all_output
40
+ attr_accessor :view_paths
39
41
 
40
42
  DEFAULT_XML_OPTIONS = { :dasherize => true, :skip_types => false }
41
43
 
@@ -55,6 +57,8 @@ module Rabl
55
57
  @xml_options = {}
56
58
  @cache_sources = false
57
59
  @cache_all_output = false
60
+ @escape_all_output = false
61
+ @view_paths = []
58
62
  end
59
63
 
60
64
  # @param [Symbol, String, #encode] engine_name The name of a JSON engine,
@@ -94,7 +98,7 @@ module Rabl
94
98
  #
95
99
  # @param [Symbol] option Key for a given attribute
96
100
  def [](option)
97
- send(option)
101
+ __send__(option)
98
102
  end
99
103
 
100
104
  # Returns merged default and inputted xml options
@@ -176,7 +176,7 @@ module Rabl
176
176
  # Includes a helper module with a RABL template
177
177
  # helper ExampleHelper
178
178
  def helper(*klazzes)
179
- klazzes.each { |klazz| self.class.send(:include, klazz) }
179
+ klazzes.each { |klazz| self.class.__send__(:include, klazz) }
180
180
  end
181
181
  alias_method :helpers, :helper
182
182
 
@@ -225,7 +225,7 @@ module Rabl
225
225
 
226
226
  # Supports calling helpers defined for the template scope using method_missing hook
227
227
  def method_missing(name, *args, &block)
228
- context_scope.respond_to?(name) ? context_scope.send(name, *args, &block) : super
228
+ context_scope.respond_to?(name, true) ? context_scope.__send__(name, *args, &block) : super
229
229
  end
230
230
 
231
231
  def copy_instance_variables_from(object, exclude = []) #:nodoc:
@@ -8,7 +8,12 @@ module Rabl
8
8
  # data_object(:user => :person) => @_object.send(:user)
9
9
  def data_object(data)
10
10
  data = (data.is_a?(Hash) && data.keys.size == 1) ? data.keys.first : data
11
- data.is_a?(Symbol) && @_object ? @_object.send(data) : data
11
+ data.is_a?(Symbol) && @_object ? @_object.__send__(data) : data
12
+ end
13
+
14
+ # data_object_attribute(data) => @_object.send(data)
15
+ def data_object_attribute(data)
16
+ escape_output @_object.__send__(data)
12
17
  end
13
18
 
14
19
  # data_name(data) => "user"
@@ -19,7 +24,7 @@ module Rabl
19
24
  def data_name(data)
20
25
  return nil unless data # nil or false
21
26
  return data.values.first if data.is_a?(Hash) # @user => :user
22
- data = @_object.send(data) if data.is_a?(Symbol) && @_object # :address
27
+ data = @_object.__send__(data) if data.is_a?(Symbol) && @_object # :address
23
28
  if is_collection?(data) && data.respond_to?(:first) # data collection
24
29
  data_name(data.first).to_s.pluralize if data.first.present?
25
30
  elsif is_object?(data) # actual data object
@@ -50,12 +55,12 @@ module Rabl
50
55
  # is_object?([]) => false
51
56
  # is_object?({}) => false
52
57
  def is_object?(obj)
53
- obj && !data_object(obj).respond_to?(:each)
58
+ obj && !data_object(obj).respond_to?(:map)
54
59
  end
55
60
 
56
61
  # Returns true if the obj is a collection of items
57
62
  def is_collection?(obj)
58
- obj && data_object(obj).respond_to?(:each)
63
+ obj && data_object(obj).respond_to?(:map)
59
64
  end
60
65
 
61
66
  # Returns the scope wrapping this engine, used for retrieving data, invoking methods, etc
@@ -87,7 +92,12 @@ module Rabl
87
92
 
88
93
  # Returns true if the cache has been enabled for the application
89
94
  def template_cache_configured?
90
- defined?(Rails) && defined?(ActionController) && ActionController::Base.perform_caching
95
+ defined?(Rails) && defined?(ActionController::Base) && ActionController::Base.perform_caching
96
+ end
97
+
98
+ # Escape output if configured and supported
99
+ def escape_output(data)
100
+ defined?(ERB::Util.h) && Rabl.configuration.escape_all_output ? ERB::Util.h(data) : data
91
101
  end
92
102
 
93
103
  end
@@ -30,21 +30,21 @@ module Rabl
30
30
  # Returns source for a given relative file
31
31
  # fetch_source("show", :view_path => "...") => "...contents..."
32
32
  def fetch_source(file, options={})
33
- Rabl.source_cache(file, options[:view_path]) do
33
+ view_paths = Array(options[:view_path]) + Array(Rabl.configuration.view_paths)
34
+ Rabl.source_cache(file, view_paths) do
34
35
  file_path = if defined?(Padrino) && context_scope.respond_to?(:settings)
35
36
  fetch_padrino_source(file, options)
36
37
  elsif defined?(Rails) && context_scope.respond_to?(:view_paths)
37
- view_path = Array(options[:view_path] || context_scope.view_paths.to_a)
38
- fetch_rails_source(file, options) || fetch_manual_template(view_path, file)
38
+ _view_paths = view_paths + Array(context_scope.view_paths.to_a)
39
+ fetch_rails_source(file, options) || fetch_manual_template(_view_paths, file)
39
40
  elsif defined?(Sinatra) && context_scope.respond_to?(:settings)
40
41
  fetch_sinatra_source(file, options)
41
42
  else # generic template resolution
42
- view_path = Array(options[:view_path])
43
- fetch_manual_template(view_path, file)
43
+ fetch_manual_template(view_paths, file)
44
44
  end
45
45
 
46
46
  unless File.exist?(file_path.to_s)
47
- raise "Cannot find rabl template '#{file}' within registered (#{file_path}) view paths!"
47
+ raise "Cannot find rabl template '#{file}' within registered (#{view_paths.map(&:to_s).inspect}) view paths!"
48
48
  end
49
49
 
50
50
  [File.read(file_path.to_s), file_path.to_s] if file_path
@@ -1,3 +1,3 @@
1
1
  module Rabl
2
- VERSION = "0.6.10"
2
+ VERSION = "0.6.11"
3
3
  end
@@ -4,7 +4,6 @@ require File.expand_path('../../lib/rabl/template', __FILE__)
4
4
  require File.expand_path('../models/user', __FILE__)
5
5
 
6
6
  context "Rabl::Engine" do
7
-
8
7
  helper(:rabl) { |t| RablTemplate.new("code", :format => 'bson') { t } }
9
8
 
10
9
  context "with bson defaults" do
@@ -16,7 +15,6 @@ context "Rabl::Engine" do
16
15
  end
17
16
 
18
17
  context "#object" do
19
-
20
18
  asserts "that it sets data source" do
21
19
  template = rabl %q{
22
20
  object @user
@@ -37,7 +35,6 @@ context "Rabl::Engine" do
37
35
  end
38
36
 
39
37
  context "#collection" do
40
-
41
38
  asserts "that it sets object to be casted as a simple array" do
42
39
  template = rabl %{
43
40
  collection @users
@@ -55,11 +52,9 @@ context "Rabl::Engine" do
55
52
  scope.instance_variable_set :@users, [User.new, User.new]
56
53
  template.render(scope).split("").sort
57
54
  end.equals "<\x00\x00\x00\x04people\x00/\x00\x00\x00\x030\x00\x12\x00\x00\x00\x03person\x00\x05\x00\x00\x00\x00\x00\x031\x00\x12\x00\x00\x00\x03person\x00\x05\x00\x00\x00\x00\x00\x00\x00".split("").sort
58
-
59
55
  end
60
56
 
61
57
  context "#attribute" do
62
-
63
58
  asserts "that it adds an attribute or method to be included in output" do
64
59
  template = rabl %{
65
60
  object @user
@@ -89,11 +84,9 @@ context "Rabl::Engine" do
89
84
  scope.instance_variable_set :@user, User.new(:name => 'irvine')
90
85
  template.render(scope).split("").sort
91
86
  end.equals "!\x00\x00\x00\x03user\x00\x16\x00\x00\x00\x02city\x00\a\x00\x00\x00irvine\x00\x00\x00".split("").sort
92
-
93
87
  end
94
88
 
95
89
  context "#code" do
96
-
97
90
  asserts "that it can create an arbitraty code node" do
98
91
  template = rabl %{
99
92
  code(:foo) { 'bar' }
@@ -107,11 +100,9 @@ context "Rabl::Engine" do
107
100
  }
108
101
  template.render(Object.new).split("").sort
109
102
  end.equals "\x05\x00\x00\x00\x00".split("").sort
110
-
111
103
  end
112
104
 
113
105
  context "#child" do
114
-
115
106
  asserts "that it can create a child node" do
116
107
  template = rabl %{
117
108
  object @user
@@ -136,7 +127,6 @@ context "Rabl::Engine" do
136
127
  end
137
128
 
138
129
  context "#glue" do
139
-
140
130
  asserts "that it glues data from a child node" do
141
131
  template = rabl %{
142
132
  object @user
@@ -190,7 +180,6 @@ context "Rabl::Engine" do
190
180
  end
191
181
 
192
182
  context "#object" do
193
-
194
183
  asserts "that it sets data source" do
195
184
  template = rabl %q{
196
185
  object @user
@@ -211,7 +200,6 @@ context "Rabl::Engine" do
211
200
  end
212
201
 
213
202
  context "#collection" do
214
-
215
203
  asserts "that it sets object to be casted as a simple array" do
216
204
  template = rabl %{
217
205
  collection @users
@@ -229,11 +217,9 @@ context "Rabl::Engine" do
229
217
  scope.instance_variable_set :@users, [User.new, User.new]
230
218
  template.render(scope).split("").sort
231
219
  end.equals "\"\x00\x00\x00\x04person\x00\x15\x00\x00\x00\x030\x00\x05\x00\x00\x00\x00\x031\x00\x05\x00\x00\x00\x00\x00\x00".split("").sort
232
-
233
220
  end
234
221
 
235
222
  context "#attribute" do
236
-
237
223
  asserts "that it adds an attribute or method to be included in output" do
238
224
  template = rabl %{
239
225
  object @user
@@ -263,11 +249,9 @@ context "Rabl::Engine" do
263
249
  scope.instance_variable_set :@user, User.new(:name => 'irvine')
264
250
  template.render(scope).split("").sort
265
251
  end.equals "\x16\x00\x00\x00\x02city\x00\a\x00\x00\x00irvine\x00\x00".split("").sort
266
-
267
252
  end
268
253
 
269
254
  context "#code" do
270
-
271
255
  asserts "that it can create an arbitraty code node" do
272
256
  template = rabl %{
273
257
  code(:foo) { 'bar' }
@@ -281,11 +265,9 @@ context "Rabl::Engine" do
281
265
  }
282
266
  template.render(Object.new).split("").sort
283
267
  end.equals "\x05\x00\x00\x00\x00".split("").sort
284
-
285
268
  end
286
269
 
287
270
  context "#child" do
288
-
289
271
  asserts "that it can create a child node" do
290
272
  template = rabl %{
291
273
  object @user
@@ -310,7 +292,6 @@ context "Rabl::Engine" do
310
292
  end
311
293
 
312
294
  context "#glue" do
313
-
314
295
  asserts "that it glues data from a child node" do
315
296
  template = rabl %{
316
297
  object @user
@@ -2,7 +2,6 @@ require File.expand_path('../teststrap', __FILE__)
2
2
  require File.expand_path('../models/user', __FILE__)
3
3
 
4
4
  context "Rabl::Builder" do
5
-
6
5
  helper(:builder) { |opt| Rabl::Builder.new(opt) }
7
6
  helper(:build_hash) { |obj, opt| builder(opt).build(obj) }
8
7
 
@@ -10,6 +10,7 @@ context 'Rabl::Configuration' do
10
10
  asserts(:include_json_root).equals true
11
11
  asserts(:include_xml_root).equals false
12
12
  asserts(:enable_json_callbacks).equals false
13
+ asserts(:view_paths).equals []
13
14
  asserts(:json_engine).equals { json_engine }
14
15
  end
15
16
 
@@ -5,7 +5,6 @@ require File.expand_path('../models/user', __FILE__)
5
5
  require File.expand_path('../models/ormless', __FILE__)
6
6
 
7
7
  context "Rabl::Engine" do
8
-
9
8
  helper(:rabl) { |t| RablTemplate.new { t } }
10
9
 
11
10
  context "#initialize" do
@@ -28,5 +28,51 @@ context "Rabl::Helpers" do
28
28
  asserts "returns name of an object" do
29
29
  @helper_class.data_name(@user)
30
30
  end.equals('user')
31
- end
31
+ end # data_name method
32
+
33
+ context "for is_object method" do
34
+ asserts "returns nil if no data" do
35
+ @helper_class.is_object?(nil)
36
+ end.equals(nil)
37
+
38
+ asserts "returns true for an object" do
39
+ @helper_class.is_object?(@user)
40
+ end.equals(true)
41
+
42
+ # asserts "returns true for an object with each" do
43
+ # obj = Class.new { def each; end }
44
+ # @helper_class.is_object?(obj.new)
45
+ # end.equals(true)
46
+
47
+ asserts "returns true for a hash alias" do
48
+ @helper_class.is_object?(@user => :user)
49
+ end.equals(true)
50
+
51
+ asserts "returns false for an array" do
52
+ @helper_class.is_object?([@user])
53
+ end.equals(false)
54
+ end # is_object method
55
+
56
+ context "for is_collection method" do
57
+ asserts "returns nil if no data" do
58
+ @helper_class.is_collection?(nil)
59
+ end.equals(nil)
60
+
61
+ asserts "returns false for an object" do
62
+ @helper_class.is_collection?(@user)
63
+ end.equals(false)
64
+
65
+ # asserts "returns false for an object with each" do
66
+ # obj = Class.new { def each; end }
67
+ # @helper_class.is_collection?(obj.new)
68
+ # end.equals(false)
69
+
70
+ asserts "returns false for a hash alias" do
71
+ @helper_class.is_collection?(@user => :user)
72
+ end.equals(false)
73
+
74
+ asserts "returns true for an array" do
75
+ @helper_class.is_collection?([@user])
76
+ end.equals(true)
77
+ end # is_collection method
32
78
  end
@@ -21,7 +21,7 @@ context "PostsController" do
21
21
 
22
22
  context "for index action" do
23
23
  setup do
24
- get "/posts", format: :json
24
+ get "/posts", :format => :json
25
25
  end
26
26
 
27
27
  # Attributes (regular)
@@ -74,7 +74,7 @@ context "PostsController" do
74
74
 
75
75
  context "for show action" do
76
76
  setup do
77
- get "/posts/#{@post1.id}", format: :json
77
+ get "/posts/#{@post1.id}", :format => :json
78
78
  json_output['post']
79
79
  end
80
80
 
@@ -17,7 +17,7 @@ context "PostsController" do
17
17
  Post.delete_all
18
18
  @post1 = Post.create(:title => "Foo", :body => "Bar", :user_id => @user1.id)
19
19
  @post2 = Post.create(:title => "Baz", :body => "Bah", :user_id => @user2.id)
20
- @post3 = Post.create(:title => "Kaz", :body => "Paz", :user_id => @user3.id)
20
+ @post3 = Post.create(:title => "Kaz", :body => "<script>alert('xss & test');</script>", :user_id => @user3.id)
21
21
  @posts = [@post1, @post2, @post3]
22
22
  end
23
23
 
@@ -74,6 +74,32 @@ context "PostsController" do
74
74
  end.includes(:created_by_admin)
75
75
  end # index action, json
76
76
 
77
+ context "escaping output in index action" do
78
+ context "for first post" do
79
+ setup do
80
+ Rabl.configuration.escape_all_output = true
81
+ get "/posts/#{@post1.id}", format: :json
82
+ json_output['post']
83
+ end
84
+
85
+ # Attributes (regular)
86
+ asserts("contains post title") { topic['title'] }.equals { @post1.title }
87
+ asserts("contains post body") { topic['body'] }.equals { @post1.body }
88
+ end
89
+
90
+ context "for third post with script tags" do
91
+ setup do
92
+ Rabl.configuration.escape_all_output = true
93
+ get "/posts/#{@post3.id}", format: :json
94
+ json_output['post']
95
+ end
96
+
97
+ # Attributes (regular)
98
+ asserts("contains post title") { topic['title'] }.equals { @post3.title }
99
+ asserts("contains escaped post body") { topic['body'] }.equals { ERB::Util.h(@post3.body) }
100
+ end
101
+ end # escaping output
102
+
77
103
  context "for show action" do
78
104
  setup do
79
105
  get "/posts/#{@post1.id}", format: :json
@@ -85,7 +111,7 @@ context "PostsController" do
85
111
  asserts("contains post body") { topic['body'] }.equals { @post1.body }
86
112
 
87
113
  # Attributes (custom name)
88
- asserts("contains post posted_at") { topic['posted_at'] }.equals { @post1.created_at.iso8601 }
114
+ asserts("contains post posted_at") { topic['posted_at'] }.equals { @post1.created_at.utc.to_s }
89
115
 
90
116
  # Child
91
117
  asserts("contains post user child username") { topic["user"]["username"] }.equals { @post1.user.username }
@@ -35,7 +35,7 @@ context "UsersController" do
35
35
  # Attributes (custom name)
36
36
  asserts("contains registered_at") do
37
37
  json_output.map { |u| u["user"]["registered_at"] }
38
- end.equals { @users.map(&:created_at).map(&:iso8601) }
38
+ end.equals { @users.map(&:created_at).map(&:utc).map(&:to_s) }
39
39
 
40
40
  # Node (renders based on attribute)
41
41
  asserts("contains role") do
@@ -64,7 +64,7 @@ context "UsersController" do
64
64
  asserts("contains email") { json_output["person"]["email"] }.equals { @user1.email }
65
65
  asserts("contains location") { json_output["person"]["location"] }.equals { @user1.location }
66
66
  # Attributes (custom name)
67
- asserts("contains registered_at") { json_output["person"]["registered_at"] }.equals { @user1.created_at.iso8601 }
67
+ asserts("contains registered_at") { json_output["person"]["registered_at"] }.equals { @user1.created_at.utc.to_s }
68
68
  # Node (renders based on attribute)
69
69
  asserts("contains role node") { json_output["person"]["role"] }.equals "normal"
70
70
 
@@ -4,7 +4,6 @@ require File.expand_path('../../lib/rabl/template', __FILE__)
4
4
  require File.expand_path('../models/user', __FILE__)
5
5
 
6
6
  context "Rabl::Engine" do
7
-
8
7
  helper(:rabl) { |t| RablTemplate.new("code", :format => 'msgpack') { t } }
9
8
 
10
9
  context "with msgpack defaults" do
@@ -16,7 +15,6 @@ context "Rabl::Engine" do
16
15
  end
17
16
 
18
17
  context "#object" do
19
-
20
18
  asserts "that it sets data source" do
21
19
  template = rabl %q{
22
20
  object @user
@@ -37,7 +35,6 @@ context "Rabl::Engine" do
37
35
  end
38
36
 
39
37
  context "#collection" do
40
-
41
38
  asserts "that it sets object to be casted as a simple array" do
42
39
  template = rabl %{
43
40
  collection @users
@@ -55,11 +52,9 @@ context "Rabl::Engine" do
55
52
  scope.instance_variable_set :@users, [User.new, User.new]
56
53
  template.render(scope).split("").sort
57
54
  end.equals "\x81\xA6person\x92\x81\xA6person\x80\x81\xA6person\x80".split("").sort
58
-
59
55
  end
60
56
 
61
57
  context "#attribute" do
62
-
63
58
  asserts "that it adds an attribute or method to be included in output" do
64
59
  template = rabl %{
65
60
  object @user
@@ -89,11 +84,9 @@ context "Rabl::Engine" do
89
84
  scope.instance_variable_set :@user, User.new(:name => 'irvine')
90
85
  template.render(scope).split("").sort
91
86
  end.equals "\x81\xA4user\x81\xA4city\xA6irvine".split("").sort
92
-
93
87
  end
94
88
 
95
89
  context "#code" do
96
-
97
90
  asserts "that it can create an arbitraty code node" do
98
91
  template = rabl %{
99
92
  code(:foo) { 'bar' }
@@ -107,11 +100,9 @@ context "Rabl::Engine" do
107
100
  }
108
101
  template.render(Object.new).split("").sort
109
102
  end.equals "\x80".split("").sort
110
-
111
103
  end
112
104
 
113
105
  context "#child" do
114
-
115
106
  asserts "that it can create a child node" do
116
107
  template = rabl %{
117
108
  object @user
@@ -137,7 +128,6 @@ context "Rabl::Engine" do
137
128
  end
138
129
 
139
130
  context "#glue" do
140
-
141
131
  asserts "that it glues data from a child node" do
142
132
  template = rabl %{
143
133
  object @user
@@ -191,7 +181,6 @@ context "Rabl::Engine" do
191
181
  end
192
182
 
193
183
  context "#object" do
194
-
195
184
  asserts "that it sets data source" do
196
185
  template = rabl %q{
197
186
  object @user
@@ -212,7 +201,6 @@ context "Rabl::Engine" do
212
201
  end
213
202
 
214
203
  context "#collection" do
215
-
216
204
  asserts "that it sets object to be casted as a simple array" do
217
205
  template = rabl %{
218
206
  collection @users
@@ -230,11 +218,9 @@ context "Rabl::Engine" do
230
218
  scope.instance_variable_set :@users, [User.new, User.new]
231
219
  template.render(scope).split("").sort
232
220
  end.equals "\x81\xA6person\x92\x80\x80".split("").sort
233
-
234
221
  end
235
222
 
236
223
  context "#attribute" do
237
-
238
224
  asserts "that it adds an attribute or method to be included in output" do
239
225
  template = rabl %{
240
226
  object @user
@@ -264,11 +250,9 @@ context "Rabl::Engine" do
264
250
  scope.instance_variable_set :@user, User.new(:name => 'irvine')
265
251
  template.render(scope).split("").sort
266
252
  end.equals "\x81\xA4city\xA6irvine".split("").sort
267
-
268
253
  end
269
254
 
270
255
  context "#code" do
271
-
272
256
  asserts "that it can create an arbitraty code node" do
273
257
  template = rabl %{
274
258
  code(:foo) { 'bar' }
@@ -282,11 +266,9 @@ context "Rabl::Engine" do
282
266
  }
283
267
  template.render(Object.new).split("").sort
284
268
  end.equals "\x80".split("").sort
285
-
286
269
  end
287
270
 
288
271
  context "#child" do
289
-
290
272
  asserts "that it can create a child node" do
291
273
  template = rabl %{
292
274
  object @user
@@ -311,7 +293,6 @@ context "Rabl::Engine" do
311
293
  end
312
294
 
313
295
  context "#glue" do
314
-
315
296
  asserts "that it glues data from a child node" do
316
297
  template = rabl %{
317
298
  object @user
@@ -62,4 +62,27 @@ context "Rabl::Partials" do
62
62
  end
63
63
  teardown { Object.send(:remove_const, :Sinatra) }
64
64
  end
65
+
66
+ context "fetch source using configured view paths" do
67
+ helper(:tmp_path) { @tmp_path ||= Pathname.new(Dir.mktmpdir) }
68
+
69
+ setup do
70
+ Rabl.configure do |config|
71
+ config.view_paths = tmp_path
72
+ end
73
+
74
+ ::Sinatra = stub(Class.new)
75
+ File.open(tmp_path + "test.rabl", "w") do |f|
76
+ f.puts "content"
77
+ end
78
+ File.open(tmp_path + "test.json.rabl", "w") do |f|
79
+ f.puts "content2"
80
+ end
81
+ TestPartial.new.fetch_source('test')
82
+ end
83
+ asserts('detects file.json.rabl first') { topic }.equals do
84
+ ["content2\n", (tmp_path + 'test.json.rabl').to_s]
85
+ end
86
+ teardown { Object.send(:remove_const, :Sinatra) }
87
+ end
65
88
  end
@@ -4,7 +4,6 @@ require File.expand_path('../../lib/rabl/template', __FILE__)
4
4
  require File.expand_path('../models/user', __FILE__)
5
5
 
6
6
  context "Rabl::Engine" do
7
-
8
7
  helper(:rabl) { |t| RablTemplate.new("code", :format => 'plist') { t } }
9
8
 
10
9
  context "with plist defaults" do
@@ -16,7 +15,6 @@ context "Rabl::Engine" do
16
15
  end
17
16
 
18
17
  context "#object" do
19
-
20
18
  asserts "that it sets data source" do
21
19
  template = rabl %q{
22
20
  object @user
@@ -37,7 +35,6 @@ context "Rabl::Engine" do
37
35
  end
38
36
 
39
37
  context "#collection" do
40
-
41
38
  asserts "that it sets object to be casted as a simple array" do
42
39
  template = rabl %{
43
40
  collection @users
@@ -55,11 +52,9 @@ context "Rabl::Engine" do
55
52
  scope.instance_variable_set :@users, [User.new, User.new]
56
53
  template.render(scope).split("").sort
57
54
  end.equals "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>person</key>\n\t<array>\n\t\t<dict>\n\t\t\t<key>person</key>\n\t\t\t<dict/>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>person</key>\n\t\t\t<dict/>\n\t\t</dict>\n\t</array>\n</dict>\n</plist>\n".split("").sort
58
-
59
55
  end
60
56
 
61
57
  context "#attribute" do
62
-
63
58
  asserts "that it adds an attribute or method to be included in output" do
64
59
  template = rabl %{
65
60
  object @user
@@ -89,11 +84,9 @@ context "Rabl::Engine" do
89
84
  scope.instance_variable_set :@user, User.new(:name => 'irvine')
90
85
  template.render(scope).split("").sort
91
86
  end.equals "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>user</key>\n\t<dict>\n\t\t<key>city</key>\n\t\t<string>irvine</string>\n\t</dict>\n</dict>\n</plist>\n".split("").sort
92
-
93
87
  end
94
88
 
95
89
  context "#code" do
96
-
97
90
  asserts "that it can create an arbitraty code node" do
98
91
  template = rabl %{
99
92
  code(:foo) { 'bar' }
@@ -107,21 +100,18 @@ context "Rabl::Engine" do
107
100
  }
108
101
  template.render(Object.new).split("").sort
109
102
  end.equals "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict/>\n</plist>\n".split("").sort
110
-
111
103
  end
112
104
 
113
105
  context "#child" do
114
-
115
106
  asserts "that it can create a child node" do
116
107
  template = rabl %{
117
108
  object @user
118
- attribute :name
119
109
  child(@user) { attribute :city }
120
110
  }
121
111
  scope = Object.new
122
112
  scope.instance_variable_set :@user, User.new(:name => 'leo', :city => 'LA')
123
113
  template.render(scope).split("").sort
124
- end.equals "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>user</key>\n\t<dict>\n\t\t<key>name</key>\n\t\t<string>leo</string>\n\t\t<key>user</key>\n\t\t<dict>\n\t\t\t<key>city</key>\n\t\t\t<string>LA</string>\n\t\t</dict>\n\t</dict>\n</dict>\n</plist>\n".split("").sort
114
+ end.equals "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>user</key>\n\t<dict>\n\t\t<key>user</key>\n\t\t<dict>\n\t\t\t<key>city</key>\n\t\t\t<string>LA</string>\n\t\t</dict>\n\t</dict>\n</dict>\n</plist>\n".split("").sort
125
115
 
126
116
  asserts "that it can create a child node with different key" do
127
117
  template = rabl %{
@@ -132,12 +122,10 @@ context "Rabl::Engine" do
132
122
  scope = Object.new
133
123
  scope.instance_variable_set :@user, User.new(:name => 'leo', :city => 'LA')
134
124
  template.render(scope)
135
-
136
125
  end.equals "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>user</key>\n\t<dict>\n\t\t<key>name</key>\n\t\t<string>leo</string>\n\t\t<key>person</key>\n\t\t<dict>\n\t\t\t<key>city</key>\n\t\t\t<string>LA</string>\n\t\t</dict>\n\t</dict>\n</dict>\n</plist>\n"
137
126
  end
138
127
 
139
128
  context "#glue" do
140
-
141
129
  asserts "that it glues data from a child node" do
142
130
  template = rabl %{
143
131
  object @user
@@ -191,7 +179,6 @@ context "Rabl::Engine" do
191
179
  end
192
180
 
193
181
  context "#object" do
194
-
195
182
  asserts "that it sets data source" do
196
183
  template = rabl %q{
197
184
  object @user
@@ -212,7 +199,6 @@ context "Rabl::Engine" do
212
199
  end
213
200
 
214
201
  context "#collection" do
215
-
216
202
  asserts "that it sets object to be casted as a simple array" do
217
203
  template = rabl %{
218
204
  collection @users
@@ -230,11 +216,9 @@ context "Rabl::Engine" do
230
216
  scope.instance_variable_set :@users, [User.new, User.new]
231
217
  template.render(scope)
232
218
  end.equals "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>person</key>\n\t<array>\n\t\t<dict/>\n\t\t<dict/>\n\t</array>\n</dict>\n</plist>\n"
233
-
234
219
  end
235
220
 
236
221
  context "#attribute" do
237
-
238
222
  asserts "that it adds an attribute or method to be included in output" do
239
223
  template = rabl %{
240
224
  object @user
@@ -264,11 +248,9 @@ context "Rabl::Engine" do
264
248
  scope.instance_variable_set :@user, User.new(:name => 'irvine')
265
249
  template.render(scope)
266
250
  end.equals "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>city</key>\n\t<string>irvine</string>\n</dict>\n</plist>\n"
267
-
268
251
  end
269
252
 
270
253
  context "#code" do
271
-
272
254
  asserts "that it can create an arbitrary code node" do
273
255
  template = rabl %{
274
256
  code(:foo) { 'bar' }
@@ -282,21 +264,18 @@ context "Rabl::Engine" do
282
264
  }
283
265
  template.render(Object.new)
284
266
  end.equals "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict/>\n</plist>\n"
285
-
286
267
  end
287
268
 
288
269
  context "#child" do
289
-
290
270
  asserts "that it can create a child node" do
291
271
  template = rabl %{
292
272
  object @user
293
- attribute :name
294
273
  child(@user) { attribute :city }
295
274
  }
296
275
  scope = Object.new
297
276
  scope.instance_variable_set :@user, User.new(:name => 'leo', :city => 'LA')
298
277
  template.render(scope).split("").sort
299
- end.equals "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>name</key>\n\t<string>leo</string>\n\t<key>user</key>\n\t<dict>\n\t\t<key>city</key>\n\t\t<string>LA</string>\n\t</dict>\n</dict>\n</plist>\n".split("").sort
278
+ end.equals "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>user</key>\n\t<dict>\n\t\t<key>city</key>\n\t\t<string>LA</string>\n\t</dict>\n</dict>\n</plist>\n".split("").sort
300
279
 
301
280
  asserts "that it can create a child node with different key" do
302
281
  template = rabl %{
@@ -311,7 +290,6 @@ context "Rabl::Engine" do
311
290
  end
312
291
 
313
292
  context "#glue" do
314
-
315
293
  asserts "that it glues data from a child node" do
316
294
  template = rabl %{
317
295
  object @user
@@ -3,6 +3,7 @@ require 'pathname'
3
3
 
4
4
  context "Rabl::Renderer" do
5
5
  helper(:tmp_path) { @tmp_path ||= Pathname.new(Dir.mktmpdir) }
6
+
6
7
  context "#render" do
7
8
  asserts 'renders empty array' do
8
9
  source = %q{
@@ -60,14 +61,12 @@ context "Rabl::Renderer" do
60
61
  attribute :name, :as => 'city'
61
62
  }
62
63
 
63
- scope = Object.new
64
64
  user = User.new(:name => 'irvine')
65
65
 
66
66
  renderer = Rabl::Renderer.new(source, nil, { :format => 'json', :locals => {:object => user} })
67
67
  renderer.render.split("").sort
68
68
  end.equals "{\"user\":{\"city\":\"irvine\"}}".split("").sort
69
69
 
70
-
71
70
  asserts 'loads source from file' do
72
71
  File.open(tmp_path + "test.json.rabl", "w") do |f|
73
72
  f.puts %q{
@@ -82,6 +81,23 @@ context "Rabl::Renderer" do
82
81
  renderer.render.split("").sort
83
82
  end.equals "{\"user\":{\"age\":24,\"name\":\"irvine\"}}".split("").sort
84
83
 
84
+ asserts 'uses globally configured view paths' do
85
+ Rabl.configure do |config|
86
+ config.view_paths << tmp_path
87
+ end
88
+
89
+ File.open(tmp_path + "test.rabl", "w") do |f|
90
+ f.puts %q{
91
+ attributes :age
92
+ }
93
+ end
94
+
95
+ user = User.new(:name => 'irvine')
96
+
97
+ renderer = Rabl::Renderer.new('test', user)
98
+ renderer.render.split("").sort
99
+ end.equals "{\"user\":{\"age\":24,\"name\":\"irvine\"}}".split("").sort
100
+
85
101
 
86
102
  asserts 'handles paths for extends' do
87
103
  File.open(tmp_path + "test.json.rabl", "w") do |f|
@@ -185,5 +201,4 @@ context "Rabl::Renderer" do
185
201
  Rabl::Renderer.plist(user, 'test', :view_path => tmp_path)
186
202
  end.equals "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>user</key>\n\t<dict>\n\t\t<key>age</key>\n\t\t<integer>24</integer>\n\t\t<key>name</key>\n\t\t<string>ivan</string>\n\t</dict>\n</dict>\n</plist>\n"
187
203
  end
188
-
189
204
  end
@@ -18,4 +18,4 @@ module Kernel
18
18
  ensure
19
19
  $VERBOSE = old_verbose
20
20
  end
21
- end unless Kernel.respond_to? :silence_warnings
21
+ end unless Kernel.respond_to? :silence_warnings
@@ -5,7 +5,6 @@ class Scope
5
5
  end
6
6
 
7
7
  context "RablTemplate" do
8
-
9
8
  asserts "that it registers for .rabl files" do
10
9
  Tilt['test.rabl']
11
10
  end.equals RablTemplate
@@ -44,7 +43,6 @@ context "RablTemplate" do
44
43
  end
45
44
 
46
45
  context "#render compiled" do
47
-
48
46
  # asserts "that it can be passed locals" do
49
47
  # template = RablTemplate.new { "code(:name) { @name }" }
50
48
  # template.render(Scope.new, :object => 'Bob')
@@ -61,8 +59,5 @@ context "RablTemplate" do
61
59
  template = RablTemplate.new { "code(:lol) { 'Hey ' + yield + '!' }" }
62
60
  template.render(Scope.new) { 'Joe' }
63
61
  end.matches %r{"lol":"Hey Joe!"}
64
-
65
62
  end
66
-
67
-
68
63
  end
@@ -27,4 +27,3 @@ end
27
27
  class Riot::Context
28
28
  # Custom context code here
29
29
  end
30
-
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: rabl
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.6.10
5
+ version: 0.6.11
6
6
  platform: ruby
7
7
  authors:
8
8
  - Nathan Esquenazi
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2012-04-19 00:00:00 Z
13
+ date: 2012-05-10 00:00:00 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activesupport