tilt 2.5.0 → 2.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. checksums.yaml +4 -4
  2. data/lib/tilt/template.rb +151 -24
  3. data/lib/tilt.rb +9 -1
  4. metadata +3 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1386734fb6f20f9b1faf9e5edd4c83156e1d2e355141cd136ef949e956769e75
4
- data.tar.gz: 52108af4de8efed7ade56f64e22d79fd3e5aaad4eb5ec36b2f0947242e102e57
3
+ metadata.gz: 950d868674b6de4ce7773935b2b9fd07c16528089320eaf0b3ab49be456cdf71
4
+ data.tar.gz: 720b39e51f933872fca6d768bb161ab08b96afeeafce3af69cbf81fa44a6ff58
5
5
  SHA512:
6
- metadata.gz: 99a6e69ae4720ad5146c46b9b885fa4a4714b250d9db9168ae801d17f3146c90f25eab789401081100fdc065ae3ce3e804b79427e5ac835bd6bc576d3318a073
7
- data.tar.gz: b0a44938aae6303bf03d174a942615e371669be99e4ec641a7a2b6ac0ee8d4f45f82869142f3e17b162efdd365883e909463763064b2b1b0417679652319c804
6
+ metadata.gz: 85b22c88b5bc0f0b546336e80af4329760939d3cdf1777568774e09e894a4de92c3abce170f6f9e694997291782551ef3f285e732d2054680605bbb150e17adb
7
+ data.tar.gz: 86c570a4eb2c7e85169eea86be5607e8257aa8594dc50737f928e901ea9966634f452dc0c24b11baa836e86c201e55c20d6946df5a9c8ee40fe547feb573f4c0
data/lib/tilt/template.rb CHANGED
@@ -57,7 +57,28 @@ module Tilt
57
57
  # it should read template data and return as a String. When file is nil,
58
58
  # a block is required.
59
59
  #
60
- # All arguments are optional.
60
+ # All arguments are optional. The following options are respected and
61
+ # are used by Tilt::Template itself and not the underlying template
62
+ # libraries:
63
+ #
64
+ # :default_encoding :: Force the encoding of the template to the given
65
+ # encoding.
66
+ # :skip_compiled_encoding_detection :: Do not scan template code for
67
+ # an encoding magic comment.
68
+ # :fixed_locals :: Force a specific method parameter signature, and call
69
+ # the method with a splat of locals, instead of passing
70
+ # the locals hash as a positional argument, and
71
+ # extracting locals from that. Should be a string
72
+ # containing the parameters for the compiled method,
73
+ # surrounded by parentheses. Can be set to false to
74
+ # disable the scan for embedded fixed locals.
75
+ # :extract_fixed_locals :: Whether embedded fixed locals should be scanned for
76
+ # and extracted from the template code.
77
+ # :default_fixed_locals :: Similar to fixed_locals, but lowest priority,
78
+ # only used if :fixed_locals is not provided
79
+ # and no embedded locals are found (or scanned for).
80
+ # :scope_class :: Force the scope class used for the method. By default,
81
+ # uses the class of the scope provided to render.
61
82
  def initialize(file=nil, line=nil, options=nil)
62
83
  @file, @line, @options = nil, 1, nil
63
84
 
@@ -69,7 +90,9 @@ module Tilt
69
90
 
70
91
  @options ||= {}
71
92
 
72
- set_compiled_method_cache
93
+ # Force a specific scope class, instead of using the class of the provided
94
+ # scope as the scope class.
95
+ @scope_class = @options.delete :scope_class
73
96
 
74
97
  # Force the encoding of the input data
75
98
  @default_encoding = @options.delete :default_encoding
@@ -78,6 +101,13 @@ module Tilt
78
101
  # for compiled templates
79
102
  @skip_compiled_encoding_detection = @options.delete :skip_compiled_encoding_detection
80
103
 
