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.
- checksums.yaml +7 -0
- data/.gitignore +16 -0
- data/.rspec +2 -0
- data/.travis.yml +34 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +23 -0
- data/README.md +45 -0
- data/Rakefile +34 -0
- data/benchmarks/benchmark.rb +94 -0
- data/benchmarks/context.rb +13 -0
- data/benchmarks/view.erb +23 -0
- data/benchmarks/view.haml +18 -0
- data/benchmarks/view.rbhtml +23 -0
- data/benchmarks/view.slim +17 -0
- data/bin/hamlit +6 -0
- data/hamlit.gemspec +40 -0
- data/lib/hamlit/attribute.rb +31 -0
- data/lib/hamlit/cli.rb +89 -0
- data/lib/hamlit/compiler.rb +24 -0
- data/lib/hamlit/compilers/attributes.rb +78 -0
- data/lib/hamlit/compilers/comment.rb +13 -0
- data/lib/hamlit/compilers/doctype.rb +39 -0
- data/lib/hamlit/compilers/dynamic.rb +9 -0
- data/lib/hamlit/compilers/filter.rb +53 -0
- data/lib/hamlit/compilers/new_attribute.rb +107 -0
- data/lib/hamlit/compilers/old_attribute.rb +147 -0
- data/lib/hamlit/compilers/preserve.rb +10 -0
- data/lib/hamlit/compilers/script.rb +31 -0
- data/lib/hamlit/compilers/strip.rb +30 -0
- data/lib/hamlit/compilers/text.rb +15 -0
- data/lib/hamlit/concerns/attribute_builder.rb +21 -0
- data/lib/hamlit/concerns/balanceable.rb +59 -0
- data/lib/hamlit/concerns/deprecation.rb +20 -0
- data/lib/hamlit/concerns/error.rb +27 -0
- data/lib/hamlit/concerns/escapable.rb +17 -0
- data/lib/hamlit/concerns/included.rb +28 -0
- data/lib/hamlit/concerns/indentable.rb +53 -0
- data/lib/hamlit/concerns/line_reader.rb +60 -0
- data/lib/hamlit/concerns/registerable.rb +24 -0
- data/lib/hamlit/concerns/ripperable.rb +20 -0
- data/lib/hamlit/concerns/string_interpolation.rb +48 -0
- data/lib/hamlit/engine.rb +42 -0
- data/lib/hamlit/filters/base.rb +44 -0
- data/lib/hamlit/filters/coffee.rb +12 -0
- data/lib/hamlit/filters/css.rb +34 -0
- data/lib/hamlit/filters/erb.rb +11 -0
- data/lib/hamlit/filters/escaped.rb +19 -0
- data/lib/hamlit/filters/javascript.rb +34 -0
- data/lib/hamlit/filters/less.rb +12 -0
- data/lib/hamlit/filters/markdown.rb +11 -0
- data/lib/hamlit/filters/plain.rb +21 -0
- data/lib/hamlit/filters/preserve.rb +11 -0
- data/lib/hamlit/filters/ruby.rb +11 -0
- data/lib/hamlit/filters/sass.rb +12 -0
- data/lib/hamlit/filters/scss.rb +12 -0
- data/lib/hamlit/filters/tilt.rb +41 -0
- data/lib/hamlit/helpers.rb +38 -0
- data/lib/hamlit/html/pretty.rb +49 -0
- data/lib/hamlit/html/ugly.rb +10 -0
- data/lib/hamlit/parser.rb +123 -0
- data/lib/hamlit/parsers/attribute.rb +52 -0
- data/lib/hamlit/parsers/comment.rb +27 -0
- data/lib/hamlit/parsers/doctype.rb +18 -0
- data/lib/hamlit/parsers/filter.rb +18 -0
- data/lib/hamlit/parsers/multiline.rb +54 -0
- data/lib/hamlit/parsers/script.rb +93 -0
- data/lib/hamlit/parsers/tag.rb +71 -0
- data/lib/hamlit/parsers/text.rb +11 -0
- data/lib/hamlit/parsers/whitespace.rb +38 -0
- data/lib/hamlit/railtie.rb +21 -0
- data/lib/hamlit/template.rb +9 -0
- data/lib/hamlit/version.rb +3 -0
- data/lib/hamlit.rb +8 -0
- data/spec/Rakefile +79 -0
- data/spec/hamlit/compilers/script_spec.rb +46 -0
- data/spec/hamlit/engine/comment_spec.rb +29 -0
- data/spec/hamlit/engine/doctype_spec.rb +19 -0
- data/spec/hamlit/engine/error_spec.rb +47 -0
- data/spec/hamlit/engine/multiline_spec.rb +44 -0
- data/spec/hamlit/engine/new_attribute_spec.rb +19 -0
- data/spec/hamlit/engine/old_attributes_spec.rb +85 -0
- data/spec/hamlit/engine/preservation_spec.rb +11 -0
- data/spec/hamlit/engine/script_spec.rb +87 -0
- data/spec/hamlit/engine/silent_script_spec.rb +135 -0
- data/spec/hamlit/engine/tag_spec.rb +210 -0
- data/spec/hamlit/engine/text_spec.rb +29 -0
- data/spec/hamlit/engine_spec.rb +20 -0
- data/spec/hamlit/filters/coffee_spec.rb +41 -0
- data/spec/hamlit/filters/css_spec.rb +33 -0
- data/spec/hamlit/filters/erb_spec.rb +16 -0
- data/spec/hamlit/filters/javascript_spec.rb +82 -0
- data/spec/hamlit/filters/less_spec.rb +22 -0
- data/spec/hamlit/filters/markdown_spec.rb +28 -0
- data/spec/hamlit/filters/ruby_spec.rb +24 -0
- data/spec/hamlit/filters/sass_spec.rb +37 -0
- data/spec/hamlit/filters/scss_spec.rb +21 -0
- data/spec/hamlit/ugly_spec.rb +912 -0
- data/spec/rails/.gitignore +17 -0
- data/spec/rails/.rspec +2 -0
- data/spec/rails/Gemfile +19 -0
- data/spec/rails/Gemfile.lock +177 -0
- data/spec/rails/README.rdoc +28 -0
- data/spec/rails/Rakefile +6 -0
- data/spec/rails/app/assets/images/.keep +0 -0
- data/spec/rails/app/assets/javascripts/application.js +15 -0
- data/spec/rails/app/assets/stylesheets/application.css +15 -0
- data/spec/rails/app/controllers/application_controller.rb +8 -0
- data/spec/rails/app/controllers/concerns/.keep +0 -0
- data/spec/rails/app/controllers/users_controller.rb +20 -0
- data/spec/rails/app/helpers/application_helper.rb +2 -0
- data/spec/rails/app/mailers/.keep +0 -0
- data/spec/rails/app/models/.keep +0 -0
- data/spec/rails/app/models/concerns/.keep +0 -0
- data/spec/rails/app/views/application/index.html.haml +15 -0
- data/spec/rails/app/views/layouts/application.html.haml +12 -0
- data/spec/rails/app/views/users/capture.html.haml +5 -0
- data/spec/rails/app/views/users/capture_haml.html.haml +5 -0
- data/spec/rails/app/views/users/form.html.haml +2 -0
- data/spec/rails/app/views/users/helpers.html.haml +1 -0
- data/spec/rails/app/views/users/index.html.haml +9 -0
- data/spec/rails/app/views/users/safe_buffer.html.haml +4 -0
- data/spec/rails/bin/bundle +3 -0
- data/spec/rails/bin/rails +8 -0
- data/spec/rails/bin/rake +8 -0
- data/spec/rails/bin/setup +29 -0
- data/spec/rails/bin/spring +15 -0
- data/spec/rails/config/application.rb +34 -0
- data/spec/rails/config/boot.rb +3 -0
- data/spec/rails/config/database.yml +25 -0
- data/spec/rails/config/environment.rb +5 -0
- data/spec/rails/config/environments/development.rb +41 -0
- data/spec/rails/config/environments/production.rb +79 -0
- data/spec/rails/config/environments/test.rb +42 -0
- data/spec/rails/config/initializers/assets.rb +11 -0
- data/spec/rails/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/rails/config/initializers/cookies_serializer.rb +3 -0
- data/spec/rails/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/rails/config/initializers/inflections.rb +16 -0
- data/spec/rails/config/initializers/mime_types.rb +4 -0
- data/spec/rails/config/initializers/session_store.rb +3 -0
- data/spec/rails/config/initializers/wrap_parameters.rb +14 -0
- data/spec/rails/config/locales/en.yml +23 -0
- data/spec/rails/config/routes.rb +13 -0
- data/spec/rails/config/secrets.yml +22 -0
- data/spec/rails/config.ru +4 -0
- data/spec/rails/db/schema.rb +16 -0
- data/spec/rails/db/seeds.rb +7 -0
- data/spec/rails/lib/assets/.keep +0 -0
- data/spec/rails/lib/tasks/.keep +0 -0
- data/spec/rails/log/.keep +0 -0
- data/spec/rails/public/404.html +67 -0
- data/spec/rails/public/422.html +67 -0
- data/spec/rails/public/500.html +66 -0
- data/spec/rails/public/favicon.ico +0 -0
- data/spec/rails/public/robots.txt +5 -0
- data/spec/rails/spec/hamlit_spec.rb +87 -0
- data/spec/rails/spec/rails_helper.rb +56 -0
- data/spec/rails/spec/spec_helper.rb +91 -0
- data/spec/rails/vendor/assets/javascripts/.keep +0 -0
- data/spec/rails/vendor/assets/stylesheets/.keep +0 -0
- data/spec/spec_helper.rb +48 -0
- metadata +560 -0
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
module Hamlit
|
|
2
|
+
module Compilers
|
|
3
|
+
module Doctype
|
|
4
|
+
def on_haml_doctype(format, type)
|
|
5
|
+
if type == 'XML'
|
|
6
|
+
return xml_doctype_tag(format)
|
|
7
|
+
elsif type
|
|
8
|
+
return doctype_tag(type)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
case format
|
|
12
|
+
when :html4
|
|
13
|
+
doctype_tag(:transitional)
|
|
14
|
+
when :html5
|
|
15
|
+
doctype_tag(:html)
|
|
16
|
+
when :xhtml
|
|
17
|
+
doctype_tag(:transitional)
|
|
18
|
+
else
|
|
19
|
+
doctype_tag(format)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
def xml_doctype_tag(format)
|
|
26
|
+
case format
|
|
27
|
+
when :html4, :html5
|
|
28
|
+
[:multi]
|
|
29
|
+
else
|
|
30
|
+
[:multi, [:static, "<?xml version='1.0' encoding='utf-8' ?>"], [:static, "\n"]]
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def doctype_tag(type)
|
|
35
|
+
[:multi, [:html, :doctype, type.to_s], [:static, "\n"]]
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
require 'hamlit/concerns/included'
|
|
2
|
+
require 'hamlit/concerns/registerable'
|
|
3
|
+
require 'hamlit/filters/coffee'
|
|
4
|
+
require 'hamlit/filters/css'
|
|
5
|
+
require 'hamlit/filters/erb'
|
|
6
|
+
require 'hamlit/filters/escaped'
|
|
7
|
+
require 'hamlit/filters/javascript'
|
|
8
|
+
require 'hamlit/filters/less'
|
|
9
|
+
require 'hamlit/filters/plain'
|
|
10
|
+
require 'hamlit/filters/preserve'
|
|
11
|
+
require 'hamlit/filters/ruby'
|
|
12
|
+
require 'hamlit/filters/sass'
|
|
13
|
+
require 'hamlit/filters/markdown'
|
|
14
|
+
require 'hamlit/filters/scss'
|
|
15
|
+
|
|
16
|
+
module Hamlit
|
|
17
|
+
module Compilers
|
|
18
|
+
module Filter
|
|
19
|
+
extend Concerns::Included
|
|
20
|
+
|
|
21
|
+
included do
|
|
22
|
+
extend Concerns::Registerable
|
|
23
|
+
|
|
24
|
+
define_options :format
|
|
25
|
+
|
|
26
|
+
register :coffee, Filters::Coffee
|
|
27
|
+
register :coffeescript, Filters::Coffee
|
|
28
|
+
register :css, Filters::Css
|
|
29
|
+
register :erb, Filters::Erb
|
|
30
|
+
register :escaped, Filters::Escaped
|
|
31
|
+
register :javascript, Filters::Javascript
|
|
32
|
+
register :less, Filters::Less
|
|
33
|
+
register :markdown, Filters::Markdown
|
|
34
|
+
register :plain, Filters::Plain
|
|
35
|
+
register :preserve, Filters::Preserve
|
|
36
|
+
register :ruby, Filters::Ruby
|
|
37
|
+
register :sass, Filters::Sass
|
|
38
|
+
register :scss, Filters::Scss
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def on_haml_filter(name, lines)
|
|
42
|
+
ast = compile_filter(name, lines)
|
|
43
|
+
compile(ast)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
private
|
|
47
|
+
|
|
48
|
+
def compile_filter(name, exp)
|
|
49
|
+
self.class.find(name).new(options).compile(exp)
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
require 'hamlit/concerns/ripperable'
|
|
2
|
+
|
|
3
|
+
# This module compiles new-style attributes, which is
|
|
4
|
+
# surrounded by parentheses.
|
|
5
|
+
module Hamlit
|
|
6
|
+
module Compilers
|
|
7
|
+
module NewAttribute
|
|
8
|
+
include Concerns::Ripperable
|
|
9
|
+
|
|
10
|
+
def compile_new_attribute(str)
|
|
11
|
+
str = str.gsub(/\A\(|\)\Z/, '')
|
|
12
|
+
attrs = parse_new_attributes(str)
|
|
13
|
+
attrs.map do |key, value|
|
|
14
|
+
next true_attribute(key) if value == 'true'
|
|
15
|
+
[:html, :attr, key, [:dynamic, value]]
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
def parse_new_attributes(str)
|
|
22
|
+
attributes = {}
|
|
23
|
+
|
|
24
|
+
while str.length > 0
|
|
25
|
+
tokens = Ripper.lex(str)
|
|
26
|
+
key = read_key!(tokens)
|
|
27
|
+
val = read_value!(tokens)
|
|
28
|
+
if key && val
|
|
29
|
+
attributes[key] = val
|
|
30
|
+
elsif key
|
|
31
|
+
attributes[key] = 'true'
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
token = tokens.first
|
|
35
|
+
break unless token
|
|
36
|
+
|
|
37
|
+
pos = token.first.last
|
|
38
|
+
str = str[pos..-1]
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
attributes
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def read_key!(tokens)
|
|
45
|
+
skip_tokens!(tokens, :on_sp)
|
|
46
|
+
(row, col), type, key = tokens.shift
|
|
47
|
+
key
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def read_value!(tokens)
|
|
51
|
+
skip_tokens!(tokens, :on_sp)
|
|
52
|
+
(row, col), type, str = tokens.shift
|
|
53
|
+
return nil if str != '='
|
|
54
|
+
|
|
55
|
+
skip_tokens!(tokens, :on_sp)
|
|
56
|
+
return if tokens.empty?
|
|
57
|
+
|
|
58
|
+
case tokens.first[TYPE_POSITION]
|
|
59
|
+
when :on_tstring_beg
|
|
60
|
+
val = fetch_balanced_quotes(tokens)
|
|
61
|
+
else
|
|
62
|
+
val = fetch_until(tokens, :on_sp)
|
|
63
|
+
end
|
|
64
|
+
val.length.times { tokens.shift }
|
|
65
|
+
val.map(&:last).join
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def fetch_balanced_quotes(all_tokens)
|
|
69
|
+
tokens = []
|
|
70
|
+
open_count = 0
|
|
71
|
+
|
|
72
|
+
all_tokens.each do |token|
|
|
73
|
+
(row, col), type, str = token
|
|
74
|
+
case type
|
|
75
|
+
when :on_tstring_beg then open_count += 1
|
|
76
|
+
when :on_tstring_end then open_count -= 1
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
tokens << token
|
|
80
|
+
break if open_count == 0
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
tokens
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def fetch_until(all_tokens, type)
|
|
87
|
+
tokens = []
|
|
88
|
+
|
|
89
|
+
all_tokens.each do |token|
|
|
90
|
+
break if token[TYPE_POSITION] == type
|
|
91
|
+
tokens << token
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
tokens
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def true_attribute(key)
|
|
98
|
+
case options[:format]
|
|
99
|
+
when :xhtml
|
|
100
|
+
[:html, :attr, key, [:static, key]]
|
|
101
|
+
else
|
|
102
|
+
[:html, :attr, key, [:multi]]
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
require 'hamlit/attribute'
|
|
2
|
+
require 'hamlit/concerns/attribute_builder'
|
|
3
|
+
require 'hamlit/concerns/balanceable'
|
|
4
|
+
require 'hamlit/concerns/ripperable'
|
|
5
|
+
|
|
6
|
+
# This module compiles only old-style attribute, which is
|
|
7
|
+
# surrounded by brackets.
|
|
8
|
+
module Hamlit
|
|
9
|
+
module Compilers
|
|
10
|
+
module OldAttribute
|
|
11
|
+
include Concerns::AttributeBuilder
|
|
12
|
+
include Concerns::Balanceable
|
|
13
|
+
include Concerns::Ripperable
|
|
14
|
+
|
|
15
|
+
def compile_old_attribute(str)
|
|
16
|
+
return runtime_build(str) unless Ripper.sexp(str)
|
|
17
|
+
|
|
18
|
+
attrs = parse_old_attributes(str)
|
|
19
|
+
flatten_attributes(attrs).map do |key, value|
|
|
20
|
+
next true_attribute(key) if value == 'true'
|
|
21
|
+
[:html, :attr, key, [:dynamic, value]]
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
# Parse brace-balanced string and return the result as hash
|
|
28
|
+
def parse_old_attributes(str)
|
|
29
|
+
attributes = {}
|
|
30
|
+
|
|
31
|
+
split_hash(str).each do |attr|
|
|
32
|
+
tokens = Ripper.lex("{#{attr}")
|
|
33
|
+
tokens = tokens.drop(1)
|
|
34
|
+
|
|
35
|
+
key = read_hash_key!(tokens)
|
|
36
|
+
val = tokens.map(&:last).join.strip
|
|
37
|
+
|
|
38
|
+
skip_tokens!(tokens, :on_sp)
|
|
39
|
+
if type_of(tokens.first) == :on_lbrace
|
|
40
|
+
val = parse_old_attributes(val)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
attributes[key] = val if key
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
attributes
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def read_hash_key!(tokens)
|
|
50
|
+
skip_tokens!(tokens, :on_sp)
|
|
51
|
+
|
|
52
|
+
(row, col), type, str = tokens.shift
|
|
53
|
+
case type
|
|
54
|
+
when :on_label
|
|
55
|
+
str.gsub!(/:\Z/, '')
|
|
56
|
+
when :on_symbeg
|
|
57
|
+
if %w[:" :'].include?(str)
|
|
58
|
+
str = read_string!(tokens)
|
|
59
|
+
else
|
|
60
|
+
(row, col), type, str = tokens.shift
|
|
61
|
+
end
|
|
62
|
+
assert_rocket!(tokens)
|
|
63
|
+
when :on_tstring_beg
|
|
64
|
+
str = read_string!(tokens)
|
|
65
|
+
assert_rocket!(tokens)
|
|
66
|
+
end
|
|
67
|
+
str
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def read_string!(tokens)
|
|
71
|
+
(row, col), type, str = tokens.shift
|
|
72
|
+
return '' if type == :on_tstring_end
|
|
73
|
+
|
|
74
|
+
raise SyntaxError if type_of(tokens.shift) != :on_tstring_end
|
|
75
|
+
str
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def assert_rocket!(tokens, *types)
|
|
79
|
+
skip_tokens!(tokens, :on_sp)
|
|
80
|
+
(row, col), type, str = tokens.shift
|
|
81
|
+
|
|
82
|
+
raise SyntaxError unless type == :on_op && str == '=>'
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def runtime_build(str)
|
|
86
|
+
str = str.gsub(/(\A\{|\}\Z)/, '')
|
|
87
|
+
quote = options[:attr_quote].inspect
|
|
88
|
+
code = "::Hamlit::Attribute.build(#{quote}, #{str})"
|
|
89
|
+
[[:dynamic, code]]
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def split_hash(str)
|
|
93
|
+
columns = HashParser.assoc_columns(str)
|
|
94
|
+
columns = reject_nested_columns(str, columns)
|
|
95
|
+
|
|
96
|
+
splitted = []
|
|
97
|
+
start_pos = 1
|
|
98
|
+
columns.each do |end_pos|
|
|
99
|
+
splitted << str[start_pos..(end_pos - 1)]
|
|
100
|
+
start_pos = end_pos + 1
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
splitted
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def reject_nested_columns(str, columns)
|
|
107
|
+
result = []
|
|
108
|
+
open_count = 0
|
|
109
|
+
|
|
110
|
+
Ripper.lex(str).each do |(row, col), type, str|
|
|
111
|
+
if columns.include?(col) && open_count == 1
|
|
112
|
+
result << col
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
case type
|
|
116
|
+
when :on_lbrace
|
|
117
|
+
open_count += 1
|
|
118
|
+
when :on_rbrace
|
|
119
|
+
open_count -= 1
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
result
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
class HashParser < Ripper
|
|
126
|
+
attr_reader :columns
|
|
127
|
+
|
|
128
|
+
def self.assoc_columns(src)
|
|
129
|
+
parser = new(src)
|
|
130
|
+
parser.parse
|
|
131
|
+
parser.columns
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def initialize(src)
|
|
135
|
+
super(src)
|
|
136
|
+
@columns = []
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
private
|
|
140
|
+
|
|
141
|
+
def on_assoc_new(*args)
|
|
142
|
+
@columns << column - 1
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
require 'hamlit/concerns/escapable'
|
|
2
|
+
require 'hamlit/concerns/included'
|
|
3
|
+
|
|
4
|
+
module Hamlit
|
|
5
|
+
module Compilers
|
|
6
|
+
module Script
|
|
7
|
+
extend Concerns::Included
|
|
8
|
+
|
|
9
|
+
included do
|
|
10
|
+
include Concerns::Escapable
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def on_haml_script(code, options, *exps)
|
|
14
|
+
variable = result_identifier
|
|
15
|
+
|
|
16
|
+
assign = [:code, "#{variable} = #{code}"]
|
|
17
|
+
result = escape_html([:dynamic, variable], options[:force_escape])
|
|
18
|
+
result = [:dynamic, variable] if options[:disable_escape]
|
|
19
|
+
[:multi, assign, *exps.map { |exp| compile(exp) }, compile(result)]
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
|
|
24
|
+
def result_identifier
|
|
25
|
+
@id_auto_increment ||= -1
|
|
26
|
+
@id_auto_increment += 1
|
|
27
|
+
"_hamlit_compiler#{@id_auto_increment}"
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
module Hamlit
|
|
2
|
+
module Compilers
|
|
3
|
+
module Strip
|
|
4
|
+
def on_haml_strip(*exps)
|
|
5
|
+
stripped = strip_newline(exps)
|
|
6
|
+
on_multi(*stripped)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
private
|
|
10
|
+
|
|
11
|
+
def strip_newline(content)
|
|
12
|
+
indexes = newline_indexes(content)
|
|
13
|
+
return content if indexes.length < 2
|
|
14
|
+
|
|
15
|
+
content = content.dup
|
|
16
|
+
content.delete_at(indexes.last)
|
|
17
|
+
content.delete_at(indexes.first)
|
|
18
|
+
content
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def newline_indexes(exps)
|
|
22
|
+
indexes = []
|
|
23
|
+
exps.each_with_index do |exp, index|
|
|
24
|
+
indexes << index if exp == [:static, "\n"]
|
|
25
|
+
end
|
|
26
|
+
indexes
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
require 'hamlit/concerns/string_interpolation'
|
|
2
|
+
|
|
3
|
+
module Hamlit
|
|
4
|
+
module Compilers
|
|
5
|
+
module Text
|
|
6
|
+
include Concerns::StringInterpolation
|
|
7
|
+
|
|
8
|
+
def on_haml_text(exp)
|
|
9
|
+
return [:static, exp] unless contains_interpolation?(exp)
|
|
10
|
+
|
|
11
|
+
[:dynamic, string_literal(exp)]
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module Hamlit
|
|
2
|
+
module Concerns
|
|
3
|
+
module AttributeBuilder
|
|
4
|
+
def flatten_attributes(attributes)
|
|
5
|
+
flattened = {}
|
|
6
|
+
|
|
7
|
+
attributes.each do |key, value|
|
|
8
|
+
case value
|
|
9
|
+
when Hash
|
|
10
|
+
flatten_attributes(value).each do |k, v|
|
|
11
|
+
flattened["#{key}-#{k}"] = v
|
|
12
|
+
end
|
|
13
|
+
else
|
|
14
|
+
flattened[key] = value
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
flattened
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
require 'ripper'
|
|
2
|
+
|
|
3
|
+
module Hamlit
|
|
4
|
+
module Concerns
|
|
5
|
+
module Balanceable
|
|
6
|
+
def fetch_balanced_braces(all_tokens)
|
|
7
|
+
fetch_balanced_tokens(all_tokens, :on_lbrace, :on_rbrace)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def fetch_balanced_parentheses(all_tokens)
|
|
11
|
+
fetch_balanced_tokens(all_tokens, :on_lparen, :on_rparen)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def balanced_braces_exist?(tokens)
|
|
15
|
+
balanced_tokens_exist?(tokens, :on_lbrace, :on_rbrace)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def balanced_parens_exist?(tokens)
|
|
19
|
+
balanced_tokens_exist?(tokens, :on_lparen, :on_rparen)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
|
|
24
|
+
def fetch_balanced_tokens(all_tokens, open_token, close_token)
|
|
25
|
+
tokens = []
|
|
26
|
+
open_count = 0
|
|
27
|
+
|
|
28
|
+
all_tokens.each_with_index do |token, index|
|
|
29
|
+
(row, col), type, str = token
|
|
30
|
+
case type
|
|
31
|
+
when open_token then open_count += 1
|
|
32
|
+
when close_token then open_count -= 1
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
tokens << token
|
|
36
|
+
break if open_count == 0
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
tokens
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def balanced_tokens_exist?(tokens, open_token, close_token)
|
|
43
|
+
open_count = 0
|
|
44
|
+
|
|
45
|
+
tokens.each do |token|
|
|
46
|
+
(row, col), type, str = token
|
|
47
|
+
case type
|
|
48
|
+
when open_token then open_count += 1
|
|
49
|
+
when close_token then open_count -= 1
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
break if open_count == 0
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
open_count == 0
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# A module to suppress deprecation warnings by temple.
|
|
2
|
+
# These deprecated options are specified in haml-spec.
|
|
3
|
+
module Hamlit
|
|
4
|
+
module Concerns
|
|
5
|
+
module Deprecation
|
|
6
|
+
DEPCATED_OPTIONS = %i[html4 html5].freeze
|
|
7
|
+
|
|
8
|
+
def initialize(opts = {})
|
|
9
|
+
super rewrite_deprecated_options(opts)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# Temple's warning is noisy in haml-spec.
|
|
13
|
+
def rewrite_deprecated_options(options)
|
|
14
|
+
options = options.dup
|
|
15
|
+
options[:format] = :html if DEPCATED_OPTIONS.include?(options[:format])
|
|
16
|
+
options
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
module Hamlit
|
|
2
|
+
class SyntaxError < StandardError; end
|
|
3
|
+
class CompileError < StandardError; end
|
|
4
|
+
|
|
5
|
+
module Concerns
|
|
6
|
+
module Error
|
|
7
|
+
# Template engine should raise Exception on runtime to
|
|
8
|
+
# show template's error backtrace.
|
|
9
|
+
def syntax_error(message)
|
|
10
|
+
code = %Q{raise Hamlit::SyntaxError.new(%q{#{message}})}
|
|
11
|
+
[:code, code]
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def assert!(message)
|
|
15
|
+
raise CompileError.new(message)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def assert_scan!(scanner, regexp)
|
|
19
|
+
result = scanner.scan(regexp)
|
|
20
|
+
unless result
|
|
21
|
+
raise CompileError.new("Expected to scan #{regexp} but got nil")
|
|
22
|
+
end
|
|
23
|
+
result
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
require 'hamlit/concerns/included'
|
|
2
|
+
|
|
3
|
+
module Hamlit
|
|
4
|
+
module Concerns
|
|
5
|
+
module Escapable
|
|
6
|
+
extend Included
|
|
7
|
+
|
|
8
|
+
included do
|
|
9
|
+
define_options escape_html: false
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def escape_html(exp, force_escape = false)
|
|
13
|
+
[:escape, force_escape || @options[:escape_html], exp]
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Mini ActiveSupport::Concern
|
|
2
|
+
module Hamlit
|
|
3
|
+
module Concerns
|
|
4
|
+
class MultipleIncludedBlocks < StandardError
|
|
5
|
+
def initialize
|
|
6
|
+
super "Cannot define multiple 'included' blocks for a Concern"
|
|
7
|
+
end
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
module Included
|
|
11
|
+
def self.extended(klass)
|
|
12
|
+
klass.class_eval do
|
|
13
|
+
def self.included(base = nil, &block)
|
|
14
|
+
if block_given?
|
|
15
|
+
raise MultipleIncludedBlocks if defined?(@_included_block)
|
|
16
|
+
|
|
17
|
+
@_included_block = block
|
|
18
|
+
return
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
base.instance_exec(&@_included_block) if defined?(@_included_block)
|
|
22
|
+
super
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
require 'hamlit/concerns/error'
|
|
2
|
+
|
|
3
|
+
module Hamlit
|
|
4
|
+
EOF = -1
|
|
5
|
+
|
|
6
|
+
module Concerns
|
|
7
|
+
module Indentable
|
|
8
|
+
include Concerns::Error
|
|
9
|
+
|
|
10
|
+
def reset_indent
|
|
11
|
+
@current_indent = 0
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Return nearest line's indent level since next line. This method ignores
|
|
15
|
+
# empty line. It returns -1 if next_line does not exist.
|
|
16
|
+
def next_indent
|
|
17
|
+
count_indent(next_line)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def next_width
|
|
21
|
+
count_width(next_line)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def with_indented(&block)
|
|
25
|
+
@current_indent += 1
|
|
26
|
+
result = block.call
|
|
27
|
+
@current_indent -= 1
|
|
28
|
+
|
|
29
|
+
result
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def count_indent(line, strict: false)
|
|
33
|
+
return EOF unless line
|
|
34
|
+
width = count_width(line)
|
|
35
|
+
|
|
36
|
+
return (width + 1) / 2 unless strict
|
|
37
|
+
assert!('Expected to count even-width indent') if width.odd?
|
|
38
|
+
|
|
39
|
+
width / 2
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def count_width(line)
|
|
43
|
+
return EOF unless line
|
|
44
|
+
line[/\A +/].to_s.length
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def same_indent?(line)
|
|
48
|
+
return false unless line
|
|
49
|
+
count_indent(line) == @current_indent
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|