haml 6.0.0.beta.1-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. checksums.yaml +7 -0
  2. data/.github/FUNDING.yml +1 -0
  3. data/.github/workflows/test.yml +40 -0
  4. data/.gitignore +19 -0
  5. data/CHANGELOG.md +1515 -0
  6. data/FAQ.md +147 -0
  7. data/Gemfile +23 -0
  8. data/MIT-LICENSE +20 -0
  9. data/README.md +210 -0
  10. data/REFERENCE.md +1380 -0
  11. data/Rakefile +116 -0
  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 +47 -0
  24. data/lib/haml/ambles.rb +20 -0
  25. data/lib/haml/attribute_builder.rb +175 -0
  26. data/lib/haml/attribute_compiler.rb +128 -0
  27. data/lib/haml/attribute_parser.rb +110 -0
  28. data/lib/haml/cli.rb +154 -0
  29. data/lib/haml/compiler/children_compiler.rb +126 -0
  30. data/lib/haml/compiler/comment_compiler.rb +39 -0
  31. data/lib/haml/compiler/doctype_compiler.rb +46 -0
  32. data/lib/haml/compiler/script_compiler.rb +116 -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 +97 -0
  36. data/lib/haml/dynamic_merger.rb +67 -0
  37. data/lib/haml/engine.rb +53 -0
  38. data/lib/haml/error.rb +16 -0
  39. data/lib/haml/escapable.rb +13 -0
  40. data/lib/haml/filters/base.rb +12 -0
  41. data/lib/haml/filters/cdata.rb +20 -0
  42. data/lib/haml/filters/coffee.rb +17 -0
  43. data/lib/haml/filters/css.rb +33 -0
  44. data/lib/haml/filters/erb.rb +10 -0
  45. data/lib/haml/filters/escaped.rb +22 -0
  46. data/lib/haml/filters/javascript.rb +33 -0
  47. data/lib/haml/filters/less.rb +20 -0
  48. data/lib/haml/filters/markdown.rb +11 -0
  49. data/lib/haml/filters/plain.rb +29 -0
  50. data/lib/haml/filters/preserve.rb +22 -0
  51. data/lib/haml/filters/ruby.rb +10 -0
  52. data/lib/haml/filters/sass.rb +15 -0
  53. data/lib/haml/filters/scss.rb +15 -0
  54. data/lib/haml/filters/text_base.rb +25 -0
  55. data/lib/haml/filters/tilt_base.rb +49 -0
  56. data/lib/haml/filters.rb +75 -0
  57. data/lib/haml/force_escapable.rb +29 -0
  58. data/lib/haml/haml_error.rb +66 -0
  59. data/lib/haml/helpers.rb +15 -0
  60. data/lib/haml/html.rb +22 -0
  61. data/lib/haml/identity.rb +13 -0
  62. data/lib/haml/object_ref.rb +30 -0
  63. data/lib/haml/parser.rb +986 -0
  64. data/lib/haml/rails_helpers.rb +51 -0
  65. data/lib/haml/rails_template.rb +55 -0
  66. data/lib/haml/railtie.rb +15 -0
  67. data/lib/haml/ruby_expression.rb +32 -0
  68. data/lib/haml/string_splitter.rb +20 -0
  69. data/lib/haml/template.rb +20 -0
  70. data/lib/haml/temple_line_counter.rb +31 -0
  71. data/lib/haml/util.rb +260 -0
  72. data/lib/haml/version.rb +4 -0
  73. data/lib/haml.rb +13 -0
  74. metadata +359 -0
