dryml 1.3.3 → 1.4.0.pre2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. data/Gemfile +6 -0
  2. data/README +2 -0
  3. data/Rakefile +2 -1
  4. data/VERSION +1 -1
  5. data/cucumber.yml +9 -0
  6. data/dryml.gemspec +4 -2
  7. data/features/cookbook/01_simple_page_templates.feature +44 -0
  8. data/features/cookbook/02_defining_simple_tags.feature +375 -0
  9. data/features/cookbook/03_implicit_context.feature +229 -0
  10. data/features/cookbook/04_tag_attributes.feature +120 -0
  11. data/features/cookbook/05_repeated_and_optional_content.feature +241 -0
  12. data/features/cookbook/06_pseudo_parameters.feature +191 -0
  13. data/features/cookbook/07_nested_parameters.feature +147 -0
  14. data/features/cookbook/08_customizing_tags.feature +307 -0
  15. data/features/cookbook/09_aliasing_tags.feature +50 -0
  16. data/features/cookbook/10_polymorphic_tags.feature +168 -0
  17. data/features/cookbook/11_wrapping_content.feature +57 -0
  18. data/features/cookbook/12_local_and_scoped_variables.feature +102 -0
  19. data/features/doctest_examples.feature +187 -0
  20. data/features/merge_params.feature +36 -0
  21. data/features/replace_parameters.feature +21 -0
  22. data/features/static_tags.feature +91 -0
  23. data/features/step_definitions/contexts.rb +25 -0
  24. data/features/step_definitions/dom_comparison.rb +10 -0
  25. data/features/step_definitions/rendering.rb +21 -0
  26. data/features/support/env.rb +32 -0
  27. data/features/support/models/author.rb +18 -0
  28. data/features/support/models/blog_post.rb +37 -0
  29. data/features/support/models/discussion.rb +15 -0
  30. data/features/support/models/post.rb +12 -0
  31. data/features/support/strip_formatter.rb +14 -0
  32. data/lib/dryml/dryml_builder.rb +4 -14
  33. data/lib/dryml/dryml_doc.rb +6 -1
  34. data/lib/dryml/helper.rb +17 -1
  35. data/lib/dryml/part_context.rb +12 -15
  36. data/lib/dryml/railtie/template_handler.rb +1 -3
  37. data/lib/dryml/railtie.rb +1 -0
  38. data/lib/dryml/taglib.rb +24 -30
  39. data/lib/dryml/template.rb +32 -86
  40. data/lib/dryml/template_environment.rb +40 -17
  41. data/lib/dryml.rb +22 -11
  42. data/taglibs/core.dryml +18 -12
  43. data/taglibs/dryml.dryml +3 -0
  44. metadata +97 -56
