curlybars 1.5.1 → 1.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/lib/curlybars.rb +0 -1
  3. data/lib/curlybars/configuration.rb +1 -9
  4. data/lib/curlybars/error/base.rb +2 -0
  5. data/lib/curlybars/method_whitelist.rb +5 -2
  6. data/lib/curlybars/node/block_helper_else.rb +1 -0
  7. data/lib/curlybars/node/path.rb +6 -0
  8. data/lib/curlybars/processor/tilde.rb +3 -0
  9. data/lib/curlybars/rendering_support.rb +8 -0
  10. data/lib/curlybars/template_handler.rb +18 -6
  11. data/lib/curlybars/version.rb +1 -1
  12. data/spec/acceptance/application_layout_spec.rb +2 -2
  13. data/spec/acceptance/collection_blocks_spec.rb +1 -1
  14. data/spec/acceptance/global_helper_spec.rb +1 -1
  15. data/spec/curlybars/lexer_spec.rb +3 -2
  16. data/spec/curlybars/rendering_support_spec.rb +4 -9
  17. data/spec/curlybars/template_handler_spec.rb +33 -30
  18. data/spec/integration/cache_spec.rb +20 -18
  19. data/spec/integration/node/block_helper_else_spec.rb +0 -2
  20. data/spec/integration/node/each_else_spec.rb +0 -2
  21. data/spec/integration/node/each_spec.rb +0 -2
  22. data/spec/integration/node/helper_spec.rb +0 -2
  23. data/spec/integration/node/if_else_spec.rb +0 -2
  24. data/spec/integration/node/if_spec.rb +0 -2
  25. data/spec/integration/node/output_spec.rb +0 -2
  26. data/spec/integration/node/partial_spec.rb +0 -2
  27. data/spec/integration/node/path_spec.rb +0 -2
  28. data/spec/integration/node/root_spec.rb +0 -2
  29. data/spec/integration/node/sub_expression_spec.rb +0 -2
  30. data/spec/integration/node/template_spec.rb +0 -2
  31. data/spec/integration/node/unless_else_spec.rb +0 -2
  32. data/spec/integration/node/unless_spec.rb +0 -2
  33. data/spec/integration/node/with_spec.rb +0 -2
  34. data/spec/integration/processors_spec.rb +0 -1
  35. metadata +41 -13
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 307c759c2acc1c33ab91a236aeb5042e6ecfee67581eef05f468c241a722e1f6
4
- data.tar.gz: 68b0a401f830e5985d0d6b657974f84c2afdda2d49e70c696e97641845d31a16
3
+ metadata.gz: 2be6d03409f5c575fb33c7ba4ed74117420fd22ddca8272005c5f23e459a0d8e
4
+ data.tar.gz: ad11b01849c9d28a70b2ae2260615665cc2dc3ca3c380b9dfbc2ab9c91bf1de3
5
5
  SHA512:
6
- metadata.gz: 7db835baca28f2c15af2fb1a582059bb8346d1de41f8d9ed72262ea7ef1e2ff2e8130091b4e1494858b366f050e1b2fe2cf1753afbd1a403c66058c37f8fa9ff
7
- data.tar.gz: 9a54e30bba2976a6c6f0ff4e6fef5f00075dc6186a9eb07c70a63ead7a96629a17897ce9ea9e09fad00049262a891eb88b1389873b629ca22f12c7b712686166
6
+ metadata.gz: ba6035a72fd5cf75120cc3adfc663192dae68d75132887b801bd29a53c4b655f6be09ed6b8e4a2ee497e708172c38db19258215b5f3b1a9b788371db20eeac3c
7
+ data.tar.gz: 83961d2f0ef03848c1ffb3feb9db859c866ff90e74d173f116b16c3af5ff4eac710e934cd7b3bb5039749f05169bd4f95e3f19fc208163f3333a6d66ba7261df
@@ -118,7 +118,6 @@ require 'curlybars/rendering_support'
118
118
  require 'curlybars/parser'
119
119
  require 'curlybars/position'
120
120
  require 'curlybars/lexer'
121
- require 'curlybars/parser'
122
121
  require 'curlybars/processor/token_factory'
123
122
  require 'curlybars/processor/tilde'
124
123
  require 'curlybars/error/lex'
@@ -16,15 +16,7 @@ module Curlybars
16
16
  end
17
17
 
18
18
  class Configuration
