haml 6.0.0.beta.1-java
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 +7 -0
- data/.github/FUNDING.yml +1 -0
- data/.github/workflows/test.yml +40 -0
- data/.gitignore +19 -0
- data/CHANGELOG.md +1515 -0
- data/FAQ.md +147 -0
- data/Gemfile +23 -0
- data/MIT-LICENSE +20 -0
- data/README.md +210 -0
- data/REFERENCE.md +1380 -0
- data/Rakefile +116 -0
- data/bin/bench +66 -0
- data/bin/console +11 -0
- data/bin/ruby +3 -0
- data/bin/setup +7 -0
- data/bin/stackprof +27 -0
- data/bin/test +24 -0
- data/exe/haml +6 -0
- data/ext/haml/extconf.rb +10 -0
- data/ext/haml/haml.c +537 -0
- data/ext/haml/hescape.c +108 -0
- data/ext/haml/hescape.h +20 -0
- data/haml.gemspec +47 -0
- data/lib/haml/ambles.rb +20 -0
- data/lib/haml/attribute_builder.rb +175 -0
- data/lib/haml/attribute_compiler.rb +128 -0
- data/lib/haml/attribute_parser.rb +110 -0
- data/lib/haml/cli.rb +154 -0
- data/lib/haml/compiler/children_compiler.rb +126 -0
- data/lib/haml/compiler/comment_compiler.rb +39 -0
- data/lib/haml/compiler/doctype_compiler.rb +46 -0
- data/lib/haml/compiler/script_compiler.rb +116 -0
- data/lib/haml/compiler/silent_script_compiler.rb +24 -0
- data/lib/haml/compiler/tag_compiler.rb +76 -0
- data/lib/haml/compiler.rb +97 -0
- data/lib/haml/dynamic_merger.rb +67 -0
- data/lib/haml/engine.rb +53 -0
- data/lib/haml/error.rb +16 -0
- data/lib/haml/escapable.rb +13 -0
- data/lib/haml/filters/base.rb +12 -0
- data/lib/haml/filters/cdata.rb +20 -0
- data/lib/haml/filters/coffee.rb +17 -0
- data/lib/haml/filters/css.rb +33 -0
- data/lib/haml/filters/erb.rb +10 -0
- data/lib/haml/filters/escaped.rb +22 -0
- data/lib/haml/filters/javascript.rb +33 -0
- data/lib/haml/filters/less.rb +20 -0
- data/lib/haml/filters/markdown.rb +11 -0
- data/lib/haml/filters/plain.rb +29 -0
- data/lib/haml/filters/preserve.rb +22 -0
- data/lib/haml/filters/ruby.rb +10 -0
- data/lib/haml/filters/sass.rb +15 -0
- data/lib/haml/filters/scss.rb +15 -0
- data/lib/haml/filters/text_base.rb +25 -0
- data/lib/haml/filters/tilt_base.rb +49 -0
- data/lib/haml/filters.rb +75 -0
- data/lib/haml/force_escapable.rb +29 -0
- data/lib/haml/haml_error.rb +66 -0
- data/lib/haml/helpers.rb +15 -0
- data/lib/haml/html.rb +22 -0
- data/lib/haml/identity.rb +13 -0
- data/lib/haml/object_ref.rb +30 -0
- data/lib/haml/parser.rb +986 -0
- data/lib/haml/rails_helpers.rb +51 -0
- data/lib/haml/rails_template.rb +55 -0
- data/lib/haml/railtie.rb +15 -0
- data/lib/haml/ruby_expression.rb +32 -0
- data/lib/haml/string_splitter.rb +20 -0
- data/lib/haml/template.rb +20 -0
- data/lib/haml/temple_line_counter.rb +31 -0
- data/lib/haml/util.rb +260 -0
- data/lib/haml/version.rb +4 -0
- data/lib/haml.rb +13 -0
- 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,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", '
')
|
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,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
|
data/lib/haml/filters.rb
ADDED
@@ -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
|
data/lib/haml/helpers.rb
ADDED
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,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
|