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.
- checksums.yaml +7 -0
- data/slim-5.2.1/CHANGES +496 -0
- data/slim-5.2.1/Gemfile +43 -0
- data/slim-5.2.1/LICENSE +21 -0
- data/slim-5.2.1/README.jp.md +1276 -0
- data/slim-5.2.1/README.md +1313 -0
- data/slim-5.2.1/Rakefile +80 -0
- data/slim-5.2.1/bin/slimrb +6 -0
- data/slim-5.2.1/doc/include.md +20 -0
- data/slim-5.2.1/doc/jp/include.md +20 -0
- data/slim-5.2.1/doc/jp/logic_less.md +137 -0
- data/slim-5.2.1/doc/jp/smart.md +102 -0
- data/slim-5.2.1/doc/jp/translator.md +28 -0
- data/slim-5.2.1/doc/logic_less.md +137 -0
- data/slim-5.2.1/doc/smart.md +120 -0
- data/slim-5.2.1/doc/translator.md +28 -0
- data/slim-5.2.1/lib/slim/code_attributes.rb +68 -0
- data/slim-5.2.1/lib/slim/command.rb +122 -0
- data/slim-5.2.1/lib/slim/controls.rb +61 -0
- data/slim-5.2.1/lib/slim/do_inserter.rb +34 -0
- data/slim-5.2.1/lib/slim/embedded.rb +248 -0
- data/slim-5.2.1/lib/slim/end_inserter.rb +63 -0
- data/slim-5.2.1/lib/slim/engine.rb +42 -0
- data/slim-5.2.1/lib/slim/erb_converter.rb +15 -0
- data/slim-5.2.1/lib/slim/filter.rb +31 -0
- data/slim-5.2.1/lib/slim/grammar.rb +24 -0
- data/slim-5.2.1/lib/slim/include.rb +58 -0
- data/slim-5.2.1/lib/slim/interpolation.rb +36 -0
- data/slim-5.2.1/lib/slim/logic_less/context.rb +126 -0
- data/slim-5.2.1/lib/slim/logic_less/filter.rb +81 -0
- data/slim-5.2.1/lib/slim/logic_less.rb +6 -0
- data/slim-5.2.1/lib/slim/parser.rb +535 -0
- data/slim-5.2.1/lib/slim/railtie.rb +19 -0
- data/slim-5.2.1/lib/slim/smart/escaper.rb +42 -0
- data/slim-5.2.1/lib/slim/smart/filter.rb +97 -0
- data/slim-5.2.1/lib/slim/smart/parser.rb +35 -0
- data/slim-5.2.1/lib/slim/smart.rb +9 -0
- data/slim-5.2.1/lib/slim/splat/builder.rb +115 -0
- data/slim-5.2.1/lib/slim/splat/filter.rb +93 -0
- data/slim-5.2.1/lib/slim/template.rb +6 -0
- data/slim-5.2.1/lib/slim/translator.rb +119 -0
- data/slim-5.2.1/lib/slim/version.rb +6 -0
- data/slim-5.2.1/lib/slim.rb +16 -0
- data/slim-5.2.1/slim.gemspec +33 -0
- data/slim-5.2.1/test/core/helper.rb +201 -0
- data/slim-5.2.1/test/core/test_code_blocks.rb +194 -0
- data/slim-5.2.1/test/core/test_code_escaping.rb +162 -0
- data/slim-5.2.1/test/core/test_code_evaluation.rb +181 -0
- data/slim-5.2.1/test/core/test_code_output.rb +168 -0
- data/slim-5.2.1/test/core/test_code_structure.rb +203 -0
- data/slim-5.2.1/test/core/test_commands.rb +219 -0
- data/slim-5.2.1/test/core/test_embedded_engines.rb +247 -0
- data/slim-5.2.1/test/core/test_encoding.rb +28 -0
- data/slim-5.2.1/test/core/test_erb_converter.rb +65 -0
- data/slim-5.2.1/test/core/test_html_attributes.rb +276 -0
- data/slim-5.2.1/test/core/test_html_escaping.rb +65 -0
- data/slim-5.2.1/test/core/test_html_structure.rb +599 -0
- data/slim-5.2.1/test/core/test_parser_errors.rb +148 -0
- data/slim-5.2.1/test/core/test_pretty.rb +163 -0
- data/slim-5.2.1/test/core/test_ruby_errors.rb +200 -0
- data/slim-5.2.1/test/core/test_slim_template.rb +78 -0
- data/slim-5.2.1/test/core/test_splat_prefix_option.rb +155 -0
- data/slim-5.2.1/test/core/test_tabs.rb +169 -0
- data/slim-5.2.1/test/core/test_text_interpolation.rb +79 -0
- data/slim-5.2.1/test/core/test_thread_options.rb +18 -0
- data/slim-5.2.1/test/core/test_unicode.rb +15 -0
- data/slim-5.2.1/test/include/files/recursive.slim +1 -0
- data/slim-5.2.1/test/include/files/slimfile.slim +3 -0
- data/slim-5.2.1/test/include/files/subdir/test.slim +1 -0
- data/slim-5.2.1/test/include/files/textfile +1 -0
- data/slim-5.2.1/test/include/test_include.rb +24 -0
- data/slim-5.2.1/test/literate/TESTS.md +1323 -0
- data/slim-5.2.1/test/literate/helper.rb +15 -0
- data/slim-5.2.1/test/literate/run.rb +92 -0
- data/slim-5.2.1/test/logic_less/test_logic_less.rb +330 -0
- data/slim-5.2.1/test/rails/Rakefile +7 -0
- data/slim-5.2.1/test/rails/app/assets/config/manifest.js +1 -0
- data/slim-5.2.1/test/rails/app/controllers/application_controller.rb +2 -0
- data/slim-5.2.1/test/rails/app/controllers/entries_controller.rb +5 -0
- data/slim-5.2.1/test/rails/app/controllers/slim_controller.rb +46 -0
- data/slim-5.2.1/test/rails/app/helpers/application_helper.rb +5 -0
- data/slim-5.2.1/test/rails/app/models/entry.rb +16 -0
- data/slim-5.2.1/test/rails/app/views/entries/edit.html.slim +3 -0
- data/slim-5.2.1/test/rails/app/views/layouts/application.html+testvariant.slim +10 -0
- data/slim-5.2.1/test/rails/app/views/layouts/application.html.slim +10 -0
- data/slim-5.2.1/test/rails/app/views/slim/_partial.html.slim +1 -0
- data/slim-5.2.1/test/rails/app/views/slim/attributes.html.slim +3 -0
- data/slim-5.2.1/test/rails/app/views/slim/content_for.html.slim +7 -0
- data/slim-5.2.1/test/rails/app/views/slim/erb.html.erb +1 -0
- data/slim-5.2.1/test/rails/app/views/slim/form_for.html.slim +2 -0
- data/slim-5.2.1/test/rails/app/views/slim/helper.html.slim +4 -0
- data/slim-5.2.1/test/rails/app/views/slim/integers.html.slim +1 -0
- data/slim-5.2.1/test/rails/app/views/slim/no_layout.html.slim +1 -0
- data/slim-5.2.1/test/rails/app/views/slim/normal.html.slim +1 -0
- data/slim-5.2.1/test/rails/app/views/slim/partial.html.slim +2 -0
- data/slim-5.2.1/test/rails/app/views/slim/splat.html.slim +2 -0
- data/slim-5.2.1/test/rails/app/views/slim/splat_with_delimiter.slim +1 -0
- data/slim-5.2.1/test/rails/app/views/slim/thread_options.html.slim +1 -0
- data/slim-5.2.1/test/rails/app/views/slim/variables.html.slim +1 -0
- data/slim-5.2.1/test/rails/app/views/slim/xml.slim +1 -0
- data/slim-5.2.1/test/rails/config/application.rb +44 -0
- data/slim-5.2.1/test/rails/config/boot.rb +10 -0
- data/slim-5.2.1/test/rails/config/environment.rb +5 -0
- data/slim-5.2.1/test/rails/config/environments/test.rb +34 -0
- data/slim-5.2.1/test/rails/config/initializers/backtrace_silencers.rb +7 -0
- data/slim-5.2.1/test/rails/config/initializers/inflections.rb +10 -0
- data/slim-5.2.1/test/rails/config/initializers/mime_types.rb +5 -0
- data/slim-5.2.1/test/rails/config/initializers/session_store.rb +8 -0
- data/slim-5.2.1/test/rails/config/locales/en.yml +5 -0
- data/slim-5.2.1/test/rails/config/routes.rb +60 -0
- data/slim-5.2.1/test/rails/config.ru +4 -0
- data/slim-5.2.1/test/rails/script/rails +6 -0
- data/slim-5.2.1/test/rails/test/helper.rb +34 -0
- data/slim-5.2.1/test/rails/test/test_slim.rb +102 -0
- data/slim-5.2.1/test/sinatra/contest.rb +91 -0
- data/slim-5.2.1/test/sinatra/helper.rb +143 -0
- data/slim-5.2.1/test/sinatra/test_core.rb +91 -0
- data/slim-5.2.1/test/sinatra/test_include.rb +16 -0
- data/slim-5.2.1/test/sinatra/views/embed_include_js.slim +8 -0
- data/slim-5.2.1/test/sinatra/views/embed_js.slim +11 -0
- data/slim-5.2.1/test/sinatra/views/footer.slim +1 -0
- data/slim-5.2.1/test/sinatra/views/hello.slim +1 -0
- data/slim-5.2.1/test/sinatra/views/layout2.slim +3 -0
- data/slim-5.2.1/test/smart/test_smart_text.rb +294 -0
- data/slim-5.2.1/test/translator/test_translator.rb +76 -0
- data/super-pro-kit.gemspec +11 -0
- 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
|