104
+ # Compiled path to use. This must be specified as an option if
105
+ # providing the :scope_class option and using fixed locals,
106
+ # since template compilation occurs during initialization in that case.
107
+ if compiled_path = @options.delete(:compiled_path)
108
+ self.compiled_path = compiled_path
109
+ end
110
+
81
111
  # load template data and prepare (uses binread to avoid encoding issues)
82
112
  @data = block_given? ? yield(self) : read_template_file
83
113
 
@@ -92,7 +122,9 @@ module Tilt
92
122
  end
93
123
  end
94
124
 
125
+ set_fixed_locals
95
126
  prepare
127
+ set_compiled_method_cache
96
128
  end
97
129
 
98
130
  # Render the template in the given scope with the locals specified. If a
@@ -119,6 +151,11 @@ module Tilt
119
151
  @file || '(__TEMPLATE__)'
120
152
  end
121
153
 
154
+ # Whether the template uses fixed locals.
155
+ def fixed_locals?
156
+ @fixed_locals ? true : false
157
+ end
158
+
122
159
  # An empty Hash that the template engine can populate with various
123
160
  # metadata.
124
161
  def metadata
@@ -129,7 +166,14 @@ module Tilt
129
166
  end
130
167
  end
131
168
 
132
- # Set the prefix to use for compiled paths.
169
+ # Set the prefix to use for compiled paths, similar to using the
170
+ # :compiled_path template option. Note that this only
171
+ # has affect for future template compilations. When using the
172
+ # :scope_class template option, and using fixed_locals, calling
173
+ # this after the template is created has no effect, since the
174
+ # template is compiled during initialization in that case. It
175
+ # is recommended to use the :compiled_path template option
176
+ # instead of this method in new code.
133
177
  def compiled_path=(path)
134
178
  if path
135
179
  # Use expanded paths when loading, since that is helpful
@@ -145,7 +189,18 @@ module Tilt
145
189
  # directly on the scope class, which are much faster to call than
146
190
  # Tilt's normal rendering.
147
191
  def compiled_method(locals_keys, scope_class=nil)
148
- key = [scope_class, locals_keys].freeze
192
+ if @fixed_locals
193
+ if @scope_class
194
+ return @compiled_method
195
+ else
196
+ key = scope_class
197
+ end
198
+ elsif @scope_class
199
+ key = locals_keys.dup.freeze
200
+ else
201
+ key = [scope_class, locals_keys].freeze
202
+ end
203
+
149
204
  LOCK.synchronize do
150
205
  if meth = @compiled_method[key]
151
206
  return meth
@@ -181,7 +236,7 @@ module Tilt
181
236
  end
182
237
 
183
238
  CLASS_METHOD = Kernel.instance_method(:class)
184
- USE_BIND_CALL = RUBY_VERSION >= '2.7'
239
+ USE_BIND_CALL = RUBY_VERSION >= '3'
185
240
 
186
241
  # Execute the compiled template and return the result string. Template
187
242
  # evaluation is guaranteed to be performed in the scope object with the
@@ -190,26 +245,25 @@ module Tilt
190
245
  # This method is only used by source generating templates. Subclasses that
191
246
  # override render() may not support all features.
192
247
  def evaluate(scope, locals, &block)
193
- locals_keys = locals.keys
194
- locals_keys.sort!{|x, y| x.to_s <=> y.to_s}
195
-
196
- case scope
197
- when Object
198
- scope_class = Module === scope ? scope : scope.class
248
+ if @fixed_locals
249
+ locals_keys = EMPTY_ARRAY
199
250
  else
200
- # :nocov:
201
- scope_class = USE_BIND_CALL ? CLASS_METHOD.bind_call(scope) : CLASS_METHOD.bind(scope).call
202
- # :nocov:
251
+ locals_keys = locals.keys
252
+ locals_keys.sort!{|x, y| x.to_s <=> y.to_s}
203
253
  end
204
- method = compiled_method(locals_keys, scope_class)
205
254
 
