slimi 0.1.0 → 0.4.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/.rubocop.yml +3 -0
- data/CHANGELOG.md +36 -0
- data/Gemfile.lock +1 -1
- data/README.md +2 -19
- data/lib/slimi/errors.rb +41 -7
- data/lib/slimi/filters/interpolation.rb +28 -7
- data/lib/slimi/parser.rb +138 -11
- data/lib/slimi/range.rb +39 -0
- data/lib/slimi/version.rb +1 -1
- data/lib/slimi.rb +1 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 05cfa3a429ac2da0e1241e65e69a40f9171079cddb9451a6d7186726a5cb498c
|
4
|
+
data.tar.gz: 68826c3fe78dc87bfd704cc38a9222da1adeed36a8c0d0e903bb4f3077ed698d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9c729933bc060a21df2e55db525d28a8e519526995ec5b7fb3defd17ecb11c71fc7e6ec664c162396f6a8be9175549dd842c7c5f9be76c68afadadc9e3e442be
|
7
|
+
data.tar.gz: 60b3b1ad54a01bcbc2154e83b11efe3ac1b3fb5723773f04aabff9d1957dec60cb8afd431630b78dc8e13fa86d109d86a78c66005bafb10c23e0965368d9bd80
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,42 @@
|
|
2
2
|
|
3
3
|
## Unreleased
|
4
4
|
|
5
|
+
## 0.4.0 - 2021-12-25
|
6
|
+
|
7
|
+
### Added
|
8
|
+
|
9
|
+
- Support :file option on parser for showing correct file path on syntax error.
|
10
|
+
|
11
|
+
### Fixed
|
12
|
+
|
13
|
+
- Fix NameError on unknown line indicator.
|
14
|
+
- Fix bug that default parser options are not used.
|
15
|
+
|
16
|
+
## 0.3.0 - 2021-12-24
|
17
|
+
|
18
|
+
### Added
|
19
|
+
|
20
|
+
- Support unquoted attributes.
|
21
|
+
|
22
|
+
### Fixed
|
23
|
+
|
24
|
+
- Fix bug about blank line handling.
|
25
|
+
|
26
|
+
## 0.2.0 - 2021-12-23
|
27
|
+
|
28
|
+
### Added
|
29
|
+
|
30
|
+
- Support embedded template.
|
31
|
+
- Show useful message at syntax error.
|
32
|
+
|
33
|
+
## 0.1.1 - 2021-12-21
|
34
|
+
|
35
|
+
### Fixed
|
36
|
+
|
37
|
+
- Fix bug that Slimi::Interpolation was not working.
|
38
|
+
|
5
39
|
## 0.1.0 - 2021-12-20
|
6
40
|
|
41
|
+
### Added
|
42
|
+
|
7
43
|
- Initial release.
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -1,10 +1,11 @@
|
|
1
1
|
# Slimi
|
2
2
|
|
3
3
|
[](https://github.com/r7kamura/slimi/actions/workflows/test.yml)
|
4
|
+
[](https://rubygems.org/gems/slimi)
|
4
5
|
|
5
6
|
Yet another implementation for [Slim](https://github.com/slim-template/slim) template language.
|
6
7
|
|
7
|
-
|
8
|
+
Slimi is used by [Slimcop](https://github.com/r7kamura/slimcop).
|
8
9
|
|
9
10
|
## Installation
|
10
11
|
|
@@ -29,21 +30,3 @@ gem install slimi
|
|
29
30
|
## Usage
|
30
31
|
|
31
32
|
TBD.
|
32
|
-
|
33
|
-
## Development
|
34
|
-
|
35
|
-
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
36
|
-
|
37
|
-
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
38
|
-
|
39
|
-
## Contributing
|
40
|
-
|
41
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/r7kamura/slimi. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/r7kamura/slimi/blob/main/CODE_OF_CONDUCT.md).
|
42
|
-
|
43
|
-
## License
|
44
|
-
|
45
|
-
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
46
|
-
|
47
|
-
## Code of Conduct
|
48
|
-
|
49
|
-
Everyone interacting in the Slimi project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/r7kamura/slimi/blob/main/CODE_OF_CONDUCT.md).
|
data/lib/slimi/errors.rb
CHANGED
@@ -5,25 +5,59 @@ module Slimi
|
|
5
5
|
class BaseError < StandardError
|
6
6
|
end
|
7
7
|
|
8
|
-
class
|
8
|
+
class SlimSyntaxError < BaseError
|
9
|
+
# @param [Integer] column
|
10
|
+
# @param [String] file_path
|
11
|
+
# @param [String] line
|
12
|
+
# @param [Integer] line_number
|
13
|
+
def initialize(column:, file_path:, line:, line_number:)
|
14
|
+
super()
|
15
|
+
@column = column
|
16
|
+
@file_path = file_path
|
17
|
+
@line = line
|
18
|
+
@line_number = line_number
|
19
|
+
end
|
20
|
+
|
21
|
+
# @note Override.
|
22
|
+
# @return [String]
|
23
|
+
def to_s
|
24
|
+
<<~TEXT
|
25
|
+
#{error_type} at #{@file_path}:#{@line_number}:#{@column}
|
26
|
+
#{@line}
|
27
|
+
#{' ' * (@column - 1)}^
|
28
|
+
TEXT
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
# @return [String]
|
34
|
+
def error_type
|
35
|
+
self.class.to_s.split('::').last
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
class InvalidEmptyAttributeError < SlimSyntaxError
|
40
|
+
end
|
41
|
+
|
42
|
+
class LineEndingNotFoundError < SlimSyntaxError
|
9
43
|
end
|
10
44
|
|
11
|
-
class
|
45
|
+
class MalformedIndentationError < SlimSyntaxError
|
12
46
|
end
|
13
47
|
|
14
|
-
class
|
48
|
+
class RubyAttributeClosingDelimiterNotFoundError < SlimSyntaxError
|
15
49
|
end
|
16
50
|
|
17
|
-
class UnexpectedEosError <
|
51
|
+
class UnexpectedEosError < SlimSyntaxError
|
18
52
|
end
|
19
53
|
|
20
|
-
class UnexpectedIndentationError <
|
54
|
+
class UnexpectedIndentationError < SlimSyntaxError
|
21
55
|
end
|
22
56
|
|
23
|
-
class UnexpectedTextAfterClosedTagError <
|
57
|
+
class UnexpectedTextAfterClosedTagError < SlimSyntaxError
|
24
58
|
end
|
25
59
|
|
26
|
-
class
|
60
|
+
class UnknownLineIndicatorError < SlimSyntaxError
|
27
61
|
end
|
28
62
|
end
|
29
63
|
end
|
@@ -1,34 +1,55 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'strscan'
|
4
|
-
require 'temple'
|
5
4
|
|
6
5
|
module Slimi
|
7
6
|
module Filters
|
8
|
-
class Interpolation
|
7
|
+
class Interpolation
|
8
|
+
def initialize(*); end
|
9
|
+
|
10
|
+
def call(node)
|
11
|
+
convert(node)
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def convert(value)
|
17
|
+
if value.instance_of?(::Array)
|
18
|
+
if value[0] == :slimi && value[1] == :interpolate
|
19
|
+
on_slimi_interpolate(value[2], value[3], value[4])
|
20
|
+
else
|
21
|
+
value.map do |element|
|
22
|
+
call(element)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
else
|
26
|
+
value
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
9
30
|
# @param [Integer] begin_
|
10
31
|
# @param [Integer] end_
|
11
32
|
# @return [Array] S-expression.
|
12
|
-
def on_slimi_interpolate(begin_,
|
33
|
+
def on_slimi_interpolate(begin_, _end_, string)
|
13
34
|
block = [:multi]
|
14
35
|
scanner = ::StringScanner.new(string)
|
15
36
|
until scanner.eos?
|
16
37
|
charpos = scanner.charpos
|
17
|
-
if (value = scanner.scan(/\\#\{/)
|
38
|
+
if (value = scanner.scan(/\\#\{/))
|
18
39
|
block << [:static, value]
|
19
40
|
elsif scanner.scan(/#\{((?>[^{}]|(\{(?>[^{}]|\g<1>)*\}))*)\}/)
|
20
41
|
code = scanner[1]
|
21
42
|
begin2 = begin_ + charpos + 2
|
22
|
-
end2 = end_ + scanner.charpos - 1
|
23
43
|
if code.start_with?('{') && code.end_with?('}')
|
24
44
|
escape = true
|
25
45
|
code = code[1..-2]
|
26
46
|
begin2 -= 1
|
27
|
-
end2 -= 1
|
28
47
|
else
|
29
48
|
escape = false
|
30
49
|
end
|
31
|
-
block << [:slimi, :position, begin2,
|
50
|
+
block << [:slimi, :position, begin2, begin2 + code.length, [:slim, :output, escape, code, [:multi]]]
|
51
|
+
elsif (value = scanner.scan(/([#\\]?[^#\\]*([#\\][^\\\#{][^#\\]*)*)/)) # rubocop:disable Lint/DuplicateBranch
|
52
|
+
block << [:static, value]
|
32
53
|
end
|
33
54
|
end
|
34
55
|
block
|
data/lib/slimi/parser.rb
CHANGED
@@ -6,22 +6,30 @@ require 'temple'
|
|
6
6
|
module Slimi
|
7
7
|
class Parser < ::Temple::Parser
|
8
8
|
define_options(
|
9
|
+
:file,
|
9
10
|
attr_list_delims: {
|
10
11
|
'(' => ')',
|
11
12
|
'[' => ']',
|
12
13
|
'{' => '}'
|
13
14
|
},
|
15
|
+
code_attr_delims: {
|
16
|
+
'(' => ')',
|
17
|
+
'[' => ']',
|
18
|
+
'{' => '}'
|
19
|
+
},
|
14
20
|
shortcut: {
|
15
21
|
'#' => { attr: 'id' },
|
16
22
|
'.' => { attr: 'class' }
|
17
23
|
}
|
18
24
|
)
|
19
25
|
|
20
|
-
def initialize(
|
26
|
+
def initialize(_options = {})
|
21
27
|
super
|
28
|
+
@file_path = options[:file] || '(__TEMPLATE__)'
|
22
29
|
factory = Factory.new(
|
23
30
|
attribute_delimiters: options[:attr_list_delims] || {},
|
24
31
|
default_tag: options[:default_tag] || 'div',
|
32
|
+
ruby_attribute_delimiters: options[:code_attr_delims] || {},
|
25
33
|
shortcut: options[:shortcut] || {}
|
26
34
|
)
|
27
35
|
@attribute_delimiters = factory.attribute_delimiters
|
@@ -32,6 +40,10 @@ module Slimi
|
|
32
40
|
@quoted_attribute_regexp = factory.quoted_attribute_regexp
|
33
41
|
@tag_name_regexp = factory.tag_name_regexp
|
34
42
|
@attribute_name_regexp = factory.attribute_name_regexp
|
43
|
+
@ruby_attribute_regexp = factory.ruby_attribute_regexp
|
44
|
+
@ruby_attribute_delimiter_regexp = factory.ruby_attribute_delimiter_regexp
|
45
|
+
@ruby_attribute_delimiters = factory.ruby_attribute_delimiters
|
46
|
+
@embedded_template_regexp = factory.embedded_template_regexp
|
35
47
|
end
|
36
48
|
|
37
49
|
def call(source)
|
@@ -45,19 +57,32 @@ module Slimi
|
|
45
57
|
private
|
46
58
|
|
47
59
|
def parse_block
|
60
|
+
return if parse_blank_line
|
61
|
+
|
48
62
|
parse_indent
|
49
63
|
|
50
|
-
|
51
|
-
parse_html_comment ||
|
64
|
+
parse_html_comment ||
|
52
65
|
parse_html_conditional_comment ||
|
53
66
|
parse_slim_comment_block ||
|
54
67
|
parse_verbatim_text_block ||
|
55
68
|
parse_inline_html ||
|
56
69
|
parse_code_block ||
|
57
70
|
parse_output_block ||
|
71
|
+
parse_embedded_template ||
|
58
72
|
parse_doctype ||
|
59
73
|
parse_tag ||
|
60
|
-
|
74
|
+
syntax_error!(Errors::UnknownLineIndicatorError)
|
75
|
+
end
|
76
|
+
|
77
|
+
# Parse blank line.
|
78
|
+
# @return [Boolean] True if it could parse a blank line.
|
79
|
+
def parse_blank_line
|
80
|
+
if @scanner.skip(/[ \t]*$/)
|
81
|
+
parse_line_ending
|
82
|
+
true
|
83
|
+
else
|
84
|
+
false
|
85
|
+
end
|
61
86
|
end
|
62
87
|
|
63
88
|
def parse_indent
|
@@ -66,7 +91,7 @@ module Slimi
|
|
66
91
|
@indents << indent if @indents.empty?
|
67
92
|
|
68
93
|
if indent > @indents.last
|
69
|
-
|
94
|
+
syntax_error!(Errors::UnexpectedIndentationError) unless expecting_indentation?
|
70
95
|
|
71
96
|
@indents << indent
|
72
97
|
else
|
@@ -77,10 +102,22 @@ module Slimi
|
|
77
102
|
@stacks.pop
|
78
103
|
end
|
79
104
|
|
80
|
-
|
105
|
+
syntax_error!(Errors::MalformedIndentationError) if indent != @indents.last
|
81
106
|
end
|
82
107
|
end
|
83
108
|
|
109
|
+
# Parse embedded template lines.
|
110
|
+
# e.g.
|
111
|
+
# ruby:
|
112
|
+
# a = b + c
|
113
|
+
def parse_embedded_template
|
114
|
+
return unless @scanner.skip(@embedded_template_regexp)
|
115
|
+
|
116
|
+
embedded_template_engine_name = @scanner[1]
|
117
|
+
attributes = parse_attributes
|
118
|
+
@stacks.last << [:slim, :embedded, embedded_template_engine_name, parse_text_block, attributes]
|
119
|
+
end
|
120
|
+
|
84
121
|
# @return [Boolean]
|
85
122
|
def parse_tag
|
86
123
|
parse_tag_inner && expect_line_ending
|
@@ -117,7 +154,7 @@ module Slimi
|
|
117
154
|
@stacks.last << [:static, ' '] if with_trailing_white_space2
|
118
155
|
@stacks << block
|
119
156
|
elsif @scanner.skip(%r{[ \t]*/[ \t]*})
|
120
|
-
|
157
|
+
syntax_error!(Errors::UnexpectedTextAfterClosedTagError) unless @scanner.match?(/\r?\n/)
|
121
158
|
else
|
122
159
|
@scanner.skip(/[ \t]+/)
|
123
160
|
tag << [:slim, :text, :inline, parse_text_block]
|
@@ -163,8 +200,6 @@ module Slimi
|
|
163
200
|
marker = @scanner[1]
|
164
201
|
attribute_value = @scanner[2]
|
165
202
|
attribute_names = @attribute_shortcuts[marker]
|
166
|
-
raise 'Illegal shortcut' unless attribute_names
|
167
|
-
|
168
203
|
attribute_names.map do |attribute_name|
|
169
204
|
result << [:html, :attr, attribute_name.to_s, [:static, attribute_value]]
|
170
205
|
end
|
@@ -218,12 +253,19 @@ module Slimi
|
|
218
253
|
attribute_delimiter_closing_part_regexp = /[ \t]*#{attribute_delimiter_closing_regexp}/
|
219
254
|
end
|
220
255
|
|
256
|
+
# TODO: Support splat attributes.
|
221
257
|
loop do
|
222
258
|
if @scanner.skip(@quoted_attribute_regexp)
|
223
259
|
attribute_name = @scanner[1]
|
224
260
|
escape = @scanner[2].empty?
|
225
261
|
quote = @scanner[3]
|
226
262
|
attributes << [:html, :attr, attribute_name, [:escape, escape, parse_quoted_attribute_value(quote)]]
|
263
|
+
elsif @scanner.skip(@ruby_attribute_regexp)
|
264
|
+
attribute_name = @scanner[1]
|
265
|
+
escape = @scanner[2].empty?
|
266
|
+
attribute_value = parse_ruby_attribute_value(attribute_delimiter_closing)
|
267
|
+
syntax_error!(Errors::InvalidEmptyAttributeError) if attribute_value.empty?
|
268
|
+
attributes << [:html, :attr, attribute_name, [:slim, :attrvalue, escape, attribute_value]]
|
227
269
|
elsif !attribute_delimiter_closing_part_regexp
|
228
270
|
break
|
229
271
|
elsif @scanner.skip(boolean_attribute_regexp)
|
@@ -238,6 +280,46 @@ module Slimi
|
|
238
280
|
attributes
|
239
281
|
end
|
240
282
|
|
283
|
+
# Parse Ruby attribute value part.
|
284
|
+
# e.g. div class=foo
|
285
|
+
# ^^^
|
286
|
+
# `- Ruby attribute value
|
287
|
+
# @param [String] attribute_delimiter_closing
|
288
|
+
# @return [String]
|
289
|
+
def parse_ruby_attribute_value(attribute_delimiter_closing)
|
290
|
+
ending_regexp = /\s/
|
291
|
+
ending_regexp = ::Regexp.union(ending_regexp, attribute_delimiter_closing) if attribute_delimiter_closing
|
292
|
+
count = 0
|
293
|
+
attribute_value = +''
|
294
|
+
opening_delimiter = nil
|
295
|
+
closing_delimiter = nil
|
296
|
+
loop do
|
297
|
+
break if count.zero? && @scanner.match?(ending_regexp)
|
298
|
+
|
299
|
+
if @scanner.skip(/([,\\])\r?\n/)
|
300
|
+
attribute_value << @scanner[1] << "\n"
|
301
|
+
else
|
302
|
+
if count.positive?
|
303
|
+
if opening_delimiter && @scanner.skip(::Regexp.escape(opening_delimiter))
|
304
|
+
count += 1
|
305
|
+
elsif closing_delimiter && @scanner.skip(::Regexp.escape(closing_delimiter))
|
306
|
+
count -= 1
|
307
|
+
end
|
308
|
+
elsif @scanner.skip(@ruby_attribute_delimiter_regexp)
|
309
|
+
count = 1
|
310
|
+
opening_delimiter = @scanner.matched
|
311
|
+
closing_delimiter = @ruby_attribute_delimiters[opening_delimiter]
|
312
|
+
end
|
313
|
+
if (character = @scanner.scan(/./))
|
314
|
+
attribute_value << character
|
315
|
+
end
|
316
|
+
end
|
317
|
+
end
|
318
|
+
syntax_error!(Errors::RubyAttributeClosingDelimiterNotFoundError) if count != 0
|
319
|
+
|
320
|
+
attribute_value
|
321
|
+
end
|
322
|
+
|
241
323
|
# @return [Boolean]
|
242
324
|
def parse_html_comment
|
243
325
|
if @scanner.skip(%r{/!})
|
@@ -452,7 +534,7 @@ module Slimi
|
|
452
534
|
result = +''
|
453
535
|
result << @scanner.scan(/.*/)
|
454
536
|
while result.end_with?(',') || result.end_with?('\\')
|
455
|
-
|
537
|
+
syntax_error!(Errors::UnexpectedEosError) unless @scanner.scan(/\r?\n/)
|
456
538
|
|
457
539
|
result << "\n"
|
458
540
|
result << @scanner.scan(/.*/)
|
@@ -468,17 +550,47 @@ module Slimi
|
|
468
550
|
[:slimi, :position, begin_, end_, inner]
|
469
551
|
end
|
470
552
|
|
553
|
+
# @param [Class] syntax_error_class A child class of Slimi::Errors::SlimSyntaxError.
|
554
|
+
# @raise [Slimi::Errors::SlimSyntaxError]
|
555
|
+
def syntax_error!(syntax_error_class)
|
556
|
+
range = Range.new(index: @scanner.charpos, source: @scanner.string)
|
557
|
+
raise syntax_error_class.new(
|
558
|
+
column: range.column,
|
559
|
+
file_path: @file_path,
|
560
|
+
line: range.line,
|
561
|
+
line_number: range.line_number
|
562
|
+
)
|
563
|
+
end
|
564
|
+
|
471
565
|
# Convert human-friendly options into machine-friendly objects.
|
472
566
|
class Factory
|
567
|
+
EMBEDDED_TEMPLAE_ENGINE_NAMES = %w[
|
568
|
+
coffee
|
569
|
+
css
|
570
|
+
javascript
|
571
|
+
less
|
572
|
+
markdown
|
573
|
+
rdoc
|
574
|
+
ruby
|
575
|
+
sass
|
576
|
+
scss
|
577
|
+
textile
|
578
|
+
].freeze
|
579
|
+
|
473
580
|
# @return [Hash]
|
474
581
|
attr_reader :attribute_delimiters
|
475
582
|
|
583
|
+
# @return [Hash]
|
584
|
+
attr_reader :ruby_attribute_delimiters
|
585
|
+
|
476
586
|
# @param [Hash] attribute_delimiters
|
477
587
|
# @param [String] default_tag
|
588
|
+
# @param [Hash] ruby_attribute_delimiters
|
478
589
|
# @param [Hash] shortcut
|
479
|
-
def initialize(attribute_delimiters:, default_tag:, shortcut:)
|
590
|
+
def initialize(attribute_delimiters:, default_tag:, ruby_attribute_delimiters:, shortcut:)
|
480
591
|
@attribute_delimiters = attribute_delimiters
|
481
592
|
@default_tag = default_tag
|
593
|
+
@ruby_attribute_delimiters = ruby_attribute_delimiters
|
482
594
|
@shortcut = shortcut
|
483
595
|
end
|
484
596
|
|
@@ -534,11 +646,26 @@ module Slimi
|
|
534
646
|
%r{(#{markers_regexp}+)((?:\p{Word}|-|/\d+|:(\w|-)+)*)}
|
535
647
|
end
|
536
648
|
|
649
|
+
# @return [Regexp]
|
650
|
+
def ruby_attribute_regexp
|
651
|
+
/#{attribute_name_regexp}[ \t]*=(=?)[ \t]*/
|
652
|
+
end
|
653
|
+
|
654
|
+
# @return [Regexp]
|
655
|
+
def embedded_template_regexp
|
656
|
+
/(#{::Regexp.union(EMBEDDED_TEMPLAE_ENGINE_NAMES)})(?:[ \t]*(?:(.*)))?:([ \t]*)/
|
657
|
+
end
|
658
|
+
|
537
659
|
# @return [Regexp]
|
538
660
|
def quoted_attribute_regexp
|
539
661
|
/#{attribute_name_regexp}[ \t]*=(=?)[ \t]*("|')/
|
540
662
|
end
|
541
663
|
|
664
|
+
# @return [Regexp]
|
665
|
+
def ruby_attribute_delimiter_regexp
|
666
|
+
::Regexp.union(@ruby_attribute_delimiters.keys)
|
667
|
+
end
|
668
|
+
|
542
669
|
# @return [Regexp] Pattern that matches to tag header part.
|
543
670
|
def tag_name_regexp
|
544
671
|
markers = tag_shortcuts.keys.sort_by { |marker| -marker.size }
|
data/lib/slimi/range.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Slimi
|
4
|
+
# Get line-based information from source code and its index.
|
5
|
+
class Range
|
6
|
+
# @param [Integer] index 0-indexed per-character index.
|
7
|
+
# @param [String] source
|
8
|
+
def initialize(index:, source:)
|
9
|
+
@index = index
|
10
|
+
@source = source
|
11
|
+
end
|
12
|
+
|
13
|
+
# @return [Integer] 1-indexed column index.
|
14
|
+
def column
|
15
|
+
(@index - line_beginning_index) + 1
|
16
|
+
end
|
17
|
+
|
18
|
+
def line
|
19
|
+
@source[line_beginning_index...line_ending_index]
|
20
|
+
end
|
21
|
+
|
22
|
+
# @return [Integer] 1-indexed line index.
|
23
|
+
def line_number
|
24
|
+
@source[0..@index].scan(/^/).length
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
# @return [Integer]
|
30
|
+
def line_beginning_index
|
31
|
+
@source.rindex(/^/, @index) || 0
|
32
|
+
end
|
33
|
+
|
34
|
+
# @return [Integer]
|
35
|
+
def line_ending_index
|
36
|
+
@source.index(/$/, @index)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/lib/slimi/version.rb
CHANGED
data/lib/slimi.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: slimi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.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: 2021-12-
|
11
|
+
date: 2021-12-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: temple
|
@@ -48,6 +48,7 @@ files:
|
|
48
48
|
- lib/slimi/filters/interpolation.rb
|
49
49
|
- lib/slimi/filters/unposition.rb
|
50
50
|
- lib/slimi/parser.rb
|
51
|
+
- lib/slimi/range.rb
|
51
52
|
- lib/slimi/version.rb
|
52
53
|
- slimi.gemspec
|
53
54
|
homepage: https://github.com/r7kamura/slimi
|