tilt 2.2.0 → 2.6.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0b933744ac3dc007d759af22c61ea725d84e6d83a689c07e384792d08f330f60
4
- data.tar.gz: b07ad772a645934f3c0f912d2864eb9b47964b423a83d3cbc7978e6c90385229
3
+ metadata.gz: c7d6bc14bd4e47e94393d385285b1e147bcd06eac37dbcc8549b9d34b3513d2c
4
+ data.tar.gz: b4c7d8bffee3d9002adca1498b3f132629d82f7b5b05414914fdfcf44cc15c93
5
5
  SHA512:
6
- metadata.gz: 17e9ff63c011271c8fceb20c08f1c3d36f85c6674608690575ffc08b79b5d9704c0d63e456c00a2a0207295f54ef8c5df9f59c5de71680b1bf018faee93cba26
7
- data.tar.gz: fcffaeed7fba1e7f2bd9ec25f57426d544281cd434f8138253f5046f47e73a871770b4e8be1cb08349462b988a6101bbbca1f7ecc273bd74f457271eb3a84aa9
6
+ metadata.gz: 0325d0761536f88b597e37a2bf5e6fa467f35ce7ced1921f1912a25c85492cbddcb3ed27811beb6f7fe09f3dc302104da199f662ca6ed92d4b303dfce2f96d64
7
+ data.tar.gz: a82be500d86a6f2df1de115bee8f506033b3679f838d3416e21f0773539d5eda3ab73d49c46d7fd2189bfaeaa0d26cb568d66123b96682a96c6604efe23461c3
data/lib/tilt/coffee.rb CHANGED
@@ -15,18 +15,6 @@ module Tilt
15
15
  attr_accessor :default_bare
16
16
  end
17
17
 
18
- # :nocov:
19
- def self.default_no_wrap
20
- warn "#{self.class}.default_no_wrap is deprecated and will be removed in Tilt 2.3. Switch to #{self.class}.default_bare."
21
- default_bare
22
- end
23
-
24
- def self.default_no_wrap=(value)
25
- warn "#{self.class}.default_no_wrap= is deprecated and will be removed in Tilt 2.3. Switch to #{self.class}.default_bare=."
26
- self.default_bare = value
27
- end
28
- # :nocov:
29
-
30
18
  def self.literate?
31
19
  false
32
20
  end
@@ -2,53 +2,94 @@
2
2
  require_relative 'template'
3
3
  require 'commonmarker'
4
4
 
5
- aliases = {
6
- :smartypants => :SMART
7
- }.freeze
8
- parse_opts = [
9
- :FOOTNOTES,
10
- :LIBERAL_HTML_TAG,
11
- :SMART,
12
- :smartypants,
13
- :STRIKETHROUGH_DOUBLE_TILDE,
14
- :UNSAFE,
15
- :VALIDATE_UTF8,
16
- ].freeze
17
- render_opts = [
18
- :FOOTNOTES,
19
- :FULL_INFO_STRING,
20
- :GITHUB_PRE_LANG,
21
- :HARDBREAKS,
22
- :NOBREAKS,
23
- :SAFE, # Removed in v0.18.0 (2018-10-17)
24
- :SOURCEPOS,
25
- :TABLE_PREFER_STYLE_ATTRIBUTES,
26
- :UNSAFE,
27
- ].freeze
28
- exts = [
29
- :autolink,
30
- :strikethrough,
31
- :table,
32
- :tagfilter,
33
- :tasklist,
34
- ].freeze
5
+ if defined?(::Commonmarker)
6
+ aliases = {
7
+ :smartypants => :smart
8
+ }.freeze
9
+ parse_opts = [
10
+ :smart,
11
+ :default_info_string,
12
+ ].freeze
13
+ render_opts = [
14
+ :hardbreaks,
15
+ :github_pre_lang,
16
+ :width,
17
+ :unsafe,
18
+ :escape,
19
+ :sourcepos,
20
+ ].freeze
21
+ exts = [
22
+ :strikethrough,
23
+ :tagfilter,
24
+ :table,
25
+ :autolink,
26
+ :tasklist,
27
+ :superscript,
28
+ :header_ids,
29
+ :footnotes,
30
+ :description_lists,
31
+ :front_matter_delimiter,
32
+ :shortcodes,
33
+ ].freeze
35
34
 
