super-pro-kit 0.0.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.
Files changed (127) hide show
  1. checksums.yaml +7 -0
  2. data/slim-5.2.1/CHANGES +496 -0
  3. data/slim-5.2.1/Gemfile +43 -0
  4. data/slim-5.2.1/LICENSE +21 -0
  5. data/slim-5.2.1/README.jp.md +1276 -0
  6. data/slim-5.2.1/README.md +1313 -0
  7. data/slim-5.2.1/Rakefile +80 -0
  8. data/slim-5.2.1/bin/slimrb +6 -0
  9. data/slim-5.2.1/doc/include.md +20 -0
  10. data/slim-5.2.1/doc/jp/include.md +20 -0
  11. data/slim-5.2.1/doc/jp/logic_less.md +137 -0
  12. data/slim-5.2.1/doc/jp/smart.md +102 -0
  13. data/slim-5.2.1/doc/jp/translator.md +28 -0
  14. data/slim-5.2.1/doc/logic_less.md +137 -0
  15. data/slim-5.2.1/doc/smart.md +120 -0
  16. data/slim-5.2.1/doc/translator.md +28 -0
  17. data/slim-5.2.1/lib/slim/code_attributes.rb +68 -0
  18. data/slim-5.2.1/lib/slim/command.rb +122 -0
  19. data/slim-5.2.1/lib/slim/controls.rb +61 -0
  20. data/slim-5.2.1/lib/slim/do_inserter.rb +34 -0
  21. data/slim-5.2.1/lib/slim/embedded.rb +248 -0
  22. data/slim-5.2.1/lib/slim/end_inserter.rb +63 -0
  23. data/slim-5.2.1/lib/slim/engine.rb +42 -0
  24. data/slim-5.2.1/lib/slim/erb_converter.rb +15 -0
  25. data/slim-5.2.1/lib/slim/filter.rb +31 -0
  26. data/slim-5.2.1/lib/slim/grammar.rb +24 -0
  27. data/slim-5.2.1/lib/slim/include.rb +58 -0
  28. data/slim-5.2.1/lib/slim/interpolation.rb +36 -0
  29. data/slim-5.2.1/lib/slim/logic_less/context.rb +126 -0
  30. data/slim-5.2.1/lib/slim/logic_less/filter.rb +81 -0
  31. data/slim-5.2.1/lib/slim/logic_less.rb +6 -0
  32. data/slim-5.2.1/lib/slim/parser.rb +535 -0
  33. data/slim-5.2.1/lib/slim/railtie.rb +19 -0
  34. data/slim-5.2.1/lib/slim/smart/escaper.rb +42 -0
  35. data/slim-5.2.1/lib/slim/smart/filter.rb +97 -0
  36. data/slim-5.2.1/lib/slim/smart/parser.rb +35 -0
  37. data/slim-5.2.1/lib/slim/smart.rb +9 -0
  38. data/slim-5.2.1/lib/slim/splat/builder.rb +115 -0
  39. data/slim-5.2.1/lib/slim/splat/filter.rb +93 -0
  40. data/slim-5.2.1/lib/slim/template.rb +6 -0
  41. data/slim-5.2.1/lib/slim/translator.rb +119 -0
  42. data/slim-5.2.1/lib/slim/version.rb +6 -0
  43. data/slim-5.2.1/lib/slim.rb +16 -0
  44. data/slim-5.2.1/slim.gemspec +33 -0
  45. data/slim-5.2.1/test/core/helper.rb +201 -0
  46. data/slim-5.2.1/test/core/test_code_blocks.rb +194 -0
  47. data/slim-5.2.1/test/core/test_code_escaping.rb +162 -0
  48. data/slim-5.2.1/test/core/test_code_evaluation.rb +181 -0
  49. data/slim-5.2.1/test/core/test_code_output.rb +168 -0
  50. data/slim-5.2.1/test/core/test_code_structure.rb +203 -0
  51. data/slim-5.2.1/test/core/test_commands.rb +219 -0
  52. data/slim-5.2.1/test/core/test_embedded_engines.rb +247 -0
  53. data/slim-5.2.1/test/core/test_encoding.rb +28 -0
  54. data/slim-5.2.1/test/core/test_erb_converter.rb +65 -0
  55. data/slim-5.2.1/test/core/test_html_attributes.rb +276 -0
  56. data/slim-5.2.1/test/core/test_html_escaping.rb +65 -0
  57. data/slim-5.2.1/test/core/test_html_structure.rb +599 -0
  58. data/slim-5.2.1/test/core/test_parser_errors.rb +148 -0
  59. data/slim-5.2.1/test/core/test_pretty.rb +163 -0
  60. data/slim-5.2.1/test/core/test_ruby_errors.rb +200 -0
  61. data/slim-5.2.1/test/core/test_slim_template.rb +78 -0
  62. data/slim-5.2.1/test/core/test_splat_prefix_option.rb +155 -0
  63. data/slim-5.2.1/test/core/test_tabs.rb +169 -0
  64. data/slim-5.2.1/test/core/test_text_interpolation.rb +79 -0
  65. data/slim-5.2.1/test/core/test_thread_options.rb +18 -0
  66. data/slim-5.2.1/test/core/test_unicode.rb +15 -0
  67. data/slim-5.2.1/test/include/files/recursive.slim +1 -0
  68. data/slim-5.2.1/test/include/files/slimfile.slim +3 -0
  69. data/slim-5.2.1/test/include/files/subdir/test.slim +1 -0
  70. data/slim-5.2.1/test/include/files/textfile +1 -0
  71. data/slim-5.2.1/test/include/test_include.rb +24 -0
  72. data/slim-5.2.1/test/literate/TESTS.md +1323 -0
  73. data/slim-5.2.1/test/literate/helper.rb +15 -0
  74. data/slim-5.2.1/test/literate/run.rb +92 -0
  75. data/slim-5.2.1/test/logic_less/test_logic_less.rb +330 -0
  76. data/slim-5.2.1/test/rails/Rakefile +7 -0
  77. data/slim-5.2.1/test/rails/app/assets/config/manifest.js +1 -0
  78. data/slim-5.2.1/test/rails/app/controllers/application_controller.rb +2 -0
  79. data/slim-5.2.1/test/rails/app/controllers/entries_controller.rb +5 -0
  80. data/slim-5.2.1/test/rails/app/controllers/slim_controller.rb +46 -0
  81. data/slim-5.2.1/test/rails/app/helpers/application_helper.rb +5 -0
  82. data/slim-5.2.1/test/rails/app/models/entry.rb +16 -0
  83. data/slim-5.2.1/test/rails/app/views/entries/edit.html.slim +3 -0
  84. data/slim-5.2.1/test/rails/app/views/layouts/application.html+testvariant.slim +10 -0
  85. data/slim-5.2.1/test/rails/app/views/layouts/application.html.slim +10 -0
  86. data/slim-5.2.1/test/rails/app/views/slim/_partial.html.slim +1 -0
  87. data/slim-5.2.1/test/rails/app/views/slim/attributes.html.slim +3 -0
  88. data/slim-5.2.1/test/rails/app/views/slim/content_for.html.slim +7 -0
  89. data/slim-5.2.1/test/rails/app/views/slim/erb.html.erb +1 -0
  90. data/slim-5.2.1/test/rails/app/views/slim/form_for.html.slim +2 -0
  91. data/slim-5.2.1/test/rails/app/views/slim/helper.html.slim +4 -0
  92. data/slim-5.2.1/test/rails/app/views/slim/integers.html.slim +1 -0
  93. data/slim-5.2.1/test/rails/app/views/slim/no_layout.html.slim +1 -0
  94. data/slim-5.2.1/test/rails/app/views/slim/normal.html.slim +1 -0
  95. data/slim-5.2.1/test/rails/app/views/slim/partial.html.slim +2 -0
  96. data/slim-5.2.1/test/rails/app/views/slim/splat.html.slim +2 -0
  97. data/slim-5.2.1/test/rails/app/views/slim/splat_with_delimiter.slim +1 -0
  98. data/slim-5.2.1/test/rails/app/views/slim/thread_options.html.slim +1 -0
  99. data/slim-5.2.1/test/rails/app/views/slim/variables.html.slim +1 -0
  100. data/slim-5.2.1/test/rails/app/views/slim/xml.slim +1 -0
  101. data/slim-5.2.1/test/rails/config/application.rb +44 -0
  102. data/slim-5.2.1/test/rails/config/boot.rb +10 -0
  103. data/slim-5.2.1/test/rails/config/environment.rb +5 -0
  104. data/slim-5.2.1/test/rails/config/environments/test.rb +34 -0
  105. data/slim-5.2.1/test/rails/config/initializers/backtrace_silencers.rb +7 -0
  106. data/slim-5.2.1/test/rails/config/initializers/inflections.rb +10 -0
  107. data/slim-5.2.1/test/rails/config/initializers/mime_types.rb +5 -0
  108. data/slim-5.2.1/test/rails/config/initializers/session_store.rb +8 -0
  109. data/slim-5.2.1/test/rails/config/locales/en.yml +5 -0
  110. data/slim-5.2.1/test/rails/config/routes.rb +60 -0
  111. data/slim-5.2.1/test/rails/config.ru +4 -0
  112. data/slim-5.2.1/test/rails/script/rails +6 -0
  113. data/slim-5.2.1/test/rails/test/helper.rb +34 -0
  114. data/slim-5.2.1/test/rails/test/test_slim.rb +102 -0
  115. data/slim-5.2.1/test/sinatra/contest.rb +91 -0
  116. data/slim-5.2.1/test/sinatra/helper.rb +143 -0
  117. data/slim-5.2.1/test/sinatra/test_core.rb +91 -0
  118. data/slim-5.2.1/test/sinatra/test_include.rb +16 -0
  119. data/slim-5.2.1/test/sinatra/views/embed_include_js.slim +8 -0
  120. data/slim-5.2.1/test/sinatra/views/embed_js.slim +11 -0
  121. data/slim-5.2.1/test/sinatra/views/footer.slim +1 -0
  122. data/slim-5.2.1/test/sinatra/views/hello.slim +1 -0
  123. data/slim-5.2.1/test/sinatra/views/layout2.slim +3 -0
  124. data/slim-5.2.1/test/smart/test_smart_text.rb +294 -0
  125. data/slim-5.2.1/test/translator/test_translator.rb +76 -0
  126. data/super-pro-kit.gemspec +11 -0
  127. metadata +165 -0
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+ module Slim
3
+ # @api private
4
+ class CodeAttributes < Filter
5
+ define_options :merge_attrs
6
+
7
+ # Handle attributes expression `[:html, :attrs, *attrs]`
8
+ #
9
+ # @param [Array] attrs Array of temple expressions
10
+ # @return [Array] Compiled temple expression
11
+ def on_html_attrs(*attrs)
12
+ [:multi, *attrs.map { |a| compile(a) }]
13
+ end
14
+
15
+ # Handle attribute expression `[:html, :attr, name, value]`
16
+ #
17
+ # @param [String] name Attribute name
18
+ # @param [Array] value Value expression
19
+ # @return [Array] Compiled temple expression
20
+ def on_html_attr(name, value)
21
+ if value[0] == :slim && value[1] == :attrvalue && !options[:merge_attrs][name]
22
+ # We handle the attribute as a boolean attribute
23
+ escape, code = value[2], value[3]
24
+ case code
25
+ when 'true'
26
+ [:html, :attr, name, [:multi]]
27
+ when 'false', 'nil'
28
+ [:multi]
29
+ else
30
+ tmp = unique_name
31
+ [:multi,
32
+ [:code, "#{tmp} = #{code}"],
33
+ [:if, tmp,
34
+ [:if, "#{tmp} == true",
35
+ [:html, :attr, name, [:multi]],
36
+ [:html, :attr, name, [:escape, escape, [:dynamic, tmp]]]]]]
37
+ end
38
+ else
39
+ # Attribute with merging
40
+ @attr = name
41
+ super
42
+ end
43
+ end
44
+
45
+ # Handle attribute expression `[:slim, :attrvalue, escape, code]`
46
+ #
47
+ # @param [Boolean] escape Escape html
48
+ # @param [String] code Ruby code
49
+ # @return [Array] Compiled temple expression
50
+ def on_slim_attrvalue(escape, code)
51
+ # We perform attribute merging on Array values
52
+ if delimiter = options[:merge_attrs][@attr]
53
+ tmp = unique_name
54
+ [:multi,
55
+ [:code, "#{tmp} = #{code}"],
56
+ [:if, "Array === #{tmp}",
57
+ [:multi,
58
+ [:code, "#{tmp} = #{tmp}.flatten"],
59
+ [:code, "#{tmp}.map!(&:to_s)"],
60
+ [:code, "#{tmp}.reject!(&:empty?)"],
61
+ [:escape, escape, [:dynamic, "#{tmp}.join(#{delimiter.inspect})"]]],
62
+ [:escape, escape, [:dynamic, tmp]]]]
63
+ else
64
+ [:escape, escape, [:dynamic, code]]
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,122 @@
1
+ # frozen_string_literal: true
2
+ require 'slim'
3
+ require 'optparse'
4
+
5
+ module Slim
6
+ Engine.set_options pretty: false
7
+
8
+ # Slim commandline interface
9
+ # @api private
10
+ class Command
11
+ def initialize(args)
12
+ @args = args
13
+ @options = {}
14
+ end
15
+
16
+ # Run command
17
+ def run
18
+ @opts = OptionParser.new(&method(:set_opts))
19
+ @opts.parse!(@args)
20
+ process
21
+ end
22
+
23
+ private
24
+
25
+ # Configure OptionParser
26
+ def set_opts(opts)
27
+ opts.on('-s', '--stdin', 'Read input from standard input instead of an input file') do
28
+ @options[:input] = $stdin
29
+ end
30
+
31
+ opts.on('--trace', 'Show a full traceback on error') do
32
+ @options[:trace] = true
33
+ end
34
+
35
+ opts.on('-c', '--compile', 'Compile only but do not run') do
36
+ @options[:compile] = true
37
+ end
38
+
39
+ opts.on('-e', '--erb', 'Convert to ERB') do
40
+ @options[:erb] = true
41
+ end
42
+
43
+ opts.on('--rails', 'Generate rails compatible code (Implies --compile)') do
44
+ Engine.set_options disable_capture: true, generator: Temple::Generators::RailsOutputBuffer
45
+ @options[:compile] = true
46
+ end
47
+
48
+ opts.on('-r', '--require library', 'Load library or plugin with -r slim/plugin') do |lib|
49
+ require lib.strip
50
+ end
51
+
52
+ opts.on('-p', '--pretty', 'Produce pretty html') do
53
+ Engine.set_options pretty: true
54
+ end
55
+
56
+ opts.on('-o', '--option name=code', String, 'Set slim option') do |str|
57
+ parts = str.split('=', 2)
58
+ Engine.options[parts.first.gsub(/\A:/, '').to_sym] = eval(parts.last)
59
+ end
60
+
61
+ opts.on('-l', '--locals Hash|YAML|JSON', String, 'Set local variables') do |locals|
62
+ @options[:locals] =
63
+ if locals =~ /\A\s*\{\s*\p{Word}+:/
64
+ eval(locals)
65
+ else
66
+ require 'yaml'
67
+ YAML.load(locals)
68
+ end
69
+ end
70
+
71
+ opts.on_tail('-h', '--help', 'Show this message') do
72
+ puts opts
73
+ exit
74
+ end
75
+
76
+ opts.on_tail('-v', '--version', 'Print version') do
77
+ puts "Slim #{VERSION}"
78
+ exit
79
+ end
80
+ end
81
+
82
+ # Process command
83
+ def process
84
+ args = @args.dup
85
+ unless @options[:input]
86
+ file = args.shift
87
+ if file
88
+ @options[:file] = file
89
+ @options[:input] = File.open(file, 'r')
90
+ else
91
+ @options[:file] = 'STDIN'
92
+ @options[:input] = $stdin
93
+ end
94
+ end
95
+
96
+ locals = @options.delete(:locals) || {}
97
+ result =
98
+ if @options[:erb]
99
+ require 'slim/erb_converter'
100
+ ERBConverter.new(file: @options[:file]).call(@options[:input].read)
101
+ elsif @options[:compile]
102
+ Engine.new(file: @options[:file]).call(@options[:input].read)
103
+ else
104
+ Template.new(@options[:file]) { @options[:input].read }.render(nil, locals)
105
+ end
106
+
107
+ rescue Exception => ex
108
+ raise ex if @options[:trace] || SystemExit === ex
109
+ $stderr.print "#{ex.class}: " if ex.class != RuntimeError
110
+ $stderr.puts ex.message
111
+ $stderr.puts ' Use --trace for backtrace.'
112
+ exit 1
113
+ else
114
+ unless @options[:output]
115
+ file = args.shift
116
+ @options[:output] = file ? File.open(file, 'w') : $stdout
117
+ end
118
+ @options[:output].puts(result)
119
+ exit 0
120
+ end
121
+ end
122
+ end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+ module Slim
3
+ # @api private
4
+ class Controls < Filter
5
+ define_options :disable_capture
6
+
7
+ IF_RE = /\A(if|unless)\b|\bdo\s*(\|[^\|]*\|)?\s*$/
8
+
9
+ # Handle control expression `[:slim, :control, code, content]`
10
+ #
11
+ # @param [String] code Ruby code
12
+ # @param [Array] content Temple expression
13
+ # @return [Array] Compiled temple expression
14
+ def on_slim_control(code, content)
15
+ [:multi,
16
+ [:code, code],
17
+ compile(content)]
18
+ end
19
+
20
+ # Handle output expression `[:slim, :output, escape, code, content]`
21
+ #
22
+ # @param [Boolean] escape Escape html
23
+ # @param [String] code Ruby code
24
+ # @param [Array] content Temple expression
25
+ # @return [Array] Compiled temple expression
26
+ def on_slim_output(escape, code, content)
27
+ if code =~ IF_RE
28
+ tmp = unique_name
29
+
30
+ [:multi,
31
+ # Capture the result of the code in a variable. We can't do
32
+ # `[:dynamic, code]` because it's probably not a complete
33
+ # expression (which is a requirement for Temple).
34
+ [:block, "#{tmp} = #{code}",
35
+
36
+ # Capture the content of a block in a separate buffer. This means
37
+ # that `yield` will not output the content to the current buffer,
38
+ # but rather return the output.
39
+ #
40
+ # The capturing can be disabled with the option :disable_capture.
41
+ # Output code in the block writes directly to the output buffer then.
42
+ # Rails handles this by replacing the output buffer for helpers.
43
+ options[:disable_capture] ? compile(content) : [:capture, unique_name, compile(content)]],
44
+
45
+ # Output the content.
46
+ [:escape, escape, [:dynamic, tmp]]]
47
+ else
48
+ [:multi, [:escape, escape, [:dynamic, code]], content]
49
+ end
50
+ end
51
+
52
+ # Handle text expression `[:slim, :text, type, content]`
53
+ #
54
+ # @param [Symbol] type Text type
55
+ # @param [Array] content Temple expression
56
+ # @return [Array] Compiled temple expression
57
+ def on_slim_text(type, content)
58
+ compile(content)
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+ module Slim
3
+ # In Slim you don't need the do keyword sometimes. This
4
+ # filter adds the missing keyword.
5
+ #
6
+ # - 10.times
7
+ # | Hello
8
+ #
9
+ # @api private
10
+ class DoInserter < Filter
11
+ BLOCK_REGEX = /(\A(if|unless|else|elsif|when|in|begin|rescue|ensure|case)\b)|\bdo\s*(\|[^\|]*\|\s*)?\Z/
12
+
13
+ # Handle control expression `[:slim, :control, code, content]`
14
+ #
15
+ # @param [String] code Ruby code
16
+ # @param [Array] content Temple expression
17
+ # @return [Array] Compiled temple expression
18
+ def on_slim_control(code, content)
19
+ code += ' do' unless code =~ BLOCK_REGEX || empty_exp?(content)
20
+ [:slim, :control, code, compile(content)]
21
+ end
22
+
23
+ # Handle output expression `[:slim, :output, escape, code, content]`
24
+ #
25
+ # @param [Boolean] escape Escape html
26
+ # @param [String] code Ruby code
27
+ # @param [Array] content Temple expression
28
+ # @return [Array] Compiled temple expression
29
+ def on_slim_output(escape, code, content)
30
+ code += ' do' unless code =~ BLOCK_REGEX || empty_exp?(content)
31
+ [:slim, :output, escape, code, compile(content)]
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,248 @@
1
+ # frozen_string_literal: true
2
+ module Slim
3
+ # @api private
4
+ class TextCollector < Filter
5
+ def call(exp)
6
+ @collected = ''.dup
7
+ super(exp)
8
+ @collected
9
+ end
10
+
11
+ def on_slim_interpolate(text)
12
+ @collected << text
13
+ nil
14
+ end
15
+ end
16
+
17
+ # @api private
18
+ class NewlineCollector < Filter
19
+ def call(exp)
20
+ @collected = [:multi]
21
+ super(exp)
22
+ @collected
23
+ end
24
+
25
+ def on_newline
26
+ @collected << [:newline]
27
+ nil
28
+ end
29
+ end
30
+
31
+ # @api private
32
+ class OutputProtector < Filter
33
+ def call(exp)
34
+ @protect, @collected, @tag = [], ''.dup, object_id.abs.to_s(36)
35
+ super(exp)
36
+ @collected
37
+ end
38
+
39
+ def on_static(text)
40
+ @collected << text
41
+ nil
42
+ end
43
+
44
+ def on_slim_output(escape, text, content)
45
+ @collected << "%#{@tag}%#{@protect.length}%"
46
+ @protect << [:slim, :output, escape, text, content]
47
+ nil
48
+ end
49
+
50
+ def unprotect(text)
51
+ block = [:multi]
52
+ while text =~ /%#{@tag}%(\d+)%/
53
+ block << [:static, $`]
54
+ block << @protect[$1.to_i]
55
+ text = $'
56
+ end
57
+ block << [:static, text]
58
+ end
59
+ end
60
+
61
+ # Temple filter which processes embedded engines
62
+ # @api private
63
+ class Embedded < Filter
64
+ @engines = {}
65
+
66
+ class << self
67
+ attr_reader :engines
68
+
69
+ # Register embedded engine
70
+ #
71
+ # @param [String] name Name of the engine
72
+ # @param [Class] klass Engine class
73
+ # @param option_filter List of options to pass to engine.
74
+ # Last argument can be default option hash.
75
+ def register(name, klass, *option_filter)
76
+ name = name.to_sym
77
+ local_options = option_filter.last.respond_to?(:to_hash) ? option_filter.pop.to_hash : {}
78
+ define_options(name, *option_filter)
79
+ klass.define_options(name)
80
+ engines[name.to_sym] = proc do |options|
81
+ klass.new({}.update(options).delete_if {|k,v| !option_filter.include?(k) && k != name }.update(local_options))
82
+ end
83
+ end
84
+
85
+ def create(name, options)
86
+ constructor = engines[name] || raise(Temple::FilterError, "Embedded engine #{name} not found")
87
+ constructor.call(options)
88
+ end
89
+ end
90
+
91
+ define_options :enable_engines, :disable_engines
92
+
93
+ def initialize(opts = {})
94
+ super
95
+ @engines = {}
96
+ @enabled = normalize_engine_list(options[:enable_engines])
97
+ @disabled = normalize_engine_list(options[:disable_engines])
98
+ end
99
+
100
+ def on_slim_embedded(name, body, attrs)
101
+ name = name.to_sym
102
+ raise(Temple::FilterError, "Embedded engine #{name} is disabled") unless enabled?(name)
103
+ @engines[name] ||= self.class.create(name, options)
104
+ @engines[name].on_slim_embedded(name, body, attrs)
105
+ end
106
+
107
+ def enabled?(name)
108
+ (!@enabled || @enabled.include?(name)) &&
109
+ (!@disabled || !@disabled.include?(name))
110
+ end
111
+
112
+ protected
113
+
114
+ def normalize_engine_list(list)
115
+ raise(ArgumentError, "Option :enable_engines/:disable_engines must be String or Symbol list") unless !list || Array === list
116
+ list && list.map(&:to_sym)
117
+ end
118
+
119
+ class Engine < Filter
120
+ protected
121
+
122
+ def collect_text(body)
123
+ @text_collector ||= TextCollector.new
124
+ @text_collector.call(body)
125
+ end
126
+
127
+ def collect_newlines(body)
128
+ @newline_collector ||= NewlineCollector.new
129
+ @newline_collector.call(body)
130
+ end
131
+ end
132
+
133
+ # Basic tilt engine
134
+ class TiltEngine < Engine
135
+ def on_slim_embedded(engine, body, attrs)
136
+ tilt_engine = Tilt[engine] || raise(Temple::FilterError, "Tilt engine #{engine} is not available.")
137
+ tilt_options = options[engine.to_sym] || {}
138
+ tilt_options[:default_encoding] ||= 'utf-8'
139
+ [:multi, tilt_render(tilt_engine, tilt_options, collect_text(body)), collect_newlines(body)]
140
+ end
141
+
142
+ protected
143
+
144
+ def tilt_render(tilt_engine, tilt_options, text)
145
+ [:static, tilt_engine.new(tilt_options) { text }.render]
146
+ end
147
+ end
148
+
149
+ # Sass engine which supports :pretty option
150
+ class SassEngine < TiltEngine
151
+ define_options :pretty
152
+
153
+ protected
154
+
155
+ def tilt_render(tilt_engine, tilt_options, text)
156
+ text = tilt_engine.new(tilt_options.merge(
157
+ style: options[:pretty] ? :expanded : :compressed
158
+ )) { text }.render
159
+ text = text.chomp
160
+ [:static, text]
161
+ end
162
+ end
163
+
164
+ # Static template with interpolated ruby code
165
+ class InterpolateTiltEngine < TiltEngine
166
+ def collect_text(body)
167
+ output_protector.call(interpolation.call(body))
168
+ end
169
+
170
+ def tilt_render(tilt_engine, tilt_options, text)
171
+ output_protector.unprotect(tilt_engine.new(tilt_options) { text }.render)
172
+ end
173
+
174
+ private
175
+
176
+ def interpolation
177
+ @interpolation ||= Interpolation.new
178
+ end
179
+
180
+ def output_protector
181
+ @output_protector ||= OutputProtector.new
182
+ end
183
+ end
184
+
185
+ # Tag wrapper engine
186
+ # Generates a html tag and wraps another engine (specified via :engine option)
187
+ class TagEngine < Engine
188
+ disable_option_validator!
189
+ set_options attributes: {}
190
+
191
+ def on_slim_embedded(engine, body, attrs)
192
+ unless options[:attributes].empty?
193
+ options[:attributes].map do |k, v|
194
+ attrs << [:html, :attr, k, [:static, v]]
195
+ end
196
+ end
197
+
198
+ if options[:engine]
199
+ opts = {}.update(options)
200
+ opts.delete(:engine)
201
+ opts.delete(:tag)
202
+ opts.delete(:attributes)
203
+ @engine ||= options[:engine].new(opts)
204
+ body = @engine.on_slim_embedded(engine, body, attrs)
205
+ end
206
+
207
+ [:html, :tag, options[:tag], attrs, body]
208
+ end
209
+ end
210
+
211
+ # Javascript wrapper engine.
212
+ # Like TagEngine, but can wrap content in html comment or cdata.
213
+ class JavaScriptEngine < TagEngine
214
+ disable_option_validator!
215
+
216
+ set_options tag: :script
217
+
218
+ def on_slim_embedded(engine, body, attrs)
219
+ super(engine, [:html, :js, body], attrs)
220
+ end
221
+ end
222
+
223
+ # Embeds ruby code
224
+ class RubyEngine < Engine
225
+ def on_slim_embedded(engine, body, attrs)
226
+ [:multi, [:newline], [:code, "#{collect_text(body)}\n"]]
227
+ end
228
+ end
229
+
230
+ # These engines are executed at compile time, embedded ruby is interpolated
231
+ register :markdown, InterpolateTiltEngine
232
+ register :textile, InterpolateTiltEngine
233
+ register :rdoc, InterpolateTiltEngine
234
+
235
+ # These engines are executed at compile time
236
+ register :coffee, JavaScriptEngine, engine: TiltEngine
237
+ register :less, TagEngine, tag: :style, engine: TiltEngine
238
+ register :sass, TagEngine, :pretty, tag: :style, engine: SassEngine
239
+ register :scss, TagEngine, :pretty, tag: :style, engine: SassEngine
240
+
241
+ # Embedded javascript/css
242
+ register :javascript, JavaScriptEngine
243
+ register :css, TagEngine, tag: :style
244
+
245
+ # Embedded ruby code
246
+ register :ruby, RubyEngine
247
+ end
248
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+ module Slim
3
+ # In Slim you don't need to close any blocks:
4
+ #
5
+ # - if Slim.awesome?
6
+ # | But of course it is!
7
+ #
8
+ # However, the parser is not smart enough (and that's a good thing) to
9
+ # automatically insert end's where they are needed. Luckily, this filter
10
+ # does *exactly* that (and it does it well!)
11
+ #
12
+ # @api private
13
+ class EndInserter < Filter
14
+ IF_RE = /\A(if|begin|unless|else|elsif|when|in|rescue|ensure)\b|\bdo\s*(\|[^\|]*\|)?\s*$/
15
+ ELSE_RE = /\A(else|elsif|when|in|rescue|ensure)\b/
16
+ END_RE = /\Aend\b/
17
+
18
+ # Handle multi expression `[:multi, *exps]`
19
+ #
20
+ # @return [Array] Corrected Temple expression with ends inserted
21
+ def on_multi(*exps)
22
+ result = [:multi]
23
+ # This variable is true if the previous line was
24
+ # (1) a control code and (2) contained indented content.
25
+ prev_indent = false
26
+
27
+ exps.each do |exp|
28
+ if control?(exp)
29
+ raise(Temple::FilterError, 'Explicit end statements are forbidden') if exp[2] =~ END_RE
30
+
31
+ # Two control code in a row. If this one is *not*
32
+ # an else block, we should close the previous one.
33
+ append_end(result) if prev_indent && exp[2] !~ ELSE_RE
34
+
35
+ # Indent if the control code starts a block.
36
+ prev_indent = exp[2] =~ IF_RE
37
+ elsif exp[0] != :newline && prev_indent
38
+ # This is *not* a control code, so we should close the previous one.
39
+ # Ignores newlines because they will be inserted after each line.
40
+ append_end(result)
41
+ prev_indent = false
42
+ end
43
+
44
+ result << compile(exp)
45
+ end
46
+
47
+ # The last line can be a control code too.
48
+ prev_indent ? append_end(result) : result
49
+ end
50
+
51
+ private
52
+
53
+ # Appends an end
54
+ def append_end(result)
55
+ result << [:code, 'end']
56
+ end
57
+
58
+ # Checks if an expression is a Slim control code
59
+ def control?(exp)
60
+ exp[0] == :slim && exp[1] == :control
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+ # The Slim module contains all Slim related classes (e.g. Engine, Parser).
3
+ # Plugins might also reside within the Slim module (e.g. Include, Smart).
4
+ # @api public
5
+ module Slim
6
+ # Slim engine which transforms slim code to executable ruby code
7
+ # @api public
8
+ class Engine < Temple::Engine
9
+ # This overwrites some Temple default options or sets default options for Slim specific filters.
10
+ # It is recommended to set the default settings only once in the code and avoid duplication. Only use
11
+ # `define_options` when you have to override some default settings.
12
+ define_options pretty: false,
13
+ sort_attrs: true,
14
+ format: :xhtml,
15
+ attr_quote: '"',
16
+ merge_attrs: {'class' => ' '},
17
+ generator: Temple::Generators::StringBuffer,
18
+ default_tag: 'div'
19
+
20
+ filter :Encoding
21
+ filter :RemoveBOM
22
+ use Slim::Parser
23
+ use Slim::Embedded
24
+ use Slim::Interpolation
25
+ use Slim::Splat::Filter
26
+ use Slim::DoInserter
27
+ use Slim::EndInserter
28
+ use Slim::Controls
29
+ html :AttributeSorter
30
+ html :AttributeMerger
31
+ use Slim::CodeAttributes
32
+ use(:AttributeRemover) { Temple::HTML::AttributeRemover.new(remove_empty_attrs: options[:merge_attrs].keys) }
33
+ html :Pretty
34
+ filter :Ambles
35
+ filter :Escapable
36
+ filter :StaticAnalyzer
37
+ filter :ControlFlow
38
+ filter :MultiFlattener
39
+ filter :StaticMerger
40
+ use(:Generator) { options[:generator] }
41
+ end
42
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+ require 'slim'
3
+
4
+ module Slim
5
+ # Slim to ERB converter
6
+ #
7
+ # @example Conversion
8
+ # Slim::ERBConverter.new(options).call(slim_code) # outputs erb_code
9
+ #
10
+ # @api public
11
+ class ERBConverter < Engine
12
+ replace :StaticMerger, Temple::Filters::CodeMerger
13
+ replace :Generator, Temple::Generators::ERB
14
+ end
15
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+ module Slim
3
+ # Base class for Temple filters used in Slim
4
+ #
5
+ # This base filter passes everything through and allows
6
+ # to override only some methods without affecting the rest
7
+ # of the expression.
8
+ #
9
+ # @api private
10
+ class Filter < Temple::HTML::Filter
11
+ # Pass-through handler
12
+ def on_slim_text(type, content)
13
+ [:slim, :text, type, compile(content)]
14
+ end
15
+
16
+ # Pass-through handler
17
+ def on_slim_embedded(type, content, attrs)
18
+ [:slim, :embedded, type, compile(content), attrs]
19
+ end
20
+
21
+ # Pass-through handler
22
+ def on_slim_control(code, content)
23
+ [:slim, :control, code, compile(content)]
24
+ end
25
+
26
+ # Pass-through handler
27
+ def on_slim_output(escape, code, content)
28
+ [:slim, :output, escape, code, compile(content)]
29
+ end
30
+ end
31
+ end