slimi 0.5.0 → 0.7.1

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: 94ce8aacd3d29798f0831cedcd033b1706b2ccebe85264cff5321d8671d7fda3
4
- data.tar.gz: 5cbe5fe9791eafac5951f02853bb9600efb726f10d4a990d96b8ef5bfb2c4c38
3
+ metadata.gz: b6e85f64f0d3aeb959f34ab6c7779a1e355fcf03d660f1b91aea2ef77cbf3c34
4
+ data.tar.gz: a61600677c85e6eebd57d5d58b8c47fe6669487a88f1398e9f641972ad6dd603
5
5
  SHA512:
6
- metadata.gz: ba6180bd2e6e890dd2149e19390a4cb030c85ddbaac97f89d259fc9cd476673ea62cc788f84654561642ec6e86055ac5c0ae0cd8d3f4eb86a7225ca200b82d30
7
- data.tar.gz: 537418a830f3b7d791e98ac107eea63732ede37d531c1d879eb9ded7588ab2a4897569fb05a552e73f543d6a4ce159fe9a66c0f0c2d6cd870e9976d58b6a46a2
6
+ metadata.gz: eee6c48c7c8ae0270ce25c24ed8f0061c4656b4f0df3802f8536700f566a795f91f233a9a0eeda856829fb7143d35c426d31b02f77118d658950024dd4458949
7
+ data.tar.gz: 779ac85207a4ebd2511d868322281e30fe8f2364d49b77eff380dc7f93513905bfd5a8bd6253c2d6062525d8bacabf455f9a1164281e253df7098c0b54bfb23e
data/.rubocop.yml CHANGED
@@ -24,8 +24,14 @@ RSpec/ImplicitSubject:
24
24
  RSpec/MultipleExpectations:
25
25
  Enabled: false
26
26
 
27
+ RSpec/MultipleMemoizedHelpers:
28
+ Enabled: false
29
+
27
30
  RSpec/NamedSubject:
28
31
  Enabled: false
29
32
 
33
+ Security/Eval:
34
+ Enabled: false
35
+
30
36
  Style/Documentation:
31
37
  Enabled: false
data/CHANGELOG.md CHANGED
@@ -2,6 +2,47 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 0.7.1 - 2022-01-18
6
+
7
+ ### Fixed
8
+
9
+ - Fix error handling on unexpected line ending.
10
+ - Fix missing some metadata in gemspec.
11
+
12
+ ## 0.7.0 - 2022-01-04
13
+
14
+ ### Added
15
+
16
+ - Add `slimi` executable.
17
+
18
+ ### Fixed
19
+
20
+ - Remove preceding white spaces from HTML comment.
21
+ - Fix bug that :generator option was not working.
22
+ - Fix bug that Ruby code in nested line can be problem on compilation.
23
+
24
+ ## 0.6.0 - 2022-01-03
25
+
26
+ ### Added
27
+
28
+ - Support annotate_rendered_view_with_filenames.
29
+
30
+ ### Changed
31
+
32
+ - Rename expression name from slim to slimi.
33
+
34
+ ### Fixed
35
+
36
+ - Fix bug at registering handler to ActionView.
37
+ - Fix Engine options at RailsTemplateHandler.
38
+ - Define missing :generator option at Engine.
39
+
40
+ ## 0.5.1 - 2022-01-02
41
+
42
+ ### Changed
43
+
44
+ - Wrap slim attrvalue by slimi position expression.
45
+
5
46
  ## 0.5.0 - 2022-01-02
6
47
 
7
48
  ### Added
data/Gemfile CHANGED
@@ -5,6 +5,7 @@ source 'https://rubygems.org'
5
5
  # Specify your gem's dependencies in slimi.gemspec
6
6
  gemspec
7
7
 
8
+ gem 'actionview'
8
9
  gem 'rake', '~> 13.0'
9
10
  gem 'rspec'
10
11
  gem 'rubocop'
data/Gemfile.lock CHANGED
@@ -1,18 +1,48 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- slimi (0.5.0)
4
+ slimi (0.7.1)
5
5
  temple
6
+ thor
6
7
  tilt
7
8
 
8
9
  GEM
9
10
  remote: https://rubygems.org/
10
11
  specs:
12
+ actionview (7.0.0)
13
+ activesupport (= 7.0.0)
14
+ builder (~> 3.1)
15
+ erubi (~> 1.4)
16
+ rails-dom-testing (~> 2.0)
17
+ rails-html-sanitizer (~> 1.1, >= 1.2.0)
18
+ activesupport (7.0.0)
19
+ concurrent-ruby (~> 1.0, >= 1.0.2)
20
+ i18n (>= 1.6, < 2)
21
+ minitest (>= 5.1)
22
+ tzinfo (~> 2.0)
11
23
  ast (2.4.2)
24
+ builder (3.2.4)
25
+ concurrent-ruby (1.1.9)
26
+ crass (1.0.6)
12
27
  diff-lcs (1.4.4)
28
+ erubi (1.10.0)
29
+ i18n (1.8.11)
30
+ concurrent-ruby (~> 1.0)
31
+ loofah (2.13.0)
32
+ crass (~> 1.0.2)
33
+ nokogiri (>= 1.5.9)
34
+ minitest (5.15.0)
35
+ nokogiri (1.12.5-x86_64-linux)
36
+ racc (~> 1.4)
13
37
  parallel (1.21.0)
14
38
  parser (3.0.3.2)
15
39
  ast (~> 2.4.1)
40
+ racc (1.6.0)
41
+ rails-dom-testing (2.0.3)
42
+ activesupport (>= 4.2.0)
43
+ nokogiri (>= 1.6)
44
+ rails-html-sanitizer (1.4.2)
45
+ loofah (~> 2.3)
16
46
  rainbow (3.0.0)
17
47
  rake (13.0.6)
18
48
  regexp_parser (2.2.0)
@@ -45,13 +75,17 @@ GEM
45
75
  rubocop (~> 1.19)
46
76
  ruby-progressbar (1.11.0)
47
77
  temple (0.8.2)
78
+ thor (1.2.1)
48
79
  tilt (2.0.10)
80
+ tzinfo (2.0.4)
81
+ concurrent-ruby (~> 1.0)
49
82
  unicode-display_width (2.1.0)
50
83
 
51
84
  PLATFORMS
52
85
  x86_64-linux
53
86
 
54
87
  DEPENDENCIES
88
+ actionview
55
89
  rake (~> 13.0)
56
90
  rspec
57
91
  rubocop
data/README.md CHANGED
@@ -15,8 +15,67 @@ It uses Slimi to apply `rubocop --auto-correct` to embedded Ruby codes in Slim t
15
15
 
16
16
  ## Usage
17
17
 
18
- Just replace `gem 'slim'` with `gem 'slimi'` in your application's Gemfile.
18
+ ### Rails
19
+
20
+ Add this line to your application's Gemfile.
19
21
 
20
22
  ```ruby
21
23
  gem 'slimi'
22
24
  ```
25
+
26
+ This will cause `app/views/**/*.slim` files to be rendered by Slimi.
27
+
28
+ ### CLI
29
+
30
+ Slimi can be tested from command line by `slimi` executable. This takes Slim code from STDIN and converts it into another form.
31
+
32
+ ```console
33
+ $ slimi --help
34
+ Commands:
35
+ slimi compile # Convert Slim into Ruby
36
+ slimi erb # Convert Slim into ERB
37
+ slimi help [COMMAND] # Describe available commands or one specific command
38
+ slimi parse # Convert Slim into Temple expression
39
+ slimi render # Convert Slim into HTML
40
+ ```
41
+
42
+ ## Compatibility
43
+
44
+ - Line indicators
45
+ - [x] Vebatim text
46
+ - [x] Inline HTML
47
+ - [x] Control
48
+ - [x] Output
49
+ - [x] HTML comment
50
+ - [x] Code comment
51
+ - [x] IE conditional comment
52
+ - Tags
53
+ - [x] Doctype declaration
54
+ - [x] Closed tags
55
+ - [x] Trailing and leading white space
56
+ - [x] Inline tags
57
+ - [x] Text content
58
+ - [x] Dynamic content
59
+ - [x] Tag shortcuts
60
+ - [ ] Dynamic tags
61
+ - Attributes
62
+ - [x] Attributes wrapper
63
+ - [x] Quoted attributes
64
+ - [x] Ruby attributes
65
+ - [x] Boolean attributes
66
+ - [x] Attribute merging
67
+ - [x] Attribute shortcuts
68
+ - [ ] Splat attributes
69
+ - Plugins
70
+ - [ ] Include partials
71
+ - [ ] Translator/I18n
72
+ - [ ] Logic-less mode
73
+ - [ ] Smart text mode
74
+ - CLI
75
+ - [x] Convert Slim to Ruby
76
+ - [x] Convert Slim to HTML
77
+ - [x] Convert Slim to ERB
78
+ - Slimi-only features
79
+ - [x] Embedded Ruby code location
80
+ - [x] Support for annotate_rendered_view_with_filenames
81
+ - [x] Convert Slim to Temple expression by CLI
data/exe/slimi ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ $LOAD_PATH.unshift(File.expand_path('../lib', __dir__))
5
+ require 'slimi'
6
+
7
+ Slimi::Cli.start
data/lib/slimi/cli.rb ADDED
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'thor'
4
+
5
+ module Slimi
6
+ # Provide CLI features.
7
+ class Cli < ::Thor
8
+ desc 'compile', 'Convert Slim into Ruby'
9
+ def compile
10
+ slim = $stdin.read
11
+ ruby = Engine.new.call(slim)
12
+ puts ruby
13
+ end
14
+
15
+ desc 'erb', 'Convert Slim into ERB'
16
+ def erb
17
+ slim = $stdin.read
18
+ expression = ErbConverter.new.call(slim)
19
+ puts expression
20
+ end
21
+
22
+ desc 'parse', 'Convert Slim into Temple expression'
23
+ def parse
24
+ slim = $stdin.read
25
+ expression = Parser.new.call(slim)
26
+ pp expression
27
+ end
28
+
29
+ desc 'render', 'Convert Slim into HTML'
30
+ def render
31
+ slim = $stdin.read
32
+ ruby = Engine.new.call(slim)
33
+ result = eval(ruby)
34
+ puts result
35
+ end
36
+ end
37
+ end
data/lib/slimi/engine.rb CHANGED
@@ -3,21 +3,22 @@
3
3
  require 'temple'