35
+ Tilt::CommonMarkerTemplate = Tilt::StaticTemplate.subclass do
36
+ parse_options = @options.select { |key, _| parse_opts.include?(key.downcase) }.transform_keys(&:downcase)
37
+ parse_options.merge!(@options.select { |key, _| aliases.has_key?(key) }.transform_keys { |key| aliases[key] })
38
+ render_options = @options.select { |key, _| render_opts.include?(key.downcase) }.transform_keys(&:downcase)
39
+ extensions = @options.select { |key, _| exts.include?(key) }.transform_keys(&:downcase)
36
40
 
37
- Tilt::CommonMarkerTemplate = Tilt::StaticTemplate.subclass do
38
- extensions = exts.select do |extension|
39
- @options[extension]
41
+ Commonmarker.to_html(@data, options: { parse: parse_options, render: render_options, extension: extensions })
40
42
  end
43
+ # :nocov:
44
+ else
45
+ aliases = {
46
+ :smartypants => :SMART
47
+ }.freeze
48
+ parse_opts = [
49
+ :FOOTNOTES,
50
+ :LIBERAL_HTML_TAG,
51
+ :SMART,
52
+ :smartypants,
53
+ :STRIKETHROUGH_DOUBLE_TILDE,
54
+ :UNSAFE,
55
+ :VALIDATE_UTF8,
56
+ ].freeze
57
+ render_opts = [
58
+ :FOOTNOTES,
59
+ :FULL_INFO_STRING,
60
+ :GITHUB_PRE_LANG,
61
+ :HARDBREAKS,
62
+ :NOBREAKS,
63
+ :SAFE, # Removed in v0.18.0 (2018-10-17)
64
+ :SOURCEPOS,
65
+ :TABLE_PREFER_STYLE_ATTRIBUTES,
66
+ :UNSAFE,
67
+ ].freeze
68
+ exts = [
69
+ :autolink,
70
+ :strikethrough,
71
+ :table,
72
+ :tagfilter,
73
+ :tasklist,
74
+ ].freeze
41
75
 
42
- parse_options, render_options = [parse_opts, render_opts].map do |opts|
43
- opts = opts.select do |option|
44
- @options[option]
45
- end.map! do |option|
46
- aliases[option] || option
76
+ Tilt::CommonMarkerTemplate = Tilt::StaticTemplate.subclass do
77
+ extensions = exts.select do |extension|
78
+ @options[extension]
47
79
  end
48
80
 
49
- opts = :DEFAULT unless opts.any?
50
- opts
51
- end
81
+ parse_options, render_options = [parse_opts, render_opts].map do |opts|
82
+ opts = opts.select do |option|
83
+ @options[option]
84
+ end.map! do |option|
85
+ aliases[option] || option
86
+ end
87
+
88
+ opts = :DEFAULT unless opts.any?
89
+ opts
90
+ end
52
91
 
53
- CommonMarker.render_doc(@data, parse_options, extensions).to_html(render_options, extensions)
92
+ CommonMarker.render_doc(@data, parse_options, extensions).to_html(render_options, extensions)
93
+ end
54
94
  end
95
+ # :nocov:
data/lib/tilt/creole.rb CHANGED
@@ -2,6 +2,8 @@
2
2
  require_relative 'template'
3
3
  require 'creole'
4
4
 
5
+ warn 'tilt/creole is deprecated, as creole requires modifying string literals', uplevel: 1
6
+
5
7
  allowed_opts = [:allowed_schemes, :extensions, :no_escape].freeze
6
8
 
7
9
  # Creole implementation. See: http://www.wikicreole.org/
data/lib/tilt/erb.rb CHANGED
@@ -8,23 +8,9 @@ module Tilt
8
8
  class ERBTemplate < Template
9
9
  SUPPORTS_KVARGS = ::ERB.instance_method(:initialize).parameters.assoc(:key) rescue false
10
10
 
11
- # Remove in Tilt 2.3
12
- @default_output_variable = nil
13
- def self._default_output_variable
14
- @default_output_variable
15
- end
16
- def self.default_output_variable
17
- warn "#{self}.default_output_variable is deprecated and will be removed in Tilt 2.3.", uplevel: 1
18
- @default_output_variable
19
- end
20
- def self.default_output_variable=(name)
21
- warn "#{self}.default_output_variable= is deprecated and will be removed in Tilt 2.3. Switch to using the :outvar option.", uplevel: 1
22
- @default_output_variable = name
23
- end
24
-
25
11
  def prepare
26
12
  @freeze_string_literals = !!@options[:freeze]
27
- @outvar = @options[:outvar] || self.class._default_output_variable || '_erbout'
13
+ @outvar = @options[:outvar] || '_erbout'
28
14
  trim = case @options[:trim]
29
15
  when false
30
16
  nil
data/lib/tilt/etanni.rb CHANGED
@@ -5,7 +5,7 @@ module Tilt
5
5
  class EtanniTemplate < Template
