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