slimi 0.1.1 → 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e7aed4b0083f7ec850df87f869b5687873dcf98fd6f80ab93854c101e0d03098
4
- data.tar.gz: bfa813fce529081b2eb876e00a9b722feecf914a5741c9ca341ec2aa8d1463ac
3
+ metadata.gz: ce4329befc9d19fb756c5609a28a3169c4f5a5aa2698771df14541b88b792da1
4
+ data.tar.gz: d99512e7191942f2fabb8667cb4de369dcad5d773c1e162cc039f2911b4b1dc9
5
5
  SHA512:
6
- metadata.gz: bcd9e3abde25cca87e45eb7244658ed6a99d56e458d2b0b3e1199252eb5621480fb7afc12f6246f3760e13a07a2efaabd80f45e5deb868212228cbf96b582a01
7
- data.tar.gz: 9fd6030053873163c81f12646461cb502a4d3632e9de4bd8ec77081546081e50fd7e088ad93f23b15666d54007ca1b298f44dd63eeb74b2f5778e716e5e3d6fc
6
+ metadata.gz: 6c1b46a4afdfc4ce2a8ce816898a17e6bd448e0e76a001efbebfe7fc498375a2c1c71aaa5f40cce11012f28e7e87f5c7eef06b70b6dbcd560a6343d5494ee71c
7
+ data.tar.gz: 7554a443efa9d30952d3446b92c494dd6ecf1caeb78d77aea347eef1ab862e64c35e93d4ef76c1423728734eb3b23913e75497c3358b0df2543229e05b177c07
data/CHANGELOG.md CHANGED
@@ -2,6 +2,13 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 0.2.0 - 2021-12-23
6
+
7
+ ### Added
8
+
9
+ - Support embedded template.
10
+ - Show useful message at syntax error.
11
+
5
12
  ## 0.1.1 - 2021-12-21
6
13
 
7
14
  ### Fixed
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- slimi (0.1.0)
4
+ slimi (0.2.0)
5
5
  temple
6
6
 
7
7
  GEM
data/README.md CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  Yet another implementation for [Slim](https://github.com/slim-template/slim) template language.
7
7
 
8
- The current goal is to generate AST with detailed location information so that the embedded Ruby code in slim templates can be auto-corrected by Linter such as RuboCop.
8
+ Slimi is used by [Slimcop](https://github.com/r7kamura/slimcop).
9
9
 
10
10
  ## Installation
11
11
 
@@ -30,21 +30,3 @@ gem install slimi
30
30
  ## Usage
31
31
 
32
32
  TBD.
33
-
34
- ## Development
35
-
36
- 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.
37
-
38
- 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).
39
-
40
- ## Contributing
41
-
42
- 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).
43
-
44
- ## License
45
-
46
- The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
47
-
48
- ## Code of Conduct
49
-
50
- 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,53 @@ module Slimi
5
5
  class BaseError < StandardError
6
6
  end
7
7
 
8
- class ParserError < BaseError
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
9
37
  end
10
38
 
11
- class LineEndingNotFoundError < ParserError
39
+ class LineEndingNotFoundError < SlimSyntaxError
12
40
  end
13
41
 
14
- class MalformedIndentationError < ParserError
42
+ class MalformedIndentationError < SlimSyntaxError
15
43
  end
16
44
 
17
- class UnexpectedEosError < ParserError
45
+ class UnexpectedEosError < SlimSyntaxError
18
46
  end
19
47
 
20
- class UnexpectedIndentationError < ParserError
48
+ class UnexpectedIndentationError < SlimSyntaxError
21
49
  end
22
50
 
23
- class UnexpectedTextAfterClosedTagError < ParserError
51
+ class UnexpectedTextAfterClosedTagError < SlimSyntaxError
24
52
  end
25
53
 
26
- class UnknownLineIndicator < ParserError
54
+ class UnknownLineIndicator < SlimSyntaxError
27
55
  end
28
56
  end
29
57
  end
data/lib/slimi/parser.rb CHANGED
@@ -32,6 +32,7 @@ module Slimi
32
32
  @quoted_attribute_regexp = factory.quoted_attribute_regexp
33
33
  @tag_name_regexp = factory.tag_name_regexp
34
34
  @attribute_name_regexp = factory.attribute_name_regexp
35
+ @embedded_template_regexp = factory.embedded_template_regexp
35
36
  end
36
37
 
37
38
  def call(source)
@@ -55,6 +56,7 @@ module Slimi
55
56
  parse_inline_html ||
56
57
  parse_code_block ||
57
58
  parse_output_block ||
59
+ parse_embedded_template ||
58
60
  parse_doctype ||
59
61
  parse_tag ||
60
62
  raise(Errors::UnknownLineIndicatorError)
@@ -66,7 +68,7 @@ module Slimi
66
68
  @indents << indent if @indents.empty?