6
6
  def prepare
7
7
  separator = data.hash.abs
8
- chomp = "<<#{separator}.chomp!"
8
+ chomp = "<<#{separator}.chomp"
9
9
  start = "\n_out_ << #{chomp}\n"
10
10
  stop = "\n#{separator}\n"
11
11
  replacement = "#{stop}\\1#{start}"
@@ -13,7 +13,7 @@ module Tilt
13
13
  temp = @data.strip
14
14
  temp.gsub!(/<\?r\s+(.*?)\s+\?>/m, replacement)
15
15
 
16
- @code = "_out_ = [<<#{separator}.chomp!]\n#{temp}#{stop}_out_.join"
16
+ @code = "_out_ = [<<#{separator}.chomp]\n#{temp}#{stop}_out_.join"
17
17
  end
18
18
 
19
19
  def precompiled_template(locals)
data/lib/tilt/liquid.rb CHANGED
@@ -13,9 +13,6 @@ module Tilt
13
13
  # to #to_h it will be ignored.
14
14
  #
15
15
  # LiquidTemplate does not support yield blocks.
16
- #
17
- # It's suggested that your program require 'liquid' at load
18
- # time when using this template engine.
19
16
  class LiquidTemplate < Template
20
17
  def prepare
21
18
  @options[:line_numbers] = true unless @options.has_key?(:line_numbers)
data/lib/tilt/mapping.rb CHANGED
@@ -113,14 +113,14 @@ module Tilt
113
113
  # the exception of the first, since that was the most preferred one.
114
114
  #
115
115
  # mapping = Tilt::Mapping.new
116
- # mapping.register_lazy('Maruku::Template', 'maruku/template', 'md')
116
+ # mapping.register_lazy('Kramdown::Template', 'kramdown/template', 'md')
117
117
  # mapping.register_lazy('RDiscount::Template', 'rdiscount/template', 'md')
118
118
  # mapping['index.md']
119
119
  # # => RDiscount::Template
120
120
  #
121
121
  # In the previous example we say that RDiscount has a *higher priority* than
122
- # Maruku. Tilt will first try to `require "rdiscount/template"`, falling
123
- # back to `require "maruku/template"`. If none of these are successful,
122
+ # Kramdown. Tilt will first try to `require "rdiscount/template"`, falling
123
+ # back to `require "kramdown/template"`. If none of these are successful,
124
124
  # the first error will be raised.
125
125
  class Mapping < BaseMapping
126
126
  LOCK = Mutex.new
data/lib/tilt/prawn.rb CHANGED
@@ -15,16 +15,9 @@ module Tilt
15
15
 
16
16
  def evaluate(scope, locals, &block)
17
17
  pdf = @engine
18
- if @data.respond_to?(:to_str)
19
- locals = locals.dup
20
- locals[:pdf] = pdf
21
- super
22
- else
23
- warn "Non-string provided as prawn template data. This is no longer supported and support for it will be removed in Tilt 2.3", :uplevel=>2
24
- # :nocov:
25
- @data.call(pdf) if @data.kind_of?(Proc)
26
- # :nocov:
27
- end
18
+ locals = locals.dup
19
+ locals[:pdf] = pdf
20
+ super
28
21
  pdf.render
29
22
  end
30
23
 
data/lib/tilt/rdoc.rb CHANGED
@@ -6,14 +6,6 @@ require 'rdoc/markup/to_html'
6
6
  require 'rdoc/options'
7
7
 
8
8
  # RDoc template. See: https://github.com/ruby/rdoc
9
- #
10
- # It's suggested that your program run the following at load time when
11
- # using this templae engine in a threaded environment:
12
- #
13
- # require 'rdoc'
14
- # require 'rdoc/markup'
15
- # require 'rdoc/markup/to_html'
16
- # require 'rdoc/options'
17
9
  Tilt::RDocTemplate = Tilt::StaticTemplate.subclass do
18
10
  RDoc::Markup::ToHtml.new(RDoc::Options.new, nil).convert(@data).to_s
19
11
  end
@@ -4,41 +4,28 @@ require 'redcarpet'
4
4
 
5
5
  aliases = {:escape_html => :filter_html, :smartypants => :smart}.freeze
6
6
 
