haml 7.4.1 → 7.5.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: 4dced0d7329423afd97a56b1ce6b32f4c332a9f4e725aed6a41f4e5d7c10bfd7
4
- data.tar.gz: 985f140fb9f9ae590c0e37ae7d5f06632c5c1f4a522578639e2a98527fb85e20
3
+ metadata.gz: 8cf8d7cf95a5096090897276b03dd8073e73705fa1b880bba96af5dceb3b2c55
4
+ data.tar.gz: 4d1e1ff1bd53361d0a31c78533a838e60e52d10c5646ff0d8bbd87a552ccc658
5
5
  SHA512:
6
- metadata.gz: ba4cc15a925752648e293fd712e024c92da5d0e1d827e28719e871e5ffa7a647fc928c46650f7a2c92bf3ad8c67e70f821fd1710de346affb528639f34652af1
7
- data.tar.gz: 062d2e3a5b523a5450179790f20627920e9086065b13f15591b4472178a3e7ec4672caa299466a428b343a21b5fd7eb85c0549f032b22ba5854aacf1510ad576
6
+ metadata.gz: 3bbfe67377d06702fa3240048fd25410f885f05a503d4e8e7793f0ccbba9ffb99e601d46068150d2170c11a3807660571fe26f337becfc155758f05cc470bc40
7
+ data.tar.gz: '01159a17fda467397309cfa38de5ad7b1e8820d506447b87221a8cdc087f02e8546cb1d2ad9a358d4ad0fa0c0b29c60b0a03bcf692e2fa551d748111701d8adc'
data/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # Haml Changelog
2
2
 
3
+ ## 7.5.1
4
+
5
+ * Improve frozen strings management https://github.com/haml/haml/pull/1205
6
+
7
+ ## 7.5.0
8
+
9
+ * Compile a multi-line attribute hash statically https://github.com/haml/haml/pull/1222
10
+ * Errors from multi-line attributes will be reported on the tag's line instead of the expression that raised the error.
11
+
3
12
  ## 7.4.1
4
13
 
5
14
  * Build the preserve regex once per tag list instead of per call https://github.com/haml/haml/pull/1220
@@ -3,6 +3,7 @@ require 'set'
3
3
  require 'haml/attribute_builder'
4
4
  require 'haml/attribute_parser'
5
5
  require 'haml/ruby_expression'
6
+ require 'haml/temple_line_counter'
6
7
 
7
8
  module Haml
8
9
  # The set of boolean attributes. You may add custom attributes to this constant.
@@ -24,12 +25,15 @@ module Haml
24
25
  def compile(node)
25
26
  hashes = []
26
27
  return runtime_compile(node) if node.value[:object_ref] != :nil
27
- [node.value[:dynamic_attributes].new, node.value[:dynamic_attributes].old].compact.each do |attribute_str|
28
+ dynamic_attributes = node.value[:dynamic_attributes]
29
+ [dynamic_attributes.new, dynamic_attributes.old].compact.each do |attribute_str|
28
30
  hash = AttributeParser.parse(attribute_str)
29
31
  return runtime_compile(node) if hash.nil? || hash.any? { |_key, value| value.empty? }
30
32
  hashes << hash
31
33
  end
32
- static_compile(node.value[:attributes], hashes)
34
+ temple = static_compile(node.value[:attributes], hashes)
35
+ restore_newlines!(temple, dynamic_attributes)
36
+ temple
33
37
  end
34
38
 
35
39
  private
@@ -67,6 +71,13 @@ module Haml
67
71
  temple
68
72
  end
69
73
 
74
+ # ChildrenCompiler counts on the tag spanning as many lines as its attribute source does.
75
+ def restore_newlines!(temple, dynamic_attributes)
76
+ missing = dynamic_attributes.newline_count
77
+ missing -= TempleLineCounter.count_lines(temple) if missing > 0
78
+ missing.times { temple << [:newline] }
79
+ end
80
+
70
81
  def compile_id!(temple, key, values)
71
82
  build_code = attribute_builder(:id, values)
72
83
  if values.all? { |type, exp| type == :static || Temple::StaticAnalyzer.static?(exp) }
@@ -15,15 +15,11 @@ module Haml
15
15
  end
16
16
 
17
17
  # @return [Hash,nil] - keys and values are the attribute source as written, or nil if