67
69
 
68
70
  if indent > @indents.last
69
- raise Errors::UnexpectedIndentationError unless expecting_indentation?
71
+ syntax_error!(Errors::UnexpectedIndentationError) unless expecting_indentation?
70
72
 
71
73
  @indents << indent
72
74
  else
@@ -77,10 +79,22 @@ module Slimi
77
79
  @stacks.pop
78
80
  end
79
81
 
80
- raise Errors::MalformedIndentationError if indent != @indents.last
82
+ syntax_error!(Errors::MalformedIndentationError) if indent != @indents.last
81
83
  end
82
84
  end
83
85
 
86
+ # Parse embedded template lines.
87
+ # e.g.
88
+ # ruby:
89
+ # a = b + c
90
+ def parse_embedded_template
91
+ return unless @scanner.skip(@embedded_template_regexp)
92
+
93
+ embedded_template_engine_name = @scanner[1]
94
+ attributes = parse_attributes
95
+ @stacks.last << [:slim, :embedded, embedded_template_engine_name, parse_text_block, attributes]
96
+ end
97
+
84
98
  # @return [Boolean]
85
99
  def parse_tag
86
100
  parse_tag_inner && expect_line_ending
@@ -117,7 +131,7 @@ module Slimi
117
131
  @stacks.last << [:static, ' '] if with_trailing_white_space2
118
132
  @stacks << block
119
133
  elsif @scanner.skip(%r{[ \t]*/[ \t]*})
120
- raise Errors::UnexpectedTextAfterClosedTagError unless @scanner.match?(/\r?\n/)
134
+ syntax_error!(Errors::UnexpectedTextAfterClosedTagError) unless @scanner.match?(/\r?\n/)
121
135
  else
122
136
  @scanner.skip(/[ \t]+/)
123
137
  tag << [:slim, :text, :inline, parse_text_block]
@@ -452,7 +466,7 @@ module Slimi
452
466
  result = +''
453
467
  result << @scanner.scan(/.*/)
454
468
  while result.end_with?(',') || result.end_with?('\\')
455
- raise Errors::UnexpectedEosError unless @scanner.scan(/\r?\n/)
469
+ syntax_error!(Errors::UnexpectedEosError) unless @scanner.scan(/\r?\n/)
456
470
 
457
471
  result << "\n"
458
472
  result << @scanner.scan(/.*/)
@@ -468,8 +482,33 @@ module Slimi
468
482
  [:slimi, :position, begin_, end_, inner]
469
483
  end
470
484
 
485
+ # @param [Class] syntax_error_class A child class of Slimi::Errors::SlimSyntaxError.
486
+ # @raise [Slimi::Errors::SlimSyntaxError]
487
+ def syntax_error!(syntax_error_class)
488
+ range = Range.new(index: @scanner.charpos, source: @scanner.string)
489
+ raise syntax_error_class.new(
490
+ column: range.column,
491
+ file_path: '(__TEMPLATE__)',
492
+ line: range.line,
493
+ line_number: range.line_number
494
+ )
495
+ end
496
+
471
497
  # Convert human-friendly options into machine-friendly objects.
472
498
  class Factory
499
+ EMBEDDED_TEMPLAE_ENGINE_NAMES = %w[
500
+ coffee
501
+ css
502
+ javascript
503
+ less
504
+ markdown
505
+ rdoc
506
+ ruby
507
+ sass
508
+ scss
509
+ textile
510
+ ].freeze
511
+
473
512
  # @return [Hash]
474
513
  attr_reader :attribute_delimiters
475
514
 
@@ -534,6 +573,11 @@ module Slimi
534
573
  %r{(#{markers_regexp}+)((?:\p{Word}|-|/\d+|:(\w|-)+)*)}
535
574
  end
536
575
 
576
+ # @return [Regexp]
577
+ def embedded_template_regexp
578
+ /(#{::Regexp.union(EMBEDDED_TEMPLAE_ENGINE_NAMES)})(?:[ \t]*(?:(.*)))?:([ \t]*)/
579
+ end
580
+
537
581
  # @return [Regexp]
538
582
  def quoted_attribute_regexp
539
583
  /#{attribute_name_regexp}[ \t]*=(=?)[ \t]*("|')/
@@ -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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Slimi
4
- VERSION = '0.1.1'
4
+ VERSION = '0.2.0'
5
5
  end
data/lib/slimi.rb CHANGED
@@ -6,4 +6,5 @@ module Slimi
6
6
  autoload :Errors, 'slimi/errors'
7
7
  autoload :Filters, 'slimi/filters'
8
8
  autoload :Parser, 'slimi/parser'
9
+ autoload :Range, 'slimi/range'
9
10
  end
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.1.1
4
+ version: 0.2.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-20 00:00:00.000000000 Z
11
+ date: 2021-12-22 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