@@ -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
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+ require 'tilt'
3
+
4
+ module Haml
5
+ class Filters
6
+ class TiltBase < Base
7
+ def self.render(name, source, indent_width: 0)
8
+ text = ::Tilt["t.#{name}"].new { source }.render
9
+ return text if indent_width == 0
10
+ text.gsub!(/^/, ' ' * indent_width)
11
+ end
12
+
13
+ def explicit_require?(needed_registration)
14
+ Gem::Version.new(Tilt::VERSION) >= Gem::Version.new('2.0.0') &&
15
+ !Tilt.registered?(needed_registration)
16
+ end
17
+
18
+ private
19
+
20
+ def compile_with_tilt(node, name, indent_width: 0)
21
+ if ::Haml::Util.contains_interpolation?(node.value[:text])
22
+ dynamic_compile(node, name, indent_width: indent_width)
23
+ else
24
+ static_compile(node, name, indent_width: indent_width)
25
+ end
26
+ end
27
+
28
+ def static_compile(node, name, indent_width: 0)
29
+ temple = [:multi, [:static, TiltBase.render(name, node.value[:text], indent_width: indent_width)]]
30
+ node.value[:text].split("\n").size.times do
31
+ temple << [:newline]
32
+ end
33
+ temple
34
+ end
35
+
36
+ def dynamic_compile(node, name, indent_width: 0)
37
+ # original: Haml::Filters#compile
38
+ text = ::Haml::Util.unescape_interpolation(node.value[:text]).gsub(/(\\+)n/) do |s|
39
+ escapes = $1.size
40
+ next s if escapes % 2 == 0
41
+ "#{'\\' * (escapes - 1)}\n"
42
+ end
43
+ text.prepend("\n").sub!(/\n"\z/, '"')
44
+
45
+ [:dynamic, "::Haml::Filters::TiltBase.render('#{name}', #{text}, indent_width: #{indent_width})"]
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+ require 'haml/filters/base'
3
+ require 'haml/filters/text_base'
4
+ require 'haml/filters/tilt_base'
5
+ require 'haml/filters/coffee'
6
+ require 'haml/filters/css'
7
+ require 'haml/filters/erb'
8
+ require 'haml/filters/escaped'
9
+ require 'haml/filters/javascript'
10
+ require 'haml/filters/less'
11
+ require 'haml/filters/markdown'
12
+ require 'haml/filters/plain'
13
+ require 'haml/filters/preserve'
14
+ require 'haml/filters/ruby'
15
+ require 'haml/filters/sass'
16
+ require 'haml/filters/scss'
17
+ require 'haml/filters/cdata'
18
+
19
+ module Haml
20
+ class Filters
21
+ @registered = {}
22
+
23
+ class << self
24
+ attr_reader :registered
25
+
26
+ def remove_filter(name)
27
+ registered.delete(name.to_s.downcase.to_sym)
28
+ if constants.map(&:to_s).include?(name.to_s)
29
+ remove_const name.to_sym
30
+ end
31
+ end
32
+
33
+ private
34
+
35
+ def register(name, compiler)
36
+ registered[name] = compiler
37
+ end
38
+ end
39
+
40
+ register :coffee, Coffee
41
+ register :coffeescript, CoffeeScript
42
+ register :css, Css
43
+ register :erb, Erb
44
+ register :escaped, Escaped
45
+ register :javascript, Javascript
46
+ register :less, Less
47
+ register :markdown, Markdown
48
+ register :plain, Plain
49
+ register :preserve, Preserve
50
+ register :ruby, Ruby
51
+ register :sass, Sass
52
+ register :scss, Scss
53
+ register :cdata, Cdata
54
+
55
+ def initialize(options = {})
56
+ @options = options
57
+ @compilers = {}
58
+ end
59
+
60
+ def compile(node)
61
+ node.value[:text] ||= ''
62
+ find_compiler(node).compile(node)
63
+ end
64
+
65
+ private
66
+
67
+ def find_compiler(node)
68
+ name = node.value[:name].to_sym
69
+ compiler = Filters.registered[name]
70
+ raise FilterNotFound.new("FilterCompiler for '#{name}' was not found", node.line.to_i - 1) unless compiler
71
+
72
+ @compilers[name] ||= compiler.new(@options)
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+ require 'haml/escapable'
3
+
4
+ module Haml
5
+ # This module allows Temple::Filter to dispatch :fescape on `#compile`.
6
+ module FescapeDispathcer
7
+ def on_fescape(flag, exp)
8
+ [:fescape, flag, compile(exp)]
9
+ end
10
+ end
11
+ ::Temple::Filter.include FescapeDispathcer
12
+
13
+ # Unlike Haml::Escapable, this escapes value even if it's html_safe.
14
+ class ForceEscapable < Escapable
15
+ def initialize(opts = {})
16
+ super
17
+ @escape_code = options[:escape_code] || "::Haml::Util.escape_html((%s))"
18
+ @escaper = eval("proc {|v| #{@escape_code % 'v'} }")
19
+ end
20
+
21
+ alias_method :on_fescape, :on_escape
22
+
23
+ # ForceEscapable doesn't touch :escape expression.
24
+ # This method is not used if it's inserted after Haml::Escapable.
25
+ def on_escape(flag, exp)
26
+ [:escape, flag, compile(exp)]
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Haml
4
+ # An exception raised by Haml code.
5
+ # TODO: unify Haml::Error (former Hamlit::Error) and Haml::HamlError (former Haml::Error)
6
+ class HamlError < StandardError
7
+
8
+ MESSAGES = {
9
+ bad_script_indent: '"%s" is indented at wrong level: expected %d, but was at %d.',
10
+ cant_run_filter: 'Can\'t run "%s" filter; you must require its dependencies first',
11
+ cant_use_tabs_and_spaces: "Indentation can't use both tabs and spaces.",
12
+ deeper_indenting: "The line was indented %d levels deeper than the previous line.",
13
+ filter_not_defined: 'Filter "%s" is not defined.',
14
+ gem_install_filter_deps: '"%s" filter\'s %s dependency missing: try installing it or adding it to your Gemfile',
15
+ illegal_element: "Illegal element: classes and ids must have values.",
16
+ illegal_nesting_content: "Illegal nesting: nesting within a tag that already has content is illegal.",
17
+ illegal_nesting_header: "Illegal nesting: nesting within a header command is illegal.",
18
+ illegal_nesting_line: "Illegal nesting: content can't be both given on the same line as %%%s and nested within it.",
19
+ illegal_nesting_plain: "Illegal nesting: nesting within plain text is illegal.",
20
+ illegal_nesting_self_closing: "Illegal nesting: nesting within a self-closing tag is illegal.",
21
+ inconsistent_indentation: "Inconsistent indentation: %s used for indentation, but the rest of the document was indented using %s.",
22
+ indenting_at_start: "Indenting at the beginning of the document is illegal.",
23
+ install_haml_contrib: 'To use the "%s" filter, please install the haml-contrib gem.',
24
+ invalid_attribute_list: 'Invalid attribute list: %s.',
25
+ invalid_filter_name: 'Invalid filter name ":%s".',
26
+ invalid_tag: 'Invalid tag: "%s".',
27
+ missing_if: 'Got "%s" with no preceding "if"',
28
+ no_ruby_code: "There's no Ruby code for %s to evaluate.",
29
+ self_closing_content: "Self-closing tags can't have content.",
30
+ unbalanced_brackets: 'Unbalanced brackets.',
31
+ no_end: <<-END
32
+ You don't need to use "- end" in Haml. Un-indent to close a block:
33
+ - if foo?
34
+ %strong Foo!
35
+ - else
36
+ Not foo.
37
+ %p This line is un-indented, so it isn't part of the "if" block
38
+ END
39
+ }.freeze
40
+
41
+ def self.message(key, *args)
42
+ string = MESSAGES[key] or raise "[HAML BUG] No error messages for #{key}"
43
+ (args.empty? ? string : string % args).rstrip
44
+ end
45
+
46
+ # The line of the template on which the error occurred.
47
+ #
48
+ # @return [Fixnum]
49
+ attr_reader :line
50
+
51
+ # @param message [String] The error message
52
+ # @param line [Fixnum] See \{#line}
53
+ def initialize(message = nil, line = nil)
54
+ super(message)
55
+ @line = line
56
+ end
57
+ end
58
+
59
+ # SyntaxError is the type of exception raised when Haml encounters an
60
+ # ill-formatted document.
61
+ # It's not particularly interesting,
62
+ # except in that it's a subclass of {Haml::HamlError}.
63
+ class HamlSyntaxError < HamlError; end
64
+
65
+ class HamlInvalidAttributeNameError < HamlSyntaxError; end
66
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+ module Haml
3
+ module Helpers
4
+ def self.preserve(input)
5
+ s = input.to_s.chomp("\n")
6
+ s.gsub!(/\n/, '&#x000A;')
7
+ s.delete!("\r")
8
+ s
9
+ end
10
+
11
+ def preserve(input)
12
+ Helpers.preserve(input)
13
+ end
14
+ end
15
+ end
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,30 @@
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 = underscore(object.class)
10
+ {
11
+ 'class' => [prefix, suffix].compact.join('_'),
12
+ 'id' => [prefix, suffix, object.id || 'new'].compact.join('_'),
13
+ }
14
+ end
15
+
16
+ private
17
+
18
+ # Haml::Buffer.underscore
19
+ def underscore(camel_cased_word)
20
+ word = camel_cased_word.to_s.dup
21
+ word.gsub!(/::/, '_')
22
+ word.gsub!(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
23
+ word.gsub!(/([a-z\d])([A-Z])/, '\1_\2')
24
+ word.tr!('-', '_')
25
+ word.downcase!
26
+ word
27
+ end
28
+ end
29
+ end
30
+ end