haml 5.2.2 → 6.1.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.
Files changed (98) hide show
  1. checksums.yaml +4 -4
  2. data/.github/FUNDING.yml +3 -0
  3. data/.github/workflows/test.yml +13 -14
  4. data/.gitignore +16 -16
  5. data/.yardopts +0 -3
  6. data/CHANGELOG.md +116 -3
  7. data/Gemfile +18 -11
  8. data/MIT-LICENSE +1 -1
  9. data/README.md +17 -23
  10. data/REFERENCE.md +69 -145
  11. data/Rakefile +48 -81
  12. data/bin/bench +66 -0
  13. data/bin/console +11 -0
  14. data/bin/ruby +3 -0
  15. data/bin/setup +7 -0
  16. data/bin/stackprof +27 -0
  17. data/bin/test +24 -0
  18. data/exe/haml +6 -0
  19. data/ext/haml/extconf.rb +10 -0
  20. data/ext/haml/haml.c +537 -0
  21. data/ext/haml/hescape.c +108 -0
  22. data/ext/haml/hescape.h +20 -0
  23. data/haml.gemspec +39 -37
  24. data/lib/haml/ambles.rb +20 -0
  25. data/lib/haml/attribute_builder.rb +134 -179
  26. data/lib/haml/attribute_compiler.rb +85 -194
  27. data/lib/haml/attribute_parser.rb +92 -126
  28. data/lib/haml/cli.rb +154 -0
  29. data/lib/haml/compiler/children_compiler.rb +155 -0
  30. data/lib/haml/compiler/comment_compiler.rb +51 -0
  31. data/lib/haml/compiler/doctype_compiler.rb +46 -0
  32. data/lib/haml/compiler/script_compiler.rb +114 -0
  33. data/lib/haml/compiler/silent_script_compiler.rb +24 -0
  34. data/lib/haml/compiler/tag_compiler.rb +76 -0
  35. data/lib/haml/compiler.rb +63 -296
  36. data/lib/haml/dynamic_merger.rb +67 -0
  37. data/lib/haml/engine.rb +48 -227
  38. data/lib/haml/error.rb +5 -4
  39. data/lib/haml/escape.rb +13 -0
  40. data/lib/haml/escape_any.rb +21 -0
  41. data/lib/haml/filters/base.rb +12 -0
  42. data/lib/haml/filters/cdata.rb +20 -0
  43. data/lib/haml/filters/coffee.rb +17 -0
  44. data/lib/haml/filters/css.rb +33 -0
  45. data/lib/haml/filters/erb.rb +10 -0
  46. data/lib/haml/filters/escaped.rb +22 -0
  47. data/lib/haml/filters/javascript.rb +33 -0
  48. data/lib/haml/filters/less.rb +20 -0
  49. data/lib/haml/filters/markdown.rb +11 -0
  50. data/lib/haml/filters/plain.rb +29 -0
  51. data/lib/haml/filters/preserve.rb +22 -0
  52. data/lib/haml/filters/ruby.rb +10 -0
  53. data/lib/haml/filters/sass.rb +15 -0
  54. data/lib/haml/filters/scss.rb +15 -0
  55. data/lib/haml/filters/text_base.rb +25 -0
  56. data/lib/haml/filters/tilt_base.rb +59 -0
  57. data/lib/haml/filters.rb +54 -378
  58. data/lib/haml/force_escape.rb +29 -0
  59. data/lib/haml/helpers.rb +3 -697
  60. data/lib/haml/html.rb +22 -0
  61. data/lib/haml/identity.rb +13 -0
  62. data/lib/haml/object_ref.rb +35 -0
  63. data/lib/haml/parser.rb +157 -22
  64. data/lib/haml/rails_helpers.rb +53 -0
  65. data/lib/haml/rails_template.rb +57 -0
  66. data/lib/haml/railtie.rb +3 -46
  67. data/lib/haml/ruby_expression.rb +32 -0
  68. data/lib/haml/string_splitter.rb +140 -0
  69. data/lib/haml/template.rb +15 -34
  70. data/lib/haml/temple_line_counter.rb +2 -1
  71. data/lib/haml/util.rb +18 -15
  72. data/lib/haml/version.rb +1 -2
  73. data/lib/haml/whitespace.rb +8 -0
  74. data/lib/haml.rb +8 -20
  75. metadata +211 -55
  76. data/.gitmodules +0 -3
  77. data/TODO +0 -24
  78. data/benchmark.rb +0 -70
  79. data/bin/haml +0 -9
  80. data/lib/haml/.gitattributes +0 -1
  81. data/lib/haml/buffer.rb +0 -182
  82. data/lib/haml/escapable.rb +0 -77
  83. data/lib/haml/exec.rb +0 -347
  84. data/lib/haml/generator.rb +0 -42
  85. data/lib/haml/helpers/action_view_extensions.rb +0 -60
  86. data/lib/haml/helpers/action_view_mods.rb +0 -132
  87. data/lib/haml/helpers/action_view_xss_mods.rb +0 -60
  88. data/lib/haml/helpers/safe_erubi_template.rb +0 -20
  89. data/lib/haml/helpers/safe_erubis_template.rb +0 -33
  90. data/lib/haml/helpers/xss_mods.rb +0 -114
  91. data/lib/haml/options.rb +0 -273
  92. data/lib/haml/plugin.rb +0 -54
  93. data/lib/haml/sass_rails_filter.rb +0 -47
  94. data/lib/haml/template/options.rb +0 -27
  95. data/lib/haml/temple_engine.rb +0 -124
  96. data/yard/default/.gitignore +0 -1
  97. data/yard/default/fulldoc/html/css/common.sass +0 -15
  98. data/yard/default/layout/html/footer.erb +0 -12
data/lib/haml/html.rb ADDED
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+ module Haml
3
+ class HTML < Temple::HTML::Fast
4
+ DEPRECATED_FORMATS = %i[html4 html5].freeze
5
+
6
+ def initialize(opts = {})
7
+ if DEPRECATED_FORMATS.include?(opts[:format])
8
+ opts = opts.dup
9
+ opts[:format] = :html
10
+ end
11
+ super(opts)
12
+ end
13
+
14
+ # This dispatcher supports Haml's "revealed" conditional comment.
15
+ def on_html_condcomment(condition, content, revealed = false)
16
+ on_html_comment [:multi,
17
+ [:static, "[#{condition}]>#{'<!-->' if revealed}"],
18
+ content,
19
+ [:static, "#{'<!--' if revealed}<![endif]"]]
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+ module Haml
3
+ class Identity
4
+ def initialize
5
+ @unique_id = 0
6
+ end
7
+
8
+ def generate
9
+ @unique_id += 1
10
+ "_haml_compiler#{@unique_id}"
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+ module Haml
3
+ module ObjectRef
4
+ class << self
5
+ def parse(args)
6
+ object, prefix = args
7
+ return {} unless object
8
+
9
+ suffix =
10
+ if object.respond_to?(:haml_object_ref)
11
+ object.haml_object_ref
12
+ else
13
+ underscore(object.class)
14
+ end
15
+ {
16
+ 'class' => [prefix, suffix].compact.join('_'),
17
+ 'id' => [prefix, suffix, object.id || 'new'].compact.join('_'),
18
+ }
19
+ end
20
+
21
+ private
22
+
23
+ # Haml::Buffer.underscore
24
+ def underscore(camel_cased_word)
25
+ word = camel_cased_word.to_s.dup
26
+ word.gsub!(/::/, '_')
27
+ word.gsub!(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
28
+ word.gsub!(/([a-z\d])([A-Z])/, '\1_\2')
29
+ word.tr!('-', '_')
30
+ word.downcase!
31
+ word
32
+ end
33
+ end
34
+ end
35
+ end
data/lib/haml/parser.rb CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  require 'ripper'
4
4
  require 'strscan'
5
+ require 'haml/error'
6
+ require 'haml/util'
5
7
 
6
8
  module Haml
7
9
  class Parser
@@ -95,15 +97,23 @@ module Haml
95
97
  METHOD_CALL_PREFIX = 'a('
96
98
 
97
99
  def initialize(options)
98
- @options = Options.wrap(options)
100
+ @options = ParserOptions.new(options)
99
101
  # Record the indent levels of "if" statements to validate the subsequent
100
102
  # elsif and else statements are indented at the appropriate level.
101
103
  @script_level_stack = []
102
104
  @template_index = 0
103
105
  @template_tabs = 0
106
+ # When used in Haml::Engine, which gives options[:generator] to every filter
107
+ # in the engine, including Haml::Parser, we don't want to throw exceptions.
108
+ # However, when Haml::Parser is used as a library, we want to throw exceptions.
109
+ @raise_error = !options.key?(:generator)
104
110
  end
105
111
 
106
112
  def call(template)
113
+ template = Haml::Util.check_haml_encoding(template) do |msg, line|
114
+ raise Haml::Error.new(msg, line)
115
+ end
116
+
107
117
  match = template.rstrip.scan(/(([ \t]+)?(.*?))(?:\Z|\r\n|\r|\n)/m)
108
118
  # discard the last match which is always blank
109
119
  match.pop
@@ -152,7 +162,8 @@ module Haml
152
162
  @root
153
163
  rescue Haml::Error => e
154
164
  e.backtrace.unshift "#{@options.filename}:#{(e.line ? e.line + 1 : @line.index + 1) + @options.line - 1}"
155
- raise
165
+ raise if @raise_error
166
+ error_with_lineno(e)
156
167
  end
157
168
 
158
169
  def compute_tabs(line)
@@ -182,6 +193,16 @@ module Haml
182
193
 
183
194
  private
184
195
 
196
+ def error_with_lineno(error)
197
+ return error if error.line
198
+
199
+ trace = error.backtrace.first
200
+ return error unless trace
201
+
202
+ line = trace.match(/\d+\z/).to_s.to_i
203
+ SyntaxError.new(error.message, line)
204
+ end
205
+
185
206
  # @private
186
207
  Line = Struct.new(:whitespace, :text, :full, :index, :parser, :eod) do
187
208
  alias_method :eod?, :eod
@@ -221,7 +242,7 @@ module Haml
221
242
  self[:old] = value
222
243
  end
223
244
 
224
- # This will be a literal for Haml::Buffer#attributes's last argument, `attributes_hashes`.
245
+ # This will be a literal for Haml::HamlBuffer#attributes's last argument, `attributes_hashes`.
225
246
  def to_literal
226
247
  [new, stripped_old].compact.join(', ')
227
248
  end
@@ -307,13 +328,13 @@ module Haml
307
328
  raise SyntaxError.new(Error.message(:illegal_nesting_plain), @next_line.index)
308
329
  end
309
330
 
310
- unless contains_interpolation?(line.text)
331
+ unless Util.contains_interpolation?(line.text)
311
332
  return ParseNode.new(:plain, line.index + 1, :text => line.text)
312
333
  end
313
334
 
314
335
  escape_html = @options.escape_html && @options.mime_type != 'text/plain' if escape_html.nil?
315
- line.text = unescape_interpolation(line.text, escape_html)
316
- script(line, false)
336
+ line.text = Util.unescape_interpolation(line.text)
337
+ script(line, false).tap { |n| n.value[:escape_interpolation] = true if escape_html }
317
338
  end
318
339
 
319
340
  def script(line, escape_html = nil, preserve = false)
@@ -400,7 +421,8 @@ module Haml
400
421
  when '='
401
422
  parse = true
402
423
  if value[0] == ?=
403
- value = unescape_interpolation(value[1..-1].strip, escape_html)
424
+ value = Util.unescape_interpolation(value[1..-1].strip)
425
+ escape_interpolation = true if escape_html
404
426
  escape_html = false
405
427
  end
406
428
  when '&', '!'
@@ -408,19 +430,21 @@ module Haml
408
430
  parse = true
409
431
  preserve_script = (value[0] == ?~)
410
432
  if value[1] == ?=
411
- value = unescape_interpolation(value[2..-1].strip, escape_html)
433
+ value = Util.unescape_interpolation(value[2..-1].strip)
434
+ escape_interpolation = true if escape_html
412
435
  escape_html = false
413
436
  else
414
437
  value = value[1..-1].strip
415
438
  end
416
- elsif contains_interpolation?(value)
417
- value = unescape_interpolation(value, escape_html)
439
+ elsif Util.contains_interpolation?(value)
440
+ value = Util.unescape_interpolation(value)
441
+ escape_interpolation = true if escape_html
418
442
  parse = true
419
443
  escape_html = false
420
444
  end
421
445
  else
422
- if contains_interpolation?(value)
423
- value = unescape_interpolation(value, escape_html)
446
+ if Util.contains_interpolation?(value)
447
+ value = Util.unescape_interpolation(value, escape_html)
424
448
  parse = true
425
449
  escape_html = false
426
450
  end
@@ -431,13 +455,13 @@ module Haml
431
455
 
432
456
  if attributes_hashes[:new]
433
457
  static_attributes, attributes_hash = attributes_hashes[:new]
434
- AttributeBuilder.merge_attributes!(attributes, static_attributes) if static_attributes
458
+ AttributeMerger.merge_attributes!(attributes, static_attributes) if static_attributes
435
459
  dynamic_attributes.new = attributes_hash
436
460
  end
437
461
 
438
462
  if attributes_hashes[:old]
439
463
  static_attributes = parse_static_hash(attributes_hashes[:old])
440
- AttributeBuilder.merge_attributes!(attributes, static_attributes) if static_attributes
464
+ AttributeMerger.merge_attributes!(attributes, static_attributes) if static_attributes
441
465
  dynamic_attributes.old = attributes_hashes[:old] unless static_attributes || @options.suppress_eval
442
466
  end
443
467
 
@@ -459,7 +483,8 @@ module Haml
459
483
  :nuke_inner_whitespace => nuke_inner_whitespace,
460
484
  :nuke_outer_whitespace => nuke_outer_whitespace, :object_ref => object_ref,
461
485
  :escape_html => escape_html, :preserve_tag => preserve_tag,
462
- :preserve_script => preserve_script, :parse => parse, :value => line.text)
486
+ :preserve_script => preserve_script, :parse => parse, :value => line.text,
487
+ :escape_interpolation => escape_interpolation)
463
488
  end
