slim-5.2.1/0000755000004100000410000000000014572524745012532 5ustar www-datawww-dataslim-5.2.1/bin/0000755000004100000410000000000014572524745013302 5ustar www-datawww-dataslim-5.2.1/bin/slimrb0000755000004100000410000000016714572524745014524 0ustar www-datawww-data#!/usr/bin/env ruby $:.unshift File.dirname(__FILE__) + '/../lib' require 'slim/command' Slim::Command.new(ARGV).run slim-5.2.1/.gitignore0000644000004100000410000000020014572524745014512 0ustar www-datawww-data*.swp *.gem Gemfile.lock .bundle .redcar .rvmrc .yardoc coverage pkg test/rails/log test/rails/tmp /.ruby-gemset /.ruby-version slim-5.2.1/doc/0000755000004100000410000000000014572524745013277 5ustar www-datawww-dataslim-5.2.1/doc/include.md0000644000004100000410000000104314572524745015242 0ustar www-datawww-data# Include The include plugin allows Slim templates to include other files. The .slim extension is appended automatically to the filename. If the included file is not a Slim file, it is interpreted as a text file with `#{interpolation}`. Example: include partial.slim include partial include partial.txt Enable the include plugin with require 'slim/include' # Options | Type | Name | Default | Purpose | | ---- | ---- | ------- | ------- | | Array | :include_dirs | [Dir.pwd, '.'] | Directories where to look for the files | slim-5.2.1/doc/jp/0000755000004100000410000000000014572524745013710 5ustar www-datawww-dataslim-5.2.1/doc/jp/include.md0000644000004100000410000000133414572524745015656 0ustar www-datawww-data# インクルード インクルードプラグインを使うことで, Slim テンプレートに他の Slim ファイルを読み込むことができます。.slim 拡張子はファイル名に自動的に付加されます。 読み込まれたファイルが Slim でない場合は `#{文字列展開}` を含んだテキストファイルとして扱われます。 例: include partial.slim include partial include partial.txt インクルードプラグインを有効化 require 'slim/include' # オプション | タイプ | 名前 | デフォルト値 | 目的 | | ------ | ---- | ------------ | ---- | | Array | :include_dirs | [Dir.pwd, '.'] | ファイルを検索するディレクトリ | slim-5.2.1/doc/jp/smart.md0000644000004100000410000001041614572524745015362 0ustar www-datawww-data# スマートテキスト テキストとマークアップを組み合わせる最も簡単な方法は スマートテキストモード を使うことです。 スマートテキストプラグインを有効化します。 require 'slim/smart' 自動的に `:implicit_text` オプションが有効になることで, 次のように簡単にテキストを入力できるようになります: p This is text. 小文字のタグ名や暗黙的なテキスト行などの特殊文字で始まっていない行を Slim に自動的に処理させることができます。 テキストが複数行にわたる場合, 単にそれらをインデントします。 p This is text, and it spans several lines. `>` を使って明示的にテキストをマークすることもできます。 例えば, 小文字や特殊文字で始まっている場合, テキストが複数行にわたる場合, 単に見た目の一貫性のために, タグ名に大文字を使いたい場合, `:implicit_text` オプションを無効にしたままにする必要がある場合です。 p > 'This is text, too.' p > This is text which spans several lines. `:smart_text_escaping` が有効化されている限り, エスケープされるべきテキストは自動的にエスケープされます。 しかし, 不便にならないように検出された HTML エンティティはそのまま使われます。 この方法はいつでも HTML のエスケープを気にすることのない, 最も理想的な方法です。 h1 Questions & Answers footer Copyright © #{Time.now.year} スマートテキストの素晴らしいところの 1 つはマークアップとよくミックスしているところです。 スマートテキストの行は通常改行を維持するので, 強調やリンクのような他のタグを簡単に混ぜ合わせて使うことができます: p Your credit card strong will not > be charged now. p Check a href=r(:faq) our FAQ > for more info. (タグから小文字のテキストを区別する場合明示的なテキストを示すインジケーター `>` の使用には注意してください)。 インラインタグのまわりにスペースを入れたくない場合があります。 幸いなことにスマートテキストはこの一般的なケースを処理できます。 スマートテキストのブロックが `:smart_text_begin_chars` で指定 (デフォルトは `,.;:!?)]}`) された文字で始まる場合には先頭の改行が行われません。 同様に, スマートテキストのブロックが `:smart_text_begin_chars` で指定 (デフォルトは `,.;:!?)]}`) された文字で終わる場合には改行されません。 これによって通常のテキストとリンクや span タグを混在させることがとても容易になります: p Please proceed to a href="/" our homepage . p Status: failed ( a href="#1" details ). スマートテキストはタグのショートカットをも把握しているので, 次のような場合にも正しく対応します: .class #id #{'More'} i text ... 当然のことながら, これは短いテキストのスニペットでより便利に作業できることを意味しています。 ほとんどがテキストのコンテンツの場合, Markdown や Textile のような ビルトインの埋め込みエンジンを使う方が良いでしょう。 ## オプション | 種類 | 名前 | デフォルト | 用途 | | ---- | ---- | ---------- | ---- | | 真偽値 | :implicit_text | true | 暗黙的テキストの判別を有効化 | | 真偽値 | :smart_text | true | スマートテキストによる処理を有効化 | | 文字列 | :smart_text_begin_chars | ',.;:!?)]}' | スマートテキストで先頭の改行を抑制する文字 | | 文字列 | :smart_text_end_chars | '([{' | スマートテキストで末尾の改行を抑制する文字 | | 真偽値 | :smart_text_escaping | true | 設定すると, スマートテキスト中のエスケープが必要な HTML 文字は自動的にエスケープされる | slim-5.2.1/doc/jp/translator.md0000644000004100000410000000211714572524745016424 0ustar www-datawww-data# 翻訳/I18n 翻訳プラグインは Gettext, Fast-Gettext または Rails I18n を使ったテンプレートの自動翻訳機能を提供します。 テンプレート内の静的テキストを翻訳版に変換します。 例: h1 Welcome to #{url}! Gettext は文字列を英語からドイツ語に変換し, 文字列が展開される部分は %1, %2, ... の順に変換されます。 "Welcome to %1!" -> "Willkommen auf %1!" 次のようにレンダリングされます。

Willkommen auf github.com/slim-template/slim!

翻訳プラグインを有効化します。 require 'slim/translator' # オプション | 種類 | 名前 | デフォルト | 用途 | | ---- | ---- | ---------- | ---- | | 真偽値 | :tr | true | 翻訳の有効化 ('slim/translator' の required が必要) | | シンボル | :tr_mode | :dynamic | 翻訳を :static = コンパイル時に実施, :dynamic = ランタイムで実施 | | 文字列 | :tr_fn | インストールされた翻訳ライブラリに依存 | 翻訳用ヘルパ, gettext の場合 '_' | slim-5.2.1/doc/jp/logic_less.md0000644000004100000410000001154114572524745016357 0ustar www-datawww-data# ロジックレスモード ロジックレスモードは [Mustache](https://github.com/defunkt/mustache) にインスパイアされています。ロジックレスモードは 例えば動的コンテンツを含む再帰的ハッシュツリーのような辞書オブジェクトを使います。 ## 条件付き オブジェクトが false または empty? ではない場合, コンテンツが表示されます。 - article h1 = title ## 反転条件付き オブジェクトが false または empty? の場合, コンテンツが表示されます。 -! article p Sorry, article not found ## 繰り返し オブジェクトが配列の場合, この部分は繰り返されます。 - articles tr: td = title ## ラムダ式 Mustache のように, Slim はラムダ式をサポートします。 = person = name ラムダ式は次のように定義できます: def lambda_method "
#{yield(name: 'Andrew')}
" end 任意に 1 つ以上のハッシュを `yield` に渡すことができます。複数のハッシュを渡した場合, 先述したようにブロックが繰り返されます。 ## 辞書アクセス サンプルコード: - article h1 = title 辞書オブジェクトは `:dictionary_access` オプションによって設定された順序でアクセスされます。デフォルトの順序: 1. `シンボル` - `article.respond_to?(:has_key?)` 且つ `article.has_key?(:title)` の場合, Slim は `article[:title]` を実行します。 2. `文字列` - `article.respond_to?(:has_key?)` 且つ `article.has_key?('title')` の場合, Slim は `article['title']` を実行します。 3. `メソッド` - `article.respond_to?(:title)` の場合, Slim は `article.send(:title)` を実行します。 4. `インスタンス変数` - `article.instance_variable_defined?(@title)` の場合, Slim は `article.instance_variable_get @title` を実行します。 すべて失敗した場合, Slim は親オブジェクトに対して同じ順序で title の参照を解決しようとします。この例では, 親オブジェクトはレンダリングしているテンプレートに対する辞書オブジェクトになります。 ご想像のとおり, article への参照は辞書オブジェクトに対して同じ手順で行われます。インスタンス変数はビューのコードでは利用を許されていませんが, Slim はそれを見つけて使います。基本的には, テンプレートの中で @ プレフィックスを落として使っています。パラメータ付きメソッドの呼び出しは許可されません。 ## 文字列 `self` キーワードは検討中の要素を `.to_s` した値を返します。 辞書オブジェクトを与え, { article: [ 'Article 1', 'Article 2' ] } ビューで次のように - article tr: td = self これは次のようになります。 Article 1 Article 2 ## 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.md0000644000004100000410000001072714572524745014756 0ustar www-datawww-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.

This is in fact a verbatim text as well.

You can also mark the text explicitly with a leading `>`. This is used for example when the text starts with a lowercase letter or an unusual character, or merely for aesthetic consistency when it spans several lines. It may be also needed if you want to use uppercase tag names and therefore need to keep the `:implicit_text` option disabled. > This is an explicit text. > This is an explicit text which spans several lines. > 'This is a text, too.' > This is another way > of typing text which spans > several lines, if you prefer that. BTW, all these examples can be pasted to `slimrb -r slim/smart` to see how the generated output looks like. The plugin also improves upon Slim's automatic HTML escaping. As long as you leave the `:smart_text_escaping` enabled, any non-verbatim text (i.e., any implicit, explicit, and inline text) is automatically escaped for you. However, for your convenience, any HTML entities detected are still used verbatim. This way you are most likely to get what you really wanted, without having to worry about HTML escaping all the time. h1 Questions & Answers footer Copyright © #{Time.now.year} Another cool thing about the plugin is that it makes text mix fairly well with markup. The text lines are made to preserve newlines as needed, so it is easy to mix them with other tags, like emphasis or links: p Your credit card strong will not > be charged now. p Check a href='/faq' our FAQ > for more info. (Note the use of the explicit text indicator `>` to distinguish lowercase text from tags). However, sometimes you do not want any whitespace around the inline tag at all. Fortunately the plugin takes care of the most common cases for you as well. The newline before the tag is suppressed if the preceding line ends with a character from the `:smart_text_end_chars` set (`([{` by default). Similarly, the newline after the tag is suppressed if the following line begins with a character from the `:smart_text_begin_chars` set (`,.;:!?)]}` by default). This makes it quite easy to naturally mix normal text with links or spans like this: p Please proceed to a href="/" our homepage . p Status: failed ( a href="#1" see details ). Note that the plugin is smart enough to know about tag shortcuts, too, so it will correctly deal even with cases like this: .class #id #{'More'} i text ... And that's it. Of course, all this is meant only to make working with short text snippets more convenient. For bulk text content, you are more than welcome to use one of the builtin embedded engines, such as Markdown or Textile. ## Options | Type | Name | Default | Purpose | | ---- | ---- | ------- | ------- | | Boolean | :implicit_text | true | Enable implicit text recognition | | Boolean | :smart_text | true | Enable smart text mode newline processing | | String | :smart_text_begin_chars | ',.;:!?)]}' | Characters suppressing leading newline in smart text | | String | :smart_text_end_chars | '([{' | Characters suppressing trailing newline in smart text | | Boolean | :smart_text_escaping | true | When set, HTML characters which need escaping are automatically escaped in smart text | slim-5.2.1/doc/translator.md0000644000004100000410000000162414572524745016015 0ustar www-datawww-data# Translator/I18n The translator plugin provides automatic translation of the templates using Gettext, Fast-Gettext or Rails I18n. Static text in the template is replaced by the translated version. Example: h1 Welcome to #{url}! Gettext translates the string from english to german where interpolations are replaced by %1, %2, ... "Welcome to %1!" -> "Willkommen auf %1!" and renders as