19
- attr_accessor :presenters_namespace
20
- attr_accessor :nesting_limit
21
- attr_accessor :traversing_limit
22
- attr_accessor :output_limit
23
- attr_accessor :rendering_timeout
24
- attr_accessor :custom_processors
25
- attr_accessor :compiler_transformers
26
- attr_accessor :global_helpers_provider_classes
27
- attr_accessor :cache
19
+ attr_accessor :presenters_namespace, :nesting_limit, :traversing_limit, :output_limit, :rendering_timeout, :custom_processors, :compiler_transformers, :global_helpers_provider_classes, :cache
28
20
 
29
21
  def initialize
30
22
  @presenters_namespace = ''
@@ -8,8 +8,10 @@ module Curlybars
8
8
  @id = id
9
9
  @position = position
10
10
  @metadata = metadata
11
+
11
12
  return if position.nil?
12
13
  return if position.file_name.nil?
14
+
13
15
  location = "%s:%d:%d" % [position.file_name, position.line_number, position.line_offset]
14
16
  set_backtrace([location])
15
17
  end
@@ -1,5 +1,6 @@
1
1
  module Curlybars
2
2
  module MethodWhitelist
3
+ # rubocop:disable Style/SoleNestedConditional
3
4
  def allow_methods(*methods_without_type, **methods_with_type, &contextual_block)
4
5
  methods_with_type_validator = lambda do |methods_to_validate|
5
6
  methods_to_validate.each do |(method_name, type)|
@@ -49,8 +50,8 @@ module Curlybars
49
50
  memo[method] = nil
50
51
  end
51
52
 
52
- methods_with_type_resolved = all_methods_with_type.each_with_object({}) do |(method_name, type), memo|
53
- memo[method_name] = if type.respond_to?(:call)
53
+ methods_with_type_resolved = all_methods_with_type.transform_values do |type|
54
+ if type.respond_to?(:call)
54
55
  type.call(context)
55
56
  else
56
57
  type
@@ -65,6 +66,7 @@ module Curlybars
65
66
  # Included modules
66
67
  included_modules.each do |mod|
67
68
  next unless mod.respond_to?(:methods_schema)
69
+
68
70
  schema.merge!(mod.methods_schema(context))
69
71
  end
70
72
 
@@ -90,6 +92,7 @@ module Curlybars
90
92
  allowed_methods.include?(method)
91
93
  end
92
94
  end
95
+ # rubocop:enable Style/SoleNestedConditional
93
96
 
94
97
  def self.extended(base)
95
98
  # define a default of no method allowed
@@ -100,6 +100,7 @@ module Curlybars
100
100
 
101
101
  def check_open_and_close_elements(helper, helperclose, error_class)
102
102
  return unless helper.path != helperclose.path
103
+
103
104
  message = "block `#{helper.path}` cannot be closed by `#{helperclose.path}`"
104
105
  raise error_class.new('closing_tag_mismatch', message, helperclose.position)
105
106
  end
@@ -109,26 +109,32 @@ module Curlybars
109
109
  case check_type
110
110
  when :presenter
111
111
  return if presenter?(branches)
112
+
112
113
  message = "`#{path}` must resolve to a presenter"
113
114
  raise Curlybars::Error::Validate.new('not_a_presenter', message, position)
114
115
  when :presenter_collection
115
116
  return if presenter_collection?(branches)
117
+
116
118
  message = "`#{path}` must resolve to a collection of presenters"
117
119
  raise Curlybars::Error::Validate.new('not_a_presenter_collection', message, position)
118
120
  when :leaf
119
121
  return if leaf?(branches)
122
+
120
123
  message = "`#{path}` cannot resolve to a component"
121
124
  raise Curlybars::Error::Validate.new('not_a_leaf', message, position)
122
125
  when :partial
123
126
  return if partial?(branches)
127
+
124
128
  message = "`#{path}` cannot resolve to a partial"
125
129
  raise Curlybars::Error::Validate.new('not_a_partial', message, position)
126
130
  when :helper
127
131
  return if helper?(branches)
132
+
128
133
  message = "`#{path}` cannot resolve to a helper"
129
134
  raise Curlybars::Error::Validate.new('not_a_helper', message, position)
130
135
  when :not_helper
131
136
  return unless helper?(branches)
137
+
132
138
  message = "`#{path}` resolves to a helper"
133
139
  raise Curlybars::Error::Validate.new('is_a_helper', message, position)
134
140
  when :anything
@@ -10,10 +10,12 @@ module Curlybars
10
10
  when :TILDE_START
11
11
  tokens[index] = create_token(:START, token.value, token.position)
12
12
  next if index == 0
13
+
13
14
  strip_token_if_text(tokens, index - 1, :rstrip)
14
15
  when :TILDE_END
15
16
  tokens[index] = create_token(:END, token.value, token.position)
16
17
  next if index == (tokens.length - 1)
18
+
17
19
  strip_token_if_text(tokens, index + 1, :lstrip)
