Permalink
Browse files

Merge pull request #739 from govorov/angular2

Possible solution for Angular2 syntax support
  • Loading branch information...
2 parents 365abe4 + c2b9225 commit 53723a3b7cabb0cdf0d6d2215c361e21d6fb3cb4 @minad minad committed on GitHub Nov 28, 2016
Showing with 206 additions and 3 deletions.
  1. +44 −1 README.md
  2. +7 −2 lib/slim/parser.rb
  3. +155 −0 test/core/test_splat_prefix_option.rb
View
@@ -559,6 +559,8 @@ This renders as:
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
@@ -967,7 +969,7 @@ There are a lot of them but the good thing is, that Slim checks the configuratio
| 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.
@@ -1047,6 +1049,47 @@ performance. The rendering time in total will increase. If you want to disable i
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:
+```
+<h1 #var="" (bind1)="test" [bind2]="ok" [(bind3)]="works?" *ngIf="expr" *ngFor="expression">
+ {{it works}}
+</h1>
+```
+
## Tools
### Slim Command 'slimrb'
View
@@ -18,7 +18,8 @@ class Parser < Temple::Parser
shortcut: {
'#' => { attr: 'id' },
'.' => { attr: 'class' }
- }
+ },
+ splat_prefix: '*'
class SyntaxError < StandardError
attr_reader :error, :file, :line, :lineno, :column
@@ -413,9 +414,13 @@ def parse_attributes(attributes)
end_re = /\A\s*#{Regexp.escape delimiter}/
end
+ splat_prefix = Regexp.escape(options[:splat_prefix])
+ splat_regexp_source = '\A\s*' << splat_prefix << '(?=[^\s]+)'
+ @splat_attrs_regexp = Regexp.new(splat_regexp_source)
+
while true
case @line
- when /\A\s*\*(?=[^\s]+)/
+ when @splat_attrs_regexp
# Splat attribute
@line = $'
attributes << [:slim, :splat, parse_ruby_code(delimiter)]
@@ -0,0 +1,155 @@
+require '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 '<div a="The letter a" b="The letter b"></div><p a="The letter a" b="The letter b"></p>', source, options(prefix)
+ end
+ end
+
+ def test_shortcut_splat
+ prefixes.each do |prefix|
+ source = %Q{
+#{prefix}hash This is my title
+}
+
+ assert_html '<div a="The letter a" b="The letter b">This is my title</div>', source, options(prefix)
+ end
+ end
+
+ def test_splat
+ prefixes.each do |prefix|
+ source = %Q{
+h1 #{prefix}hash class=[] This is my title
+}
+
+ assert_html '<h1 a="The letter a" b="The letter b">This is my title</h1>', source, options(prefix)
+ end
+ end
+
+ def test_closed_splat
+ prefixes.each do |prefix|
+ source = %Q{
+#{prefix}hash /
+}
+
+ assert_html '<div a="The letter a" b="The letter b" />', 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 '<h1 id="title">This is my title</h1>', 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 '<div id="test">This is my title</div>', source, options(prefix)
+ end
+ end
+
+ def test_closed_splat_tag
+ prefixes.each do |prefix|
+ source = %Q{
+#{prefix}hash /
+}
+
+ assert_html '<div a="The letter a" b="The letter b" />', 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 '<div a="The letter a" b="The letter b" id="myid">This is my title</div>', 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 '<div a="The letter a" b="The letter b" class="myclass">This is my title</div>', 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 '<div a="The letter a" b="The letter b" class="myclass" id="myid">This is my title</div>', 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 '<div a="The letter a" b="The letter b" class="myclass secondclass x y z" id="myid">This is my title</div>', 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 '<div disabled="" nonempty="">This is my title</div>', 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 '<div a="1" b="2" c="3" d="4" e="5" f="6">This is my title</div>', 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 '<h1 a="The letter a" b="The letter b" data-id="123">This is my title</h1>', source, options(prefix)
+ end
+ end
+
+end

0 comments on commit 53723a3

Please sign in to comment.