18
- # the text is not a Hash literal whose keys are all static.
18
+ # the text is not a Hash literal whose keys are all static, or if it holds a heredoc.
19
19
  def parse(text)
20
20
  exp = wrap_bracket(text)
21
- # A multi-line hash is left to the runtime, which keeps the [:newline] bookkeeping of
22
- # the compiled code correct. Compiling it statically is a separate optimization.
23
- return if exp.include?("\n")
24
-
25
21
  node = hash_node(exp)
26
- return if node.nil?
22
+ return if node.nil? || contains_heredoc?(exp, node)
27
23
 
28
24
  hash = {}
29
25
  node.elements.each do |element|
@@ -58,6 +54,12 @@ module Haml
58
54
  node if node.is_a?(Prism::HashNode)
59
55
  end
60
56
 
57
+ # A heredoc's body lies outside its node, so the value's slice would not be the value.
58
+ # Its opener always spells `<<`, which spares the tree walk for nearly every hash.
59
+ def contains_heredoc?(exp, node)
60
+ exp.include?('<<') && !node.breadth_first_search { |n| n.respond_to?(:heredoc?) && n.heredoc? }.nil?
61
+ end
62
+
61
63
  # The key as written between its delimiters, not unescaped: an escape has to reach the
62
64
  # attribute name as the source spelled it, like the `\0` of `{ "a\0b" => 1 }`.
63
65
  def static_key(key)
@@ -40,9 +40,7 @@ module Haml
40
40
  when :script, :silent_script
41
41
  @lineno += 1
42
42
  when :tag
43
- [node.value[:dynamic_attributes].new, node.value[:dynamic_attributes].old].compact.each do |attribute_hash|
44
- @lineno += attribute_hash.count("\n")
45
- end
43
+ @lineno += node.value[:dynamic_attributes].newline_count
46
44
  @lineno += 1 if node.children.empty? && node.value[:parse]
47
45
  end
48
46
 
@@ -36,7 +36,7 @@ module Haml
36
36
  return exps
37
37
  end
38
38
 
39
- strlit_body = String.new
39
+ strlit_body = +''
40
40
  exps.each do |type, arg|
41
41
  case type
42
42
  when :static
data/lib/haml/engine.rb CHANGED
@@ -53,7 +53,7 @@ module Haml
53
53
  end
54
54
 
55
55
  def precompiled_with_ambles(_local_names, after_preamble:)
56
- "#{after_preamble.tr("\n", ';')}#{@precompiled}".dup
56
+ "#{after_preamble.tr("\n", ';')}#{@precompiled}"
57
57
  end
58
58
  end
59
59
  end
data/lib/haml/parser.rb CHANGED
@@ -227,7 +227,7 @@ module Haml
227
227
  end
228
228
 
229
229
  def inspect