@@ -0,0 +1,168 @@
1
+ Feature: Polymorphic tags
2
+
3
+ Scenario: Using a polymorphic tag
4
+ Given a file named "example_taglib.dryml" with:
5
+ """
6
+ <def tag="card" polymorphic>
7
+ <div class="card" merge-attrs>
8
+ <h3 param="heading"><%= h this.to_s %></h3>
9
+ <div param="body"></div>
10
+ </div>
11
+ </def>
12
+
13
+ <def tag="card" for="BlogPost">
14
+ <card merge>
15
+ <heading: param><a href="#{this.url}"><%= this.title %></a></heading:>
16
+ <body: param><do:author><%= this.name %></do></body:>
17
+ </card>
18
+ </def>
19
+ """
20
+ And a file named "example.dryml" with:
21
+ """
22
+ <card />
23
+ """
24
+ When I include the taglib "example_taglib"
25
+ And the current context is a blog post
26
+ And I render "example.dryml"
27
+ Then the output DOM should be:
28
+ """
29
+ <div class="card">
30
+ <h3 class="heading"><a href="/blog_posts/1">A Blog Post</a></h3>
31
+ <div class="body">Nobody</div>
32
+ </div>
33
+ """
34
+
35
+ Scenario: Using a polymorphic tag for a subclass
36
+ Given a file named "example_taglib.dryml" with:
37
+ """
38
+ <def tag="card" polymorphic>
39
+ <div class="card" merge-attrs>
40
+ <h3 param="heading"><%= h this.to_s %></h3>
41
+ <div param="body"></div>
42
+ </div>
43
+ </def>
44
+
45
+ <def tag="card" for="BlogPost">
46
+ <card merge>
47
+ <heading: param><a href="#{this.url}"><%= this.title %></a></heading:>
48
+ <body: param><do:author><%= this.name %></do></body:>
49
+ </card>
50
+ </def>
51
+ """
52
+ And a file named "example.dryml" with:
53
+ """
54
+ <card />
55
+ """
56
+ When I include the taglib "example_taglib"
57
+ And the current context is a special blog post
58
+ And I render "example.dryml"
59
+ Then the output DOM should be:
60
+ """
61
+ <div class="card">
62
+ <h3 class="heading"><a href="/special_blog_posts/1">A Blog Post</a></h3>
63
+ <div class="body">Nobody</div>
64
+ </div>
65
+ """
66
+
67
+
68
+ Scenario: Using a polymorphic tag for a subclass with a customized tag (fails)
69
+ issue 779 / https://github.com/tablatom/hobo/commit/aceb7afc384287b19e59ebb94020a2c509143c76
70
+ Given a file named "example_taglib.dryml" with:
71
+ """
72
+ <def tag="card" polymorphic>
73
+ <div class="card" merge-attrs>
74
+ <h3 param="heading"><%= h this.to_s %></h3>
75
+ <div param="body"></div>
76
+ </div>
77
+ </def>
78
+
79
+ <def tag="card" for="BlogPost">
80
+ <card merge>
81
+ <heading: param><a href="#{this.url}"><%= this.title %></a></heading:>
82
+ <body: param><do:author><%= this.name %></do></body:>
83
+ </card>
84
+ </def>
85
+
86
+ <def tag="card" for="SpecialBlogPost">
87
+ <card class="special" for-type="BlogPost" merge/>
88
+ </def>
89
+ """
90
+ And a file named "example.dryml" with:
91
+ """
92
+ <card class="more_special" />
93
+ """
94
+ When I include the taglib "example_taglib"
95
+ And the current context is a special blog post
96
+ And I render "example.dryml"
97
+ Then the output DOM should be:
98
+ """
99
+ <div class="card special more_special">
100
+ <h3 class="heading"><a href="/special_blog_posts/1">A Blog Post</a></h3>
101
+ <div class="body">Nobody</div>
102
+ </div>
103
+ """
104
+
105
+ Scenario: using call-tag to call a polymorphic tag
106
+ Given a file named "example_taglib.dryml" with:
107
+ """
108
+ <def tag="card" polymorphic>
109
+ <div class="card" merge-attrs>
110
+ <h3 param="heading"><%= h this.to_s %></h3>
111
+ <div param="body"></div>
112
+ </div>
113
+ </def>
114
+
115
+ <def tag="card" for="BlogPost">
116
+ <card merge>
117
+ <heading: param><a href="#{this.url}"><%= this.title %></a></heading:>
118
+ <body: param><do:author><%= this.name %></do></body:>
119
+ </card>
120
+ </def>
121
+ """
122
+ And a file named "example.dryml" with:
123
+ """
124
+ <call-tag tag="card" />
125
+ """
126
+ When I include the taglib "example_taglib"
127
+ And the current context is a blog post
128
+ And I render "example.dryml"
129
+ Then the output DOM should be:
130
+ """
131
+ <div class="card">
132
+ <h3 class="heading"><a href="/blog_posts/1">A Blog Post</a></h3>
133
+ <div class="body">Nobody</div>
134
+ </div>
135
+ """
136
+
137
+ Scenario: using call-tag to call a polymorphic tag with an explicit type (fails)
138
+ Given a file named "example_taglib.dryml" with:
139
+ """
140
+ <def tag="card" polymorphic>
141
+ <div class="card" merge-attrs>
142
+ <h3 param="heading"><%= h this.to_s %></h3>
143
+ <div param="body"></div>
144
+ </div>
145
+ </def>
146
+
147
+ <def tag="card" for="BlogPost">
148
+ <card merge>
149
+ <heading: param><a href="#{this.url}"><%= this.title %></a></heading:>
150
+ <body: param><do:author><%= this.name %></do></body:>
151
+ </card>
152
+ </def>
153
+ """
154
+ And a file named "example.dryml" with:
155
+ """
156
+ <call-tag tag="card" for-type="BlogPost" />
157
+ """
158
+ When I include the taglib "example_taglib"
159
+ And the current context is a special blog post
160
+ And I render "example.dryml"
161
+ Then the output DOM should be:
162
+ """
163
+ <div class="card">
164
+ <h3 class="heading"><a href="/special_blog_posts/1">A Blog Post</a></h3>
165
+ <div class="body">Nobody</div>
166
+ </div>
167
+ """
168
+
@@ -0,0 +1,57 @@
1
+ Feature: Wrapping content
2
+
3
+ Background:
4
+ Given a file named "example_taglib.dryml" with:
5
+ """
6
+ <def tag="card">
7
+ <div class="card" merge-attrs>
8
+ <h3 param="heading"><%= this.name %></h3>
9
+ <div param="body"></div>
10
+ </div>
11
+ </def>
12
+ """
13
+
14
+ Scenario: wrapping content inside a parameter
15
+ Given a file named "example.dryml" with:
16
+ """
17
+ <card>
18
+ <heading:><a href="#{this.url}"><param-content for="heading"/></a></heading:>
19
+ </card>
20
+ """
21
+ When I include the taglib "example_taglib"
22
+ And the current context is a blog post
23
+ And I render "example.dryml"
24
+ Then the output DOM should be:
25
+ """
26
+ <div class="card">
27
+ <h3 class="heading"><a href="/blog_posts/1">A Blog Post</a></h3>
28
+ <div class="body"></div>
29
+ </div>
30
+ """
31
+
32
+ Scenario: wrapping content outside a parameter
33
+ Given a file named "example.dryml" with:
34
+ """
35
+ <card>
36
+ <heading: replace>
37
+ <div class="header">
38
+ <heading: restore/>
39
+ <p>ID: <%= this.id %></p>
40
+ </div>
41
+ </heading:>
42
+ </card>
43
+ """
44
+ When I include the taglib "example_taglib"
45
+ And the current context is a blog post
46
+ And I render "example.dryml"
47
+ Then the output DOM should be:
48
+ """
49
+ <div class="card">
50
+ <div class="header">
51
+ <h3 class="heading">A Blog Post</h3>
52
+ <p>ID: 1</p>
53
+ </div>
54
+ <div class="body"></div>
55
+ </div>
56
+ """
57
+
@@ -0,0 +1,102 @@
1
+ Feature: Local and scoped variables
2
+
3
+ Scenario: local variables
4
+ Given a file named "example.dryml" with:
5
+ """
6
+ <% erb_local = 'Hello World' %>
7
+ <set dryml-local="Hello World" />
8
+ <p><%= erb_local %></p>
9
+ <p><%= dryml_local %></p>
10
+ """
11
+ When I render "example.dryml"
12
+ Then the output DOM should be:
13
+ """
14
+ <p>Hello World</p>
15
+ <p>Hello World</p>
16
+ """
17
+
18
+ Scenario: scoped variables
19
+ Given a file named "example_taglib.dryml" with:
20
+ """
21
+ <def tag="show-the-var">
22
+ <p><%= scope.the_var %></p>
23
+ </def>
24
+ """
25
+ And a file named "example.dryml" with:
26
+ """
27
+ <show-the-var />
28
+ <set-scoped the-var="foo">
29
+ <show-the-var />
30
+ <set-scoped the-var="bar">
31
+ <show-the-var />
32
+ </set-scoped>
33
+ <show-the-var />
34
+ </set-scoped>
35
+ <show-the-var />
36
+ """
37
+ When I include the taglib "example_taglib"
38
+ And I render "example.dryml"
39
+ Then the output DOM should be:
40
+ """
41
+ <p></p>
42
+ <p>foo</p>
43
+ <p>bar</p>
44
+ <p>foo</p>
45
+ <p></p>
46
+ """
47
+
48
+ Scenario: collecting content in a scoped var
49
+ Given a file named "example_taglib.dryml" with:
50
+ """
51
+ <def tag="tab-item" attrs="id, name">
52
+ <% scope.tabs_content << [id, parameters.default] %>
53
+ <li><a href="##{id}"><%= name %></a></li>
54
+ </def>
55
+
56
+ <def tag="tabs">
57
+ <set-scoped tabs-content="&[]">
58
+ <ul class="tabs">
59
+ <do param="default" />
60
+ </ul>
61
+ <repeat with="&scope.tabs_content">
62
+ <div id="#{this[0]}">
63
+ <%= this[1] %>
64
+ </div>
65
+ </repeat>
66
+ </set-scoped>
67
+ </def>
68
+ """
69
+ And a file named "example.dryml" with:
70
+ """
71
+ <tabs>
72
+ <tab-item id="foo" name="First Item">
73
+ <p>Foo Foo Foo</p>
74
+ </tab-item>
75
+ <tab-item id="bar" name="Second Item">
76
+ <p>Bar Bar Bar</p>
77
+ </tab-item>
78
+ <tab-item id="baz" name="Third Item">
79
+ <p>Baz Baz Baz</p>
80
+ </tab-item>
81
+ </tabs>
82
+ """
83
+ When I include the taglib "example_taglib"
84
+ And I render "example.dryml"
85
+ Then the output DOM should be:
86
+ """
87
+ <ul class="tabs">
88
+ <li><a href="#foo">First Item</a></li>
89
+ <li><a href="#bar">Second Item</a></li>
90
+ <li><a href="#baz">Third Item</a></li>
91
+ </ul>
92
+ <div id="foo">
93
+ <p>Foo Foo Foo</p>
94
+ </div>
95
+ <div id="bar">
96
+ <p>Bar Bar Bar</p>
97
+ </div>
98
+ <div id="baz">
99
+ <p>Baz Baz Baz</p>
100
+ </div>
101
+ """
102
+
@@ -0,0 +1,187 @@
1
+ Feature: Doctest examples
2
+
3
+ Scenario: plain text
4
+ Given a file named "doctest.dryml" with:
5
+ """
6
+ hi
7
+ """
8
+ When I render "doctest.dryml"
9
+ Then the output DOM should be:
10
+ """
11
+ hi
12
+ """
13
+
14
+ Scenario: single ERB output tag
15
+ Given a file named "doctest.dryml" with:
16
+ """
17
+ <%= this %>
18
+ """
19
+ And the local variable "this" has the value "hello"
20
+ When I render "doctest.dryml"
21
+ Then the output DOM should be:
22
+ """
23
+ hello
24
+ """
25
+
26
+ Scenario: if-else
27
+ Given a file named "doctest.dryml" with:
28
+ """
29
+ <if test="&true">
30
+ Hi
31
+ </if>
32
+ <else>
33
+ Bye
34
+ </else>
35
+ """
36
+ When I render "doctest.dryml"
37
+ Then the output DOM should be:
38
+ """
39
+ Hi
40
+ """
41
+
42
+ Scenario: repeating tags
43
+ Given a file named "doctest.dryml" with:
44
+ """
45
+ <repeat with="&[1,2,3]">
46
+ <span><%= this %></span>
47
+ </repeat>
48
+ """
49
+ When I render "doctest.dryml"
50
+ Then the output DOM should be:
51
+ """
52
+ <span>1</span>
53
+ <span>2</span>
54
+ <span>3</span>
55
+ """
56
+
57
+ Scenario: defining a tag with a default parameter
58
+ Given a file named "doctest.dryml" with:
59
+ """
60
+ <def tag="myp">
61
+ <p param="default"/>
62
+ </def>
63
+ <myp>Hi</myp>
64
+ """
65
+ When I render "doctest.dryml"
66
+ Then the output DOM should be:
67
+ """
68
+ <p>
69
+ Hi
70
+ </p>
71
+ """
72
+
73
+ Scenario: calling a tag using call-tag
74
+ Given a file named "doctest.dryml" with:
75
+ """
76
+ <def tag="myp">
77
+ <p param="default" />
78
+ </def>
79
+ <call-tag tag="myp">
80
+ Hi
81
+ </call-tag>
82
+ """
83
+ When I render "doctest.dryml"
84
+ Then the output DOM should be:
85
+ """
86
+ <p>
87
+ Hi
88
+ </p>
89
+ """
90
+
91
+ Scenario: wrapping content with a custom tag
92
+ Given a file named "doctest.dryml" with:
93
+ """
94
+ <def tag="myp">
95
+ <p param="default" />
96
+ </def>
97
+ <wrap tag="myp" when="&true">
98
+ img
99
+ </wrap>
100
+ """
101
+ When I render "doctest.dryml"
102
+ Then the output DOM should be:
103
+ """
104
+ <p>
105
+ img
106
+ </p>
107
+ """
108
+
109
+ Scenario: extending a tag (fails)
110
+ Given a file named "doctest_taglib.dryml" with:
111
+ """
112
+ <def tag="myp">
113
+ <p param="default" />
114
+ </def>
115
+ """
116
+ And a file named "doctest_extend.dryml" with:
117
+ """
118
+ <extend tag="myp">
119
+ <old-myp merge>
120
+ <default: replace>Hello <default restore /></default:>
121
+ </old-myp>
122
+ </extend>
123
+ """
124
+ And a file named "doctest.dryml" with:
125
+ """
126
+ <myp>New World</myp>
127
+ """
128
+ When I include the taglib "doctest_taglib"
129
+ And I include the taglib "doctest_extend"
130
+ When I render "doctest.dryml"
131
+ Then the output DOM should be:
132
+ """
133
+ <p>Hello New World</p>
134
+ """
135
+
136
+ Scenario: extending a tag with a non-default param (fails)
137
+ Given a file named "doctest_taglib.dryml" with:
138
+ """
139
+ <def tag="myp">
140
+ <p param="foo" />
141
+ </def>
142
+ """
143
+ And a file named "doctest_extend.dryml" with:
144
+ """
145
+ <extend tag="myp">
146
+ <old-myp merge>
147
+ <foo:>
148
+ Hello <param-content for="foo" />
149
+ </foo:>
150
+ </old-myp>
151
+ </extend>
152
+ """
153
+ And a file named "doctest.dryml" with:
154
+ """
155
+ <myp><foo:>New World</foo:></myp>
156
+ """
157
+ When I include the taglib "doctest_taglib"
158
+ And I include the taglib "doctest_extend"
159
+ When I render "doctest.dryml"
160
+ Then the output DOM should be:
161
+ """
162
+ <p class="foo">Hello New World</p>
163
+ """
164
+
165
+ Scenario: param-content-restore from an output context
166
+ Given a file named "doctest_taglib.dryml" with:
167
+ """
168
+ <def tag="myp">
169
+ <p param="foo">World</p>
170
+ </def>
171
+ """
172
+ And a file named "doctest.dryml" with:
173
+ """
174
+ <myp>
175
+ <foo:>
176
+ Hello <param-content for="foo" />
177
+ </foo:>
178
+ </myp>
179
+ """
180
+ When I include the taglib "doctest_taglib"
181
+ When I render "doctest.dryml"
182
+ Then the output DOM should be:
183
+ """
184
+ <p class="foo">Hello World</p>
185
+ """
186
+
187
+
@@ -0,0 +1,36 @@
1
+ Feature: merge-params
2
+
3
+ Scenario: merge-params with a param name
4
+ Given a file named "doctest_taglib.dryml" with:
5
+ """
6
+ <def tag="myp">
7
+ <p param="foo">This is foo</p>
8
+ <p param="bar">This is bar</p>
9
+ </def>
10
+ """
11
+ And a file named "doctest_extend.dryml" with:
12
+ """
13
+ <extend tag="myp">
14
+ <old-myp merge-params="bar" />
15
+ </extend>
16
+ """
17
+ And a file named "doctest.dryml" with:
18
+ """
19
+ <myp>
20
+ <foo:>
21
+ New stuff
22
+ </foo:>
23
+ <bar:>
24
+ Brand-new bar
25
+ </bar:>
26
+ </myp>
27
+ """
28
+ When I include the taglib "doctest_taglib"
29
+ And I include the taglib "doctest_extend"
30
+ When I render "doctest.dryml"
31
+ Then the output DOM should be:
32
+ """
33
+ <p class="foo">This is foo</p>
34
+ <p class="bar">Brand-new bar</p>
35
+ """
36
+
@@ -0,0 +1,21 @@
1
+ Feature: replace parameters
2
+
3
+ Scenario: simple replace parameter
4
+ Given a file named "doctest_taglib.dryml" with:
5
+ """
6
+ <def tag="myp">
7
+ <p param="foo" />
8
+ </def>
9
+ """
10
+ And a file named "doctest.dryml" with:
11
+ """
12
+ <myp><foo: replace>Hello World</foo:></myp>
13
+ """
14
+ When I include the taglib "doctest_taglib"
15
+ When I render "doctest.dryml"
16
+ Then the output DOM should be:
17
+ """
18
+ Hello World
19
+ """
20
+
21
+
@@ -0,0 +1,91 @@
1
+ Feature: Static tags render correctly
2
+
3
+ Scenario: Static tag with static attributes
4
+
5
+ Given a file named "static_tag.dryml" with:
6
+ """
7
+ <div class="foo">
8
+ FOO
9
+ </div>
10
+ """
11
+ When I render "static_tag.dryml"
12
+ Then the output DOM should be:
13
+ """
14
+ <div class="foo">
15
+ FOO
16
+ </div>
17
+ """
18
+
19
+ Scenario: Static tag with an interpolated attribute
20
+
21
+ Given a file named "static_tag.dryml" with:
22
+ """
23
+ <% some_var = 'foo' %>
24
+ <div class="#{some_var}">
25
+ FOO
26
+ </div>
27
+ """
28
+ When I render "static_tag.dryml"
29
+ Then the output DOM should be:
30
+ """
31
+ <div class="foo">
32
+ FOO
33
+ </div>
34
+ """
35
+
36
+ Scenario: define tags that are used in Rapid
37
+ Given a file named "static_tag.dryml" with:
38
+ """
39
+ <html lang="en">
40
+ <head>
41
+ <link rel="stylesheet" href="foo" />
42
+ </head>
43
+ <body>
44
+ <header>
45
+ <a href="something" target="_blank">Link text</a>
46
+ </header>
47
+ <section class="content">
48
+ <table width="100%">
49
+ <tr>
50
+ <td>FOO</td>
51
+ <td>BAR</td>
52
+ </tr>
53
+ </table>
54
+ </section>
55
+ <footer>
56
+ <form action="wut">
57
+ <input type="text" name="some_field" />
58
+ <submit value="Submit" />
59
+ </form>
60
+ </footer>
61
+ </body>
62
+ </html>
63
+ """
64
+ When I render "static_tag.dryml"
65
+ Then the output DOM should be:
66
+ """
67
+ <html lang="en">
68
+ <head>
69
+ <link rel="stylesheet" href="foo" />
70
+ </head>
71
+ <body>
72
+ <header>
73
+ <a href="something" target="_blank">Link text</a>
74
+ </header>
75
+ <section class="content">
76
+ <table width="100%">
77
+ <tr>
78
+ <td>FOO</td>
79
+ <td>BAR</td>
80
+ </tr>
81
+ </table>
82
+ </section>
83
+ <footer>
84
+ <form action="wut">
85
+ <input type="text" name="some_field" />
86
+ <submit value="Submit" />
87
+ </form>
88
+ </footer>
89
+ </body>
90
+ </html>
91
+ """
@@ -0,0 +1,25 @@
1
+ When /^the current context is a blog post$/ do
2
+ @locals ||= {}
3
+ @locals[:this] = BlogPost.new
4
+ end
5
+
6
+ When /^the current context is a special blog post$/ do
7
+ @locals ||= {}
8
+ @locals[:this] = SpecialBlogPost.new
9
+ end
10
+
11
+ When /^the current context is an array$/ do
12
+ @locals ||= {}
13
+ @locals[:this] = %w(foo bar baz blam mumble)
14
+ end
15
+
16
+ When /^the current context is a list of discussions$/ do
17
+ @locals ||= {}
18
+ discussions = []
19
+ (1..3).each do |i|
20
+ posts = (1..i).to_a.map { |x| Post.new(:title => "Post #{x+3*i}") }
21
+ discussions << Discussion.new(:name => "Discussion #{i}", :posts => posts)
22
+ end
23
+ @locals[:this] = discussions
24
+ end
25
+