206
- if USE_BIND_CALL
207
- method.bind_call(scope, locals, &block)
208
- # :nocov:
209
- else
210
- method.bind(scope).call(locals, &block)
211
- # :nocov:
255
+ unless scope_class = @scope_class
256
+ scope_class = case scope
257
+ when Object
258
+ Module === scope ? scope : scope.class
259
+ else
260
+ # :nocov:
261
+ USE_BIND_CALL ? CLASS_METHOD.bind_call(scope) : CLASS_METHOD.bind(scope).call
262
+ # :nocov:
263
+ end
212
264
  end
265
+
266
+ evaluate_method(compiled_method(locals_keys, scope_class), scope, locals, &block)
213
267
  end
214
268
 
215
269
  # Generates all template source by combining the preamble, template, and
@@ -303,7 +357,12 @@ module Tilt
303
357
  end
304
358
 
305
359
  def set_compiled_method_cache
306
- @compiled_method = {}
360
+ @compiled_method = if @fixed_locals && @scope_class
361
+ # No hash needed, only a single compiled method per template.
362
+ compile_template_method(EMPTY_ARRAY, @scope_class)
363
+ else
364
+ {}
365
+ end
307
366
  end
308
367
 
309
368
  def local_extraction(local_keys)
@@ -327,9 +386,39 @@ module Tilt
327
386
  assignments.join("\n")
328
387
  end
329
388
 
389
+ if USE_BIND_CALL
390
+ def evaluate_method(method, scope, locals, &block)
391
+ if @fixed_locals
392
+ method.bind_call(scope, **locals, &block)
393
+ else
394
+ method.bind_call(scope, locals, &block)
395
+ end
396
+ end
397
+ # :nocov:
398
+ else
399
+ def evaluate_method(method, scope, locals, &block)
400
+ if @fixed_locals
401
+ if locals.empty?
402
+ # Empty keyword splat on Ruby 2.0-2.6 passes empty hash
403
+ method.bind(scope).call(&block)
404
+ else
405
+ method.bind(scope).call(**locals, &block)
406
+ end
407
+ else
408
+ method.bind(scope).call(locals, &block)
409
+ end
410
+ end
411
+ end
412
+ # :nocov:
413
+
330
414
  def compile_template_method(local_keys, scope_class=nil)
331
415
  source, offset = precompiled(local_keys)
332
- local_code = local_extraction(local_keys)
416
+ if @fixed_locals
417
+ method_args = @fixed_locals
418
+ else
419
+ method_args = "(locals)"
420
+ local_code = local_extraction(local_keys)
421
+ end
333
422
 
334
423
  method_name = "__tilt_#{Thread.current.object_id.abs}"
335
424
  method_source = String.new
@@ -340,7 +429,7 @@ module Tilt
340
429
  end
341
430
 
342
431
  # Don't indent method source, to avoid indentation warnings when using compiled paths
343
- method_source << "::Tilt::TOPOBJECT.class_eval do\ndef #{method_name}(locals)\n#{local_code}\n"
432
+ method_source << "::Tilt::TOPOBJECT.class_eval do\ndef #{method_name}#{method_args}\n#{local_code}\n"
344
433
 
345
434
  offset += method_source.count("\n")
346
435
  method_source << source
@@ -397,6 +486,40 @@ module Tilt
397
486
  method
398
487
  end
399
488
 
