hamli 0.1.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
[![test](https://github.com/r7kamura/hamli/actions/workflows/test.yml/badge.svg)](https://github.com/r7kamura/hamli/actions/workflows/test.yml)
|
4
|
+
[![Gem Version](https://badge.fury.io/rb/hamli.svg)](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
|