hamli 0.1.0 → 0.5.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 +42 -0
- data/Gemfile.lock +1 -1
- data/README.md +3 -0
- data/lib/hamli/filters/base.rb +24 -0
- data/lib/hamli/filters/interpolation.rb +37 -0
- data/lib/hamli/filters.rb +8 -0
- data/lib/hamli/parser.rb +153 -7
- data/lib/hamli/version.rb +1 -1
- data/lib/hamli.rb +1 -0
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ff0371e95f3c87b4519036500b8ff6b5a7de3a91f9509f05240a9a23d53105ff
|
4
|
+
data.tar.gz: f96c2b0b84ad2d546433934ebe40e6973effe559896e0bacda88a0d769e462fc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 60c15036fe01fc5c4716cf49f8969dca86055628c42ba7c299a66de3102f08b7520d1c296f58b032840bfd925b5fcefaae068add96cc9f7d9370a68667d27c1e
|
7
|
+
data.tar.gz: a6c1a3d3b777ef1fd46f4928d2c045f57051169d84d2643050e1b917cb49cc0db0b9a20f9dee049a9fed8a1ad172ed74bae20fa4b94ab6616405d66d814970b2
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,48 @@
|
|
2
2
|
|
3
3
|
## Unreleased
|
4
4
|
|
5
|
+
## 0.5.0 - 2022-01-30
|
6
|
+
|
7
|
+
### Added
|
8
|
+
|
9
|
+
- Support escaped output line.
|
10
|
+
- Support non-escaped output line.
|
11
|
+
|
12
|
+
## 0.4.0 - 2022-01-26
|
13
|
+
|
14
|
+
### Added
|
15
|
+
|
16
|
+
- Add :file option for better error report.
|
17
|
+
|
18
|
+
### Fixed
|
19
|
+
|
20
|
+
- Fix error from parse_text_block on some case.
|
21
|
+
- Fix filter bug on :text node.
|
22
|
+
- Fix parse_interpolate_line bug.
|
23
|
+
- Fix haml comment parser bug.
|
24
|
+
- Fix pipe multi-line handling.
|
25
|
+
|
26
|
+
## 0.3.0 - 2022-01-26
|
27
|
+
|
28
|
+
### Added
|
29
|
+
|
30
|
+
- Support output block in tag line.
|
31
|
+
- Support HTML comment line.
|
32
|
+
- Support HTML conditional comment line.
|
33
|
+
- Support Haml comment line.
|
34
|
+
- Support output line.
|
35
|
+
- Support control line.
|
36
|
+
|
37
|
+
## 0.2.0 - 2022-01-25
|
38
|
+
|
39
|
+
### Added
|
40
|
+
|
41
|
+
- Add Interpolation Filter.
|
42
|
+
|
43
|
+
### Changed
|
44
|
+
|
45
|
+
- Use :position node.
|
46
|
+
|
5
47
|
## 0.1.0 - 2022-01-25
|
6
48
|
|
7
49
|
### Added
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -1,9 +1,12 @@
|
|
1
1
|
# Hamli
|
2
2
|
|
3
3
|
[](https://github.com/r7kamura/hamli/actions/workflows/test.yml)
|
4
|
+
[](https://rubygems.org/gems/hamli)
|
4
5
|
|
5
6
|
Yet another implementation for [Haml](https://github.com/haml/haml) template language.
|
6
7
|
|
8
|
+
Hamli is used by [Hamlcop](https://github.com/r7kamura/hamlcop).
|
9
|
+
|
7
10
|
## Installation
|
8
11
|
|
9
12
|
Add this line to your application's Gemfile:
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'temple'
|
4
|
+
|
5
|
+
module Hamli
|
6
|
+
module Filters
|
7
|
+
# Pass-through some expressions which are unknown for Temple.
|
8
|
+
class Base < ::Temple::HTML::Filter
|
9
|
+
# @param [Integer] begin_
|
10
|
+
# @param [Integer] end_
|
11
|
+
# @param [Array] expression
|
12
|
+
# @return [Array]
|
13
|
+
def on_hamli_position(begin_, end_, expression)
|
14
|
+
[:hamli, :position, begin_, end_, compile(expression)]
|
15
|
+
end
|
16
|
+
|
17
|
+
# @param [Array] expression
|
18
|
+
# @return [Array]
|
19
|
+
def on_hamli_text(expression)
|
20
|
+
[:hamli, :text, compile(expression)]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'strscan'
|
4
|
+
|
5
|
+
module Hamli
|
6
|
+
module Filters
|
7
|
+
class Interpolation < Base
|
8
|
+
# @param [Integer] begin_
|
9
|
+
# @param [Integer] end_
|
10
|
+
# @return [Array] S-expression.
|
11
|
+
def on_hamli_interpolate(begin_, _end_, string)
|
12
|
+
block = [:multi]
|
13
|
+
scanner = ::StringScanner.new(string)
|
14
|
+
until scanner.eos?
|
15
|
+
charpos = scanner.charpos
|
16
|
+
if (value = scanner.scan(/\\#\{/))
|
17
|
+
block << [:static, value]
|
18
|
+
elsif scanner.scan(/#\{((?>[^{}]|(\{(?>[^{}]|\g<1>)*\}))*)\}/)
|
19
|
+
code = scanner[1]
|
20
|
+
begin2 = begin_ + charpos + 2
|
21
|
+
if code.start_with?('{') && code.end_with?('}')
|
22
|
+
escape = true
|
23
|
+
code = code[1..-2]
|
24
|
+
begin2 -= 1
|
25
|
+
else
|
26
|
+
escape = false
|
27
|
+
end
|
28
|
+
block << [:hamli, :position, begin2, begin2 + code.length, [:hamli, :output, escape, code, [:multi]]]
|
29
|
+
elsif (value = scanner.scan(/([#\\]?[^#\\]*([#\\][^\\\#{][^#\\]*)*)/)) # rubocop:disable Lint/DuplicateBranch
|
30
|
+
block << [:static, value]
|
31
|
+
end
|
32
|
+
end
|
33
|
+
block
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/lib/hamli/parser.rb
CHANGED
@@ -4,6 +4,15 @@ require 'temple'
|
|
4
4
|
|
5
5
|
module Hamli
|
6
6
|
class Parser < ::Temple::Parser
|
7
|
+
define_options(
|
8
|
+
:file
|
9
|
+
)
|
10
|
+
|
11
|
+
def initialize(_options = {})
|
12
|
+
super
|
13
|
+
@file_path = options[:file] || '(__TEMPLATE__)'
|
14
|
+
end
|
15
|
+
|
7
16
|
# @param [String] source Haml template source.
|
8
17
|
# @return [Array]
|
9
18
|
def call(source)
|
@@ -25,6 +34,20 @@ module Hamli
|
|
25
34
|
parse_tag_line
|
26
35
|
elsif @scanner.match?(/[#.]/)
|
27
36
|
parse_div_line
|
37
|
+
elsif @scanner.match?(%r{/\[})
|
38
|
+
parse_html_conditional_comment_line
|
39
|
+
elsif @scanner.match?(%r{/})
|
40
|
+
parse_html_comment_line
|
41
|
+
elsif @scanner.match?(/-#/)
|
42
|
+
parse_haml_comment_line
|
43
|
+
elsif @scanner.match?(/-/)
|
44
|
+
parse_control_line
|
45
|
+
elsif @scanner.match?(/=/)
|
46
|
+
parse_output_line
|
47
|
+
elsif @scanner.match?(/&=/)
|
48
|
+
parse_escaped_output_line
|
49
|
+
elsif @scanner.match?(/!=/)
|
50
|
+
parse_non_escaped_output_line
|
28
51
|
else
|
29
52
|
parse_text_line
|
30
53
|
end
|
@@ -110,10 +133,19 @@ module Hamli
|
|
110
133
|
content = [:multi]
|
111
134
|
tag << content
|
112
135
|
@stacks << content
|
113
|
-
elsif @scanner.scan(/[ \t]
|
114
|
-
#
|
136
|
+
elsif @scanner.scan(/[ \t]*([<>]*)=/)
|
137
|
+
# white_space_marker = @scanner[1]
|
138
|
+
# without_outer_white_space = white_space_marker.include?('>') # TODO
|
139
|
+
# without_inner_white_space = white_space_marker.include?('<') # TODO
|
140
|
+
@scanner.skip(/[ \t]+/)
|
141
|
+
begin_ = @scanner.charpos
|
142
|
+
content = parse_broken_lines
|
143
|
+
end_ = @scanner.charpos
|
144
|
+
block = [:multi]
|
145
|
+
tag << [:hamli, :position, begin_, end_, [:hamli, :output, false, content, block]]
|
146
|
+
@stacks << block
|
115
147
|
elsif @scanner.scan(%r{[ \t]*/[ \t]*})
|
116
|
-
#
|
148
|
+
# Does nothing.
|
117
149
|
else
|
118
150
|
@scanner.scan(/[ \t]+/)
|
119
151
|
tag << [:hamli, :text, parse_text_block]
|
@@ -274,7 +306,7 @@ module Hamli
|
|
274
306
|
)
|
275
307
|
/x
|
276
308
|
)
|
277
|
-
[:hamli, :object_reference, begin_, @scanner.charpos, value]
|
309
|
+
[:hamli, :object_reference, [:hamli, :position, begin_, @scanner.charpos, value]]
|
278
310
|
end
|
279
311
|
|
280
312
|
# Parse ruby attributes part.
|
@@ -292,7 +324,51 @@ module Hamli
|
|
292
324
|
)
|
293
325
|
/x
|
294
326
|
)
|
295
|
-
[:hamli, :ruby_attributes, begin_, @scanner.charpos, value]
|
327
|
+
[:hamli, :ruby_attributes, [:hamli, :position, begin_, @scanner.charpos, value]]
|
328
|
+
end
|
329
|
+
|
330
|
+
# Parse HTML comment part.
|
331
|
+
# e.g. /[if IE]
|
332
|
+
# ^^^^^^^^
|
333
|
+
def parse_html_conditional_comment_line
|
334
|
+
@scanner.pos += 1
|
335
|
+
condition = @scanner.scan(
|
336
|
+
/
|
337
|
+
(?<brackets>
|
338
|
+
\[
|
339
|
+
(?:[^\[\]] | \g<brackets>)*
|
340
|
+
\]
|
341
|
+
)
|
342
|
+
/x
|
343
|
+
)
|
344
|
+
block = [:multi]
|
345
|
+
@stacks.last << [:html, :condcomment, condition, block]
|
346
|
+
@stacks << block
|
347
|
+
parse_line_ending
|
348
|
+
end
|
349
|
+
|
350
|
+
# Parse HTML comment part.
|
351
|
+
# e.g. / abc
|
352
|
+
# ^^^^^
|
353
|
+
def parse_html_comment_line
|
354
|
+
@scanner.pos += 1
|
355
|
+
block = [:multi]
|
356
|
+
block << [:static, @scanner.scan(/[^\r\n]*/)]
|
357
|
+
@stacks.last << [:html, :comment, block]
|
358
|
+
@stacks << block
|
359
|
+
parse_line_ending
|
360
|
+
end
|
361
|
+
|
362
|
+
# Parse Haml comment part.
|
363
|
+
# e.g. -# abc
|
364
|
+
# ^^^^^^
|
365
|
+
def parse_haml_comment_line
|
366
|
+
@scanner.pos += 2
|
367
|
+
@scanner.scan(/[^\r\n]*/)
|
368
|
+
while !@scanner.eos? && (@scanner.match?(/[ \t]*(?=\r|$)/) || peek_indent > @indents.last)
|
369
|
+
@scanner.scan(/[^\r\n]*/)
|
370
|
+
parse_line_ending
|
371
|
+
end
|
296
372
|
end
|
297
373
|
|
298
374
|
# Parse text block part.
|
@@ -325,7 +401,7 @@ module Hamli
|
|
325
401
|
|
326
402
|
# @return [Array, nil]
|
327
403
|
def parse_interpolate_line
|
328
|
-
return unless @scanner.match?(/[^\r\n]
|
404
|
+
return unless @scanner.match?(/[^\r\n]+/)
|
329
405
|
|
330
406
|
begin_ = @scanner.charpos
|
331
407
|
value = @scanner.matched
|
@@ -334,6 +410,70 @@ module Hamli
|
|
334
410
|
[:hamli, :interpolate, begin_, end_, value]
|
335
411
|
end
|
336
412
|
|
413
|
+
# Parse escaped output line part.
|
414
|
+
# e.g. != abc
|
415
|
+
# ^^^^^^
|
416
|
+
# @todo Support :escape_html option on this parser, then rethink about escaping.
|
417
|
+
def parse_non_escaped_output_line
|
418
|
+
@scanner.pos += 1
|
419
|
+
parse_output_line
|
420
|
+
end
|
421
|
+
|
422
|
+
# Parse escaped output line part.
|
423
|
+
# e.g. &= abc
|
424
|
+
# ^^^^^^
|
425
|
+
def parse_escaped_output_line
|
426
|
+
@scanner.pos += 2
|
427
|
+
@scanner.scan(/[ \t]*/)
|
428
|
+
parse_ruby_line(escaped: true, name: :output)
|
429
|
+
end
|
430
|
+
|
431
|
+
# Parse output line part.
|
432
|
+
# e.g. = abc
|
433
|
+
# ^^^^^
|
434
|
+
def parse_output_line
|
435
|
+
@scanner.pos += 1
|
436
|
+
@scanner.scan(/[ \t]*/)
|
437
|
+
parse_ruby_line(escaped: false, name: :output)
|
438
|
+
end
|
439
|
+
|
440
|
+
# Parse control line part.
|
441
|
+
# e.g. - abc
|
442
|
+
# ^^^^^
|
443
|
+
def parse_control_line
|
444
|
+
@scanner.pos += 1
|
445
|
+
@scanner.scan(/[ \t]*/)
|
446
|
+
parse_ruby_line(escaped: false, name: :control)
|
447
|
+
end
|
448
|
+
|
449
|
+
# @param [Boolean] escaped
|
450
|
+
# @param [Symbol] name
|
451
|
+
def parse_ruby_line(escaped:, name:)
|
452
|
+
@scanner.scan(/[ \t]*/)
|
453
|
+
block = [:multi]
|
454
|
+
begin_ = @scanner.charpos
|
455
|
+
content = parse_broken_lines
|
456
|
+
end_ = @scanner.charpos
|
457
|
+
@stacks.last << [:hamli, :position, begin_, end_, [:hamli, name, escaped, content, block]]
|
458
|
+
@stacks << block
|
459
|
+
end
|
460
|
+
|
461
|
+
# @note Broken line means line-breaked lines, separated by trailing "," or "|".
|
462
|
+
# @return [String]
|
463
|
+
def parse_broken_lines
|
464
|
+
result = +''
|
465
|
+
result << @scanner.scan(/[^\r\n]*/)
|
466
|
+
while result.end_with?(',') || result.end_with?('|')
|
467
|
+
syntax_error!(Errors::UnexpectedEosError) unless @scanner.scan(/\r?\n/)
|
468
|
+
|
469
|
+
result << "\n"
|
470
|
+
result << @scanner.scan(/[^\r\n]*/)
|
471
|
+
end
|
472
|
+
lines = result.lines
|
473
|
+
result.gsub!(/\|$/, '') if lines.length >= 2 && lines.all? { |line| line.end_with?("|\n") }
|
474
|
+
result.delete_suffix("\n")
|
475
|
+
end
|
476
|
+
|
337
477
|
# @param [Class] syntax_error_class A child class of Hamli::Errors::HamlSyntaxError.
|
338
478
|
# @raise [Hamli::Errors::HamlSyntaxError]
|
339
479
|
def syntax_error!(syntax_error_class)
|
@@ -348,7 +488,7 @@ module Hamli
|
|
348
488
|
|
349
489
|
# @return [Integer]
|
350
490
|
def indent_from_last_match
|
351
|
-
@scanner.matched.chars.map do |char|
|
491
|
+
(@scanner.matched || '').chars.map do |char|
|
352
492
|
case char
|
353
493
|
when "\t"
|
354
494
|
4
|
@@ -364,5 +504,11 @@ module Hamli
|
|
364
504
|
def expecting_indentation?
|
365
505
|
@stacks.length > @indents.length
|
366
506
|
end
|
507
|
+
|
508
|
+
# @return [Integer] Indent level.
|
509
|
+
def peek_indent
|
510
|
+
@scanner.match?(/[ \t]*/)
|
511
|
+
indent_from_last_match
|
512
|
+
end
|
367
513
|
end
|
368
514
|
end
|
data/lib/hamli/version.rb
CHANGED
data/lib/hamli.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hamli
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ryo Nakamura
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-01-
|
11
|
+
date: 2022-01-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: temple
|
@@ -43,6 +43,9 @@ files:
|
|
43
43
|
- hamli.gemspec
|
44
44
|
- lib/hamli.rb
|
45
45
|
- lib/hamli/errors.rb
|
46
|
+
- lib/hamli/filters.rb
|
47
|
+
- lib/hamli/filters/base.rb
|
48
|
+
- lib/hamli/filters/interpolation.rb
|
46
49
|
- lib/hamli/parser.rb
|
47
50
|
- lib/hamli/range.rb
|
48
51
|
- lib/hamli/version.rb
|