7
- # :nocov:
8
- unless defined? ::Redcarpet::Render and defined? ::Redcarpet::Markdown
9
- # Redcarpet 1.x
10
- warn "Tilt support for RedCarpet 1.x is deprecated and will be removed in Tilt 2.3", uplevel: 1
11
- _flags = [:smart, :filter_html, :smartypants, :escape_html]
12
-
13
- Tilt::RedcarpetTemplate = Tilt::StaticTemplate.subclass do
14
- flags = _flags.select { |flag| @options[flag] }.map! { |flag| aliases[flag] || flag }
15
- RedcarpetCompat.new(@data, *flags).to_html
16
- end
17
- # :nocov:
18
- else
19
- Tilt::RedcarpetTemplate = Tilt::StaticTemplate.subclass do
20
- aliases.each do |opt, aka|
21
- if options.key?(aka) || !@options.key?(opt)
22
- @options[opt] = @options.delete(aka)
23
- end
7
+ Tilt::RedcarpetTemplate = Tilt::StaticTemplate.subclass do
8
+ aliases.each do |opt, aka|
9
+ if options.key?(aka) || !@options.key?(opt)
10
+ @options[opt] = @options.delete(aka)
24
11
  end
12
+ end
25
13
 
26
- # only raise an exception if someone is trying to enable :escape_html
27
- @options.delete(:escape_html) unless @options[:escape_html]
14
+ # only raise an exception if someone is trying to enable :escape_html
15
+ @options.delete(:escape_html) unless @options[:escape_html]
28
16
 
29
- renderer = @options.delete(:renderer) || ::Redcarpet::Render::HTML.new(@options)
30
- if options.delete(:smartypants) && !(renderer.is_a?(Class) && renderer <= ::Redcarpet::Render::SmartyPants)
31
- renderer = if renderer == ::Redcarpet::Render::XHTML
32
- ::Redcarpet::Render::SmartyHTML.new(:xhtml => true)
33
- elsif renderer == ::Redcarpet::Render::HTML
34
- ::Redcarpet::Render::SmartyHTML
35
- elsif renderer.is_a? Class
36
- Class.new(renderer) { include ::Redcarpet::Render::SmartyPants }
37
- else
38
- renderer.extend ::Redcarpet::Render::SmartyPants
39
- end
17
+ renderer = @options.delete(:renderer) || ::Redcarpet::Render::HTML.new(@options)
18
+ if options.delete(:smartypants) && !(renderer.is_a?(Class) && renderer <= ::Redcarpet::Render::SmartyPants)
19
+ renderer = if renderer == ::Redcarpet::Render::XHTML
20
+ ::Redcarpet::Render::SmartyHTML.new(:xhtml => true)
21
+ elsif renderer == ::Redcarpet::Render::HTML
22
+ ::Redcarpet::Render::SmartyHTML
23
+ elsif renderer.is_a? Class
24
+ Class.new(renderer) { include ::Redcarpet::Render::SmartyPants }
25
+ else
26
+ renderer.extend ::Redcarpet::Render::SmartyPants
40
27
  end
41
-
42
- Redcarpet::Markdown.new(renderer, @options).render(@data)
43
28
  end
29
+
30
+ Redcarpet::Markdown.new(renderer, @options).render(@data)
44
31
  end
data/lib/tilt/sass.rb CHANGED
@@ -13,6 +13,13 @@ module Tilt
13
13
  # :nocov:
14
14
  require 'uri'
15
15
 
16
+ ALLOWED_KEYS = (defined?(::Sass::Compiler) ? ::Sass::Compiler : ::Sass::Embedded).
17
+ instance_method(:compile_string).
18
+ parameters.
19
+ map{|k, v| v if k == :key}.
20
+ compact rescue nil
21
+ private_constant :ALLOWED_KEYS
22
+
16
23
  private
17
24
 
18
25
  def _prepare_output
@@ -22,9 +29,11 @@ module Tilt
22
29
  def sass_options
23
30
  path = File.absolute_path(eval_file)
24
31
  path = '/' + path unless path.start_with?('/')
25
- @options[:url] = ::URI::File.build([nil, ::URI::DEFAULT_PARSER.escape(path)]).to_s
26
- @options[:syntax] = :indented
27
- @options
32
+ opts = @options.dup
33
+ opts[:url] = ::URI::File.build([nil, ::URI::DEFAULT_PARSER.escape(path)]).to_s
34
+ opts[:syntax] = :indented
35
+ opts.delete_if{|k| !ALLOWED_KEYS.include?(k)} if ALLOWED_KEYS
36
+ opts
28
37
  end
29
38
  rescue LoadError => err
30
39
  begin
@@ -61,9 +70,9 @@ module Tilt
61
70
  private
62
71
 
63
72
  def sass_options
64
- super
65
- @options[:syntax] = :scss
66
- @options
73
+ opts = super
74
+ opts[:syntax] = :scss
75
+ opts
67
76
  end
