hamlit 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|