rabl-rails 0.3.2 → 0.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,8 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## 0.3.3
4
+ * Add response caching
5
+
3
6
  ## 0.3.2
4
7
  * Using child with a nil value will be correctly formatted as nil
5
8
  * Allow controller's assigns to have symbol keys
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # RABL for Rails #
1
+ # RABL for Rails [![Build Status](https://travis-ci.org/ccocchi/rabl-rails.png?branch=master)](https://travis-ci.org/ccocchi/rabl-rails)
2
2
 
3
3
  RABL (Ruby API Builder Language) is a ruby templating system for rendering resources in different format (JSON, XML, BSON, ...). You can find documentation [here](http://github.com/nesquena/rabl).
4
4
 
@@ -94,7 +94,7 @@ RablRails.configure do |config|
94
94
  # config.json_engine = :oj
95
95
  # config.xml_engine = 'LibXML'
96
96
  # config.use_custom_responder = false
97
- # config.default_responder_template = 'show'
97
+ # config.default_responder_template = 'show'
98
98
  # config.enable_jsonp_callbacks = false
99
99
  end
100
100
  ```
@@ -285,7 +285,10 @@ You can find more informations about how to use this method in the [wiki](http:/
285
285
 
286
286
  ### Other features
287
287
 
288
- You can find more informations about other features (caching, custom_responder, ...) in the [WIKI](https://github.com/ccocchi/rabl-rails/wiki)
288
+ * [Caching](https://github.com/ccocchi/rabl-rails/wiki/Caching)
289
+ * [Custom responder](https://github.com/ccocchi/rabl-rails/wiki/Using-custom-responder)
290
+
291
+ And more in the [WIKI](https://github.com/ccocchi/rabl-rails/wiki)
289
292
 
290
293
  ## Performance
291
294
 
@@ -65,11 +65,12 @@ module RablRails
65
65
  def child(name_or_data, options = {})
66
66
  data, name = extract_data_and_name(name_or_data)
67
67
  name = options[:root] if options.has_key? :root
68
- if options[:partial]
68
+
69
+ @template[name] = if options[:partial]
69
70
  template = Library.instance.compile_template_from_path(options[:partial])
70
- @template[name] = template.merge!(:_data => data)
71
+ template.merge!(:_data => data)
71
72
  elsif block_given?
72
- @template[name] = sub_compile(data) { yield }
73
+ sub_compile(data) { yield }
73
74
  end
74
75
  end
75
76
 
@@ -140,6 +141,10 @@ module RablRails
140
141
  @template[sequence('if')] = Condition.new(proc, sub_compile(nil) { yield })
141
142
  end
142
143
 
144
+ def cache(&block)
145
+ @template.cache_key = block_given? ? block : nil
146
+ end
147
+
143
148
  protected
144
149
 
145
150
  #
@@ -27,10 +27,13 @@ module RablRails
27
27
  end
28
28
  end
29
29
  collection_or_resource ||= @_resource
30
- output_hash = collection_or_resource.respond_to?(:each) ? render_collection(collection_or_resource, template.source) :
31
- render_resource(collection_or_resource, template.source)
32
- _options[:root_name] = template.root_name
33
- format_output(output_hash)
30
+
31
+ render_with_cache(template.cache_key, collection_or_resource) do
32
+ output_hash = collection_or_resource.respond_to?(:each) ? render_collection(collection_or_resource, template.source)
33
+ : render_resource(collection_or_resource, template.source)
34
+ _options[:root_name] = template.root_name
35
+ format_output(output_hash)
36
+ end
34
37
  end
35
38
 
36
39
  #
@@ -43,6 +46,16 @@ module RablRails
43
46
 
44
47
  protected
45
48
 
49
+ def render_with_cache(key, collection_or_resource, &block)
50
+ if !key.is_a?(FalseClass) && ActionController::Base.perform_caching
51
+ Rails.cache.fetch(resolve_cache_key(key, collection_or_resource)) do
52
+ yield
53
+ end
54
+ else
55
+ yield
56
+ end
57
+ end
58
+
46
59
  #
47
60
  # Render a single resource as a hash, according to the compiled
48
61
  # template source passed.
@@ -68,14 +81,7 @@ module RablRails
68
81
  instance_exec data, &(value.last)
69
82
  when Hash
70
83
  current_value = value.dup
71
- data_symbol = current_value.delete(:_data)
72
- object = if data_symbol == nil
73
- data
74
- else
75
- data_symbol.to_s.start_with?('@') ? instance_variable_get(data_symbol)
76
- : data.respond_to?(data_symbol) ? data.send(data_symbol)
77
- : send(data_symbol)
78
- end
84
+ object = object_from_data(data, current_value.delete(:_data))
79
85
 
80
86
  if key.to_s.start_with?('_') # glue
81
87
  output.merge!(render_resource(object, current_value))
@@ -133,6 +139,23 @@ module RablRails
133
139
  @_context.respond_to?(name) ? @_context.send(name, *args, &block) : super
134
140
  end
135
141
 
142
+ def resolve_cache_key(key, data)
143
+ return data.cache_key unless key
144
+ key.is_a?(Proc) ? instance_exec(data, &key) : key
145
+ end
146
+
147
+ private
148
+
149
+ def object_from_data(data, symbol)
150
+ return data if symbol == nil
151
+
152
+ if symbol.to_s.start_with?('@')
153
+ instance_variable_get(symbol)
154
+ else
155
+ data.respond_to?(symbol) ? data.send(symbol) : send(symbol)
156
+ end
157
+ end
158
+
136
159
  #
137
160
  # Copy assigns from controller's context into this
138
161
  # renderer context to include instances variables when
@@ -7,6 +7,10 @@ module RablRails
7
7
 
8
8
  RablRails.enable_jsonp_callbacks && params.has_key?(:callback) ? "#{params[:callback]}(#{json})" : json
9
9
  end
10
+
11
+ def resolve_cache_key(key, data)
12
+ "#{super}.json"
13
+ end
10
14
  end
11
15
  end
12
16
  end
@@ -6,6 +6,10 @@ module RablRails
6
6
  hash = { _options[:root_name] => hash } if _options[:root_name] && RablRails.include_plist_root
7
7
  RablRails.plist_engine.dump(hash)
8
8
  end
9
+
10
+ def resolve_cache_key(key, data)
11
+ "#{super}.plist"
12
+ end
9
13
  end
10
14
  end
11
15
  end
@@ -9,6 +9,10 @@ module RablRails
9
9
  xml_options = { root: _options[:root_name] }.merge!(DEFAULT_OPTIONS)
10
10
  hash.to_xml(xml_options)
11
11
  end
12
+
13
+ def resolve_cache_key(key, data)
14
+ "#{super}.xml"
15
+ end
12
16
  end
13
17
  end
14
18
  end
@@ -1,11 +1,12 @@
1
1
  module RablRails
2
2
  class CompiledTemplate
3
- attr_accessor :source, :data, :root_name
3
+ attr_accessor :source, :data, :root_name, :cache_key
4
4
 
5
5
  delegate :[], :[]=, :merge!, :to => :source
6
6
 
7
7
  def initialize
8
8
  @source = {}
9
+ @cache_key = false
9
10
  end
10
11
 
11
12
  def initialize_dup(other)
@@ -1,3 +1,3 @@
1
1
  module RablRails
2
- VERSION = '0.3.2'
2
+ VERSION = '0.3.3'
3
3
  end
@@ -15,7 +15,11 @@ class TestBaseRenderer < ActiveSupport::TestCase
15
15
  @context.assigns['data'] = @data
16
16
 
17
17
  @template = RablRails::CompiledTemplate.new
18
+ @template.source = {}
18
19
  @template.data = :@data
20
+
21
+ @cache = mock
22
+ Rails.stub(:cache).and_return(@cache)
19
23
  end
20
24
 
21
25
  def render_hash
@@ -29,7 +33,35 @@ class TestBaseRenderer < ActiveSupport::TestCase
29
33
 
30
34
  test "properly handle assigns with symbol keys" do
31
35
  @context.assigns[:foo] = 'bar'
32
- @template.source = {}
33
36
  assert_nothing_raised { render_hash }
34
37
  end
38
+
39
+ test "cache should be applied if no cache key is given" do
40
+ @cache.should_not_receive(:fetch)
41
+ render_hash
42
+ end
43
+
44
+ test "cache should not be used if disabled in Rails configuration" do
45
+ ActionController::Base.stub(:perform_caching).and_return(false)
46
+ @cache.should_not_receive(:fetch)
47
+ @template.cache_key = 'something'
48
+ render_hash
49
+ end
50
+
51
+ test "cache shoud use #cache_key as default" do
52
+ ActionController::Base.stub(:perform_caching).and_return(true)
53
+ @data.stub(:cache_key).and_return('data_cache_key')
54
+ @cache.should_receive(:fetch).with('data_cache_key').and_return({ some: 'hash' })
55
+ @template.cache_key = nil
56
+
57
+ assert_equal({ some: 'hash' }, render_hash)
58
+ end
59
+
60
+ test "cache should use the proc if given" do
61
+ ActionController::Base.stub(:perform_caching).and_return(true)
62
+ @template.cache_key = ->(u) { 'proc_cache_key' }
63
+ @cache.should_receive(:fetch).with('proc_cache_key').and_return({ some: 'hash' })
64
+
65
+ assert_equal({ some: 'hash' }, render_hash)
66
+ end
35
67
  end
@@ -58,6 +58,21 @@ class CompilerTest < ActiveSupport::TestCase
58
58
  assert_equal false, t.root_name
59
59
  end
60
60
 
61
+ test "template should not have a cache key if cache is not enable" do
62
+ t = @compiler.compile_source('')
63
+ assert_equal false, t.cache_key
64
+ end
65
+
66
+ test "cache can take no argument" do
67
+ t = @compiler.compile_source(%{ cache })
68
+ assert_nil t.cache_key
69
+ end
70
+
71
+ test "cache can take a block" do
72
+ t = @compiler.compile_source(%( cache { 'foo' }))
73
+ assert_instance_of Proc, t.cache_key
74
+ end
75
+
61
76
  # Compilation
62
77
 
63
78
  test "simple attributes are compiled to hash" do
@@ -152,6 +167,23 @@ class CompilerTest < ActiveSupport::TestCase
152
167
  assert_equal({ :id => :id }, t.source)
153
168
  end
154
169
 
170
+ test "extends should not overwrite nodes previously defined" do
171
+ skip('Bug reported by @abrisse')
172
+
173
+ template = mock('file_template', :source => %(condition(-> { true }) { 'foo' }))
174
+ lookup_context = mock
175
+ lookup_context.stub(:find_template).with('users/xtnd', [], false).and_return(template)
176
+ RablRails::Library.reset_instance
177
+ RablRails::Library.instance.instance_variable_set(:@lookup_context, lookup_context)
178
+
179
+ t = @compiler.compile_source(%{
180
+ condition(-> { false }) { 'bar' }
181
+ extends('users/xtnd')
182
+ })
183
+
184
+ assert_equal 2, t.source.keys.size
185
+ end
186
+
155
187
  test "node are compiled without evaluating the block" do
156
188
  t = @compiler.compile_source(%{ node(:foo) { bar } })
157
189
  assert_not_nil t.source[:foo]
@@ -174,4 +174,16 @@ class TestJsonRenderer < ActiveSupport::TestCase
174
174
  @template.source = { :name => :name }
175
175
  assert_equal %q[some_callback({"name":"foobar"})], render_json_output
176
176
  end
177
+
178
+ test "cache key should be different from Base to avoid name collisions" do
179
+ ActionController::Base.stub(:perform_caching).and_return(true)
180
+ @data.stub(:cache_key).and_return('data_cache_key')
181
+ @template.cache_key = nil
182
+
183
+ @cache = mock
184
+ @cache.should_receive(:fetch).with('data_cache_key.json').and_return(%("some":"json"))
185
+ Rails.stub(:cache).and_return(@cache)
186
+
187
+ assert_equal %("some":"json"), render_json_output
188
+ end
177
189
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rabl-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.2
4
+ version: 0.3.3
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: 2013-05-28 00:00:00.000000000 Z
12
+ date: 2013-06-06 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport