haml 5.1.2 → 6.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (96) hide show
  1. checksums.yaml +4 -4
  2. data/.github/FUNDING.yml +3 -0
  3. data/.github/workflows/test.yml +36 -0
  4. data/.gitignore +16 -15
  5. data/.yardopts +0 -3
  6. data/CHANGELOG.md +189 -1
  7. data/FAQ.md +1 -1
  8. data/Gemfile +20 -12
  9. data/MIT-LICENSE +1 -1
  10. data/README.md +10 -17
  11. data/REFERENCE.md +129 -164
  12. data/Rakefile +15 -89
  13. data/bin/bench +66 -0
  14. data/bin/console +11 -0
  15. data/bin/ruby +3 -0
  16. data/bin/setup +7 -0
  17. data/bin/stackprof +27 -0
  18. data/bin/test +24 -0
  19. data/exe/haml +6 -0
  20. data/haml.gemspec +34 -35
  21. data/lib/haml/ambles.rb +20 -0
  22. data/lib/haml/attribute_builder.rb +131 -133
  23. data/lib/haml/attribute_compiler.rb +91 -182
  24. data/lib/haml/attribute_parser.rb +92 -126
  25. data/lib/haml/cli.rb +154 -0
  26. data/lib/haml/compiler/children_compiler.rb +155 -0
  27. data/lib/haml/compiler/comment_compiler.rb +51 -0
  28. data/lib/haml/compiler/doctype_compiler.rb +52 -0
  29. data/lib/haml/compiler/script_compiler.rb +114 -0
  30. data/lib/haml/compiler/silent_script_compiler.rb +24 -0
  31. data/lib/haml/compiler/tag_compiler.rb +76 -0
  32. data/lib/haml/compiler.rb +63 -296
  33. data/lib/haml/dynamic_merger.rb +67 -0
  34. data/lib/haml/engine.rb +48 -227
  35. data/lib/haml/error.rb +5 -4
  36. data/lib/haml/escape.rb +13 -0
  37. data/lib/haml/escape_any.rb +21 -0
  38. data/lib/haml/filters/base.rb +12 -0
  39. data/lib/haml/filters/cdata.rb +20 -0
  40. data/lib/haml/filters/coffee.rb +17 -0
  41. data/lib/haml/filters/css.rb +33 -0
  42. data/lib/haml/filters/erb.rb +10 -0
  43. data/lib/haml/filters/escaped.rb +22 -0
  44. data/lib/haml/filters/javascript.rb +33 -0
  45. data/lib/haml/filters/less.rb +20 -0
  46. data/lib/haml/filters/markdown.rb +11 -0
  47. data/lib/haml/filters/plain.rb +29 -0
  48. data/lib/haml/filters/preserve.rb +22 -0
  49. data/lib/haml/filters/ruby.rb +10 -0
  50. data/lib/haml/filters/sass.rb +15 -0
  51. data/lib/haml/filters/scss.rb +15 -0
  52. data/lib/haml/filters/text_base.rb +25 -0
  53. data/lib/haml/filters/tilt_base.rb +59 -0
  54. data/lib/haml/filters.rb +54 -378
  55. data/lib/haml/force_escape.rb +29 -0
  56. data/lib/haml/helpers.rb +3 -691
  57. data/lib/haml/html.rb +22 -0
  58. data/lib/haml/identity.rb +13 -0
  59. data/lib/haml/object_ref.rb +35 -0
  60. data/lib/haml/parser.rb +190 -27
  61. data/lib/haml/rails_helpers.rb +53 -0
  62. data/lib/haml/rails_template.rb +62 -0
  63. data/lib/haml/railtie.rb +3 -41
  64. data/lib/haml/ruby_expression.rb +32 -0
  65. data/lib/haml/string_splitter.rb +140 -0
  66. data/lib/haml/template.rb +15 -34
  67. data/lib/haml/temple_line_counter.rb +2 -1
  68. data/lib/haml/util.rb +20 -16
  69. data/lib/haml/version.rb +1 -2
  70. data/lib/haml/whitespace.rb +8 -0
  71. data/lib/haml.rb +8 -20
  72. metadata +205 -53
  73. data/.gitmodules +0 -3
  74. data/.travis.yml +0 -97
  75. data/TODO +0 -24
  76. data/benchmark.rb +0 -70
  77. data/bin/haml +0 -9
  78. data/lib/haml/.gitattributes +0 -1
  79. data/lib/haml/buffer.rb +0 -238
  80. data/lib/haml/escapable.rb +0 -50
  81. data/lib/haml/exec.rb +0 -347
  82. data/lib/haml/generator.rb +0 -42
  83. data/lib/haml/helpers/action_view_extensions.rb +0 -60
  84. data/lib/haml/helpers/action_view_mods.rb +0 -132
  85. data/lib/haml/helpers/action_view_xss_mods.rb +0 -60
  86. data/lib/haml/helpers/safe_erubi_template.rb +0 -20
  87. data/lib/haml/helpers/safe_erubis_template.rb +0 -33
  88. data/lib/haml/helpers/xss_mods.rb +0 -111
  89. data/lib/haml/options.rb +0 -273
  90. data/lib/haml/plugin.rb +0 -37
  91. data/lib/haml/sass_rails_filter.rb +0 -47
  92. data/lib/haml/template/options.rb +0 -27
  93. data/lib/haml/temple_engine.rb +0 -123
  94. data/yard/default/.gitignore +0 -1
  95. data/yard/default/fulldoc/html/css/common.sass +0 -15
  96. data/yard/default/layout/html/footer.erb +0 -12
data/lib/haml/engine.rb CHANGED
@@ -1,238 +1,59 @@
1
1
  # frozen_string_literal: true
2
-
3
- require 'forwardable'
4
-
2
+ require 'temple'
5
3
  require 'haml/parser'
6
4
  require 'haml/compiler'
7
- require 'haml/options'
8
- require 'haml/helpers'
9
- require 'haml/buffer'
10
- require 'haml/filters'
11
- require 'haml/error'
12
- require 'haml/temple_engine'
5
+ require 'haml/html'
6
+ require 'haml/string_splitter'
7
+ require 'haml/escape'
8
+ require 'haml/escape_any'
9
+ require 'haml/force_escape'
10
+ require 'haml/dynamic_merger'
11
+ require 'haml/ambles'
12
+ require 'haml/whitespace'
13
13
 
14
14
  module Haml
15
- # This is the frontend for using Haml programmatically.
16
- # It can be directly used by the user by creating a
17
- # new instance and calling \{#render} to render the template.
18
- # For example:
19
- #
20
- # template = File.read('templates/really_cool_template.haml')
21
- # haml_engine = Haml::Engine.new(template)
22
- # output = haml_engine.render
23
- # puts output
24
- class Engine
25
- extend Forwardable
26
- include Haml::Util
27
-
28
- # The Haml::Options instance.
29
- # See {file:REFERENCE.md#options the Haml options documentation}.
30
- #
31
- # @return Haml::Options
32
- attr_accessor :options
33
-
34
- # The indentation used in the Haml document,
35
- # or `nil` if the indentation is ambiguous
36
- # (for example, for a single-level document).
37
- #
38
- # @return [String]
39
- attr_accessor :indentation
40
-
41
- # Tilt currently depends on these moved methods, provide a stable API
42
- def_delegators :compiler, :precompiled, :precompiled_method_return_value
43
-
44
- def options_for_buffer
45
- @options.for_buffer
46
- end
47
-
48
- # Precompiles the Haml template.
49
- #
50
- # @param template [String] The Haml template
51
- # @param options [{Symbol => Object}] An options hash;
52
- # see {file:REFERENCE.md#options the Haml options documentation}
53
- # @raise [Haml::Error] if there's a Haml syntax error in the template
54
- def initialize(template, options = {})
55
- # Reflect changes of `Haml::Options.defaults` to `Haml::TempleEngine` options, but `#initialize_encoding`
56
- # should be run against the arguemnt `options[:encoding]` for backward compatibility with old `Haml::Engine`.
57
- options = Options.defaults.dup.tap { |o| o.delete(:encoding) }.merge!(options)
58
- @options = Options.new(options)
59
-
60
- @template = check_haml_encoding(template) do |msg, line|
61
- raise Haml::Error.new(msg, line)
62
- end
63
-
64
- @temple_engine = TempleEngine.new(options)
65
- @temple_engine.compile(@template)
66
- end
67
-
68
- # Deprecated API for backword compatibility
69
- def compiler
70
- @temple_engine
71
- end
72
-
73
- # Processes the template and returns the result as a string.
74
- #
75
- # `scope` is the context in which the template is evaluated.
76
- # If it's a `Binding`, Haml uses it as the second argument to `Kernel#eval`;
77
- # otherwise, Haml just uses its `#instance_eval` context.
78
- #
79
- # Note that Haml modifies the evaluation context
80
- # (either the scope object or the `self` object of the scope binding).
81
- # It extends {Haml::Helpers}, and various instance variables are set
82
- # (all prefixed with `haml_`).
83
- # For example:
84
- #
85
- # s = "foobar"
86
- # Haml::Engine.new("%p= upcase").render(s) #=> "<p>FOOBAR</p>"
87
- #
88
- # # s now extends Haml::Helpers
89
- # s.respond_to?(:html_attrs) #=> true
90
- #
91
- # `locals` is a hash of local variables to make available to the template.
92
- # For example:
93
- #
94
- # Haml::Engine.new("%p= foo").render(Object.new, :foo => "Hello, world!") #=> "<p>Hello, world!</p>"
95
- #
96
- # If a block is passed to render,
97
- # that block is run when `yield` is called
98
- # within the template.
99
- #
100
- # Due to some Ruby quirks,
101
- # if `scope` is a `Binding` object and a block is given,
102
- # the evaluation context may not be quite what the user expects.
103
- # In particular, it's equivalent to passing `eval("self", scope)` as `scope`.
104
- # This won't have an effect in most cases,
105
- # but if you're relying on local variables defined in the context of `scope`,
106
- # they won't work.
107
- #
108
- # @param scope [Binding, Object] The context in which the template is evaluated
109
- # @param locals [{Symbol => Object}] Local variables that will be made available
110
- # to the template
111
- # @param block [#to_proc] A block that can be yielded to within the template
112
- # @return [String] The rendered template
113
- def render(scope = Object.new, locals = {}, &block)
114
- parent = scope.instance_variable_defined?(:@haml_buffer) ? scope.instance_variable_get(:@haml_buffer) : nil
115
- buffer = Haml::Buffer.new(parent, @options.for_buffer)
116
-
117
- if scope.is_a?(Binding)
118
- scope_object = eval("self", scope)
119
- scope = scope_object.instance_eval{binding} if block_given?
120
- else
121
- scope_object = scope
122
- scope = scope_object.instance_eval{binding}
123
- end
124
-
125
- set_locals(locals.merge(:_hamlout => buffer, :_erbout => buffer.buffer), scope, scope_object)
126
-
127
- scope_object.extend(Haml::Helpers)
128
- scope_object.instance_variable_set(:@haml_buffer, buffer)
129
- begin
130
- eval(@temple_engine.precompiled_with_return_value, scope, @options.filename, @options.line)
131
- rescue ::SyntaxError => e
132
- raise SyntaxError, e.message
133
- end
134
- ensure
135
- # Get rid of the current buffer
136
- scope_object.instance_variable_set(:@haml_buffer, buffer.upper) if buffer
137
- end
138
- alias_method :to_html, :render
139
-
140
- # Returns a proc that, when called,
141
- # renders the template and returns the result as a string.
142
- #
143
- # `scope` works the same as it does for render.
144
- #
145
- # The first argument of the returned proc is a hash of local variable names to values.
146
- # However, due to an unfortunate Ruby quirk,
147
- # the local variables which can be assigned must be pre-declared.
148
- # This is done with the `local_names` argument.
149
- # For example:
150
- #
151
- # # This works
152
- # Haml::Engine.new("%p= foo").render_proc(Object.new, :foo).call :foo => "Hello!"
153
- # #=> "<p>Hello!</p>"
154
- #
155
- # # This doesn't
156
- # Haml::Engine.new("%p= foo").render_proc.call :foo => "Hello!"
157
- # #=> NameError: undefined local variable or method `foo'
158
- #
159
- # The proc doesn't take a block; any yields in the template will fail.
160
- #
161
- # @param scope [Binding, Object] The context in which the template is evaluated
162
- # @param local_names [Array<Symbol>] The names of the locals that can be passed to the proc
163
- # @return [Proc] The proc that will run the template
164
- def render_proc(scope = Object.new, *local_names)
165
- if scope.is_a?(Binding)
166
- scope_object = eval("self", scope)
167
- else
168
- scope_object = scope
169
- scope = scope_object.instance_eval{binding}
170
- end
171
-
172
- begin
173
- str = @temple_engine.precompiled_with_ambles(local_names)
174
- eval(
175
- "Proc.new { |*_haml_locals| _haml_locals = _haml_locals[0] || {}; #{str}}\n",
176
- scope,
177
- @options.filename,
178
- @options.line
179
- )
180
- rescue ::SyntaxError => e
181
- raise SyntaxError, e.message
182
- end
183
- end
184
-
185
- # Defines a method on `object` with the given name
186
- # that renders the template and returns the result as a string.
187
- #
188
- # If `object` is a class or module,
189
- # the method will instead be defined as an instance method.
190
- # For example:
191
- #
192
- # t = Time.now
193
- # Haml::Engine.new("%p\n Today's date is\n .date= self.to_s").def_method(t, :render)
194
- # t.render #=> "<p>\n Today's date is\n <div class='date'>Fri Nov 23 18:28:29 -0800 2007</div>\n</p>\n"
195
- #
196
- # Haml::Engine.new(".upcased= upcase").def_method(String, :upcased_div)
197
- # "foobar".upcased_div #=> "<div class='upcased'>FOOBAR</div>\n"
198
- #
199
- # The first argument of the defined method is a hash of local variable names to values.
200
- # However, due to an unfortunate Ruby quirk,
201
- # the local variables which can be assigned must be pre-declared.
202
- # This is done with the `local_names` argument.
203
- # For example:
204
- #
205
- # # This works
206
- # obj = Object.new
207
- # Haml::Engine.new("%p= foo").def_method(obj, :render, :foo)
208
- # obj.render(:foo => "Hello!") #=> "<p>Hello!</p>"
209
- #
210
- # # This doesn't
211
- # obj = Object.new
212
- # Haml::Engine.new("%p= foo").def_method(obj, :render)
213
- # obj.render(:foo => "Hello!") #=> NameError: undefined local variable or method `foo'
214
- #
215
- # Note that Haml modifies the evaluation context
216
- # (either the scope object or the `self` object of the scope binding).
217
- # It extends {Haml::Helpers}, and various instance variables are set
218
- # (all prefixed with `haml_`).
219
- #
220
- # @param object [Object, Module] The object on which to define the method
221
- # @param name [String, Symbol] The name of the method to define
222
- # @param local_names [Array<Symbol>] The names of the locals that can be passed to the proc
223
- def def_method(object, name, *local_names)
224
- method = object.is_a?(Module) ? :module_eval : :instance_eval
15
+ class Engine < Temple::Engine
16
+ define_options(
17
+ :buffer_class,
18
+ generator: Temple::Generators::StringBuffer,
19
+ format: :html,
20
+ attr_quote: "'",
21
+ escape_html: true,
22
+ escape_attrs: true,
23
+ autoclose: %w(area base basefont br col command embed frame
24
+ hr img input isindex keygen link menuitem meta
25
+ param source track wbr),
26
+ filename: "",
27
+ disable_capture: false,
28
+ remove_whitespace: false,
29
+ )
30
+
31
+ use Parser
32
+ use Compiler
33
+ use HTML
34
+ use StringSplitter
35
+ filter :StaticAnalyzer
36
+ use Escape
37
+ use EscapeAny
38
+ use ForceEscape
39
+ filter :ControlFlow
40
+ use Ambles
41
+ filter :MultiFlattener
42
+ use Whitespace
43
+ filter :StaticMerger
44
+ use DynamicMerger
45
+ use :Generator, -> { options[:generator] }
46
+ end
225
47
 