4
4
 
5
5
  module Slimi
6
- # Convert Slim code into Ruby code.
6
+ # Convert Slim into Ruby.
7
7
  class Engine < ::Temple::Engine
8
8
  define_options(
9
9
  attr_quote: '"',
10
10
  default_tag: 'div',
11
11
  format: :xhtml,
12
+ generator: ::Temple::Generators::StringBuffer,
12
13
  merge_attrs: { 'class' => ' ' },
13
14
  pretty: false,
14
15
  sort_attrs: true
15
16
  )
16
17
 
17
18
  use Parser
18
- use Filters::Unposition
19
19
  use Filters::Embedded
20
20
  use Filters::Interpolation
21
+ use Filters::Unposition
21
22
  use Filters::DoInserter
22
23
  use Filters::EndInserter
23
24
  use Filters::Control
@@ -28,10 +29,11 @@ module Slimi
28
29
  use Filters::Attribute
29
30
  use(:AttributeRemover) { ::Temple::HTML::AttributeRemover.new(remove_empty_attrs: options[:merge_attrs].keys) }
30
31
  html :Pretty
32
+ use Filters::Amble
31
33
  filter :Escapable
32
34
  filter :ControlFlow
33
35
  filter :MultiFlattener
34
36
  filter :StaticMerger
35
- generator :StringBuffer
37
+ use(:Generator) { options[:generator] }
36
38
  end
37
39
  end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Slimi
4
+ # Convert Slim into ERB.
5
+ class ErbConverter < Engine
6
+ replace :StaticMerger, ::Temple::Filters::CodeMerger
7
+ replace :Generator, Temple::Generators::ERB
8
+ end
9
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Slimi
4
+ module Filters
5
+ # Support Rails annotate_rendered_view_with_filenames feature.
6
+ class Amble < Base
7
+ define_options(
8
+ :postamble,
9
+ :preamble
10
+ )
11
+
12
+ # @param [Array] expression
13
+ # @return [Array]
14
+ def call(expression)
15
+ result = %i[multi]
16
+ result << [:static, options[:preamble]] if options[:preamble]
17
+ result << expression
18
+ result << [:static, options[:postamble]] if options[:postamble]
19
+ result
20
+ end
21
+ end
22
+ end
23
+ end
@@ -3,7 +3,7 @@
3
3
  module Slimi
4
4
  module Filters
5
5
  # Handle `[:slimi, :attributes, ...]`.
6
- class Attribute < ::Temple::HTML::Filter
6
+ class Attribute < Base
7
7
  define_options :merge_attrs
8
8
 
9
9
  # @param [Array<Array>] expressions
@@ -16,7 +16,7 @@ module Slimi
16
16
  # @param [Array] value
17
17
  # @return [Array]
18
18
  def on_html_attr(name, value)
19
- if value[0] == :slim && value[1] == :attrvalue && !options[:merge_attrs][name]
19
+ if value[0] == :slimi && value[1] == :attrvalue && !options[:merge_attrs][name]
20
20
  escape = value[2]
21
21
  code = value[3]
22
22
  case code
@@ -42,7 +42,7 @@ module Slimi
42
42
  # @param [Boolean] escape
43
43
  # @param [String] code\
44
44
  # @return [Array]\
45
- def on_slim_attrvalue(escape, code)
45
+ def on_slimi_attrvalue(escape, code)
46
46
  if (delimiter = options[:merge_attrs][@attr])
47
47
  tmp = unique_name
