slimi 0.2.0 → 0.3.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: ce4329befc9d19fb756c5609a28a3169c4f5a5aa2698771df14541b88b792da1
4
- data.tar.gz: d99512e7191942f2fabb8667cb4de369dcad5d773c1e162cc039f2911b4b1dc9
3
+ metadata.gz: 69032d72b1695bfe2afc7a11dbb965e4abf252a7c42caab252e972bcb45c13f8
4
+ data.tar.gz: af3822a5d2375300d4b07f0114c30c933eb215c88bfcee1bd6cc4938d769d76e
5
5
  SHA512:
6
- metadata.gz: 6c1b46a4afdfc4ce2a8ce816898a17e6bd448e0e76a001efbebfe7fc498375a2c1c71aaa5f40cce11012f28e7e87f5c7eef06b70b6dbcd560a6343d5494ee71c
7
- data.tar.gz: 7554a443efa9d30952d3446b92c494dd6ecf1caeb78d77aea347eef1ab862e64c35e93d4ef76c1423728734eb3b23913e75497c3358b0df2543229e05b177c07
6
+ metadata.gz: b59318e78f3c7c83e67334326992babdc60d3d299ed8973778f7c3c463b1eaaaacbefafe20ee8f7072eff13db72c3a88c5a0cae7f4ecd18629bc9e8a35645599
7
+ data.tar.gz: 173fdc474e985a89ead0c473d25bcb2bb4deb586679d17bee18d5384b29e21900e79e03567ed302bce9ac37b81dc4ad29ed3b837eeeac5027d7db57ed3879c4b
data/CHANGELOG.md CHANGED
@@ -2,6 +2,16 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 0.3.0 - 2021-12-24
6
+
7
+ ### Added
8
+
9
+ - Support unquoted attributes.
10
+
11
+ ### Fixed
12
+
13
+ - Fix bug about blank line handling.
14
+
5
15
  ## 0.2.0 - 2021-12-23
6
16
 
7
17
  ### Added
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- slimi (0.2.0)
4
+ slimi (0.3.0)
5
5
  temple
6
6
 
7
7
  GEM
data/lib/slimi/errors.rb CHANGED
@@ -36,12 +36,18 @@ module Slimi
36
36
  end
37
37
  end
38
38
 
39
+ class InvalidEmptyAttributeError < SlimSyntaxError
40
+ end
41
+
39
42
  class LineEndingNotFoundError < SlimSyntaxError
40
43
  end
41
44
 
42
45
  class MalformedIndentationError < SlimSyntaxError
43
46
  end
44
47
 
48
+ class RubyAttributeClosingDelimiterNotFoundError < SlimSyntaxError
49
+ end
50
+
45
51
  class UnexpectedEosError < SlimSyntaxError
46
52
  end
47
53
 
data/lib/slimi/parser.rb CHANGED
@@ -11,6 +11,11 @@ module Slimi
11
11
  '[' => ']',
12
12
  '{' => '}'
13
13
  },