68
77
  end
69
78
  end
data/lib/tilt/string.rb CHANGED
@@ -7,6 +7,7 @@ module Tilt
7
7
  class StringTemplate < Template
8
8
  def prepare
9
9
  hash = "TILT#{@data.hash.abs}"
10
+ @freeze_string_literals = !!@options[:freeze]
10
11
  @code = String.new("<<#{hash}.chomp\n#{@data}\n#{hash}")
11
12
  end
12
13
 
@@ -18,5 +19,9 @@ module Tilt
18
19
  source, offset = super
19
20
  [source, offset + 1]
20
21
  end
22
+
23
+ def freeze_string_literals?
24
+ @freeze_string_literals
25
+ end
21
26
  end
22
27
  end
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,12 +101,19 @@ 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
 
84
114
  if @data.respond_to?(:force_encoding)
85
115
  if default_encoding
86
- @data = @data.dup if @data.frozen?
116
+ @data = _dup_string_if_frozen(@data)
87
117
  @data.force_encoding(default_encoding)
88
118
  end
89
119
 
@@ -92,18 +122,16 @@ 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
99
131
  # block is given, it is typically available within the template via
100
132
  # +yield+.
101
133
  def render(scope=nil, locals=nil, &block)
102
- current_template = Thread.current[:tilt_current_template]
103
- Thread.current[:tilt_current_template] = self
104
134
  evaluate(scope || Object.new, locals || EMPTY_HASH, &block)
105
- ensure
106
- Thread.current[:tilt_current_template] = current_template
107
135
  end
108
136
 
109
137
  # The basename of the template file.
@@ -123,6 +151,11 @@ module Tilt
123
151
  @file || '(__TEMPLATE__)'
124
152
  end
125
153
 
154
+ # Whether the template uses fixed locals.
155
+ def fixed_locals?
156
+ @fixed_locals ? true : false
157
+ end
158
+
126
159
  # An empty Hash that the template engine can populate with various
127
160
  # metadata.
128
161
  def metadata
@@ -133,7 +166,14 @@ module Tilt
133
166
  end
134
167
  end
135
168
 
136
- # 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.
137
177
  def compiled_path=(path)
138
178
  if path
139
179
  # Use expanded paths when loading, since that is helpful
@@ -149,7 +189,18 @@ module Tilt
149
189
  # directly on the scope class, which are much faster to call than
150
190
  # Tilt's normal rendering.
151
191
  def compiled_method(locals_keys, scope_class=nil)
152
- 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
+
153
204
  LOCK.synchronize do
154
205
  if meth = @compiled_method[key]
155
206
  return meth
@@ -185,7 +236,7 @@ module Tilt
185
236
  end
186
237
 
187
238
  CLASS_METHOD = Kernel.instance_method(:class)
188
- USE_BIND_CALL = RUBY_VERSION >= '2.7'
239
+ USE_BIND_CALL = RUBY_VERSION >= '3'
189
240
 
190
241
  # Execute the compiled template and return the result string. Template
191
242
  # evaluation is guaranteed to be performed in the scope object with the
@@ -194,26 +245,25 @@ module Tilt
194
245
  # This method is only used by source generating templates. Subclasses that
195
246
  # override render() may not support all features.
196
247
  def evaluate(scope, locals, &block)
197
- locals_keys = locals.keys
198
- locals_keys.sort!{|x, y| x.to_s <=> y.to_s}
199
-
200
- case scope
201
- when Object
202
- scope_class = Module === scope ? scope : scope.class
248
+ if @fixed_locals
249
+ locals_keys = EMPTY_ARRAY
203
250
  else
204
- # :nocov:
205
- scope_class = USE_BIND_CALL ? CLASS_METHOD.bind_call(scope) : CLASS_METHOD.bind(scope).call
206
- # :nocov:
251
+ locals_keys = locals.keys
252
+ locals_keys.sort!{|x, y| x.to_s <=> y.to_s}
207
253
  end
208
- method = compiled_method(locals_keys, scope_class)
209
254
 
210
- if USE_BIND_CALL
211
- method.bind_call(scope, locals, &block)
212
- # :nocov:
213
- else
214
- method.bind(scope).call(locals, &block)
215
- # :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
216
264
  end
265
+
266
+ evaluate_method(compiled_method(locals_keys, scope_class), scope, locals, &block)
217
267
  end
218
268
 
219
269
  # Generates all template source by combining the preamble, template, and
@@ -271,6 +321,18 @@ module Tilt
271
321
 
272
322
  private
273
323
 