Willkommen auf github.com/slim-template/slim!

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.md0000644000004100000410000000740614572524745015753 0ustar www-datawww-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/CHANGES0000644000004100000410000004251514572524745013534 0ustar www-datawww-data5.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/0000755000004100000410000000000014572524745014072 5ustar www-datawww-dataslim-5.2.1/.github/workflows/0000755000004100000410000000000014572524745016127 5ustar www-datawww-dataslim-5.2.1/.github/workflows/test.yml0000644000004100000410000000606514572524745017640 0ustar www-datawww-dataname: 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/0000755000004100000410000000000014572524745013300 5ustar www-datawww-dataslim-5.2.1/lib/slim.rb0000644000004100000410000000065714572524745014601 0ustar www-datawww-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/0000755000004100000410000000000014572524745014244 5ustar www-datawww-dataslim-5.2.1/lib/slim/splat/0000755000004100000410000000000014572524745015367 5ustar www-datawww-dataslim-5.2.1/lib/slim/splat/filter.rb0000644000004100000410000000601514572524745017203 0ustar www-datawww-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.rb0000644000004100000410000000707414572524745017352 0ustar www-datawww-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}" 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.rb0000644000004100000410000000217314572524745017111 0ustar www-datawww-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.rb0000644000004100000410000001544714572524745016335 0ustar www-datawww-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.rb0000644000004100000410000000414114572524745017751 0ustar www-datawww-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.rb0000644000004100000410000000276114572524745016044 0ustar www-datawww-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.rb0000644000004100000410000000146314572524745016062 0ustar www-datawww-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.rb0000644000004100000410000000025114572524745016712 0ustar www-datawww-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.rb0000644000004100000410000000053414572524745017432 0ustar www-datawww-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/0000755000004100000410000000000014572524745015372 5ustar www-datawww-dataslim-5.2.1/lib/slim/smart/filter.rb0000644000004100000410000000650214572524745017207 0ustar www-datawww-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.rb0000644000004100000410000000201214572524745017334 0ustar www-datawww-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.rb0000644000004100000410000000244414572524745017217 0ustar www-datawww-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.rb0000644000004100000410000000124414572524745016220 0ustar www-datawww-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.rb0000644000004100000410000000215114572524745017457 0ustar www-datawww-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.rb0000644000004100000410000000565514572524745016775 0ustar www-datawww-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.rb0000644000004100000410000000627714572524745016223 0ustar www-datawww-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.rb0000644000004100000410000000046314572524745015722 0ustar www-datawww-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/0000755000004100000410000000000014572524745016367 5ustar www-datawww-dataslim-5.2.1/lib/slim/logic_less/filter.rb0000644000004100000410000000432714572524745020207 0ustar www-datawww-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.rb0000644000004100000410000000602614572524745020404 0ustar www-datawww-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.rb0000644000004100000410000000015214572524745016254 0ustar www-datawww-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.rb0000644000004100000410000000367414572524745017264 0ustar www-datawww-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.rb0000644000004100000410000000025714572524745016410 0ustar www-datawww-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.rb0000644000004100000410000000175414572524745016231 0ustar www-datawww-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.rb0000644000004100000410000004175114572524745016075 0ustar www-datawww-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 ('"\'> @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]*)/ # 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.rb0000644000004100000410000000404214572524745016434 0ustar www-datawww-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.rb0000644000004100000410000000343714572524745016223 0ustar www-datawww-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/0000755000004100000410000000000014572524745013511 5ustar www-datawww-dataslim-5.2.1/test/sinatra/0000755000004100000410000000000014572524745015152 5ustar www-datawww-dataslim-5.2.1/test/sinatra/views/0000755000004100000410000000000014572524745016307 5ustar www-datawww-dataslim-5.2.1/test/sinatra/views/layout2.slim0000644000004100000410000000003514572524745020572 0ustar www-datawww-datah1 Slim Layout! p == yield slim-5.2.1/test/sinatra/views/hello.slim0000644000004100000410000000002314572524745020273 0ustar www-datawww-datah1 Hello From Slim slim-5.2.1/test/sinatra/views/embed_include_js.slim0000644000004100000410000000022214572524745022444 0ustar www-datawww-datadoctype 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.slim0000644000004100000410000000033314572524745020744 0ustar www-datawww-datadoctype 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.slim0000644000004100000410000000001414572524745020466 0ustar www-datawww-datafooter Slim slim-5.2.1/test/sinatra/contest.rb0000644000004100000410000000624514572524745017165 0ustar www-datawww-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.rb0000644000004100000410000000633014572524745016760 0ustar www-datawww-dataif 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.rb0000644000004100000410000000511514572524745017470 0ustar www-datawww-datarequire_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.rb0000644000004100000410000000072714572524745020167 0ustar www-datawww-datarequire '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/0000755000004100000410000000000014572524745015322 5ustar www-datawww-dataslim-5.2.1/test/literate/run.rb0000644000004100000410000000463614572524745016464 0ustar www-datawww-datarequire '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.md0000644000004100000410000005055514572524745016560 0ustar www-datawww-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 Link1 Link1 ~~~ 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 Text1 Text2 Text3 Text4 Text5 Text6 Text7 ~~~ 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 Link1 Link2 ~~~ You can also combine both. ~~~ slim a#closed<> class="test" / a#closed>< class="test"/ a<> href='url1' Link1 a<> href='url2' Link2 ~~~ ~~~ html Link1 Link2 ~~~ ### 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
  • Link
  • Link
  • Link
  • ~~~ 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
  • Link
  • Link
  • ~~~ 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.rb0000644000004100000410000000070414572524745017127 0ustar www-datawww-datarequire '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/0000755000004100000410000000000014572524745015134 5ustar www-datawww-dataslim-5.2.1/test/include/files/0000755000004100000410000000000014572524745016236 5ustar www-datawww-dataslim-5.2.1/test/include/files/textfile0000644000004100000410000000001214572524745017776 0ustar www-datawww-data1+2=#{1+2}slim-5.2.1/test/include/files/subdir/0000755000004100000410000000000014572524745017526 5ustar www-datawww-dataslim-5.2.1/test/include/files/subdir/test.slim0000644000004100000410000000001014572524745021362 0ustar www-datawww-data| subdirslim-5.2.1/test/include/files/recursive.slim0000644000004100000410000000000514572524745021126 0ustar www-datawww-data| recslim-5.2.1/test/include/files/slimfile.slim0000644000004100000410000000004114572524745020723 0ustar www-datawww-data| slim1 include recursive | slim2slim-5.2.1/test/include/test_include.rb0000644000004100000410000000114014572524745020137 0ustar www-datawww-datarequire '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/0000755000004100000410000000000014572524745014637 5ustar www-datawww-dataslim-5.2.1/test/smart/test_smart_text.rb0000644000004100000410000000776614572524745020435 0ustar www-datawww-datarequire '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_escaping source = %q{ | Not escaped <&>. p Escaped <&>. p Escaped <&>. > Escaped <&>. Protected & < > © Á. Protected  ÿ. Escaped &#xx; f; &9; &_; &;. } result = %q{Not escaped <&>.

    Escaped <&>.

    Escaped <&>. Escaped <&>. Protected & < > © Á. Protected  ÿ. Escaped &#xx; &#1f; &9; &_; &;.

    } assert_html result, source end def test_smart_text_disabled_escaping Slim::Engine.with_options( smart_text_escaping: false ) do source = %q{ p Not escaped <&>. | Not escaped <&>. p Not escaped <&>. > Not escaped <&>. Not escaped & < > © Á. Not escaped  ÿ. Not escaped &#xx; f; &9; &_; &;. } result = %q{

    Not escaped <&>.

    Not escaped <&>.

    Not escaped <&>. Not escaped <&>. Not escaped & < > © Á. Not escaped  ÿ. Not escaped &#xx; f; &9; &_; &;.

    } assert_html result, source end end def test_smart_text_in_tag_escaping source = %q{ p Escaped <&>. Protected & < > © Á. Protected  ÿ. Escaped &#xx; f; &9; &_; &;. } result = %q{

    Escaped <&>. Protected & < > © Á. Protected  ÿ. Escaped &#xx; &#1f; &9; &_; &;.

    } 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{

    Text with link. Text with another link to somewhere else. This link goes elsewhere. See (link)?

    } 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/0000755000004100000410000000000014572524745015634 5ustar www-datawww-dataslim-5.2.1/test/logic_less/test_logic_less.rb0000644000004100000410000001530414572524745021346 0ustar www-datawww-datarequire '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 '

    Joe
    Jack

    ', source, scope: Scope.new, dictionary: '@hash' end def test_flag_section source = %q{ p - show_person - person .name = name - show_person | shown } hash = { show_person: true, person: [ { name: 'Joe', }, { name: 'Jack', } ] } assert_html '

    Joe
    Jack
    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 '

    Person1Person2

    ', source, scope: Scope.new, dictionary: '@hash' end def test_boolean_attributes source = %q{ p - person input checked=selected = name } assert_html '

    JoeJack

    ', source, scope: Scope.new, dictionary: '@hash' end def test_sections source = %q{ p - person .name = name } assert_html '

    Joe
    Jack

    ', source, dictionary: 'ViewEnv.new' end def test_with_array source = %q{ ul - people_with_locations li = name li = city } assert_html '
    • Andy
    • Atlanta
    • Fred
    • Melbourne
    • Daniel
    • Karlsruhe
    ', source, dictionary: 'ViewEnv.new' end def test_method source = %q{ a href=output_number Link } assert_html 'Link', source, dictionary: 'ViewEnv.new' end def test_conditional_parent source = %q{ - prev_page li.previous a href=prev_page Older - next_page li.next a href=next_page Newer} 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/0000755000004100000410000000000014572524745015702 5ustar www-datawww-dataslim-5.2.1/test/translator/test_translator.rb0000644000004100000410000000503414572524745021461 0ustar www-datawww-datarequire '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

    ", source, tr_mode: :static end def test_translation_reverse source = %q{ ' alpha #{1} beta #{2} gamma #{3} } assert_html "3 ammag 2 ateb 1 ahpla ", source, tr_mode: :dynamic, tr_fn: 'TestSlimTranslator.tr_reverse' assert_html "3 ammag 2 ateb 1 ahpla ", source, tr_mode: :static, tr_fn: 'TestSlimTranslator.tr_reverse' end end slim-5.2.1/test/rails/0000755000004100000410000000000014572524745014623 5ustar www-datawww-dataslim-5.2.1/test/rails/test/0000755000004100000410000000000014572524745015602 5ustar www-datawww-dataslim-5.2.1/test/rails/test/helper.rb0000644000004100000410000000175014572524745017411 0ustar www-datawww-data# Configure Rails Envinronment ENV["RAILS_ENV"] = "test" require File.expand_path("../../config/environment.rb", __FILE__) require "rails/test_help" require "nokogiri" require 'rails-controller-testing' Rails::Controller::Testing.install Rails.backtrace_cleaner.remove_silencers! class ActionDispatch::IntegrationTest protected def assert_xpath(xpath, message="Unable to find '#{xpath}' in response body.") assert_response :success, "Response type is not :success (code 200..299)." body = @response.body assert !body.empty?, "No response body found." doc = Nokogiri::HTML(body) rescue nil assert_not_nil doc, "Cannot parse response body." assert doc.xpath(xpath).size >= 1, message end def assert_html(expected, options = {}) expected = "Dummy#{options[:heading]}
    #{expected}
    " unless options[:skip_layout] assert_equal expected, @response.body end end slim-5.2.1/test/rails/test/test_slim.rb0000644000004100000410000000605014572524745020133 0ustar www-datawww-datarequire 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/Rakefile0000644000004100000410000000041114572524745016264 0ustar www-datawww-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.ru0000644000004100000410000000023314572524745016436 0ustar www-datawww-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/0000755000004100000410000000000014572524745015403 5ustar www-datawww-dataslim-5.2.1/test/rails/app/views/0000755000004100000410000000000014572524745016540 5ustar www-datawww-dataslim-5.2.1/test/rails/app/views/layouts/0000755000004100000410000000000014572524745020240 5ustar www-datawww-dataslim-5.2.1/test/rails/app/views/layouts/application.html+testvariant.slim0000644000004100000410000000016614572524745026737 0ustar www-datawww-datadoctype 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.slim0000644000004100000410000000016414572524745024375 0ustar www-datawww-datadoctype html html head title Dummy = csrf_meta_tag body = yield :page_heading .content= yield slim-5.2.1/test/rails/app/views/entries/0000755000004100000410000000000014572524745020211 5ustar www-datawww-dataslim-5.2.1/test/rails/app/views/entries/edit.html.slim0000644000004100000410000000010014572524745022756 0ustar www-datawww-data= form_for @entry do |f| label: b Name = f.text_field :name slim-5.2.1/test/rails/app/views/slim/0000755000004100000410000000000014572524745017504 5ustar www-datawww-dataslim-5.2.1/test/rails/app/views/slim/variables.html.slim0000644000004100000410000000001214572524745023276 0ustar www-datawww-datah1= @helloslim-5.2.1/test/rails/app/views/slim/partial.html.slim0000644000004100000410000000004114572524745022764 0ustar www-datawww-datah1 Hello Slim! = render "partial"slim-5.2.1/test/rails/app/views/slim/xml.slim0000644000004100000410000000001614572524745021167 0ustar www-datawww-datah1 Hello Slim!slim-5.2.1/test/rails/app/views/slim/no_layout.html.slim0000644000004100000410000000003714572524745023346 0ustar www-datawww-datah1 Hello Slim without a layout!slim-5.2.1/test/rails/app/views/slim/splat_with_delimiter.slim0000644000004100000410000000003414572524745024603 0ustar www-datawww-data.cute *{class: "nice"} Helloslim-5.2.1/test/rails/app/views/slim/form_for.html.slim0000644000004100000410000000006014572524745023142 0ustar www-datawww-data= form_for @entry do |f| = f.text_field :name slim-5.2.1/test/rails/app/views/slim/thread_options.html.slim0000644000004100000410000000001514572524745024353 0ustar www-datawww-datap@empty Test slim-5.2.1/test/rails/app/views/slim/_partial.html.slim0000644000004100000410000000002114572524745023121 0ustar www-datawww-datap With a partial!slim-5.2.1/test/rails/app/views/slim/normal.html.slim0000644000004100000410000000001614572524745022622 0ustar www-datawww-datah1 Hello Slim!slim-5.2.1/test/rails/app/views/slim/helper.html.slim0000644000004100000410000000005314572524745022612 0ustar www-datawww-datap = headline do ' Hello = 'User' slim-5.2.1/test/rails/app/views/slim/erb.html.erb0000644000004100000410000000002314572524745021704 0ustar www-datawww-data

    Hello Erb!

    slim-5.2.1/test/rails/app/views/slim/splat.html.slim0000644000004100000410000000003714572524745022460 0ustar www-datawww-data#splat *{tag: 'splat'} Hello slim-5.2.1/test/rails/app/views/slim/integers.html.slim0000644000004100000410000000001314572524745023147 0ustar www-datawww-datap= @integerslim-5.2.1/test/rails/app/views/slim/attributes.html.slim0000644000004100000410000000024514572524745023524 0ustar www-datawww-data/ Exercises Temple `:capture` handling (used here for preparing HTML attributes) with the / Rails-specific Temple generators .static class="#{['a', 'b'].join('-')}" slim-5.2.1/test/rails/app/views/slim/content_for.html.slim0000644000004100000410000000023314572524745023653 0ustar www-datawww-datap Page content - content_for :page_heading, "Heading set from a view" - content_for :hello_slim do p= @hello h1= yield :hello_slim h2= yield :hello_slimslim-5.2.1/test/rails/app/assets/0000755000004100000410000000000014572524745016705 5ustar www-datawww-dataslim-5.2.1/test/rails/app/assets/config/0000755000004100000410000000000014572524745020152 5ustar www-datawww-dataslim-5.2.1/test/rails/app/assets/config/manifest.js0000644000004100000410000000004514572524745022315 0ustar www-datawww-data// file required by sprockets >= 4.0 slim-5.2.1/test/rails/app/models/0000755000004100000410000000000014572524745016666 5ustar www-datawww-dataslim-5.2.1/test/rails/app/models/entry.rb0000644000004100000410000000037414572524745020360 0ustar www-datawww-dataclass Entry include ActiveModel::Conversion extend ActiveModel::Naming attr_accessor :name def initialize(attributes = {}) attributes.each do |name, value| send("#{name}=", value) end end def persisted? false end end slim-5.2.1/test/rails/app/helpers/0000755000004100000410000000000014572524745017045 5ustar www-datawww-dataslim-5.2.1/test/rails/app/helpers/application_helper.rb0000644000004100000410000000014614572524745023235 0ustar www-datawww-datamodule ApplicationHelper def headline(&block) "

    #{capture(&block)}

    ".html_safe end end slim-5.2.1/test/rails/app/controllers/0000755000004100000410000000000014572524745017751 5ustar www-datawww-dataslim-5.2.1/test/rails/app/controllers/slim_controller.rb0000644000004100000410000000132114572524745023502 0ustar www-datawww-dataclass SlimController < ApplicationController def normal end def xml end def no_layout render layout: false end def variables @hello = "Hello Slim with variables!" end def partial end def streaming @hello = "Hello Streaming!" render :content_for, stream: true end def integers @integer = 1337 end def thread_options default_shortcut = {'#' => {attr: 'id'}, '.' => {attr: 'class'} } Slim::Engine.with_options(shortcut: default_shortcut.merge({'@' => { attr: params[:attr] }})) do render end end def variant request.variant = :testvariant render :normal end def content_for @hello = "Hello Slim!" end def helper end end slim-5.2.1/test/rails/app/controllers/application_controller.rb0000644000004100000410000000007114572524745025042 0ustar www-datawww-dataclass ApplicationController < ActionController::Base end slim-5.2.1/test/rails/app/controllers/entries_controller.rb0000644000004100000410000000013414572524745024210 0ustar www-datawww-dataclass EntriesController < ApplicationController def edit @entry = Entry.new end end slim-5.2.1/test/rails/config/0000755000004100000410000000000014572524745016070 5ustar www-datawww-dataslim-5.2.1/test/rails/config/locales/0000755000004100000410000000000014572524745017512 5ustar www-datawww-dataslim-5.2.1/test/rails/config/locales/en.yml0000644000004100000410000000032514572524745020637 0ustar www-datawww-data# Sample localization file for English. Add more files in this directory for other locales. # See http://github.com/svenfuchs/rails-i18n/tree/master/rails%2Flocale for starting points. en: hello: "Hello world" slim-5.2.1/test/rails/config/environments/0000755000004100000410000000000014572524745020617 5ustar www-datawww-dataslim-5.2.1/test/rails/config/environments/test.rb0000644000004100000410000000264514572524745022132 0ustar www-datawww-dataDummy::Application.configure do # Settings specified here will take precedence over those in config/application.rb # The test environment is used exclusively to run your application's # test suite. You never need to work with it otherwise. Remember that # your test database is "scratch space" for the test suite and is wiped # and recreated between test runs. Don't rely on the data there! config.cache_classes = true # Show full error reports and disable caching config.consider_all_requests_local = true config.action_controller.perform_caching = false # Raise exceptions instead of rendering exception templates config.action_dispatch.show_exceptions = false # Disable request forgery protection in test environment config.action_controller.allow_forgery_protection = false # Tell Action Mailer not to deliver emails to the real world. # The :test delivery method accumulates sent emails in the # ActionMailer::Base.deliveries array. #config.action_mailer.delivery_method = :test # Use SQL instead of Active Record's schema dumper when creating the test database. # This is necessary if your schema can't be completely dumped by the schema dumper, # like if you have constraints or database-specific column types # config.active_record.schema_format = :sql # Print deprecation notices to the stderr config.active_support.deprecation = :stderr config.eager_load = false end slim-5.2.1/test/rails/config/routes.rb0000644000004100000410000000340214572524745017735 0ustar www-datawww-dataDummy::Application.routes.draw do # The priority is based upon order of creation: # first created -> highest priority. resources :entries # Sample of regular route: # match 'products/:id' => 'catalog#view' # Keep in mind you can assign values other than :controller and :action # Sample of named route: # match 'products/:id/purchase' => 'catalog#purchase', as: :purchase # This route can be invoked with purchase_url(id: product.id) # Sample resource route (maps HTTP verbs to controller actions automatically): # resources :products # Sample resource route with options: # resources :products do # member do # get 'short' # post 'toggle' # end # # collection do # get 'sold' # end # end # Sample resource route with sub-resources: # resources :products do # resources :comments, :sales # resource :seller # end # Sample resource route with more complex sub-resources # resources :products do # resources :comments # resources :sales do # get 'recent', on: :collection # end # end # Sample resource route within a namespace: # namespace :admin do # # Directs /admin/products/* to Admin::ProductsController # # (app/controllers/admin/products_controller.rb) # resources :products # end # You can have the root of your site routed with "root" # just remember to delete public/index.html. # root to: "welcome#index" # See how all your routes lay out with "rake routes" # This is a legacy wild controller route that's not recommended for RESTful applications. # Note: This route will make all actions in every controller accessible via GET requests. get ':controller(/:action(/:id(.:format)))' end slim-5.2.1/test/rails/config/application.rb0000644000004100000410000000357714572524745020734 0ustar www-datawww-datarequire File.expand_path('../boot', __FILE__) require 'active_model/railtie' require 'action_controller/railtie' require 'action_view/railtie' #require 'active_record/railtie' #require 'action_mailer/railtie' #require 'sprockets/railtie' require 'slim' module Dummy class Application < Rails::Application # Settings in config/environments/* take precedence over those specified here. # Application configuration should go into files in config/initializers # -- all .rb files in that directory are automatically loaded. # Custom directories with classes and modules you want to be autoloadable. # config.autoload_paths += %W(#{config.root}/extras) # Only load the plugins named here, in the order given (default is alphabetical). # :all can be used as a placeholder for all plugins not explicitly named. # config.plugins = [ :exception_notification, :ssl_requirement, :all ] # Activate observers that should always be running. # config.active_record.observers = :cacher, :garbage_collector, :forum_observer # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. # config.time_zone = 'Central Time (US & Canada)' # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s] # config.i18n.default_locale = :de # JavaScript files you want as :defaults (application.js is always included). # config.action_view.javascript_expansions[:defaults] = %w(jquery rails) # Configure the default encoding used in templates for Ruby 1.9. config.encoding = "utf-8" # Configure sensitive parameters which will be filtered from the log file. config.filter_parameters += [:password] end end slim-5.2.1/test/rails/config/environment.rb0000644000004100000410000000022514572524745020760 0ustar www-datawww-data# Load the rails application require File.expand_path('../application', __FILE__) # Initialize the rails application Dummy::Application.initialize! slim-5.2.1/test/rails/config/boot.rb0000644000004100000410000000041714572524745017362 0ustar www-datawww-datarequire 'rubygems' gemfile = File.expand_path('../../../../../../Gemfile', __FILE__) if File.exist?(gemfile) ENV['BUNDLE_GEMFILE'] = gemfile require 'bundler' Bundler.setup(:default, :integration) end $:.unshift File.expand_path('../../../../../../lib', __FILE__)slim-5.2.1/test/rails/config/initializers/0000755000004100000410000000000014572524745020576 5ustar www-datawww-dataslim-5.2.1/test/rails/config/initializers/mime_types.rb0000644000004100000410000000031514572524745023275 0ustar www-datawww-data# Be sure to restart your server when you modify this file. # Add new mime types for use in respond_to blocks: # Mime::Type.register "text/richtext", :rtf # Mime::Type.register_alias "text/html", :iphone slim-5.2.1/test/rails/config/initializers/backtrace_silencers.rb0000644000004100000410000000062414572524745025113 0ustar www-datawww-data# Be sure to restart your server when you modify this file. # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ } # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code. # Rails.backtrace_cleaner.remove_silencers! slim-5.2.1/test/rails/config/initializers/inflections.rb0000644000004100000410000000057014572524745023442 0ustar www-datawww-data# Be sure to restart your server when you modify this file. # Add new inflection rules using the following format # (all these examples are active by default): # ActiveSupport::Inflector.inflections do |inflect| # inflect.plural /^(ox)$/i, '\1en' # inflect.singular /^(ox)en/i, '\1' # inflect.irregular 'person', 'people' # inflect.uncountable %w( fish sheep ) # end slim-5.2.1/test/rails/config/initializers/session_store.rb0000644000004100000410000000062714572524745024027 0ustar www-datawww-data# Be sure to restart your server when you modify this file. Dummy::Application.config.session_store :cookie_store, key: '_dummy_session' # Use the database for sessions instead of the cookie-based default, # which shouldn't be used to store highly confidential information # (create the session table with "rails generate session_migration") # Dummy::Application.config.session_store :active_record_store slim-5.2.1/test/rails/script/0000755000004100000410000000000014572524745016127 5ustar www-datawww-dataslim-5.2.1/test/rails/script/rails0000755000004100000410000000044714572524745017174 0ustar www-datawww-data#!/usr/bin/env ruby # This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application. APP_PATH = File.expand_path('../../config/application', __FILE__) require File.expand_path('../../config/boot', __FILE__) require 'rails/commands' slim-5.2.1/test/core/0000755000004100000410000000000014572524745014441 5ustar www-datawww-dataslim-5.2.1/test/core/test_parser_errors.rb0000644000004100000410000000676614572524745020734 0ustar www-datawww-datarequire 'helper' class TestParserErrors < TestSlim def test_correct_filename source = %q{ doctype 5 div Invalid } assert_syntax_error "Unexpected indentation\n test.slim, Line 3, Column 2\n div Invalid\n ^\n", source, file: 'test.slim' end def test_unexpected_indentation source = %q{ doctype 5 div Invalid } assert_syntax_error "Unexpected indentation\n (__TEMPLATE__), Line 3, Column 2\n div Invalid\n ^\n", source end def test_malformed_indentation source = %q{ p div Valid div Invalid } assert_syntax_error "Malformed indentation\n (__TEMPLATE__), Line 4, Column 1\n div Invalid\n ^\n", source end def test_malformed_indentation2 source = %q{ div Valid div Invalid } assert_syntax_error "Malformed indentation\n (__TEMPLATE__), Line 3, Column 1\n div Invalid\n ^\n", source end def test_unknown_line_indicator source = %q{ p div Valid .valid #valid ?invalid } assert_syntax_error "Unknown line indicator\n (__TEMPLATE__), Line 6, Column 2\n ?invalid\n ^\n", source end def test_expected_closing_delimiter source = %q{ p img(src="img.jpg" title={title} } assert_syntax_error "Expected closing delimiter )\n (__TEMPLATE__), Line 3, Column 33\n img(src=\"img.jpg\" title={title}\n ^\n", source end def test_missing_quote_unexpected_end source = %q{ p img(src="img.jpg } assert_syntax_error "Unexpected end of file\n (__TEMPLATE__), Line 3, Column 0\n \n ^\n", source end def test_expected_closing_attribute_delimiter source = %q{ p img src=[hash[1] + hash[2] } assert_syntax_error "Expected closing delimiter ]\n (__TEMPLATE__), Line 3, Column 28\n img src=[hash[1] + hash[2]\n ^\n", source end def test_invalid_empty_attribute source = %q{ p img{src= } } assert_syntax_error "Invalid empty attribute\n (__TEMPLATE__), Line 3, Column 11\n img{src= }\n ^\n", source end def test_invalid_empty_attribute2 source = %q{ p img{src=} } assert_syntax_error "Invalid empty attribute\n (__TEMPLATE__), Line 3, Column 10\n img{src=}\n ^\n", source end def test_invalid_empty_attribute3 source = %q{ p img src= } assert_syntax_error "Invalid empty attribute\n (__TEMPLATE__), Line 3, Column 10\n img src=\n ^\n", source end def test_missing_tag_in_block_expansion source = %{ html: body: } assert_syntax_error "Expected tag\n (__TEMPLATE__), Line 2, Column 11\n html: body:\n ^\n", source end def test_invalid_tag_in_block_expansion source = %{ html: body: /comment } assert_syntax_error "Expected tag\n (__TEMPLATE__), Line 2, Column 12\n html: body: /comment\n ^\n", source source = %{ html: body:/comment } assert_syntax_error "Expected tag\n (__TEMPLATE__), Line 2, Column 11\n html: body:/comment\n ^\n", source end def test_unexpected_text_after_closed source = %{ img / text } assert_syntax_error "Unexpected text after closed tag\n (__TEMPLATE__), Line 2, Column 6\n img / text\n ^\n", source end def test_illegal_shortcuts source = %{ .#test } assert_syntax_error "Illegal shortcut\n (__TEMPLATE__), Line 2, Column 0\n .#test\n ^\n", source source = %{ div.#test } assert_syntax_error "Illegal shortcut\n (__TEMPLATE__), Line 2, Column 3\n div.#test\n ^\n", source end end slim-5.2.1/test/core/test_embedded_engines.rb0000644000004100000410000001540714572524745021275 0ustar www-datawww-datarequire 'helper' require 'erb' class TestSlimEmbeddedEngines < TestSlim def test_render_with_markdown source = %q{ markdown: #Header Hello from #{"Markdown!"} #{1+2} [#{1}](#{"#2"}) * one * two } if ::Tilt['md'].name =~ /Redcarpet/ # redcarpet assert_html "

    Header

    \n\n

    Hello from Markdown!

    \n\n

    3

    \n\n

    1

    \n\n
      \n
    • one
    • \n
    • two
    • \n
    \n", source elsif ::Tilt['md'].name =~ /RDiscount/ # rdiscount assert_html "

    Header

    \n\n

    Hello from Markdown!

    \n\n

    3

    \n\n

    1

    \n\n
      \n
    • one
    • \n
    • two
    • \n
    \n\n", source else # kramdown, :auto_ids by default assert_html "

    Header

    \n

    Hello from Markdown!

    \n\n

    3

    \n\n

    1

    \n\n
      \n
    • one
    • \n
    • two
    • \n
    \n", source Slim::Embedded.with_options(markdown: {auto_ids: false}) do assert_html "

    Header

    \n

    Hello from Markdown!

    \n\n

    3

    \n\n

    1

    \n\n
      \n
    • one
    • \n
    • two
    • \n
    \n", source end assert_html "

    Header

    \n

    Hello from Markdown!

    \n\n

    3

    \n\n

    1

    \n\n
      \n
    • one
    • \n
    • two
    • \n
    \n", source end end def test_render_with_css source = %q{ css: h1 { color: blue } } assert_html "", source end def test_render_with_css_empty_attributes source = %q{ css []: h1 { color: blue } } assert_html "", source end def test_render_with_css_attribute source = %q{ css scoped = "true": h1 { color: blue } } assert_html "", source end def test_render_with_css_multiple_attributes source = %q{ css class="myClass" scoped = "true" : h1 { color: blue } } assert_html "", source end def test_render_with_javascript source = %q{ javascript: $(function() {}); alert('hello') p Hi } assert_html %{

    Hi

    }, source end def test_render_with_javascript_empty_attributes source = %q{ javascript (): alert('hello') } assert_html %{}, source end def test_render_with_javascript_attribute source = %q{ javascript [class = "myClass"]: alert('hello') } assert_html %{}, source end def test_render_with_javascript_multiple_attributes source = %q{ javascript { class = "myClass" id="myId" other-attribute = 'my_other_attribute' } : alert('hello') } assert_html %{}, source end def test_render_with_javascript_with_tabs source = "javascript:\n\t$(function() {});\n\talert('hello')\np Hi" assert_html "

    Hi

    ", source end def test_render_with_javascript_including_variable source = %q{ - func = "alert('hello');" javascript: $(function() { #{func} }); } assert_html %q||, source end def test_render_with_javascript_with_explicit_html_comment Slim::Engine.with_options(js_wrapper: :comment) do source = "javascript:\n\t$(function() {});\n\talert('hello')\np Hi" assert_html "

    Hi

    ", source end end def test_render_with_javascript_with_explicit_cdata_comment Slim::Engine.with_options(js_wrapper: :cdata) do source = "javascript:\n\t$(function() {});\n\talert('hello')\np Hi" assert_html "

    Hi

    ", source end end def test_render_with_javascript_with_format_xhtml_comment Slim::Engine.with_options(js_wrapper: :guess, format: :xhtml) do source = "javascript:\n\t$(function() {});\n\talert('hello')\np Hi" assert_html "

    Hi

    ", source end end def test_render_with_javascript_with_format_html_comment Slim::Engine.with_options(js_wrapper: :guess, format: :html) do source = "javascript:\n\t$(function() {});\n\talert('hello')\np Hi" assert_html "

    Hi

    ", source end end def test_render_with_ruby source = %q{ ruby: variable = 1 + 2 = variable } assert_html '3', source end def test_render_with_ruby_heredoc source = %q{ ruby: variable = <<-MSG foobar MSG = variable } assert_html "foobar\n", source end # TODO: Reactivate sass tests if false def test_render_with_scss source = %q{ scss: $color: #f00; body { color: $color; } } assert_html "", source end def test_render_with_scss_attribute source = %q{ scss [class="myClass"]: $color: #f00; body { color: $color; } } assert_html "", source end def test_render_with_sass source = %q{ sass: $color: #f00 body color: $color } assert_html "", source end def test_render_with_sass_attribute source = %q{ sass [class="myClass"]: $color: #f00 body color: $color } assert_html "", source end end def test_disabled_embedded_engine source = %{ ruby: Embedded Ruby } assert_runtime_error 'Embedded engine ruby is disabled', source, enable_engines: [:javascript] assert_runtime_error 'Embedded engine ruby is disabled', source, enable_engines: %w(javascript) source = %{ ruby: Embedded Ruby } assert_runtime_error 'Embedded engine ruby is disabled', source, enable_engines: [:javascript] assert_runtime_error 'Embedded engine ruby is disabled', source, enable_engines: %w(javascript) source = %{ ruby: Embedded Ruby } assert_runtime_error 'Embedded engine ruby is disabled', source, disable_engines: [:ruby] assert_runtime_error 'Embedded engine ruby is disabled', source, disable_engines: %w(ruby) end def test_enabled_embedded_engine source = %q{ javascript: $(function() {}); } assert_html '', source, disable_engines: [:ruby] assert_html '', source, disable_engines: %w(ruby) source = %q{ javascript: $(function() {}); } assert_html '', source, enable_engines: [:javascript] assert_html '', source, enable_engines: %w(javascript) end end slim-5.2.1/test/core/test_commands.rb0000644000004100000410000001422214572524745017627 0ustar www-datawww-datarequire 'helper' require 'open3' require 'tempfile' class TestSlimCommands < Minitest::Test # nothing complex STATIC_TEMPLATE = "p Hello World!\n" # requires a `name` variable to exist at render time DYNAMIC_TEMPLATE = "p Hello \#{name}!\n" # a more complex example LONG_TEMPLATE = "h1 Hello\np\n | World!\n small Tiny text" # exception raising example EXCEPTION_TEMPLATE = '- raise NotImplementedError' def test_option_help out, err = exec_slimrb '--help' assert err.empty? assert_match %r{Show this message}, out end def test_option_version out, err = exec_slimrb '--version' assert err.empty? assert_match %r{\ASlim #{Regexp.escape Slim::VERSION}$}, out end def test_render prepare_common_test STATIC_TEMPLATE do |out, err| assert err.empty? assert_equal "

    Hello World!

    \n", out end end # superficial test, we don't want to test Tilt/Temple def test_compile prepare_common_test STATIC_TEMPLATE, '--compile' do |out, err| assert err.empty? assert_match %r{\"

    Hello World!<\/p>\".freeze}, out end end def test_erb prepare_common_test DYNAMIC_TEMPLATE, '--erb' do |out, err| assert err.empty? assert_equal "

    Hello <%= ::Temple::Utils.escape_html((name)) %>!

    \n", out end end def test_rails prepare_common_test DYNAMIC_TEMPLATE, '--rails' do |out, err| assert err.empty? if Gem::Version.new(Temple::VERSION) >= Gem::Version.new('0.9') assert out.include? %Q{@output_buffer = output_buffer || ActionView::OutputBuffer.new;} else assert out.include? %Q{@output_buffer = ActiveSupport::SafeBuffer.new;} end assert out.include? %Q{@output_buffer.safe_concat(("

    Hello ".freeze));} assert out.include? %Q{@output_buffer.safe_concat(((::Temple::Utils.escape_html((name))).to_s));} assert out.include? %Q{@output_buffer.safe_concat(("!

    ".freeze));} end end def test_pretty prepare_common_test LONG_TEMPLATE, '--pretty' do |out, err| assert err.empty? assert_equal "

    \n Hello\n

    \n

    \n World!Tiny text\n

    \n", out end end def test_locals_json data = '{"name":"from slim"}' prepare_common_test DYNAMIC_TEMPLATE, '--locals', data do |out, err| assert err.empty? assert_equal "

    Hello from slim!

    \n", out end end def test_locals_yaml data = "name: from slim" prepare_common_test DYNAMIC_TEMPLATE, '--locals', data do |out, err| assert err.empty? assert_equal "

    Hello from slim!

    \n", out end end def test_locals_hash data = '{name:"from slim"}' prepare_common_test DYNAMIC_TEMPLATE, '--locals', data do |out, err| assert err.empty? assert_equal "

    Hello from slim!

    \n", out end end def test_require with_tempfile 'puts "Not in slim"', 'rb' do |lib| prepare_common_test STATIC_TEMPLATE, '--require', lib, stdin_file: false, file_file: false do |out, err| assert err.empty? assert_equal "Not in slim\n

    Hello World!

    \n", out end end end def test_error prepare_common_test EXCEPTION_TEMPLATE, stdin_file: false do |out, err| assert out.empty? assert_match %r{NotImplementedError: NotImplementedError}, err assert_match %r{Use --trace for backtrace}, err end end def test_trace_error prepare_common_test EXCEPTION_TEMPLATE, '--trace', stdin_file: false do |out, err| assert out.empty? assert_match %r{bin\/slimrb}, err end end private # Whether you call slimrb with a file argument or pass the slim content # via $stdin; whether you want the output written to $stdout or into # another file given as argument, the output is the same. # # This method prepares a test with this exact behaviour: # # It yields the tupel (out, err) once after the `content` was passed # in via $stdin and once it was passed as a (temporary) file argument. # # In effect, this method executes a test (given as block) 4 times: # # 1. read from $stdin, write to $stdout # 2. read from file, write to $stdout # 3. read from $stdin, write to file # 4. read from file, write to file def prepare_common_test(content, *args) options = Hash === args.last ? args.pop : {} # case 1. $stdin → $stdout unless options[:stdin_stdout] == false out, err = exec_slimrb(*args, '--stdin') do |i| i.write content end yield out, err end # case 2. file → $stdout unless options[:file_stdout] == false with_tempfile content do |in_file| out, err = exec_slimrb(*args, in_file) yield out, err end end # case 3. $stdin → file unless options[:stdin_file] == false with_tempfile content do |out_file| _, err = exec_slimrb(*args, '--stdin', out_file) do |i| i.write content end yield File.read(out_file), err end end # case 3. file → file unless options[:file_file] == false with_tempfile '' do |out_file| with_tempfile content do |in_file| _, err = exec_slimrb(*args, in_file, out_file) do |i| i.write content end yield File.read(out_file), err end end end end # Calls bin/slimrb as a subprocess. # # Yields $stdin to the caller and returns a tupel (out,err) with the # contents of $stdout and $stderr. # # (I'd like to use Minitest::Assertions#capture_subprecess_io here, # but then there's no way to insert data via $stdin.) def exec_slimrb(*args) out, err = nil, nil Open3.popen3 'ruby', 'bin/slimrb', *args do |i,o,e,t| yield i if block_given? i.close out, err = o.read, e.read end return out, err end # Creates a temporary file with the given content and yield the path # to this file. The file itself is only available inside the block and # will be deleted afterwards. def with_tempfile(content=nil, extname='slim') f = Tempfile.new ['slim', ".#{extname}"] if content f.write content f.flush # ensure content is actually saved to disk f.rewind end yield f.path ensure f.close f.unlink end end slim-5.2.1/test/core/helper.rb0000644000004100000410000000725314572524745016254 0ustar www-datawww-databegin require 'simplecov' SimpleCov.start rescue LoadError end require 'minitest/autorun' require 'slim' require 'slim/grammar' Slim::Engine.after Slim::Parser, Temple::Filters::Validator, grammar: Slim::Grammar Slim::Engine.before :Pretty, Temple::Filters::Validator class TestSlim < Minitest::Test def setup @env = Env.new end def render(source, options = {}, &block) scope = options.delete(:scope) locals = options.delete(:locals) Slim::Template.new(options[:file], options) { source }.render(scope || @env, locals, &block) end class HtmlSafeString < String def html_safe? true end def to_s self end end def with_html_safe String.send(:define_method, :html_safe?) { false } String.send(:define_method, :html_safe) { HtmlSafeString.new(self) } yield ensure String.send(:undef_method, :html_safe?) if String.method_defined?(:html_safe?) String.send(:undef_method, :html_safe) if String.method_defined?(:html_safe) end def assert_html(expected, source, options = {}, &block) assert_equal expected, render(source, options, &block) end def assert_syntax_error(message, source, options = {}) render(source, options) raise 'Syntax error expected' rescue Slim::Parser::SyntaxError => ex assert_equal message, ex.message message =~ /([^\s]+), Line (\d+)/ assert_backtrace ex, "#{$1}:#{$2}" end def assert_ruby_error(error, from, source, options = {}) render(source, options) raise 'Ruby error expected' rescue error => ex assert_backtrace(ex, from) end def assert_backtrace(ex, from) ex.backtrace[0] =~ /([^\s]+:\d+)/ assert_equal from, $1 end def assert_ruby_syntax_error(from, source, options = {}) render(source, options) raise 'Ruby syntax error expected' rescue SyntaxError => ex ex.message =~ /([^\s]+:\d+):/ assert_equal from, $1 end def assert_runtime_error(message, source, options = {}) render(source, options) raise Exception, 'Runtime error expected' rescue RuntimeError => ex assert_equal message, ex.message end end class Env attr_reader :var, :x def initialize @var = 'instance' @x = 0 end def id_helper "notice" end def hash {a: 'The letter a', b: 'The letter b'} end def show_first?(show = false) show end def define_macro(name, &block) @macro ||= {} @macro[name.to_s] = block '' end def call_macro(name, *args) @macro[name.to_s].call(*args) end def hello_world(text = "Hello World from @env", opts = {}) text = text + (opts.to_a * " ") if opts.any? if block_given? "#{text} #{yield} #{text}" else text end end def message(*args) args.join(' ') end def action_path(*args) "/action-#{args.join('-')}" end def in_keyword "starts with keyword" end def evil_method "" end def output_number 1337 end def succ_x @x = @x.succ end end class ViewEnv def output_number 1337 end def person [{name: 'Joe'}, {name: 'Jack'}] end def people %w(Andy Fred Daniel).collect{|n| Person.new(n)} end def cities %w{Atlanta Melbourne Karlsruhe} end def people_with_locations array = [] people.each_with_index do |p,i| p.location = Location.new cities[i] array << p end array end end require 'forwardable' class Person extend Forwardable attr_accessor :name def initialize(name) @name = name end def location=(location) @location = location end def_delegators :@location, :city end class Location attr_accessor :city def initialize(city) @city = city end end slim-5.2.1/test/core/test_html_structure.rb0000644000004100000410000003666414572524745021130 0ustar www-datawww-datarequire 'helper' class TestSlimHtmlStructure < TestSlim def test_simple_render # Keep the trailing space behind "body "! source = %q{ html head title Simple Test Title body p Hello World, meet Slim. } assert_html 'Simple Test Title

    Hello World, meet Slim.

    ', source end def test_relaxed_indentation_of_first_line source = %q{ p .content } assert_html "

    ", source end def test_html_tag_with_text_and_empty_line source = %q{ p Hello p World } assert_html "

    Hello

    World

    ", source end def test_html_namespaces source = %q{ html:body html:p html:id="test" Text } assert_html 'Text', source end def test_doctype source = %q{ doctype 1.1 html } assert_html '', source, format: :xhtml end def test_doctype_new_syntax source = %q{ doctype 5 html } assert_html '', source, format: :xhtml end def test_doctype_new_syntax_html5 source = %q{ doctype html html } assert_html '', source, format: :xhtml end def test_render_with_shortcut_attributes source = %q{ h1#title This is my title #notice.hello.world = hello_world } assert_html '

    This is my title

    Hello World from @env
    ', source end def test_render_with_overwritten_default_tag source = %q{ #notice.hello.world = hello_world } assert_html '
    Hello World from @env
    ', source, default_tag: 'section' end def test_render_with_custom_shortcut source = %q{ #notice.hello.world@test = hello_world @abc = hello_world } assert_html '
    Hello World from @env
    Hello World from @env
    ', source, shortcut: {'#' => {attr: 'id'}, '.' => {attr: 'class'}, '@' => {tag: 'section', attr: 'role'}} end def test_render_with_custom_array_shortcut source = %q{ #user@.admin Daniel } assert_html '
    Daniel
    ', source, shortcut: {'#' => {attr: 'id'}, '.' => {attr: 'class'}, '@' => {attr: 'role'}, '@.' => {attr: ['class', 'role']}} end def test_render_with_custom_shortcut_and_additional_attrs source = %q{ ^items == "[{'title':'item0'},{'title':'item1'},{'title':'item2'},{'title':'item3'},{'title':'item4'}]" } assert_html '', source, shortcut: {'^' => {tag: 'script', attr: 'data-binding', additional_attrs: { type: "application/json" }}} end def test_render_with_custom_lambda_shortcut begin Slim::Parser.options[:shortcut]['~'] = {attr: ->(v) {{class: "styled-#{v}", id: "id-#{v}"}}} source = %q{ ~foo Hello } assert_html '
    Hello
    ', source ensure Slim::Parser.options[:shortcut].delete('~') end end def test_render_with_custom_lambda_shortcut_and_multiple_values begin Slim::Parser.options[:shortcut]['~'] = {attr: ->(v) {{class: "styled-#{v}"}}} source = %q{ ~foo~bar Hello } assert_html '
    Hello
    ', source ensure Slim::Parser.options[:shortcut].delete('~') end end def test_render_with_custom_lambda_shortcut_and_existing_class begin Slim::Parser.options[:shortcut]['~'] = {attr: ->(v) {{class: "styled-#{v}"}}} source = %q{ ~foo.baz Hello } assert_html '
    Hello
    ', source ensure Slim::Parser.options[:shortcut].delete('~') end end def test_render_with_existing_class_and_custom_lambda_shortcut begin Slim::Parser.options[:shortcut]['~'] = {attr: ->(v) {{class: "styled-#{v}"}}} source = %q{ .baz~foo Hello } assert_html '
    Hello
    ', source ensure Slim::Parser.options[:shortcut].delete('~') end end def test_render_with_text_block source = %q{ p | Lorem ipsum dolor sit amet, consectetur adipiscing elit. } assert_html '

    Lorem ipsum dolor sit amet, consectetur adipiscing elit.

    ', source end def test_render_with_text_block_with_subsequent_markup source = %q{ p | Lorem ipsum dolor sit amet, consectetur adipiscing elit. p Some more markup } assert_html '

    Lorem ipsum dolor sit amet, consectetur adipiscing elit.

    Some more markup

    ', source end def test_render_with_text_block_with_trailing_whitespace source = %q{ ' this is a link to a href="link" page } assert_html "this is\na link to page", source end def test_nested_text source = %q{ p | This is line one. This is line two. This is line three. This is line four. p This is a new paragraph. } assert_html "

    This is line one.\n This is line two.\n This is line three.\n This is line four.

    This is a new paragraph.

    ", source end def test_nested_text_with_nested_html_one_same_line source = %q{ p | This is line one. This is line two. span.bold This is a bold line in the paragraph. | This is more content. } assert_html "

    This is line one.\n This is line two.This is a bold line in the paragraph. This is more content.

    ", source end def test_nested_text_with_nested_html_one_same_line2 source = %q{ p |This is line one. This is line two. span.bold This is a bold line in the paragraph. | This is more content. } assert_html "

    This is line one.\n This is line two.This is a bold line in the paragraph. This is more content.

    ", source end def test_nested_text_with_nested_html source = %q{ p | This is line one. This is line two. This is line three. This is line four. span.bold This is a bold line in the paragraph. | This is more content. } assert_html "

    This is line one.\n This is line two.\n This is line three.\n This is line four.This is a bold line in the paragraph. This is more content.

    ", source end def test_simple_paragraph_with_padding source = %q{ p There will be 3 spaces in front of this line. } assert_html '

    There will be 3 spaces in front of this line.

    ', source end def test_paragraph_with_nested_text source = %q{ p This is line one. This is line two. } assert_html "

    This is line one.\n This is line two.

    ", source end def test_paragraph_with_padded_nested_text source = %q{ p This is line one. This is line two. } assert_html "

    This is line one.\n This is line two.

    ", source end def test_paragraph_with_attributes_and_nested_text source = %q{ p#test class="paragraph" This is line one. This is line two. } assert_html "

    This is line one.\nThis is line two.

    ", source end def test_relaxed_text_indentation source = %q{ p | text block text line3 } assert_html "

    text block\ntext\n line3

    ", source end def test_output_code_with_leading_spaces source = %q{ p= hello_world p = hello_world p = hello_world } assert_html '

    Hello World from @env

    Hello World from @env

    Hello World from @env

    ', source end def test_single_quoted_attributes source = %q{ p class='underscored_class_name' = output_number } assert_html '

    1337

    ', source end def test_nonstandard_attributes source = %q{ p id="dashed-id" class="underscored_class_name" = output_number } assert_html '

    1337

    ', source end def test_nonstandard_shortcut_attributes source = %q{ p#dashed-id.underscored_class_name = output_number } assert_html '

    1337

    ', source end def test_dashed_attributes source = %q{ p data-info="Illudium Q-36" = output_number } assert_html '

    1337

    ', source end def test_dashed_attributes_with_shortcuts source = %q{ p#marvin.martian data-info="Illudium Q-36" = output_number } assert_html '

    1337

    ', source end def test_parens_around_attributes source = %q{ p(id="marvin" class="martian" data-info="Illudium Q-36") = output_number } assert_html '

    1337

    ', source end def test_square_brackets_around_attributes source = %q{ p[id="marvin" class="martian" data-info="Illudium Q-36"] = output_number } assert_html '

    1337

    ', source end # Regression test for bug #796 def test_square_brackets_around_attributes_multiline_with_tabs source = "div\n\tp[\n\t\tclass=\"martian\"\n\t]\n\tp Next line" assert_html '

    Next line

    ', source end def test_parens_around_attributes_with_equal_sign_snug_to_right_paren source = %q{ p(id="marvin" class="martian" data-info="Illudium Q-36")= output_number } assert_html '

    1337

    ', source end def test_default_attr_delims_option source = %q{ p= output_number } Slim::Parser.options[:attr_list_delims].each do |k,v| str = source.sub('<',k).sub('>',v) assert_html '

    1337

    ', str end end def test_custom_attr_delims_option source = %q{ p { foo="bar" } } assert_html '

    ', source assert_html '

    ', source, attr_list_delims: {'{' => '}'} assert_html '

    { foo="bar" }

    ', source, attr_list_delims: {'(' => ')', '[' => ']'} end def test_closed_tag source = %q{ closed/ } assert_html '', source, format: :xhtml end def test_custom_attr_list_delims_option source = %q{ p { foo="bar" x=(1+1) } p < x=(1+1) > Hello } assert_html '

    < x=(1+1) > Hello

    ', source assert_html '

    < x=(1+1) > Hello

    ', source, attr_list_delims: {'{' => '}'} assert_html '

    { foo="bar" x=(1+1) }

    Hello

    ', source, attr_list_delims: {'<' => '>'}, code_attr_delims: { '(' => ')' } end def test_attributs_with_parens_and_spaces source = %q{label{ for='filter' }= hello_world} assert_html '', source end def test_attributs_with_parens_and_spaces2 source = %q{label{ for='filter' } = hello_world} assert_html '', source end def test_attributs_with_multiple_spaces source = %q{label for='filter' class="test" = hello_world} assert_html '', source end def test_closed_tag_with_attributes source = %q{ closed id="test" / } assert_html '', source, format: :xhtml end def test_closed_tag_with_attributes_and_parens source = %q{ closed(id="test")/ } assert_html '', source, format: :xhtml end def test_render_with_html_comments source = %q{ p Hello /! This is a comment Another comment p World } assert_html "

    Hello

    World

    ", source end def test_render_with_html_conditional_and_tag source = %q{ /[ if IE ] p Get a better browser. } assert_html "", source end def test_render_with_html_conditional_and_method_output source = %q{ /[ if IE ] = message 'hello' } assert_html "", source end def test_multiline_attributes_with_method source = %q{ p = output_number } Slim::Parser.options[:attr_list_delims].each do |k,v| str = source.sub('<',k).sub('>',v) assert_html '

    1337

    ', str end end def test_multiline_attributes_with_text_on_same_line source = %q{ p THE space modulator } Slim::Parser.options[:attr_list_delims].each do |k,v| str = source.sub('<',k).sub('>',v) assert_html '

    THE space modulator

    ', str end end def test_multiline_attributes_with_nested_text source = %q{ p | THE space modulator } Slim::Parser.options[:attr_list_delims].each do |k,v| str = source.sub('<',k).sub('>',v) assert_html '

    THE space modulator

    ', str end end def test_multiline_attributes_with_dynamic_attr source = %q{ p | THE space modulator } Slim::Parser.options[:attr_list_delims].each do |k,v| str = source.sub('<',k).sub('>',v) assert_html '

    THE space modulator

    ', str end end def test_multiline_attributes_with_nested_tag source = %q{ p span.emphasis THE | space modulator } Slim::Parser.options[:attr_list_delims].each do |k,v| str = source.sub('<',k).sub('>',v) assert_html '

    THE space modulator

    ', str end end def test_multiline_attributes_with_nested_text_and_extra_indentation source = %q{ li< id="myid" class="myclass" data-info="myinfo"> a href="link" My Link } Slim::Parser.options[:attr_list_delims].each do |k,v| str = source.sub('<',k).sub('>',v) assert_html '
  • My Link
  • ', str end end def test_block_expansion_support source = %q{ ul li.first: a href='a' foo li: a href='b' bar li.last: a href='c' baz } assert_html %{}, source end def test_block_expansion_class_attributes source = %q{ .a: .b: #c d } assert_html %{
    d
    }, source end def test_block_expansion_nesting source = %q{ html: body: .content | Text } assert_html %{
    Text
    }, source end def test_eval_attributes_once source = %q{ input[value=succ_x] input[value=succ_x] } assert_html %{}, source end def test_html_line_indicator source = %q{ head meta name="keywords" content=hello_world - if true

    #{hello_world}

    span = hello_world } assert_html '

    Hello World from @env

    Hello World from @env', source end end slim-5.2.1/test/core/test_splat_prefix_option.rb0000644000004100000410000000730214572524745022117 0ustar www-datawww-datarequire 'helper' class TestSplatPrefixOption < TestSlim def prefixes ['*','**','*!','*%','*^','*$'] end def options(prefix) { splat_prefix: prefix } end def test_splat_without_content prefixes.each do |prefix| source = %Q{ #{prefix}hash p#{prefix}hash } assert_html '

    ', source, options(prefix) end end def test_shortcut_splat prefixes.each do |prefix| source = %Q{ #{prefix}hash This is my title } assert_html '
    This is my title
    ', source, options(prefix) end end def test_splat prefixes.each do |prefix| source = %Q{ h1 #{prefix}hash class=[] This is my title } assert_html '

    This is my title

    ', source, options(prefix) end end def test_closed_splat prefixes.each do |prefix| source = %Q{ #{prefix}hash / } assert_html '
    ', source, options(prefix) end end def test_splat_tag_name prefixes.each do |prefix| source = %Q{ #{prefix}{tag: 'h1', id: 'title'} This is my title } assert_html '

    This is my title

    ', source, options(prefix) end end def test_splat_empty_tag_name prefixes.each do |prefix| source = %Q{ #{prefix}{tag: '', id: 'test'} This is my title } assert_html '
    This is my title
    ', source, options(prefix) end end def test_closed_splat_tag prefixes.each do |prefix| source = %Q{ #{prefix}hash / } assert_html '
    ', source, options(prefix) end end def test_splat_with_id_shortcut prefixes.each do |prefix| source = %Q{ #myid#{prefix}hash This is my title } assert_html '
    This is my title
    ', source, options(prefix) end end def test_splat_with_class_shortcut prefixes.each do |prefix| source = %Q{ .myclass#{prefix}hash This is my title } assert_html '
    This is my title
    ', source, options(prefix) end end def test_splat_with_id_and_class_shortcuts prefixes.each do |prefix| source = %Q{ #myid.myclass#{prefix}hash This is my title } assert_html '
    This is my title
    ', source, options(prefix) end end def test_splat_with_class_merging prefixes.each do |prefix| source = %Q{ #myid.myclass #{prefix}{class: [:secondclass, %w(x y z)]} #{prefix}hash This is my title } assert_html '
    This is my title
    ', source, options(prefix) end end def test_splat_with_boolean_attribute prefixes.each do |prefix| source = %Q{ #{prefix}{disabled: true, empty1: false, nonempty: '', empty2: nil} This is my title } assert_html '
    This is my title
    ', source, options(prefix) end end def test_splat_merging_with_arrays prefixes.each do |prefix| source = %Q{ #{prefix}{a: 1, b: 2} #{prefix}[[:c, 3], [:d, 4]] #{prefix}[[:e, 5], [:f, 6]] This is my title } assert_html '
    This is my title
    ', source, options(prefix) end end def test_splat_with_other_attributes prefixes.each do |prefix| source = %Q{ h1 data-id="123" #{prefix}hash This is my title } assert_html '

    This is my title

    ', source, options(prefix) end end end slim-5.2.1/test/core/test_ruby_errors.rb0000644000004100000410000000651014572524745020404 0ustar www-datawww-datarequire 'helper' class TestSlimRubyErrors < TestSlim def test_multline_attribute source = %q{ p(data-1=1 data2-=1) p = unknown_ruby_method } assert_ruby_error NameError, "test.slim:5", source, file: 'test.slim' end def test_broken_output_line source = %q{ p = hello_world + \ hello_world + \ unknown_ruby_method } assert_ruby_error NameError, "test.slim:4", source, file: 'test.slim' end def test_broken_output_line2 source = %q{ p = hello_world + \ hello_world p Hello = unknown_ruby_method } assert_ruby_error NameError,"(__TEMPLATE__):5", source end def test_output_block source = %q{ p = hello_world "Hello Ruby" do = unknown_ruby_method } assert_ruby_error NameError,"(__TEMPLATE__):3", source end def test_output_block2 source = %q{ p = hello_world "Hello Ruby" do = "Hello from block" p Hello = unknown_ruby_method } assert_ruby_error NameError, "(__TEMPLATE__):5", source end def test_text_block source = %q{ p Text line 1 Text line 2 = unknown_ruby_method } assert_ruby_error NameError,"(__TEMPLATE__):4", source end def test_text_block2 source = %q{ | Text line 1 Text line 2 = unknown_ruby_method } assert_ruby_error NameError,"(__TEMPLATE__):5", source end def test_comment source = %q{ / Comment line 1 Comment line 2 = unknown_ruby_method } assert_ruby_error NameError,"(__TEMPLATE__):4", source end def test_embedded_ruby1 source = %q{ ruby: a = 1 b = 2 = a + b = unknown_ruby_method } assert_ruby_error NameError,"(__TEMPLATE__):7", source end def test_embedded_ruby2 source = %q{ ruby: a = 1 unknown_ruby_method } assert_ruby_error NameError,"(__TEMPLATE__):4", source end def test_embedded_ruby3 source = %q{ h1 before ruby: a = 1 h1 between ruby: b = a + 1 unknown_ruby_method c = 3 h1 third } assert_ruby_error NameError,"(__TEMPLATE__):10", source end def test_embedded_markdown source = %q{ markdown: #Header Hello from #{"Markdown!"} "Second Line!" = unknown_ruby_method } assert_ruby_error NameError,"(__TEMPLATE__):6", source end def test_embedded_javascript source = %q{ javascript: alert(); alert(); = unknown_ruby_method } assert_ruby_error NameError,"(__TEMPLATE__):5", source end def test_invalid_nested_code source = %q{ p - test = 123 = "Hello from within a block! " } assert_ruby_syntax_error "(__TEMPLATE__):3", source end def test_invalid_nested_output source = %q{ p = "Hello Ruby!" = "Hello from within a block! " } assert_ruby_syntax_error "(__TEMPLATE__):3", source end def test_explicit_end source = %q{ div - if show_first? p The first paragraph - end } assert_runtime_error 'Explicit end statements are forbidden', source end def test_multiple_id_attribute source = %{ #alpha id="beta" Test it } assert_runtime_error 'Multiple id attributes specified', source end def test_splat_multiple_id_attribute source = %{ #alpha *{id:"beta"} Test it } assert_runtime_error 'Multiple id attributes specified', source end # def test_invalid_option # render('', foobar: 42) # raise Exception, 'ArgumentError expected' # rescue ArgumentError => ex # assert_equal 'Option :foobar is not supported by Slim::Engine', ex.message # end end slim-5.2.1/test/core/test_unicode.rb0000644000004100000410000000060314572524745017452 0ustar www-datawww-datarequire 'helper' class TestSlimUnicode < TestSlim def test_unicode_tags source = "Статья года" result = "<Статья>года" assert_html result, source end def test_unicode_attrs source = "Статья года=123 content" result = "<Статья года=\"123\">content" assert_html result, source end end slim-5.2.1/test/core/test_erb_converter.rb0000644000004100000410000000305414572524745020666 0ustar www-datawww-datarequire 'helper' require 'slim/erb_converter' class TestSlimERBConverter < TestSlim def test_converter source = %q{ doctype 5 html head title Hello World! /! Meta tags with long explanatory multiline comment meta name="description" content="template language" /! Stylesheets link href="style.css" media="screen" rel="stylesheet" type="text/css" link href="colors.css" media="screen" rel="stylesheet" type="text/css" /! Javascripts script src="jquery.js" script src="jquery.ui.js" /[if lt IE 9] script src="old-ie1.js" script src="old-ie2.js" css: body { background-color: red; } body #container p Hello World! p= "dynamic text with\nnewline" } result = %q{ Hello World!

    Hello World!

    <%= ::Temple::Utils.escape_html(("dynamic text with\nnewline")) %>

    } assert_equal result, Slim::ERBConverter.new.call(source) end end slim-5.2.1/test/core/test_pretty.rb0000644000004100000410000000562214572524745017361 0ustar www-datawww-datarequire 'helper' class TestSlimPretty < TestSlim def setup super Slim::Engine.set_options pretty: true end def teardown Slim::Engine.set_options pretty: false end def test_pretty source = %q{ doctype 5 html head title Hello World! /! Meta tags with long explanatory multiline comment meta name="description" content="template language" /! Stylesheets link href="style.css" media="screen" rel="stylesheet" type="text/css" link href="colors.css" media="screen" rel="stylesheet" type="text/css" /! Javascripts script src="jquery.js" script src="jquery.ui.js" /[if lt IE 9] script src="old-ie1.js" script src="old-ie2.js" css: body { background-color: red; } body #container p Hello World! p= "dynamic text with\nnewline" } result = %q{ Hello World!

    Hello World!

    dynamic text with newline

    } assert_html result, source end def test_partials body = %q{body == render content} content = %q{div | content} source = %q{html == render body, scope: self, locals: { content: content }} result = %q{
    content
    } assert_html result, source, scope: self, locals: {body: body, content: content } end def test_correct_line_number source = %q{ html head body p Slim = '' = '' = '' = unknown_ruby_method } assert_ruby_error NameError,"(__TEMPLATE__):9", source end def test_unindenting source = %q{ span before span = " middle " span after } result = %q{before middle after} assert_html result, source source = %q{ html body == "
    \n link\n
    " } result = %q{ } assert_html result, source end def test_helper_unindent source = %q{ = define_macro :content div a link html body == call_macro :content } result = %q{ } assert_html result, source end end slim-5.2.1/test/core/test_html_escaping.rb0000644000004100000410000000245614572524745020651 0ustar www-datawww-datarequire 'helper' class TestSlimHtmlEscaping < TestSlim def test_html_will_not_be_escaped source = %q{ p World, meet "Slim". } assert_html '

    World, meet "Slim".

    ', source end def test_html_with_newline_will_not_be_escaped source = %q{ p | World, meet "Slim". } assert_html "

    World,\n meet \"Slim\".

    ", source end def test_html_with_escaped_interpolation source = %q{ - x = '"' - content = '' p class="#{x}" test #{content} } assert_html '

    test <x>

    ', source end def test_html_nested_escaping source = %q{ = hello_world do | escaped & } assert_html 'Hello World from @env escaped & Hello World from @env', source end def test_html_quoted_attr_escape source = %q{ p id="&" class=="&" } assert_html '

    ', source end def test_html_quoted_attr_escape_with_interpolation source = %q{ p id="&#{'"'}" class=="&#{'"'}" p id="&#{{'"'}}" class=="&#{{'"'}}" } assert_html '

    ', source end def test_html_ruby_attr_escape source = %q{ p id=('&'.to_s) class==('&'.to_s) } assert_html '

    ', source end end slim-5.2.1/test/core/test_code_output.rb0000644000004100000410000000567514572524745020374 0ustar www-datawww-datarequire 'helper' class TestSlimCodeOutput < TestSlim def test_render_with_call source = %q{ p = hello_world } assert_html '

    Hello World from @env

    ', source end def test_render_with_trailing_whitespace source = %q{ p => hello_world } assert_html '

    Hello World from @env

    ', source end def test_render_with_trailing_whitespace_after_tag source = %q{ p=> hello_world } assert_html '

    Hello World from @env

    ', source end def test_no_escape_render_with_trailing_whitespace source = %q{ p ==> hello_world } assert_html '

    Hello World from @env

    ', source end def test_no_escape_render_with_trailing_whitespace_after_tag source = %q{ p==> hello_world } assert_html '

    Hello World from @env

    ', source end def test_render_with_conditional_call source = %q{ p = hello_world if true } assert_html '

    Hello World from @env

    ', source end def test_render_with_parameterized_call source = %q{ p = hello_world("Hello Ruby!") } assert_html '

    Hello Ruby!

    ', source end def test_render_with_spaced_parameterized_call source = %q{ p = hello_world "Hello Ruby!" } assert_html '

    Hello Ruby!

    ', source end def test_render_with_spaced_parameterized_call_2 source = %q{ p = hello_world "Hello Ruby!", dummy: "value" } assert_html '

    Hello Ruby!dummy value

    ', source end def test_render_with_call_and_inline_text source = %q{ h1 This is my title p = hello_world } assert_html '

    This is my title

    Hello World from @env

    ', source end def test_render_with_attribute_starts_with_keyword source = %q{ p = hello_world in_keyword } assert_html '

    starts with keyword

    ', source end def test_hash_call source = %q{ p = hash[:a] } assert_html '

    The letter a

    ', source end def test_tag_output_without_space source = %q{ p= hello_world p=hello_world } assert_html '

    Hello World from @env

    Hello World from @env

    ', source end def test_class_output_without_space source = %q{ .test=hello_world #test==hello_world } assert_html '
    Hello World from @env
    Hello World from @env
    ', source end def test_attribute_output_without_space source = %q{ p id="test"=hello_world p(id="test")==hello_world } assert_html '

    Hello World from @env

    Hello World from @env

    ', source end def test_render_with_backslash_end # Keep trailing spaces! source = %q{ p = \ "Hello" + \ " Ruby!" - variable = 1 + \ 2 + \ 3 = variable + \ 1 } assert_html '

    Hello Ruby!

    7', source end def test_render_with_comma_end source = %q{ p = message("Hello", "Ruby!") } assert_html '

    Hello Ruby!

    ', source end def test_render_with_no_trailing_character source = %q{ p = hello_world} assert_html '

    Hello World from @env

    ', source end end slim-5.2.1/test/core/test_text_interpolation.rb0000644000004100000410000000320114572524745021754 0ustar www-datawww-datarequire 'helper' class TestSlimTextInterpolation < TestSlim def test_interpolation_in_attribute source = %q{ p id="a#{id_helper}b" = hello_world } assert_html '

    Hello World from @env

    ', source end def test_nested_interpolation_in_attribute source = %q{ p id="#{"abc#{1+1}" + "("}" = hello_world } assert_html '

    Hello World from @env

    ', source end def test_interpolation_in_text source = %q{ p | #{hello_world} with "quotes" p | A message from the compiler: #{hello_world} } assert_html '

    Hello World from @env with "quotes"

    A message from the compiler: Hello World from @env

    ', source end def test_interpolation_in_tag source = %q{ p #{hello_world} } assert_html '

    Hello World from @env

    ', source end def test_escape_interpolation source = %q{ p \\#{hello_world} p text1 \\#{hello_world} text2 } assert_html '

    #{hello_world}

    text1 #{hello_world} text2

    ', source end def test_complex_interpolation source = %q{ p Message: #{message('hello', "user #{output_number}")} } assert_html '

    Message: hello user 1337

    ', source end def test_interpolation_with_escaping source = %q{ | #{evil_method} } assert_html '<script>do_something_evil();</script>', source end def test_interpolation_without_escaping source = %q{ | #{{evil_method}} } assert_html '', source end def test_interpolation_with_escaping_and_delimiter source = %q{ | #{(evil_method)} } assert_html '<script>do_something_evil();</script>', source end end slim-5.2.1/test/core/test_tabs.rb0000644000004100000410000000302114572524745016752 0ustar www-datawww-datarequire 'helper' class TestSlimTabs < TestSlim def teardown Slim::Engine.set_options tabsize: 4 end def test_single_tab1_expansion Slim::Engine.set_options tabsize: 1 source = %Q{ | \t0 \t1 \t2 \t3 \t4 \t5 \t6 \t7 \t8 } result = %q{ 0 1 2 3 4 5 6 7 8 }.strip assert_html result, source end def test_single_tab4_expansion Slim::Engine.set_options tabsize: 4 source = %Q{ | \t0 \t1 \t2 \t3 \t4 \t5 \t6 \t7 \t8 } result = %q{ 0 1 2 3 4 5 6 7 8 }.strip assert_html result, source end def test_multi_tab1_expansion Slim::Engine.set_options tabsize: 1 source = %Q{ | \t0 \t\t1 \t \t2 \t \t3 \t \t4 \t\t1 \t \t2 \t \t3 \t \t4 \t\t1 \t \t2 \t \t3 \t \t4 \t\t1 \t \t2 \t \t3 \t \t4 } result = %q{ 0 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 }.strip assert_html result, source end def test_multi_tab4_expansion Slim::Engine.set_options tabsize: 4 source = %Q{ | \t0 \t\t1 \t \t2 \t \t3 \t \t4 \t\t1 \t \t2 \t \t3 \t \t4 \t\t1 \t \t2 \t \t3 \t \t4 \t\t1 \t \t2 \t \t3 \t \t4 } result = %q{ 0 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4 }.strip assert_html result, source end end slim-5.2.1/test/core/test_code_structure.rb0000644000004100000410000000646114572524745021066 0ustar www-datawww-datarequire 'helper' class TestSlimCodeStructure < TestSlim def test_render_with_conditional source = %q{ div - if show_first? p The first paragraph - else p The second paragraph } assert_html '

    The second paragraph

    ', source end def test_render_with_begin source = %q{ - if true - begin p A - if true - begin p B - if true - begin p C - rescue p D } assert_html '

    A

    B

    C

    ', source end def test_render_with_consecutive_conditionals source = %q{ div - if show_first? true p The first paragraph - if show_first? true p The second paragraph } assert_html '

    The first paragraph

    The second paragraph

    ', source end def test_render_with_parameterized_conditional source = %q{ div - if show_first? false p The first paragraph - else p The second paragraph } assert_html '

    The second paragraph

    ', source end def test_render_with_when_string_in_condition source = %q{ - if true | Hello - unless 'when' == nil | world } assert_html 'Hello world', source end def test_render_with_conditional_and_following_nonconditonal source = %q{ div - if true p The first paragraph - var = 42 = var } assert_html '

    The first paragraph

    42
    ', source end def test_render_with_inline_condition source = %q{ p = hello_world if true } assert_html '

    Hello World from @env

    ', source end def test_render_with_case source = %q{ p - case 42 - when 41 | 41 - when 42 | 42 | is the answer p - case 41 - when 41 | 41 - when 42 | 42 | is the answer p - case 42 when 41 | 41 - when 42 | 42 | is the answer p - case 41 when 41 | 41 - when 42 | 42 | is the answer } assert_html '

    42 is the answer

    41 is the answer

    42 is the answer

    41 is the answer

    ', source end if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("2.7") def test_render_with_case_in source = %q{ p - case [:greet, "world"] - in :greet, value if false = "Goodbye #{value}" - in :greet, value unless true = "Top of the morning to you, #{value}" - in :greet, value = "Hello #{value}" } assert_html '

    Hello world

    ', source end end def test_render_with_slim_comments source = %q{ p Hello / This is a comment Another comment p World } assert_html '

    Hello

    World

    ', source end def test_render_with_yield source = %q{ div == yield :menu } assert_html '
    This is the menu
    ', source do 'This is the menu' end end def test_render_with_begin_rescue source = %q{ - begin p Begin - rescue p Rescue p After } assert_html '

    Begin

    After

    ', source end def test_render_with_begin_rescue_exception source = %q{ - begin p Begin - raise 'Boom' p After Boom - rescue => ex p = ex.message p After } assert_html '

    Begin

    Boom

    After

    ', source end def test_render_with_begin_rescue_ensure source = %q{ - begin p Begin - raise 'Boom' p After Boom - rescue => ex p = ex.message - ensure p Ensure p After } assert_html '

    Begin

    Boom

    Ensure

    After

    ', source end end slim-5.2.1/test/core/test_slim_template.rb0000644000004100000410000000416314572524745020670 0ustar www-datawww-datarequire 'helper' class ::MockError < NameError end class TestSlimTemplate < TestSlim def test_default_mime_type assert_equal 'text/html', Slim::Template.default_mime_type end def test_registered_extension assert_equal Slim::Template, Tilt['test.slim'] end def test_preparing_and_evaluating template = Slim::Template.new { |t| "p Hello World!\n" } assert_equal "

    Hello World!

    ", template.render end def test_evaluating_in_an_object_scope template = Slim::Template.new { "p = 'Hey ' + @name + '!'\n" } scope = Object.new scope.instance_variable_set :@name, 'Joe' assert_equal "

    Hey Joe!

    ", template.render(scope) end def test_passing_a_block_for_yield template = Slim::Template.new { "p = 'Hey ' + yield + '!'\n" } assert_equal "

    Hey Joe!

    ", template.render { 'Joe' } end def test_backtrace_file_and_line_reporting_without_locals data = File.read(__FILE__).split("\n__END__\n").last fail unless data[0] == ?h template = Slim::Template.new('test.slim', 10) { data } begin template.render fail 'should have raised an exception' rescue => ex assert_kind_of NameError, ex assert_backtrace(ex, 'test.slim:12') end end def test_backtrace_file_and_line_reporting_with_locals data = File.read(__FILE__).split("\n__END__\n").last fail unless data[0] == ?h template = Slim::Template.new('test.slim') { data } begin template.render(Object.new, name: 'Joe', foo: 'bar') fail 'should have raised an exception' rescue => ex assert_kind_of MockError, ex assert_backtrace(ex, 'test.slim:5') end end def test_compiling_template_source_to_a_method template = Slim::Template.new { |t| "Hello World!" } template.render method = template.send(:compiled_method, []) assert_kind_of UnboundMethod, method end def test_passing_locals template = Slim::Template.new { "p = 'Hey ' + name + '!'\n" } assert_equal "

    Hey Joe!

    ", template.render(Object.new, name: 'Joe') end end __END__ html body h1 = "Hey #{name}" = raise MockError p we never get here slim-5.2.1/test/core/test_code_evaluation.rb0000644000004100000410000001107614572524745021173 0ustar www-datawww-datarequire 'helper' class TestSlimCodeEvaluation < TestSlim def test_render_with_call_to_set_attributes source = %q{ p id="#{id_helper}" class="hello world" = hello_world } assert_html '

    Hello World from @env

    ', source end def test_render_with_call_to_set_custom_attributes source = %q{ p data-id="#{id_helper}" data-class="hello world" = hello_world } assert_html '

    Hello World from @env

    ', source end def test_render_with_call_to_set_attributes_and_call_to_set_content source = %q{ p id="#{id_helper}" class="hello world" = hello_world } assert_html '

    Hello World from @env

    ', source end def test_render_with_parameterized_call_to_set_attributes_and_call_to_set_content source = %q{ p id="#{id_helper}" class="hello world" = hello_world("Hello Ruby!") } assert_html '

    Hello Ruby!

    ', source end def test_render_with_spaced_parameterized_call_to_set_attributes_and_call_to_set_content source = %q{ p id="#{id_helper}" class="hello world" = hello_world "Hello Ruby!" } assert_html '

    Hello Ruby!

    ', source end def test_render_with_spaced_parameterized_call_to_set_attributes_and_call_to_set_content_2 source = %q{ p id="#{id_helper}" class="hello world" = hello_world "Hello Ruby!", dummy: "value" } assert_html '

    Hello Ruby!dummy value

    ', source end def test_hash_call_in_attribute source = %q{ p id="#{hash[:a]}" Test it } assert_html '

    Test it

    ', source end def test_instance_variable_in_attribute_without_quotes source = %q{ p id=@var } assert_html '

    ', source end def test_method_call_in_attribute_without_quotes source = %q{ form action=action_path(:page, :save) method='post' } assert_html '
    ', source end def test_ruby_attribute_with_unbalanced_delimiters source = %q{ div crazy=action_path('[') id="crazy_delimiters" } assert_html '
    ', source end def test_method_call_in_delimited_attribute_without_quotes source = %q{ form(action=action_path(:page, :save) method='post') } assert_html '
    ', source end def test_method_call_in_delimited_attribute_without_quotes2 source = %q{ form(method='post' action=action_path(:page, :save)) } assert_html '
    ', source end def test_hash_call_in_attribute_without_quotes source = %q{ p id=hash[:a] Test it } assert_html '

    Test it

    ', source end def test_hash_call_in_delimited_attribute source = %q{ p(id=hash[:a]) Test it } assert_html '

    Test it

    ', source end def test_hash_call_in_attribute_with_ruby_evaluation source = %q{ p id=(hash[:a] + hash[:a]) Test it } assert_html '

    Test it

    ', source end def test_hash_call_in_delimited_attribute_with_ruby_evaluation source = %q{ p(id=(hash[:a] + hash[:a])) Test it } assert_html '

    Test it

    ', source end def test_hash_call_in_delimited_attribute_with_ruby_evaluation_2 source = %q{ p[id=(hash[:a] + hash[:a])] Test it } assert_html '

    Test it

    ', source end def test_hash_call_in_delimited_attribute_with_ruby_evaluation_3 source = %q{ p(id=(hash[:a] + hash[:a]) class=hash[:a]) Test it } assert_html '

    Test it

    ', source end def test_hash_call_in_delimited_attribute_with_ruby_evaluation_4_ source = %q{ p(id=hash[:a] class=hash[:a]) Test it } assert_html '

    Test it

    ', source end def test_computation_in_attribute source = %q{ p id=(1 + 1)*5 Test it } assert_html '

    Test it

    ', source end def test_code_attribute_does_not_modify_argument require 'ostruct' template = 'span class=attribute' model = OpenStruct.new(attribute: [:a, :b, [:c, :d]]) output = Slim::Template.new { template }.render(model) assert_equal('', output) assert_equal([:a, :b, [:c, :d]], model.attribute) end def test_number_type_interpolation source = %q{ p = output_number } assert_html '

    1337

    ', source end end slim-5.2.1/test/core/test_encoding.rb0000644000004100000410000000125714572524745017620 0ustar www-datawww-datarequire 'helper' class TestSlimEncoding < TestSlim def test_windows_crlf source = "a href='#' something\r\nbr\r\na href='#' others\r\n" result = "something
    others" assert_html result, source end def test_binary source = "| \xFF\xFF".dup source.force_encoding(Encoding::BINARY) result = "\xFF\xFF".dup result.force_encoding(Encoding::BINARY) out = render(source, default_encoding: 'binary') out.force_encoding(Encoding::BINARY) assert_equal result, out end def test_bom source = "\xEF\xBB\xBFh1 Hello World!" result = '

    Hello World!

    ' assert_html result, source end end slim-5.2.1/test/core/test_code_blocks.rb0000644000004100000410000000757714572524745020314 0ustar www-datawww-datarequire 'helper' class TestSlimCodeBlocks < TestSlim def test_render_with_output_code_block source = %q{ p = hello_world "Hello Ruby!" do | Hello from within a block! } assert_html '

    Hello Ruby! Hello from within a block! Hello Ruby!

    ', source end def test_render_with_output_code_block_without_do source = %q{ p = hello_world "Hello Ruby!" | Hello from within a block! } assert_html '

    Hello Ruby! Hello from within a block! Hello Ruby!

    ', source end def test_render_variable_ending_with_do source = %q{ - appelido=10 p= appelido - appelido } assert_html '

    10

    ', source end def test_render_with_output_code_within_block source = %q{ p = hello_world "Hello Ruby!" do = hello_world "Hello from within a block!" } assert_html '

    Hello Ruby! Hello from within a block! Hello Ruby!

    ', source end def test_render_with_output_code_within_block_without_do source = %q{ p = hello_world "Hello Ruby!" = hello_world "Hello from within a block!" } assert_html '

    Hello Ruby! Hello from within a block! Hello Ruby!

    ', source end def test_render_with_output_code_within_block_2 source = %q{ p = hello_world "Hello Ruby!" do = hello_world "Hello from within a block!" do = hello_world "And another one!" } assert_html '

    Hello Ruby! Hello from within a block! And another one! Hello from within a block! Hello Ruby!

    ', source end def test_render_with_output_code_within_block_2_without_do source = %q{ p = hello_world "Hello Ruby!" = hello_world "Hello from within a block!" = hello_world "And another one!" } assert_html '

    Hello Ruby! Hello from within a block! And another one! Hello from within a block! Hello Ruby!

    ', source end def test_output_block_with_arguments source = %q{ p = define_macro :person do |first_name, last_name| .first_name = first_name .last_name = last_name == call_macro :person, 'John', 'Doe' == call_macro :person, 'Max', 'Mustermann' } assert_html '

    John
    Doe
    Max
    Mustermann

    ', source end def test_render_with_control_code_loop source = %q{ p - 3.times do | Hey! } assert_html '

    Hey!Hey!Hey!

    ', source end def test_render_with_control_code_loop_without_do source = %q{ p - 3.times | Hey! } assert_html '

    Hey!Hey!Hey!

    ', source end def test_captured_code_block_with_conditional source = %q{ = hello_world "Hello Ruby!" do - if true | Hello from within a block! } assert_html 'Hello Ruby! Hello from within a block! Hello Ruby!', source end def test_captured_code_block_with_conditional_without_do source = %q{ = hello_world "Hello Ruby!" - if true | Hello from within a block! } assert_html 'Hello Ruby! Hello from within a block! Hello Ruby!', source end def test_if_without_content source = %q{ - if true } assert_html '', source end def test_unless_without_content source = %q{ - unless true } assert_html '', source end def test_if_with_comment source = %q{ - if true / comment } assert_html '', source end def test_control_do_with_comment source = %q{ - hello_world "Hello" / comment } assert_html '', source end def test_output_do_with_comment source = %q{ = hello_world "Hello" / comment } assert_html 'Hello', source end def test_output_if_without_content source = %q{ = if true } assert_html '', source end def test_output_if_with_comment source = %q{ = if true / comment } assert_html '', source end def test_output_format_with_if source = %q{ h3.subtitle - if true a href="#" Title true - else a href="#" Title false } assert_html '

    Title true

    ', source end end slim-5.2.1/test/core/test_thread_options.rb0000644000004100000410000000100314572524745021041 0ustar www-datawww-datarequire 'helper' class TestSlimThreadOptions < TestSlim def test_thread_options source = %q{p.test} assert_html '

    ', source assert_html "

    ", source, attr_quote: "'" Slim::Engine.with_options(attr_quote: "'") do assert_html "

    ", source assert_html '

    ', source, attr_quote: '"' end assert_html '

    ', source assert_html "

    ", source, attr_quote: "'" end end slim-5.2.1/test/core/test_code_escaping.rb0000644000004100000410000000743414572524745020620 0ustar www-datawww-datarequire 'helper' class TestSlimCodeEscaping < TestSlim def test_escaping_evil_method source = %q{ p = evil_method } assert_html '

    <script>do_something_evil();</script>

    ', source end def test_render_without_html_safe source = %q{ p = "Hello World\\n, meet \\"Slim\\"." } assert_html "

    <strong>Hello World\n, meet \"Slim\"</strong>.

    ", source end def test_render_without_html_safe2 source = %q{ p = "Hello World\\n, meet 'Slim'." } assert_html "

    <strong>Hello World\n, meet 'Slim'</strong>.

    ", source end def test_render_with_html_safe_false source = %q{ p = "Hello World\\n, meet \\"Slim\\"." } with_html_safe do assert_html "

    <strong>Hello World\n, meet \"Slim\"</strong>.

    ", source, use_html_safe: true end end def test_render_with_html_safe_true source = %q{ p = "Hello World\\n, meet \\"Slim\\".".html_safe } with_html_safe do assert_html "

    Hello World\n, meet \"Slim\".

    ", source, use_html_safe: true end end def test_render_splat_with_html_safe_true source = %q{ p *{ title: '&'.html_safe } } with_html_safe do assert_html "

    ", source, use_html_safe: true end end def test_render_splat_with_html_safe_false source = %q{ p *{ title: '&' } } with_html_safe do assert_html "

    ", source, use_html_safe: true end end def test_render_splat_injecting_evil_attr_name source = %q{ p *{ ">

    'test' } } with_html_safe do assert_raises Slim::InvalidAttributeNameError do render(source, use_html_safe: true) end end end def test_render_attribute_with_html_safe_true source = %q{ p title=('&'.html_safe) } with_html_safe do assert_html "

    ", source, use_html_safe: true end end def test_render_with_disable_escape_false source = %q{ = "

    Hello

    " == "

    World

    " } assert_html "<p>Hello</p>

    World

    ", source end def test_render_with_disable_escape_true source = %q{ = "

    Hello

    " == "

    World

    " } assert_html "

    Hello

    World

    ", source, disable_escape: true end def test_escaping_evil_method_with_pretty source = %q{ p = evil_method } assert_html "

    \n <script>do_something_evil();</script>\n

    ", source, pretty: true end def test_render_without_html_safe_with_pretty source = %q{ p = "Hello World\\n, meet \\"Slim\\"." } assert_html "

    \n <strong>Hello World\n , meet \"Slim\"</strong>.\n

    ", source, pretty: true end def test_render_with_html_safe_false_with_pretty source = %q{ p = "Hello World\\n, meet \\"Slim\\"." } with_html_safe do assert_html "

    \n <strong>Hello World\n , meet \"Slim\"</strong>.\n

    ", source, use_html_safe: true, pretty: true end end def test_render_with_html_safe_true_with_pretty source = %q{ p = "Hello World\\n, meet \\"Slim\\".".html_safe } with_html_safe do assert_html "

    \n Hello World\n , meet \"Slim\".\n

    ", source, use_html_safe: true, pretty: true end end def test_render_with_disable_escape_false_with_pretty source = %q{ = "

    Hello

    " == "

    World

    " } assert_html "<p>Hello</p>

    World

    ", source, pretty: true end def test_render_with_disable_escape_true_with_pretty source = %q{ = "

    Hello

    " == "

    World

    " } assert_html "

    Hello

    World

    ", source, disable_escape: true, pretty: true end end slim-5.2.1/test/core/test_html_attributes.rb0000644000004100000410000001511014572524745021235 0ustar www-datawww-datarequire 'helper' class TestSlimHTMLAttributes < TestSlim def test_ternary_operation_in_attribute source = %q{ p id="#{(false ? 'notshown' : 'shown')}" = output_number } assert_html '

    1337

    ', source end def test_ternary_operation_in_attribute_2 source = %q{ p id=(false ? 'notshown' : 'shown') = output_number } assert_html '

    1337

    ', source end def test_class_attribute_merging source = %{ .alpha class="beta" Test it } assert_html '
    Test it
    ', source end def test_class_attribute_merging_with_nil source = %{ .alpha class="beta" class=nil class="gamma" Test it } assert_html '
    Test it
    ', source end def test_class_attribute_merging_with_empty_static source = %{ .alpha class="beta" class="" class="gamma" Test it } assert_html '
    Test it
    ', source end def test_id_attribute_merging source = %{ #alpha id="beta" Test it } assert_html '
    Test it
    ', source, merge_attrs: {'class' => ' ', 'id' => '_' } end def test_id_attribute_merging2 source = %{ #alpha id="beta" Test it } assert_html '
    Test it
    ', source, merge_attrs: {'class' => ' ', 'id' => '-' } end def test_boolean_attribute_false source = %{ - cond=false option selected=false Text option selected=cond Text2 } assert_html '', source end def test_boolean_attribute_true source = %{ - cond=true option selected=true Text option selected=cond Text2 } assert_html '', source end def test_boolean_attribute_nil source = %{ - cond=nil option selected=nil Text option selected=cond Text2 } assert_html '', source end def test_boolean_attribute_string2 source = %{ option selected="selected" Text } assert_html '', source end def test_boolean_attribute_shortcut source = %{ option(class="clazz" selected) Text option(selected class="clazz") Text } assert_html '', source end def test_array_attribute_merging source = %{ .alpha class="beta" class=[[""], :gamma, nil, :delta, [true, false]] .alpha class=:beta,:gamma } assert_html '
    ', source end def test_hyphenated_attribute source = %{ .alpha data={a: 'alpha', b: 'beta', c_d: 'gamma', c: {e: 'epsilon'}} } assert_html '
    ', source end def test_hyphenated_underscore_attribute source = %{ .alpha data={a: 'alpha', b: 'beta', c_d: 'gamma', c: {e: 'epsilon'}} } assert_html '
    ', source, hyphen_underscore_attrs: true end def test_splat_without_content source = %q{ *hash p*hash } assert_html '

    ', source end def test_shortcut_splat source = %q{ *hash This is my title } assert_html '
    This is my title
    ', source end def test_splat source = %q{ h1 *hash class=[] This is my title } assert_html '

    This is my title

    ', source end def test_closed_splat source = %q{ *hash / } assert_html '
    ', source end def test_splat_tag_name source = %q{ *{tag: 'h1', id: 'title'} This is my title } assert_html '

    This is my title

    ', source end def test_splat_empty_tag_name source = %q{ *{tag: '', id: 'test'} This is my title } assert_html '
    This is my title
    ', source end def test_closed_splat_tag source = %q{ *hash / } assert_html '
    ', source end def test_splat_with_id_shortcut source = %q{ #myid*hash This is my title } assert_html '
    This is my title
    ', source end def test_splat_with_class_shortcut source = %q{ .myclass*hash This is my title } assert_html '
    This is my title
    ', source end def test_splat_with_id_and_class_shortcuts source = %q{ #myid.myclass*hash This is my title } assert_html '
    This is my title
    ', source end def test_splat_with_class_merging source = %q{ #myid.myclass *{class: [:secondclass, %w(x y z)]} *hash This is my title } assert_html '
    This is my title
    ', source end def test_splat_with_boolean_attribute source = %q{ *{disabled: true, empty1: false, nonempty: '', empty2: nil} This is my title } assert_html '
    This is my title
    ', source end def test_splat_merging_with_arrays source = %q{ *{a: 1, b: 2} *[[:c, 3], [:d, 4]] *[[:e, 5], [:f, 6]] This is my title } assert_html '
    This is my title
    ', source end def test_splat_with_other_attributes source = %q{ h1 data-id="123" *hash This is my title } assert_html '

    This is my title

    ', source end def test_attribute_merging source = %q{ a class=true class=false a class=false *{class:true} a class=true a class=false } assert_html '', source end def test_static_empty_attribute source = %q{ p(id="marvin" name="" class="" data-info="Illudium Q-36")= output_number } assert_html '

    1337

    ', source end def test_dynamic_empty_attribute source = %q{ p(id="marvin" class=nil nonempty=("".to_s) data-info="Illudium Q-36")= output_number } assert_html '

    1337

    ', source end def test_weird_attribute source = %q{ p img(src='img.png' whatsthis?!) img src='img.png' whatsthis?!="wtf" } assert_html '

    ', source end end slim-5.2.1/.yardopts0000644000004100000410000000024314572524745014377 0ustar www-datawww-data--markup-provider redcarpet --markup markdown - README.md CHANGES LICENSE test/literate/TESTS.md doc/logic_less.md doc/translator.md doc/smart.md doc/include.md slim-5.2.1/Rakefile0000644000004100000410000000361514572524745014204 0ustar www-datawww-databegin require 'bundler/setup' Bundler::GemHelper.install_tasks rescue Exception end require 'rake/testtask' task 'test' => %w(test:core test:literate test:logic_less test:translator test:smart test:include) namespace 'test' do Rake::TestTask.new('core') do |t| t.libs << 'lib' << 'test/core' t.test_files = FileList['test/core/test_*.rb'] t.warning = true #t.ruby_opts << '-w' << '-v' end Rake::TestTask.new('literate') do |t| t.libs << 'lib' << 'test/literate' t.test_files = FileList['test/literate/run.rb'] t.warning = true end Rake::TestTask.new('logic_less') do |t| t.libs << 'lib' << 'test/core' t.test_files = FileList['test/logic_less/test_*.rb'] t.warning = true end Rake::TestTask.new('translator') do |t| t.libs << 'lib' << 'test/core' t.test_files = FileList['test/translator/test_*.rb'] t.warning = true end Rake::TestTask.new('smart') do |t| t.libs << 'lib' << 'test/core' t.test_files = FileList['test/smart/test_*.rb'] t.warning = true end Rake::TestTask.new('include') do |t| t.libs << 'lib' << 'test/core' t.test_files = FileList['test/include/test_*.rb'] t.warning = true end Rake::TestTask.new('rails') do |t| t.libs << 'lib' t.test_files = FileList['test/rails/test/test_*.rb'] t.warning = true end Rake::TestTask.new('sinatra') do |t| t.libs << 'lib' t.test_files = FileList['test/sinatra/test_*.rb'] # Copied from test task in Sinatra project to mimic their approach t.ruby_opts = ['-r rubygems'] if defined? Gem t.ruby_opts << '-I.' t.warning = true end end begin require 'yard' YARD::Rake::YardocTask.new do |t| t.files = %w(lib/**/*.rb) end rescue LoadError task :yard do abort 'YARD is not available. In order to run yard, you must: gem install yard' end end desc 'Generate Documentation' task doc: :yard task default: 'test' slim-5.2.1/README.jp.md0000644000004100000410000013357414572524745014436 0ustar www-datawww-data# Slim [![Gem Version](https://img.shields.io/gem/v/slim.svg)](http://rubygems.org/gems/slim) ![Build Status](https://github.com/slim-template/slim/actions/workflows/test.yml/badge.svg) [![GitHub Sponsors](https://img.shields.io/github/sponsors/slim-template)](https://github.com/sponsors/slim-template) Slim は 不可解にならない程度に view の構文を本質的な部品まで減らすことを目指したテンプレート言語です。標準的な HTML テンプレートからどれだけのものを減らせるか、検証するところから始まりました。(<, >, 閉じタグなど) 多くの人が Slim に興味を持ったことで, 機能的で柔軟な構文に成長しました。 簡単な特徴 * すっきりした構文 * 閉じタグの無い短い構文 (代わりにインデントを用いる) * 閉じタグを用いた HTML 形式の構文 * 設定可能なショートカットタグ (デフォルトでは `#` は `
    ` に, `.` は `
    ` に) * 安全性 * デフォルトで自動 HTML エスケープ * Rails の `html_safe?` に対応 * 柔軟な設定 * プラグインを用いた拡張性: * Mustache と同様のロジックレスモード * インクルード * 多言語化/I18n * 高性能 * ERB/Erubis に匹敵するスピード * Rails のストリーミングに対応 * 全てのメジャーフレームワークが対応 (Rails, Sinatra, ...) * タグや属性の Unicode に完全対応 * Markdown や Textile のような埋め込みエンジン ## リンク * ホームページ: * ソース: * バグ: * API ドキュメント: * 最新の Gem: * GitHub main: ## イントロダクション ### Slim とは? Slim は __Rails5 以降__ に対応した高速, 軽量なテンプレートエンジンです。主要な Ruby の実装全てでしっかりテストされています。 私たちは継続的インテグレーションを採用しています。(github actions) Slim の核となる構文は1つの考えによって導かれています: "この動作を行うために最低限必要なものは何か。" 多くの人々の Slim への貢献によって, 彼らが使う [Haml](https://github.com/haml/haml) や [Jade](https://github.com/visionmedia/jade) の影響を受け構文の追加が行われています。 Slim の開発チームは美は見る人の目の中にあることを分っているので、こういった追加にオープンです。 Slim は 構文解析/コンパイルに [Temple](https://github.com/judofyr/temple) を使い [Tilt](https://github.com/jeremyevans/tilt) に組み込まれます。これにより [Sinatra](https://github.com/sinatra/sinatra) やプレーンな [Rack](https://github.com/rack/rack) とも一緒に使えます。 Temple のアーキテクチャはとても柔軟で, モンキーパッチなしで構文解析とコンパイルのプロセスの拡張が可能です。これはロジックレスのプラグインや I18n が提供する翻訳プラグインに 使用されます。ロジックレスモードでは HTML をビルドするために Slim の構文を使いたいが, テンプレートの中で Ruby を書きたくない場合にも Slim を使うことができます。 ### なぜ Slim を使うのか? * Slim によって メンテナンスが容易な限りなく最小限のテンプレートを作成でき, 正しい文法の HTML や XML が書けることを保証します。 * Slim の構文は美しく, テンプレートを書くのがより楽しくなります。Slim は主要なフレームワークで互換性があるので, 簡単に始めることができます。 * Slim のアーキテクチャは非常に柔軟なので, 構文の拡張やプラグインを書くことができます。 ___そう, Slim は速い!___ Slim は開発当初からパフォーマンスに注意して開発されてきました。 この数字が信じられませんか? それは仕方ないことです。是非 rake タスクを使って自分でベンチマークを取ってみてください! 私たちの考えでは, あなたは Slim の機能と構文を使うべきです。Slim はあなたのアプリケーションのパフォーマンスに悪影響を与えないことを保証します。 ### どうやって使い始めるの? Slim を gem としてインストール: ~~~ gem install slim ~~~ あなたの Gemfile に `gem 'slim'` と書いてインクルードするか, ファイルに `require 'slim'` と書く必要があります。これだけです! 後は拡張子に .slim を使うだけで準備完了です。 ### 構文例 Slim テンプレートがどのようなものか簡単な例を示します: ~~~ slim doctype html html head title Slim のファイル例 meta name="keywords" content="template language" meta name="author" content=author link rel="icon" type="image/png" href=file_path("favicon.png") javascript: alert('Slim は javascript の埋め込みに対応しています!') body h1 マークアップ例 #content p このマークアップ例は Slim の典型的なファイルがどのようなものか示します。 == yield - if items.any? table#items - for item in items tr td.name = item.name td.price = item.price - else p アイテムが見つかりませんでした。いくつか目録を追加してください。 ありがとう! div id="footer" == render 'footer' | Copyright © #{@year} #{@author} ~~~ インデントについて, インデントの深さはあなたの好みで選択できます。もしあなたが最初のインデントをスペース2つ, その次に5スペースを使いたい場合, それも自由です。マークアップを入れ子にするには最低1つのスペースによるインデントが必要なだけです。 ## ラインインジケータ ### テキスト `|` パイプを使うと, Slim はパイプよりも深くインデントされた全ての行をコピーします。行中の処理は基本的にどのようなものでもエスケープされます。 ~~~ slim body p | これはテキストブロックのテストです。 ~~~ 構文解析結果は以下: ~~~ html

    これはテキストブロックのテストです。

    ~~~ ブロックの左端はパイプ +1 スペースのインデントに設定されています。 追加のスペースはコピーされます。 ~~~ slim body p | この行は左端になります。 この行はスペース 1 つを持つことになります。 この行はスペース 2 つを持つことになります。 以下同様に... ~~~ テキスト行に HTML を埋め込むこともできます。 ~~~ slim - articles.each do |a| | #{a.name}#{a.description} ~~~ ### 末尾スペース付きのテキスト `'` シングルクォートは `|` と同様に行をコピーしますが, 末尾にスペースが1つ追加されます。 ### インライン html `<` (HTML 形式) HTML タグを直接 Slim の中に書くことができます。Slim では, 閉じタグを使った HTML タグ形式や HTML と Slim を混ぜてテンプレートの中に書くことができます。 行頭が '<' の場合, 暗黙的に `|` があるものとして動作します: ~~~ slim head title Example - if articles.empty? - else table - articles.each do |a| #{a.name}#{a.description} ~~~ ### 制御コード `-` ダッシュは制御コードを意味します。制御コードの例としてループと条件文があります。`end` は `-` の後ろに置くことができません。ブロックはインデントによってのみ定義されます。 複数行にわたる Ruby のコードが必要な場合, 行末にバックスラッシュ `\` を追加します。行末がカンマ `,` で終わる場合 (例 関数呼び出し) には, 行末にバックスラッシュを追加する必要はありません。 ~~~ slim body - if articles.empty? | 在庫なし ~~~ ### 出力 `=` イコールはバッファに追加する出力を生成する Ruby コードの呼び出しを Slim に命令します。Ruby のコードが複数行にわたる場合, 例のように行末にバックスラッシュを追加します。 ~~~ slim = javascript_include_tag \ "jquery", "application" ~~~ 行末がカンマ `,` で終わる場合 (例 関数呼び出し) には行末にバックスラッシュを追加する必要はありません。行末・行頭にスペースを追加するために修飾子の `>` や `<` がサポートされています。 * `=>` は末尾のスペースを伴った出力をします。 末尾のスペースが追加されることを除いて, 単一の等合 (`=`) と同じです。 * `=<` は先頭のスペースを伴った出力をします。先頭のスペースが追加されることを除いて, 単一の等号 (`=`) と同じです。 ### HTML エスケープを伴わない出力 `==` 単一のイコール (`=`) と同じですが, `escape_html` メソッドを経由しません。 末尾や先頭のスペースを追加するための修飾子 `>` と `<` はサポートされています。 * `==>` は HTML エスケープを行わずに, 末尾のスペースを伴った出力をします。末尾のスペースが追加されることを除いて, 二重等号 (`==`) と同じです。 * `==<` は HTML エスケープを行わずに, 先頭のスペースを伴った出力をします。先頭のスペースが追加されることを除いて, 二重等号 (`==`) と同じです。 ### コードコメント `/` コードコメントにはスラッシュを使います。スラッシュ以降は最終的なレンダリング結果に表示されません。コードコメントには `/` を, html コメントには `/!` を使います。 ~~~ slim body p / この行は表示されません。 この行も表示されません。 /! html コメントとして表示されます。 ~~~ 構文解析結果は以下: ~~~ html

    ~~~ ### HTML コメント `/!` html コメントにはスラッシュの直後にエクスクラメーションマークを使います (``)。 ### IE コンディショナルコメント `/[...]` ~~~ slim /[if IE] p もっといいブラウザを使ってください。 ~~~ レンダリング結果: ~~~ html ~~~ ## HTML タグ ### 宣言 doctype キーワードでは, とても簡単な方法で複雑な DOCTYPE を生成できます。 XML バージョン ~~~ slim doctype xml doctype xml ISO-8859-1 ~~~ XHTML DOCTYPES ~~~ slim doctype html doctype 5 doctype 1.1 doctype strict doctype frameset doctype mobile doctype basic doctype transitional ~~~ HTML 4 DOCTYPES ~~~ slim doctype strict doctype frameset doctype transitional ~~~ ### 閉じタグ (末尾の `/`) 末尾に `/` を付けることで明示的にタグを閉じることができます。 ~~~ slim img src="image.png"/ ~~~ (注) 標準的な html タグ (img, br, ...) は自動的にタグを閉じるので, 通常必要ありません。 ### 行頭・行末にスペースを追加する (`<`, `>`) a タグの後に > を追加することで末尾にスペースを追加するよう Slim に強制することができます。 ~~~ slim a> href='url1' リンク1 a> href='url2' リンク2 ~~~ < を追加することで先頭にスペースを追加できます。 ~~~ slim a< href='url1' リンク1 a< href='url2' リンク2 ~~~ これらを組み合わせて使うこともできます。 ~~~ slim a<> href='url1' リンク1 ~~~ ### インラインタグ タグをよりコンパクトにインラインにしたくなることがあるかもしれません。 ~~~ slim ul li.first: a href="/a" A リンク li: a href="/b" B リンク ~~~ 可読性のために, 属性を囲むことができるのを忘れないでください。 ~~~ slim ul li.first: a[href="/a"] A リンク li: a[href="/b"] B リンク ~~~ ### テキストコンテンツ タグと同じ行で開始するか ~~~ slim body h1 id="headline" 私のサイトへようこそ。 ~~~ 入れ子にするかのどちらかです。エスケープ処理を行うためにはパイプかシングルクォートを使わなければなりません。 ~~~ slim body h1 id="headline" | 私のサイトへようこそ。 ~~~ スマートテキストモードを有効化して利用する場合 ~~~ slim body h1 id="headline" 私のサイトへようこそ。 ~~~ ### 動的コンテンツ (`=` と `==`) 同じ行で呼び出すか ~~~ slim body h1 id="headline" = page_headline ~~~ 入れ子にすることができます。 ~~~ slim body h1 id="headline" = page_headline ~~~ ### 属性 タグの後に直接属性を書きます。通常の属性記述にはダブルクォート `"` か シングルクォート `'` を使わなければなりません (引用符で囲まれた属性)。 ~~~ slim a href="https://slim-template.github.io" title='Slim のホームページ' Slim のホームページへ ~~~ 引用符で囲まれたテキストを属性として使えます。 #### 属性の囲み 区切り文字が構文を読みやすくするのであれば, `{...}`, `(...)`, `[...]` で属性を囲むことができます。 これらの記号は設定で変更できます (`:attr_list_delims` オプション参照)。 ~~~ slim body h1(id="logo") = page_logo h2[id="tagline" class="small tagline"] = page_tagline ~~~ 属性を囲んだ場合, 属性を複数行にわたって書くことができます: ~~~ slim h2[id="tagline" class="small tagline"] = page_tagline ~~~ 属性の囲みや変数まわりにスペースを使うことができます: ~~~ slim h1 id = "logo" = page_logo h2 [ id = "tagline" ] = page_tagline ~~~ #### 引用符で囲まれた属性 例: ~~~ slim a href="https://slim-template.github.io" title='Slim のホームページ' Slim のホームページへ ~~~ 引用符で囲まれたテキストを属性として使えます: ~~~ slim a href="http://#{url}" #{url} へ ~~~ 属性値はデフォルトでエスケープされます。属性のエスケープを無効にしたい場合 == を使います。 ~~~ slim a href=="&" ~~~ 引用符で囲まれた属性をバックスラッシュ `\` で改行できます。 ~~~ slim a data-title="help" data-content="極めて長い長い長いヘルプテキストで\ 続けてその後はまたやり直して繰り返し...." ~~~ #### Ruby コードを用いた属性 `=` の後に直接 Ruby コードを書きます。コードにスペースが含まれる場合, `(...)` の括弧でコードを囲まなければなりません。ハッシュを `{...}` に, 配列を `[...]` に書くこともできます。 ~~~ slim body table - for user in users td id="user_#{user.id}" class=user.role a href=user_action(user, :edit) Edit #{user.name} a href=(path_to_user user) = user.name ~~~ 属性値はデフォルトでエスケープされます。属性のエスケープを無効にしたい場合 == を使います。 ~~~ slim a href==action_path(:start) ~~~ Ruby コードの属性は, コントロールセクションにあるようにバックスラッシュ `\` や `,` を用いて改行できます。 #### 真偽値属性 属性値の `true`, `false` や `nil` は真偽値として 評価されます。属性を括弧で囲む場合, 属性値の指定を省略することができます。 ~~~ slim input type="text" disabled="disabled" input type="text" disabled=true input(type="text" disabled) input type="text" input type="text" disabled=false input type="text" disabled=nil ~~~ #### 属性の結合 複数の属性が与えられた場合に属性をまとめるように設定することができます (`:merge_attrs` 参照)。デフォルト設定では class 属性はスペース区切りで結合されます。 ~~~ slim a.menu class="highlight" href="https://slim-template.github.io/" slim-template.github.io ~~~ レンダリング結果: ~~~ html slim-template.github.io ~~~ また, `Array` を属性値として使うと、配列要素が区切り文字で結合されます。 ~~~ slim a class=["menu","highlight"] a class=:menu,:highlight ~~~ #### アスタリスク属性 `*` アスタリスクによってハッシュを属性/値のペアとして使うことができます。 ~~~ slim .card*{'data-url'=>place_path(place), 'data-id'=>place.id} = place.name ~~~ レンダリング結果: ~~~ html
    Slim の家
    ~~~ 次のようにハッシュを返すメソッドやインスタンス変数を使うこともできます。 ~~~ slim .card *method_which_returns_hash = place.name .card *@hash_instance_variable = place.name ~~~ 属性の結合 (Slim オプション `:merge_attrs` 参照) に対応するハッシュ属性には `Array` を与えることもできます。 ~~~ slim .first *{class: [:second, :third]} テキスト ~~~ レンダリング結果 ~~~ slim div class="first second third" ~~~ アスタリスク(スプラット)属性のプレフィックスは `splat_prefix` オプションで設定できます。デフォルト値は `'*'` です。 #### 動的タグ `*` アスタリスク属性を使用することで完全に動的なタグを作ることができます。:tag をキーにもつハッシュを返すメソッドを 作るだけです。 ~~~ slim ruby: def a_unless_current @page_current ? {tag: 'span'} : {tag: 'a', href: 'https://slim-template.github.io/'} end - @page_current = true *a_unless_current リンク - @page_current = false *a_unless_current リンク ~~~ レンダリング結果: ~~~ html リンクリンク ~~~ ### ショートカット #### タグショートカット `:shortcut` オプションを設定することで独自のタグショートカットを定義できます。Rails アプリケーションでは, `config/initializers/slim.rb` のようなイニシャライザに定義します。Sinatra アプリでは, `require 'slim'` を書いた行以降であれば, どこにでも設定を定義することができます。 ~~~ ruby Slim::Engine.set_options shortcut: {'c' => {tag: 'container'}, '#' => {attr: 'id'}, '.' => {attr: 'class'} } ~~~ Slim コードの中でこの様に使用できます。 ~~~ slim c.content テキスト ~~~ レンダリング結果 ~~~ html テキスト ~~~ #### 属性のショートカット カスタムショートカットを定義することができます (id の`#` , class の `.` のように)。 例として, type 属性付きの input 要素のショートカット `&` を追加します。 ~~~ ruby Slim::Engine.set_options shortcut: {'&' => {tag: 'input', attr: 'type'}, '#' => {attr: 'id'}, '.' => {attr: 'class'}} ~~~ Slim コードの中でこの様に使用できます。 ~~~ slim &text name="user" &password name="pw" &submit ~~~ レンダリング結果 ~~~ html ~~~ 別の例として, role 属性のショートカット `@` を追加します。 ~~~ ruby Slim::Engine.set_options shortcut: {'@' => 'role', '#' => 'id', '.' => 'class'} ~~~ Slim コードの中でこの様に使用できます。 ~~~ slim .person@admin = person.name ~~~ レンダリング結果 ~~~ html
    Daniel
    ~~~ 1つのショートカットを使って複数の属性を設定することもできます。 ~~~ ruby Slim::Engine.set_options shortcut: {'@' => {attr: %w(data-role role)}} ~~~ Slim の中で次のように使用すると, ~~~ slim .person@admin = person.name ~~~ このようにレンダリングされます。 ~~~ html
    Daniel
    ~~~ 次のように追加の属性固定値を設定することもできます。 ~~~ ruby Slim::Engine.set_options shortcut: {'^' => {tag: 'script', attr: 'data-binding', additional_attrs: { type: "text/javascript" }}} ~~~ このように使用します。 ~~~ slim ^products == @products.to_json ~~~ レンダリング結果です。 ~~~ html ~~~ #### ID ショートカット `#` と class ショートカット `.` `id` と `class` の属性を次のショートカットで指定できます。 ~~~ slim body h1#headline = page_headline h2#tagline.small.tagline = page_tagline .content = show_content ~~~ これは次に同じです ~~~ slim body h1 id="headline" = page_headline h2 id="tagline" class="small tagline" = page_tagline div class="content" = show_content ~~~ ## ヘルパ, キャプチャとインクルード いくつかのヘルパを使用してテンプレートを拡張することもできます。次のヘルパが定義されているとして, ~~~ruby module Helpers def headline(&block) if defined?(::Rails) # Rails の場合には capture メソッドを使う "

    #{capture(&block)}

    " else # フレームワークなしで Slim を使う場合(Tilt の場合), # そのまま出力する "

    #{yield}

    " end end end ~~~ 実行する Slim のテンプレートコードのスコープにインクルードされます。このヘルパは, Slim テンプレートの中で次のように使用することができます。 ~~~ slim p = headline do ' Hello = user.name ~~~ `do` ブロック内のコンテンツが自動的にキャプチャされ `yield` を通してヘルパに渡されます。糖衣構文として `do` キーワードを省略して書くこともできます。 ~~~ slim p = headline ' Hello = user.name ~~~ ### ローカル変数のキャプチャ 次のように `Binding` を使ってローカル変数をキャプチャすることができます: ~~~ruby module Helpers def capture_to_local(var, &block) set_var = block.binding.eval("lambda {|x| #{var} = x }") # Rails では capture! を使います # Slim をフレームワークなしで使う場合 (Tilt のみを使う場合), # キャプチャブロックを取得するには yield だけが利用できます set_var.call(defined?(::Rails) ? capture(&block) : yield) end end ~~~ このヘルパは次のように使用できます ~~~ slim / captured_content 変数は Binding 前に定義されていなければいけません。 = capture_to_local captured_content=:captured_content p この段落は captured_content 変数にキャプチャされます = captured_content ~~~ 別の興味深いユースケースは, enumerableを使いそれぞれの要素をキャプチャすることです。ヘルパは, このようになります。 ~~~ ruby module Capture def capture(var, enumerable = nil, &block) value = enumerable ? enumerable.map(&block) : yield block.binding.eval("lambda {|x| #{var} = x }").call(value) nil end end ~~~ そして, 次のように使用出来ます。 ~~~ slim - links = { 'https://slim-template.github.io' => 'The Slim Template Language' } = capture link_list=:link_list, links do |url, text| a href=url = text ~~~ その後は, `link_list`はキャプチャしたコンテンツを含みます。 ### インクルードヘルパ コンパイル時にインクルード機能を使いたい場合には, [パーシャルのインクルード](doc/jp/include.md) を見てください。 実行時にサブテンプレートを実行すること ( Rails の `#render` のように) もできます。インクルードヘルパを自分で用意する必要があります: ~~~ ruby module Helpers def include_slim(name, options = {}, &block) Slim::Template.new("#{name}.slim", options).render(self, &block) end end ~~~ このヘルパは次のように使用できます ~~~ slim nav = include_slim 'menu' section = include_slim 'content' ~~~ しかし, このヘルパはキャッシュを行いません。その為, 目的にあったよりインテリジェントなバージョンを 実装する必要があります。また, ほとんどのフレームワークにはすでに同様のヘルパが含まれるので注意してください。(例: Rails の `render` メソッド) ## テキストの展開 Ruby の標準的な展開方法を使用します。テキストはデフォルトで html エスケープされます。2 重括弧にすることでエスケープしないこともできます。 ~~~ slim body h1 ようこそ #{current_user.name} ショーへ。 | エスケープしない #{{content}} こともできます。 ~~~ 展開したテキストのエスケープ方法 (言い換えればそのままのレンダリング) ~~~ slim body h1 ようこそ \#{current_user.name} ショーへ。 ~~~ ## 埋め込みエンジン (Markdown, ...) [Tilt](https://github.com/jeremyevans/tilt)のおかげで, Slim は他のテンプレートエンジンの埋め込みに見事に対応しています。 例: ~~~ slim coffee: square = (x) -> x * x markdown: #Header #{"Markdown"} からこんにちわ! 2行目! p: markdown: Tag with **inline** markdown! ~~~ 対応エンジン: | フィルタ | 必要な gems | 種類 | 説明 | | -------- | ----------- | ---- | ----------- | | ruby: | なし | ショートカット | Ruby コードを埋め込むショートカット | | javascript: | なし | ショートカット | javascript コードを埋め込み、script タグで囲む | | css: | なし | ショートカット | css コードを埋め込み、style タグで囲む | | sass: | sass-embedded または sassc または sass | コンパイル時 | sass コードを埋め込み、style タグで囲む | | scss: | sass-embedded または sassc または sass | コンパイル時 | scss コードを埋め込み、style タグで囲む | | less: | less | コンパイル時 | less コードを埋め込み、style タグで囲む | | coffee: | coffee-script | コンパイル時 | CoffeeScript をコンパイルし、 script タグで囲む | | markdown: | redcarpet/rdiscount/kramdown | コンパイル時 + 展開 | Markdown をコンパイルし、テキスト中の # \{variables} を展開 | | textile: | redcloth | コンパイル時 + 展開 | textile をコンパイルし、テキスト中の # \{variables} を展開 | | rdoc: | rdoc | コンパイル時 + 展開 | RDoc をコンパイルし、テキスト中の # \{variables} を展開 | 埋め込みエンジンは Slim の `Slim::Embedded` フィルタのオプションで直接設定されます。例: ~~~ ruby Slim::Embedded.options[:markdown] = {auto_ids: false} ~~~ 以下埋め込みエンジンの場合はHTMLのattributeも指定できます: * Javascript * CSS * CoffeeScript * LESS * SASS * SCSS 例: ~~~ scss scss class="myClass": $color: #f00; body { color: $color; } ~~~ レンダリング結果: ~~~ html ~~~ ## Slim の設定 Slim とその基礎となる [Temple](https://github.com/judofyr/temple) は非常に柔軟に設定可能です。 Slim を設定する方法はコンパイル機構に少し依存します。(Rails や [Tilt](https://github.com/jeremyevans/tilt))。デフォルトオプションの設定は `Slim::Engine` クラスでいつでも可能です。Rails の 環境設定ファイルで設定可能です。例えば, config/environments/developers.rb で設定したいとします: ### デフォルトオプション ~~~ ruby # デバック用に html をきれいにインデントし属性をソートしない Slim::Engine.set_options pretty: true, sort_attrs: false ~~~ ハッシュで直接オプションにアクセスすることもできます: ~~~ ruby Slim::Engine.options[:pretty] = true ~~~ ### 実行時のオプション設定 実行時のオプション設定の方法は2つあります。Tilt テンプレート (`Slim::Template`) の場合, テンプレートを インスタンス化する時にオプションを設定できます。 ~~~ ruby Slim::Template.new('template.slim', optional_option_hash).render(scope) ~~~ 他の方法は Rails に主に関係がありますがスレッド毎にオプション設定を行う方法です: ~~~ slim Slim::Engine.with_options(option_hash) do # ここで作成される Slim エンジンは option_hash を使用します # Rails での使用例: render :page, layout: true end ~~~ Rails ではコンパイルされたテンプレートエンジンのコードとオプションはテンプレート毎にキャッシュされ, 後でオプションを変更できないことに注意する必要があります。 ~~~ slim # 最初のレンダリング呼び出し Slim::Engine.with_options(pretty: true) do render :page, layout: true end # 2回目のレンダリング呼び出し Slim::Engine.with_options(pretty: false) do render :page, layout: true # :pretty is still true because it is cached end ~~~ ### 設定可能なオプション 次のオプションが `Slim::Engine` によって用意され `Slim::Engine.set_options` で設定することができます。 沢山ありますが, 素晴らしいことに, Slim は設定キーをチェックし, 無効な設定キーを使用しようとしていた場合, エラーを返してくれます。 | 型 | 名前 | デフォルト | 用途 | | ---- | ---- | ---------- | ---- | | String | :file | nil | 解析対象のファイル名。 Slim::Template によって自動的に設定されます | | Integer | :tabsize | 4 | 1 タブあたりのスペース数 (構文解析で利用されます) | | String | :encoding | "utf-8" | テンプレートのエンコーディングを設定 | | String | :default_tag | "div" | タグ名が省略されている場合デフォルトのタグとして使用される | | Hash | :shortcut | \{'.' => {attr: 'class'}, '#' => {attr: 'id'}} | 属性のショートカット | | Hash | :code_attr_delims | \{'(' => ')', '[' => ']', '{' => '}'} | Ruby コードの属性区切り文字 | | Hash | :attr_list_delims | \{'(' => ')', '[' => ']', '{' => '}'} | 属性リスト区切り文字 | | Array<Symbol,String> | :enable_engines | nil (すべて有効) | 有効な埋め込みエンジンリスト (ホワイトリスト) | | Array<Symbol,String> | :disable_engines | nil (無効なし) | 無効な埋め込みエンジンリスト (ブラックリスト) | | Boolean | :disable_capture | false (Rails では true) | ブロック内キャプチャ無効 (ブロックはデフォルトのバッファに書き込む) | | Boolean | :disable_escape | false | Stringの自動エスケープ無効 | | Boolean | :use_html_safe | false (Rails では true) | ActiveSupport の String# html_safe? を使う (:disable_escape と一緒に機能する) | | Symbol | :format | :xhtml | HTML の出力フォーマット (対応フォーマット :html, :xhtml, :xml) | | String | :attr_quote | '"' | HTML の属性を囲む文字 (' または " が可能) | | Hash | :merge_attrs | \{'class' => ' '} | 複数の html 属性が与えられたときに, 結合に使われる文字 (例: class="class1 class2") | | Array<String> | :hyphen_attrs | %w(data) | 属性にハッシュが与えられたとき, ハイフンで区切られます。(例: data={a:1, b:2} は data-a="1" data-b="2" のように) | | Boolean | :sort_attrs | true | 名前順に属性をソート | | Symbol | :js_wrapper | nil | :commentや :cdata , :both で JavaScript をラップします。:guess を指定することで :format オプションに基いて設定することもできます | | Boolean | :pretty | false | HTML を綺麗にインデントします。ブロック要素のタグでのみ、インデントされます。 (遅くなります!) | | String | :indent | ' ' | インデントに使用される文字列 | | Boolean | :streaming | false (Rails では true, 無効化するにはストリーミングを参照) | ストリーミング出力の有効化, 体感的なパフォーマンスの向上 | | Class | :generator | Temple::Generators::StringBuffer/ RailsOutputBuffer | Temple コードジェネレータ (デフォルトのジェネレータはStringバッファを生成します) | | String | :buffer | '_buf' (Rails では '@output_buffer') | バッファに使用される変数 | | String | :splat_prefix | '*' | アスタリスク(スプラット)属性のプレフィックス | Temple フィルタによってもっと多くのオプションがサポートされていますが一覧には載せず公式にはサポートしません。 Slim と Temple のコードを確認しなければなりません。 ### オプションの優先順位と継承 Slim や Temple のアーキテクチャについてよく知っている開発者は, 別の場所で設定を 上書きすることができます。 Temple はサブクラスがスーパークラスのオプションを上書きできるように 継承メカニズムを採用しています。オプションの優先順位は次のとおりです: 1. `Slim::Template` オプションはエンジン初期化時に適用されます 2. `Slim::Template.options` 3. `Slim::Engine.thread_options`, `Slim::Engine.options` 5. Praser/Filter/Generator `thread_options`, `options` (例: `Slim::Parser`, `Slim::Compiler`) `Temple::Engine` のようにスーパークラスのオプションを設定することも可能です。しかし, こうするとすべての Temple テンプレートエンジンに影響します。 ~~~ ruby Slim::Engine < Temple::Engine Slim::Compiler < Temple::Filter ~~~ ## プラグイン Slim はロジックレスモードと I18n, インクルードプラグインを提供しています。プラグインのドキュメントを確認してください。 * [ロジックレスモード](doc/jp/logic_less.md) * [パーシャルのインクルード](doc/jp/include.md) * [多言語化/I18n](doc/jp/translator.md) * [スマートテキストモード](doc/jp/smart.md) ## フレームワークサポート ### Tilt Slim は生成されたコードをコンパイルするために [Tilt](https://github.com/jeremyevans/tilt) を使用します。Slim テンプレートを直接使いたい場合, Tilt インターフェイスが使用できます。 ~~~ ruby Tilt.new['template.slim'].render(scope) Slim::Template.new('template.slim', optional_option_hash).render(scope) Slim::Template.new(optional_option_hash) { source }.render(scope) ~~~ optional_option_hash は前述のオプションを持つことができます。スコープはコードが実行されるテンプレートの オブジェクトです。 ### Sinatra ~~~ ruby require 'sinatra' require 'slim' get('/') { slim :index } __END__ @@ index doctype html html head title Slim で Sinatra body h1 Slim は楽しい! ~~~ ### Rails Rails のジェネレータは [slim-rails](https://github.com/slim-template/slim-rails) によって提供されます。 slim-rails は Rails で Slim を使用する場合に必須ではありません。Slim をインストールし Gemfile に `gem 'slim'` を追加するだけです。 後は .slim 拡張子を使うだけです。 #### ストリーミング HTTP ストリーミングをサポートしているバージョンの Rails であれば, デフォルトで有効化されています。しかし, ストリーミングは体感的なパフォーマンスを改善しているだけであることに注意してください。 レンダリング時間は増加するでしょう。ストリーミングを無効化したい場合, 以下のように設定します: ~~~ ruby Slim::RailsTemplate.set_options streaming: false ~~~ ### Angular2 Slim は Angular2 の構文に対応しています。ただし, いくつかのオプションを設定する必要があります: #### `splat_prefix` オプション このオプションは, アスタリスク(スプラット)属性に使用する構文をパーサに指定します。 デフォルト値はアスタリスクです: `splat_prefix: '*'` アスタリスクは Angular2 でも構造ディレクティブとして `*ngIf` などで使われます。デフォルトの設定値では, Slim と Angular2 の構文は衝突します。 解決方法は 2 つあります: * `splat_prefix` に 2重アスタリスクのようなカスタム値(`splat_prefix: '**'`)を設定します。これで構造ディレクティブは期待通りに機能するはずです。アスタリスク属性は設定したカスタム値のプレフィックスで書かなければならないので注意してください。 * アスタリスクではない代わりのディレクティブ構文を使います。 #### 属性区切り文字 Angular と Slim はそれぞれの構文で括弧を使います。この場合も解決方法は 2 つあります: * バインディングに代わりの構文を使う (`bind-...` など) * 属性区切り文字を波括弧に限定する ``` code_attr_delims: { '{' => '}', }, attr_list_delims: { '{' => '}', }, ``` これで次のように書けます: ``` h1{ #var (bind1)="test" [bind2]="ok" [(bind3)]="works?" *ngIf="expr" *ngFor="expression" } {{it works}} ``` コンパイル結果: ```

    {{it works}}

    ``` ## ツール ### Slim コマンド 'slimrb' gem の 'slim' にはコマンドラインから Slim をテストするための小さなツール 'slimrb' が付属します。
    $ slimrb --help
    Usage: slimrb [options]
        -s, --stdin                      Read input from standard input instead of an input file
            --trace                      Show a full traceback on error
        -c, --compile                    Compile only but do not run
        -e, --erb                        Convert to ERB
            --rails                      Generate rails compatible code (Implies --compile)
        -r, --require library            Load library or plugin with -r slim/plugin
        -p, --pretty                     Produce pretty html
        -o, --option name=code           Set slim option
        -l, --locals Hash|YAML|JSON      Set local variables
        -h, --help                       Show this message
        -v, --version                    Print version
    
    'slimrb' で起動し, コードをタイプし Ctrl-d で EOF を送ります。Windows のコマンドプロンプトでは Ctrl-z で EOF を送ります。使い方例:
    $ slimrb
    markdown:
      最初の段落。
    
      2つ目の段落。
    
      * 1つ
      * 2つ
      * 3つ
    
    //Enter Ctrl-d
    <p>最初の段落。 </p>
    
    <p>2つめの段落。 </p>
    
    <ul>
    <li>1つ</li>
    <li>2つ</li>
    <li>3つ</li>
    </ul>
    
    ### 構文ハイライト 様々なテキストエディタ(Vim や Emacs, Textmateなど)のためのプラグインがあります。: * [Vim](https://github.com/slim-template/vim-slim) * [Emacs](https://github.com/slim-template/emacs-slim) * [Textmate / Sublime Text](https://github.com/slim-template/ruby-slim.tmbundle) * [Espresso text editor](https://github.com/slim-template/Slim-Sugar) * [Coda](https://github.com/slim-template/Coda-2-Slim.mode) * [Atom](https://github.com/slim-template/language-slim) ### テンプレート変換 (HAML, ERB, ...) * Slim は gem に含まれる `slimrb` や `Slim::ERBConverter` を用いて ERB に変換できます。 * [Haml2Slim converter](https://github.com/slim-template/haml2slim) * [ERB2Slim, HTML2Slim converter](https://github.com/slim-template/html2slim) ## テスト ### ベンチマーク *そうです, Slim は最速の Ruby のテンプレートエンジンです! production モードの Slim は Erubis (最速のテンプレートエンジン) と同じくらい高速です。 どんな理由であれ, あなたが Slim を選択していただければ嬉しいし, 私たちは パフォーマンスが障害にならないだろうことを保証します。* ベンチマークは `rake bench` で実行します。時間が余計にかかりますが遅い解析ベンチマークを 実行したい場合 `slow` オプションを追加できます。 ~~~ rake bench slow=1 iterations=1000 ~~~ ### テストスイートと継続的インテグレーション Slim は minitest ベースの拡張性のあるテストスイートを提供します。テストは 'rake test' または rails のインテグレーションテストの場合 'rake test:rails' で実行できます。 私たちは現在 markdown ファイルで書かれ, 人間が読み書きしやすいテストを試しています: [TESTS.md](test/literate/TESTS.md) Slim は主要な Ruby 実装全てで動作します: * Ruby 2.5 * JRuby ## 貢献 Slim の改良を支援したい場合, Git で管理されているプロジェクトを clone してください。 ~~~ $ git clone git://github.com/slim-template/slim ~~~ 魔法をかけた後 pull request を送ってください。私たちは pull request が大好きです! Ruby の 2.5.0 でテストをすることを覚えておいてください。 もしドキュメントの不足を見つけたら, README.md をアップデートして私たちを助けて下さい。Slim に割ける時間がないが, 私たちが知っておくべきことを見つけた場合には issue を送ってください。 ## License Slim は [MIT license](http://www.opensource.org/licenses/MIT) に基づいてリリースされています。 ## 作者 * [Daniel Mendler](https://github.com/minad) (Lead developer) * [Andrew Stone](https://github.com/stonean) * [Fred Wu](https://github.com/fredwu) ## 寄付と支援 このプロジェクトをサポートしたい場合, GitHub sponsors のページを見てください。 [![GitHub Sponsors](https://img.shields.io/github/sponsors/slim-template)](https://github.com/sponsors/slim-template) ## 関連プロジェクト テンプレートのコンパイルフレームワーク: * [Temple](https://github.com/judofyr/temple) フレームワークサポート: * [Rails generators (slim-rails)](https://github.com/slim-template/slim-rails) * [slimkeyfy - Translation string extraction](https://github.com/phrase/slimkeyfy) 構文ハイライト: * [Vim](https://github.com/slim-template/vim-slim) * [Emacs](https://github.com/slim-template/emacs-slim) * [Textmate / Sublime Text](https://github.com/slim-template/ruby-slim.tmbundle) * [Espresso text editor](https://github.com/slim-template/Slim-Sugar) * [Coda](https://github.com/slim-template/Coda-2-Slim.mode) * [Atom](https://github.com/slim-template/language-slim) 静的コード解析: * [Slim-Lint](https://github.com/sds/slim-lint) * [SublimeLinter-slim-lint](https://github.com/elstgav/SublimeLinter-slim-lint) テンプレート変換 (HAML, ERB, ...): * [Haml2Slim converter](https://github.com/slim-template/haml2slim) * [ERB2Slim, HTML2Slim converter](https://github.com/slim-template/html2slim) 移植言語/同様の言語: * [Sliq (Slim/Liquid integration)](https://github.com/slim-template/sliq) * [Slm (Slim port to Javascript)](https://github.com/slm-lang/slm) * [Coffee script plugin for Slim](https://github.com/yury/coffee-views) * [Clojure port of Slim](https://github.com/chaslemley/slim.clj) * [Hamlet.rb (Similar template language)](https://github.com/gregwebs/hamlet.rb) * [Plim (Python port of Slim)](https://github.com/2nd/plim) * [Skim (Slim for Javascript)](https://github.com/jfirebaugh/skim) * [Emblem.js (Javascript, similar to Slim)](https://github.com/machty/emblem.js) * [Hamlit (High performance Haml implementation, based on Temple like Slim)](https://github.com/k0kubun/hamlit) * [Faml (Faster Haml implementation, also using Temple like Slim)](https://github.com/eagletmt/faml) * [Haml (Older engine which inspired Slim)](https://github.com/haml/haml) * [Jade (Similar engine for javascript)](https://github.com/visionmedia/jade) * [Pug (Successor of Jade, Similar engine for javascript)](https://github.com/pugjs/pug) * [Sweet (Similar engine which also allows to write classes and functions)](https://github.com/joaomdmoura/sweet) * [Amber (Similar engine for Go)](https://github.com/eknkc/amber) * [Slang (Slim-inspired templating language for Crystal)](https://github.com/jeromegn/slang) slim-5.2.1/Gemfile0000644000004100000410000000153214572524745014026 0ustar www-datawww-datasource 'https://rubygems.org/' gemspec gem 'minitest', '~> 5.15' gem 'rake', '~> 13.0' gem 'kramdown', '~> 2.4' if ENV['TEMPLE'] && ENV['TEMPLE'] != 'master' gem 'temple', "= #{ENV['TEMPLE']}" else # Test against temple master by default gem 'temple', github: 'judofyr/temple' end if ENV['TILT'] if ENV['TILT'] == 'master' gem 'tilt', github: 'jeremyevans/tilt' else gem 'tilt', "= #{ENV['TILT']}" end end if ENV['RAILS'] gem 'rails-controller-testing' # we need some smarter test logic for the different Rails versions if ENV['RAILS'] == 'main' gem 'rails', github: 'rails/rails', branch: 'main' else gem 'rails', "= #{ENV['RAILS']}" end end if ENV['SINATRA'] gem 'rack-test' if ENV['SINATRA'] == 'main' gem 'sinatra', github: 'sinatra/sinatra' else gem 'sinatra', "= #{ENV['SINATRA']}" end end slim-5.2.1/LICENSE0000644000004100000410000000206514572524745013542 0ustar www-datawww-dataThe MIT License Copyright (c) 2010 - 2023 Slim Team 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. slim-5.2.1/README.md0000644000004100000410000011664014572524745014021 0ustar www-datawww-data# Slim [![Gem Version](https://img.shields.io/gem/v/slim.svg)](http://rubygems.org/gems/slim) ![Build Status](https://github.com/slim-template/slim/actions/workflows/test.yml/badge.svg) [![GitHub Sponsors](https://img.shields.io/github/sponsors/slim-template)](https://github.com/sponsors/slim-template) Slim is a template language whose goal is to reduce the view syntax to the essential parts without becoming cryptic. It started as an exercise to see how much could be removed from a standard html template (<, >, closing tags, etc...). As more people took an interest in Slim, the functionality grew and so did the flexibility of the syntax. A short list of the features... * Elegant syntax * Short syntax without closing tags (Using indentation instead) * HTML style mode with closing tags * Configurable shortcut tags (`#` for `
    ` and `.` for `
    ` in the default configuration) * Safety * Automatic HTML escaping by default * Support for Rails' `html_safe?` * Highly configurable * Extensible via the following plugins: * Logic less mode similar to Mustache * Includes * Translator/I18n * High performance * Comparable speed to ERB/Erubis * Streaming support in Rails * Supported by all major frameworks (Rails, Sinatra, ...) * Full Unicode support for tags and attributes * Embedded engines like Markdown and Textile ## Links * Homepage: * Source: * Bugs: * API documentation: * Latest Gem: * GitHub main: ## Introduction ### What is Slim? Slim is a fast, lightweight templating engine with support for __Rails 5 and later__. It has been heavily tested on all major ruby implementations. We use continuous integration (github actions). Slim's core syntax is guided by one thought: "What's the minimum required to make this work". As more people have contributed to Slim, there have been syntax additions influenced from their use of [Haml](https://github.com/haml/haml) and [Jade](https://github.com/visionmedia/jade). The Slim team is open to these additions because we know beauty is in the eye of the beholder. Slim uses [Temple](https://github.com/judofyr/temple) for parsing/compilation and is also integrated into [Tilt](https://github.com/jeremyevans/tilt), so it can be used together with [Sinatra](https://github.com/sinatra/sinatra) or plain [Rack](https://github.com/rack/rack). The architecture of Temple is very flexible and allows the extension of the parsing and compilation process without monkey-patching. This is used by the logic less plugin and the translator plugin which provides I18n. In logic-less mode you can use Slim if you like the Slim syntax to build your HTML but don't want to write Ruby in your templates. ### Why use Slim? * Slim allows you to write very minimal templates which are easy to maintain and pretty much guarantees that you write well-formed HTML and XML * The Slim syntax is aesthetic and makes it more fun to write templates. Since you can use Slim as a drop-in replacement in all the major frameworks it is easy to adopt. * The Slim architecture is very flexible and allows you to write syntax extensions and plugins. ___Yes, Slim is speedy!___ Slim was developed right from the start with performance in mind. Don't trust the numbers? That's as it should be. Please try the benchmark rake task yourself! However in our opinion you should use Slim because of its features and syntax. We just ensure that Slim doesn't have a negative impact on the performance of your application. ### How to start? Install Slim as a gem: ~~~ gem install slim ~~~ Include Slim in your Gemfile with `gem 'slim'` or require it with `require 'slim'`. That's it! Now, just use the .slim extension and you're good to go. ### Syntax example Here's a quick example to demonstrate what a Slim template looks like: ~~~ slim doctype html html head title Slim Examples meta name="keywords" content="template language" meta name="author" content=author link rel="icon" type="image/png" href=file_path("favicon.png") javascript: alert('Slim supports embedded javascript!') body h1 Markup examples #content p This example shows you how a basic Slim file looks. == yield - if items.any? table#items - for item in items tr td.name = item.name td.price = item.price - else p No items found. Please add some inventory. Thank you! div id="footer" == render 'footer' | Copyright © #{@year} #{@author} ~~~ Indentation matters, but the indentation depth can be chosen as you like. If you want to first indent 2 spaces, then 5 spaces, it's your choice. To nest markup you only need to indent by one space, the rest is gravy. ## Line indicators ### Verbatim text `|` The pipe tells Slim to just copy the line. It essentially escapes any processing. Each following line that is indented greater than the pipe is copied over. ~~~ slim body p | This is a test of the text block. ~~~ The parsed result of the above: ~~~ html

    This is a test of the text block.

    ~~~ If the text starts on the same line, the left margin is set at the indent of the pipe + one space. Any additional spaces will be copied over. ~~~ slim body p | This line is on the left margin. This line will have one space in front of it. This line will have two spaces in front of it. And so on... ~~~ You can also embed html in the text line ~~~ slim - articles.each do |a| | #{a.name}#{a.description} ~~~ #### Verbatim text with leading and/or trailing white space `|<` `|>` `|<>` You can add white space around verbatim text in the same way as for `=` output: ~~~ slim | This line will not have any extra white space. | This line will have a leading space, but it is difficult to see. |< This line will have a leading white space. |> This line will have a trailing white space. |<> This line will have both leading and trailing white space. ~~~ ### Verbatim text with trailing white space `'` The single quote tells Slim to copy the line (similar to `|`), but makes sure that a single trailing white space is appended. ### Inline html `<` You can write html tags directly in Slim which allows you to write your templates in a more html like style with closing tags or mix html and Slim style. The leading `<` works like an implicit `|`: ~~~ slim head title Example - if articles.empty? - else table - articles.each do |a| #{a.name}#{a.description} ~~~ ### Control code `-` The dash denotes control code. Examples of control code are loops and conditionals. `end` is forbidden behind `-`. Blocks are defined only by indentation. If your ruby code needs to use multiple lines, append a backslash `\` at the end of the lines. If your line ends with comma `,` (e.g because of a method call) you don't need the additional backslash before the linebreak. ~~~ slim body - if articles.empty? | No inventory ~~~ ### Output `=` The equals sign tells Slim it's a Ruby call that produces output to add to the buffer. If your ruby code needs to use multiple lines, append a backslash `\` at the end of the lines. For example: ~~~ slim = javascript_include_tag \ "jquery", "application" ~~~ If your line ends with comma `,` (e.g because of a method call) you don't need the additional backslash before the linebreak. For trailing or leading whitespace the modifiers `>` and `<` are supported. * Output with trailing white space `=>`. Same as the single equals sign (`=`), except that it adds a trailing white space. * Output with leading white space `=<`. Same as the single equals sign (`=`), except that it adds a leading white space. ### Output without HTML escaping `==` Same as the single equals sign (`=`), but does not go through the `escape_html` method. For trailing or leading whitespace the modifiers `>` and `<` are supported. * Output without HTML escaping and trailing white space `==>`. Same as the double equals sign (`==`), except that it adds a trailing white space. * Output without HTML escaping and leading white space `==<`. Same as the double equals sign (`==`), except that it adds a leading white space. ### Code comment `/` Use the forward slash for code comments - anything after it won't get displayed in the final render. Use `/` for code comments and `/!` for html comments ~~~ slim body p / This line won't get displayed. Neither does this line. /! This will get displayed as html comments. ~~~ The parsed result of the above: ~~~ html

    ~~~ ### HTML comment `/!` Use the forward slash immediately followed by an exclamation mark for html comments (``). ### IE conditional comment `/[...]` ~~~ slim /[if IE] p Get a better browser. ~~~ This renders as: ~~~ html ~~~ ## HTML tags ### declaration The doctype keyword can be used to generate the complex doctypes in a very simple manner. XML VERSION ~~~ slim doctype xml doctype xml ISO-8859-1 ~~~ XHTML DOCTYPES ~~~ slim doctype html doctype 5 doctype 1.1 doctype strict doctype frameset doctype mobile doctype basic doctype transitional ~~~ HTML 4 DOCTYPES ~~~ slim doctype strict doctype frameset doctype transitional ~~~ ### Closed tags (trailing `/`) You can close tags explicitly by appending a trailing `/`. ~~~ slim img src="image.png"/ ~~~ Note, that this is usually not necessary since the standard html tags (img, br, ...) are closed automatically. ### Trailing and leading whitespace (`<`, `>`) You can force Slim to add a trailing whitespace after a tag by adding a `>`. ~~~ slim a> href='url1' Link1 a> href='url2' Link2 ~~~ You can add a leading whitespace by adding `<`. ~~~ slim a< href='url1' Link1 a< href='url2' Link2 ~~~ You can also combine both. ~~~ slim a<> href='url1' Link1 ~~~ ### Inline tags Sometimes you may want to be a little more compact and inline the tags. ~~~ slim ul li.first: a href="/a" A link li: a href="/b" B link ~~~ For readability, don't forget you can wrap the attributes. ~~~ slim ul li.first: a[href="/a"] A link li: a[href="/b"] B link ~~~ ### Text content Either start on the same line as the tag ~~~ slim body h1 id="headline" Welcome to my site. ~~~ Or nest it. You must use a pipe or an apostrophe to escape processing ~~~ slim body h1 id="headline" | Welcome to my site. ~~~ Or enable and rely on smart text instead ~~~ slim body h1 id="headline" Welcome to my site. ~~~ ### Dynamic content (`=` and `==`) Can make the call on the same line ~~~ slim body h1 id="headline" = page_headline ~~~ Or nest it. ~~~ slim body h1 id="headline" = page_headline ~~~ ### Attributes You write attributes directly after the tag. For normal text attributes you must use double `"` or single quotes `'` (Quoted attributes). ~~~ slim a href="https://slim-template.github.io" title='Slim Homepage' Goto the Slim homepage ~~~ You can use text interpolation in the quoted attributes. #### Attributes wrapper If a delimiter makes the syntax more readable for you, you can use the characters `{...}`, `(...)`, `[...]` to wrap the attributes. You can configure these symbols (See option `:attr_list_delims`). ~~~ slim body h1(id="logo") = page_logo h2[id="tagline" class="small tagline"] = page_tagline ~~~ If you wrap the attributes, you can spread them across multiple lines: ~~~ slim h2[id="tagline" class="small tagline"] = page_tagline ~~~ You may use spaces around the wrappers and assignments: ~~~ slim h1 id = "logo" = page_logo h2 [ id = "tagline" ] = page_tagline ~~~ #### Quoted attributes Example: ~~~ slim a href="https://slim-template.github.io" title='Slim Homepage' Goto the Slim homepage ~~~ You can use text interpolation in the quoted attributes: ~~~ slim a href="http://#{url}" Goto the #{url} ~~~ The attribute value will be escaped by default. Use == if you want to disable escaping in the attribute. ~~~ slim a href=="&" ~~~ You can break quoted attributes with backslash `\` ~~~ slim a data-title="help" data-content="extremely long help text that goes on\ and on and on and then starts over...." ~~~ #### Ruby attributes Write the ruby code directly after the `=`. If the code contains spaces you have to wrap the code into parentheses `(...)`. You can also directly write hashes `{...}` and arrays `[...]`. ~~~ slim body table - for user in users td id="user_#{user.id}" class=user.role a href=user_action(user, :edit) Edit #{user.name} a href=(path_to_user user) = user.name ~~~ The attribute value will be escaped by default. Use == if you want to disable escaping in the attribute. ~~~ slim a href==action_path(:start) ~~~ You can also break ruby attributes with backslash `\` or trailing `,` as described for control sections. #### Boolean attributes The attribute values `true`, `false` and `nil` are interpreted as booleans. If you use the attribute wrapper you can omit the attribute assigment. ~~~ slim input type="text" disabled="disabled" input type="text" disabled=true input(type="text" disabled) input type="text" input type="text" disabled=false input type="text" disabled=nil ~~~ #### 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="https://slim-template.github.io/" slim-template.github.io ~~~ This renders as: ~~~ html slim-template.github.io ~~~ You can also use an `Array` as attribute value and the array elements will be merged using the delimiter. ~~~ slim a class=["menu","highlight"] a class=:menu,:highlight ~~~ #### Splat attributes `*` The splat shortcut allows you to turn a hash into attribute/value pairs. ~~~ slim .card*{'data-url'=>place_path(place), 'data-id'=>place.id} = place.name ~~~ This renders as: ~~~ html
    Slim's house
    ~~~ You can also use methods or instance variables which return a hash as shown here: ~~~ slim .card *method_which_returns_hash = place.name .card *@hash_instance_variable = place.name ~~~ The hash attributes which support attribute merging (see Slim option `:merge_attrs`) can be given as an `Array` ~~~ slim .first *{class: [:second, :third]} Text ~~~ This renders as: ~~~ html div class="first second third" ~~~ Splat attributes prefix may be configured via `splat_prefix` option. Default value is `'*'` #### 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 a_unless_current @page_current ? {tag: 'span'} : {tag: 'a', href: 'https://slim-template.github.io/'} end - @page_current = true *a_unless_current Link - @page_current = false *a_unless_current Link ~~~ This renders as: ~~~ html LinkLink ~~~ ### Shortcuts #### Tag shortcuts You can define custom tag shortcuts by setting the option `:shortcut`. In Rails apps, you need to put this code for your shortcuts into an initializer like `config/initializers/slim.rb`. In Sinatra, you simply add the same configuration anywhere below the line where you `require 'slim'`. ~~~ ruby Slim::Engine.set_options shortcut: {'c' => {tag: 'container'}, '#' => {attr: 'id'}, '.' => {attr: 'class'} } ~~~ We can use it in Slim code like this ~~~ slim c.content Text ~~~ which renders to ~~~ html Text ~~~ #### Attribute shortcuts You can define custom shortcuts (Similar to `#` for id and `.` for class). In this example we add `&` to create a shortcut for the input elements with type attribute. ~~~ ruby Slim::Engine.set_options shortcut: {'&' => {tag: 'input', attr: 'type'}, '#' => {attr: 'id'}, '.' => {attr: 'class'}} ~~~ We can use it in Slim code like this ~~~ slim &text name="user" &password name="pw" &submit ~~~ which renders to ~~~ html ~~~ In another example we add `@` to create a shortcut for the role attribute. ~~~ ruby Slim::Engine.set_options shortcut: {'@' => {attr: 'role'}, '#' => {attr: 'id'}, '.' => {attr: 'class'}} ~~~ We can use it in Slim code like this ~~~ slim .person@admin = person.name ~~~ which renders to ~~~ html
    Daniel
    ~~~ You can also set multiple attributes with same value at once using one shortcut. ~~~ ruby Slim::Engine.set_options shortcut: {'@' => {attr: %w(data-role role)}} ~~~ We can use it in Slim code like this ~~~ slim .person@admin = person.name ~~~ which renders to ~~~ html
    Daniel
    ~~~ You can also set additional fixed value attributes to a shortcut. ~~~ ruby Slim::Engine.set_options shortcut: {'^' => {tag: 'script', attr: 'data-binding', additional_attrs: { type: "text/javascript" }}} ~~~ Then ~~~ slim ^products == @products.to_json ~~~ which renders to ~~~ html ~~~ #### Lambda shortcuts You can define custom shortcuts using lambdas. In this example we add `~` to create a shortcut with a special processing (adding a prefix) for the class attribute. ~~~ ruby Slim::Engine.set_options shortcut: {'~' => {attr: ->(v) {{class: "styled-#{v}"}}}} ~~~ We can use it in Slim code like this ~~~ slim h1~title Hello ~text~question.paragraph How are you? ~~~ which renders to ~~~ html

    Hello

    How are you?
    ~~~ #### ID shortcut `#` and class shortcut `.` You can specify the `id` and `class` attributes in the following shortcut form ~~~ slim body h1#headline = page_headline h2#tagline.small.tagline = page_tagline .content = show_content ~~~ This is the same as ~~~ slim body h1 id="headline" = page_headline h2 id="tagline" class="small tagline" = page_tagline div class="content" = show_content ~~~ ## Helpers, capturing and includes If you use Slim you might want to extend your template with some helpers. Assume that you have the following helper ~~~ruby module Helpers def headline(&block) if defined?(::Rails) # In Rails we have to use capture! "

    #{capture(&block)}

    " else # If we are using Slim without a framework (Plain Tilt), # this works directly. "

    #{yield}

    " end end end ~~~ which is included in the scope that executes the Slim template code. The helper can then be used in the Slim template as follows ~~~ slim p = headline do ' Hello = user.name ~~~ The content in the `do` block is then captured automatically and passed to the helper via `yield`. As a syntactic sugar you can omit the `do` keyword and write only ~~~ slim p = headline ' Hello = user.name ~~~ ### Capturing to local variables Using the `Binding` you can capture to local variables as follows: ~~~ruby module Helpers def capture_to_local(var, &block) set_var = block.binding.eval("lambda {|x| #{var} = x }") # In Rails we have to use capture! # If we are using Slim without a framework (Plain Tilt), # you can just yield to get the captured block. set_var.call(defined?(::Rails) ? capture(&block) : yield) end end ~~~ The helper can then be used in the Slim template as follows ~~~ slim / The captured_content variable must be known by the Binding beforehand. = capture_to_local captured_content=:captured_content p This will be captured in the variable captured_content = captured_content ~~~ Another interesting use case is to use an enumerable and capture for each element. The helper could look like this ~~~ ruby module Capture def capture(var, enumerable = nil, &block) value = enumerable ? enumerable.map(&block) : yield block.binding.eval("lambda {|x| #{var} = x }").call(value) nil end end ~~~ and it would be used as follows ~~~ slim - links = { 'https://slim-template.github.io' => 'The Slim Template Language' } = capture link_list=:link_list, links do |url, text| a href=url = text ~~~ Afterwards, `link_list` contains the captured content. ### Include helper If you want includes which are processed at compile time, you can take a look at [Include partials](doc/include.md). However you can also execute subtemplates at runtime (similar to Rails' `#render`). You have to write your own include helper: ~~~ ruby module Helpers def include_slim(name, options = {}, &block) Slim::Template.new("#{name}.slim", options).render(self, &block) end end ~~~ This helper can then be used as follows ~~~ slim nav = include_slim 'menu' section = include_slim 'content' ~~~ However this helper doesn't do any caching. You should therefore implement a more intelligent version of the helper which fits your purposes. You should also be aware that most frameworks already bring their own include helper, e.g. Rails has `render`. ## Text interpolation Use standard Ruby interpolation. The text will be html escaped by default, but you can avoid escaping by using double braces. ~~~ slim body h1 Welcome #{current_user.name} to the show. | Unescaped #{{content}} is also possible. ~~~ To escape the interpolation (i.e. render as is) ~~~ slim body h1 Welcome \#{current_user.name} to the show. ~~~ ## Embedded engines (Markdown, ...) Thanks to [Tilt](https://github.com/jeremyevans/tilt), Slim has extensive support for embedding other template engines. Examples: ~~~ slim coffee: square = (x) -> x * x markdown: #Header Hello from #{"Markdown!"} Second Line! p: markdown: Tag with **inline** markdown! ~~~ Supported engines: | Filter | Required gems | Type | Description | | ------ | ------------- | ---- | ----------- | | ruby: | none | Shortcut | Shortcut to embed ruby code | | javascript: | none | Shortcut | Shortcut to embed javascript code and wrap in script tag | | css: | none | Shortcut | Shortcut to embed css code and wrap in style tag | | sass: | sass-embedded or sassc or sass | Compile time | Embed sass code and wrap in style tag | | scss: | sass-embedded or sassc or sass | Compile time | Embed scss code and wrap in style tag | | less: | less | Compile time | Embed less css code and wrap in style tag | | coffee: | coffee-script | Compile time | Compile coffee script code and wrap in script tag | | markdown: | redcarpet/rdiscount/kramdown | Compile time + Interpolation | Compile markdown code and interpolate #\{variables} in text | | textile: | redcloth | Compile time + Interpolation | Compile textile code and interpolate #\{variables} in text | | rdoc: | rdoc | Compile time + Interpolation | Compile rdoc code and interpolate #\{variables} in text | The embedded engines can be configured in Slim by setting the options directly on the `Slim::Embedded` filter. Example: ~~~ ruby Slim::Embedded.options[:markdown] = {auto_ids: false} ~~~ You can also specify HTML attributes for the following embedded engines: * Javascript * CSS * CoffeeScript * LESS * SASS * SCSS Example: ~~~ scss scss class="myClass": $color: #f00; body { color: $color; } ~~~ This will generate the following HTML: ~~~ html ~~~ ## Configuring Slim Slim and the underlying [Temple](https://github.com/judofyr/temple) framework are highly configurable. The way how you configure Slim depends a bit on the compilation mechanism (Rails or [Tilt](https://github.com/rtomayko/tilt)). It is always possible to set default options per `Slim::Engine` class. This can be done in Rails' environment files. For instance, in config/environments/development.rb you probably want: ### Default options ~~~ ruby # Indent html for pretty debugging and do not sort attributes Slim::Engine.set_options pretty: true, sort_attrs: false ~~~ You can also access the option hash directly: ~~~ ruby Slim::Engine.options[:pretty] = true ~~~ ### Setting options at runtime There are two ways to set options at runtime. For Tilt templates (`Slim::Template`) you can set the options when you instantiate the template: ~~~ ruby Slim::Template.new('template.slim', optional_option_hash).render(scope) ~~~ The other possibility is to set the options per thread which is interesting mostly for Rails: ~~~ ruby Slim::Engine.with_options(option_hash) do # Any Slim engines which are created here use the option_hash # For example in Rails: render :page, layout: true end ~~~ You have to be aware that the compiled engine code and the options are cached per template in Rails and you cannot change the option afterwards. ~~~ ruby # First render call Slim::Engine.with_options(pretty: true) do render :page, layout: true end # Second render call Slim::Engine.with_options(pretty: false) do render :page, layout: true # :pretty is still true because it is cached end ~~~ ### Available options The following options are exposed by the `Slim::Engine` and can be set with `Slim::Engine.set_options`. There are a lot of them but the good thing is, that Slim checks the configuration keys and reports an error if you try to use an invalid configuration key. | Type | Name | Default | Purpose | | ---- | ---- | ------- | ------- | | String | :file | nil | Name of parsed file, set automatically by Slim::Template | | Integer | :tabsize | 4 | Number of white spaces per tab (used by the parser) | | String | :encoding | "utf-8" | Set encoding of template | | String | :default_tag | "div" | Default tag to be used if tag name is omitted | | Hash | :shortcut | \{'.' => {attr: 'class'}, '#' => {attr: 'id'}} | Attribute shortcuts | | Hash | :code_attr_delims | \{'(' => ')', '[' => ']', '{' => '}'} | Attribute delimiters for Ruby code attributes | | Hash | :attr_list_delims | \{'(' => ')', '[' => ']', '{' => '}'} | Attribute list delimiter | | Array<Symbol,String> | :enable_engines | nil (All enabled) | List of enabled embedded engines (whitelist) | | Array<Symbol,String> | :disable_engines | nil (None disabled) | List of disabled embedded engines (blacklist) | | Boolean | :disable_capture | false (true in Rails) | Disable capturing in blocks (blocks write to the default buffer | | Boolean | :disable_escape | false | Disable automatic escaping of strings | | Boolean | :use_html_safe | false (true in Rails) | Use String#html_safe? from ActiveSupport (Works together with :disable_escape) | | Symbol | :format | :xhtml | HTML output format (Possible formats :html, :xhtml, :xml) | | String | :attr_quote | '"' | Character to wrap attributes in html (can be ' or ") | | Hash | :merge_attrs | \{'class' => ' '} | Joining character used if multiple html attributes are supplied (e.g. class="class1 class2") | | Array<String> | :hyphen_attrs | %w(data) | Attributes which will be hyphenated if a Hash is given (e.g. data={a_foo:1,b:2} will render as data-a_foo="1" data-b="2") | | Boolean | :hyphen_underscore_attrs | false | Attributes that have underscores in their names will be hyphenated (e.g. data={a_foo:1,b_bar:2} will render as data-a-foo="1" data-b-bar="2") | | Boolean | :sort_attrs | true | Sort attributes by name | | Symbol | :js_wrapper | nil | Wrap javascript by :comment, :cdata or :both. You can also :guess the wrapper based on :format. | | Boolean | :pretty | false | Pretty HTML indenting, only block level tags are indented (This is slower!) | | String | :indent | ' ' | Indentation string | | Boolean | :streaming | false (true in Rails, see below how to disable it!) | Enable output streaming, improves the perceived performance | | Class | :generator | Temple::Generators::StringBuffer/ RailsOutputBuffer | Temple code generator (default generator generates string buffer) | | String | :buffer | '_buf' ('@output_buffer' in Rails) | Variable used for buffer | | String | :splat_prefix | '*' | Prefix used for splat attributes | There are more options which are supported by the Temple filters but which are not exposed and are not officially supported. You have to take a look at the Slim and Temple code for that. ### Option priority and inheritance For developers who know more about Slim and Temple architecture it is possible to override default options at different positions. Temple uses an inheritance mechanism to allow subclasses to override options of the superclass. The option priorities are as follows: 1. `Slim::Template` options passed at engine instantiation 2. `Slim::Template.options` 3. `Slim::Engine.thread_options`, `Slim::Engine.options` 5. Parser/Filter/Generator `thread_options`, `options` (e.g `Slim::Parser`, `Slim::Compiler`) It is also possible to set options for superclasses like `Temple::Engine`. But this will affect all temple template engines then. ~~~ ruby Slim::Engine < Temple::Engine Slim::Compiler < Temple::Filter ~~~ ## Plugins Slim currently provides plugins for logic less mode, includes and I18n. See the plugin documentation. * [Logic less mode](doc/logic_less.md) * [Include partials](doc/include.md) * [Translator/I18n](doc/translator.md) * [Smart text mode](doc/smart.md) ## Framework support ### Tilt Slim uses [Tilt](https://github.com/jeremyevans/tilt) to compile the generated code. If you want to use the Slim template directly, you can use the Tilt interface. ~~~ ruby Tilt.new['template.slim'].render(scope) Slim::Template.new('template.slim', optional_option_hash).render(scope) Slim::Template.new(optional_option_hash) { source }.render(scope) ~~~ The optional option hash can have to options which were documented in the section above. The scope is the object in which the template code is executed. ### Sinatra ~~~ ruby require 'sinatra' require 'slim' get('/') { slim :index } __END__ @@ index doctype html html head title Sinatra With Slim body h1 Slim Is Fun! ~~~ ### Rails Rails generators are provided by [slim-rails](https://github.com/slim-template/slim-rails). slim-rails is not necessary to use Slim in Rails though. Just install Slim and add it to your Gemfile with `gem 'slim'`. Then just use the .slim extension and you're good to go. #### Streaming HTTP streaming is enabled by default if you use a Rails version which supports it. However you have to be aware that streaming only improves the perceived performance. The rendering time in total will increase. If you want to disable it use: ~~~ ruby Slim::RailsTemplate.set_options streaming: false ~~~ ### Angular2 Slim now supports Angular2 syntax. But you need to set some configuration options: #### `splat_prefix` option This option tells parser what syntax to use for splat attributes. Default value is asterisk: `splat_prefix: '*'` Asterisk is also used in Angular2 for structural directives such as `*ngIf` and others, so default configuration causes a conflict between slim and angular2 syntax. There are two ways to resolve it: * Set `splat_prefix` to any custom value, double asterisk, for example: `splat_prefix: '**'`. Now structural directives should work as expected. Remember that now splat attributes should be written with new custom prefix before them. * Use alternative directive syntax without asterisk. #### Attribute delimeters Angular and slim both uses brackets in their syntax. So there are also two ways: * Use alternative syntax for binding (`bind-...` and so on) * Limit attribute delimeters to curly braces only: ``` code_attr_delims: { '{' => '}', }, attr_list_delims: { '{' => '}', }, ``` Now you can use something like this: ``` h1{ #var (bind1)="test" [bind2]="ok" [(bind3)]="works?" *ngIf="expr" *ngFor="expression" } {{it works}} ``` Will be compiled to: ```

    {{it works}}

    ``` ## Tools ### Slim Command 'slimrb' The gem 'slim' comes with the small tool 'slimrb' to test Slim from the command line.
    $ slimrb --help
    Usage: slimrb [options]
        -s, --stdin                      Read input from standard input instead of an input file
            --trace                      Show a full traceback on error
        -c, --compile                    Compile only but do not run
        -e, --erb                        Convert to ERB
            --rails                      Generate rails compatible code (Implies --compile)
        -r, --require library            Load library or plugin with -r slim/plugin
        -p, --pretty                     Produce pretty html for debugging purposes
        -o, --option name=code           Set slim option
        -l, --locals Hash|YAML|JSON      Set local variables
        -h, --help                       Show this message
        -v, --version                    Print version
    
    Start 'slimrb', type your code and press Ctrl-d to send EOF. In Windows Command Prompt press Ctrl-z, Enter to send EOF. Example usage:
    $ slimrb
    markdown:
      First paragraph.
    
      Second paragraph.
    
      * one
      * two
      * three
    
    //Enter Ctrl-d
    <p>First paragraph </p>
    
    <p>Second paragraph </p>
    
    <ul>
    <li>one</li>
    <li>two</li>
    <li>three</li>
    </ul>
    
    ### Syntax Highlighters There are plugins for various text editors (including the most important ones - Vim, Emacs and Textmate): * [Vim](https://github.com/slim-template/vim-slim) * [Emacs](https://github.com/slim-template/emacs-slim) * [Textmate / Sublime Text](https://github.com/slim-template/ruby-slim.tmbundle) * [Espresso text editor](https://github.com/slim-template/Slim-Sugar) * [Coda](https://github.com/slim-template/Coda-2-Slim.mode) * [Atom](https://github.com/slim-template/language-slim) * VS Code ([Official marketplace](https://marketplace.visualstudio.com/items?itemName=sianglim.slim), [Open VSX registry](https://open-vsx.org/extension/sianglim/slim)) ### Template Converters (HAML, ERB, ...) * Slim can be converted to ERB using `slimrb` or `Slim::ERBConverter' which are both included in the Slim gem * [Haml2Slim converter](https://github.com/slim-template/haml2slim) * [ERB2Slim, HTML2Slim converter](https://github.com/slim-template/html2slim) ## Testing ### Benchmarks *Yes, Slim is one of the fastest Ruby template engines out there! In production mode Slim is nearly as fast as Erubis (which is the fastest template engine). But we would be happy if you chose Slim also for any other reason, we assure you performance will not be an obstacle.* Run the benchmarks with `rake bench`. You can add the option `slow` to run the slow parsing benchmark which needs more time. You can also increase the number of iterations. ~~~ $ rake bench slow=1 iterations=1000 ~~~ ### Test suite and continuous integration Slim provides an extensive test-suite based on minitest. You can run the tests with 'rake test' and the rails integration tests with 'rake test:rails'. We are currently experimenting with human-readable literate tests which are written as markdown files: [TESTS.md](test/literate/TESTS.md) Slim is working well on all major Ruby implementations: * Ruby 2.5 and newer * JRuby ## Contributing If you'd like to help improve Slim, clone the project with Git by running: ~~~ $ git clone git://github.com/slim-template/slim ~~~ Work your magic and then submit a pull request. We love pull requests! Please remember to keep the compatibility with Ruby versions 2.5 and newer. If you find the documentation lacking, help us out and update this README.md. If you don't have the time to work on Slim, but found something we should know about, please submit an issue. ## License Slim is released under the [MIT license](http://www.opensource.org/licenses/MIT). ## Authors * [Daniel Mendler](https://github.com/minad) (Lead developer) * [Andrew Stone](https://github.com/stonean) * [Fred Wu](https://github.com/fredwu) ## Donations and sponsoring If you want to support this project please visit the GitHub sponsors page. [![GitHub Sponsors](https://img.shields.io/github/sponsors/slim-template)](https://github.com/sponsors/slim-template) ## Related projects Template compilation framework: * [Temple](https://github.com/judofyr/temple) Framework support: * [Rails generators (slim-rails)](https://github.com/slim-template/slim-rails) * [slimkeyfy - Translation string extraction](https://github.com/phrase/slimkeyfy) Syntax highlighting: * [Vim](https://github.com/slim-template/vim-slim) * [Emacs](https://github.com/slim-template/emacs-slim) * [Textmate / Sublime Text](https://github.com/slim-template/ruby-slim.tmbundle) * [Espresso text editor](https://github.com/slim-template/Slim-Sugar) * [Coda](https://github.com/slim-template/Coda-2-Slim.mode) * [Atom](https://github.com/slim-template/language-slim) Static code analysis: * [Slim-Lint](https://github.com/sds/slim-lint) * [SublimeLinter-slim-lint](https://github.com/elstgav/SublimeLinter-slim-lint) Template Converters (HAML, ERB, ...): * [ERB 2 Slim](http://erb2slim.com/) * [Haml2Slim converter](https://github.com/slim-template/haml2slim) * [ERB2Slim, HTML2Slim converter](https://github.com/slim-template/html2slim) Language ports/Similar languages: * [Sliq (Slim/Liquid integration)](https://github.com/slim-template/sliq) * [Slm (Slim port to Javascript)](https://github.com/slm-lang/slm) * [Coffee script plugin for Slim](https://github.com/yury/coffee-views) * [Clojure port of Slim](https://github.com/chaslemley/slim.clj) * [Hamlet.rb (Similar template language)](https://github.com/gregwebs/hamlet.rb) * [Plim (Python port of Slim)](https://github.com/2nd/plim) * [Skim (Slim for Javascript)](https://github.com/jfirebaugh/skim) * [Emblem.js (Javascript, similar to Slim)](https://github.com/machty/emblem.js) * [Hamlit (High performance Haml implementation, based on Temple like Slim)](https://github.com/k0kubun/hamlit) * [Faml (Faster Haml implementation, also using Temple like Slim)](https://github.com/eagletmt/faml) * [Haml (Older engine which inspired Slim)](https://github.com/haml/haml) * [Pug (Similar engine for javascript)](https://github.com/pugjs/pug) * [Sweet (Similar engine which also allows to write classes and functions)](https://github.com/joaomdmoura/sweet) * [Amber (Similar engine for Go)](https://github.com/eknkc/amber) * [Slang (Slim-inspired templating language for Crystal)](https://github.com/jeromegn/slang) slim-5.2.1/slim.gemspec0000644000004100000410000000272514572524745015051 0ustar www-datawww-datarequire File.dirname(__FILE__) + '/lib/slim/version' require 'date' Gem::Specification.new do |s| s.name = 'slim' s.version = Slim::VERSION s.date = Date.today.to_s s.authors = ['Daniel Mendler', 'Andrew Stone', 'Fred Wu'] s.email = ['mail@daniel-mendler.de', 'andy@stonean.com', 'ifredwu@gmail.com'] s.summary = 'Slim is a template language.' s.description = 'Slim is a template language whose goal is reduce the syntax to the essential parts without becoming cryptic.' s.homepage = 'https://slim-template.github.io/' s.license = 'MIT' s.metadata = { "bug_tracker_uri" => "https://github.com/slim-template/slim/issues", "changelog_uri" => "https://github.com/slim-template/slim/blob/main/CHANGES", "documentation_uri" => "https://rubydoc.info/gems/slim/frames", "homepage_uri" => "https://slim-template.github.io/", "source_code_uri" => "https://github.com/slim-template/slim", "wiki_uri" => "https://github.com/slim-template/slim/wiki", "funding_uri" => "https://github.com/sponsors/slim-template" } s.files = `git ls-files`.split("\n") s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) } s.require_paths = %w(lib) s.required_ruby_version = '>= 2.5.0' s.add_runtime_dependency('temple', ['~> 0.10.0']) s.add_runtime_dependency('tilt', ['>= 2.1.0']) end