226
- object.send(method, "def #{name}(_haml_locals = {}); #{@temple_engine.precompiled_with_ambles(local_names)}; end",
227
- @options.filename, @options.line)
48
+ # For backward compatibility of Tilt integration. TODO: We should deprecate this
49
+ # and let Tilt have a native support of Haml 6. At least it generates warnings now.
50
+ class TempleEngine < Engine
51
+ def compile(template)
52
+ @precompiled = call(template)
228
53
  end
229
54
 
230
- private
231
-
232
- def set_locals(locals, scope, scope_object)
233
- scope_object.instance_variable_set :@_haml_locals, locals
234
- set_locals = locals.keys.map { |k| "#{k} = @_haml_locals[#{k.inspect}]" }.join("\n")
235
- eval(set_locals, scope)
55
+ def precompiled_with_ambles(_local_names, after_preamble:)
56
+ "#{after_preamble.tr("\n", ';')}#{@precompiled}".dup
236
57
  end
237
58
  end
238
59
  end
data/lib/haml/error.rb CHANGED
@@ -1,9 +1,6 @@
1
1
  # frozen_string_literal: true
2
-
3
2
  module Haml
4
- # An exception raised by Haml code.
5
3
  class Error < StandardError
6
-
7
4
  MESSAGES = {
8
5
  bad_script_indent: '"%s" is indented at wrong level: expected %d, but was at %d.',
9
6
  cant_run_filter: 'Can\'t run "%s" filter; you must require its dependencies first',
@@ -61,5 +58,9 @@ END
61
58
  # except in that it's a subclass of {Haml::Error}.
62
59
  class SyntaxError < Error; end
63
60
 
64
- class InvalidAttributeNameError < SyntaxError; end
61
+ # An invalid filter name was used.
62
+ class FilterNotFound < Error; end
63
+
64
+ # InternalError means that you hit a bug of Haml itself.
65
+ class InternalError < Error; end
65
66
  end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+ require 'haml/util'
3
+
4
+ module Haml
5
+ class Escape < Temple::Filters::Escapable
6
+ def initialize(opts = {})
7
+ super
8
+ @escape_code = options[:escape_code] ||
9
+ "::Haml::Util.escape_html#{options[:use_html_safe] ? '_safe' : ''}((%s))"
10
+ @escaper = eval("proc {|v| #{@escape_code % 'v'} }")
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+ require 'haml/escape'
3
+
4
+ module Haml
5
+ # This module allows Temple::Filter to dispatch :fescape on `#compile`.
6
+ module EscapeanyDispathcer
7
+ def on_escapeany(flag, exp)
8
+ [:escapeany, flag, compile(exp)]
9
+ end
10
+ end
11
+ ::Temple::Filter.include EscapeanyDispathcer
12
+
13
+ # Unlike Haml::Escape, this calls to_s when not escaped.
14
+ class EscapeAny < Escape
15
+ alias_method :on_escapeany, :on_escape
16
+
17
+ def on_dynamic(value)
18
+ [:dynamic, @escape ? @escape_code % value : "(#{value}).to_s"]
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+ require 'haml/util'
3
+
4
+ module Haml
5
+ class Filters
6
+ class Base
7
+ def initialize(options = {})
8
+ @format = options[:format]
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+ module Haml
3
+ class Filters
4
+ class Cdata < TextBase
5
+ def compile(node)
6
+ compile_cdata(node)
7
+ end
8
+
9
+ private
10
+
11
+ def compile_cdata(node)
12
+ temple = [:multi]
13
+ temple << [:static, "<![CDATA[\n"]
14
+ compile_text!(temple, node, ' ')
15
+ temple << [:static, "\n]]>"]
16
+ temple
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+ module Haml
3
+ class Filters
4
+ class Coffee < TiltBase
5
+ def compile(node)
6
+ require 'tilt/coffee' if explicit_require?('coffee')
7
+ temple = [:multi]
8
+ temple << [:static, "<script>\n"]
9
+ temple << compile_with_tilt(node, 'coffee', indent_width: 2)
10
+ temple << [:static, "</script>"]
11
+ temple
12
+ end
13
+ end
14
+
15
+ CoffeeScript = Coffee
16
+ end
17
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+ module Haml
3
+ class Filters
4
+ class Css < TextBase
5
+ def compile(node)
6
+ case @format
7
+ when :xhtml
8
+ compile_xhtml(node)
9
+ else
10
+ compile_html(node)
11
+ end
12
+ end
13
+
14
+ private
15
+
16
+ def compile_html(node)
17
+ temple = [:multi]
18
+ temple << [:static, "<style>\n"]
19
+ compile_text!(temple, node, ' ')
20
+ temple << [:static, "\n</style>"]
21
+ temple
22
+ end
23
+
24
+ def compile_xhtml(node)
25
+ temple = [:multi]
26
+ temple << [:static, "<style type='text/css'>\n /*<![CDATA[*/\n"]
27
+ compile_text!(temple, node, ' ')
28
+ temple << [:static, "\n /*]]>*/\n</style>"]
29
+ temple
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+ module Haml
3
+ class Filters
4
+ class Erb < TiltBase
5
+ def compile(node)
6
+ precompiled_with_tilt(node, 'erb')
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+ module Haml
3
+ class Filters
4
+ class Escaped < Base
5
+ def compile(node)
6
+ text = node.value[:text].rstrip
7
+ temple = compile_text(text)
8
+ [:escape, true, temple]
9
+ end
10
+
11
+ private
12
+
13
+ def compile_text(text)
14
+ if ::Haml::Util.contains_interpolation?(text)
15
+ [:dynamic, ::Haml::Util.unescape_interpolation(text)]
16
+ else
17
+ [:static, text]
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+ module Haml
3
+ class Filters
4
+ class Javascript < TextBase
5
+ def compile(node)
6
+ case @format
7
+ when :xhtml
8
+ compile_xhtml(node)
9
+ else
10
+ compile_html(node)
11
+ end
12
+ end
13
+
14
+ private
15
+
16
+ def compile_html(node)
17
+ temple = [:multi]
18
+ temple << [:static, "<script>\n"]
19
+ compile_text!(temple, node, ' ')
20
+ temple << [:static, "\n</script>"]
21
+ temple
22
+ end
23
+
24
+ def compile_xhtml(node)
25
+ temple = [:multi]
26
+ temple << [:static, "<script type='text/javascript'>\n //<![CDATA[\n"]
27
+ compile_text!(temple, node, ' ')
28
+ temple << [:static, "\n //]]>\n</script>"]
29
+ temple
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+ # LESS support is deprecated since it requires therubyracer.gem,
3
+ # which is hard to maintain.
4
+ #
5
+ # It's not supported in Sprockets 3.0+ too.
6
+ # https://github.com/sstephenson/sprockets/pull/547
7
+ module Haml
8
+ class Filters
9
+ class Less < TiltBase
10
+ def compile(node)
11
+ require 'tilt/less' if explicit_require?('less')
12
+ temple = [:multi]
13
+ temple << [:static, "<style>\n"]
14
+ temple << compile_with_tilt(node, 'less', indent_width: 2)
15
+ temple << [:static, '</style>']
16
+ temple
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+ module Haml
3
+ class Filters
4
+ class Markdown < TiltBase
5
+ def compile(node)
6
+ require 'tilt/redcarpet' if explicit_require?('markdown')
7
+ compile_with_tilt(node, 'markdown')
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+ require 'haml/string_splitter'
3
+
4
+ module Haml
5
+ class Filters
6
+ class Plain < Base
7
+ def compile(node)
8
+ text = node.value[:text]
9
+ text = text.rstrip unless ::Haml::Util.contains_interpolation?(text) # for compatibility
10
+ [:multi, *compile_plain(text)]
11
+ end
12
+
13
+ private
14
+
15
+ def compile_plain(text)
16
+ string_literal = ::Haml::Util.unescape_interpolation(text)
17
+ StringSplitter.compile(string_literal).map do |temple|
18
+ type, str = temple
19
+ case type
20
+ when :dynamic
21
+ [:escape, false, [:dynamic, str]]
22
+ else
23
+ temple
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+ module Haml
3
+ class Filters
4
+ class Preserve < Base
5
+ def compile(node)
6
+ text = node.value[:text].rstrip + "\n"
7
+ text = text.gsub("\n", '&#x000A;')
8
+ compile_text(text)
9
+ end
10
+
11
+ private
12
+
13
+ def compile_text(text)
14
+ if ::Haml::Util.contains_interpolation?(text)
15
+ [:dynamic, ::Haml::Util.unescape_interpolation(text)]
16
+ else
17
+ [:static, text]
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+ module Haml
3
+ class Filters
4
+ class Ruby < Base
5
+ def compile(node)
6
+ [:code, node.value[:text]]
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+ module Haml
3
+ class Filters
4
+ class Sass < TiltBase
5
+ def compile(node)
6
+ require 'tilt/sass' if explicit_require?('sass')
7
+ temple = [:multi]
8
+ temple << [:static, "<style>\n"]
9
+ temple << compile_with_tilt(node, 'sass', indent_width: 2)
10
+ temple << [:static, "</style>"]
11
+ temple
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+ module Haml
3
+ class Filters
4
+ class Scss < TiltBase
5
+ def compile(node)
6
+ require 'tilt/sass' if explicit_require?('scss')
7
+ temple = [:multi]
8
+ temple << [:static, "<style>\n"]
9
+ temple << compile_with_tilt(node, 'scss', indent_width: 2)
10
+ temple << [:static, "</style>"]
11
+ temple
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+ module Haml
3
+ class Filters
4
+ class TextBase < Base
5
+ def compile_text!(temple, node, prefix)
6
+ text = node.value[:text].rstrip.gsub(/^/, prefix)
7
+ if ::Haml::Util.contains_interpolation?(node.value[:text])
8
+ # original: Haml::Filters#compile
9
+ text = ::Haml::Util.unescape_interpolation(text).gsub(/(\\+)n/) do |s|
10
+ escapes = $1.size
11
+ next s if escapes % 2 == 0
12
+ "#{'\\' * (escapes - 1)}\n"
13
+ end
14
+ text.prepend("\n")
15
+ temple << [:dynamic, text]
16
+ else
17
+ node.value[:text].split("\n").size.times do
18
+ temple << [:newline]
19
+ end
20
+ temple << [:static, text]
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end