18
20
  end
19
21
  end
@@ -22,6 +24,7 @@ module Curlybars
22
24
  def strip_token_if_text(tokens, index, strip_method)
23
25
  token = tokens[index]
24
26
  return if token.type != :TEXT
27
+
25
28
  stripped_value = token.value.public_send(strip_method)
26
29
  tokens[index] = create_token(token.type, stripped_value, token.position)
27
30
  end
@@ -23,12 +23,14 @@ module Curlybars
23
23
  def check_timeout!
24
24
  return unless timeout.present?
25
25
  return unless (Time.now - start_time) > timeout
26
+
26
27
  message = "Rendering took too long (> #{timeout} seconds)"
27
28
  raise ::Curlybars::Error::Render.new('timeout', message, nil)
28
29
  end
29
30
 
30
31
  def check_context_is_presenter(context, path, position)
31
32
  return if presenter?(context)
33
+
32
34
  message = "`#{path}` is not a context type object"
33
35
  raise Curlybars::Error::Render.new('context_is_not_a_presenter', message, position)
34
36
  end
@@ -83,9 +85,11 @@ module Curlybars
83
85
  resolved = chain.inject(base_context) do |context, meth|
84
86
  next context if meth == 'this'
85
87
  next context.count if meth == 'length' && presenter_collection?(context)
88
+
86
89
  raise_if_not_traversable(context, meth, position)
87
90
  outcome = instrument(context.method(meth)) { context.public_send(meth) }
88
91
  return -> {} if outcome.nil?
92
+
89
93
  outcome
90
94
  end
91
95
 
@@ -101,6 +105,7 @@ module Curlybars
101
105
 
102
106
  def cached_call(meth)
103
107
  return cached_calls[meth] if cached_calls.key? meth
108
+
104
109
  instrument(meth) { cached_calls[meth] = meth.call(*arguments_for_signature(meth, [], {})) }
105
110
  end
106
111
 
@@ -202,6 +207,7 @@ module Curlybars
202
207
 
203
208
  def check_context_allows_method(context, meth, position)
204
209
  return if context.allows_method?(meth.to_sym)
210
+
205
211
  message = "`#{meth}` is not available - "
206
212
  message += "add `allow_methods :#{meth}` to #{context.class} to allow this path"
207
213
  raise Curlybars::Error::Render.new('unallowed_path', message, position, meth: meth.to_sym)
@@ -209,12 +215,14 @@ module Curlybars
209
215
 
210
216
  def check_context_has_method(context, meth, position)
211
217
  return if context.respond_to?(meth.to_sym)
218
+
212
219
  message = "`#{meth}` is not available in #{context.class}"
213
220
  raise Curlybars::Error::Render.new('unallowed_path', message, position)
214
221
  end
215
222
 
216
223
  def check_traverse_not_too_deep(traverse, position)
217
224
  return unless traverse.count('.') > Curlybars.configuration.traversing_limit
225
+
218
226
  message = "`#{traverse}` too deep"
219
227
  raise Curlybars::Error::Render.new('traverse_too_deep', message, position)
220
228
  end
@@ -13,9 +13,17 @@ module Curlybars
13
13
  # template - The ActionView::Template template that should be compiled.
14
14
  #
15
15
  # Returns a String containing the Ruby code representing the template.
16
- def call(template)
17
- instrument(template) do
18
- compile(template)
16
+ if ActionView::VERSION::MAJOR < 6
17
+ def call(template)
18
+ instrument(template) do
19
+ compile_for_actionview5(template)
20
+ end
21
+ end
22
+ else
23
+ def call(template, source)
24
+ instrument(template) do
25
+ compile(template, source)
26
+ end
19
27
  end
20
28
  end
21
29
 
@@ -43,9 +51,13 @@ module Curlybars
43
51
 
44
52
  private
45
53
 
46
- def compile(template)
54
+ def compile_for_actionview5(template)
55
+ compile(template, template.source)
56
+ end
57
+
58
+ def compile(template, source)
47
59
  # Template is empty, so there's no need to initialize a presenter.
48
- return %("") if template.source.empty?
60
+ return %("") if source.empty?
49
61
 
50
62
  path = template.virtual_path
51
63
  presenter_class = Curlybars::Presenter.presenter_for_path(path)
@@ -55,7 +67,7 @@ module Curlybars
55
67
  # For security reason, we strip the encoding directive in order to avoid
56
68
  # potential issues when rendering the template in another character
57
69
  # encoding.