324
+ if RUBY_VERSION >= '2.3'
325
+ def _dup_string_if_frozen(string)
326
+ +string
327
+ end
328
+ # :nocov:
329
+ else
330
+ def _dup_string_if_frozen(string)
331
+ string.frozen? ? string.dup : string
332
+ end
333
+ end
334
+ # :nocov:
335
+
274
336
  def process_arg(arg)
275
337
  if arg
276
338
  case
@@ -295,7 +357,12 @@ module Tilt
295
357
  end
296
358
 
297
359
  def set_compiled_method_cache
298
- @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
299
366
  end
300
367
 
301
368
  def local_extraction(local_keys)
@@ -319,9 +386,39 @@ module Tilt
319
386
  assignments.join("\n")
320
387
  end
321
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
+
322
414
  def compile_template_method(local_keys, scope_class=nil)
323
415
  source, offset = precompiled(local_keys)
324
- 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
325
422
 
326
423
  method_name = "__tilt_#{Thread.current.object_id.abs}"
327
424
  method_source = String.new
@@ -332,7 +429,7 @@ module Tilt
332
429
  end
333
430
 
334
431
  # Don't indent method source, to avoid indentation warnings when using compiled paths
335
- 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"
336
433
 
337
434
  offset += method_source.count("\n")
338
435
  method_source << source
@@ -355,7 +452,11 @@ module Tilt
355
452
  path << ".rb"
356
453
 
357
454
  # Wrap method source in a class block for the scope, so constant lookup works
358
- method_source = "class #{scope_class.name}\n#{method_source}\nend"
455
+ if freeze_string_literals?
456
+ method_source_prefix = "# frozen-string-literal: true\n"
457
+ method_source = method_source.sub(/\A# frozen-string-literal: true\n/, '')
458
+ end
459
+ method_source = "#{method_source_prefix}class #{scope_class.name}\n#{method_source}\nend"
359
460
 
360
461
  load_compiled_method(path, method_source)
361
462
  else
@@ -372,7 +473,12 @@ module Tilt
372
473
  end
373
474
 
374
475
  def load_compiled_method(path, method_source)
375
- File.binwrite(path, method_source)
476
+ # Write to a temporary path specific to the current process, and
477
+ # rename after writing. This prevents issues during parallel
478
+ # coverage testing.
479
+ tmp_path = "#{path}-#{$$}"
480
+ File.binwrite(tmp_path, method_source)
481
+ File.rename(tmp_path, path)
376
482
 
377
483
  # Use load and not require, so unbind_compiled_method does not
378
484
  # break if the same path is used more than once.
@@ -385,13 +491,49 @@ module Tilt
385
491
  method
386
492
  end
387
493
 
494
+ # Set the fixed locals for the template, which may be nil if no fixed locals can
495
+ # be determined.
496
+ def set_fixed_locals
497
+ fixed_locals = @options.delete(:fixed_locals)
498
+ extract_fixed_locals = @options.delete(:extract_fixed_locals)
499
+ default_fixed_locals = @options.delete(:default_fixed_locals)
500
+
501
+ if fixed_locals.nil?
502
+ if extract_fixed_locals.nil?
503
+ extract_fixed_locals = Tilt.extract_fixed_locals
504
+ end
505
+
506
+ if extract_fixed_locals
507
+ fixed_locals = extract_fixed_locals()
508
+ end
509
+
510
+ if fixed_locals.nil?
511
+ fixed_locals = default_fixed_locals
512
+ end
513
+ end
514
+
515
+ @fixed_locals = fixed_locals
516
+ end
517
+
518
+ # Extract fixed locals from the template code string. Should return nil
519
+ # if there are no fixed locals specified, or a method argument string
520
+ # surrounded by parentheses if there are fixed locals. The method
521
+ # argument string will be used when defining the template method if given.
522
+ def extract_fixed_locals
523
+ if @data.is_a?(String) && (match = /\#\s*locals:\s*(\(.*\))/.match(@data))
524
+ match[1]
525
+ end
526
+ end
527
+
388
528
  def extract_encoding(script, &block)
389
529
  extract_magic_comment(script, &block) || script.encoding
390
530
  end
391
531
 
392
532
  def extract_magic_comment(script)
393
- if script.frozen?
394
- script = script.dup
533
+ was_frozen = script.frozen?
534
+ script = _dup_string_if_frozen(script)
535
+
536
+ if was_frozen
395
537
  yield script
396
538
  end
397
539
 
@@ -413,6 +555,16 @@ module Tilt
413
555
  end
414
556
  end
415
557
 
558
+ # Static templates are templates that return the same output for every render
559
+ #
560
+ # Instead of inheriting from the StaticTemplate class, you will use the .subclass
561
+ # method with a block which processes @data and returns the transformed value.
562
+ #
563
+ # Basic example which transforms the template to uppercase:
564
+ #
565
+ # UppercaseTemplate = Tilt::StaticTemplate.subclass do
566
+ # @data.upcase
567
+ # end
416
568
  class StaticTemplate < Template
417
569
  def self.subclass(mime_type: 'text/html', &block)
418
570
  Class.new(self) do
@@ -451,5 +603,9 @@ module Tilt
451
603
  # Do nothing, since compiled method cache is not used.
452
604
  def set_compiled_method_cache
453
605
  end
606
+
607
+ # Do nothing, since fixed locals are not used.
608
+ def set_fixed_locals
609
+ end
454
610
  end
455
611
  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.2.0'
8
+ VERSION = '2.6.1'
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
@@ -18,6 +22,8 @@ module Tilt
18
22
  # is called, all attempts to modify the default mapping will fail.
19
23
  # This also freezes Tilt itself.
20
24
  def self.finalize!
25
+ return self if @default_mapping.is_a?(FinalizedMapping)
26
+
21
27
  class << self
22
28
  prepend(Module.new do
23
29
  def lazy_map(*)
@@ -80,23 +86,14 @@ module Tilt
80
86
  @default_mapping.templates_for(file)
81
87
  end
82
88
 
83
- # @return the template object that is currently rendering.
84
- #
85
- # @example
86
- # tmpl = Tilt['index.erb'].new { '<%= Tilt.current_template %>' }
87
- # tmpl.render == tmpl.to_s
88
- #
89
- # @note This is currently an experimental feature and might return nil
90
- # in the future.
91
- def self.current_template
92
- warn "Tilt.current_template is deprecated and will be removed in Tilt 2.3", uplevel: 1
93
- Thread.current[:tilt_current_template]
94
- end
95
-
96
89
  class << self
97
90
  # @return [Tilt::Mapping] the main mapping object
98
91
  attr_reader :default_mapping
99
92
 
93
+ # Whether to extract fixed locals from templates by scanning the
94
+ # template content.
95
+ attr_accessor :extract_fixed_locals
96
+
100
97
  # Alias register as prefer for Tilt 1.x compatibility.
101
98
  alias prefer register
102
99
  end
@@ -150,11 +147,9 @@ module Tilt
150
147
 
151
148
  # ERB
152
149
  register_lazy :ERBTemplate, 'tilt/erb', 'erb', 'rhtml'
153
- register_lazy :ErubisTemplate, 'tilt/erubis', 'erb', 'rhtml', 'erubis'
154
150
  register_lazy :ErubiTemplate, 'tilt/erubi', 'erb', 'rhtml', 'erubi'
155
151
 
156
152
  # Markdown
157
- register_lazy :MarukuTemplate, 'tilt/maruku', 'markdown', 'mkd', 'md'
158
153
  register_lazy :KramdownTemplate, 'tilt/kramdown', 'markdown', 'mkd', 'md'
159
154
  register_lazy :RDiscountTemplate, 'tilt/rdiscount', 'markdown', 'mkd', 'md'
160
155
  register_lazy :RedcarpetTemplate, 'tilt/redcarpet', 'markdown', 'mkd', 'md'
@@ -186,7 +181,6 @@ module Tilt
186
181
  register_lazy :SlimTemplate, 'tilt/slim', 'slim'
187
182
  register_lazy :StringTemplate, 'tilt/string', 'str'
188
183
  register_lazy :TypeScriptTemplate, 'tilt/typescript', 'ts', 'tsx'
189
- register_lazy :WikiClothTemplate, 'tilt/wikicloth', 'wiki', 'mediawiki', 'mw'
190
184
  register_lazy :YajlTemplate, 'tilt/yajl', 'yajl'
191
185
 
192
186
  # TILT3: Remove
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.2.0
4
+ version: 2.6.1
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: 2023-06-05 00:00:00.000000000 Z
12
+ date: 1980-01-02 00:00:00.000000000 Z
14
13
  dependencies: []
15
14
  description: Generic interface to multiple Ruby template engines
16
15
  email: code@jeremyevans.net
@@ -36,7 +35,6 @@ files:
36
35
  - lib/tilt/csv.rb
37
36
  - lib/tilt/erb.rb
38
37
  - lib/tilt/erubi.rb
39
- - lib/tilt/erubis.rb
40
38
  - lib/tilt/etanni.rb
41
39
  - lib/tilt/haml.rb
42
40
  - lib/tilt/kramdown.rb
@@ -44,7 +42,6 @@ files:
44
42
  - lib/tilt/livescript.rb
45
43
  - lib/tilt/mapping.rb
46
44
  - lib/tilt/markaby.rb
47
- - lib/tilt/maruku.rb
48
45
  - lib/tilt/nokogiri.rb
49
46
  - lib/tilt/pandoc.rb
50
47
  - lib/tilt/pipeline.rb
@@ -61,7 +58,6 @@ files:
61
58
  - lib/tilt/string.rb
62
59
  - lib/tilt/template.rb
63
60
  - lib/tilt/typescript.rb
64
- - lib/tilt/wikicloth.rb
65
61
  - lib/tilt/yajl.rb
66
62
  homepage: https://github.com/jeremyevans/tilt
67
63
  licenses:
@@ -71,7 +67,6 @@ metadata:
71
67
  changelog_uri: https://github.com/jeremyevans/tilt/blob/master/CHANGELOG.md
72
68
  mailing_list_uri: https://github.com/jeremyevans/tilt/discussions
73
69
  source_code_uri: https://github.com/jeremyevans/tilt
74
- post_install_message:
75
70
  rdoc_options:
76
71
  - "--line-numbers"
77
72
  - "--inline-source"
@@ -92,8 +87,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
92
87
  - !ruby/object:Gem::Version
93
88
  version: '0'
94
89
  requirements: []
95
- rubygems_version: 3.4.10
96
- signing_key:
90
+ rubygems_version: 3.6.7
97
91
  specification_version: 4
98
92
  summary: Generic interface to multiple Ruby template engines
99
93
  test_files: []
data/lib/tilt/erubis.rb DELETED
@@ -1,52 +0,0 @@
1
- # frozen_string_literal: true
2
- require_relative 'erb'
3
- require 'erubis'
4
-
5
- module Tilt
6
- # Erubis template implementation. See:
7
- # http://www.kuwata-lab.com/erubis/
8
- #
9
- # ErubisTemplate supports the following additional options, which are not
10
- # passed down to the Erubis engine:
11
- #
12
- # :engine_class allows you to specify a custom engine class to use
13
- # instead of the default (which is ::Erubis::Eruby).
14
- #
15
- # :escape_html when true, ::Erubis::EscapedEruby will be used as
16
- # the engine class instead of the default. All content
17
- # within <%= %> blocks will be automatically html escaped.
18
- class ErubisTemplate < ERBTemplate
19
- # Remove in Tilt 2.3
20
- @default_output_variable = nil
21
-
22
- def prepare
23
- @freeze_string_literals = !!@options.delete(:freeze)
24
- @outvar = @options.delete(:outvar) || self.class._default_output_variable || '_erbout'
25
- @options[:preamble] = false
26
- @options[:postamble] = false
27
- @options[:bufvar] = @outvar
28
- engine_class = @options.delete(:engine_class)
29
- engine_class = ::Erubis::EscapedEruby if @options.delete(:escape_html)
30
- @engine = (engine_class || ::Erubis::Eruby).new(@data, @options)
31
- end
32
-
33
- def precompiled_preamble(locals)
34
- [super, "#{@outvar} = _buf = String.new"].join("\n")
35
- end
36
-
37
- def precompiled_postamble(locals)
38
- [@outvar, super].join("\n")
39
- end
40
-
41
- # Erubis doesn't have ERB's line-off-by-one under 1.9 problem.
42
- # Override and adjust back.
43
- def precompiled(locals)
44
- source, offset = super
45
- [source, offset - 1]
46
- end
47
-
48
- def freeze_string_literals?
49
- @freeze_string_literals
50
- end
51
- end
52
- end
data/lib/tilt/maruku.rb DELETED
@@ -1,8 +0,0 @@
1
- # frozen_string_literal: true
2
- require_relative 'template'
3
- require 'maruku'
4
-
5
- # Maruku markdown implementation. See: https://github.com/bhollis/maruku
6
- Tilt::MarukuTemplate = Tilt::StaticTemplate.subclass do
7
- Maruku.new(@data, @options).to_html
8
- end
@@ -1,10 +0,0 @@
1
- # frozen_string_literal: true
2
- require_relative 'template'
3
- require 'wikicloth'
4
-
5
- # WikiCloth implementation. See: https://github.com/nricciar/wikicloth
6
- Tilt::WikiClothTemplate = Tilt::StaticTemplate.subclass do
7
- parser = @options.delete(:parser) || WikiCloth::Parser
8
- @options[:data] = @data
9
- parser.new(@options).to_html
10
- end