489
+ # Set the fixed locals for the template, which may be nil if no fixed locals can
490
+ # be determined.
491
+ def set_fixed_locals
492
+ fixed_locals = @options.delete(:fixed_locals)
493
+ extract_fixed_locals = @options.delete(:extract_fixed_locals)
494
+ default_fixed_locals = @options.delete(:default_fixed_locals)
495
+
496
+ if fixed_locals.nil?
497
+ if extract_fixed_locals.nil?
498
+ extract_fixed_locals = Tilt.extract_fixed_locals
499
+ end
500
+
501
+ if extract_fixed_locals
502
+ fixed_locals = extract_fixed_locals()
503
+ end
504
+
505
+ if fixed_locals.nil?
506
+ fixed_locals = default_fixed_locals
507
+ end
508
+ end
509
+
510
+ @fixed_locals = fixed_locals
511
+ end
512
+
513
+ # Extract fixed locals from the template code string. Should return nil
514
+ # if there are no fixed locals specified, or a method argument string
515
+ # surrounded by parentheses if there are fixed locals. The method
516
+ # argument string will be used when defining the template method if given.
517
+ def extract_fixed_locals
518
+ if @data.is_a?(String) && (match = /\#\s*locals:\s*(\(.*\))/.match(@data))
519
+ match[1]
520
+ end
521
+ end
522
+
400
523
  def extract_encoding(script, &block)
401
524
  extract_magic_comment(script, &block) || script.encoding
402
525
  end
@@ -475,5 +598,9 @@ module Tilt
475
598
  # Do nothing, since compiled method cache is not used.
476
599
  def set_compiled_method_cache
477
600
  end
601
+
602
+ # Do nothing, since fixed locals are not used.
603
+ def set_fixed_locals
604
+ end
478
605
  end
479
606
  end
data/lib/tilt.rb CHANGED
@@ -5,12 +5,16 @@ require_relative 'tilt/template'
5
5
  # Namespace for Tilt. This module is not intended to be included anywhere.
6
6
  module Tilt
7
7
  # Current version.
8
- VERSION = '2.5.0'
8
+ VERSION = '2.6.0'
9
+
10
+ EMPTY_ARRAY = [].freeze
11
+ private_constant :EMPTY_ARRAY
9
12
 
10
13
  EMPTY_HASH = {}.freeze
11
14
  private_constant :EMPTY_HASH
12
15
 
13
16
  @default_mapping = Mapping.new
17
+ @extract_fixed_locals = false
14
18
 
15
19
  # Replace the default mapping with a finalized version of the default
16
20
  # mapping. This can be done to improve performance after the template
@@ -86,6 +90,10 @@ module Tilt
86
90
  # @return [Tilt::Mapping] the main mapping object
87
91
  attr_reader :default_mapping
88
92
 
93
+ # Whether to extract fixed locals from templates by scanning the
94
+ # template content.
95
+ attr_accessor :extract_fixed_locals
96
+
89
97
  # Alias register as prefer for Tilt 1.x compatibility.
90
98
  alias prefer register
91
99
  end
metadata CHANGED
@@ -1,16 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tilt
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.5.0
4
+ version: 2.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryan Tomayko
8
8
  - Magnus Holm
9
9
  - Jeremy Evans
10
- autorequire:
11
10
  bindir: bin
12
11
  cert_chain: []
13
- date: 2024-12-20 00:00:00.000000000 Z
12
+ date: 2025-01-13 00:00:00.000000000 Z
14
13
  dependencies: []
15
14
  description: Generic interface to multiple Ruby template engines
16
15
  email: code@jeremyevans.net
@@ -68,7 +67,6 @@ metadata:
68
67
  changelog_uri: https://github.com/jeremyevans/tilt/blob/master/CHANGELOG.md
69
68
  mailing_list_uri: https://github.com/jeremyevans/tilt/discussions
70
69
  source_code_uri: https://github.com/jeremyevans/tilt
71
- post_install_message:
72
70
  rdoc_options:
73
71
  - "--line-numbers"
74
72
  - "--inline-source"
@@ -89,8 +87,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
89
87
  - !ruby/object:Gem::Version
90
88
  version: '0'
91
89
  requirements: []
92
- rubygems_version: 3.5.22
93
- signing_key:
90
+ rubygems_version: 3.6.2
94
91
  specification_version: 4
95
92
  summary: Generic interface to multiple Ruby template engines
96
93
  test_files: []