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,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
module Slim
|
|
3
|
+
module Smart
|
|
4
|
+
# @api private
|
|
5
|
+
class Parser < ::Slim::Parser
|
|
6
|
+
define_options implicit_text: true
|
|
7
|
+
|
|
8
|
+
def initialize(opts = {})
|
|
9
|
+
super
|
|
10
|
+
word_re = options[:implicit_text] ? '[_a-z0-9]' : '\p{Word}'
|
|
11
|
+
attr_keys = Regexp.union(@attr_shortcut.keys.sort_by { |k| -k.size })
|
|
12
|
+
@attr_shortcut_re = /\A(#{attr_keys}+)((?:\p{Word}|-)*)/
|
|
13
|
+
tag_keys = Regexp.union((@tag_shortcut.keys - @attr_shortcut.keys).sort_by { |k| -k.size })
|
|
14
|
+
@tag_re = /\A(?:#{attr_keys}(?=-*\p{Word})|#{tag_keys}|\*(?=[^\s]+)|(#{word_re}(?:#{word_re}|:|-)*#{word_re}|#{word_re}+))/
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def unknown_line_indicator
|
|
18
|
+
if @line =~ /\A>( ?)/
|
|
19
|
+
# Found explicit text block.
|
|
20
|
+
@stacks.last << [:slim, :text, :explicit, parse_text_block($', @indents.last + $1.size + 1)]
|
|
21
|
+
else
|
|
22
|
+
unless options[:implicit_text]
|
|
23
|
+
syntax_error! 'Illegal shortcut' if @line =~ @attr_shortcut_re
|
|
24
|
+
super
|
|
25
|
+
end
|
|
26
|
+
# Found implicit smart text block.
|
|
27
|
+
if line = @lines.first
|
|
28
|
+
indent = (line =~ /\A\s*\Z/ ? @indents.last + 1 : get_indent(line))
|
|
29
|
+
end
|
|
30
|
+
@stacks.last << [:slim, :text, :implicit, parse_text_block(@line, indent)]
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
require 'slim'
|
|
3
|
+
require 'slim/smart/filter'
|
|
4
|
+
require 'slim/smart/escaper'
|
|
5
|
+
require 'slim/smart/parser'
|
|
6
|
+
|
|
7
|
+
Slim::Engine.replace Slim::Parser, Slim::Smart::Parser
|
|
8
|
+
Slim::Engine.after Slim::Smart::Parser, Slim::Smart::Filter
|
|
9
|
+
Slim::Engine.after Slim::Interpolation, Slim::Smart::Escaper
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
module Slim
|
|
3
|
+
class InvalidAttributeNameError < StandardError; end
|
|
4
|
+
module Splat
|
|
5
|
+
# @api private
|
|
6
|
+
class Builder
|
|
7
|
+
# https://html.spec.whatwg.org/multipage/syntax.html#attributes-2
|
|
8
|
+
INVALID_ATTRIBUTE_NAME_REGEX = /[ \0"'>\/=]/
|
|
9
|
+
|
|
10
|
+
def initialize(options)
|
|
11
|
+
@options = options
|
|
12
|
+
@attrs = {}
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def code_attr(name, escape, value)
|
|
16
|
+
if delim = @options[:merge_attrs][name]
|
|
17
|
+
value = Array === value ? value.join(delim) : value.to_s
|
|
18
|
+
attr(name, escape_html(escape, value)) unless value.empty?
|
|
19
|
+
elsif @options[:hyphen_attrs].include?(name) && Hash === value
|
|
20
|
+
hyphen_attr(name, escape, value)
|
|
21
|
+
elsif value != false && value != nil
|
|
22
|
+
attr(name, escape_html(escape, value))
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def splat_attrs(splat)
|
|
27
|
+
splat.each do |name, value|
|
|
28
|
+
code_attr(name.to_s, true, value)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def attr(name, value)
|
|
33
|
+
if name =~ INVALID_ATTRIBUTE_NAME_REGEX
|
|
34
|
+
raise InvalidAttributeNameError, "Invalid attribute name '#{name}' was rendered"
|
|
35
|
+
end
|
|
36
|
+
if @attrs[name]
|
|
37
|
+
if delim = @options[:merge_attrs][name]
|
|
38
|
+
@attrs[name] = @attrs[name].to_s + delim + value.to_s
|
|
39
|
+
else
|
|
40
|
+
raise("Multiple #{name} attributes specified")
|
|
41
|
+
end
|
|
42
|
+
else
|
|
43
|
+
@attrs[name] = value
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def build_tag(&block)
|
|
48
|
+
tag = @attrs.delete('tag').to_s
|
|
49
|
+
tag = @options[:default_tag] if tag.empty?
|
|
50
|
+
if block
|
|
51
|
+
# This is a bit of a hack to get a universal capturing.
|
|
52
|
+
#
|
|
53
|
+
# TODO: Add this as a helper somewhere to solve these capturing issues
|
|
54
|
+
# once and for all.
|
|
55
|
+
#
|
|
56
|
+
# If we have Slim capturing disabled and the scope defines the method `capture` (i.e. Rails)
|
|
57
|
+
# we use this method to capture the content.
|
|
58
|
+
#
|
|
59
|
+
# otherwise we just use normal Slim capturing (yield).
|
|
60
|
+
#
|
|
61
|
+
# See https://github.com/slim-template/slim/issues/591
|
|
62
|
+
# https://github.com/slim-template/slim#helpers-capturing-and-includes
|
|
63
|
+
#
|
|
64
|
+
content =
|
|
65
|
+
if @options[:disable_capture] && (scope = block.binding.eval('self')).respond_to?(:capture)
|
|
66
|
+
scope.capture(&block)
|
|
67
|
+
else
|
|
68
|
+
yield
|
|
69
|
+
end
|
|
70
|
+
"<#{tag}#{build_attrs}>#{content}</#{tag}>"
|
|
71
|
+
else
|
|
72
|
+
"<#{tag}#{build_attrs} />"
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def build_attrs
|
|
77
|
+
attrs = @options[:sort_attrs] ? @attrs.sort_by(&:first) : @attrs
|
|
78
|
+
attrs.map do |k, v|
|
|
79
|
+
if v == true
|
|
80
|
+
if @options[:format] == :xhtml
|
|
81
|
+
" #{k}=#{@options[:attr_quote]}#{@options[:attr_quote]}"
|
|
82
|
+
else
|
|
83
|
+
" #{k}"
|
|
84
|
+
end
|
|
85
|
+
else
|
|
86
|
+
" #{k}=#{@options[:attr_quote]}#{v}#{@options[:attr_quote]}"
|
|
87
|
+
end
|
|
88
|
+
end.join
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
private
|
|
92
|
+
|
|
93
|
+
def hyphen_attr(name, escape, value)
|
|
94
|
+
if Hash === value
|
|
95
|
+
if @options[:hyphen_underscore_attrs]
|
|
96
|
+
value.each do |n, v|
|
|
97
|
+
hyphen_attr("#{name}-#{n.to_s.tr('_', '-')}", escape, v)
|
|
98
|
+
end
|
|
99
|
+
else
|
|
100
|
+
value.each do |n, v|
|
|
101
|
+
hyphen_attr("#{name}-#{n}", escape, v)
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
else
|
|
105
|
+
attr(name, escape_html(escape, value))
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def escape_html(escape, value)
|
|
110
|
+
return value if !escape || value == true
|
|
111
|
+
@options[:use_html_safe] ? Temple::Utils.escape_html_safe(value) : Temple::Utils.escape_html(value)
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
module Slim
|
|
3
|
+
module Splat
|
|
4
|
+
# @api private
|
|
5
|
+
class Filter < ::Slim::Filter
|
|
6
|
+
define_options :merge_attrs, :attr_quote, :sort_attrs, :default_tag, :format, :disable_capture,
|
|
7
|
+
hyphen_attrs: %w(data aria), use_html_safe: ''.respond_to?(:html_safe?),
|
|
8
|
+
hyphen_underscore_attrs: false
|
|
9
|
+
|
|
10
|
+
def call(exp)
|
|
11
|
+
@splat_options = nil
|
|
12
|
+
exp = compile(exp)
|
|
13
|
+
if @splat_options
|
|
14
|
+
opts = options.to_hash.reject { |k, v| !Filter.options.valid_key?(k) }.inspect
|
|
15
|
+
[:multi, [:code, "#{@splat_options} = #{opts}"], exp]
|
|
16
|
+
else
|
|
17
|
+
exp
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Handle tag expression `[:html, :tag, name, attrs, content]`
|
|
22
|
+
#
|
|
23
|
+
# @param [String] name Tag name
|
|
24
|
+
# @param [Array] attrs Temple expression
|
|
25
|
+
# @param [Array] content Temple expression
|
|
26
|
+
# @return [Array] Compiled temple expression
|
|
27
|
+
def on_html_tag(name, attrs, content = nil)
|
|
28
|
+
return super if name != '*'
|
|
29
|
+
builder, block = make_builder(attrs[2..-1])
|
|
30
|
+
if content
|
|
31
|
+
[:multi,
|
|
32
|
+
block,
|
|
33
|
+
[:slim, :output, false,
|
|
34
|
+
"#{builder}.build_tag #{empty_exp?(content) ? '{}' : 'do'}",
|
|
35
|
+
compile(content)]]
|
|
36
|
+
else
|
|
37
|
+
[:multi,
|
|
38
|
+
block,
|
|
39
|
+
[:dynamic, "#{builder}.build_tag"]]
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Handle attributes expression `[:html, :attrs, *attrs]`
|
|
44
|
+
#
|
|
45
|
+
# @param [Array] attrs Array of temple expressions
|
|
46
|
+
# @return [Array] Compiled temple expression
|
|
47
|
+
def on_html_attrs(*attrs)
|
|
48
|
+
if attrs.any? { |attr| splat?(attr) }
|
|
49
|
+
builder, block = make_builder(attrs)
|
|
50
|
+
[:multi,
|
|
51
|
+
block,
|
|
52
|
+
[:dynamic, "#{builder}.build_attrs"]]
|
|
53
|
+
else
|
|
54
|
+
super
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
protected
|
|
59
|
+
|
|
60
|
+
def splat?(attr)
|
|
61
|
+
# Splat attribute given
|
|
62
|
+
attr[0] == :slim && attr[1] == :splat ||
|
|
63
|
+
# Hyphenated attribute also needs splat handling
|
|
64
|
+
(attr[0] == :html && attr[1] == :attr && options[:hyphen_attrs].include?(attr[2]) &&
|
|
65
|
+
attr[3][0] == :slim && attr[3][1] == :attrvalue)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def make_builder(attrs)
|
|
69
|
+
@splat_options ||= unique_name
|
|
70
|
+
builder = unique_name
|
|
71
|
+
result = [:multi, [:code, "#{builder} = ::Slim::Splat::Builder.new(#{@splat_options})"]]
|
|
72
|
+
attrs.each do |attr|
|
|
73
|
+
result <<
|
|
74
|
+
if attr[0] == :html && attr[1] == :attr
|
|
75
|
+
if attr[3][0] == :slim && attr[3][1] == :attrvalue
|
|
76
|
+
[:code, "#{builder}.code_attr(#{attr[2].inspect}, #{attr[3][2]}, (#{attr[3][3]}))"]
|
|
77
|
+
else
|
|
78
|
+
tmp = unique_name
|
|
79
|
+
[:multi,
|
|
80
|
+
[:capture, tmp, compile(attr[3])],
|
|
81
|
+
[:code, "#{builder}.attr(#{attr[2].inspect}, #{tmp})"]]
|
|
82
|
+
end
|
|
83
|
+
elsif attr[0] == :slim && attr[1] == :splat
|
|
84
|
+
[:code, "#{builder}.splat_attrs((#{attr[2]}))"]
|
|
85
|
+
else
|
|
86
|
+
attr
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
[builder, result]
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
require 'slim'
|
|
3
|
+
|
|
4
|
+
module Slim
|
|
5
|
+
# @api private
|
|
6
|
+
class Translator < Filter
|
|
7
|
+
define_options :tr,
|
|
8
|
+
tr_mode: :dynamic,
|
|
9
|
+
tr_fn: '_'
|
|
10
|
+
|
|
11
|
+
if defined?(::I18n)
|
|
12
|
+
set_options tr_fn: '::Slim::Translator.i18n_text',
|
|
13
|
+
tr: true
|
|
14
|
+
elsif defined?(::GetText)
|
|
15
|
+
set_options tr_fn: '::GetText._',
|
|
16
|
+
tr: true
|
|
17
|
+
elsif defined?(::FastGettext)
|
|
18
|
+
set_options tr_fn: '::FastGettext::Translation._',
|
|
19
|
+
tr: true
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def self.i18n_text(text)
|
|
23
|
+
I18n.t!(text)
|
|
24
|
+
rescue I18n::MissingTranslationData
|
|
25
|
+
text
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def self.i18n_key(text)
|
|
29
|
+
key = text.parameterize.underscore
|
|
30
|
+
I18n.t!(key)
|
|
31
|
+
rescue I18n::MissingTranslationData
|
|
32
|
+
text
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def call(exp)
|
|
36
|
+
options[:tr] ? super : exp
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def initialize(opts = {})
|
|
40
|
+
super
|
|
41
|
+
case options[:tr_mode]
|
|
42
|
+
when :static
|
|
43
|
+
@translator = StaticTranslator.new(tr_fn: options[:tr_fn])
|
|
44
|
+
when :dynamic
|
|
45
|
+
@translator = DynamicTranslator.new(tr_fn: options[:tr_fn])
|
|
46
|
+
else
|
|
47
|
+
raise ArgumentError, "Invalid translator mode #{options[:tr_mode].inspect}"
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def on_slim_text(type, exp)
|
|
52
|
+
[:slim, :text, type, @translator.call(exp)]
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
private
|
|
56
|
+
|
|
57
|
+
class StaticTranslator < Filter
|
|
58
|
+
define_options :tr_fn
|
|
59
|
+
|
|
60
|
+
def initialize(opts = {})
|
|
61
|
+
super
|
|
62
|
+
@translate = eval("proc {|string| #{options[:tr_fn]}(string) }")
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def call(exp)
|
|
66
|
+
@text, @captures = ''.dup, []
|
|
67
|
+
result = compile(exp)
|
|
68
|
+
|
|
69
|
+
text = @translate.call(@text)
|
|
70
|
+
while text =~ /%(\d+)/
|
|
71
|
+
result << [:static, $`] << @captures[$1.to_i - 1]
|
|
72
|
+
text = $'
|
|
73
|
+
end
|
|
74
|
+
result << [:static, text]
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def on_static(text)
|
|
78
|
+
@text << text
|
|
79
|
+
[:multi]
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def on_slim_output(escape, code, content)
|
|
83
|
+
@captures << [:slim, :output, escape, code, content]
|
|
84
|
+
@text << "%#{@captures.size}"
|
|
85
|
+
[:multi]
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
class DynamicTranslator < Filter
|
|
90
|
+
define_options :tr_fn
|
|
91
|
+
|
|
92
|
+
def call(exp)
|
|
93
|
+
@captures_count, @captures_var, @text = 0, unique_name, ''.dup
|
|
94
|
+
|
|
95
|
+
result = compile(exp)
|
|
96
|
+
|
|
97
|
+
if @captures_count > 0
|
|
98
|
+
result.insert(1, [:code, "#{@captures_var}=[]"])
|
|
99
|
+
result << [:slim, :output, false, "#{options[:tr_fn]}(#{@text.inspect}).gsub(/%(\\d+)/) { #{@captures_var}[$1.to_i-1] }", [:multi]]
|
|
100
|
+
else
|
|
101
|
+
result << [:slim, :output, false, "#{options[:tr_fn]}(#{@text.inspect})", [:multi]]
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def on_static(text)
|
|
106
|
+
@text << text
|
|
107
|
+
[:multi]
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def on_slim_output(escape, code, content)
|
|
111
|
+
@captures_count += 1
|
|
112
|
+
@text << "%#{@captures_count}"
|
|
113
|
+
[:capture, "#{@captures_var}[#{@captures_count - 1}]", [:slim, :output, escape, code, content]]
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
Slim::Engine.before Slim::EndInserter, Slim::Translator
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
require 'temple'
|
|
3
|
+
require 'slim/parser'
|
|
4
|
+
require 'slim/filter'
|
|
5
|
+
require 'slim/do_inserter'
|
|
6
|
+
require 'slim/end_inserter'
|
|
7
|
+
require 'slim/embedded'
|
|
8
|
+
require 'slim/interpolation'
|
|
9
|
+
require 'slim/controls'
|
|
10
|
+
require 'slim/splat/filter'
|
|
11
|
+
require 'slim/splat/builder'
|
|
12
|
+
require 'slim/code_attributes'
|
|
13
|
+
require 'slim/engine'
|
|
14
|
+
require 'slim/template'
|
|
15
|
+
require 'slim/version'
|
|
16
|
+
require 'slim/railtie' if defined?(Rails::Railtie)
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/lib/slim/version'
|
|
2
|
+
require 'date'
|
|
3
|
+
|
|
4
|
+
Gem::Specification.new do |s|
|
|
5
|
+
s.name = 'slim'
|
|
6
|
+
s.version = Slim::VERSION
|
|
7
|
+
s.date = Date.today.to_s
|
|
8
|
+
s.authors = ['Daniel Mendler', 'Andrew Stone', 'Fred Wu']
|
|
9
|
+
s.email = ['mail@daniel-mendler.de', 'andy@stonean.com', 'ifredwu@gmail.com']
|
|
10
|
+
s.summary = 'Slim is a template language.'
|
|
11
|
+
s.description = 'Slim is a template language whose goal is reduce the syntax to the essential parts without becoming cryptic.'
|
|
12
|
+
s.homepage = 'https://slim-template.github.io/'
|
|
13
|
+
s.license = 'MIT'
|
|
14
|
+
|
|
15
|
+
s.metadata = {
|
|
16
|
+
"bug_tracker_uri" => "https://github.com/slim-template/slim/issues",
|
|
17
|
+
"changelog_uri" => "https://github.com/slim-template/slim/blob/main/CHANGES",
|
|
18
|
+
"documentation_uri" => "https://rubydoc.info/gems/slim/frames",
|
|
19
|
+
"homepage_uri" => "https://slim-template.github.io/",
|
|
20
|
+
"source_code_uri" => "https://github.com/slim-template/slim",
|
|
21
|
+
"wiki_uri" => "https://github.com/slim-template/slim/wiki",
|
|
22
|
+
"funding_uri" => "https://github.com/sponsors/slim-template"
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
s.files = `git ls-files`.split("\n")
|
|
26
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
|
27
|
+
s.require_paths = %w(lib)
|
|
28
|
+
|
|
29
|
+
s.required_ruby_version = '>= 2.5.0'
|
|
30
|
+
|
|
31
|
+
s.add_runtime_dependency('temple', ['~> 0.10.0'])
|
|
32
|
+
s.add_runtime_dependency('tilt', ['>= 2.1.0'])
|
|
33
|
+
end
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
begin
|
|
2
|
+
require 'simplecov'
|
|
3
|
+
SimpleCov.start
|
|
4
|
+
rescue LoadError
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
require 'minitest/autorun'
|
|
8
|
+
require 'slim'
|
|
9
|
+
require 'slim/grammar'
|
|
10
|
+
|
|
11
|
+
Slim::Engine.after Slim::Parser, Temple::Filters::Validator, grammar: Slim::Grammar
|
|
12
|
+
Slim::Engine.before :Pretty, Temple::Filters::Validator
|
|
13
|
+
|
|
14
|
+
class TestSlim < Minitest::Test
|
|
15
|
+
def setup
|
|
16
|
+
@env = Env.new
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def render(source, options = {}, &block)
|
|
20
|
+
scope = options.delete(:scope)
|
|
21
|
+
locals = options.delete(:locals)
|
|
22
|
+
Slim::Template.new(options[:file], options) { source }.render(scope || @env, locals, &block)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
class HtmlSafeString < String
|
|
26
|
+
def html_safe?
|
|
27
|
+
true
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def to_s
|
|
31
|
+
self
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def with_html_safe
|
|
36
|
+
String.send(:define_method, :html_safe?) { false }
|
|
37
|
+
String.send(:define_method, :html_safe) { HtmlSafeString.new(self) }
|
|
38
|
+
yield
|
|
39
|
+
ensure
|
|
40
|
+
String.send(:undef_method, :html_safe?) if String.method_defined?(:html_safe?)
|
|
41
|
+
String.send(:undef_method, :html_safe) if String.method_defined?(:html_safe)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def assert_html(expected, source, options = {}, &block)
|
|
45
|
+
assert_equal expected, render(source, options, &block)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def assert_syntax_error(message, source, options = {})
|
|
49
|
+
render(source, options)
|
|
50
|
+
raise 'Syntax error expected'
|
|
51
|
+
rescue Slim::Parser::SyntaxError => ex
|
|
52
|
+
assert_equal message, ex.message
|
|
53
|
+
message =~ /([^\s]+), Line (\d+)/
|
|
54
|
+
assert_backtrace ex, "#{$1}:#{$2}"
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def assert_ruby_error(error, from, source, options = {})
|
|
58
|
+
render(source, options)
|
|
59
|
+
raise 'Ruby error expected'
|
|
60
|
+
rescue error => ex
|
|
61
|
+
assert_backtrace(ex, from)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def assert_backtrace(ex, from)
|
|
65
|
+
ex.backtrace[0] =~ /([^\s]+:\d+)/
|
|
66
|
+
assert_equal from, $1
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def assert_ruby_syntax_error(from, source, options = {})
|
|
70
|
+
render(source, options)
|
|
71
|
+
raise 'Ruby syntax error expected'
|
|
72
|
+
rescue SyntaxError => ex
|
|
73
|
+
ex.message =~ /([^\s]+:\d+):/
|
|
74
|
+
assert_equal from, $1
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def assert_runtime_error(message, source, options = {})
|
|
78
|
+
render(source, options)
|
|
79
|
+
raise Exception, 'Runtime error expected'
|
|
80
|
+
rescue RuntimeError => ex
|
|
81
|
+
assert_equal message, ex.message
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
class Env
|
|
86
|
+
attr_reader :var, :x
|
|
87
|
+
|
|
88
|
+
def initialize
|
|
89
|
+
@var = 'instance'
|
|
90
|
+
@x = 0
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def id_helper
|
|
94
|
+
"notice"
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def hash
|
|
98
|
+
{a: 'The letter a', b: 'The letter b'}
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def show_first?(show = false)
|
|
102
|
+
show
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def define_macro(name, &block)
|
|
106
|
+
@macro ||= {}
|
|
107
|
+
@macro[name.to_s] = block
|
|
108
|
+
''
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def call_macro(name, *args)
|
|
112
|
+
@macro[name.to_s].call(*args)
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def hello_world(text = "Hello World from @env", opts = {})
|
|
116
|
+
text = text + (opts.to_a * " ") if opts.any?
|
|
117
|
+
if block_given?
|
|
118
|
+
"#{text} #{yield} #{text}"
|
|
119
|
+
else
|
|
120
|
+
text
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def message(*args)
|
|
125
|
+
args.join(' ')
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def action_path(*args)
|
|
129
|
+
"/action-#{args.join('-')}"
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def in_keyword
|
|
133
|
+
"starts with keyword"
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def evil_method
|
|
137
|
+
"<script>do_something_evil();</script>"
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def output_number
|
|
141
|
+
1337
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def succ_x
|
|
145
|
+
@x = @x.succ
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
class ViewEnv
|
|
151
|
+
def output_number
|
|
152
|
+
1337
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def person
|
|
156
|
+
[{name: 'Joe'}, {name: 'Jack'}]
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def people
|
|
160
|
+
%w(Andy Fred Daniel).collect{|n| Person.new(n)}
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def cities
|
|
164
|
+
%w{Atlanta Melbourne Karlsruhe}
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def people_with_locations
|
|
168
|
+
array = []
|
|
169
|
+
people.each_with_index do |p,i|
|
|
170
|
+
p.location = Location.new cities[i]
|
|
171
|
+
array << p
|
|
172
|
+
end
|
|
173
|
+
array
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
require 'forwardable'
|
|
178
|
+
|
|
179
|
+
class Person
|
|
180
|
+
extend Forwardable
|
|
181
|
+
|
|
182
|
+
attr_accessor :name
|
|
183
|
+
|
|
184
|
+
def initialize(name)
|
|
185
|
+
@name = name
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
def location=(location)
|
|
189
|
+
@location = location
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
def_delegators :@location, :city
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
class Location
|
|
196
|
+
attr_accessor :city
|
|
197
|
+
|
|
198
|
+
def initialize(city)
|
|
199
|
+
@city = city
|
|
200
|
+
end
|
|
201
|
+
end
|