464
489
 
465
490
  # Renders a line that creates an XHTML tag and has an implicit div because of
@@ -481,9 +506,9 @@ module Haml
481
506
  conditional, text = balance(text, ?[, ?]) if text[0] == ?[
482
507
  text.strip!
483
508
 
484
- if contains_interpolation?(text)
509
+ if Util.contains_interpolation?(text)
485
510
  parse = true
486
- text = unescape_interpolation(text)
511
+ text = Util.unescape_interpolation(text)
487
512
  else
488
513
  parse = false
489
514
  end
@@ -552,7 +577,7 @@ module Haml
552
577
 
553
578
  alias :close_script :close_silent_script
554
579
 
555
- # This is a class method so it can be accessed from {Haml::Helpers}.
580
+ # This is a class method so it can be accessed from {Haml::HamlHelpers}.
556
581
  #
557
582
  # Iterates through the classes and ids supplied through `.`
558
583
  # and `#` syntax, and returns a hash with them as attributes,
@@ -576,8 +601,8 @@ module Haml
576
601
  attributes
577
602
  end
578
603
 
579
- # This method doesn't use Haml::AttributeParser because currently it depends on Ripper and Rubinius doesn't provide it.
580
- # Ideally this logic should be placed in Haml::AttributeParser instead of here and this method should use it.
604
+ # This method doesn't use Haml::HamlAttributeParser because currently it depends on Ripper and Rubinius doesn't provide it.
605
+ # Ideally this logic should be placed in Haml::HamlAttributeParser instead of here and this method should use it.
581
606
  #
582
607
  # @param [String] text - Hash literal or text inside old attributes
583
608
  # @return [Hash,nil] - Return nil if text is not static Hash literal
@@ -714,7 +739,7 @@ module Haml
714
739
  if type == :static
715
740
  static_attributes[name] = val
716
741
  else
717
- dynamic_attributes << "#{inspect_obj(name)} => #{val},"
742
+ dynamic_attributes << "#{Util.inspect_obj(name)} => #{val},"
718
743
  end
719
744
  end
720
745
  dynamic_attributes << "}"
@@ -749,7 +774,7 @@ module Haml
749
774
 
750
775
  return name, [:static, content.first[1]] if content.size == 1
751
776
  return name, [:dynamic,
752
- %!"#{content.each_with_object(''.dup) {|(t, v), s| s << (t == :str ? inspect_obj(v)[1...-1] : "\#{#{v}}")}}"!]
777
+ %!"#{content.each_with_object(''.dup) {|(t, v), s| s << (t == :str ? Util.inspect_obj(v)[1...-1] : "\#{#{v}}")}}"!]
753
778
  end
754
779
 
755
780
  def next_line
@@ -852,5 +877,115 @@ module Haml
852
877
  def flat?
853
878
  @flat
854
879
  end
880
+
881
+ class << AttributeMerger = Object.new
882
+ # Merges two attribute hashes.
883
+ # This is the same as `to.merge!(from)`,
884
+ # except that it merges id, class, and data attributes.
885
+ #
886
+ # ids are concatenated with `"_"`,
887
+ # and classes are concatenated with `" "`.
888
+ # data hashes are simply merged.
889
+ #
890
+ # Destructively modifies `to`.
891
+ #
892
+ # @param to [{String => String,Hash}] The attribute hash to merge into
893
+ # @param from [{String => Object}] The attribute hash to merge from
894
+ # @return [{String => String,Hash}] `to`, after being merged
895
+ def merge_attributes!(to, from)
896
+ from.keys.each do |key|
897
+ to[key] = merge_value(key, to[key], from[key])
898
+ end
899
+ to
900
+ end
901
+
902
+ private
903
+
904
+ # @return [String, nil]
905
+ def filter_and_join(value, separator)
906
+ return '' if (value.respond_to?(:empty?) && value.empty?)
907
+
908
+ if value.is_a?(Array)
909
+ value = value.flatten
910
+ value.map! {|item| item ? item.to_s : nil}
911
+ value.compact!
912
+ value = value.join(separator)
913
+ else
914
+ value = value ? value.to_s : nil
915
+ end
916
+ !value.nil? && !value.empty? && value
917
+ end
918
+
919
+ # Merge a couple of values to one attribute value. No destructive operation.
920
+ #
921
+ # @param to [String,Hash,nil]
922
+ # @param from [Object]
923
+ # @return [String,Hash]
924
+ def merge_value(key, to, from)
925
+ if from.kind_of?(Hash) || to.kind_of?(Hash)
926
+ from = { nil => from } if !from.is_a?(Hash)
927
+ to = { nil => to } if !to.is_a?(Hash)
928
+ to.merge(from)
929
+ elsif key == 'id'
930
+ merged_id = filter_and_join(from, '_')
931
+ if to && merged_id
932
+ merged_id = "#{to}_#{merged_id}"
933
+ elsif to || merged_id
934
+ merged_id ||= to
935
+ end
936
+ merged_id
937
+ elsif key == 'class'
938
+ merged_class = filter_and_join(from, ' ')
939
+ if to && merged_class
940
+ merged_class = (to.split(' ') | merged_class.split(' ')).join(' ')
941
+ elsif to || merged_class
942
+ merged_class ||= to
943
+ end
944
+ merged_class
945
+ else
946
+ from
947
+ end
948
+ end
949
+ end
950
+ private_constant :AttributeMerger
951
+
952
+ class ParserOptions
953
+ # A list of options that are actually used in the parser
954
+ AVAILABLE_OPTIONS = %i[
955
+ autoclose
956
+ escape_html
957
+ filename
958
+ line
959
+ mime_type
960
+ preserve
961
+ remove_whitespace
962
+ suppress_eval
963
+ ].each do |option|
964
+ attr_reader option
965
+ end
966
+
967
+ DEFAULTS = {
968
+ autoclose: %w(area base basefont br col command embed frame
969
+ hr img input isindex keygen link menuitem meta
970
+ param source track wbr),
971
+ escape_html: false,
972
+ filename: '(haml)',
973
+ line: 1,
974
+ mime_type: 'text/html',
975
+ preserve: %w(textarea pre code),
976
+ remove_whitespace: false,
977
+ suppress_eval: false,
978
+ }
979
+
980
+ def initialize(values = {})
981
+ DEFAULTS.each {|k, v| instance_variable_set :"@#{k}", v}
982
+ AVAILABLE_OPTIONS.each do |key|
983
+ if values.key?(key)
984
+ instance_variable_set :"@#{key}", values[key]
985
+ end
986
+ end
987
+ end
988
+ end
989
+ private_constant :ParserOptions
855
990
  end
856
991
  end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: false
2
+ require 'haml/helpers'
3
+
4
+ # There are only helpers that depend on ActionView internals.
5
+ module Haml
6
+ module RailsHelpers
7
+ include Helpers
8
+ extend self
9
+
10
+ DEFAULT_PRESERVE_TAGS = %w[textarea pre code].freeze
11
+
12
+ def find_and_preserve(input = nil, tags = DEFAULT_PRESERVE_TAGS, &block)
13
+ return find_and_preserve(capture_haml(&block), input || tags) if block
14
+
15
+ tags = tags.each_with_object('') do |t, s|
16
+ s << '|' unless s.empty?
17
+ s << Regexp.escape(t)
18
+ end
19
+
20
+ re = /<(#{tags})([^>]*)>(.*?)(<\/\1>)/im
21
+ input.to_s.gsub(re) do |s|
22
+ s =~ re # Can't rely on $1, etc. existing since Rails' SafeBuffer#gsub is incompatible
23
+ "<#{$1}#{$2}>#{preserve($3)}</#{$1}>"
24
+ end
25
+ end
26
+
27
+ def preserve(input = nil, &block)
28
+ return preserve(capture_haml(&block)) if block
29
+ super.html_safe
30
+ end
31
+
32
+ def surround(front, back = front, &block)
33
+ output = capture_haml(&block)
34
+ front = escape_once(front) unless front.html_safe?
35
+ back = escape_once(back) unless back.html_safe?
36
+ "#{front}#{output.chomp}#{back}\n".html_safe
37
+ end
38
+
39
+ def precede(str, &block)
40
+ str = escape_once(str) unless str.html_safe?
41
+ "#{str}#{capture_haml(&block).chomp}\n".html_safe
42
+ end
43
+
44
+ def succeed(str, &block)
45
+ str = escape_once(str) unless str.html_safe?
46
+ "#{capture_haml(&block).chomp}#{str}\n".html_safe
47
+ end
48
+
49
+ def capture_haml(*args, &block)
50
+ capture(*args, &block)
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+ require 'temple'
3
+ require 'haml/engine'
4
+ require 'haml/rails_helpers'
5
+ require 'haml/util'
6
+
7
+ module Haml
8
+ class RailsTemplate
9
+ # Compatible with: https://github.com/judofyr/temple/blob/v0.7.7/lib/temple/mixins/options.rb#L15-L24
10
+ class << self
11
+ def options
12
+ @options ||= {
13
+ generator: Temple::Generators::RailsOutputBuffer,
14
+ use_html_safe: true,
15
+ streaming: true,
16
+ buffer_class: 'ActionView::OutputBuffer',
17
+ disable_capture: true,
18
+ }
19
+ end
20
+
21
+ def set_options(opts)
22
+ options.update(opts)
23
+ end
24
+ end
25
+
26
+ def call(template, source = nil)
27
+ source ||= template.source
28
+ options = RailsTemplate.options
29
+
30
+ # https://github.com/haml/haml/blob/4.0.7/lib/haml/template/plugin.rb#L19-L20
31
+ # https://github.com/haml/haml/blob/4.0.7/lib/haml/options.rb#L228
32
+ if template.respond_to?(:type) && template.type == 'text/xml'
33
+ options = options.merge(format: :xhtml)
34
+ end
35
+
36
+ if ActionView::Base.try(:annotate_rendered_view_with_filenames) && template.format == :html
37
+ options = options.merge(
38
+ preamble: "<!-- BEGIN #{template.short_identifier} -->\n",
39
+ postamble: "<!-- END #{template.short_identifier} -->\n",
40
+ )
41
+ end
42
+
43
+ Engine.new(options).call(source)
44
+ end
45
+
46
+ def supports_streaming?
47
+ RailsTemplate.options[:streaming]
48
+ end
49
+ end
50
+ ActionView::Template.register_template_handler(:haml, RailsTemplate.new)
51
+ end
52
+
53
+ # Haml extends Haml::Helpers in ActionView each time.
54
+ # It costs much, so Haml includes a compatible module at first.
55
+ ActiveSupport.on_load(:action_view) do
56
+ include Haml::RailsHelpers
57
+ end
data/lib/haml/railtie.rb CHANGED
@@ -1,53 +1,10 @@
1
1
  # frozen_string_literal: true
2
-
3
- require 'haml/template/options'
4
-
5
- # check for a compatible Rails version when Haml is loaded
6
- if (activesupport_spec = Gem.loaded_specs['activesupport'])
7
- if activesupport_spec.version.to_s < '4.0'
8
- raise Exception.new("\n\n** Haml now requires Rails 4.0 and later. Use Haml version 4.0.x\n\n")
9
- end
10
- end
2
+ require 'rails'
11
3
 
12
4
  module Haml
13
- module Filters
14
- module RailsErb
15
- extend Plain
16
- extend TiltFilter
17
- extend PrecompiledTiltFilter
18
- end
19
- end
20
-
21
5
  class Railtie < ::Rails::Railtie
22
- initializer :haml do |app|
23
- ActiveSupport.on_load(:action_view) do
24
- require "haml/template"
25
-
26
- if defined?(::Sass::Rails::SassTemplate) && app.config.assets.enabled
27
- require "haml/sass_rails_filter"
28
- end
29
-
30
- # Any object under ActionView::Template will be defined as the root constant with the same
31
- # name if it exists. If Erubi is loaded at all, ActionView::Template::Handlers::ERB::Erubi
32
- # will turn out to be a reference to the ::Erubi module.
33
- # In Rails 4.2, calling const_defined? results in odd exceptions, which seems to be
34
- # solved by looking for ::Erubi first.
35
- # However, in JRuby, the const_defined? finds it anyway, so we must make sure that it's
36
- # not just a reference to ::Erubi.
37
- if defined?(::Erubi) && (::ActionView::Template::Handlers::ERB.const_get('Erubi') != ::Erubi)
38
- require "haml/helpers/safe_erubi_template"
39
- Haml::Filters::RailsErb.template_class = Haml::SafeErubiTemplate
40
- else
41
- require "haml/helpers/safe_erubis_template"
42
- Haml::Filters::RailsErb.template_class = Haml::SafeErubisTemplate
43
- end
44
- Haml::Template.options[:filters] = { 'erb' => Haml::Filters::RailsErb }
45
-
46
- if app.config.respond_to?(:action_view) &&
47
- app.config.action_view.annotate_rendered_view_with_filenames
48
- Haml::Plugin.annotate_rendered_view_with_filenames = true
49
- end
50
- end
6
+ initializer :haml, before: :load_config_initializers do |app|
7
+ require 'haml/rails_template'
51
8
  end
52
9
  end
53
10
  end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+ require 'ripper'
3
+
4
+ module Haml
5
+ class RubyExpression < Ripper
6
+ class ParseError < StandardError; end
7
+
8
+ def self.syntax_error?(code)
9
+ self.new(code).parse
10
+ false
11
+ rescue ParseError
12
+ true
13
+ end
14
+
15
+ def self.string_literal?(code)
16
+ return false if syntax_error?(code)
17
+
18
+ type, instructions = Ripper.sexp(code)
19
+ return false if type != :program
20
+ return false if instructions.size > 1
21
+
22
+ type, _ = instructions.first
23
+ type == :string_literal
24
+ end
25
+
26
+ private
27
+
28
+ def on_parse_error(*)
29
+ raise ParseError
30
+ end
31
+ end
32
+ end