slimi 0.5.0 → 0.7.1

Sign up to get free protection for your applications and to get access to all the features.
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: