hamlit 0.1.0

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 (162) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +16 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +34 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE.txt +23 -0
  7. data/README.md +45 -0
  8. data/Rakefile +34 -0
  9. data/benchmarks/benchmark.rb +94 -0
  10. data/benchmarks/context.rb +13 -0
  11. data/benchmarks/view.erb +23 -0
  12. data/benchmarks/view.haml +18 -0
  13. data/benchmarks/view.rbhtml +23 -0
  14. data/benchmarks/view.slim +17 -0
  15. data/bin/hamlit +6 -0
  16. data/hamlit.gemspec +40 -0
  17. data/lib/hamlit/attribute.rb +31 -0
  18. data/lib/hamlit/cli.rb +89 -0
  19. data/lib/hamlit/compiler.rb +24 -0
  20. data/lib/hamlit/compilers/attributes.rb +78 -0
  21. data/lib/hamlit/compilers/comment.rb +13 -0
  22. data/lib/hamlit/compilers/doctype.rb +39 -0
  23. data/lib/hamlit/compilers/dynamic.rb +9 -0
  24. data/lib/hamlit/compilers/filter.rb +53 -0
  25. data/lib/hamlit/compilers/new_attribute.rb +107 -0
  26. data/lib/hamlit/compilers/old_attribute.rb +147 -0
  27. data/lib/hamlit/compilers/preserve.rb +10 -0
  28. data/lib/hamlit/compilers/script.rb +31 -0
  29. data/lib/hamlit/compilers/strip.rb +30 -0
  30. data/lib/hamlit/compilers/text.rb +15 -0
  31. data/lib/hamlit/concerns/attribute_builder.rb +21 -0
  32. data/lib/hamlit/concerns/balanceable.rb +59 -0
  33. data/lib/hamlit/concerns/deprecation.rb +20 -0
  34. data/lib/hamlit/concerns/error.rb +27 -0
  35. data/lib/hamlit/concerns/escapable.rb +17 -0
  36. data/lib/hamlit/concerns/included.rb +28 -0
  37. data/lib/hamlit/concerns/indentable.rb +53 -0
  38. data/lib/hamlit/concerns/line_reader.rb +60 -0
  39. data/lib/hamlit/concerns/registerable.rb +24 -0
  40. data/lib/hamlit/concerns/ripperable.rb +20 -0
  41. data/lib/hamlit/concerns/string_interpolation.rb +48 -0
  42. data/lib/hamlit/engine.rb +42 -0
  43. data/lib/hamlit/filters/base.rb +44 -0
  44. data/lib/hamlit/filters/coffee.rb +12 -0
  45. data/lib/hamlit/filters/css.rb +34 -0
  46. data/lib/hamlit/filters/erb.rb +11 -0
  47. data/lib/hamlit/filters/escaped.rb +19 -0
  48. data/lib/hamlit/filters/javascript.rb +34 -0
  49. data/lib/hamlit/filters/less.rb +12 -0
  50. data/lib/hamlit/filters/markdown.rb +11 -0
  51. data/lib/hamlit/filters/plain.rb +21 -0
  52. data/lib/hamlit/filters/preserve.rb +11 -0
  53. data/lib/hamlit/filters/ruby.rb +11 -0
  54. data/lib/hamlit/filters/sass.rb +12 -0
  55. data/lib/hamlit/filters/scss.rb +12 -0
  56. data/lib/hamlit/filters/tilt.rb +41 -0
  57. data/lib/hamlit/helpers.rb +38 -0
  58. data/lib/hamlit/html/pretty.rb +49 -0
  59. data/lib/hamlit/html/ugly.rb +10 -0
  60. data/lib/hamlit/parser.rb +123 -0
  61. data/lib/hamlit/parsers/attribute.rb +52 -0
  62. data/lib/hamlit/parsers/comment.rb +27 -0
  63. data/lib/hamlit/parsers/doctype.rb +18 -0
  64. data/lib/hamlit/parsers/filter.rb +18 -0
  65. data/lib/hamlit/parsers/multiline.rb +54 -0
  66. data/lib/hamlit/parsers/script.rb +93 -0
  67. data/lib/hamlit/parsers/tag.rb +71 -0
  68. data/lib/hamlit/parsers/text.rb +11 -0
  69. data/lib/hamlit/parsers/whitespace.rb +38 -0
  70. data/lib/hamlit/railtie.rb +21 -0
  71. data/lib/hamlit/template.rb +9 -0
  72. data/lib/hamlit/version.rb +3 -0
  73. data/lib/hamlit.rb +8 -0
  74. data/spec/Rakefile +79 -0
  75. data/spec/hamlit/compilers/script_spec.rb +46 -0
  76. data/spec/hamlit/engine/comment_spec.rb +29 -0
  77. data/spec/hamlit/engine/doctype_spec.rb +19 -0
  78. data/spec/hamlit/engine/error_spec.rb +47 -0
  79. data/spec/hamlit/engine/multiline_spec.rb +44 -0
  80. data/spec/hamlit/engine/new_attribute_spec.rb +19 -0
  81. data/spec/hamlit/engine/old_attributes_spec.rb +85 -0
  82. data/spec/hamlit/engine/preservation_spec.rb +11 -0
  83. data/spec/hamlit/engine/script_spec.rb +87 -0
  84. data/spec/hamlit/engine/silent_script_spec.rb +135 -0
  85. data/spec/hamlit/engine/tag_spec.rb +210 -0
  86. data/spec/hamlit/engine/text_spec.rb +29 -0
  87. data/spec/hamlit/engine_spec.rb +20 -0
  88. data/spec/hamlit/filters/coffee_spec.rb +41 -0
  89. data/spec/hamlit/filters/css_spec.rb +33 -0
  90. data/spec/hamlit/filters/erb_spec.rb +16 -0
  91. data/spec/hamlit/filters/javascript_spec.rb +82 -0
  92. data/spec/hamlit/filters/less_spec.rb +22 -0
  93. data/spec/hamlit/filters/markdown_spec.rb +28 -0
  94. data/spec/hamlit/filters/ruby_spec.rb +24 -0
  95. data/spec/hamlit/filters/sass_spec.rb +37 -0
  96. data/spec/hamlit/filters/scss_spec.rb +21 -0
  97. data/spec/hamlit/ugly_spec.rb +912 -0
  98. data/spec/rails/.gitignore +17 -0
  99. data/spec/rails/.rspec +2 -0
  100. data/spec/rails/Gemfile +19 -0
  101. data/spec/rails/Gemfile.lock +177 -0
  102. data/spec/rails/README.rdoc +28 -0
  103. data/spec/rails/Rakefile +6 -0
  104. data/spec/rails/app/assets/images/.keep +0 -0
  105. data/spec/rails/app/assets/javascripts/application.js +15 -0
  106. data/spec/rails/app/assets/stylesheets/application.css +15 -0
  107. data/spec/rails/app/controllers/application_controller.rb +8 -0
  108. data/spec/rails/app/controllers/concerns/.keep +0 -0
  109. data/spec/rails/app/controllers/users_controller.rb +20 -0
  110. data/spec/rails/app/helpers/application_helper.rb +2 -0
  111. data/spec/rails/app/mailers/.keep +0 -0
  112. data/spec/rails/app/models/.keep +0 -0
  113. data/spec/rails/app/models/concerns/.keep +0 -0
  114. data/spec/rails/app/views/application/index.html.haml +15 -0
  115. data/spec/rails/app/views/layouts/application.html.haml +12 -0
  116. data/spec/rails/app/views/users/capture.html.haml +5 -0
  117. data/spec/rails/app/views/users/capture_haml.html.haml +5 -0
  118. data/spec/rails/app/views/users/form.html.haml +2 -0
  119. data/spec/rails/app/views/users/helpers.html.haml +1 -0
  120. data/spec/rails/app/views/users/index.html.haml +9 -0
  121. data/spec/rails/app/views/users/safe_buffer.html.haml +4 -0
  122. data/spec/rails/bin/bundle +3 -0
  123. data/spec/rails/bin/rails +8 -0
  124. data/spec/rails/bin/rake +8 -0
  125. data/spec/rails/bin/setup +29 -0
  126. data/spec/rails/bin/spring +15 -0
  127. data/spec/rails/config/application.rb +34 -0
  128. data/spec/rails/config/boot.rb +3 -0
  129. data/spec/rails/config/database.yml +25 -0
  130. data/spec/rails/config/environment.rb +5 -0
  131. data/spec/rails/config/environments/development.rb +41 -0
  132. data/spec/rails/config/environments/production.rb +79 -0
  133. data/spec/rails/config/environments/test.rb +42 -0
  134. data/spec/rails/config/initializers/assets.rb +11 -0
  135. data/spec/rails/config/initializers/backtrace_silencers.rb +7 -0
  136. data/spec/rails/config/initializers/cookies_serializer.rb +3 -0
  137. data/spec/rails/config/initializers/filter_parameter_logging.rb +4 -0
  138. data/spec/rails/config/initializers/inflections.rb +16 -0
  139. data/spec/rails/config/initializers/mime_types.rb +4 -0
  140. data/spec/rails/config/initializers/session_store.rb +3 -0
  141. data/spec/rails/config/initializers/wrap_parameters.rb +14 -0
  142. data/spec/rails/config/locales/en.yml +23 -0
  143. data/spec/rails/config/routes.rb +13 -0
  144. data/spec/rails/config/secrets.yml +22 -0
  145. data/spec/rails/config.ru +4 -0
  146. data/spec/rails/db/schema.rb +16 -0
  147. data/spec/rails/db/seeds.rb +7 -0
  148. data/spec/rails/lib/assets/.keep +0 -0
  149. data/spec/rails/lib/tasks/.keep +0 -0
  150. data/spec/rails/log/.keep +0 -0
  151. data/spec/rails/public/404.html +67 -0
  152. data/spec/rails/public/422.html +67 -0
  153. data/spec/rails/public/500.html +66 -0
  154. data/spec/rails/public/favicon.ico +0 -0
  155. data/spec/rails/public/robots.txt +5 -0
  156. data/spec/rails/spec/hamlit_spec.rb +87 -0
  157. data/spec/rails/spec/rails_helper.rb +56 -0
  158. data/spec/rails/spec/spec_helper.rb +91 -0
  159. data/spec/rails/vendor/assets/javascripts/.keep +0 -0
  160. data/spec/rails/vendor/assets/stylesheets/.keep +0 -0
  161. data/spec/spec_helper.rb +48 -0
  162. metadata +560 -0
