faml 0.2.16 → 0.3.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 +4 -4
- data/CHANGELOG.md +5 -0
- data/README.md +3 -3
- data/faml.gemspec +1 -0
- data/incompatibilities/README.md +4 -5
- data/incompatibilities/spec/render/attribute_spec.md +13 -219
- data/incompatibilities/spec/render/comment_spec.md +0 -23
- data/incompatibilities/spec/render/element_spec.md +1 -1
- data/incompatibilities/spec/render/newline_spec.md +0 -17
- data/lib/faml/cli.rb +1 -7
- data/lib/faml/compiler.rb +21 -23
- data/lib/faml/engine.rb +2 -2
- data/lib/faml/text_compiler.rb +2 -2
- data/lib/faml/version.rb +1 -1
- data/spec/rails/spec/requests/faml_spec.rb +2 -2
- data/spec/render/attribute_spec.rb +0 -114
- data/spec/render/comment_spec.rb +0 -11
- data/spec/render/doctype_spec.rb +0 -7
- data/spec/render/element_spec.rb +0 -57
- data/spec/render/filters_spec.rb +0 -4
- data/spec/render/plain_spec.rb +0 -7
- data/spec/render/sanitize_spec.rb +0 -7
- data/spec/render/script_spec.rb +0 -23
- data/spec/render/unescape_spec.rb +0 -7
- metadata +17 -15
- data/lib/faml/ast.rb +0 -116
- data/lib/faml/element_parser.rb +0 -235
- data/lib/faml/filter_parser.rb +0 -56
- data/lib/faml/indent_tracker.rb +0 -116
- data/lib/faml/line_parser.rb +0 -67
- data/lib/faml/parser.rb +0 -240
- data/lib/faml/parser_utils.rb +0 -17
- data/lib/faml/ruby_multiline.rb +0 -23
- data/lib/faml/script_parser.rb +0 -106
- data/lib/faml/syntax_error.rb +0 -6
- data/spec/render/indent_spec.rb +0 -47
|
@@ -35,11 +35,4 @@ HAML
|
|
|
35
35
|
expect(render_string('%span!~ "<p>hello\n<pre>pre\nworld</pre></p>"')).to eq("<span><p>hello\n<pre>pre
world</pre></p></span>\n")
|
|
36
36
|
end
|
|
37
37
|
end
|
|
38
|
-
|
|
39
|
-
context 'without Ruby code' do
|
|
40
|
-
it 'raises error' do
|
|
41
|
-
expect { render_string('%span!=') }.to raise_error(Faml::SyntaxError)
|
|
42
|
-
expect { render_string('!=') }.to raise_error(Faml::SyntaxError)
|
|
43
|
-
end
|
|
44
|
-
end
|
|
45
38
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: faml
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Kohei Suzuki
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2015-
|
|
11
|
+
date: 2015-09-13 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: escape_utils
|
|
@@ -24,6 +24,20 @@ dependencies:
|
|
|
24
24
|
- - ">="
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
26
|
version: '0'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: haml_parser
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - ">="
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: 0.1.0
|
|
34
|
+
type: :runtime
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - ">="
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: 0.1.0
|
|
27
41
|
- !ruby/object:Gem::Dependency
|
|
28
42
|
name: parser
|
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -319,10 +333,8 @@ files:
|
|
|
319
333
|
- incompatibilities/spec/render/silent_script_spec.md
|
|
320
334
|
- incompatibilities/spec/render/unescape_spec.md
|
|
321
335
|
- lib/faml.rb
|
|
322
|
-
- lib/faml/ast.rb
|
|
323
336
|
- lib/faml/cli.rb
|
|
324
337
|
- lib/faml/compiler.rb
|
|
325
|
-
- lib/faml/element_parser.rb
|
|
326
338
|
- lib/faml/engine.rb
|
|
327
339
|
- lib/faml/error.rb
|
|
328
340
|
- lib/faml/filter_compilers.rb
|
|
@@ -339,21 +351,13 @@ files:
|
|
|
339
351
|
- lib/faml/filter_compilers/sass.rb
|
|
340
352
|
- lib/faml/filter_compilers/scss.rb
|
|
341
353
|
- lib/faml/filter_compilers/tilt_base.rb
|
|
342
|
-
- lib/faml/filter_parser.rb
|
|
343
354
|
- lib/faml/helpers.rb
|
|
344
355
|
- lib/faml/html.rb
|
|
345
|
-
- lib/faml/indent_tracker.rb
|
|
346
|
-
- lib/faml/line_parser.rb
|
|
347
356
|
- lib/faml/newline.rb
|
|
348
|
-
- lib/faml/parser.rb
|
|
349
|
-
- lib/faml/parser_utils.rb
|
|
350
357
|
- lib/faml/rails_handler.rb
|
|
351
358
|
- lib/faml/rails_helpers.rb
|
|
352
359
|
- lib/faml/railtie.rb
|
|
353
|
-
- lib/faml/ruby_multiline.rb
|
|
354
|
-
- lib/faml/script_parser.rb
|
|
355
360
|
- lib/faml/static_hash_parser.rb
|
|
356
|
-
- lib/faml/syntax_error.rb
|
|
357
361
|
- lib/faml/text_compiler.rb
|
|
358
362
|
- lib/faml/tilt.rb
|
|
359
363
|
- lib/faml/version.rb
|
|
@@ -437,7 +441,6 @@ files:
|
|
|
437
441
|
- spec/render/filters_spec.rb
|
|
438
442
|
- spec/render/haml_comment_spec.rb
|
|
439
443
|
- spec/render/helpers_spec.rb
|
|
440
|
-
- spec/render/indent_spec.rb
|
|
441
444
|
- spec/render/multiline_spec.rb
|
|
442
445
|
- spec/render/newline_spec.rb
|
|
443
446
|
- spec/render/plain_spec.rb
|
|
@@ -469,7 +472,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
469
472
|
version: '0'
|
|
470
473
|
requirements: []
|
|
471
474
|
rubyforge_project:
|
|
472
|
-
rubygems_version: 2.5.
|
|
475
|
+
rubygems_version: 2.4.5.1
|
|
473
476
|
signing_key:
|
|
474
477
|
specification_version: 4
|
|
475
478
|
summary: Faster implementation of Haml template language.
|
|
@@ -574,7 +577,6 @@ test_files:
|
|
|
574
577
|
- spec/render/filters_spec.rb
|
|
575
578
|
- spec/render/haml_comment_spec.rb
|
|
576
579
|
- spec/render/helpers_spec.rb
|
|
577
|
-
- spec/render/indent_spec.rb
|
|
578
580
|
- spec/render/multiline_spec.rb
|
|
579
581
|
- spec/render/newline_spec.rb
|
|
580
582
|
- spec/render/plain_spec.rb
|
data/lib/faml/ast.rb
DELETED
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
module Faml
|
|
2
|
-
module Ast
|
|
3
|
-
module HasChildren
|
|
4
|
-
def initialize(*)
|
|
5
|
-
super
|
|
6
|
-
self.children ||= []
|
|
7
|
-
end
|
|
8
|
-
|
|
9
|
-
def <<(ast)
|
|
10
|
-
self.children << ast
|
|
11
|
-
end
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
class Root < Struct.new(:children)
|
|
15
|
-
include HasChildren
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
class Doctype < Struct.new(:doctype, :filename, :lineno)
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
class Element < Struct.new(
|
|
22
|
-
:children,
|
|
23
|
-
:tag_name,
|
|
24
|
-
:static_class,
|
|
25
|
-
:static_id,
|
|
26
|
-
:attributes,
|
|
27
|
-
:oneline_child,
|
|
28
|
-
:self_closing,
|
|
29
|
-
:nuke_inner_whitespace,
|
|
30
|
-
:nuke_outer_whitespace,
|
|
31
|
-
:filename,
|
|
32
|
-
:lineno,
|
|
33
|
-
)
|
|
34
|
-
include HasChildren
|
|
35
|
-
|
|
36
|
-
def initialize(*)
|
|
37
|
-
super
|
|
38
|
-
self.static_class ||= ''
|
|
39
|
-
self.static_id ||= ''
|
|
40
|
-
self.attributes ||= ''
|
|
41
|
-
self.self_closing ||= false
|
|
42
|
-
self.nuke_inner_whitespace ||= false
|
|
43
|
-
self.nuke_outer_whitespace ||= false
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
class Script < Struct.new(
|
|
48
|
-
:children,
|
|
49
|
-
:script,
|
|
50
|
-
:escape_html,
|
|
51
|
-
:preserve,
|
|
52
|
-
:mid_block_keyword,
|
|
53
|
-
:filename,
|
|
54
|
-
:lineno,
|
|
55
|
-
)
|
|
56
|
-
include HasChildren
|
|
57
|
-
|
|
58
|
-
def initialize(*)
|
|
59
|
-
super
|
|
60
|
-
if self.escape_html.nil?
|
|
61
|
-
self.escape_html = true
|
|
62
|
-
end
|
|
63
|
-
if self.preserve.nil?
|
|
64
|
-
self.preserve = false
|
|
65
|
-
end
|
|
66
|
-
if self.mid_block_keyword.nil?
|
|
67
|
-
self.mid_block_keyword = false
|
|
68
|
-
end
|
|
69
|
-
end
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
class SilentScript < Struct.new(:children, :script, :mid_block_keyword, :filename, :lineno)
|
|
73
|
-
include HasChildren
|
|
74
|
-
|
|
75
|
-
def initialize(*)
|
|
76
|
-
super
|
|
77
|
-
if self.mid_block_keyword.nil?
|
|
78
|
-
self.mid_block_keyword = false
|
|
79
|
-
end
|
|
80
|
-
end
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
class HtmlComment < Struct.new(:children, :comment, :conditional, :filename, :lineno)
|
|
84
|
-
include HasChildren
|
|
85
|
-
|
|
86
|
-
def initialize(*)
|
|
87
|
-
super
|
|
88
|
-
self.comment ||= ''
|
|
89
|
-
self.conditional ||= ''
|
|
90
|
-
end
|
|
91
|
-
end
|
|
92
|
-
|
|
93
|
-
class HamlComment < Struct.new(:children, :filename, :lineno)
|
|
94
|
-
include HasChildren
|
|
95
|
-
end
|
|
96
|
-
|
|
97
|
-
class Text < Struct.new(:text, :escape_html, :filename, :lineno)
|
|
98
|
-
def initialize(*)
|
|
99
|
-
super
|
|
100
|
-
if self.escape_html.nil?
|
|
101
|
-
self.escape_html = true
|
|
102
|
-
end
|
|
103
|
-
end
|
|
104
|
-
end
|
|
105
|
-
|
|
106
|
-
class Filter < Struct.new(:name, :texts, :filename, :lineno)
|
|
107
|
-
def initialize(*)
|
|
108
|
-
super
|
|
109
|
-
self.texts ||= []
|
|
110
|
-
end
|
|
111
|
-
end
|
|
112
|
-
|
|
113
|
-
class Empty < Struct.new(:filename, :lineno)
|
|
114
|
-
end
|
|
115
|
-
end
|
|
116
|
-
end
|
data/lib/faml/element_parser.rb
DELETED
|
@@ -1,235 +0,0 @@
|
|
|
1
|
-
require 'strscan'
|
|
2
|
-
require 'faml/ast'
|
|
3
|
-
require 'faml/parser_utils'
|
|
4
|
-
require 'faml/ruby_multiline'
|
|
5
|
-
require 'faml/script_parser'
|
|
6
|
-
require 'faml/syntax_error'
|
|
7
|
-
|
|
8
|
-
module Faml
|
|
9
|
-
class ElementParser
|
|
10
|
-
def initialize(line_parser)
|
|
11
|
-
@line_parser = line_parser
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
ELEMENT_REGEXP = /\A%([-:\w]+)([-:\w.#]*)(.+)?\z/o
|
|
15
|
-
|
|
16
|
-
def parse(text)
|
|
17
|
-
m = text.match(ELEMENT_REGEXP)
|
|
18
|
-
unless m
|
|
19
|
-
syntax_error!('Invalid element declaration')
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
element = Ast::Element.new
|
|
23
|
-
element.filename = @line_parser.filename
|
|
24
|
-
element.lineno = @line_parser.lineno
|
|
25
|
-
element.tag_name = m[1]
|
|
26
|
-
element.static_class, element.static_id = parse_class_and_id(m[2])
|
|
27
|
-
rest = m[3] || ''
|
|
28
|
-
|
|
29
|
-
element.attributes, rest = parse_attributes(rest)
|
|
30
|
-
element.nuke_inner_whitespace, element.nuke_outer_whitespace, rest = parse_nuke_whitespace(rest)
|
|
31
|
-
element.self_closing, rest = parse_self_closing(rest)
|
|
32
|
-
element.oneline_child = ScriptParser.new(@line_parser).parse(rest)
|
|
33
|
-
|
|
34
|
-
element
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
private
|
|
38
|
-
|
|
39
|
-
def parse_class_and_id(class_and_id)
|
|
40
|
-
classes = []
|
|
41
|
-
id = ''
|
|
42
|
-
scanner = StringScanner.new(class_and_id)
|
|
43
|
-
until scanner.eos?
|
|
44
|
-
unless scanner.scan(/([#.])([-:_a-zA-Z0-9]+)/)
|
|
45
|
-
syntax_error!('Illegal element: classes and ids must have values.')
|
|
46
|
-
end
|
|
47
|
-
case scanner[1]
|
|
48
|
-
when '.'
|
|
49
|
-
classes << scanner[2]
|
|
50
|
-
when '#'
|
|
51
|
-
id = scanner[2]
|
|
52
|
-
end
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
[classes.join(' '), id]
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
OLD_ATTRIBUTE_BEGIN = '{'
|
|
59
|
-
NEW_ATTRIBUTE_BEGIN = '('
|
|
60
|
-
|
|
61
|
-
def parse_attributes(rest)
|
|
62
|
-
old_attributes = ''
|
|
63
|
-
new_attributes = ''
|
|
64
|
-
|
|
65
|
-
loop do
|
|
66
|
-
case rest[0]
|
|
67
|
-
when OLD_ATTRIBUTE_BEGIN
|
|
68
|
-
unless old_attributes.empty?
|
|
69
|
-
break
|
|
70
|
-
end
|
|
71
|
-
old_attributes, rest = parse_old_attributes(rest)
|
|
72
|
-
when NEW_ATTRIBUTE_BEGIN
|
|
73
|
-
unless new_attributes.empty?
|
|
74
|
-
break
|
|
75
|
-
end
|
|
76
|
-
new_attributes, rest = parse_new_attributes(rest)
|
|
77
|
-
else
|
|
78
|
-
break
|
|
79
|
-
end
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
attributes = old_attributes
|
|
83
|
-
unless new_attributes.empty?
|
|
84
|
-
if attributes.empty?
|
|
85
|
-
attributes = new_attributes
|
|
86
|
-
else
|
|
87
|
-
attributes << ", " << new_attributes
|
|
88
|
-
end
|
|
89
|
-
end
|
|
90
|
-
[attributes, rest]
|
|
91
|
-
end
|
|
92
|
-
|
|
93
|
-
def parse_old_attributes(text)
|
|
94
|
-
text = text.dup
|
|
95
|
-
s = StringScanner.new(text)
|
|
96
|
-
s.pos = 1
|
|
97
|
-
depth = 1
|
|
98
|
-
loop do
|
|
99
|
-
depth = ParserUtils.balance(s, '{', '}', depth)
|
|
100
|
-
if depth == 0
|
|
101
|
-
attr = s.pre_match + s.matched
|
|
102
|
-
return [attr[1, attr.size-2], s.rest]
|
|
103
|
-
else
|
|
104
|
-
if /,\s*\z/ === text && @line_parser.has_next?
|
|
105
|
-
text << "\n" << @line_parser.next_line
|
|
106
|
-
else
|
|
107
|
-
syntax_error!('Unmatched brace')
|
|
108
|
-
end
|
|
109
|
-
end
|
|
110
|
-
end
|
|
111
|
-
end
|
|
112
|
-
|
|
113
|
-
def parse_new_attributes(text)
|
|
114
|
-
text = text.dup
|
|
115
|
-
s = StringScanner.new(text)
|
|
116
|
-
s.pos = 1
|
|
117
|
-
depth = 1
|
|
118
|
-
loop do
|
|
119
|
-
pre_pos = s.pos
|
|
120
|
-
depth = ParserUtils.balance(s, '(', ')', depth)
|
|
121
|
-
if depth == 0
|
|
122
|
-
t = s.string.byteslice(pre_pos ... s.pos-1)
|
|
123
|
-
return [parse_new_attribute_list(t), s.rest]
|
|
124
|
-
else
|
|
125
|
-
if @line_parser.has_next?
|
|
126
|
-
text << "\n" << @line_parser.next_line
|
|
127
|
-
else
|
|
128
|
-
syntax_error!('Unmatched paren')
|
|
129
|
-
end
|
|
130
|
-
end
|
|
131
|
-
end
|
|
132
|
-
end
|
|
133
|
-
|
|
134
|
-
def parse_new_attribute_list(text)
|
|
135
|
-
s = StringScanner.new(text)
|
|
136
|
-
attributes = []
|
|
137
|
-
until s.eos?
|
|
138
|
-
name = scan_key(s)
|
|
139
|
-
s.skip(/\s*/)
|
|
140
|
-
|
|
141
|
-
if scan_operator(s)
|
|
142
|
-
s.skip(/\s*/)
|
|
143
|
-
value = scan_value(s)
|
|
144
|
-
else
|
|
145
|
-
value = 'true'
|
|
146
|
-
end
|
|
147
|
-
spaces = s.scan(/\s*/)
|
|
148
|
-
line_count = spaces.count("\n")
|
|
149
|
-
|
|
150
|
-
attributes << "#{name.inspect} => #{value},#{"\n" * line_count}"
|
|
151
|
-
end
|
|
152
|
-
attributes.join
|
|
153
|
-
end
|
|
154
|
-
|
|
155
|
-
def scan_key(scanner)
|
|
156
|
-
scanner.scan(/[-:\w]+/).tap do |name|
|
|
157
|
-
unless name
|
|
158
|
-
syntax_error!('Invalid attribute list (missing attribute name)')
|
|
159
|
-
end
|
|
160
|
-
end
|
|
161
|
-
end
|
|
162
|
-
|
|
163
|
-
def scan_operator(scanner)
|
|
164
|
-
scanner.skip(/=/)
|
|
165
|
-
end
|
|
166
|
-
|
|
167
|
-
def scan_value(scanner)
|
|
168
|
-
if quote = scanner.scan(/["']/)
|
|
169
|
-
scan_quoted_value(scanner, quote)
|
|
170
|
-
else
|
|
171
|
-
scan_variable_value(scanner)
|
|
172
|
-
end
|
|
173
|
-
end
|
|
174
|
-
|
|
175
|
-
def scan_quoted_value(scanner, quote)
|
|
176
|
-
re = /((?:\\.|\#(?!\{)|[^#{quote}\\#])*)(#{quote}|#\{)/
|
|
177
|
-
pos = scanner.pos
|
|
178
|
-
loop do
|
|
179
|
-
unless scanner.scan(re)
|
|
180
|
-
syntax_error!('Invalid attribute list (mismatched quotation)')
|
|
181
|
-
end
|
|
182
|
-
if scanner[2] == quote
|
|
183
|
-
break
|
|
184
|
-
end
|
|
185
|
-
depth = ParserUtils.balance(scanner, '{', '}')
|
|
186
|
-
if depth != 0
|
|
187
|
-
syntax_error!('Invalid attribute list (mismatched interpolation)')
|
|
188
|
-
end
|
|
189
|
-
end
|
|
190
|
-
str = scanner.string.byteslice(pos-1 .. scanner.pos-1)
|
|
191
|
-
|
|
192
|
-
# Even if the quote is single, string interpolation is performed in Haml.
|
|
193
|
-
str[0] = '"'
|
|
194
|
-
str[-1] = '"'
|
|
195
|
-
str
|
|
196
|
-
end
|
|
197
|
-
|
|
198
|
-
def scan_variable_value(scanner)
|
|
199
|
-
scanner.scan(/(@@?|\$)?\w+/).tap do |var|
|
|
200
|
-
unless var
|
|
201
|
-
syntax_error!('Invalid attribute list (invalid variable name)')
|
|
202
|
-
end
|
|
203
|
-
end
|
|
204
|
-
end
|
|
205
|
-
|
|
206
|
-
def parse_nuke_whitespace(rest)
|
|
207
|
-
m = rest.match(/\A(><|<>|[><])(.*)\z/)
|
|
208
|
-
if m
|
|
209
|
-
nuke_whitespace = m[1]
|
|
210
|
-
[
|
|
211
|
-
nuke_whitespace.include?('<'),
|
|
212
|
-
nuke_whitespace.include?('>'),
|
|
213
|
-
m[2],
|
|
214
|
-
]
|
|
215
|
-
else
|
|
216
|
-
[false, false, rest]
|
|
217
|
-
end
|
|
218
|
-
end
|
|
219
|
-
|
|
220
|
-
def parse_self_closing(rest)
|
|
221
|
-
if rest[0] == '/'
|
|
222
|
-
if rest.size > 1
|
|
223
|
-
syntax_error!("Self-closing tags can't have content")
|
|
224
|
-
end
|
|
225
|
-
[true, '']
|
|
226
|
-
else
|
|
227
|
-
[false, rest]
|
|
228
|
-
end
|
|
229
|
-
end
|
|
230
|
-
|
|
231
|
-
def syntax_error!(message)
|
|
232
|
-
raise SyntaxError.new(message, @line_parser.lineno)
|
|
233
|
-
end
|
|
234
|
-
end
|
|
235
|
-
end
|