14
+ code_attr_delims: {
15
+ '(' => ')',
16
+ '[' => ']',
17
+ '{' => '}'
18
+ },
14
19
  shortcut: {
15
20
  '#' => { attr: 'id' },
16
21
  '.' => { attr: 'class' }
@@ -22,6 +27,7 @@ module Slimi
22
27
  factory = Factory.new(
23
28
  attribute_delimiters: options[:attr_list_delims] || {},
24
29
  default_tag: options[:default_tag] || 'div',
30
+ ruby_attribute_delimiters: options[:code_attr_delims] || {},
25
31
  shortcut: options[:shortcut] || {}
26
32
  )
27
33
  @attribute_delimiters = factory.attribute_delimiters
@@ -32,6 +38,9 @@ module Slimi
32
38
  @quoted_attribute_regexp = factory.quoted_attribute_regexp
33
39
  @tag_name_regexp = factory.tag_name_regexp
34
40
  @attribute_name_regexp = factory.attribute_name_regexp
41
+ @ruby_attribute_regexp = factory.ruby_attribute_regexp
42
+ @ruby_attribute_delimiter_regexp = factory.ruby_attribute_delimiter_regexp
43
+ @ruby_attribute_delimiters = factory.ruby_attribute_delimiters
35
44
  @embedded_template_regexp = factory.embedded_template_regexp
36
45
  end
37
46
 
@@ -46,10 +55,11 @@ module Slimi
46
55
  private
47
56
 
48
57
  def parse_block
58
+ return if parse_blank_line
59
+
49
60
  parse_indent
50
61
 
51
- parse_line_ending ||
52
- parse_html_comment ||
62
+ parse_html_comment ||
53
63
  parse_html_conditional_comment ||
54
64
  parse_slim_comment_block ||
55
65
  parse_verbatim_text_block ||
@@ -62,6 +72,17 @@ module Slimi
62
72
  raise(Errors::UnknownLineIndicatorError)
63
73
  end
64
74
 
75
+ # Parse blank line.
76
+ # @return [Boolean] True if it could parse a blank line.
77
+ def parse_blank_line
78
+ if @scanner.skip(/[ \t]*$/)
79
+ parse_line_ending
80
+ true
81
+ else
82
+ false
83
+ end
84
+ end
85
+
65
86
  def parse_indent
66
87
  @scanner.skip(/[ \t]*/)
67
88
  indent = indent_from_last_match
@@ -232,12 +253,19 @@ module Slimi
232
253
  attribute_delimiter_closing_part_regexp = /[ \t]*#{attribute_delimiter_closing_regexp}/
233
254
  end
234
255
 
256
+ # TODO: Support splat attributes.
235
257
  loop do
236
258
  if @scanner.skip(@quoted_attribute_regexp)
237
259
  attribute_name = @scanner[1]
238
260
  escape = @scanner[2].empty?
239
261
  quote = @scanner[3]
240
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]]
241
269
  elsif !attribute_delimiter_closing_part_regexp
242
270
  break
243
271
  elsif @scanner.skip(boolean_attribute_regexp)
@@ -252,6 +280,46 @@ module Slimi
252
280
  attributes
253
281
  end
254
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
+
255
323
  # @return [Boolean]
256
324
  def parse_html_comment
257
325
  if @scanner.skip(%r{/!})
@@ -512,12 +580,17 @@ module Slimi
512
580
  # @return [Hash]
513
581
  attr_reader :attribute_delimiters
514
582
 
583
+ # @return [Hash]
584
+ attr_reader :ruby_attribute_delimiters
585
+
515
586
  # @param [Hash] attribute_delimiters
516
587
  # @param [String] default_tag
588
+ # @param [Hash] ruby_attribute_delimiters
517
589
  # @param [Hash] shortcut
518
- def initialize(attribute_delimiters:, default_tag:, shortcut:)
590
+ def initialize(attribute_delimiters:, default_tag:, ruby_attribute_delimiters:, shortcut:)
519
591
  @attribute_delimiters = attribute_delimiters
520
592
  @default_tag = default_tag
593
+ @ruby_attribute_delimiters = ruby_attribute_delimiters
521
594
  @shortcut = shortcut
522
595
  end
523
596
 
@@ -573,6 +646,11 @@ module Slimi
573
646
  %r{(#{markers_regexp}+)((?:\p{Word}|-|/\d+|:(\w|-)+)*)}
574
647
  end
575
648
 
649
+ # @return [Regexp]
650
+ def ruby_attribute_regexp
651
+ /#{attribute_name_regexp}[ \t]*=(=?)[ \t]*/
652
+ end
653
+
576
654
  # @return [Regexp]
577
655
  def embedded_template_regexp
578
656
  /(#{::Regexp.union(EMBEDDED_TEMPLAE_ENGINE_NAMES)})(?:[ \t]*(?:(.*)))?:([ \t]*)/
@@ -583,6 +661,11 @@ module Slimi
583
661
  /#{attribute_name_regexp}[ \t]*=(=?)[ \t]*("|')/
584
662
  end
585
663
 
664
+ # @return [Regexp]
665
+ def ruby_attribute_delimiter_regexp
666
+ ::Regexp.union(@ruby_attribute_delimiters.keys)
667
+ end
668
+
586
669
  # @return [Regexp] Pattern that matches to tag header part.
587
670
  def tag_name_regexp
588
671
  markers = tag_shortcuts.keys.sort_by { |marker| -marker.size }
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.2.0'
4
+ VERSION = '0.3.0'
5
5
  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.2.0
4
+ version: 0.3.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-22 00:00:00.000000000 Z
11
+ date: 2021-12-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: temple