@@ -0,0 +1,60 @@
1
+ module Hamlit
2
+ module Concerns
3
+ module LineReader
4
+ def reset_lines(lines)
5
+ @lines = lines
6
+ @current_lineno = -1
7
+ end
8
+
9
+ def current_line
10
+ @lines[@current_lineno]
11
+ end
12
+
13
+ # Return nearest line ignoring empty lines.
14
+ def next_line
15
+ lineno = @current_lineno + 1
16
+ while @lines[lineno] && empty_line?(@lines[lineno])
17
+ lineno += 1
18
+ end
19
+ @lines[lineno]
20
+ end
21
+
22
+ def empty_line?(line)
23
+ line =~ /\A *\Z/
24
+ end
25
+
26
+ def skip_lines
27
+ while next_indent >= @current_indent
28
+ @current_lineno += 1
29
+ end
30
+ end
31
+
32
+ def read_lines
33
+ lines = []
34
+ while read_line?
35
+ lines << @lines[@current_lineno + 1]
36
+ @current_lineno += 1
37
+ end
38
+ trim_lines(lines)
39
+ end
40
+
41
+ private
42
+
43
+ def trim_lines(lines)
44
+ size = (lines.first || '').index(/[^\s]/) || 0
45
+ lines.map { |line| line.gsub(/\A {#{size}}/, '') }
46
+ end
47
+
48
+ def read_line?
49
+ return true if count_indent(next_line, strict: false) >= @current_indent
50
+
51
+ line = @lines[@current_lineno + 1]
52
+ return false unless line
53
+
54
+ # NOTE: preserve filter also requires an empty line
55
+ line.gsub(/ /, '').length == 0
56
+ end
57
+ end
58
+ end
59
+ end
60
+
@@ -0,0 +1,24 @@
1
+ module Hamlit
2
+ class NotFound < StandardError
3
+ def initialize(name)
4
+ super(%Q{Filter "#{name}" is not defined.})
5
+ end
6
+ end
7
+
8
+ module Concerns
9
+ module Registerable
10
+ def registered
11
+ @registered ||= {}
12
+ end
13
+
14
+ def register(name, compiler)
15
+ registered[name.to_sym] = compiler
16
+ end
17
+
18
+ def find(name)
19
+ raise NotFound.new(name) unless registered[name.to_sym]
20
+ registered[name.to_sym]
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,20 @@
1
+ require 'ripper'
2
+
3
+ module Hamlit
4
+ module Concerns
5
+ module Ripperable
6
+ TYPE_POSITION = 1
7
+
8
+ def skip_tokens!(tokens, *types)
9
+ while types.include?(type_of(tokens.first))
10
+ tokens.shift
11
+ end
12
+ end
13
+
14
+ def type_of(token)
15
+ return nil unless token
16
+ token[TYPE_POSITION]
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,48 @@
1
+ module Hamlit
2
+ module Concerns
3
+ module StringInterpolation
4
+ def string_literal(str)
5
+ unescape_interpolation(str)
6
+ end
7
+
8
+ def contains_interpolation?(str)
9
+ /#[\{$@]/ === str
10
+ end
11
+
12
+ private
13
+
14
+ def unescape_interpolation(str)
15
+ res = ''
16
+ rest = handle_interpolation(str.inspect) do |scan|
17
+ escapes = (scan[2].size - 1) / 2
18
+ res << scan.matched[0...-3 - escapes]
19
+ if escapes % 2 == 1
20
+ res << '#{'
21
+ else
22
+ content = eval('"' + balance(scan, ?{, ?}, 1)[0][0...-1] + '"')
23
+ res << '#{' + content + '}'
24
+ end
25
+ end
26
+ res + rest
27
+ end
28
+
29
+ def handle_interpolation(str)
30
+ scan = StringScanner.new(str)
31
+ yield scan while scan.scan(/(.*?)(\\*)\#\{/)
32
+ scan.rest
33
+ end
34
+
35
+ def balance(scanner, start, finish, count = 0)
36
+ str = ''
37
+ scanner = StringScanner.new(scanner) unless scanner.is_a? StringScanner
38
+ regexp = Regexp.new("(.*?)[\\#{start.chr}\\#{finish.chr}]", Regexp::MULTILINE)
39
+ while scanner.scan(regexp)
40
+ str << scanner.matched
41
+ count += 1 if scanner.matched[-1] == start
42
+ count -= 1 if scanner.matched[-1] == finish
43
+ return [str.strip, scanner.rest] if count == 0
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,42 @@
1
+ require 'temple'
2
+ require 'hamlit/compiler'
3
+ require 'hamlit/html/pretty'
4
+ require 'hamlit/html/ugly'
5
+ require 'hamlit/parser'
6
+
7
+ module Hamlit
8
+ class Engine < Temple::Engine
9
+ define_options(
10
+ generator: Temple::Generators::ArrayBuffer,
11
+ format: :html,
12
+ attr_quote: "'",
13
+ ugly: true,
14
+ )
15
+
16
+ use Parser
17
+ use Compiler
18
+ use :Html, -> { create(html_compiler) }
19
+ filter :Escapable
20
+ filter :ControlFlow
21
+ filter :MultiFlattener
22
+ filter :StaticMerger
23
+ use :Generator, -> { create(options[:generator]) }
24
+
25
+ private
26
+
27
+ def create(klass)
28
+ valid_options = options.to_hash.select do |key, value|
29
+ klass.options.valid_key?(key)
30
+ end
31
+ klass.new(valid_options)
32
+ end
33
+
34
+ def html_compiler
35
+ if options[:ugly]
36
+ HTML::Ugly
37
+ else
38
+ HTML::Pretty
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,44 @@
1
+ module Hamlit
2
+ module Filters
3
+ class Base
4
+ attr_reader :options
5
+
6
+ def self.indent_source(source, indent_width: 0)
7
+ lines = source.split("\n")
8
+ self.new.compile_lines(lines, indent_width: indent_width)
9
+ end
10
+
11
+ def initialize(options = {})
12
+ @options = options
13
+ end
14
+
15
+ def compile(lines)
16
+ raise NotImplementedError
17
+ end
18
+
19
+ def compile_lines(lines, indent_width: 0)
20
+ base = (lines.first || '').index(/[^\s]/) || 0
21
+ width = indent_width - base
22
+ width = 0 if width < 0
23
+
24
+ lines = strip_last(lines).map do |line|
25
+ ' ' * width + line
26
+ end
27
+
28
+ text = lines.join("\n") + "\n"
29
+ text
30
+ end
31
+
32
+ private
33
+
34
+ # NOTE: empty line is reserved for preserve filter.
35
+ def strip_last(lines)
36
+ lines = lines.dup
37
+ while lines.last && lines.last.length == 0
38
+ lines.delete_at(-1)
39
+ end
40
+ lines
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,12 @@
1
+ require 'hamlit/filters/tilt'
2
+
3
+ module Hamlit
4
+ module Filters
5
+ class Coffee < Filters::Tilt
6
+ def compile(lines)
7
+ ast = [:html, :tag, 'script', [:html, :attrs]]
8
+ compile_with_tilt('coffee', lines.join("\n"), ast)
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,34 @@
1
+ require 'hamlit/filters/base'
2
+
3
+ module Hamlit
4
+ module Filters
5
+ class Css < Base
6
+ def compile(lines)
7
+ return compile_xhtml(lines) if options[:format] == :xhtml
8
+
9
+ compile_html(lines)
10
+ end
11
+
12
+ private
13
+
14
+ def compile_html(lines)
15
+ ast = [:haml, :text, compile_lines(lines, indent_width: 2)]
16
+ ast = [:multi, [:static, "\n"], ast]
17
+ ast = [:html, :tag, 'style', [:html, :attrs], ast]
18
+ ast
19
+ end
20
+
21
+ def compile_xhtml(lines)
22
+ attr = [:html, :attr, 'type', [:static, 'text/css']]
23
+ attrs = [:html, :attrs, attr]
24
+
25
+ multi = [:multi, [:static, "\n"]]
26
+ multi << [:static, " /*<![CDATA[*/\n"]
27
+ multi << [:haml, :text, compile_lines(lines, indent_width: 4)]
28
+ multi << [:static, " /*]]>*/\n"]
29
+
30
+ [:html, :tag, 'style', attrs, multi]
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,11 @@
1
+ require 'hamlit/filters/tilt'
2
+
3
+ module Hamlit
4
+ module Filters
5
+ class Erb < Filters::Tilt
6
+ def compile(lines)
7
+ compile_with_tilt('erb', lines.join("\n"), [], indent_width: 0)
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,19 @@
1
+ require 'hamlit/filters/base'
2
+
3
+ module Hamlit
4
+ module Filters
5
+ class Escaped < Base
6
+ def compile(lines)
7
+ ast = [:haml, :text, lines.join("\n")]
8
+ ast = [:multi, escape_html(ast)]
9
+ ast
10
+ end
11
+
12
+ private
13
+
14
+ def escape_html(ast)
15
+ [:escape, true, ast]
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,34 @@
1
+ require 'hamlit/filters/base'
2
+
3
+ module Hamlit
4
+ module Filters
5
+ class Javascript < Base
6
+ def compile(lines)
7
+ return compile_xhtml(lines) if options[:format] == :xhtml
8
+
9
+ compile_html(lines)
10
+ end
11
+
12
+ private
13
+
14
+ def compile_html(lines)
15
+ ast = [:haml, :text, compile_lines(lines, indent_width: 2)]
16
+ ast = [:multi, [:static, "\n"], ast]
17
+ ast = [:html, :tag, 'script', [:html, :attrs], ast]
18
+ ast
19
+ end
20
+
21
+ def compile_xhtml(lines)
22
+ attr = [:html, :attr, 'type', [:static, 'text/javascript']]
23
+ attrs = [:html, :attrs, attr]
24
+
25
+ multi = [:multi, [:static, "\n"]]
26
+ multi << [:static, " //<![CDATA[\n"]
27
+ multi << [:haml, :text, compile_lines(lines, indent_width: 4)]
28
+ multi << [:static, " //]]>\n"]
29
+
30
+ [:html, :tag, 'script', attrs, multi]
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,12 @@
1
+ require 'hamlit/filters/tilt'
2
+
3
+ module Hamlit
4
+ module Filters
5
+ class Less < Filters::Tilt
6
+ def compile(lines)
7
+ ast = [:html, :tag, 'style', [:html, :attrs]]
8
+ compile_with_tilt('less', lines.join("\n"), ast)
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,11 @@
1
+ require 'hamlit/filters/tilt'
2
+
3
+ module Hamlit
4
+ module Filters
5
+ class Markdown < Filters::Tilt
6
+ def compile(lines)
7
+ compile_with_tilt('markdown', lines.join("\n"), [], indent_width: 0)
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,21 @@
1
+ require 'hamlit/filters/base'
2
+
3
+ module Hamlit
4
+ module Filters
5
+ class Plain < Base
6
+ def compile(lines)
7
+ ast = [:multi]
8
+ text = compile_lines(lines)
9
+ text.gsub!(/\n\Z/, '') unless string_interpolated?(text)
10
+ ast << [:haml, :text, text]
11
+ ast
12
+ end
13
+
14
+ private
15
+
16
+ def string_interpolated?(text)
17
+ text =~ /\#{[^\#{}]*}/
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,11 @@
1
+ require 'hamlit/filters/base'
2
+
3
+ module Hamlit
4
+ module Filters
5
+ class Preserve < Base
6
+ def compile(lines)
7
+ [:multi, [:haml, :text, lines.join('&#x000A;')]]
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ require 'hamlit/filters/base'
2
+
3
+ module Hamlit
4
+ module Filters
5
+ class Ruby < Base
6
+ def compile(lines)
7
+ [:multi, [:code, lines.join("\n")]]
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,12 @@
1
+ require 'hamlit/filters/tilt'
2
+
3
+ module Hamlit
4
+ module Filters
5
+ class Sass < Filters::Tilt
6
+ def compile(lines)
7
+ ast = [:html, :tag, 'style', [:html, :attrs]]
8
+ compile_with_tilt('sass', lines.join("\n"), ast)
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ require 'hamlit/filters/tilt'
2
+
3
+ module Hamlit
4
+ module Filters
5
+ class Scss < Filters::Tilt
6
+ def compile(lines)
7
+ ast = [:html, :tag, 'style', [:html, :attrs]]
8
+ compile_with_tilt('scss', lines.join("\n"), ast)
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,41 @@
1
+ require 'tilt'
2
+ require 'hamlit/concerns/string_interpolation'
3
+ require 'hamlit/filters/base'
4
+
5
+ module Hamlit
6
+ module Filters
7
+ class Tilt < Filters::Base
8
+ include Concerns::StringInterpolation
9
+
10
+ def self.render(name, source, indent_width: 2)
11
+ result = ::Tilt["t.#{name}"].new { source }.render
12
+ indent_source(result, indent_width: indent_width)
13
+ end
14
+
15
+ private
16
+
17
+ def compile_with_tilt(name, source, ast, indent_width: 2)
18
+ if contains_interpolation?(source)
19
+ return runtime_compile(name, source, ast, indent_width: indent_width)
20
+ end
21
+
22
+ content = [:static, Filters::Tilt.render(name, source, indent_width: indent_width)]
23
+ build_ast(ast, content)
24
+ end
25
+
26
+ def runtime_compile(name, source, ast, indent_width: 2)
27
+ literal = string_literal(source)
28
+ code = "::Hamlit::Filters::Tilt.render(#{name.inspect}, #{literal}, indent_width: #{indent_width})"
29
+ content = [:dynamic, code]
30
+ build_ast(ast, content)
31
+ end
32
+
33
+ def build_ast(ast, content)
34
+ return content if ast.empty?
35
+
36
+ content = [:multi, [:static, "\n"], content]
37
+ ast << content
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,38 @@
1
+ # This is a module compatible with Haml::Helpers.
2
+ # It is included by ActionView in initializer.
3
+ module Hamlit
4
+ module Helpers
5
+ extend self
6
+
7
+ DEFAULT_PRESERVE_TAGS = %w[textarea pre code].freeze
8
+
9
+ def find_and_preserve(input = nil, tags = DEFAULT_PRESERVE_TAGS, &block)
10
+ return find_and_preserve(capture_haml(&block), input || tags) if block
11
+
12
+ tags = tags.each_with_object('') do |t, s|
13
+ s << '|' unless s.empty?
14
+ s << Regexp.escape(t)
15
+ end
16
+
17
+ re = /<(#{tags})([^>]*)>(.*?)(<\/\1>)/im
18
+ input.to_s.gsub(re) do |s|
19
+ s =~ re # Can't rely on $1, etc. existing since Rails' SafeBuffer#gsub is incompatible
20
+ "<#{$1}#{$2}>#{preserve($3)}</#{$1}>"
21
+ end
22
+ end
23
+
24
+ def preserve(input = nil, &block)
25
+ return preserve(capture_haml(&block)) if block
26
+ s = input.to_s.chomp("\n")
27
+ s.gsub!(/\n/, '&#x000A;')
28
+ s.delete!("\r")
29
+ s
30
+ end
31
+
32
+ # NOTE: currently Hamlit::Helpers is enabled by default on only
33
+ # Rails environment. Thus you can use capture.
34
+ def capture_haml(*args, &block)
35
+ capture(*args, &block)
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,49 @@
1
+ require 'hamlit/concerns/deprecation'
2
+ require 'temple/html/pretty'
3
+
4
+ # NOTE: This does not work and disabled by default.
5
+ # Actually on_static is just a workaround. This should be totally rewritten.
6
+ # Because pretty mode is not used on production and not so important,
7
+ # it is not done for now.
8
+ module Hamlit
9
+ module HTML
10
+ class Pretty < Temple::HTML::Pretty
11
+ include Concerns::Deprecation
12
+
13
+ def call(exp)
14
+ result = super(exp)
15
+ result << [:static, "\n"] if @added_newline
16
+ result
17
+ end
18
+
19
+ def on_static(exp)
20
+ if exp == "\n"
21
+ @added_newline = true
22
+ [:static, '']
23
+ else
24
+ [:static, exp]
25
+ end
26
+ end
27
+
28
+ def on_html_tag(name, attrs, content = nil)
29
+ if content.is_a?(Array) && content.first != :multi
30
+ return parse_oneline_tag(name, attrs, content)
31
+ end
32
+
33
+ super
34
+ end
35
+
36
+ private
37
+
38
+ def parse_oneline_tag(name, attrs, content)
39
+ name = name.to_s
40
+ closed = !content || (empty_exp?(content) && (@format == :xml || options[:autoclose].include?(name)))
41
+ result = [:multi, [:static, "<#{name}"], compile(attrs)]
42
+ result << [:static, (closed && @format != :html ? ' /' : '') + '>']
43
+ result << compile(content) if content
44
+ result << [:static, "</#{name}>"] if !closed
45
+ result
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,10 @@
1
+ require 'hamlit/concerns/deprecation'
2
+ require 'temple/html/fast'
3
+
4
+ module Hamlit
5
+ module HTML
6
+ class Ugly < Temple::HTML::Fast
7
+ include Concerns::Deprecation
8
+ end
9
+ end
10
+ end