58
- safe_source = template.source.gsub(/\A#{ActionView::ENCODING_FLAG}/, '')
70
+ safe_source = source.gsub(/\A#{ActionView::ENCODING_FLAG}/, '')
59
71
 
60
72
  source = Curlybars.compile(safe_source, template.identifier)
61
73
 
@@ -1,3 +1,3 @@
1
1
  module Curlybars
2
- VERSION = '1.5.1'.freeze
2
+ VERSION = '1.6.0'.freeze
3
3
  end
@@ -2,7 +2,7 @@ describe "Using Curlybars for the application layout", type: :request do
2
2
  example "A simple layout view in Curlybars" do
3
3
  get '/'
4
4
 
5
- expect(body).to eq(<<-HTML.strip_heredoc)
5
+ expect(body).to eq(<<~HTML)
6
6
  <html>
7
7
  <head>
8
8
  <title>Dummy app</title>
@@ -31,7 +31,7 @@ describe "Using Curlybars for the application layout", type: :request do
31
31
  example "A simple layout view in Curlybars with html safe logic" do
32
32
  get '/articles/1'
33
33
 
34
- expect(body).to eq(<<-HTML.strip_heredoc)
34
+ expect(body).to eq(<<~HTML)
35
35
  <html>
36
36
  <head>
37
37
  <title>Dummy app</title>
@@ -8,7 +8,7 @@ describe "Collection blocks", type: :request do
8
8
  example "Rendering collections" do
9
9
  get '/categories'
10
10
 
11
- expect(body).to eq(<<-HTML.strip_heredoc)
11
+ expect(body).to eq(<<~HTML)
12
12
  <html>
13
13
  <head>
14
14
  <title>Dummy app</title>
@@ -9,7 +9,7 @@ describe "Collection blocks", type: :request do
9
9
  example "Render a global helper" do
10
10
  get '/welcome'
11
11
 
12
- expect(body).to eq(<<-HTML.strip_heredoc)
12
+ expect(body).to eq(<<~HTML)
13
13
  <html>
14
14
  <head>
15
15
  <title>Dummy app</title>
@@ -37,6 +37,7 @@ describe Curlybars::Lexer do
37
37
  it "is resilient to whitespaces" do
38
38
  expect(lex('{{! }}')).to produce []
39
39
  end
40
+
40
41
  it "is resilient to newlines" do
41
42
  expect(lex("{{!\n}}")).to produce []
42
43
  end
@@ -202,7 +203,7 @@ describe Curlybars::Lexer do
202
203
  end
203
204
  end
204
205
 
205
- # rubocop:disable Layout/AlignArray
206
+ # rubocop:disable Layout/ArrayAlignment
206
207
  describe "{{#if path}}...{{else}}...{{/if}}" do
207
208
  it "is lexed" do
208
209
  expect(lex('{{#if path}} text {{else}} text {{/if}}')).to produce(
@@ -320,7 +321,7 @@ describe Curlybars::Lexer do
320
321
  )
321
322
  end
322
323
  end
323
- # rubocop:enable Layout/AlignArray
324
+ # rubocop:enable Layout/ArrayAlignment
324
325
 
325
326
  describe "{{#with path}}...{{/with}}" do
326
327
  it "is lexed" do
@@ -1,3 +1,4 @@
1
+ # rubocop:disable RSpec/MultipleMemoizedHelpers
1
2
  describe Curlybars::RenderingSupport do
2
3
  let(:file_name) { '/app/views/template.hbs' }
3
4
  let(:presenter) { double(:presenter, allows_method?: true, meth: :value) }
@@ -7,7 +8,6 @@ describe Curlybars::RenderingSupport do
7
8
  let(:position) do
8
9
  double(:position, file_name: 'template.hbs', line_number: 1, line_offset: 0)
9
10
  end
10
- let(:block) { -> {} }
11
11
 
12
12
  describe "#check_timeout!" do
13
13
  it "skips checking if timeout is nil" do
@@ -179,14 +179,6 @@ describe Curlybars::RenderingSupport do
179
179
  end
180
180
 
181
181
  describe "#cached_call" do
182
- before do
183
- class APresenter
184
- def meth
185
- :value
186
- end
187
- end
188
- end
189
-
190
182
  it "(cache miss) calls the method if not cached already" do
191
183
  meth = presenter.method(:meth)
192
184
  allow(meth).to receive(:call)
@@ -217,6 +209,8 @@ describe Curlybars::RenderingSupport do
217
209
  end
218
210
 
219
211
  describe "#call" do
212
+ let(:block) { -> {} }
213
+
220
214
  it "calls with no arguments a method with no parameters" do
221
215
  method = -> { :return }
222
216
  arguments = []
@@ -424,3 +418,4 @@ describe Curlybars::RenderingSupport do
424
418
  allow(presenter).to receive(:allows_method?).and_return(false)
425
419
  end
426
420
  end
421
+ # rubocop:enable RSpec/MultipleMemoizedHelpers
@@ -100,13 +100,11 @@ describe Curlybars::TemplateHandler do
100
100
  end
101
101
 
102
102
  it "strips the `# encoding: *` directive away from the template" do
103
- allow(template).to receive(:source) do
104
- <<-TEMPLATE.strip_heredoc
105
- # encoding: utf-8"
106
- first line
107
- TEMPLATE
108
- end
109
- expect(output).to eq(<<-TEMPLATE.strip_heredoc)
103
+ output = render(<<~TEMPLATE)
104
+ # encoding: utf-8"
105
+ first line
106
+ TEMPLATE
107
+ expect(output).to eq(<<~TEMPLATE)
110
108
 
111
109
  first line
112
110
  TEMPLATE
@@ -114,55 +112,54 @@ describe Curlybars::TemplateHandler do
114
112
 
115
113
  it "passes in the presenter context to the presenter class" do
116
114
  allow(context).to receive(:bar).and_return("BAR")
117
- allow(template).to receive(:source).and_return("{{bar}}")
115
+ output = render("{{bar}}")
118
116
  expect(output).to eq("BAR")
119
117
  end
120
118
 
121
119
  it "fails if there's no matching presenter class" do
122
120
  allow(template).to receive(:virtual_path).and_return("missing")
123
- allow(template).to receive(:source).and_return(" FOO ")
124
- expect { output }.to raise_exception(Curlybars::Error::Presenter::NotFound)
121
+ expect { render(" FOO ") }.to raise_exception(Curlybars::Error::Presenter::NotFound)
125
122
  end
126
123
 
127
124
  it "allows calling public methods on the presenter" do
128
- allow(template).to receive(:source).and_return("{{foo}}")
125
+ output = render("{{foo}}")
129
126
  expect(output).to eq("FOO")
130
127
  end
131
128
 
132
129
  it "marks its output as HTML safe" do
133
- allow(template).to receive(:source).and_return("{{foo}}")
130
+ output = render("{{foo}}")
134
131
  expect(output).to be_html_safe
135
132
  end
136
133
 
137
134
  it "calls the #setup! method before rendering the view" do
138
- allow(template).to receive(:source).and_return("{{foo}}")
139
- output
135
+ render("{{foo}}")
140
136
  expect(context.content_for(:foo)).to eq("bar")
141
137
  end
142
138
 
143
139
  describe "caching" do
144
140
  before do
145
- allow(template).to receive(:source).and_return("{{bar}}")
146
141
  allow(context).to receive(:bar).and_return("BAR")
147
142
  end
148
143
 
144
+ let(:output) { -> { render("{{bar}}") } }
145
+
149
146
  it "caches the result with the #cache_key from the presenter" do
150
147
  context.assigns[:cache_key] = "x"
151
- expect(output).to eq("BAR")
148
+ expect(output.call).to eq("BAR")
152
149
 
153
150
  allow(context).to receive(:bar).and_return("BAZ")
154
- expect(output).to eq("BAR")
151
+ expect(output.call).to eq("BAR")
155
152
 
156
153
  context.assigns[:cache_key] = "y"
157
- expect(output).to eq("BAZ")
154
+ expect(output.call).to eq("BAZ")
158
155
  end
159
156
 
160
157
  it "doesn't cache when the cache key is nil" do
161
158
  context.assigns[:cache_key] = nil
162
- expect(output).to eq("BAR")
159
+ expect(output.call).to eq("BAR")
163
160
 
164
161
  allow(context).to receive(:bar).and_return("BAZ")
165
- expect(output).to eq("BAZ")
162
+ expect(output.call).to eq("BAZ")
166
163
  end
167
164
 
168
165
  it "adds the presenter class' cache key to the instance's cache key" do
@@ -171,51 +168,57 @@ describe Curlybars::TemplateHandler do
171
168
 
172
169
  allow(presenter_class).to receive(:cache_key).and_return("foo")
173
170
 
174
- expect(output).to eq("BAR")
171
+ expect(output.call).to eq("BAR")
175
172
 
176
173
  allow(presenter_class).to receive(:cache_key).and_return("bar")
177
174
 
178
175
  allow(context).to receive(:bar).and_return("FOOBAR")
179
- expect(output).to eq("FOOBAR")
176
+ expect(output.call).to eq("FOOBAR")
180
177
  end
181
178
 
182
179
  it "expires the cache keys after #cache_duration" do
183
180
  context.assigns[:cache_key] = "x"
184
181
  context.assigns[:cache_duration] = 42
185
182
 
186
- expect(output).to eq("BAR")
183
+ expect(output.call).to eq("BAR")
187
184
 
188
185
  allow(context).to receive(:bar).and_return("FOO")
189
186
 
190
187
  # Cached fragment has not yet expired.
191
188
  context.advance_clock(41)
192
- expect(output).to eq("BAR")
189
+ expect(output.call).to eq("BAR")
193
190
 
194
191
  # Now it has! Huzzah!
195
192
  context.advance_clock(1)
196
- expect(output).to eq("FOO")
193
+ expect(output.call).to eq("FOO")
197
194
  end
198
195
 
199
196
  it "passes #cache_options to the cache backend" do
200
197
  context.assigns[:cache_key] = "x"
201
198
  context.assigns[:cache_options] = { expires_in: 42 }
202
199
 
203
- expect(output).to eq("BAR")
200
+ expect(output.call).to eq("BAR")
204
201
 
205
202
  allow(context).to receive(:bar).and_return("FOO")
206
203
 
207
204
  # Cached fragment has not yet expired.
208
205
  context.advance_clock(41)
209
- expect(output).to eq("BAR")
206
+ expect(output.call).to eq("BAR")
210
207
 
211
208
  # Now it has! Huzzah!
212
209
  context.advance_clock(1)
213
- expect(output).to eq("FOO")
210
+ expect(output.call).to eq("FOO")
214
211
  end
215
212
  end
216
213
 
217
- def output
218
- code = Curlybars::TemplateHandler.call(template)
214
+ def render(source)
215
+ if ActionView::VERSION::MAJOR < 6
216
+ allow(template).to receive(:source).and_return(source)
217
+ code = Curlybars::TemplateHandler.call(template)
218
+ else
219
+ code = Curlybars::TemplateHandler.call(template, source)
220
+ end
221
+
219
222
  context.reset!
220
223
  context.instance_eval(code)
221
224
  end
@@ -1,29 +1,31 @@
1
1
  describe "caching" do
2
- class DummyCache
3
- attr_reader :reads, :hits
4
-
5
- def initialize
6
- @store = {}
7
- @reads = 0
8
- @hits = 0
9
- end
2
+ let(:dummy_cache) do
3
+ Class.new do
4
+ attr_reader :reads, :hits
5
+
6
+ def initialize
7
+ @store = {}
8
+ @reads = 0
9
+ @hits = 0
10
+ end
10
11
 
11
- def fetch(key)
12
- @reads += 1
13
- if @store.key?(key)
14
- @hits += 1
15
- @store[key]
16
- else
17
- value = yield
18
- @store[key] = value
19
- value
12
+ def fetch(key)
13
+ @reads += 1
14
+ if @store.key?(key)
15
+ @hits += 1
16
+ @store[key]
17
+ else
18
+ value = yield
19
+ @store[key] = value
20
+ value
21
+ end
20
22
  end
21
23
  end
22
24
  end
23
25
 
24
26
  let(:global_helpers_providers) { [] }
25
27
  let(:presenter) { IntegrationTest::Presenter.new(double("view_context")) }
26
- let(:cache) { DummyCache.new }
28
+ let(:cache) { dummy_cache.new }
27
29
 
28
30
  before do
29
31
  Curlybars.configure do |config|
@@ -230,8 +230,6 @@ describe "{{#helper arg1 arg2 ... key=value ...}}...<{{else}}>...{{/helper}}" do
230
230
  end
231
231
 
232
232
  describe "#validate" do
233
- let(:presenter_class) { double(:presenter_class) }
234
-
235
233
  it "without errors when global helper" do
236
234
  allow(Curlybars.configuration).to receive(:global_helpers_provider_classes).and_return([IntegrationTest::GlobalHelperProvider])
237
235
 
@@ -151,8 +151,6 @@ describe "{{#each collection}}...{{else}}...{{/each}}" do
151
151
  end
152
152
 
153
153
  describe "#validate" do
154
- let(:presenter_class) { double(:presenter_class) }
155
-
156
154
  it "without errors" do
157
155
  dependency_tree = { a_presenter_collection: [{}] }
158
156
 
@@ -238,8 +238,6 @@ describe "{{#each collection}}...{{/each}}" do
238
238
  end
239
239
 
240
240
  describe "#validate" do
241
- let(:presenter_class) { double(:presenter_class) }
242
-
243
241
  it "without errors" do
244
242
  dependency_tree = { a_presenter_collection: [{}] }
245
243
 
@@ -121,8 +121,6 @@ describe "{{helper context key=value}}" do
121
121
  end
122
122
 
123
123
  describe "#validate" do
124
- let(:presenter_class) { double(:presenter_class) }
125
-
126
124
  it "with errors" do
127
125
  dependency_tree = {}
128
126
 
@@ -82,8 +82,6 @@ describe "{{#if}}...{{else}}...{{/if}}" do
82
82
  end
83
83
 
84
84
  describe "#validate" do
85
- let(:presenter_class) { double(:presenter_class) }
86
-
87
85
  it "validates without errors the literal condition" do
88
86
  dependency_tree = {}
89
87
 
@@ -112,8 +112,6 @@ describe "{{#if}}...{{/if}}" do
112
112
  end
113
113
 
114
114
  describe "#validate" do
115
- let(:presenter_class) { double(:presenter_class) }
116
-
117
115
  it "validates with errors the condition" do
118
116
  dependency_tree = {}
119
117
 
@@ -51,8 +51,6 @@ describe '{{value}}' do
51
51
  end
52
52
 
53
53
  describe "#validate" do
54
- let(:presenter_class) { double(:presenter_class) }
55
-
56
54
  it "validates the path with errors" do
57
55
  dependency_tree = {}
58
56
 
@@ -25,8 +25,6 @@ describe "{{> partial}}" do
25
25
  end
26
26
 
27
27
  describe "#validate" do
28
- let(:presenter_class) { double(:presenter_class) }
29
-
30
28
  it "validates the path with errors" do
31
29
  dependency_tree = {}
32
30
 
@@ -123,8 +123,6 @@ describe "{{path}}" do
123
123
  end
124
124
 
125
125
  describe "#validate" do
126
- let(:presenter_class) { double(:presenter_class) }
127
-
128
126
  it "without errors" do
129
127
  dependency_tree = { sub_context: {}, outer_field: nil }
130
128
 
@@ -1,7 +1,5 @@
1
1
  describe "root" do
2
2
  describe "#validate" do
3
- let(:presenter_class) { double(:presenter_class) }
4
-
5
3
  it "without errors if template is empty" do
6
4
  dependency_tree = {}
7
5
 
@@ -227,8 +227,6 @@ describe "{{(helper arg1 arg2 ... key=value ...)}}" do
227
227
  end
228
228
 
229
229
  describe "#validate" do
230
- let(:presenter_class) { double(:presenter_class) }
231
-
232
230
  before do
233
231
  allow(Curlybars.configuration).to receive(:global_helpers_provider_classes).and_return([IntegrationTest::GlobalHelperProvider])
234
232
  end
@@ -53,8 +53,6 @@ describe "template" do
53
53
  end
54
54
 
55
55
  describe "#validate" do
56
- let(:presenter_class) { double(:presenter_class) }
57
-
58
56
  it "without errors" do
59
57
  dependency_tree = { presenter: { field: nil } }
60
58
 
@@ -82,8 +82,6 @@ describe "{{#unless}}...{{else}}...{{/unless}}" do
82
82
  end
83
83
 
84
84
  describe "#validate" do
85
- let(:presenter_class) { double(:presenter_class) }
86
-
87
85
  it "validates with errors the condition" do
88
86
  dependency_tree = {}
89
87
 
@@ -99,8 +99,6 @@ describe "{{#unless}}...{{/unless}}" do
99
99
  end
100
100
 
101
101
  describe "#validate" do
102
- let(:presenter_class) { double(:presenter_class) }
103
-
104
102
  it "validates with errors the condition" do
105
103
  dependency_tree = {}
106
104
 
@@ -75,8 +75,6 @@ describe "{{#with presenter}}...{{/with}}" do
75
75
  end
76
76
 
77
77
  describe "#validate" do
78
- let(:presenter_class) { double(:presenter_class) }
79
-
80
78
  it "without errors" do
81
79
  dependency_tree = { a_presenter: {} }
82
80
 
@@ -1,6 +1,5 @@
1
1
  describe "processors" do
2
2
  let(:presenter) { double(:presenter, dependency_tree: { curlybars: nil }) }
3
- let(:global_helpers_providers) { [] }
4
3
  let(:processor) { double(:processor) }
5
4
 
6
5
  before do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: curlybars
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.1
4
+ version: 1.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Libo Cannici
@@ -14,7 +14,7 @@ authors:
14
14
  autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
- date: 2020-11-02 00:00:00.000000000 Z
17
+ date: 2021-01-05 00:00:00.000000000 Z
18
18
  dependencies:
19
19
  - !ruby/object:Gem::Dependency
20
20
  name: actionpack
@@ -25,7 +25,7 @@ dependencies:
25
25
  version: '4.2'
26
26
  - - "<"
27
27
  - !ruby/object:Gem::Version
28
- version: '6.0'
28
+ version: '6.2'
29
29
  type: :runtime
30
30
  prerelease: false
31
31
  version_requirements: !ruby/object:Gem::Requirement
@@ -35,7 +35,7 @@ dependencies:
35
35
  version: '4.2'
36
36
  - - "<"
37
37
  - !ruby/object:Gem::Version
38
- version: '6.0'
38
+ version: '6.2'
39
39
  - !ruby/object:Gem::Dependency
40
40
  name: activesupport
41
41
  requirement: !ruby/object:Gem::Requirement
@@ -45,7 +45,7 @@ dependencies:
45
45
  version: '4.2'
46
46
  - - "<"
47
47
  - !ruby/object:Gem::Version
48
- version: '6.0'
48
+ version: '6.2'
49
49
  type: :runtime
50
50
  prerelease: false
51
51
  version_requirements: !ruby/object:Gem::Requirement
@@ -55,7 +55,7 @@ dependencies:
55
55
  version: '4.2'
56
56
  - - "<"
57
57
  - !ruby/object:Gem::Version
58
- version: '6.0'
58
+ version: '6.2'
59
59
  - !ruby/object:Gem::Dependency
60
60
  name: ffi
61
61
  requirement: !ruby/object:Gem::Requirement
@@ -121,7 +121,7 @@ dependencies:
121
121
  version: '4.2'
122
122
  - - "<"
123
123
  - !ruby/object:Gem::Version
124
- version: '6.0'
124
+ version: '6.2'
125
125
  type: :development
126
126
  prerelease: false
127
127
  version_requirements: !ruby/object:Gem::Requirement
@@ -131,7 +131,7 @@ dependencies:
131
131
  version: '4.2'
132
132
  - - "<"
133
133
  - !ruby/object:Gem::Version
134
- version: '6.0'
134
+ version: '6.2'
135
135
  - !ruby/object:Gem::Dependency
136
136
  name: rake
137
137
  requirement: !ruby/object:Gem::Requirement
@@ -166,28 +166,56 @@ dependencies:
166
166
  requirements:
167
167
  - - "~>"
168
168
  - !ruby/object:Gem::Version
169
- version: 0.58.2
169
+ version: 1.6.0
170
170
  type: :development
171
171
  prerelease: false
172
172
  version_requirements: !ruby/object:Gem::Requirement
173
173
  requirements:
174
174
  - - "~>"
175
175
  - !ruby/object:Gem::Version
176
- version: 0.58.2
176
+ version: 1.6.0
177
+ - !ruby/object:Gem::Dependency
178
+ name: rubocop-performance
179
+ requirement: !ruby/object:Gem::Requirement
180
+ requirements:
181
+ - - "~>"
182
+ - !ruby/object:Gem::Version
183
+ version: 1.9.0
184
+ type: :development
185
+ prerelease: false
186
+ version_requirements: !ruby/object:Gem::Requirement
187
+ requirements:
188
+ - - "~>"
189
+ - !ruby/object:Gem::Version
190
+ version: 1.9.0
191
+ - !ruby/object:Gem::Dependency
192
+ name: rubocop-rake
193
+ requirement: !ruby/object:Gem::Requirement
194
+ requirements:
195
+ - - "~>"
196
+ - !ruby/object:Gem::Version
197
+ version: 0.5.0
198
+ type: :development
199
+ prerelease: false
200
+ version_requirements: !ruby/object:Gem::Requirement
201
+ requirements:
202
+ - - "~>"
203
+ - !ruby/object:Gem::Version
204
+ version: 0.5.0
177
205
  - !ruby/object:Gem::Dependency
178
206
  name: rubocop-rspec
179
207
  requirement: !ruby/object:Gem::Requirement
180
208
  requirements:
181
209
  - - "~>"
182
210
  - !ruby/object:Gem::Version
183
- version: 1.28.0
211
+ version: 2.1.0
184
212
  type: :development
185
213
  prerelease: false
186
214
  version_requirements: !ruby/object:Gem::Requirement
187
215
  requirements:
188
216
  - - "~>"
189
217
  - !ruby/object:Gem::Version
190
- version: 1.28.0
218
+ version: 2.1.0
191
219
  description: |-
192
220
  A view layer for your Rails apps that separates structure and logic, using Handlebars templates.
193
221
  Strongly inspired by Curly Template gem by Daniel Schierbeck.
@@ -288,7 +316,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
288
316
  requirements:
289
317
  - - ">="
290
318
  - !ruby/object:Gem::Version
291
- version: '0'
319
+ version: '2.4'
292
320
  required_rubygems_version: !ruby/object:Gem::Requirement
293
321
  requirements:
294
322
  - - ">="