## Rails でロジックレスモード
インストール:
$ gem install slim
require で指定:
gem 'slim', require: 'slim/logic_less'
特定のアクションでのみロジックレスモードを有効化したい場合, まず設定でロジックレスモードを global に無効化します。
Slim::Engine.set_options logic_less: false
さらに, アクションの中でレンダリングする度にロジックレスモードを有効化します。
class Controller
def action
Slim::Engine.with_options(logic_less: true) do
render
end
end
end
## Sinatra でロジックレスモード
Sinatra には Slim のビルトインサポートがあります。しなければならないのはロジックレス Slim プラグインを require することです。config.ru で require できます:
require 'slim/logic_less'
これで準備は整いました!
特定のアクションでのみロジックレスモードを有効化したい場合, まず設定でロジックレスモードを global に無効化します。
Slim::Engine.set_options logic_less: false
さらに, アクションの中でレンダリングする度にロジックレスモードを有効化します。
get '/page'
slim :page, logic_less: true
end
## オプション
| 種類 | 名前 | デフォルト | 用途 |
| ---- | ---- | ------- | ------- |
| 真偽値 | :logic_less | true | ロジックレスモードを有効化 ('slim/logic_less' の required が必要) |
| 文字列 | :dictionary | "self" | 変数が検索される辞書への参照 |
| シンボル/配列<シンボル> | :dictionary_access | [:symbol, :string, :method, :instance_variable] | 辞書のアクセス順序 (:symbol, :string, :method, :instance_variable) |
slim-5.2.1/doc/smart.md 0000644 0000041 0000041 00000010727 14572524745 014756 0 ustar www-data www-data # Smart text
The smart text plugin was created to simplify the typing and combining of text and markup in Slim templates.
Using the plugin gives you:
* More convenient ways to type text in Slim templates.
* Smarter and more consistent HTML escaping of typed text.
* Easier combining of the text with inline HTML tags with smart handling of whitespace on the boundaries.
To get started, enable the smart text plugin with
require 'slim/smart'
First of all, this automatically enables the `:implicit_text` option.
When enabled, Slim will treat any line which doesn't start
with a lowercase tag name or any of the special characters as an implicit text line.
If the text needs to span several lines, indent them as usual.
This allows you to easily type text like this, without any leading indicator:
This is an implicit text.
This is a text
which spans
several lines.
This is yet another text.
This works in addition to ways already available in stock Slim:
p This is an inline text.
p This is an inline text
which spans multiple lines.
| This is a verbatim text.
| This is a verbatim text
which spans multiple lines.
Enable the translator plugin with
require 'slim/translator'
# Options
| Type | Name | Default | Purpose |
| ---- | ---- | ------- | ------- |
| Boolean | :tr | true | Enable translator (Enabled if 'slim/translator' is required) |
| Symbol | :tr_mode | :dynamic | When to translate: :static = at compile time, :dynamic = at runtime |
| String | :tr_fn | Depending on installed translation library | Translation function, could be '_' for gettext |
slim-5.2.1/doc/logic_less.md 0000644 0000041 0000041 00000007406 14572524745 015753 0 ustar www-data www-data # Logic less mode
Logic less mode is inspired by [Mustache](https://github.com/defunkt/mustache). Logic less mode uses a dictionary object
e.g. a recursive hash tree which contains the dynamic content.
## Conditional
If the object is not false or empty?, the content will show
- article
h1 = title
## Inverted conditional
If the object is false or empty?, the content will show
-! article
p Sorry, article not found
## Iteration
If the object is an array, the section will iterate
- articles
tr: td = title
## Lambdas
Like mustache, Slim supports lambdas.
= person
= name
The lambda method could be defined like this
def lambda_method
"
#{yield(name: 'Andrew')}
"
end
You can optionally pass one or more hashes to `yield`. If you pass multiple hashes, the block will be iterated as described above.
## Dictionary access
Example code:
- article
h1 = title
The dictionary object is accessed in the order given by the `:dictionary_access`. Default order:
1. `:symbol` - If `article.respond_to?(:has_key?)` and `article.has_key?(:title)`, Slim will execute `article[:title]`
2. `:string` - If `article.respond_to?(:has_key?)` and `article.has_key?('title')`, Slim will execute `article['title']`
3. `:method` - If `article.respond_to?(:title)`, Slim will execute `article.send(:title)`
4. `:instance_variable` - If `article.instance_variable_defined?(@title)`, Slim will execute `article.instance_variable_get @title`
If all the above fails, Slim will try to resolve the title reference in the same order against the parent object. In this example, the parent would be the dictionary object you are rendering the template against.
As you might have guessed, the article reference goes through the same steps against the dictionary. Instance variables are not allowed in the view code, but Slim will find and use them. Essentially, you're just dropping the @ prefix in your template. Parameterized method calls are not allowed.
## Strings
The `self` keyword will return the `.to_s` value for the element under consideration.
Given
{
article: [
'Article 1',
'Article 2'
]
}
And
- article
tr: td = self
This will yield
Article 1
Article 2
## Logic less in Rails
Install:
$ gem install slim
Require:
gem 'slim', require: 'slim/logic_less'
You might want to activate logic less mode only for a few actions, you should disable logic-less mode globally at first in the configuration
Slim::Engine.set_options logic_less: false
and activate logic less mode per render call in your action
class Controller
def action
Slim::Engine.with_options(logic_less: true) do
render
end
end
end
## Logic less in Sinatra
Sinatra has built-in support for Slim. All you have to do is require the logic less Slim plugin. This can be done in your config.ru:
require 'slim/logic_less'
You are then ready to rock!
You might want to activate logic less mode only for a few actions, you should disable logic-less mode globally at first in the configuration
Slim::Engine.set_options logic_less: false
and activate logic less mode per render call in your application
get '/page'
slim :page, logic_less: true
end
## Options
| Type | Name | Default | Purpose |
| ---- | ---- | ------- | ------- |
| Boolean | :logic_less | true | Enable logic less mode (Enabled if 'slim/logic_less' is required) |
| String | :dictionary | "self" | Dictionary where variables are looked up |
| Symbol/Array<Symbol> | :dictionary_access | [:symbol, :string, :method, :instance_variable] | Dictionary access order (:symbol, :string, :method, :instance_variable) |
slim-5.2.1/CHANGES 0000644 0000041 0000041 00000042515 14572524745 013534 0 ustar www-data www-data 5.2.1 (2024-01-20)
* Support Ruby 3.3
* Update Gem metadata
5.2.0 (2023-11-11)
* Fix logic less bug - #783
* Support Rails 7.1 - #936
* Fix splat arguments on Rails 7.1 - #942
5.1.1 (2023-05-16)
* Support lambda functions as shortcuts - #677 #813 #903
* Support --enable-frozen-string-literal - #851
5.1.0 (2023-03-06)
* Allow whitespace markers for verbatim text: `|<`, `|>`, and `|<>` - #912
* Do not swallow single quote after output line indicator - #911
* Support Tilt 2.1.0 - #910
* Fix Railtie load error - #904
* Fix attribute parsing with square brackets - #796
5.0.0 (2023-01-23)
* Fix markdown interpolation #773
* Support case/in #884
* Extract slim/railtie #850
* css: doesn't add type='text/css' anymore #828
* Remove deprecated whitespace syntax =' etc
* Add support for annotate_rendered_view_with_filenames #867, #878, #901
* Remove deprecated syntax
* Add option to hyphenate underscore attributes - #852
* Update CI/CD testing and dependencies
4.1.0 (2020-05-07)
* Add support for Tailwind CSS - #841
* Update dependencies and testing
4.0.1 (2018-09-02)
* Fix incompatibility issue with Slim Include plugin and new ability to specifiy attributes for embedded engines #819
4.0.0 (2018-08-26)
* Add ability to specify attributes for embedded engines using TagEngine - #653
* Set Tilt's default encoding to utf-8 - #800
* Prevent generation of invalid Ruby code in heredoc - #770
* Don't convert underscores to dashes on data attributes - #807 [Backward incompatible]
* Update description in README.jp.md - #795
* Removed support for embedded engines: Asciidoc, Builder, Creole, Erb, Nokogiri, Opal, Org-Ruby, Styl, Wikicloth
* Fix tests
3.0.9 (2017-11-09)
* Fixed Cross-site Scripting in splat attributes names (See #767)
* Restrict access to public methods in logic_less templates (See #781)
3.0.8 (2017-05-06)
* Added splat_prefix configuration option for Angular2 syntax support
* Require Ruby >= 2.0.0
* Relax temple dependency
3.0.7 (2016-05-22)
* Add additional attributes feature to shortcuts
* Freeze string literals
3.0.6 (2015-06-05)
* Fix warnings #625
3.0.4 (2015-06-02)
* javascript: doesn't add type='text/javascript' anymore
* slimrb: --require added
* Fix #624
3.0.3 (2015-03-06)
* Fix #392, capturing for splat attributes didn't work correctly under Rails
3.0.2 (2015-02-02)
* slimrb: Add option --locals
* Fix issues in the test suite (#576), thanks @dmke!
3.0.1 (2014-12-22)
* Allow more special characters in html attribute names (See https://html.spec.whatwg.org/multipage/syntax.html#attributes-2), #567
* Fix: Code attributes mutate their argument (#571)
3.0.0 (2014-12-07)
* Drop 1.8.7 support
* Deprecate default_options in favor of options
* Support xml pretty printing with format: :xml
* Deprecate `='`, `=='` and `tag'` syntax for trailing whitespace. Use `=<` etc. instead.
* slimrb: Remove deprecated plugin options -l and -t
2.1.0 (2014-10-15)
* Parser: Require pairwise braces in quoted attributes
* Parser: add :attr_list_delims and :code_attr_delims
* Parser: deprecate :attr_delims
* Parser: relax text indentation requirements:
| line
next line
tag some text
more text
* Parser: allow first line to be indented
* Parser: allow inline embedded languages:
.content: markdown: This is **important**
* Parser: allow line breaks in quoted attributes
* Added Opal as embedded engine
* slimrb: Change meaning of -r, deprecate -t and -l
* Fix issue with inserted end (#485)
* Add experimental 'slim/include' plugin (Might change in the future)
* Add experimental 'slim/smart' plugin (Might change in the future)
* Drop jruby18 support
* Fix rails error reporting #587 (Manipulate stacktrace)
* Splat: handle html_safe
2.0.3 (2014-07-04)
* slimrb: Don't update HTML output on exceptions
* Allow dashes at the beginning of class names (#474)
* Render empty attributes as standalone in html mode (#480)
* Fix #482: problem with whitespace modifier `tag=<`
* Fix #485: missing end for empty `if` control blocks
* Fix #510: double dash in class name
2.0.2 (2013-10-27)
* Add option :attr_delims
2.0.1 (2013-07-31)
* Support multiple attributes per shortcut (See issue #415)
* Add support for org-ruby embedded engine
* Render true boolean attributes with empty value
* Support case-when statements
* Fix issue #431
* Also escape ' to '
2.0.0 (2013-05-27)
* IMPORTANT: Backward incompatible syntax change: '{...}' and '[...]' are not
allowed as ruby attribute wrappers anymore. Use parentheses '(...)'
if you want to wrap code with spaces. This allows to write arrays and hashes directly.
Old:
div id={'obj' + name} data=({:a => 1, :b => 2}) class=['alpha', 'beta']
New:
div id=('obj' + name) data={:a => 1, :b => 2} class=['alpha', 'beta']
* Quoted attributes are escaped by default
Old:
a href='http://github.com/slim-template/slim/?a=1&b=2'
New:
a href='http://github.com/slim-template/slim/?a=1&b=2'
a href=='http://github.com/slim-template/slim/?a=1&b=2'
You can always disable escaping completly by using :disable_escape if you don't want to write '=='.
* Added hyphenation support for data attributes (Option :hyphen_attrs)
Example: div data={key1_key2: 2, key1: {key3: 3}} will render as ''
* Removed deprecated options:
- :escape_quoted_attrs
- :remove_empty_attrs
- :chain
- :attr_wrapper (renamed to :attr_quote)
- :attr_delimiter (renamed to :merge_attrs)
- Slim::LogicLess :wrapped dictionary
- Slim::Parser :shortcut string option
* Allow spaces around attributes, e.g 'a [ href = url ] text' and 'a href = url text'
* Add unicode support for tags and attributes (Issue #212)
* Generate missing `do` keywords for code blocks (see #342)
* Logic-less: Add keyword `self` for string access
* Added Slim::ERBConverter, require 'slim/erb_converter'
* Added option '-e' for ERB conversion to slimrb
* Add syntax for trailing or leading whitespace after tag, e.g. input>, input<
* Add syntax for trailing or leading whitespace after output, e.g. =>, =<
1.3.8 (2013-04-11)
* Disable some superflous deprecation warnings
1.3.7 (2013-04-10)
* Fixed issue #374, rescue and ensure blocks
* Fixed issue #333 (Throw syntax error if you write text after closed tag)
* Deprecated :attr_delimiter (renamed to :merge_attrs)
* Deprecated :attr_wrapper (renamed to :attr_quote)
* Warn if you use curly braces or brackets for ruby attributes since
curly braces and brackets will be interpreted as Hash/Array in Slim 2.0.0
Old syntax:
div id={person && person.id}
div id=[person && person.id]
New syntax in 2.0.0:
div id=(person && person.id)
* Deprecated :escape_quoted_attrs (done by default in 2.0)
* Warn if quoted attributes might be double escaped in Slim 2.0.0
Old syntax:
a href='http://github.com/slim-template/slim/?a=1&b=2'
a href=='http://github.com/slim-template/slim/?a=1&b=2'
New syntax in 2.0.0:
a href='http://github.com/slim-template/slim/?a=1&b=2'
a href=='http://github.com/slim-template/slim/?a=1&b=2'
* Improved pretty printing (Issue #202)
* Renamed Slim::EmbeddedEngine to Slim::Embedded (Old constant still available until 2.0)
* Renamed Slim::ControlStructures to Slim::Controls
* Tab expansion improved (tab + space is interpreted as equivalent to tab)
* Support for wrapping javascript in HTML comments or CDATA (Issue #340)
* Asciidoc embedded engine added
1.3.6 (2013-01-06)
* Allow attribute values to be broken with `\` (Issue #331)
* Tag shortcuts implemented (Issue #306)
* Hash format of Slim::Parser option :shortcut changed, old configuration deprecated but still supported
1.3.5 (2012-12-19)
* Logic-less:
- Rewrote logic-less mode (Issue #326, #327)
- Logic-less mode supports lambdas
- Option :dictionary_access made more powerful, value :wrapped deprecated
1.3.4 (2012-11-15)
* Fixed #314
* Logic-less test cases added
1.3.3 (2012-10-16)
* Attribute handling made consistent:
- Splat attributes, static and dynamic attributes are now all handled the same
- Merged attributes are removed if empty (in the default configuration this is only "class")
- Dynamic attributes which are not merged are checked for false or nil and removed if this is the case
- Dynamic attributes which are not merged are checked for true and generated as attribute-name="attribute-name"
* Rename class BooleanAttributes to CodeAttributes
* Add literate test suite (still incomplete), run with `rake test:literate`
* Remove UTF BOM when parsing Slim code
* Fixed issue #303
1.3.2 (2012-09-26)
* Fix boolean attributes #299
1.3.1 (2012-09-23)
* Support inline html at the beginning of a line (New line indicator <). No pipe symbol is | necessary.
It is even possible to wrap other Slim syntax in such a html block.
* Code restructured - Handling of boolean and splat attributes improved and PERFORMANCE improved.
* BACKWARD INCOMPATIBLE CHANGE - Dynamic attributes which return empty value "" are not removed anymore
(this means "" is now interpreted as true), whereas false and nil are still removed.
This corresponds to the definition of boolean attributes in XHTML and HTML5.
* Deprecated option :remove_empty_attrs
* Add option :escape_quoted_attrs to escape quoted attributes, use == if you don't want that.
The default is false to stay backward compatible.
* Use Temple::FilterError exception
* Use Temple::Parser
* / is not escaped anymore to /
* Parser: check for missing closing quote in quoted attributes
* Use new temple option validation to make Slim configuration more user friendly.
* Support thread options Slim::Engine.with_options which especially useful for Rails
* Add explicit column number to SyntaxError.to_s
1.3.0 (2012-09-04)
* Parser wraps text blocks in [:slim, :text, ...] (Used by Translator/I18n plugin)
* Added Translator/I18n plugin which uses GetText or FastGettext (require 'slim/translator')
* Moved logic less mode out of the core to plugin (require 'slim/logic_less')
1.2.2 (2012-06-21)
* Fix issue #264
1.2.1 (2012-05-22)
* Support stylus as embedded engine
* Fix issue #257
1.2.0 (2012-03-30)
* Add option :shortcut which configures attribute shortcuts
Default setting:
Slim::Parser.default_options[:shortcut] = {'#' => 'id', '.' => 'class', '*' => '*'}
Define custom shortcut attribute (e.g. a@ajax-link renders )
Slim::Parser.default_options[:shortcut] = {'@' => 'role'}
Define custom shortcut attribute with tag (e.g. @ajax-link renders )
Slim::Parser.default_options[:shortcut] = {'@' => 'a role'}
* Add syntax for splat attributes (#109)
* Support for dynamic tags, e.g. *{:tag => 'img', :src => 'image.jpg'}
1.1.1 (2012-02-29)
* Evaluating a html attribute now happens only once (#219)
* Code with trailing comma is treated as broken line (#226)
* Support option :remove_empty_attrs (default true)
* Require temple 0.4.0
1.1.0 (2012-01-06)
* Support for special characters in class/id shortcut removed
* Do not allow : in class/id shortcut
* Add support for block expansion syntax
* Support options :indent, :sort_attrs
* Require temple 0.3.5
1.0.4 (2011-11-03)
* Pass options to embedded Tilt engine
Slim::EmbeddedEngine.set_default_options :markdown => {...}
* Add test case for precompiled embedded engine 'builder'
* Bug #204 fixed, tabs were not parsed correctly
1.0.3 (2011-10-08)
* Fix rubinius test cases
* Fix line numbers for embedded engines
* Require temple 0.3.4
* Remove dynamic embedded engines Haml, Liquid, Radius, Markaby
* More thorough integration testing using travis-ci
See http://travis-ci.org/#!/stonean/slim
* Empty static attributes are not removed anymore
* Line indicator =' is supported in tags
1.0.2 (2011-08-26)
* Support for Rails 3.1 streaming (Temple > 0.3.2 required)
* Switch to default format xhtml (supports all doctypes, including html5)
* Improve parsing of #{interpolation} in quoted attributes (issue #159)
* Use travis-ci for continous integration testing
1.0.1 (2011-08-07)
* Only delimiting brackets must be balanced in ruby attributes
e.g this is possible now `a href=(ruby_code "{")
* Skip empty lines in text block (#156)
1.0.0 (2011-07-24)
* Fixed html attribute issue in sections mode (#127)
* Obsolete directive syntax removed
* Syntax for trailing whitespace added (==' and =')
* Deprecated file 'slim/rails.rb' removed
* Parsing of #{interpolation} in markdown fixed
* Support for attributes which span multiple lines
* Dynamic attributes with value true/false are interpreted as boolean
* Support boolean attributes without value e.g. option(selected id="abc")
0.9.3 (2011-05-15)
* Allow for bypassing escaping in attributes
* check if string encoding is valid
* support for html conditional comments
* Use new Temple html attribute expression [:html, :attrs, [:html, :attr, ...], ...]
* Use new slim html attribute expression (similiar to Temple)
* Option :id_delimiter replaced with :attr_delimiter
* Attribute value merging improved (nil/empty values are ignored now)
* Arrays attribute values are joined
* Boolean attributes (e.g. selected=true is converted to selected="selected")
* Option :debug removed
* Slim expression grammar provided, Temple validator used in tests
* Option :auto_escape replaced with inverse option :disable_escape
* Require temple 0.3.0
0.9.2 (2011-03-30)
* add SassEngine which respects :pretty
* embedded engine code refactored
* temple supports denser template registration
* deprecate slim/rails (just require 'slim')
* use temple rails and tilt templates
* add encoding option to Slim::Parser/Slim::Engine to enforce template encoding
* vim support is now an external project
0.9.1 (2011-03-10)
* add new doctype syntax without !
* slim directive expression has type and args
0.9.0 (2011-01-30)
* slim should not be registered as the default template handler.
* add support for unescaped text interpolation
0.8.4 (2011-01-26)
* Added the option to turn off automatic HTML escaping.
* update to tilt 1.2.2
* allow call to yield in logic less mode
* allow doctype declaration to be capitalized
0.8.3 (2010-12-23)
* Added support for html comments. The parser uses the :static filter instead of the :comment filter due to the way the parser is constructed.
0.8.2 (2010-12-22)
* fix issue #96
* Added the Temple Debugger filter.
* Rails problems fixed
0.8.1 (2010-12-17)
* remove backtick slim syntax -- no longer supported
* slim executable conflict. issue #91
* vim syntax support improved
0.8.0 (2010-11-29)
* rails logic less support
0.7.4 (2010-11-22)
* use ' for text block with trailing whitespace
* allow to disable/enable embedded engines
0.7.3 (2010-11-16)
* fix #82
* basic rails test added
0.7.2 (2010-11-09)
* get rid of rails deprecation warning
* use_html_safe is activated automatically by temple
0.7.1 (2010-11-03)
* logic less mode
* add syntax for explicitly closed tags
0.7.0 (2010-10-25)
* slim-mode.el for emacs added (modified haml-mode.el, needs some work to be fully functional for slim)
* embedded engines
* escape interpolated strings/attributes
* Slim#Filter now uses optional configuration hash
* Initial implementation for Rail's `html_safe`. Closes #25
* fallback to escape_html stolen from cgi.rb if escape_utils is unavailable, use normal requires because slim is on the load path
* Limit the allowed characters used for attributes delimiters (now only allows parentheses, square brackets and curly braces). See #16 for more info.
* Default to HTML5-mode
* Slim now uses Temple and Tilt.
* Choose your own attribute delimiter!
0.6.1 (2010-10-17)
* can wrap parens around attributes if you so desire
* added erubis to the benchmarks
0.6.0 (2010-10-17)
* Added slim itself, haml and mustache to the development env for easier benchmarking.
* added escape_html functionality. need to tweak for speed
0.5.1 (2010-10-08)
* Consecutive condition statements now working as expected.
0.5.0 (2010-10-07)
* Added 'unless' to the list of control words.
* Fixes for inline conditions. There must be a better way of doing this??
* '-' is a valid character in HTML attributes, so let's allow that.
* Improved the regex so that control code now supports code blocks.
* Output code (start with '=') can now accept code blocks.
* Method calls no longer need parenthesis. We need more tests to ensure the implementation's robustness.
0.4.1 (2010-10-03)
* Added '|' as an alias of '`' for parsing plain text. This simulates the syntax of the Jade template engine.
* Added instructions of how to use the gem.
0.4.0 (2010-09-21)
* support for nesting lines under backtick
* make it so that one space is the left margin. any additional spaces will be copied over
* support for using indentation after backtick to denote paragraphs. useful for script tags and paragraphs
0.3.1 (2010-09-17)
* fix bug with adding end to nesting ruby code
0.3.0 (2010-09-17)
* Optimize compiled string to reduce number of concatentations to the buffer
0.2.0 (2010-09-17)
* can now make code call on same line as tag
0.1.0 (2010-09-15)
* Initial release
slim-5.2.1/.github/ 0000755 0000041 0000041 00000000000 14572524745 014072 5 ustar www-data www-data slim-5.2.1/.github/workflows/ 0000755 0000041 0000041 00000000000 14572524745 016127 5 ustar www-data www-data slim-5.2.1/.github/workflows/test.yml 0000644 0000041 0000041 00000006065 14572524745 017640 0 ustar www-data www-data name: test
on:
push:
paths-ignore:
- '**.md'
pull_request:
paths-ignore:
- '**.md'
schedule:
- cron: "0 15 * * 0"
jobs:
basic:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
ruby: ['2.5', '2.6', '2.7', '3.0', '3.1', '3.2', '3.3']
steps:
- uses: actions/checkout@v4
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ matrix.ruby }}
- run: bundle update && bundle exec rake test
- run: bundle update && bundle exec rake test:sinatra
name: "rake test:sinatra SINATRA=2.2.4"
env:
SINATRA: 2.2.4
- run: bundle update && bundle exec rake test:sinatra
name: "rake test:sinatra SINATRA=3.0.6"
if: ${{ matrix.ruby != '2.5' }}
env:
SINATRA: 3.0.6
- run: bundle update && bundle exec rake test:sinatra
name: "rake test:sinatra SINATRA=3.1.0"
if: ${{ matrix.ruby != '2.5' }}
env:
SINATRA: 3.1.0
- run: bundle update && bundle exec rake test:sinatra
name: "rake test:sinatra SINATRA=3.2.0"
if: ${{ matrix.ruby != '2.5' }}
env:
SINATRA: 3.2.0
- run: bundle update && bundle exec rake test:sinatra
name: "rake test:sinatra SINATRA=4.0.0"
if: ${{ matrix.ruby != '2.5' && matrix.ruby != '2.6' }}
env:
SINATRA: 4.0.0
- run: bundle update && bundle exec rake test:sinatra
name: "rake test:sinatra SINATRA=main"
if: ${{ matrix.ruby != '2.5' && matrix.ruby != '2.6' }}
env:
SINATRA: main
rails-5:
runs-on: ubuntu-latest
strategy:
fail-fast: false
steps:
- uses: actions/checkout@v4
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: 2.7
- run: bundle update && bundle exec rake test:rails
name: "rake test:rails RAILS=5.2.8"
env:
RAILS: 5.2.8
rails-6:
runs-on: ubuntu-latest
strategy:
fail-fast: false
steps:
- uses: actions/checkout@v4
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: 2.7
- run: bundle update && bundle exec rake test:rails
name: "rake test:rails RAILS=6.0.6"
env:
RAILS: 6.0.6
- run: bundle update && bundle exec rake test:rails
name: "rake test:rails RAILS=6.1.7"
env:
RAILS: 6.1.7
rails-7:
runs-on: ubuntu-latest
strategy:
fail-fast: false
steps:
- uses: actions/checkout@v4
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: 3.3
- run: bundle update && bundle exec rake test:rails
name: "rake test:rails RAILS=7.0.8"
env:
RAILS: 7.0.8
- run: bundle update && bundle exec rake test:rails
name: "rake test:rails RAILS=7.1.3"
env:
RAILS: 7.1.3
- run: bundle update && bundle exec rake test:rails
name: "rake test:rails RAILS=main"
env:
RAILS: main
slim-5.2.1/lib/ 0000755 0000041 0000041 00000000000 14572524745 013300 5 ustar www-data www-data slim-5.2.1/lib/slim.rb 0000644 0000041 0000041 00000000657 14572524745 014601 0 ustar www-data www-data # frozen_string_literal: true
require 'temple'
require 'slim/parser'
require 'slim/filter'
require 'slim/do_inserter'
require 'slim/end_inserter'
require 'slim/embedded'
require 'slim/interpolation'
require 'slim/controls'
require 'slim/splat/filter'
require 'slim/splat/builder'
require 'slim/code_attributes'
require 'slim/engine'
require 'slim/template'
require 'slim/version'
require 'slim/railtie' if defined?(Rails::Railtie)
slim-5.2.1/lib/slim/ 0000755 0000041 0000041 00000000000 14572524745 014244 5 ustar www-data www-data slim-5.2.1/lib/slim/splat/ 0000755 0000041 0000041 00000000000 14572524745 015367 5 ustar www-data www-data slim-5.2.1/lib/slim/splat/filter.rb 0000644 0000041 0000041 00000006015 14572524745 017203 0 ustar www-data www-data # frozen_string_literal: true
module Slim
module Splat
# @api private
class Filter < ::Slim::Filter
define_options :merge_attrs, :attr_quote, :sort_attrs, :default_tag, :format, :disable_capture,
hyphen_attrs: %w(data aria), use_html_safe: ''.respond_to?(:html_safe?),
hyphen_underscore_attrs: false
def call(exp)
@splat_options = nil
exp = compile(exp)
if @splat_options
opts = options.to_hash.reject { |k, v| !Filter.options.valid_key?(k) }.inspect
[:multi, [:code, "#{@splat_options} = #{opts}"], exp]
else
exp
end
end
# Handle tag expression `[:html, :tag, name, attrs, content]`
#
# @param [String] name Tag name
# @param [Array] attrs Temple expression
# @param [Array] content Temple expression
# @return [Array] Compiled temple expression
def on_html_tag(name, attrs, content = nil)
return super if name != '*'
builder, block = make_builder(attrs[2..-1])
if content
[:multi,
block,
[:slim, :output, false,
"#{builder}.build_tag #{empty_exp?(content) ? '{}' : 'do'}",
compile(content)]]
else
[:multi,
block,
[:dynamic, "#{builder}.build_tag"]]
end
end
# Handle attributes expression `[:html, :attrs, *attrs]`
#
# @param [Array] attrs Array of temple expressions
# @return [Array] Compiled temple expression
def on_html_attrs(*attrs)
if attrs.any? { |attr| splat?(attr) }
builder, block = make_builder(attrs)
[:multi,
block,
[:dynamic, "#{builder}.build_attrs"]]
else
super
end
end
protected
def splat?(attr)
# Splat attribute given
attr[0] == :slim && attr[1] == :splat ||
# Hyphenated attribute also needs splat handling
(attr[0] == :html && attr[1] == :attr && options[:hyphen_attrs].include?(attr[2]) &&
attr[3][0] == :slim && attr[3][1] == :attrvalue)
end
def make_builder(attrs)
@splat_options ||= unique_name
builder = unique_name
result = [:multi, [:code, "#{builder} = ::Slim::Splat::Builder.new(#{@splat_options})"]]
attrs.each do |attr|
result <<
if attr[0] == :html && attr[1] == :attr
if attr[3][0] == :slim && attr[3][1] == :attrvalue
[:code, "#{builder}.code_attr(#{attr[2].inspect}, #{attr[3][2]}, (#{attr[3][3]}))"]
else
tmp = unique_name
[:multi,
[:capture, tmp, compile(attr[3])],
[:code, "#{builder}.attr(#{attr[2].inspect}, #{tmp})"]]
end
elsif attr[0] == :slim && attr[1] == :splat
[:code, "#{builder}.splat_attrs((#{attr[2]}))"]
else
attr
end
end
[builder, result]
end
end
end
end
slim-5.2.1/lib/slim/splat/builder.rb 0000644 0000041 0000041 00000007074 14572524745 017352 0 ustar www-data www-data # frozen_string_literal: true
module Slim
class InvalidAttributeNameError < StandardError; end
module Splat
# @api private
class Builder
# https://html.spec.whatwg.org/multipage/syntax.html#attributes-2
INVALID_ATTRIBUTE_NAME_REGEX = /[ \0"'>\/=]/
def initialize(options)
@options = options
@attrs = {}
end
def code_attr(name, escape, value)
if delim = @options[:merge_attrs][name]
value = Array === value ? value.join(delim) : value.to_s
attr(name, escape_html(escape, value)) unless value.empty?
elsif @options[:hyphen_attrs].include?(name) && Hash === value
hyphen_attr(name, escape, value)
elsif value != false && value != nil
attr(name, escape_html(escape, value))
end
end
def splat_attrs(splat)
splat.each do |name, value|
code_attr(name.to_s, true, value)
end
end
def attr(name, value)
if name =~ INVALID_ATTRIBUTE_NAME_REGEX
raise InvalidAttributeNameError, "Invalid attribute name '#{name}' was rendered"
end
if @attrs[name]
if delim = @options[:merge_attrs][name]
@attrs[name] = @attrs[name].to_s + delim + value.to_s
else
raise("Multiple #{name} attributes specified")
end
else
@attrs[name] = value
end
end
def build_tag(&block)
tag = @attrs.delete('tag').to_s
tag = @options[:default_tag] if tag.empty?
if block
# This is a bit of a hack to get a universal capturing.
#
# TODO: Add this as a helper somewhere to solve these capturing issues
# once and for all.
#
# If we have Slim capturing disabled and the scope defines the method `capture` (i.e. Rails)
# we use this method to capture the content.
#
# otherwise we just use normal Slim capturing (yield).
#
# See https://github.com/slim-template/slim/issues/591
# https://github.com/slim-template/slim#helpers-capturing-and-includes
#
content =
if @options[:disable_capture] && (scope = block.binding.eval('self')).respond_to?(:capture)
scope.capture(&block)
else
yield
end
"<#{tag}#{build_attrs}>#{content}#{tag}>"
else
"<#{tag}#{build_attrs} />"
end
end
def build_attrs
attrs = @options[:sort_attrs] ? @attrs.sort_by(&:first) : @attrs
attrs.map do |k, v|
if v == true
if @options[:format] == :xhtml
" #{k}=#{@options[:attr_quote]}#{@options[:attr_quote]}"
else
" #{k}"
end
else
" #{k}=#{@options[:attr_quote]}#{v}#{@options[:attr_quote]}"
end
end.join
end
private
def hyphen_attr(name, escape, value)
if Hash === value
if @options[:hyphen_underscore_attrs]
value.each do |n, v|
hyphen_attr("#{name}-#{n.to_s.tr('_', '-')}", escape, v)
end
else
value.each do |n, v|
hyphen_attr("#{name}-#{n}", escape, v)
end
end
else
attr(name, escape_html(escape, value))
end
end
def escape_html(escape, value)
return value if !escape || value == true
@options[:use_html_safe] ? Temple::Utils.escape_html_safe(value) : Temple::Utils.escape_html(value)
end
end
end
end
slim-5.2.1/lib/slim/do_inserter.rb 0000644 0000041 0000041 00000002173 14572524745 017111 0 ustar www-data www-data # frozen_string_literal: true
module Slim
# In Slim you don't need the do keyword sometimes. This
# filter adds the missing keyword.
#
# - 10.times
# | Hello
#
# @api private
class DoInserter < Filter
BLOCK_REGEX = /(\A(if|unless|else|elsif|when|in|begin|rescue|ensure|case)\b)|\bdo\s*(\|[^\|]*\|\s*)?\Z/
# Handle control expression `[:slim, :control, code, content]`
#
# @param [String] code Ruby code
# @param [Array] content Temple expression
# @return [Array] Compiled temple expression
def on_slim_control(code, content)
code += ' do' unless code =~ BLOCK_REGEX || empty_exp?(content)
[:slim, :control, code, compile(content)]
end
# Handle output expression `[:slim, :output, escape, code, content]`
#
# @param [Boolean] escape Escape html
# @param [String] code Ruby code
# @param [Array] content Temple expression
# @return [Array] Compiled temple expression
def on_slim_output(escape, code, content)
code += ' do' unless code =~ BLOCK_REGEX || empty_exp?(content)
[:slim, :output, escape, code, compile(content)]
end
end
end
slim-5.2.1/lib/slim/embedded.rb 0000644 0000041 0000041 00000015447 14572524745 016335 0 ustar www-data www-data # frozen_string_literal: true
module Slim
# @api private
class TextCollector < Filter
def call(exp)
@collected = ''.dup
super(exp)
@collected
end
def on_slim_interpolate(text)
@collected << text
nil
end
end
# @api private
class NewlineCollector < Filter
def call(exp)
@collected = [:multi]
super(exp)
@collected
end
def on_newline
@collected << [:newline]
nil
end
end
# @api private
class OutputProtector < Filter
def call(exp)
@protect, @collected, @tag = [], ''.dup, object_id.abs.to_s(36)
super(exp)
@collected
end
def on_static(text)
@collected << text
nil
end
def on_slim_output(escape, text, content)
@collected << "%#{@tag}%#{@protect.length}%"
@protect << [:slim, :output, escape, text, content]
nil
end
def unprotect(text)
block = [:multi]
while text =~ /%#{@tag}%(\d+)%/
block << [:static, $`]
block << @protect[$1.to_i]
text = $'
end
block << [:static, text]
end
end
# Temple filter which processes embedded engines
# @api private
class Embedded < Filter
@engines = {}
class << self
attr_reader :engines
# Register embedded engine
#
# @param [String] name Name of the engine
# @param [Class] klass Engine class
# @param option_filter List of options to pass to engine.
# Last argument can be default option hash.
def register(name, klass, *option_filter)
name = name.to_sym
local_options = option_filter.last.respond_to?(:to_hash) ? option_filter.pop.to_hash : {}
define_options(name, *option_filter)
klass.define_options(name)
engines[name.to_sym] = proc do |options|
klass.new({}.update(options).delete_if {|k,v| !option_filter.include?(k) && k != name }.update(local_options))
end
end
def create(name, options)
constructor = engines[name] || raise(Temple::FilterError, "Embedded engine #{name} not found")
constructor.call(options)
end
end
define_options :enable_engines, :disable_engines
def initialize(opts = {})
super
@engines = {}
@enabled = normalize_engine_list(options[:enable_engines])
@disabled = normalize_engine_list(options[:disable_engines])
end
def on_slim_embedded(name, body, attrs)
name = name.to_sym
raise(Temple::FilterError, "Embedded engine #{name} is disabled") unless enabled?(name)
@engines[name] ||= self.class.create(name, options)
@engines[name].on_slim_embedded(name, body, attrs)
end
def enabled?(name)
(!@enabled || @enabled.include?(name)) &&
(!@disabled || !@disabled.include?(name))
end
protected
def normalize_engine_list(list)
raise(ArgumentError, "Option :enable_engines/:disable_engines must be String or Symbol list") unless !list || Array === list
list && list.map(&:to_sym)
end
class Engine < Filter
protected
def collect_text(body)
@text_collector ||= TextCollector.new
@text_collector.call(body)
end
def collect_newlines(body)
@newline_collector ||= NewlineCollector.new
@newline_collector.call(body)
end
end
# Basic tilt engine
class TiltEngine < Engine
def on_slim_embedded(engine, body, attrs)
tilt_engine = Tilt[engine] || raise(Temple::FilterError, "Tilt engine #{engine} is not available.")
tilt_options = options[engine.to_sym] || {}
tilt_options[:default_encoding] ||= 'utf-8'
[:multi, tilt_render(tilt_engine, tilt_options, collect_text(body)), collect_newlines(body)]
end
protected
def tilt_render(tilt_engine, tilt_options, text)
[:static, tilt_engine.new(tilt_options) { text }.render]
end
end
# Sass engine which supports :pretty option
class SassEngine < TiltEngine
define_options :pretty
protected
def tilt_render(tilt_engine, tilt_options, text)
text = tilt_engine.new(tilt_options.merge(
style: options[:pretty] ? :expanded : :compressed
)) { text }.render
text = text.chomp
[:static, text]
end
end
# Static template with interpolated ruby code
class InterpolateTiltEngine < TiltEngine
def collect_text(body)
output_protector.call(interpolation.call(body))
end
def tilt_render(tilt_engine, tilt_options, text)
output_protector.unprotect(tilt_engine.new(tilt_options) { text }.render)
end
private
def interpolation
@interpolation ||= Interpolation.new
end
def output_protector
@output_protector ||= OutputProtector.new
end
end
# Tag wrapper engine
# Generates a html tag and wraps another engine (specified via :engine option)
class TagEngine < Engine
disable_option_validator!
set_options attributes: {}
def on_slim_embedded(engine, body, attrs)
unless options[:attributes].empty?
options[:attributes].map do |k, v|
attrs << [:html, :attr, k, [:static, v]]
end
end
if options[:engine]
opts = {}.update(options)
opts.delete(:engine)
opts.delete(:tag)
opts.delete(:attributes)
@engine ||= options[:engine].new(opts)
body = @engine.on_slim_embedded(engine, body, attrs)
end
[:html, :tag, options[:tag], attrs, body]
end
end
# Javascript wrapper engine.
# Like TagEngine, but can wrap content in html comment or cdata.
class JavaScriptEngine < TagEngine
disable_option_validator!
set_options tag: :script
def on_slim_embedded(engine, body, attrs)
super(engine, [:html, :js, body], attrs)
end
end
# Embeds ruby code
class RubyEngine < Engine
def on_slim_embedded(engine, body, attrs)
[:multi, [:newline], [:code, "#{collect_text(body)}\n"]]
end
end
# These engines are executed at compile time, embedded ruby is interpolated
register :markdown, InterpolateTiltEngine
register :textile, InterpolateTiltEngine
register :rdoc, InterpolateTiltEngine
# These engines are executed at compile time
register :coffee, JavaScriptEngine, engine: TiltEngine
register :less, TagEngine, tag: :style, engine: TiltEngine
register :sass, TagEngine, :pretty, tag: :style, engine: SassEngine
register :scss, TagEngine, :pretty, tag: :style, engine: SassEngine
# Embedded javascript/css
register :javascript, JavaScriptEngine
register :css, TagEngine, tag: :style
# Embedded ruby code
register :ruby, RubyEngine
end
end
slim-5.2.1/lib/slim/code_attributes.rb 0000644 0000041 0000041 00000004141 14572524745 017751 0 ustar www-data www-data # frozen_string_literal: true
module Slim
# @api private
class CodeAttributes < Filter
define_options :merge_attrs
# Handle attributes expression `[:html, :attrs, *attrs]`
#
# @param [Array] attrs Array of temple expressions
# @return [Array] Compiled temple expression
def on_html_attrs(*attrs)
[:multi, *attrs.map { |a| compile(a) }]
end
# Handle attribute expression `[:html, :attr, name, value]`
#
# @param [String] name Attribute name
# @param [Array] value Value expression
# @return [Array] Compiled temple expression
def on_html_attr(name, value)
if value[0] == :slim && value[1] == :attrvalue && !options[:merge_attrs][name]
# We handle the attribute as a boolean attribute
escape, code = value[2], value[3]
case code
when 'true'
[:html, :attr, name, [:multi]]
when 'false', 'nil'
[:multi]
else
tmp = unique_name
[:multi,
[:code, "#{tmp} = #{code}"],
[:if, tmp,
[:if, "#{tmp} == true",
[:html, :attr, name, [:multi]],
[:html, :attr, name, [:escape, escape, [:dynamic, tmp]]]]]]
end
else
# Attribute with merging
@attr = name
super
end
end
# Handle attribute expression `[:slim, :attrvalue, escape, code]`
#
# @param [Boolean] escape Escape html
# @param [String] code Ruby code
# @return [Array] Compiled temple expression
def on_slim_attrvalue(escape, code)
# We perform attribute merging on Array values
if delimiter = options[:merge_attrs][@attr]
tmp = unique_name
[:multi,
[:code, "#{tmp} = #{code}"],
[:if, "Array === #{tmp}",
[:multi,
[:code, "#{tmp} = #{tmp}.flatten"],
[:code, "#{tmp}.map!(&:to_s)"],
[:code, "#{tmp}.reject!(&:empty?)"],
[:escape, escape, [:dynamic, "#{tmp}.join(#{delimiter.inspect})"]]],
[:escape, escape, [:dynamic, tmp]]]]
else
[:escape, escape, [:dynamic, code]]
end
end
end
end
slim-5.2.1/lib/slim/engine.rb 0000644 0000041 0000041 00000002761 14572524745 016044 0 ustar www-data www-data # frozen_string_literal: true
# The Slim module contains all Slim related classes (e.g. Engine, Parser).
# Plugins might also reside within the Slim module (e.g. Include, Smart).
# @api public
module Slim
# Slim engine which transforms slim code to executable ruby code
# @api public
class Engine < Temple::Engine
# This overwrites some Temple default options or sets default options for Slim specific filters.
# It is recommended to set the default settings only once in the code and avoid duplication. Only use
# `define_options` when you have to override some default settings.
define_options pretty: false,
sort_attrs: true,
format: :xhtml,
attr_quote: '"',
merge_attrs: {'class' => ' '},
generator: Temple::Generators::StringBuffer,
default_tag: 'div'
filter :Encoding
filter :RemoveBOM
use Slim::Parser
use Slim::Embedded
use Slim::Interpolation
use Slim::Splat::Filter
use Slim::DoInserter
use Slim::EndInserter
use Slim::Controls
html :AttributeSorter
html :AttributeMerger
use Slim::CodeAttributes
use(:AttributeRemover) { Temple::HTML::AttributeRemover.new(remove_empty_attrs: options[:merge_attrs].keys) }
html :Pretty
filter :Ambles
filter :Escapable
filter :StaticAnalyzer
filter :ControlFlow
filter :MultiFlattener
filter :StaticMerger
use(:Generator) { options[:generator] }
end
end
slim-5.2.1/lib/slim/filter.rb 0000644 0000041 0000041 00000001463 14572524745 016062 0 ustar www-data www-data # frozen_string_literal: true
module Slim
# Base class for Temple filters used in Slim
#
# This base filter passes everything through and allows
# to override only some methods without affecting the rest
# of the expression.
#
# @api private
class Filter < Temple::HTML::Filter
# Pass-through handler
def on_slim_text(type, content)
[:slim, :text, type, compile(content)]
end
# Pass-through handler
def on_slim_embedded(type, content, attrs)
[:slim, :embedded, type, compile(content), attrs]
end
# Pass-through handler
def on_slim_control(code, content)
[:slim, :control, code, compile(content)]
end
# Pass-through handler
def on_slim_output(escape, code, content)
[:slim, :output, escape, code, compile(content)]
end
end
end
slim-5.2.1/lib/slim/logic_less.rb 0000644 0000041 0000041 00000000251 14572524745 016712 0 ustar www-data www-data # frozen_string_literal: true
require 'slim'
require 'slim/logic_less/filter'
require 'slim/logic_less/context'
Slim::Engine.after Slim::Interpolation, Slim::LogicLess
slim-5.2.1/lib/slim/erb_converter.rb 0000644 0000041 0000041 00000000534 14572524745 017432 0 ustar www-data www-data # frozen_string_literal: true
require 'slim'
module Slim
# Slim to ERB converter
#
# @example Conversion
# Slim::ERBConverter.new(options).call(slim_code) # outputs erb_code
#
# @api public
class ERBConverter < Engine
replace :StaticMerger, Temple::Filters::CodeMerger
replace :Generator, Temple::Generators::ERB
end
end
slim-5.2.1/lib/slim/smart/ 0000755 0000041 0000041 00000000000 14572524745 015372 5 ustar www-data www-data slim-5.2.1/lib/slim/smart/filter.rb 0000644 0000041 0000041 00000006502 14572524745 017207 0 ustar www-data www-data # frozen_string_literal: true
module Slim
module Smart
# Perform newline processing in the
# expressions `[:slim, :text, type, Expression]`.
#
# @api private
class Filter < ::Slim::Filter
define_options smart_text: true,
smart_text_end_chars: '([{',
smart_text_begin_chars: ',.;:!?)]}'
def initialize(opts = {})
super
@active = @prepend = @append = false
@prepend_re = /\A#{chars_re(options[:smart_text_begin_chars])}/
@append_re = /#{chars_re(options[:smart_text_end_chars])}\Z/
end
def call(exp)
if options[:smart_text]
super
else
exp
end
end
def on_multi(*exps)
# The [:multi] blocks serve two purposes.
# On outer level, they collect the building blocks like
# tags, verbatim text, and implicit/explicit text.
# Within a text block, they collect the individual
# lines in [:slim, :interpolate, string] blocks.
#
# Our goal here is to decide when we want to prepend and
# append newlines to those individual interpolated lines.
# We basically want the text to come out as it was originally entered,
# while removing newlines next to the enclosing tags.
#
# On outer level, we choose to prepend every time, except
# right after the opening tag or after other text block.
# We also use the append flag to recognize the last expression
# before the closing tag, as we don't want to append newline there.
#
# Within text block, we prepend only before the first line unless
# the outer level tells us not to, and we append only after the last line,
# unless the outer level tells us it is the last line before the closing tag.
# Of course, this is later subject to the special begin/end characters
# which may further suppress the newline at the corresponding line boundary.
# Also note that the lines themselves are already correctly separated by newlines,
# so we don't have to worry about that at all.
block = [:multi]
prev = nil
last_exp = exps.reject { |exp| exp.first == :newline }.last unless @active && @append
exps.each do |exp|
@append = exp.equal?(last_exp)
if @active
@prepend = false if prev
else
@prepend = prev && (prev.first != :slim || prev[1] != :text)
end
block << compile(exp)
prev = exp unless exp.first == :newline
end
block
end
def on_slim_text(type, content)
@active = type != :verbatim
[:slim, :text, type, compile(content)]
ensure
@active = false
end
def on_slim_text_inline(content)
# Inline text is not wrapped in multi block, so set it up as if it was.
@prepend = false
@append = true
on_slim_text(:inline, content)
end
def on_slim_interpolate(string)
if @active
string = "\n" + string if @prepend && string !~ @prepend_re
string += "\n" if @append && string !~ @append_re
end
[:slim, :interpolate, string]
end
private
def chars_re(string)
Regexp.union(string.split(//))
end
end
end
end
slim-5.2.1/lib/slim/smart/escaper.rb 0000644 0000041 0000041 00000002012 14572524745 017334 0 ustar www-data www-data # frozen_string_literal: true
module Slim
module Smart
# Perform smart entity escaping in the
# expressions `[:slim, :text, type, Expression]`.
#
# @api private
class Escaper < ::Slim::Filter
define_options smart_text_escaping: true
def call(exp)
if options[:smart_text_escaping]
super
else
exp
end
end
def on_slim_text(type, content)
[:escape, type != :verbatim, [:slim, :text, type, compile(content)]]
end
def on_static(string)
# Prevent obvious &foo; and Ӓ and ÿ entities from escaping.
block = [:multi]
until string.empty?
case string
when /\A&([a-z][a-z0-9]*|#x[0-9a-f]+|#\d+);/i
# Entity.
block << [:escape, false, [:static, $&]]
string = $'
when /\A&?[^&]*/
# Other text.
block << [:static, $&]
string = $'
end
end
block
end
end
end
end
slim-5.2.1/lib/slim/smart/parser.rb 0000644 0000041 0000041 00000002444 14572524745 017217 0 ustar www-data www-data # frozen_string_literal: true
module Slim
module Smart
# @api private
class Parser < ::Slim::Parser
define_options implicit_text: true
def initialize(opts = {})
super
word_re = options[:implicit_text] ? '[_a-z0-9]' : '\p{Word}'
attr_keys = Regexp.union(@attr_shortcut.keys.sort_by { |k| -k.size })
@attr_shortcut_re = /\A(#{attr_keys}+)((?:\p{Word}|-)*)/
tag_keys = Regexp.union((@tag_shortcut.keys - @attr_shortcut.keys).sort_by { |k| -k.size })
@tag_re = /\A(?:#{attr_keys}(?=-*\p{Word})|#{tag_keys}|\*(?=[^\s]+)|(#{word_re}(?:#{word_re}|:|-)*#{word_re}|#{word_re}+))/
end
def unknown_line_indicator
if @line =~ /\A>( ?)/
# Found explicit text block.
@stacks.last << [:slim, :text, :explicit, parse_text_block($', @indents.last + $1.size + 1)]
else
unless options[:implicit_text]
syntax_error! 'Illegal shortcut' if @line =~ @attr_shortcut_re
super
end
# Found implicit smart text block.
if line = @lines.first
indent = (line =~ /\A\s*\Z/ ? @indents.last + 1 : get_indent(line))
end
@stacks.last << [:slim, :text, :implicit, parse_text_block(@line, indent)]
end
end
end
end
end
slim-5.2.1/lib/slim/grammar.rb 0000644 0000041 0000041 00000001244 14572524745 016220 0 ustar www-data www-data # frozen_string_literal: true
module Slim
# Slim expression grammar
# @api private
module Grammar
extend Temple::Grammar
TextTypes << :verbatim | :explicit | :implicit | :inline
Expression <<
[:slim, :control, String, Expression] |
[:slim, :output, Bool, String, Expression] |
[:slim, :interpolate, String] |
[:slim, :embedded, String, Expression, HTMLAttrGroup] |
[:slim, :text, TextTypes, Expression] |
[:slim, :attrvalue, Bool, String]
HTMLAttr <<
[:slim, :splat, String]
HTMLAttrGroup <<
[:html, :attrs, 'HTMLAttr*']
end
end
slim-5.2.1/lib/slim/interpolation.rb 0000644 0000041 0000041 00000002151 14572524745 017457 0 ustar www-data www-data # frozen_string_literal: true
module Slim
# Perform interpolation of #{var_name} in the
# expressions `[:slim, :interpolate, string]`.
#
# @api private
class Interpolation < Filter
# Handle interpolate expression `[:slim, :interpolate, string]`
#
# @param [String] string Static interpolate
# @return [Array] Compiled temple expression
def on_slim_interpolate(string)
# Interpolate variables in text (#{variable}).
# Split the text into multiple dynamic and static parts.
block = [:multi]
begin
case string
when /\A\\#\{/
# Escaped interpolation
block << [:static, '#{']
string = $'
when /\A#\{((?>[^{}]|(\{(?>[^{}]|\g<1>)*\}))*)\}/
# Interpolation
string, code = $', $1
escape = code !~ /\A\{.*\}\Z/
block << [:slim, :output, escape, escape ? code : code[1..-2], [:multi]]
when /\A([#\\]?[^#\\]*([#\\][^\\#\{][^#\\]*)*)/
# Static text
block << [:static, $&]
string = $'
end
end until string.empty?
block
end
end
end
slim-5.2.1/lib/slim/translator.rb 0000644 0000041 0000041 00000005655 14572524745 016775 0 ustar www-data www-data # frozen_string_literal: true
require 'slim'
module Slim
# @api private
class Translator < Filter
define_options :tr,
tr_mode: :dynamic,
tr_fn: '_'
if defined?(::I18n)
set_options tr_fn: '::Slim::Translator.i18n_text',
tr: true
elsif defined?(::GetText)
set_options tr_fn: '::GetText._',
tr: true
elsif defined?(::FastGettext)
set_options tr_fn: '::FastGettext::Translation._',
tr: true
end
def self.i18n_text(text)
I18n.t!(text)
rescue I18n::MissingTranslationData
text
end
def self.i18n_key(text)
key = text.parameterize.underscore
I18n.t!(key)
rescue I18n::MissingTranslationData
text
end
def call(exp)
options[:tr] ? super : exp
end
def initialize(opts = {})
super
case options[:tr_mode]
when :static
@translator = StaticTranslator.new(tr_fn: options[:tr_fn])
when :dynamic
@translator = DynamicTranslator.new(tr_fn: options[:tr_fn])
else
raise ArgumentError, "Invalid translator mode #{options[:tr_mode].inspect}"
end
end
def on_slim_text(type, exp)
[:slim, :text, type, @translator.call(exp)]
end
private
class StaticTranslator < Filter
define_options :tr_fn
def initialize(opts = {})
super
@translate = eval("proc {|string| #{options[:tr_fn]}(string) }")
end
def call(exp)
@text, @captures = ''.dup, []
result = compile(exp)
text = @translate.call(@text)
while text =~ /%(\d+)/
result << [:static, $`] << @captures[$1.to_i - 1]
text = $'
end
result << [:static, text]
end
def on_static(text)
@text << text
[:multi]
end
def on_slim_output(escape, code, content)
@captures << [:slim, :output, escape, code, content]
@text << "%#{@captures.size}"
[:multi]
end
end
class DynamicTranslator < Filter
define_options :tr_fn
def call(exp)
@captures_count, @captures_var, @text = 0, unique_name, ''.dup
result = compile(exp)
if @captures_count > 0
result.insert(1, [:code, "#{@captures_var}=[]"])
result << [:slim, :output, false, "#{options[:tr_fn]}(#{@text.inspect}).gsub(/%(\\d+)/) { #{@captures_var}[$1.to_i-1] }", [:multi]]
else
result << [:slim, :output, false, "#{options[:tr_fn]}(#{@text.inspect})", [:multi]]
end
end
def on_static(text)
@text << text
[:multi]
end
def on_slim_output(escape, code, content)
@captures_count += 1
@text << "%#{@captures_count}"
[:capture, "#{@captures_var}[#{@captures_count - 1}]", [:slim, :output, escape, code, content]]
end
end
end
end
Slim::Engine.before Slim::EndInserter, Slim::Translator
slim-5.2.1/lib/slim/command.rb 0000644 0000041 0000041 00000006277 14572524745 016223 0 ustar www-data www-data # frozen_string_literal: true
require 'slim'
require 'optparse'
module Slim
Engine.set_options pretty: false
# Slim commandline interface
# @api private
class Command
def initialize(args)
@args = args
@options = {}
end
# Run command
def run
@opts = OptionParser.new(&method(:set_opts))
@opts.parse!(@args)
process
end
private
# Configure OptionParser
def set_opts(opts)
opts.on('-s', '--stdin', 'Read input from standard input instead of an input file') do
@options[:input] = $stdin
end
opts.on('--trace', 'Show a full traceback on error') do
@options[:trace] = true
end
opts.on('-c', '--compile', 'Compile only but do not run') do
@options[:compile] = true
end
opts.on('-e', '--erb', 'Convert to ERB') do
@options[:erb] = true
end
opts.on('--rails', 'Generate rails compatible code (Implies --compile)') do
Engine.set_options disable_capture: true, generator: Temple::Generators::RailsOutputBuffer
@options[:compile] = true
end
opts.on('-r', '--require library', 'Load library or plugin with -r slim/plugin') do |lib|
require lib.strip
end
opts.on('-p', '--pretty', 'Produce pretty html') do
Engine.set_options pretty: true
end
opts.on('-o', '--option name=code', String, 'Set slim option') do |str|
parts = str.split('=', 2)
Engine.options[parts.first.gsub(/\A:/, '').to_sym] = eval(parts.last)
end
opts.on('-l', '--locals Hash|YAML|JSON', String, 'Set local variables') do |locals|
@options[:locals] =
if locals =~ /\A\s*\{\s*\p{Word}+:/
eval(locals)
else
require 'yaml'
YAML.load(locals)
end
end
opts.on_tail('-h', '--help', 'Show this message') do
puts opts
exit
end
opts.on_tail('-v', '--version', 'Print version') do
puts "Slim #{VERSION}"
exit
end
end
# Process command
def process
args = @args.dup
unless @options[:input]
file = args.shift
if file
@options[:file] = file
@options[:input] = File.open(file, 'r')
else
@options[:file] = 'STDIN'
@options[:input] = $stdin
end
end
locals = @options.delete(:locals) || {}
result =
if @options[:erb]
require 'slim/erb_converter'
ERBConverter.new(file: @options[:file]).call(@options[:input].read)
elsif @options[:compile]
Engine.new(file: @options[:file]).call(@options[:input].read)
else
Template.new(@options[:file]) { @options[:input].read }.render(nil, locals)
end
rescue Exception => ex
raise ex if @options[:trace] || SystemExit === ex
$stderr.print "#{ex.class}: " if ex.class != RuntimeError
$stderr.puts ex.message
$stderr.puts ' Use --trace for backtrace.'
exit 1
else
unless @options[:output]
file = args.shift
@options[:output] = file ? File.open(file, 'w') : $stdout
end
@options[:output].puts(result)
exit 0
end
end
end
slim-5.2.1/lib/slim/smart.rb 0000644 0000041 0000041 00000000463 14572524745 015722 0 ustar www-data www-data # frozen_string_literal: true
require 'slim'
require 'slim/smart/filter'
require 'slim/smart/escaper'
require 'slim/smart/parser'
Slim::Engine.replace Slim::Parser, Slim::Smart::Parser
Slim::Engine.after Slim::Smart::Parser, Slim::Smart::Filter
Slim::Engine.after Slim::Interpolation, Slim::Smart::Escaper
slim-5.2.1/lib/slim/logic_less/ 0000755 0000041 0000041 00000000000 14572524745 016367 5 ustar www-data www-data slim-5.2.1/lib/slim/logic_less/filter.rb 0000644 0000041 0000041 00000004327 14572524745 020207 0 ustar www-data www-data # frozen_string_literal: true
module Slim
# Handle logic less mode
# This filter can be activated with the option "logic_less"
# @api private
class LogicLess < Filter
# Default dictionary access order, change it with the option :dictionary_access
DEFAULT_ACCESS_ORDER = [:symbol, :string, :method, :instance_variable].freeze
define_options logic_less: true,
dictionary: 'self',
dictionary_access: DEFAULT_ACCESS_ORDER
def initialize(opts = {})
super
access = [options[:dictionary_access]].flatten.compact
access.each do |type|
raise ArgumentError, "Invalid dictionary access #{type.inspect}" unless DEFAULT_ACCESS_ORDER.include?(type)
end
raise ArgumentError, 'Option dictionary access is missing' if access.empty?
@access = access.inspect
end
def call(exp)
if options[:logic_less]
@context = unique_name
[:multi,
[:code, "#{@context} = ::Slim::LogicLess::Context.new(#{options[:dictionary]}, #{@access})"],
super]
else
exp
end
end
# Interpret control blocks as sections or inverted sections
def on_slim_control(name, content)
method =
if name =~ /\A!\s*(.*)/
name = $1
'inverted_section'
else
'section'
end
[:block, "#{@context}.#{method}(#{name.to_sym.inspect}) do", compile(content)]
end
def on_slim_output(escape, name, content)
[:slim, :output, escape, empty_exp?(content) ? access(name) :
"#{@context}.lambda(#{name.to_sym.inspect}) do", compile(content)]
end
def on_slim_attrvalue(escape, value)
[:slim, :attrvalue, escape, access(value)]
end
def on_slim_splat(code)
[:slim, :splat, access(code)]
end
def on_dynamic(code)
raise Temple::FilterError, 'Embedded code is forbidden in logic less mode'
end
def on_code(code)
raise Temple::FilterError, 'Embedded code is forbidden in logic less mode'
end
private
def access(name)
case name
when 'yield'
'yield'
when 'self'
"#{@context}.to_s"
else
"#{@context}[#{name.to_sym.inspect}]"
end
end
end
end
slim-5.2.1/lib/slim/logic_less/context.rb 0000644 0000041 0000041 00000006026 14572524745 020404 0 ustar www-data www-data # frozen_string_literal: true
module Slim
class LogicLess
# @api private
class Context
def initialize(dict, lookup)
@scope = [Scope.new(dict, lookup)]
end
def [](name)
scope[name]
end
def lambda(name)
scope.lambda(name) do |*dict|
if dict.empty?
yield
else
new_scope do
dict.inject(''.dup) do |result, d|
scope.dict = d
result << yield
end
end
end
end
end
def section(name)
if dict = scope[name]
if !dict.respond_to?(:has_key?) && dict.respond_to?(:each)
new_scope do
dict.each do |d|
scope.dict = d
yield
end
end
else
new_scope(dict) { yield }
end
end
end
def inverted_section(name)
value = scope[name]
yield if !value || (value.respond_to?(:empty?) && value.empty?)
end
def to_s
scope.to_s
end
private
class Scope
attr_reader :lookup
attr_writer :dict
def initialize(dict, lookup, parent = nil)
@dict, @lookup, @parent = dict, lookup, parent
end
def lambda(name, &block)
@lookup.each do |lookup|
case lookup
when :method
return @dict.public_send(name, &block) if @dict.respond_to?(name, false)
when :symbol
return @dict[name].call(&block) if has_key?(name)
when :string
return @dict[name.to_s].call(&block) if has_key?(name.to_s)
when :instance_variable
var_name = "@#{name}"
return @dict.instance_variable_get(var_name).call(&block) if instance_variable?(var_name)
end
end
@parent.lambda(name, &block) if @parent
end
def [](name)
@lookup.each do |lookup|
case lookup
when :method
return @dict.public_send(name) if @dict.respond_to?(name, false)
when :symbol
return @dict[name] if has_key?(name)
when :string
return @dict[name.to_s] if has_key?(name.to_s)
when :instance_variable
var_name = "@#{name}"
return @dict.instance_variable_get(var_name) if instance_variable?(var_name)
end
end
@parent[name] if @parent
end
def to_s
@dict.to_s
end
private
def has_key?(name)
@dict.respond_to?(:has_key?) && @dict.has_key?(name)
end
def instance_variable?(name)
@dict.instance_variable_defined?(name)
rescue NameError
false
end
end
def scope
@scope.last
end
def new_scope(dict = nil)
@scope << Scope.new(dict, scope.lookup, scope)
yield
ensure
@scope.pop
end
end
end
end
slim-5.2.1/lib/slim/version.rb 0000644 0000041 0000041 00000000152 14572524745 016254 0 ustar www-data www-data # frozen_string_literal: true
module Slim
# Slim version string
# @api public
VERSION = '5.2.1'
end
slim-5.2.1/lib/slim/end_inserter.rb 0000644 0000041 0000041 00000003674 14572524745 017264 0 ustar www-data www-data # frozen_string_literal: true
module Slim
# In Slim you don't need to close any blocks:
#
# - if Slim.awesome?
# | But of course it is!
#
# However, the parser is not smart enough (and that's a good thing) to
# automatically insert end's where they are needed. Luckily, this filter
# does *exactly* that (and it does it well!)
#
# @api private
class EndInserter < Filter
IF_RE = /\A(if|begin|unless|else|elsif|when|in|rescue|ensure)\b|\bdo\s*(\|[^\|]*\|)?\s*$/
ELSE_RE = /\A(else|elsif|when|in|rescue|ensure)\b/
END_RE = /\Aend\b/
# Handle multi expression `[:multi, *exps]`
#
# @return [Array] Corrected Temple expression with ends inserted
def on_multi(*exps)
result = [:multi]
# This variable is true if the previous line was
# (1) a control code and (2) contained indented content.
prev_indent = false
exps.each do |exp|
if control?(exp)
raise(Temple::FilterError, 'Explicit end statements are forbidden') if exp[2] =~ END_RE
# Two control code in a row. If this one is *not*
# an else block, we should close the previous one.
append_end(result) if prev_indent && exp[2] !~ ELSE_RE
# Indent if the control code starts a block.
prev_indent = exp[2] =~ IF_RE
elsif exp[0] != :newline && prev_indent
# This is *not* a control code, so we should close the previous one.
# Ignores newlines because they will be inserted after each line.
append_end(result)
prev_indent = false
end
result << compile(exp)
end
# The last line can be a control code too.
prev_indent ? append_end(result) : result
end
private
# Appends an end
def append_end(result)
result << [:code, 'end']
end
# Checks if an expression is a Slim control code
def control?(exp)
exp[0] == :slim && exp[1] == :control
end
end
end
slim-5.2.1/lib/slim/template.rb 0000644 0000041 0000041 00000000257 14572524745 016410 0 ustar www-data www-data # frozen_string_literal: true
module Slim
# Tilt template implementation for Slim
# @api public
Template = Temple::Templates::Tilt(Slim::Engine, register_as: :slim)
end
slim-5.2.1/lib/slim/railtie.rb 0000644 0000041 0000041 00000001754 14572524745 016231 0 ustar www-data www-data # frozen_string_literal: true
module Slim
class Railtie < ::Rails::Railtie
initializer 'initialize slim template handler' do
ActiveSupport.on_load(:action_view) do
Slim::RailsTemplate = Temple::Templates::Rails(Slim::Engine,
register_as: :slim,
# Use rails-specific generator. This is necessary
# to support block capturing and streaming.
generator: Temple::Generators::RailsOutputBuffer,
# Disable the internal slim capturing.
# Rails takes care of the capturing by itself.
disable_capture: true,
streaming: true)
end
end
end
end
slim-5.2.1/lib/slim/parser.rb 0000644 0000041 0000041 00000041751 14572524745 016075 0 ustar www-data www-data # frozen_string_literal: true
module Slim
# Parses Slim code and transforms it to a Temple expression
# @api private
class Parser < Temple::Parser
define_options :file,
:default_tag,
tabsize: 4,
code_attr_delims: {
'(' => ')',
'[' => ']',
'{' => '}',
},
attr_list_delims: {
'(' => ')',
'[' => ']',
'{' => '}',
},
shortcut: {
'#' => { attr: 'id' },
'.' => { attr: 'class' }
},
splat_prefix: '*'
class SyntaxError < StandardError
attr_reader :error, :file, :line, :lineno, :column
def initialize(error, file, line, lineno, column)
@error = error
@file = file || '(__TEMPLATE__)'
@line = line.to_s
@lineno = lineno
@column = column
end
def to_s
line = @line.lstrip
column = @column + line.size - @line.size
%{#{error}
#{file}, Line #{lineno}, Column #{@column}
#{line}
#{' ' * column}^
}
end
end
def initialize(opts = {})
super
@attr_list_delims = options[:attr_list_delims]
@code_attr_delims = options[:code_attr_delims]
tabsize = options[:tabsize]
if tabsize > 1
@tab_re = /\G((?: {#{tabsize}})*) {0,#{tabsize - 1}}\t/
@tab = '\1' + ' ' * tabsize
else
@tab_re = "\t"
@tab = ' '
end
@tag_shortcut, @attr_shortcut, @additional_attrs = {}, {}, {}
options[:shortcut].each do |k,v|
raise ArgumentError, 'Shortcut requires :tag and/or :attr' unless (v[:attr] || v[:tag]) && (v.keys - [:attr, :tag, :additional_attrs]).empty?
@tag_shortcut[k] = v[:tag] || options[:default_tag]
if v.include?(:attr) || v.include?(:additional_attrs)
raise ArgumentError, 'You can only use special characters for attribute shortcuts' if k =~ /(\p{Word}|-)/
end
if v.include?(:attr)
@attr_shortcut[k] = v[:attr].is_a?(Proc) ? v[:attr] : [v[:attr]].flatten
end
if v.include?(:additional_attrs)
@additional_attrs[k] = v[:additional_attrs]
end
end
keys = Regexp.union @attr_shortcut.keys.sort_by { |k| -k.size }
@attr_shortcut_re = /\A(#{keys}+)((?:\p{Word}|-|\/\d+|:(\w|-)+)*)/
keys = Regexp.union @tag_shortcut.keys.sort_by { |k| -k.size }
@tag_re = /\A(?:#{keys}|\*(?=[^\s]+)|(\p{Word}(?:\p{Word}|:|-)*\p{Word}|\p{Word}+))/
keys = Regexp.escape @code_attr_delims.keys.join
@code_attr_delims_re = /\A[#{keys}]/
keys = Regexp.escape @attr_list_delims.keys.join
@attr_list_delims_re = /\A\s*([#{keys}])/
@embedded_re = /\A(#{Regexp.union(Embedded.engines.keys.map(&:to_s))})(?:\s*(?:(.*)))?:(\s*)/
keys = Regexp.escape ('"\'>='.split(//) + @attr_list_delims.flatten + @code_attr_delims.flatten).uniq.join
@attr_name = "\\A\\s*([^\\0\\s#{keys}]+)"
@quoted_attr_re = /#{@attr_name}\s*=(=?)\s*("|')/
@code_attr_re = /#{@attr_name}\s*=(=?)\s*/
splat_prefix = Regexp.escape(options[:splat_prefix])
splat_regexp_source = '\A\s*' + splat_prefix + '(?=[^\s]+)'
@splat_attrs_regexp = Regexp.new(splat_regexp_source)
end
# Compile string to Temple expression
#
# @param [String] str Slim code
# @return [Array] Temple expression representing the code
def call(str)
result = [:multi]
reset(str.split(/\r?\n/), [result])
parse_line while next_line
reset
result
end
protected
def reset(lines = nil, stacks = nil)
# Since you can indent however you like in Slim, we need to keep a list
# of how deeply indented you are. For instance, in a template like this:
#
# doctype # 0 spaces
# html # 0 spaces
# head # 1 space
# title # 4 spaces
#
# indents will then contain [0, 1, 4] (when it's processing the last line.)
#
# We uses this information to figure out how many steps we must "jump"
# out when we see an de-indented line.
@indents = []
# Whenever we want to output something, we'll *always* output it to the
# last stack in this array. So when there's a line that expects
# indentation, we simply push a new stack onto this array. When it
# processes the next line, the content will then be outputted into that
# stack.
@stacks = stacks
@lineno = 0
@lines = lines
@line = @orig_line = nil
end
def next_line
if @lines.empty?
@orig_line = @line = nil
else
@orig_line = @lines.shift
@lineno += 1
@line = @orig_line.dup
end
end
def get_indent(line)
# Figure out the indentation. Kinda ugly/slow way to support tabs,
# but remember that this is only done at parsing time.
line[/\A[ \t]*/].gsub(@tab_re, @tab).size
end
def parse_line
if @line =~ /\A\s*\Z/
@stacks.last << [:newline]
return
end
indent = get_indent(@line)
# Choose first indentation yourself
@indents << indent if @indents.empty?
# Remove the indentation
@line.lstrip!
# If there's more stacks than indents, it means that the previous
# line is expecting this line to be indented.
expecting_indentation = @stacks.size > @indents.size
if indent > @indents.last
# This line was actually indented, so we'll have to check if it was
# supposed to be indented or not.
syntax_error!('Unexpected indentation') unless expecting_indentation
@indents << indent
else
# This line was *not* indented more than the line before,
# so we'll just forget about the stack that the previous line pushed.
@stacks.pop if expecting_indentation
# This line was deindented.
# Now we're have to go through the all the indents and figure out
# how many levels we've deindented.
while indent < @indents.last && @indents.size > 1
@indents.pop
@stacks.pop
end
# This line's indentation happens to lie "between" two other line's
# indentation:
#
# hello
# world
# this # <- This should not be possible!
syntax_error!('Malformed indentation') if indent != @indents.last
end
parse_line_indicators
end
def parse_line_indicators
case @line
when /\A\/!( ?)/
# HTML comment
@stacks.last << [:html, :comment, [:slim, :text, :verbatim, parse_text_block($', @indents.last + $1.size + 2)]]
when /\A\/\[\s*(.*?)\s*\]\s*\Z/
# HTML conditional comment
block = [:multi]
@stacks.last << [:html, :condcomment, $1, block]
@stacks << block
when /\A\//
# Slim comment
parse_comment_block
when /\A([\|'])([<>]{1,2}(?: |\z)| ?)/
# Found verbatim text block.
leading_ws = $2.include?('<'.freeze)
trailing_ws = ($1 == "'") || $2.include?('>'.freeze)
@stacks.last << [:static, ' '] if leading_ws
@stacks.last << [:slim, :text, :verbatim, parse_text_block($', @indents.last + $2.count(' ') + 1)]
@stacks.last << [:static, ' '] if trailing_ws
when /\A
# Inline html
block = [:multi]
@stacks.last << [:multi, [:slim, :interpolate, @line], block]
@stacks << block
when /\A-/
# Found a code block.
# We expect the line to be broken or the next line to be indented.
@line.slice!(0)
block = [:multi]
@stacks.last << [:slim, :control, parse_broken_line, block]
@stacks << block
when /\A=(=?)([<>]*)/
# Found an output block.
# We expect the line to be broken or the next line to be indented.
@line = $'
leading_ws = $2.include?('<'.freeze)
trailing_ws = $2.include?('>'.freeze)
block = [:multi]
@stacks.last << [:static, ' '] if leading_ws
@stacks.last << [:slim, :output, $1.empty?, parse_broken_line, block]
@stacks.last << [:static, ' '] if trailing_ws
@stacks << block
when @embedded_re
# Embedded template detected. It is treated as block.
@line = $2
attrs = parse_attributes
@stacks.last << [:slim, :embedded, $1, parse_text_block($', @orig_line.size - $'.size + $2.size), attrs]
when /\Adoctype\b/
# Found doctype declaration
@stacks.last << [:html, :doctype, $'.strip]
when @tag_re
# Found a HTML tag.
@line = $' if $1
parse_tag($&)
else
unknown_line_indicator
end
@stacks.last << [:newline]
end
# Unknown line indicator found. Overwrite this method if
# you want to add line indicators to the Slim parser.
# The default implementation throws a syntax error.
def unknown_line_indicator
syntax_error! 'Unknown line indicator'
end
def parse_comment_block
while !@lines.empty? && (@lines.first =~ /\A\s*\Z/ || get_indent(@lines.first) > @indents.last)
next_line
@stacks.last << [:newline]
end
end
def parse_text_block(first_line = nil, text_indent = nil)
result = [:multi]
if !first_line || first_line.empty?
text_indent = nil
else
result << [:slim, :interpolate, first_line]
end
empty_lines = 0
until @lines.empty?
if @lines.first =~ /\A\s*\Z/
next_line
result << [:newline]
empty_lines += 1 if text_indent
else
indent = get_indent(@lines.first)
break if indent <= @indents.last
if empty_lines > 0
result << [:slim, :interpolate, "\n" * empty_lines]
empty_lines = 0
end
next_line
@line.lstrip!
# The text block lines must be at least indented
# as deep as the first line.
offset = text_indent ? indent - text_indent : 0
if offset < 0
text_indent += offset
offset = 0
end
result << [:newline] << [:slim, :interpolate, (text_indent ? "\n" : '') + (' ' * offset) + @line]
# The indentation of first line of the text block
# determines the text base indentation.
text_indent ||= indent
end
end
result
end
def parse_broken_line
broken_line = @line.strip
while broken_line =~ /[,\\]\Z/
expect_next_line
broken_line << "\n" << @line
end
broken_line
end
def parse_tag(tag)
if @tag_shortcut[tag]
@line.slice!(0, tag.size) unless @attr_shortcut[tag]
tag = @tag_shortcut[tag]
end
# Find any shortcut attributes
attributes = [:html, :attrs]
while @line =~ @attr_shortcut_re
# The class/id attribute is :static instead of :slim :interpolate,
# because we don't want text interpolation in .class or #id shortcut
syntax_error!('Illegal shortcut') unless shortcut = @attr_shortcut[$1]
if shortcut.is_a?(Proc)
shortcut.call($2).each { |a, v| attributes << [:html, :attr, a, [:static, v]] }
else
shortcut.each {|a| attributes << [:html, :attr, a, [:static, $2]] }
end
if additional_attr_pairs = @additional_attrs[$1]
additional_attr_pairs.each do |k,v|
attributes << [:html, :attr, k.to_s, [:static, v]]
end
end
@line = $'
end
@line =~ /\A[<>']*/
@line = $'
trailing_ws = $&.include?('>'.freeze)
leading_ws = $&.include?('<'.freeze)
parse_attributes(attributes)
tag = [:html, :tag, tag, attributes]
@stacks.last << [:static, ' '] if leading_ws
@stacks.last << tag
@stacks.last << [:static, ' '] if trailing_ws
case @line
when /\A\s*:\s*/
# Block expansion
@line = $'
if @line =~ @embedded_re
# Parse attributes
@line = $2
attrs = parse_attributes
tag << [:slim, :embedded, $1, parse_text_block($', @orig_line.size - $'.size + $2.size), attrs]
else
(@line =~ @tag_re) || syntax_error!('Expected tag')
@line = $' if $1
content = [:multi]
tag << content
i = @stacks.size
@stacks << content
parse_tag($&)
@stacks.delete_at(i)
end
when /\A\s*=(=?)(['<>]*)/
# Handle output code
@line = $'
trailing_ws2 = $2.include?('>'.freeze)
block = [:multi]
@stacks.last.insert(-2, [:static, ' ']) if !leading_ws && $2.include?('<'.freeze)
tag << [:slim, :output, $1 != '=', parse_broken_line, block]
@stacks.last << [:static, ' '] if !trailing_ws && trailing_ws2
@stacks << block
when /\A\s*\/\s*/
# Closed tag. Do nothing
@line = $'
syntax_error!('Unexpected text after closed tag') unless @line.empty?
when /\A\s*\Z/
# Empty content
content = [:multi]
tag << content
@stacks << content
when /\A ?/
# Text content
tag << [:slim, :text, :inline, parse_text_block($', @orig_line.size - $'.size)]
end
end
def parse_attributes(attributes = [:html, :attrs])
# Check to see if there is a delimiter right after the tag name
delimiter = nil
if @line =~ @attr_list_delims_re
delimiter = @attr_list_delims[$1]
@line = $'
end
if delimiter
boolean_attr_re = /#{@attr_name}(?=(\s|#{Regexp.escape delimiter}|\Z))/
end_re = /\A\s*#{Regexp.escape delimiter}/
end
while true
case @line
when @splat_attrs_regexp
# Splat attribute
@line = $'
attributes << [:slim, :splat, parse_ruby_code(delimiter)]
when @quoted_attr_re
# Value is quoted (static)
@line = $'
attributes << [:html, :attr, $1,
[:escape, $2.empty?, [:slim, :interpolate, parse_quoted_attribute($3)]]]
when @code_attr_re
# Value is ruby code
@line = $'
name = $1
escape = $2.empty?
value = parse_ruby_code(delimiter)
syntax_error!('Invalid empty attribute') if value.empty?
attributes << [:html, :attr, name, [:slim, :attrvalue, escape, value]]
else
break unless delimiter
case @line
when boolean_attr_re
# Boolean attribute
@line = $'
attributes << [:html, :attr, $1, [:multi]]
when end_re
# Find ending delimiter
@line = $'
break
else
# Found something where an attribute should be
@line.lstrip!
syntax_error!('Expected attribute') unless @line.empty?
# Attributes span multiple lines
@stacks.last << [:newline]
syntax_error!("Expected closing delimiter #{delimiter}") if @lines.empty?
next_line
end
end
end
attributes || [:html, :attrs]
end
def parse_ruby_code(outer_delimiter)
code, count, delimiter, close_delimiter = ''.dup, 0, nil, nil
# Attribute ends with space or attribute delimiter
end_re = /\A[\s#{Regexp.escape outer_delimiter.to_s}]/
until @line.empty? || (count == 0 && @line =~ end_re)
if @line =~ /\A[,\\]\Z/
code << @line << "\n"
expect_next_line
else
if count > 0
if @line[0] == delimiter[0]
count += 1
elsif @line[0] == close_delimiter[0]
count -= 1
end
elsif @line =~ @code_attr_delims_re
count = 1
delimiter, close_delimiter = $&, @code_attr_delims[$&]
end
code << @line.slice!(0)
end
end
syntax_error!("Expected closing delimiter #{close_delimiter}") if count != 0
code
end
def parse_quoted_attribute(quote)
value, count = ''.dup, 0
until count == 0 && @line[0] == quote[0]
if @line =~ /\A(\\)?\Z/
value << ($1 ? ' ' : "\n")
expect_next_line
else
if @line[0] == '{'
count += 1
elsif @line[0] == '}'
count -= 1
end
value << @line.slice!(0)
end
end
@line.slice!(0)
value
end
# Helper for raising exceptions
def syntax_error!(message)
raise SyntaxError.new(message, options[:file], @orig_line, @lineno,
@orig_line && @line ? @orig_line.size - @line.size : 0)
rescue SyntaxError => ex
# HACK: Manipulate stacktrace for Rails and other frameworks
# to find the right file.
ex.backtrace.unshift "#{options[:file]}:#{@lineno}"
raise
end
def expect_next_line
next_line || syntax_error!('Unexpected end of file')
@line.strip!
end
end
end
slim-5.2.1/lib/slim/controls.rb 0000644 0000041 0000041 00000004042 14572524745 016434 0 ustar www-data www-data # frozen_string_literal: true
module Slim
# @api private
class Controls < Filter
define_options :disable_capture
IF_RE = /\A(if|unless)\b|\bdo\s*(\|[^\|]*\|)?\s*$/
# Handle control expression `[:slim, :control, code, content]`
#
# @param [String] code Ruby code
# @param [Array] content Temple expression
# @return [Array] Compiled temple expression
def on_slim_control(code, content)
[:multi,
[:code, code],
compile(content)]
end
# Handle output expression `[:slim, :output, escape, code, content]`
#
# @param [Boolean] escape Escape html
# @param [String] code Ruby code
# @param [Array] content Temple expression
# @return [Array] Compiled temple expression
def on_slim_output(escape, code, content)
if code =~ IF_RE
tmp = unique_name
[:multi,
# Capture the result of the code in a variable. We can't do
# `[:dynamic, code]` because it's probably not a complete
# expression (which is a requirement for Temple).
[:block, "#{tmp} = #{code}",
# Capture the content of a block in a separate buffer. This means
# that `yield` will not output the content to the current buffer,
# but rather return the output.
#
# The capturing can be disabled with the option :disable_capture.
# Output code in the block writes directly to the output buffer then.
# Rails handles this by replacing the output buffer for helpers.
options[:disable_capture] ? compile(content) : [:capture, unique_name, compile(content)]],
# Output the content.
[:escape, escape, [:dynamic, tmp]]]
else
[:multi, [:escape, escape, [:dynamic, code]], content]
end
end
# Handle text expression `[:slim, :text, type, content]`
#
# @param [Symbol] type Text type
# @param [Array] content Temple expression
# @return [Array] Compiled temple expression
def on_slim_text(type, content)
compile(content)
end
end
end
slim-5.2.1/lib/slim/include.rb 0000644 0000041 0000041 00000003437 14572524745 016223 0 ustar www-data www-data # frozen_string_literal: true
require 'slim'
module Slim
# Handles inlined includes
#
# Slim files are compiled, non-Slim files are included as text with `#{interpolation}`
#
# @api private
class Include < Slim::Filter
define_options :file, include_dirs: [Dir.pwd, '.']
def on_html_tag(tag, attributes, content = nil)
return super if tag != 'include'
name = content.to_a.flatten.select {|s| String === s }.join
raise ArgumentError, 'Invalid include statement' unless attributes == [:html, :attrs] && !name.empty?
unless file = find_file(name)
name = "#{name}.slim" if name !~ /\.slim\Z/i
file = find_file(name)
end
raise Temple::FilterError, "'#{name}' not found in #{options[:include_dirs].join(':')}" unless file
content = File.read(file)
if file =~ /\.slim\Z/i
Thread.current[:slim_include_engine].call(content)
else
[:slim, :interpolate, content]
end
end
protected
def find_file(name)
current_dir = File.dirname(File.expand_path(options[:file]))
options[:include_dirs].map {|dir| File.expand_path(File.join(dir, name), current_dir) }.find {|file| File.file?(file) }
end
end
class Engine
after Slim::Parser, Slim::Include
after Slim::Include, :stop do |exp|
throw :stop, exp if Thread.current[:slim_include_level] > 1
exp
end
# @api private
alias call_without_include call
# @api private
def call(input)
Thread.current[:slim_include_engine] = self
Thread.current[:slim_include_level] ||= 0
Thread.current[:slim_include_level] += 1
catch(:stop) { call_without_include(input) }
ensure
Thread.current[:slim_include_engine] = nil if (Thread.current[:slim_include_level] -= 1) == 0
end
end
end
slim-5.2.1/test/ 0000755 0000041 0000041 00000000000 14572524745 013511 5 ustar www-data www-data slim-5.2.1/test/sinatra/ 0000755 0000041 0000041 00000000000 14572524745 015152 5 ustar www-data www-data slim-5.2.1/test/sinatra/views/ 0000755 0000041 0000041 00000000000 14572524745 016307 5 ustar www-data www-data slim-5.2.1/test/sinatra/views/layout2.slim 0000644 0000041 0000041 00000000035 14572524745 020572 0 ustar www-data www-data h1 Slim Layout!
p
== yield
slim-5.2.1/test/sinatra/views/hello.slim 0000644 0000041 0000041 00000000023 14572524745 020273 0 ustar www-data www-data h1 Hello From Slim
slim-5.2.1/test/sinatra/views/embed_include_js.slim 0000644 0000041 0000041 00000000222 14572524745 022444 0 ustar www-data www-data doctype html
html
head
title Slim Examples
javascript:
alert('Slim supports embedded javascript!')
body
include footer.slim
slim-5.2.1/test/sinatra/views/embed_js.slim 0000644 0000041 0000041 00000000333 14572524745 020744 0 ustar www-data www-data doctype html
html
head
title Slim Examples
javascript:
alert('Slim supports embedded javascript!')
body
h1 Markup examples
#content
p This example shows you how a basic Slim file looks.
slim-5.2.1/test/sinatra/views/footer.slim 0000644 0000041 0000041 00000000014 14572524745 020466 0 ustar www-data www-data footer Slim
slim-5.2.1/test/sinatra/contest.rb 0000644 0000041 0000041 00000006245 14572524745 017165 0 ustar www-data www-data # Copyright (c) 2009 Damian Janowski and Michel Martens for Citrusbyte
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
require "rubygems"
require "minitest/autorun"
# Contest adds +teardown+, +test+ and +context+ as class methods, and the
# instance methods +setup+ and +teardown+ now iterate on the corresponding
# blocks. Note that all setup and teardown blocks must be defined with the
# block syntax. Adding setup or teardown instance methods defeats the purpose
# of this library.
class Minitest::Test
def self.setup(&block) setup_blocks << block end
def self.teardown(&block) teardown_blocks << block end
def self.setup_blocks() @setup_blocks ||= [] end
def self.teardown_blocks() @teardown_blocks ||= [] end
def setup_blocks(base = self.class)
setup_blocks base.superclass if base.superclass.respond_to? :setup_blocks
base.setup_blocks.each do |block|
instance_eval(&block)
end
end
def teardown_blocks(base = self.class)
teardown_blocks base.superclass if base.superclass.respond_to? :teardown_blocks
base.teardown_blocks.each do |block|
instance_eval(&block)
end
end
alias setup setup_blocks
alias teardown teardown_blocks
def self.context(*name, &block)
subclass = Class.new(self)
remove_tests(subclass)
subclass.class_eval(&block) if block_given?
const_set(context_name(name.join(" ")), subclass)
end
def self.test(name, &block)
define_method(test_name(name), &block)
end
class << self
alias_method :should, :test
alias_method :describe, :context
end
private
def self.context_name(name)
# "Test#{sanitize_name(name).gsub(/(^| )(\w)/) { $2.upcase }}".to_sym
name = "Test#{sanitize_name(name).gsub(/(^| )(\w)/) { $2.upcase }}"
name.tr(" ", "_").to_sym
end
def self.test_name(name)
name = "test_#{sanitize_name(name).gsub(/\s+/,'_')}_0"
name = name.succ while method_defined? name
name.to_sym
end
def self.sanitize_name(name)
# name.gsub(/\W+/, ' ').strip
name.gsub(/\W+/, ' ')
end
def self.remove_tests(subclass)
subclass.public_instance_methods.grep(/^test_/).each do |meth|
subclass.send(:undef_method, meth.to_sym)
end
end
end
slim-5.2.1/test/sinatra/helper.rb 0000644 0000041 0000041 00000006330 14572524745 016760 0 ustar www-data www-data if ENV['COVERAGE']
require 'simplecov'
SimpleCov.start do
add_filter '/test/'
add_group 'sinatra-contrib', 'sinatra-contrib'
add_group 'rack-protection', 'rack-protection'
end
end
ENV['APP_ENV'] = 'test'
RUBY_ENGINE = 'ruby' unless defined? RUBY_ENGINE
require 'rack'
testdir = File.dirname(__FILE__)
$LOAD_PATH.unshift testdir unless $LOAD_PATH.include?(testdir)
libdir = File.dirname(File.dirname(__FILE__)) + '/lib'
$LOAD_PATH.unshift libdir unless $LOAD_PATH.include?(libdir)
require 'minitest'
require 'contest'
require 'rack/test'
require 'sinatra'
require 'sinatra/base'
class Sinatra::Base
include Minitest::Assertions
# Allow assertions in request context
def assertions
@assertions ||= 0
end
attr_writer :assertions
end
class Rack::Builder
def include?(middleware)
@ins.any? { |m| middleware === m }
end
end
Sinatra::Base.set :environment, :test
class Minitest::Test
include Rack::Test::Methods
class << self
alias_method :it, :test
alias_method :section, :context
end
def self.example(desc = nil, &block)
@example_count = 0 unless instance_variable_defined? :@example_count
@example_count += 1
it(desc || "Example #{@example_count}", &block)
end
alias_method :response, :last_response
setup do
Sinatra::Base.set :environment, :test
end
# Sets up a Sinatra::Base subclass defined with the block
# given. Used in setup or individual spec methods to establish
# the application.
def mock_app(base=Sinatra::Base, &block)
@app = Sinatra.new(base, &block)
end
def app
Rack::Lint.new(@app)
end
def slim_app(&block)
mock_app do
set :views, File.dirname(__FILE__) + '/views'
get('/', &block)
end
get '/'
end
def body
response.body.to_s
end
def assert_body(value)
if value.respond_to? :to_str
assert_equal value.lstrip.gsub(/\s*\n\s*/, ""), body.lstrip.gsub(/\s*\n\s*/, "")
else
assert_match value, body
end
end
def assert_status(expected)
assert_equal Integer(expected), Integer(status)
end
def assert_like(a,b)
pattern = /id=['"][^"']*["']|\s+/
assert_equal a.strip.gsub(pattern, ""), b.strip.gsub(pattern, "")
end
def assert_include(str, substr)
assert str.include?(substr), "expected #{str.inspect} to include #{substr.inspect}"
end
def options(uri, params = {}, env = {}, &block)
request(uri, env.merge(:method => "OPTIONS", :params => params), &block)
end
def patch(uri, params = {}, env = {}, &block)
request(uri, env.merge(:method => "PATCH", :params => params), &block)
end
def link(uri, params = {}, env = {}, &block)
request(uri, env.merge(:method => "LINK", :params => params), &block)
end
def unlink(uri, params = {}, env = {}, &block)
request(uri, env.merge(:method => "UNLINK", :params => params), &block)
end
# Delegate other missing methods to response.
def method_missing(name, *args, &block)
if response && response.respond_to?(name)
response.send(name, *args, &block)
else
super
end
rescue Rack::Test::Error
super
end
# Do not output warnings for the duration of the block.
def silence_warnings
$VERBOSE, v = nil, $VERBOSE
yield
ensure
$VERBOSE = v
end
end
slim-5.2.1/test/sinatra/test_core.rb 0000644 0000041 0000041 00000005115 14572524745 017470 0 ustar www-data www-data require_relative 'helper.rb'
begin
class SlimTest < Minitest::Test
it 'renders inline slim strings' do
slim_app { slim "h1 Hiya\n" }
assert ok?
assert_equal "
Hiya
", body
end
it 'renders .slim files in views path' do
slim_app { slim :hello }
assert ok?
assert_equal "
Hello From Slim
", body
end
it "renders with inline layouts" do
mock_app do
layout { %(h1\n | THIS. IS. \n == yield.upcase ) }
get('/') { slim 'em Sparta' }
end
get '/'
assert ok?
assert_equal "
THIS. IS. SPARTA
", body
end
it "renders with file layouts" do
slim_app { slim('| Hello World', :layout => :layout2) }
assert ok?
assert_equal "
Slim Layout!
Hello World
", body
end
it "raises error if template not found" do
mock_app { get('/') { slim(:no_such_template) } }
assert_raises(Errno::ENOENT) { get('/') }
end
HTML4_DOCTYPE = ""
it "passes slim options to the slim engine" do
mock_app { get('/') { slim("x foo='bar'", :attr_quote => "'") }}
get '/'
assert ok?
assert_body ""
end
it "passes default slim options to the slim engine" do
mock_app do
set :slim, :attr_quote => "'"
get('/') { slim("x foo='bar'") }
end
get '/'
assert ok?
assert_body ""
end
it "merges the default slim options with the overrides and passes them to the slim engine" do
mock_app do
set :slim, :attr_quote => "'"
get('/') { slim("x foo='bar'") }
get('/other') { slim("x foo='bar'", :attr_quote => '"') }
end
get '/'
assert ok?
assert_body ""
get '/other'
assert ok?
assert_body ''
end
it "can render truly nested layouts by accepting a layout and a block with the contents" do
mock_app do
template(:main_outer_layout) { "h1 Title\n== yield" }
template(:an_inner_layout) { "h2 Subtitle\n== yield" }
template(:a_page) { "p Contents." }
get('/') do
slim :main_outer_layout, :layout => false do
slim :an_inner_layout do
slim :a_page
end
end
end
end
get '/'
assert ok?
assert_body "
Title
\n
Subtitle
\n
Contents.
\n"
end
end
rescue LoadError
warn "#{$!}: skipping slim tests"
end
slim-5.2.1/test/sinatra/test_include.rb 0000644 0000041 0000041 00000000727 14572524745 020167 0 ustar www-data www-data require 'slim/include'
require_relative 'helper.rb'
begin
class SlimTest < Minitest::Test
it 'renders .slim files includes with js embed' do
slim_app { slim :embed_include_js }
assert ok?
assert_equal "Slim Examples", body
end
end
rescue LoadError
warn "#{$!}: skipping slim tests"
end
slim-5.2.1/test/literate/ 0000755 0000041 0000041 00000000000 14572524745 015322 5 ustar www-data www-data slim-5.2.1/test/literate/run.rb 0000644 0000041 0000041 00000004636 14572524745 016464 0 ustar www-data www-data require 'temple'
class LiterateTest < Temple::Engine
class Parser < Temple::Parser
def call(lines)
stack = [[:multi]]
until lines.empty?
case lines.shift
when /\A(#+)\s*(.*)\Z/
stack.pop(stack.size - $1.size)
block = [:multi]
stack.last << [:section, $2, block]
stack << block
when /\A~{3,}\s*(\w+)\s*\Z/
lang = $1
code = []
until lines.empty?
case lines.shift
when /\A~{3,}\s*\Z/
break
when /\A.*\Z/
code << $&
end
end
stack.last << [lang.to_sym, code.join("\n")]
when /\A\s*\Z/
when /\A\s*(.*?)\s*Z/
stack.last << [:comment, $1]
end
end
stack.first
end
end
class Compiler < Temple::Filter
def call(exp)
@opts, @in_testcase = {}, false
"require 'helper'\n\n#{compile(exp)}"
end
def on_section(title, body)
old_opts = @opts.dup
raise Temple::FilterError, 'New section between slim and html block' if @in_testcase
"describe #{title.inspect} do\n #{compile(body).gsub("\n", "\n ")}\nend\n"
ensure
@opts = old_opts
end
def on_multi(*exps)
exps.map {|exp| compile(exp) }.join("\n")
end
def on_comment(text)
"#{@in_testcase ? ' ' : ''}# #{text}"
end
def on_slim(code)
raise Temple::FilterError, 'Slim block must be followed by html block' if @in_testcase
@in_testcase = true
"it 'should render' do\n slim = #{code.inspect}"
end
def on_html(code)
raise Temple::FilterError, 'Html block must be preceded by slim block' unless @in_testcase
@in_testcase = false
result = " html = #{code.inspect}\n".dup
if @opts.empty?
result << " _(render(slim)).must_equal html\nend\n"
else
result << " options = #{@opts.inspect}\n _(render(slim, options)).must_equal html\nend\n"
end
end
def on_options(code)
raise Temple::FilterError, 'Options set inside test case' if @in_testcase
@opts.update(eval("{#{code}}"))
"# #{code.gsub("\n", "\n# ")}"
end
def on(*exp)
raise Temple::InvalidExpression, exp
end
end
use Parser
use Compiler
use(:Evaluator) {|code| eval(code) }
end
Dir.glob(File.join(File.dirname(__FILE__), '*.md')) do |file|
LiterateTest.new.call(File.readlines(file))
end
slim-5.2.1/test/literate/TESTS.md 0000644 0000041 0000041 00000050555 14572524745 016560 0 ustar www-data www-data # Slim test suite
You can run this testsuite with `rake test:literate`.
We use pretty mode in the test suite to make the output more readable. Pretty mode
is enabled by setting the option
~~~ options
:pretty => true
~~~
## Line indicators
In this section we test all line indicators.
### Text `|`
A text blocks starts with the `|` as line indicator.
~~~ slim
| Text block
~~~
renders as
~~~ html
Text block
~~~
You can add leading or trailing white space with the `<` and `>` markers:
~~~ slim
|< Text with leading whitespace.
| Text with leading whitespace.
|> Text with trailing whitespace.
|<> Text with both leading and trailing whitespace.
~~~
renders as
~~~ html
Text with leading whitespace. Text with leading whitespace.Text with trailing whitespace. Text with both leading and trailing whitespace.
~~~
Multiple lines can be indented beneath the first text line.
~~~ slim
| Text
block
with
multiple
lines
~~~
renders as
~~~ html
Text
block
with
multiple
lines
~~~
The first line of a text block determines the indentation.
~~~ slim
|
Text
block
with
multiple
lines
~~~
renders as
~~~ html
Text
block
with
multiple
lines
~~~
~~~ slim
|><
Text
block
with
multiple
lines
~~~
renders as
~~~ html
Text
block
with
multiple
lines
~~~
You can nest text blocks beneath tags.
~~~ slim
body
| Text
~~~
renders as
~~~ html
Text
~~~
You can embed html code in the text which is not escaped.
~~~ slim
| github.com/slim-template/slim
~~~
renders as
~~~ html
github.com/slim-template/slim
~~~
~~~ slim
|github.com/slim-template/slim
~~~
renders as
~~~ html
github.com/slim-template/slim
~~~
### Text with trailing white space `'`
A text blocks with trailing white space starts with the `'` as line indicator.
~~~ slim
' Text block
~~~
renders as
~~~ html
Text block
~~~
This is especially useful if you use tags behind a text block.
~~~ slim
' Link to
a href="http://github.com/slim-template/slim" github.com/slim-template/slim
~~~
renders as
~~~ html
Link to github.com/slim-template/slim
~~~
Multiple lines can be indented beneath the first text line.
~~~ slim
' Text
block
with
multiple
lines
~~~
renders as
~~~ html
Text
block
with
multiple
lines
~~~
The first line of a text block determines the indentation.
~~~ slim
'
Text
block
with
multiple
lines
~~~
renders as
~~~ html
Text
block
with
multiple
lines
~~~
### Inline HTML `<`
HTML can be written directly.
~~~ slim
github.com/slim-template/slim
~~~
renders as
~~~ html
github.com/slim-template/slim
~~~
HTML tags allow nested blocks inside.
~~~ slim
title Example
body
- if true
| yes
- else
| no
~~~
renders as
~~~ html
Example
yes
~~~
### Control code `-`
The dash `-` denotes arbitrary control code.
~~~ slim
- greeting = 'Hello, World!'
- if false
| Not true
- else
= greeting
~~~
renders as
~~~ html
Hello, World!
~~~
Complex code can be broken with backslash `\`.
~~~ slim
- greeting = 'Hello, '+\
\
'World!'
- if false
| Not true
- else
= greeting
~~~
renders as
~~~ html
Hello, World!
~~~
You can also write loops like this
~~~ slim
- items = [{name: 'table', price: 10}, {name: 'chair', price: 5}]
table#items
- for item in items do
tr
td.name = item[:name]
td.price = item[:price]
~~~
which renders as
~~~ html
table
10
chair
5
~~~
The `do` keyword can be omitted.
~~~ slim
- items = [{name: 'table', price: 10}, {name: 'chair', price: 5}]
table#items
- for item in items
tr
td.name = item[:name]
td.price = item[:price]
~~~
which renders as
~~~ html
table
10
chair
5
~~~
### Output `=`
The equal sign `=` produces dynamic output.
~~~ slim
= 7*7
~~~
renders as
~~~ html
49
~~~
Dynamic output is escaped by default.
~~~ slim
= ''
~~~
renders as
~~~ html
<script>evil();</script>
~~~
Long code lines can be broken with `\`.
~~~ slim
= (0..10).map do |i|\
2**i \
end.join(', ')
~~~
renders as
~~~ html
1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024
~~~
You don't need the explicit `\` if the line ends with a comma `,`.
~~~ slim
ruby:
def self.test(*args)
args.join('-')
end
= test('arg1',
'arg2',
'arg3')
~~~
renders as
~~~ html
arg1-arg2-arg3
~~~
You can also disable HTML escaping globally by setting the option
~~~ options
:disable_escape => true
~~~
~~~ slim
= ''
~~~
renders as
~~~ html
~~~
The equal sign with modifier `=>` produces dynamic output with a trailing white space.
~~~ slim
=> 7*7
~~~
renders as
~~~ html
49
~~~
~~~ slim
=< 7*7
~~~
renders as
~~~ html
49
~~~
The equal sign with modifier `=<` produces dynamic output with a leading white space.
~~~ slim
=< 7*7
~~~
renders as
~~~ html
49
~~~
The equal sign with modifiers `=<>` produces dynamic output with a leading and trailing white space.
~~~ slim
=<> 7*7
~~~
renders as
~~~ html
49
~~~
### Output without HTML escaping `==`
The double equal sign `==` produces dynamic output without HTML escaping.
~~~ slim
== ''
~~~
renders as
~~~ html
~~~
The option option
~~~ options
:disable_escape => true
~~~
doesn't affect the output of `==`.
~~~ slim
== ''
~~~
renders as
~~~ html
~~~
The double equal sign with modifier `==>` produces dynamic output without HTML escaping and trailing white space.
~~~ slim
==> ''
~~~
renders as
~~~ html
~~~
The option option
~~~ options
:disable_escape => true
~~~
doesn't affect the output of `==`.
~~~ slim
==> ''
~~~
renders as
~~~ html
~~~
### Code comment `/`
Code comments begin with `/` and produce no output.
~~~ slim
/ Comment
body
/ Another comment
with
multiple lines
p Hello!
~~~
renders as
~~~ html
Hello!
~~~
### HTML comment `/!`
Code comments begin with `/!`.
~~~ slim
/! Comment
body
/! Another comment
with multiple lines
p Hello!
/!
First line determines indentation
of the comment
~~~
renders as
~~~ html
Hello!
~~~
### IE conditional comment `/[...]`
~~~ slim
/[if IE]
p Get a better browser.
~~~
renders as
~~~ html
~~~
## HTML tags
### Doctype tags
The doctype tag is a special tag which can be used to generate the complex doctypes in a very simple way.
You can output the XML version using the doctype tag.
~~~ slim
doctype xml
doctype xml ISO-8859-1
~~~
renders as
~~~ html
~~~
In XHTML mode the following doctypes are supported:
~~~ slim
doctype html
doctype 5
doctype 1.1
doctype strict
doctype frameset
doctype mobile
doctype basic
doctype transitional
~~~
renders as
~~~ html
~~~
If we activate HTML mode with the option
~~~ options
:format => :html
~~~
the following doctypes are supported:
~~~ slim
doctype html
doctype 5
doctype strict
doctype frameset
doctype transitional
~~~
renders as
~~~ html
~~~
### Closed tags
You can close tags explicitly by appending a trailing `/`.
~~~ slim
div id="not-closed"
.closed/
#closed/
div id="closed"/
~~~
renders as
~~~ html
~~~
Note, that this is usually not necessary since the standard html tags (img, br, ...) are closed automatically.
~~~ slim
img src="image.png"
~~~
renders as
~~~ html
~~~
### Trailing and leading whitespace
You can force a trailing whitespace behind a tag by adding `>`.
~~~ slim
a#closed> class="test" /
a#closed> class="test"/
a> href='url1' Link1
a< href='url1' Link1
~~~
renders as
~~~ html
Link1Link1
~~~
If you combine > and => only one trailing whitespace is added.
~~~ slim
a> => 'Text1'
a => 'Text2'
a> = 'Text3'
a>= 'Text4'
a=> 'Text5'
a<= 'Text6'
a=< 'Text7'
~~~
renders as
~~~ html
Text1Text2Text3Text4Text5Text6Text7
~~~
You can force a leading whitespace before a tag by adding `<`.
~~~ slim
a#closed< class="test" /
a#closed< class="test"/
a< href='url1' Link1
a< href='url2' Link2
~~~
~~~ html
Link1Link2
~~~
You can also combine both.
~~~ slim
a#closed<> class="test" /
a#closed>< class="test"/
a<> href='url1' Link1
a<> href='url2' Link2
~~~
~~~ html
Link1Link2
~~~
### Inline tags
Sometimes you may want to be a little more compact and inline the tags.
~~~ slim
ul
li.first: a href="/first" First
li: a href="/second" Second
~~~
renders as
~~~ html
~~~
For readability, don't forget you can wrap the attributes.
~~~ slim
ul
li.first: a(href="/first") First
li: a(href="/second") Second
~~~
renders as
~~~ html
~~~
### Text content
### Dynamic content `=`
### Attributes
#### Attribute wrapper
If a delimiter makes the syntax more readable for you, you can use the characters `{...}`, `(...)`, `[...]` to wrap the attributes.
~~~ slim
li
a(href="http://github.com/slim-template/slim" class="important") Link
li
a[href="http://github.com/slim-template/slim" class="important"] Link
li
a{href="http://github.com/slim-template/slim" class="important"} Link
~~~
renders as
~~~ html
~~~
If you wrap the attributes, you can spread them across multiple lines:
~~~ slim
a(href="http://github.com/slim-template/slim"
class="important") Link
~~~
renders as
~~~ html
Link
~~~
~~~ slim
dl(
itemprop='address'
itemscope
itemtype='http://schema.org/PostalAddress'
)
~~~
renders as
~~~ html
~~~
You may use spaces around the wrappers and assignments:
~~~ slim
h1 id = "logo" Logo
h2 [ id = "tagline" ] Tagline
~~~
renders as
~~~ html
Logo
Tagline
~~~
#### Quoted attributes
You can use single or double quotes for simple text attributes.
~~~ slim
a href="http://github.com/slim-template/slim" title='Slim Homepage' Goto the Slim homepage
~~~
renders as
~~~ html
Goto the Slim homepage
~~~
You can use text interpolation in the quoted attributes:
~~~ slim
- url='github.com/slim-template/slim'
a href="http://#{url}" Goto the #{url}
a href="{"test"}" Test of quoted text in braces
~~~
renders as
~~~ html
Goto the github.com/slim-template/slimTest of quoted text in braces
~~~
The attribute value will be escaped by default. Use == if you want to disable escaping in the attribute.
~~~ slim
li
a href='&' Link
li
a href=="&" Link
~~~
renders as
~~~ html
~~~
You can use newlines in quoted attributes
~~~ slim
a data-title="help" data-content="extremely long help text that goes on
and one and one and then starts over...." Link
~~~
renders as
~~~ html
Link
~~~
You can break quoted attributes with an backslash `\`
~~~ slim
a data-title="help" data-content="extremely long help text that goes on\
and one and one and then starts over...." Link
~~~
renders as
~~~ html
Link
~~~
#### Ruby attributes
Long ruby attributes can be broken with backslash `\`
~~~ slim
a href=1+\
1 Link
~~~
renders as
~~~ html
Link
~~~
You don't need the explicit `\` if the line ends with a comma `,`.
~~~ slim
ruby:
def self.test(*args)
args.join('-')
end
a href=test('arg1',
'arg2',
'arg3') Link
~~~
renders as
~~~ html
Link
~~~
#### Boolean attributes
The attribute values `true`, `false` and `nil` are interpreted as booleans.
If you use the attribut wrapper you can omit the attribute assigment.
~~~ slim
- true_value1 = ""
- true_value2 = true
input type="text" disabled=true_value1
input type="text" disabled=true_value2
input type="text" disabled="disabled"
input type="text" disabled=true
input(type="text" disabled)
~~~
renders as
~~~ html
~~~
~~~ slim
- false_value1 = false
- false_value2 = nil
input type="text" disabled=false_value1
input type="text" disabled=false_value2
input type="text"
input type="text" disabled=false
input type="text" disabled=nil
~~~
renders as
~~~ html
~~~
If html5 is activated the attributes are written as standalone.
~~~ options
:format => :html
~~~
~~~ slim
- true_value1 = ""
- true_value2 = true
input type="text" disabled=true_value1
input type="text" disabled=true_value2
input type="text" disabled="disabled"
input type="text" disabled=true
input(type="text" disabled)
~~~
renders as
~~~ html
~~~
#### Attribute merging
You can configure attributes to be merged if multiple are given (See option `:merge_attrs`). In the default configuration
this is done for class attributes with the white space as delimiter.
~~~ slim
a.menu class="highlight" href="http://github.com/slim-template/slim/" github.com/slim-template/slim
~~~
renders as
~~~ html
github.com/slim-template/slim
~~~
You can also use an `Array` as attribute value and the array elements will be merged using the delimiter.
~~~ slim
- classes = [:alpha, :beta]
span class=["first","highlight"] class=classes First
span class=:second,:highlight class=classes Second
~~~
renders as
~~~ html
FirstSecond
~~~
#### Splat attributes `*`
#### Dynamic tags `*`
You can create completely dynamic tags using the splat attributes. Just create a method which returns a hash
with the :tag key.
~~~ slim
ruby:
def self.a_unless_current
@page_current ? {tag: 'span'} : {tag: 'a', href: 'http://github.com/slim-template/slim/'}
end
- @page_current = true
*a_unless_current Link
- @page_current = false
*a_unless_current Link
~~~
renders as
~~~ html
LinkLink
~~~
### Shortcuts
#### Tag shortcuts
We add tag shortcuts by setting the option `:shortcut`.
~~~ options
:shortcut => {'c' => {tag: 'container'}, 'sec' => {tag:'section'}, '#' => {attr: 'id'}, '.' => {attr: 'class'} }
~~~
~~~ slim
sec: c.content Text
~~~
renders to
~~~ html
Text
~~~
#### Attribute shortcuts
We add `&` to create a shortcut for the input elements with type attribute by setting the option `:shortcut`.
~~~ options
:shortcut => {'&' => {tag: 'input', attr: 'type'}, '#' => {attr: 'id'}, '.' => {attr: 'class'} }
~~~
~~~ slim
&text name="user"
&password name="pw"
&submit.CLASS#ID
~~~
renders to
~~~ html
~~~
This is stupid, but you can also use multiple character shortcuts.
~~~ options
:shortcut => {'&' => {tag: 'input', attr: 'type'}, '#<' => {attr: 'id'}, '#>' => {attr: 'class'} }
~~~
~~~ slim
&text name="user"
&password name="pw"
&submit#>CLASS#
~~~
You can also set multiple attributes per shortcut.
~~~ options
:shortcut => {'.' => {attr: %w(id class)} }
~~~
~~~ slim
.test
~~~
renders to
~~~ html
~~~
Shortcuts can also have multiple characters.
~~~ options
:shortcut => {'.' => {attr: 'class'}, '#' => {attr: 'id'}, '.#' => {attr: %w(class id)} }
~~~
~~~ slim
.#test
.test
#test
~~~
renders to
~~~ html
~~~
#### ID shortcut and class shortcut `.`
ID and class shortcuts can contain dashes, slashes with digits, and colons.
~~~ slim
.-test text
#test- text
.--a#b- text
.a--test-123#--b text
.a-1/2#b-1/2 text
.ab:c-test#d:e text
~~~
renders as
~~~ html
text
text
text
text
text
text
~~~
## Text interpolation
Use standard Ruby interpolation. The text will be html escaped by default.
~~~ slim
- user="John Doe "
h1 Welcome #{user}!
~~~
renders as
~~~ html
Welcome John Doe <john@doe.net>!
~~~
## Pretty printing of XML
We can enable XML mode with
~~~ options
:format => :xml
~~~
~~~ slim
doctype xml
document
closed-element/
element(boolean-attribute)
child attribute="value"
| content
~~~
~~~ html
content
~~~
## Embedded engines
## Configuring Slim
## Plugins
slim-5.2.1/test/literate/helper.rb 0000644 0000041 0000041 00000000704 14572524745 017127 0 ustar www-data www-data require 'slim'
require 'slim/logic_less'
require 'slim/translator'
require 'slim/grammar'
require 'minitest/autorun'
Slim::Engine.after Slim::Parser, Temple::Filters::Validator, grammar: Slim::Grammar
Slim::Engine.before :Pretty, Temple::Filters::Validator
Slim::Engine.set_options tr: false, logic_less: false
class Minitest::Spec
def render(source, options = {}, &block)
Slim::Template.new(options) { source }.render(self, &block)
end
end
slim-5.2.1/test/include/ 0000755 0000041 0000041 00000000000 14572524745 015134 5 ustar www-data www-data slim-5.2.1/test/include/files/ 0000755 0000041 0000041 00000000000 14572524745 016236 5 ustar www-data www-data slim-5.2.1/test/include/files/textfile 0000644 0000041 0000041 00000000012 14572524745 017776 0 ustar www-data www-data 1+2=#{1+2} slim-5.2.1/test/include/files/subdir/ 0000755 0000041 0000041 00000000000 14572524745 017526 5 ustar www-data www-data slim-5.2.1/test/include/files/subdir/test.slim 0000644 0000041 0000041 00000000010 14572524745 021362 0 ustar www-data www-data | subdir slim-5.2.1/test/include/files/recursive.slim 0000644 0000041 0000041 00000000005 14572524745 021126 0 ustar www-data www-data | rec slim-5.2.1/test/include/files/slimfile.slim 0000644 0000041 0000041 00000000041 14572524745 020723 0 ustar www-data www-data | slim1
include recursive
| slim2 slim-5.2.1/test/include/test_include.rb 0000644 0000041 0000041 00000001140 14572524745 020137 0 ustar www-data www-data require 'helper'
require 'slim/include'
class TestSlimInclude < TestSlim
def test_include
source = %q{
br/
a: include slimfile
b: include textfile
c: include slimfile.slim
d: include subdir/test
}
assert_html ' slim1recslim21+2=3slim1recslim2subdir', source, include_dirs: [File.expand_path('files', File.dirname(__FILE__))]
end
def test_include_with_newline
source = %q{
a: include slimfile
.content
}
assert_html 'slim1recslim2', source, include_dirs: [File.expand_path('files', File.dirname(__FILE__))]
end
end
slim-5.2.1/test/smart/ 0000755 0000041 0000041 00000000000 14572524745 014637 5 ustar www-data www-data slim-5.2.1/test/smart/test_smart_text.rb 0000644 0000041 0000041 00000007766 14572524745 020435 0 ustar www-data www-data require 'helper'
require 'slim/smart'
class TestSlimSmartText < TestSlim
def test_explicit_smart_text_recognition
source = %q{
>
a
>
b
>
c
>
d
> e
f
> g
h
i
}
result = %q{a
b
c
d
e
g
h
}
assert_html result, source
end
def test_implicit_smart_text_recognition
source = %q{
p
A
p
B
p
C
p
D
p E
F
p G
H
I
}
result = %q{
A
B
C
D
E
F
G
H
I}
assert_html result, source
end
def test_multi_line_smart_text
source = %q{
p
First line.
Second line.
Third line
with a continuation
and one more.
Fourth line.
}
result = %q{
First line.
Second line.
Third line
with a continuation
and one more.
Fourth line.
}
assert_html result, source
end
def test_smart_text_mixed_with_tags
source = %q{
p
Text
br
>is
strong really
> recognized.
More
b text
.
And
i more
...
span Really
?!?
.bold Really
!!!
#id
#{'Good'}
!
}
result = %q{
Text
is
really
recognized.
More
text.
And
more...
Really?!?
Really
!!!
Good
!}
assert_html result, source
end
def test_smart_text_mixed_with_links
source = %q{
p
Text with
a href="#1" link
.
Text with
a href="#2" another
link
> to somewhere else.
a href="#3"
This link
> goes
elsewhere.
See (
a href="#4" link
)?
}
result = %q{
}
assert_html result, source
end
def test_smart_text_mixed_with_code
source = %q{
p
Try a list
ul
- 2.times do |i|
li
Item: #{i}
> which stops
b here
. Right?
}
result = %q{
Try a list
Item: 0
Item: 1
which stops
here. Right?}
assert_html result, source
end
# Without unicode support, we can't distinguish uppercase and lowercase
# unicode characters reliably. So we only test the basic text, not tag names.
def test_basic_unicode_smart_text
source = %q{
p
是
čip
Čip
Žůžo
šíp
}
result = %q{
是
čip
Čip
Žůžo
šíp
}
assert_html result, source
end
def test_unicode_smart_text
source = %q{
p
是
čip
Čip
Žůžo
šíp
.řek
.
}
result = %q{
是
čip
Čip
Žůžo
šíp
.
}
assert_html result, source
end
end
slim-5.2.1/test/logic_less/ 0000755 0000041 0000041 00000000000 14572524745 015634 5 ustar www-data www-data slim-5.2.1/test/logic_less/test_logic_less.rb 0000644 0000041 0000041 00000015304 14572524745 021346 0 ustar www-data www-data require 'helper'
require 'slim/logic_less'
class TestSlimLogicLess < TestSlim
class Scope
def initialize
@hash = {
person: [
{ name: 'Joe', age: 1, selected: true },
{ name: 'Jack', age: 2 }
]
}
end
end
def test_lambda
source = %q{
p
== person
.name = name
== simple
.hello= hello
== list
li = key
}
hash = {
hello: 'Hello!',
person: lambda do |&block|
%w(Joe Jack).map do |name|
"#{block.call(name: name)}"
end.join
end,
simple: lambda do |&block|
"
#{block.call}
"
end,
list: lambda do |&block|
list = [{key: 'First'}, {key: 'Second'}]
"
#{block.call(*list)}
"
end
}
assert_html '
Joe
Jack
Hello!
First
Second
', source, scope: hash
end
def test_symbol_hash
source = %q{
p
- person
.name = name
}
hash = {
person: [
{ name: 'Joe', },
{ name: 'Jack', }
]
}
assert_html '
Joe
Jack
', source, scope: hash
end
def test_string_access
source = %q{
p
- person
.name = name
}
hash = {
'person' => [
{ 'name' => 'Joe', },
{ 'name' => 'Jack', }
]
}
assert_html '
Joe
Jack
', source, scope: hash, dictionary_access: :string
end
def test_symbol_access
source = %q{
p
- person
.name = name
}
hash = {
person: [
{ name: 'Joe', },
{ name: 'Jack', }
]
}
assert_html '
Joe
Jack
', source, scope: hash, dictionary_access: :symbol
end
def test_method_access
source = %q{
p
- person
.name = name
}
object = Object.new
def object.person
%w(Joe Jack).map do |name|
person = Object.new
person.instance_variable_set(:@name, name)
def person.name
@name
end
person
end
end
assert_html '
Joe
Jack
', source, scope: object, dictionary_access: :method
end
def test_method_access_without_private
source = %q{
p
- person
.age = age
}
object = Object.new
def object.person
person = Object.new
def person.age
42
end
person.singleton_class.class_eval { private :age }
person
end
assert_html '', source, scope: object, dictionary_access: :method
end
def test_instance_variable_access
source = %q{
p
- person
.name = name
}
object = Object.new
object.instance_variable_set(:@person, %w(Joe Jack).map do |name|
person = Object.new
person.instance_variable_set(:@name, name)
person
end)
assert_html '
Joe
Jack
', source, scope: object, dictionary_access: :instance_variable
end
def test_to_s_access
source = %q{
p
- people
.name = self
}
hash = {
people: [
'Joe',
'Jack'
]
}
assert_html '
Joe
Jack
', source, scope: hash, dictionary_access: :symbol
end
def test_string_hash
source = %q{
p
- person
.name = name
}
hash = {
'person' => [
{ 'name' => 'Joe', },
{ 'name' => 'Jack', }
]
}
assert_html '
Joe
Jack
', source, scope: hash
end
def test_dictionary_option
source = %q{
p
- person
.name = name
}
assert_html '
shown', source, scope: hash
end
def test_inverted_section
source = %q{
p
- person
.name = name
-! person
| No person
- !person
| No person 2
}
hash = {}
assert_html '
No person No person 2
', source, scope: hash
end
def test_escaped_interpolation
source = %q{
p text with \#{123} test
}
assert_html '
text with #{123} test
', source
end
def test_ruby_attributes
source = %q{
p
- person
b name=name Person
a id=name = age
span class=name
Person
}
assert_html '
', source, scope: {prev_page: 'prev', next_page: 'next'}
end
def test_render_with_yield
source = %q{
div
== yield
}
assert_html '
This is the menu
', source do
'This is the menu'
end
end
def test_render_parent_lambda
source = %q{
- list
== fn
p = string
}
assert_html '
str
str
str
',
source, scope: {
fn: ->(&block) { "#{block.call}" },
list: [ "item1", "item2", "item3" ],
string: "str"
}
end
end
slim-5.2.1/test/translator/ 0000755 0000041 0000041 00000000000 14572524745 015702 5 ustar www-data www-data slim-5.2.1/test/translator/test_translator.rb 0000644 0000041 0000041 00000005034 14572524745 021461 0 ustar www-data www-data require 'helper'
require 'slim/translator'
class TestSlimTranslator < TestSlim
def setup
super
Slim::Engine.set_options tr: true, tr_fn: 'TestSlimTranslator.tr'
end
def self.tr(s)
s.upcase
end
def self.tr_reverse(s)
s.reverse.gsub(/(\d+)%/, '%\1')
end
def test_no_translation_of_embedded
source = %q{
markdown:
#Header
Hello from #{"Markdown!"}
#{1+2}
* one
* two
}
case Tilt['md'].name.downcase
when /redcarpet/
assert_html "
Header
\n\n
Hello from Markdown!
\n\n
3
\n\n
\n
one
\n
two
\n
\n", source, tr_mode: :dynamic
assert_html "
Header
\n\n
Hello from Markdown!
\n\n
3
\n\n
\n
one
\n
two
\n
\n", source, tr_mode: :static
when /rdiscount/
assert_html "
Header
\n\n
Hello from Markdown!
\n\n
3
\n\n
\n
one
\n
two
\n
\n\n", source, tr_mode: :dynamic
assert_html "
Header
\n\n
Hello from Markdown!
\n\n
3
\n\n
\n
one
\n
two
\n
\n\n", source, tr_mode: :static
when /kramdown/
assert_html "
Header
\n
Hello from Markdown!
\n\n
3
\n\n
\n
one
\n
two
\n
\n", source, tr_mode: :dynamic
assert_html "
Header
\n
Hello from Markdown!
\n\n
3
\n\n
\n
one
\n
two
\n
\n", source, tr_mode: :static
else
raise "Missing test for #{Tilt['md']}"
end
end
def test_no_translation_of_attrs
source = %q{
' this is
a link to
a href="link" page
}
assert_html "THIS IS\nA LINK TO PAGE", source, tr_mode: :dynamic
assert_html "THIS IS\nA LINK TO PAGE", source, tr_mode: :static
end
def test_translation_and_interpolation
source = %q{
p translate #{hello_world} this
second line
third #{1+2} line
}
assert_html "
translate Hello World from @env this\nsecond line\nthird 3 line
", source, tr: false
assert_html "
TRANSLATE Hello World from @env THIS\nSECOND LINE\nTHIRD 3 LINE
", source, tr_mode: :dynamic
assert_html "
TRANSLATE Hello World from @env THIS\nSECOND LINE\nTHIRD 3 LINE
" unless options[:skip_layout]
assert_equal expected, @response.body
end
end
slim-5.2.1/test/rails/test/test_slim.rb 0000644 0000041 0000041 00000006050 14572524745 020133 0 ustar www-data www-data require File.expand_path('../helper', __FILE__)
class TestSlim < ActionDispatch::IntegrationTest
test "normal view" do
get "/slim/normal"
assert_response :success
assert_template "slim/normal"
assert_template "layouts/application"
assert_html "
Hello Slim!
"
end
test "variant" do
get "/slim/variant"
assert_response :success
assert_template "slim/normal"
assert_template "layouts/application"
assert_equal @response.body, "Variant
Hello Slim!
"
end
test "xml view" do
get "/slim/xml"
assert_response :success
assert_template "slim/xml"
assert_template "layouts/application"
assert_html "
Hello Slim!
"
end
test "helper" do
get "/slim/helper"
assert_response :success
assert_template "slim/helper"
assert_template "layouts/application"
assert_html "
Hello User
"
end
test "normal erb view" do
get "/slim/erb"
assert_html "
Hello Erb!
"
end
test "view without a layout" do
get "/slim/no_layout"
assert_template "slim/no_layout"
assert_html "
Hello Slim without a layout!
", skip_layout: true
end
test "view with variables" do
get "/slim/variables"
assert_html "
Hello Slim with variables!
"
end
test "partial view" do
get "/slim/partial"
assert_html "
Hello Slim!
With a partial!
"
end
# TODO Reenable streaming test
# test "streaming" do
# get "/slim/streaming"
# output = "2f\r\nDummy\r\nd\r\n\r\n17\r\nHeading set from a view\r\n15\r\n
\r\n53\r\n
Page content
Hello Streaming!
Hello Streaming!
\r\n14\r\n
\r\n0\r\n\r\n"
# assert_equal output, @response.body
# end
test "render integers" do
get "/slim/integers"
assert_html "
1337
"
end
test "render thread_options" do
get "/slim/thread_options", params: { attr: 'role'}
assert_html '
Test
'
get "/slim/thread_options", params: { attr: 'id'} # Overwriting doesn't work because of caching
assert_html '
Test
'
end
test "content_for" do
get "/slim/content_for"
assert_html "
Page content
Hello Slim!
Hello Slim!
", heading: 'Heading set from a view'
end
test "form_for" do
get "/entries/edit/1"
assert_match %r{action="/entries"}, @response.body
assert_match %r{}, @response.body
assert_xpath '//input[@id="entry_name" and @name="entry[name]" and @type="text"]'
end
test "attributes" do
get "/slim/attributes"
assert_html ""
end
test "splat" do
get "/slim/splat"
assert_html "
Hello
"
end
test "splat with delimiter" do
get "/slim/splat_with_delimiter"
assert_html "
Hello
"
end
end
slim-5.2.1/test/rails/Rakefile 0000644 0000041 0000041 00000000411 14572524745 016264 0 ustar www-data www-data # Add your own tasks in files placed in lib/tasks ending in .rake,
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
require File.expand_path('../config/application', __FILE__)
require 'rake'
Dummy::Application.load_tasks
slim-5.2.1/test/rails/config.ru 0000644 0000041 0000041 00000000233 14572524745 016436 0 ustar www-data www-data # This file is used by Rack-based servers to start the application.
require ::File.expand_path('../config/environment', __FILE__)
run Dummy::Application
slim-5.2.1/test/rails/app/ 0000755 0000041 0000041 00000000000 14572524745 015403 5 ustar www-data www-data slim-5.2.1/test/rails/app/views/ 0000755 0000041 0000041 00000000000 14572524745 016540 5 ustar www-data www-data slim-5.2.1/test/rails/app/views/layouts/ 0000755 0000041 0000041 00000000000 14572524745 020240 5 ustar www-data www-data slim-5.2.1/test/rails/app/views/layouts/application.html+testvariant.slim 0000644 0000041 0000041 00000000166 14572524745 026737 0 ustar www-data www-data doctype html
html
head
title Variant
= csrf_meta_tag
body
= yield :page_heading
.content= yield
slim-5.2.1/test/rails/app/views/layouts/application.html.slim 0000644 0000041 0000041 00000000164 14572524745 024375 0 ustar www-data www-data doctype html
html
head
title Dummy
= csrf_meta_tag
body
= yield :page_heading
.content= yield
slim-5.2.1/test/rails/app/views/entries/ 0000755 0000041 0000041 00000000000 14572524745 020211 5 ustar www-data www-data slim-5.2.1/test/rails/app/views/entries/edit.html.slim 0000644 0000041 0000041 00000000100 14572524745 022756 0 ustar www-data www-data = form_for @entry do |f|
label: b Name
= f.text_field :name
slim-5.2.1/test/rails/app/views/slim/ 0000755 0000041 0000041 00000000000 14572524745 017504 5 ustar www-data www-data slim-5.2.1/test/rails/app/views/slim/variables.html.slim 0000644 0000041 0000041 00000000012 14572524745 023276 0 ustar www-data www-data h1= @hello slim-5.2.1/test/rails/app/views/slim/partial.html.slim 0000644 0000041 0000041 00000000041 14572524745 022764 0 ustar www-data www-data h1 Hello Slim!
= render "partial" slim-5.2.1/test/rails/app/views/slim/xml.slim 0000644 0000041 0000041 00000000016 14572524745 021167 0 ustar www-data www-data h1 Hello Slim! slim-5.2.1/test/rails/app/views/slim/no_layout.html.slim 0000644 0000041 0000041 00000000037 14572524745 023346 0 ustar www-data www-data h1 Hello Slim without a layout! slim-5.2.1/test/rails/app/views/slim/splat_with_delimiter.slim 0000644 0000041 0000041 00000000034 14572524745 024603 0 ustar www-data www-data .cute *{class: "nice"} Hello slim-5.2.1/test/rails/app/views/slim/form_for.html.slim 0000644 0000041 0000041 00000000060 14572524745 023142 0 ustar www-data www-data = form_for @entry do |f|
= f.text_field :name
slim-5.2.1/test/rails/app/views/slim/thread_options.html.slim 0000644 0000041 0000041 00000000015 14572524745 024353 0 ustar www-data www-data p@empty Test
slim-5.2.1/test/rails/app/views/slim/_partial.html.slim 0000644 0000041 0000041 00000000021 14572524745 023121 0 ustar www-data www-data p With a partial! slim-5.2.1/test/rails/app/views/slim/normal.html.slim 0000644 0000041 0000041 00000000016 14572524745 022622 0 ustar www-data www-data h1 Hello Slim! slim-5.2.1/test/rails/app/views/slim/helper.html.slim 0000644 0000041 0000041 00000000053 14572524745 022612 0 ustar www-data www-data p
= headline do
' Hello
= 'User'
slim-5.2.1/test/rails/app/views/slim/erb.html.erb 0000644 0000041 0000041 00000000023 14572524745 021704 0 ustar www-data www-data