230
- %Q[(#{type} #{value.inspect}#{children.each_with_object(''.dup) {|c, s| s << "\n#{c.inspect.gsub!(/^/, ' ')}"}})].dup
230
+ %Q[(#{type} #{value.inspect}#{children.each_with_object(+'') {|c, s| s << "\n#{c.inspect.gsub!(/^/, ' ')}"}})]
231
231
  end
232
232
  end
233
233
 
@@ -247,6 +247,12 @@ module Haml
247
247
  [new, stripped_old].compact.join(', ')
248
248
  end
249
249
 
250
+ # The lines a tag spans beyond its first because of these attributes, which is what
251
+ # the compiled tag has to span too for the line numbers after it to hold.
252
+ def newline_count
253
+ (new ? new.count("\n") : 0) + (old ? old.count("\n") : 0)
254
+ end
255
+
250
256
  private
251
257
 
252
258
  # For `%foo{ { foo: 1 }, bar: 2 }`, :old is "{ { foo: 1 }, bar: 2 }" and this method returns " { foo: 1 }, bar: 2 " for last argument.
@@ -397,7 +403,7 @@ module Haml
397
403
  def haml_comment(text)
398
404
  if filter_opened?
399
405
  @flat = true
400
- @filter_buffer = String.new
406
+ @filter_buffer = +''
401
407
  @filter_buffer << "#{text}\n" unless text.empty?
402
408
  text = @filter_buffer
403
409
  # If we don't know the indentation by now, it'll be set in Line#tabs
@@ -533,7 +539,7 @@ module Haml
533
539
 
534
540
  if filter_opened?
535
541
  @flat = true
536
- @filter_buffer = String.new
542
+ @filter_buffer = +''
537
543
  # If we don't know the indentation by now, it'll be set in Line#tabs
538
544
  @flat_spaces = @indentation * (@template_tabs+1) if @indentation
539
545
  end
@@ -743,7 +749,7 @@ module Haml
743
749
  end
744
750
 
745
751
  static_attributes = {}
746
- dynamic_attributes = "{".dup
752
+ dynamic_attributes = +"{"
747
753
  attributes.each do |name, (type, val)|
748
754
  if type == :static
749
755
  static_attributes[name] = val
@@ -783,7 +789,7 @@ module Haml
783
789
 
784
790
  return name, [:static, content.first[1]] if content.size == 1
785
791
  return name, [:dynamic,
786
- %!"#{content.each_with_object(''.dup) {|(t, v), s| s << (t == :str ? Util.inspect_obj(v)[1...-1] : "\#{#{v}}")}}"!]
792
+ %!"#{content.each_with_object(+'') {|(t, v), s| s << (t == :str ? Util.inspect_obj(v)[1...-1] : "\#{#{v}}")}}"!]
787
793
  end
788
794
 
789
795
  def next_line
data/lib/haml/template.rb CHANGED
@@ -16,5 +16,5 @@ module Haml
16
16
  "extend Haml::Helpers; #{super}"
17
17
  end
18
18
  end
19
- Template.send(:extend, TemplateExtension)
19
+ Template.extend TemplateExtension
20
20
  end
@@ -19,13 +19,27 @@ module Haml
19
19
  arg.count("\n") + cases.map do |cond, e|
20
20
  (cond == :else ? 0 : cond.count("\n")) + count_lines(e)
21
21
  end.reduce(:+)
22
- when :escape
22
+ when :escape, :fescape
23
23
  count_lines(args[1])
24
+ when :html
25
+ count_html_lines(args)
24
26
  when :newline
25
27
  1
26
28
  else
27
29
  raise UnexpectedExpression.new("[HAML BUG] Unexpected Temple expression '#{type}' is given!")
28
30
  end
29
31
  end
32
+
33
+ def self.count_html_lines(args)
34
+ case args[0]
35
+ when :attrs
36
+ args.drop(1).sum { |a| count_lines(a) }
37
+ when :attr
38
+ count_lines(args[2])
39
+ else
40
+ raise UnexpectedExpression.new("[HAML BUG] Unexpected Temple expression 'html #{args[0]}' is given!")
41
+ end
42
+ end
43
+ private_class_method :count_html_lines
30
44
  end
31
45
  end
data/lib/haml/util.rb CHANGED
@@ -5,7 +5,6 @@ begin
5
5
  rescue LoadError
6
6
  require 'erb'
7
7
  end
8
- require 'set'
9
8
  require 'stringio'
10
9
  require 'strscan'
11
10
 
@@ -169,7 +168,7 @@ MSG
169
168
  # and the rest of the string.
170
169
  # `["Foo (Bar (Baz bang) bop)", " (Bang (bop bip))"]` in the example above.
171
170
  def balance(scanner, start, finish, count = 0)
172
- str = ''.dup
171
+ str = +''
173
172
  scanner = StringScanner.new(scanner) unless scanner.is_a? StringScanner
174
173
  regexp = Regexp.new("(.*?)[\\#{start.chr}\\#{finish.chr}]", Regexp::MULTILINE)
175
174
  while scanner.scan(regexp)
@@ -202,7 +201,7 @@ MSG
202
201
  end
203
202
 
204
203
  def unescape_interpolation(str)
205
- res = ''.dup
204
+ res = +''
206
205
  rest = Haml::Util.handle_interpolation str.dump do |scan|
207
206
  escapes = (scan[2].size - 1) / 2
208
207
  char = scan[3] # '{', '@' or '$'
data/lib/haml/version.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module Haml
3
- VERSION = '7.4.1'
3
+ VERSION = '7.5.1'
4
4
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: haml
3
3
  version: !ruby/object:Gem::Version
4
- version: 7.4.1
4
+ version: 7.5.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Natalie Weizenbaum