48
48
  [:multi,
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'temple'
4
+
5
+ module Slimi
6
+ module Filters
7
+ # Pass-through some expressions which are unknown for Temple.
8
+ class Base < ::Temple::HTML::Filter
9
+ # @param [String] code
10
+ # @param [Array] expression
11
+ # @return [Array]
12
+ def on_slimi_control(code, expression)
13
+ [:slimi, :control, code, compile(expression)]
14
+ end
15
+
16
+ # @param [String] type
17
+ # @param [String] code
18
+ # @param [Array] expression
19
+ # @param [Array] attributes
20
+ # @return [Array]
21
+ def on_slimi_embedded(type, expression, attributes)
22
+ [:slimi, :embedded, type, compile(expression), attributes]
23
+ end
24
+
25
+ # @param [Boolean] escape
26
+ # @param [String] code
27
+ # @param [Array] expression
28
+ # @return [Array]
29
+ def on_slimi_output(escape, code, expression)
30
+ [:slimi, :output, escape, code, compile(expression)]
31
+ end
32
+
33
+ # @param [Integer] begin_
34
+ # @param [Integer] end_
35
+ # @param [Array] expression
36
+ # @return [Array]
37
+ def on_slimi_position(begin_, end_, expression)
38
+ [:slimi, :position, begin_, end_, compile(expression)]
39
+ end
40
+
41
+ # @param [String] type
42
+ # @param [Array] expression
43
+ # @return [Array]
44
+ def on_slimi_text(type, expression)
45
+ [:slimi, :text, type, compile(expression)]
46
+ end
47
+ end
48
+ end
49
+ end
@@ -2,12 +2,12 @@
2
2
 
3
3
  module Slimi
4
4
  module Filters
5
- # Handle `[:slim, :control, code, multi]`.
6
- class Control < ::Temple::HTML::Filter
5
+ # Handle `[:slimi, :control, code, multi]`.
6
+ class Control < Base
7
7
  # @param [String] code
8
8
  # @param [Array] multi
9
9
  # @return [Array]
10
- def on_slim_control(code, multi)
10
+ def on_slimi_control(code, multi)
11
11
  [
12
12
  :multi,
13
13
  [:code, code],
@@ -3,24 +3,24 @@
3
3
  module Slimi
4
4
  module Filters
5
5
  # Append missing `do` to embedded Ruby code.
6
- class DoInserter < ::Temple::HTML::Filter
6
+ class DoInserter < Base
7
7
  VALID_RUBY_LINE_REGEXP = /(\A(if|unless|else|elsif|when|begin|rescue|ensure|case)\b)|\bdo\s*(\|[^|]*\|\s*)?\Z/.freeze
8
8
 
9
9
  # @param [String] code
10
10
  # @param [Array] expressio
11
11
  # @return [Array]
12
- def on_slim_control(code, expression)
12
+ def on_slimi_control(code, expression)
13
13
  code += ' do' unless code.match?(VALID_RUBY_LINE_REGEXP) || empty_exp?(expression)
14
- [:slim, :control, code, compile(expression)]
14
+ [:slimi, :control, code, compile(expression)]
15
15
  end
16
16
 
17
17
  # @param [Boolean] escape
18
18
  # @param [String] code
19
19
  # @param [Array] expression
20
20
  # @return [Array]
21
- def on_slim_output(escape, code, expression)
21
+ def on_slimi_output(escape, code, expression)
22
22
  code += ' do' unless code.match?(VALID_RUBY_LINE_REGEXP) || empty_exp?(expression)
23
- [:slim, :output, escape, code, compile(expression)]
23
+ [:slimi, :output, escape, code, compile(expression)]
24
24
  end
25
25
  end
26
26
  end
@@ -1,23 +1,25 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'tilt'
4
+
3
5
  module Slimi
4
6
  module Filters
5
7
  # @api private
6
- class TextCollector < ::Temple::HTML::Filter
8
+ class TextCollector < Base
7
9
  def call(exp)
8
10
  @collected = ''
9
11
  super(exp)
10
12
  @collected
11
13
  end
12
14
 
13
- def on_slim_interpolate(text)
15
+ def on_slimi_interpolate(text)
14
16
  @collected << text
15
17
  nil
16
18
  end
17
19
  end
18
20
 
19
21
  # @api private
20
- class NewlineCollector < ::Temple::HTML::Filter
22
+ class NewlineCollector < Base
21
23
  def call(exp)
22
24
  @collected = [:multi]
23
25
  super(exp)
@@ -31,7 +33,7 @@ module Slimi
31
33
  end
32
34
 
33
35
  # @api private
34
- class OutputProtector < ::Temple::HTML::Filter
36
+ class OutputProtector < Base
35
37
  def call(exp)
36
38
  @protect = []
37
39
  @collected = ''
@@ -45,9 +47,9 @@ module Slimi
45
47
  nil
46
48
  end
47
49
 
48
- def on_slim_output(escape, text, content)
50
+ def on_slimi_output(escape, text, content)
49
51
  @collected << @tag
50
- @protect << [:slim, :output, escape, text, content]
52
+ @protect << [:slimi, :output, escape, text, content]
51
53
  nil
52
54
  end
53
55
 
@@ -64,7 +66,7 @@ module Slimi
64
66
 
65
67
  # Temple filter which processes embedded engines
66
68
  # @api private
67
- class Embedded < ::Temple::HTML::Filter
69
+ class Embedded < Base
68
70
  @engines = {}
69
71
 
70
72
  class << self
@@ -101,12 +103,12 @@ module Slimi
101
103
  @disabled = normalize_engine_list(options[:disable_engines])
102
104
  end
103
105
 
104
- def on_slim_embedded(name, body, attrs)
106
+ def on_slimi_embedded(name, body, attrs)
105
107
  name = name.to_sym
106
108
  raise(Temple::FilterError, "Embedded engine #{name} is disabled") unless enabled?(name)
107
109
 
108
110
  @engines[name] ||= self.class.create(name, options)
109
- @engines[name].on_slim_embedded(name, body, attrs)
111
+ @engines[name].on_slimi_embedded(name, body, attrs)
110
112
  end
111
113
 
112
114
  def enabled?(name)
@@ -122,7 +124,7 @@ module Slimi
122
124
  list&.map(&:to_sym)
123
125
  end
124
126
 
125
- class Engine < ::Temple::HTML::Filter
127
+ class Engine < Base
126
128
  protected
127
129
 
128
130
  def collect_text(body)
@@ -138,7 +140,7 @@ module Slimi
138
140
 
139
141
  # Basic tilt engine
140
142
  class TiltEngine < Engine
141
- def on_slim_embedded(engine, body, _attrs)
143
+ def on_slimi_embedded(engine, body, _attrs)
142
144
  tilt_engine = Tilt[engine] || raise(Temple::FilterError, "Tilt engine #{engine} is not available.")
143
145
  tilt_options = options[engine.to_sym] || {}
144
146
  tilt_options[:default_encoding] ||= 'utf-8'
@@ -194,7 +196,7 @@ module Slimi
194
196
  class TagEngine < Engine
195
197
  disable_option_validator!
196
198
 
197
- def on_slim_embedded(engine, body, attrs)
199
+ def on_slimi_embedded(engine, body, attrs)
198
200
  unless options[:attributes].empty?
199
201
  options[:attributes].map do |k, v|
200
202
  attrs << [:html, :attr, k, [:static, v]]
@@ -207,7 +209,7 @@ module Slimi
207
209
  opts.delete(:tag)
208
210
  opts.delete(:attributes)
209
211
  @engine ||= options[:engine].new(opts)
210
- body = @engine.on_slim_embedded(engine, body, attrs)
212
+ body = @engine.on_slimi_embedded(engine, body, attrs)
211
213
  end
212
214
 
213
215
  [:html, :tag, options[:tag], attrs, body]
@@ -221,14 +223,14 @@ module Slimi
221
223
 
222
224
  set_options tag: :script, attributes: {}
223
225
 
224
- def on_slim_embedded(engine, body, attrs)
226
+ def on_slimi_embedded(engine, body, attrs)
225
227
  super(engine, [:html, :js, body], attrs)
226
228
  end
227
229
  end
228
230
 
229
231
  # Embeds ruby code
230
232
  class RubyEngine < Engine
231
- def on_slim_embedded(_engine, body, _attrs)
233
+ def on_slimi_embedded(_engine, body, _attrs)
232
234
  [:multi, [:newline], [:code, "#{collect_text(body)}\n"]]
233
235
  end
234
236
  end
@@ -3,7 +3,7 @@
3
3
  module Slimi
4
4
  module Filters
5
5
  # Append missing `end` line to embedded Ruby code in control block.
6
- class EndInserter < ::Temple::HTML::Filter
6
+ class EndInserter < Base
7
7
  # @param [Array<Array>] expressions
8
8
  def on_multi(*expressions)
9
9
  result = [:multi]
@@ -49,7 +49,7 @@ module Slimi
49
49
 
50
50
  # @return [Boolean]
51
51
  def control?
52
- @expression[0] == :slim && @expression[1] == :control
52
+ @expression[0] == :slimi && @expression[1] == :control
53
53
  end
54
54
 
55
55
  # @return [Boolean]
@@ -4,29 +4,7 @@ require 'strscan'
4
4
 
5
5
  module Slimi
6
6
  module Filters
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
-
7
+ class Interpolation < Base
30
8
  # @param [Integer] begin_
31
9
  # @param [Integer] end_
32
10
  # @return [Array] S-expression.
@@ -47,7 +25,7 @@ module Slimi
47
25
  else
48
26
  escape = false
49
27
  end
50
- block << [:slimi, :position, begin2, begin2 + code.length, [:slim, :output, escape, code, [:multi]]]
28
+ block << [:slimi, :position, begin2, begin2 + code.length, [:slimi, :output, escape, code, [:multi]]]
51
29
  elsif (value = scanner.scan(/([#\\]?[^#\\]*([#\\][^\\\#{][^#\\]*)*)/)) # rubocop:disable Lint/DuplicateBranch
52
30
  block << [:static, value]
53
31
  end
@@ -2,8 +2,8 @@
2
2
 
3
3
  module Slimi
4
4
  module Filters
5
- # Handle `[:slim, :output, escape, code, multi]`.
6
- class Output < ::Temple::HTML::Filter
5
+ # Handle `[:slimi, :output, escape, code, multi]`.
6
+ class Output < Base
7
7
  define_options :disable_capture
8
8
 
9
9
  IF_REGEXP = /\A(if|unless)\b|\bdo\s*(\|[^|]*\|)?\s*$/.freeze
@@ -12,7 +12,7 @@ module Slimi
12
12
  # @param [String] code
13
13
  # @param [Array] multi
14
14
  # @return [Array]
15
- def on_slim_output(escape, code, multi)
15
+ def on_slimi_output(escape, code, multi)
16
16
  if code.match?(IF_REGEXP)
17
17
  tmp = unique_name
18
18
  [
@@ -2,12 +2,12 @@
2
2
 
3
3
  module Slimi
4
4
  module Filters
5
- # Handle `[:slim, :text, multi]`.
6
- class Text < ::Temple::HTML::Filter
5
+ # Handle `[:slimi, :text, multi]`.
6
+ class Text < Base
7
7
  # @param [Symbol] _type
8
8
  # @param [Array] multi
9
9
  # @return [Array]
10
- def on_slim_text(_type, multi)
10
+ def on_slimi_text(_type, multi)
11
11
  compile(multi)
12
12
  end
13
13
  end
@@ -2,29 +2,13 @@
2
2
 
3
3
  module Slimi
4
4
  module Filters
5
- class Unposition
6
- def initialize(*); end
7
-
8
- # @param [Array] node S-expression.
9
- # @return [Array] S-expression.
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] == :position
19
- call(value[4])
20
- else
21
- value.map do |element|
22
- call(element)
23
- end
24
- end
25
- else
26
- value
27
- end
5
+ class Unposition < Base
6
+ # @param [Integer] _begin
7
+ # @param [Integer] _end
8
+ # @param [Array] expression
9
+ # @return [Array]
10
+ def on_slimi_position(_begin, _end, expression)
11
+ compile(expression)
28
12
  end
29
13
  end
30
14
  end
data/lib/slimi/filters.rb CHANGED
@@ -2,7 +2,9 @@
2
2
 
3
3
  module Slimi
4
4
  module Filters
5
+ autoload :Amble, 'slimi/filters/amble'
5
6
  autoload :Attribute, 'slimi/filters/attribute'
7
+ autoload :Base, 'slimi/filters/base'
6
8
  autoload :Control, 'slimi/filters/control'
7
9
  autoload :DoInserter, 'slimi/filters/do_inserter'
8
10
  autoload :Embedded, 'slimi/filters/embedded'
data/lib/slimi/parser.rb CHANGED
@@ -115,7 +115,7 @@ module Slimi
115
115
 
116
116
  embedded_template_engine_name = @scanner[1]
117
117
  attributes = parse_attributes
118
- @stacks.last << [:slim, :embedded, embedded_template_engine_name, parse_text_block, attributes]
118
+ @stacks.last << [:slimi, :embedded, embedded_template_engine_name, parse_text_block, attributes]
119
119
  end
120
120
 
121
121
  # @return [Boolean]
@@ -150,14 +150,14 @@ module Slimi
150
150
  block = [:multi]
151
151
  @stacks.last.insert(-2, [:static, ' ']) if with_leading_white_space2
152
152
  @scanner.skip(/[ \t]+/)
153
- tag << with_position { [:slim, :output, escape, parse_broken_lines, block] }
153
+ tag << with_position { [:slimi, :output, escape, parse_broken_lines, block] }
154
154
  @stacks.last << [:static, ' '] if with_trailing_white_space2
155
155
  @stacks << block
156
156
  elsif @scanner.skip(%r{[ \t]*/[ \t]*})
157
157
  syntax_error!(Errors::UnexpectedTextAfterClosedTagError) unless @scanner.match?(/\r?\n/)
158
158
  else
159
159
  @scanner.skip(/[ \t]+/)
160
- tag << [:slim, :text, :inline, parse_text_block]
160
+ tag << [:slimi, :text, :inline, parse_text_block]
161
161
  end
162
162
  true
163
163
  else
@@ -269,9 +269,10 @@ module Slimi
269
269
  elsif @scanner.skip(@ruby_attribute_regexp)
270
270
  attribute_name = @scanner[1]
271
271
  escape = @scanner[2].empty?
272
+ charpos = @scanner.charpos
272
273
  attribute_value = parse_ruby_attribute_value(attribute_delimiter_closing)
273
274
  syntax_error!(Errors::InvalidEmptyAttributeError) if attribute_value.empty?
274
- attributes << [:html, :attr, attribute_name, [:slim, :attrvalue, escape, attribute_value]]
275
+ attributes << [:html, :attr, attribute_name, [:slimi, :position, charpos, charpos + attribute_value.length, [:slimi, :attrvalue, escape, attribute_value]]]
275
276
  elsif !attribute_delimiter_closing_part_regexp
276
277
  break
277
278
  elsif @scanner.skip(boolean_attribute_regexp)
@@ -331,9 +332,9 @@ module Slimi
331
332
 
332
333
  # @return [Boolean]
333
334
  def parse_html_comment
334
- if @scanner.skip(%r{/!})
335
+ if @scanner.skip(%r{/![ \t]*})
335
336
  text_block = parse_text_block
336
- text = [:slim, :text, :verbatim, text_block]
337
+ text = [:slimi, :text, :verbatim, text_block]
337
338
  @stacks.last << [:html, :comment, text]
338
339
  true
339
340
  else
@@ -380,7 +381,7 @@ module Slimi
380
381
  def parse_verbatim_text_block_inner
381
382
  if @scanner.skip(/([|']) ?/)
382
383
  with_trailing_white_space = @scanner[1] == "'"
383
- @stacks.last << [:slim, :text, :verbatim, parse_text_block]
384
+ @stacks.last << [:slimi, :text, :verbatim, parse_text_block]
384
385
  @stacks.last << [:static, ' '] if with_trailing_white_space
385
386
  true
386
387
  else
@@ -419,7 +420,7 @@ module Slimi
419
420
  if @scanner.skip(/-/)
420
421
  block = [:multi]
421
422
  @scanner.skip(/[ \t]+/)
422
- @stacks.last << with_position { [:slim, :control, parse_broken_lines, block] }
423
+ @stacks.last << with_position { [:slimi, :control, parse_broken_lines, block] }
423
424
  @stacks << block
424
425
  true
425
426
  else
@@ -442,7 +443,7 @@ module Slimi
442
443
  block = [:multi]
443
444
  @stacks.last << [:static, ' '] if with_trailing_white_space
444
445
  @scanner.skip(/[ \t]+/)
445
- @stacks.last << with_position { [:slim, :output, escape, parse_broken_lines, block] }
446
+ @stacks.last << with_position { [:slimi, :output, escape, parse_broken_lines, block] }
446
447
  @stacks.last << [:static, ' '] if with_leading_white_space
447
448
  @stacks << block
448
449
  else
@@ -472,7 +473,7 @@ module Slimi
472
473
 
473
474
  # @raise
474
475
  def expect_line_ending
475
- parse_line_ending || @scanner.eos? || raise(LineEndingNotFoundError)
476
+ parse_line_ending || @scanner.eos? || syntax_error!(Errors::LineEndingNotFoundError)
476
477
  end
477
478
 
478
479
  # @return [Integer] Indent level.
@@ -1,14 +1,77 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Slimi
4
+ # Render Slim template in response to requests from Rails.
4
5
  class RailsTemplateHandler
5
- def initialize
6
- @engine = Engine.new
6
+ # @param [ActionView::Template] template
7
+ # @param [String, nil] source
8
+ # @return [String]
9
+ def call(template, source = nil)
10
+ Renderer.new(
11
+ source: source,
12
+ template: template
13
+ ).call
7
14
  end
8
15
 
9
- def call(template, source = nil)
10
- source ||= template.source
11
- @engine.call(source)
16
+ # Render HTML from given source and options.
17
+ class Renderer
18
+ # @param [String] source
19
+ # @param [ActionView::Template] template
20
+ def initialize(
21
+ source:,
22
+ template:
23
+ )
24
+ @source = source
25
+ @template = template
26
+ end
27
+
28
+ # @return [String]
29
+ def call
30
+ engine.call(source)
31
+ end
32
+
33
+ private
34
+
35
+ # @return [Slimi::Engine]
36
+ def engine
37
+ Engine.new(engine_options)
38
+ end
39
+
40
+ # @return [Hash{Symbol => Object}]
41
+ def engine_options
42
+ engine_default_options.merge(engine_amble_options)
43
+ end
44
+
45
+ # @return [Hash{Symbol => Object}]
46
+ def engine_default_options
47
+ {
48
+ generator: ::Temple::Generators::RailsOutputBuffer,
49
+ streaming: true,
50
+ use_html_safe: true
51
+ }
52
+ end
53
+
54
+ # @return [Hash{Symbol => Object}]
55
+ def engine_amble_options
56
+ if with_annotate_rendered_view_with_filenames?
57
+ {
58
+ postamble: "<!-- END #{@template.short_identifier} -->\n",
59
+ preamble: "<!-- BEGIN #{@template.short_identifier} -->\n"
60
+ }
61
+ else
62
+ {}
63
+ end
64
+ end
65
+
66
+ # @return [String]
67
+ def source
68
+ @source || @template.source
69
+ end
70
+
71
+ # @return [Boolean]
72
+ def with_annotate_rendered_view_with_filenames?
73
+ ::ActionView::Base.try(:annotate_rendered_view_with_filenames) && @template.format == :html
74
+ end
12
75
  end
13
76
  end
14
77
  end
data/lib/slimi/railtie.rb CHANGED
@@ -5,6 +5,7 @@ module Slimi
5
5
  initializer 'Register Slimi template handler' do
6
6
  ::ActiveSupport.on_load(:action_view) do
7
7
  ::ActionView::Template.register_template_handler(
8
+ :slim,
8
9
  RailsTemplateHandler.new
9
10
  )
10
11
  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.5.0'
4
+ VERSION = '0.7.1'
5
5
  end
data/lib/slimi.rb CHANGED
@@ -3,7 +3,9 @@
3
3
  require_relative 'slimi/version'
4
4
 
5
5
  module Slimi
6
+ autoload :Cli, 'slimi/cli'
6
7
  autoload :Engine, 'slimi/engine'
8
+ autoload :ErbConverter, 'slimi/erb_converter'
7
9
  autoload :Errors, 'slimi/errors'
8
10
  autoload :Filters, 'slimi/filters'
9
11
  autoload :Parser, 'slimi/parser'
data/slimi.gemspec CHANGED
@@ -27,10 +27,8 @@ Gem::Specification.new do |spec|
27
27
  spec.bindir = 'exe'
28
28
  spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
29
29
  spec.require_paths = ['lib']
30
- spec.metadata = {
31
- 'rubygems_mfa_required' => 'true'
32
- }
33
30
 
34
31
  spec.add_dependency 'temple'
32
+ spec.add_dependency 'thor'
35
33
  spec.add_dependency 'tilt'
36
34
  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.5.0
4
+ version: 0.7.1
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-01 00:00:00.000000000 Z
11
+ date: 2022-01-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: temple
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: thor
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: tilt
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -41,7 +55,8 @@ dependencies:
41
55
  description:
42
56
  email:
43
57
  - r7kamura@gmail.com
44
- executables: []
58
+ executables:
59
+ - slimi
45
60
  extensions: []
46
61
  extra_rdoc_files: []
47
62
  files:
@@ -56,11 +71,16 @@ files:
56
71
  - Rakefile
57
72
  - bin/console
58
73
  - bin/setup
74
+ - exe/slimi
59
75
  - lib/slimi.rb
76
+ - lib/slimi/cli.rb
60
77
  - lib/slimi/engine.rb
78
+ - lib/slimi/erb_converter.rb
61
79
  - lib/slimi/errors.rb
62
80
  - lib/slimi/filters.rb
81
+ - lib/slimi/filters/amble.rb
63
82
  - lib/slimi/filters/attribute.rb
83
+ - lib/slimi/filters/base.rb
64
84
  - lib/slimi/filters/control.rb
65
85
  - lib/slimi/filters/do_inserter.rb
66
86
  - lib/slimi/filters/embedded.rb
@@ -79,7 +99,9 @@ homepage: https://github.com/r7kamura/slimi
79
99
  licenses:
80
100
  - MIT
81
101
  metadata:
82
- rubygems_mfa_required: 'true'
102
+ homepage_uri: https://github.com/r7kamura/slimi
103
+ source_code_uri: https://github.com/r7kamura/slimi
104
+ changelog_uri: https://github.com/r7kamura/slimi/blob/main/CHANGELOG.md
83
105
  post_install_message:
84
106
  rdoc_options: []
85
107
  require_paths: