eyemask 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,9 @@
1
+ require "eyemask/liquid/blockquote"
2
+ require "eyemask/liquid/indent"
3
+ require "eyemask/liquid/markdown"
4
+ require "eyemask/liquid/parse"
5
+ require "eyemask/liquid/relevel"
6
+ require "eyemask/liquid/strip"
7
+ require "eyemask/liquid/uml"
8
+ require "eyemask/liquid/highlight"
9
+ require "eyemask/liquid/note"
@@ -0,0 +1,13 @@
1
+ require 'liquid'
2
+
3
+ module Eyemask
4
+ module Liquid
5
+ module Blockquote
6
+ def blockquote(input)
7
+ input.gsub(/^/, ">")
8
+ end
9
+ end
10
+ end
11
+ end
12
+
13
+ Liquid::Template.register_filter(Eyemask::Liquid::Blockquote)
@@ -0,0 +1,22 @@
1
+ require 'liquid'
2
+ require 'rouge'
3
+
4
+ module Eyemask
5
+ module Liquid
6
+ module Highlight
7
+
8
+ def highlight(input, lang)
9
+ formatter = Rouge::Formatters::HTML.new(inline_theme: "github")
10
+ lexer = Rouge::Lexer.find(lang)
11
+ unless lexer.nil?
12
+ formatter.format(lexer.lex(input))
13
+ else
14
+ "<pre class=\"docstring\">#{input}</pre>"
15
+ end
16
+ end
17
+
18
+ end
19
+ end
20
+ end
21
+
22
+ Liquid::Template.register_filter(Eyemask::Liquid::Highlight)
@@ -0,0 +1,21 @@
1
+ require 'liquid'
2
+
3
+ module Eyemask
4
+ module Liquid
5
+ class Indent < ::Liquid::Block
6
+
7
+ def initialize(tag_name, markup, tokens)
8
+ super
9
+ @indentation = markup.to_i
10
+ end
11
+
12
+ def render(context)
13
+ prefix = " " * @indentation
14
+ super.gsub(/^/, prefix)
15
+ end
16
+
17
+ end
18
+ end
19
+ end
20
+
21
+ Liquid::Template.register_tag('indent', Eyemask::Liquid::Indent)
@@ -0,0 +1,22 @@
1
+ require 'liquid'
2
+ require 'redcarpet'
3
+ require 'rouge/plugins/redcarpet'
4
+
5
+ module Eyemask
6
+ module Liquid
7
+ module Markdown
8
+ class HTML < Redcarpet::Render::HTML
9
+ include Rouge::Plugins::Redcarpet
10
+ include Redcarpet::Render::SmartyPants
11
+ end
12
+
13
+ MARKDOWN = Redcarpet::Markdown.new(HTML, autolink: true, tables: true, footnotes: false, fenced_code_blocks:true, no_intra_emphasis: true, superscript: true, underline: true, highlight: true)
14
+
15
+ def markdown(input)
16
+ MARKDOWN.render(input)
17
+ end
18
+ end
19
+ end
20
+ end
21
+
22
+ Liquid::Template.register_filter(Eyemask::Liquid::Markdown)
@@ -0,0 +1,25 @@
1
+ require 'liquid'
2
+
3
+ module Eyemask
4
+ module Liquid
5
+ class Note < ::Liquid::Block
6
+
7
+ MARKDOWN = Redcarpet::Markdown.new(Eyemask::Liquid::Markdown::HTML.new(hard_wrap: true), autolink: true, tables: true, footnotes: false, fenced_code_blocks:true, no_intra_emphasis: true, superscript: true, underline: true, highlight: true)
8
+
9
+ def initialize(tag_name, markup, tokens)
10
+ super
11
+ params = markup.split(" ")
12
+ @note_class = params.first
13
+ @note_data = params.drop(1).join(" ")
14
+ end
15
+
16
+ def render(context)
17
+ content = MARKDOWN.render(::Liquid::Template.parse(super).render(context.registers))
18
+ "<aside class=\"note note-#{@note_class}\" data-note=\"#{@note_data}\">#{content}</aside>"
19
+ end
20
+
21
+ end
22
+ end
23
+ end
24
+
25
+ Liquid::Template.register_tag('note', Eyemask::Liquid::Note)
@@ -0,0 +1,15 @@
1
+ require 'liquid'
2
+
3
+ module Eyemask
4
+ module Liquid
5
+ module Parse
6
+
7
+ def parse(input)
8
+ ::Liquid::Template.parse(input).render(@context.registers)
9
+ end
10
+
11
+ end
12
+ end
13
+ end
14
+
15
+ Liquid::Template.register_filter(Eyemask::Liquid::Parse)
@@ -0,0 +1,29 @@
1
+ require 'liquid'
2
+
3
+ module Eyemask
4
+ module Liquid
5
+ module RelevelFilter
6
+ def relevel(input, markup)
7
+ hash_prefix = "\#" * markup.to_i
8
+ input.gsub(/^(#+) (.*)$/, "#{hash_prefix}\\1 \\2")
9
+ end
10
+ end
11
+
12
+ class Relevel < ::Liquid::Block
13
+
14
+ def initialize(tag_name, markup, tokens)
15
+ super
16
+ @num_up = markup.to_i
17
+ end
18
+
19
+ def render(context)
20
+ hash_prefix = "\#" * @num_up
21
+ super.gsub(/^(#+) (.*)$/, "#{hash_prefix}\\1 \\2")
22
+ end
23
+
24
+ end
25
+ end
26
+ end
27
+
28
+ Liquid::Template.register_filter(Eyemask::Liquid::RelevelFilter)
29
+ Liquid::Template.register_tag('relevel', Eyemask::Liquid::Relevel)
@@ -0,0 +1,13 @@
1
+ require 'liquid'
2
+
3
+ module Eyemask
4
+ module Liquid
5
+ module Strip
6
+ def strip(input)
7
+ input.strip
8
+ end
9
+ end
10
+ end
11
+ end
12
+
13
+ Liquid::Template.register_filter(Eyemask::Liquid::Strip)
@@ -0,0 +1,72 @@
1
+ require 'liquid'
2
+ require 'base64'
3
+
4
+ module Eyemask
5
+
6
+ module Liquid
7
+
8
+ class Uml < ::Liquid::Block
9
+
10
+ def initialize(tag_name, markup, tokens)
11
+ @tag_name = tag_name
12
+ super
13
+ end
14
+
15
+ def render(context)
16
+ "\n\n<figure><img class=\"resolution-#{resolution}\" src=\"#{get_data_uri_for_diagram(super)}\"></figure>\n\n"
17
+ end
18
+
19
+ def get_data_uri_for_diagram(diagram)
20
+ data = parse_diagram(diagram)
21
+ "data:image/png;base64,#{Base64.encode64(data)}"
22
+ end
23
+
24
+ def parse_diagram(diagram)
25
+ output = ""
26
+ IO.popen(["plantuml", "-pipe"], 'r+') do |f|
27
+ f.puts("@start#{diagram_type}")
28
+ case diagram_type
29
+ when "uml"
30
+ f.puts("skinparam backgroundColor transparent")
31
+ f.puts("skinparam shadowing false")
32
+ f.puts("skinparam dpi 300")
33
+ end
34
+ f.puts(diagram)
35
+ f.puts("@end#{diagram_type}")
36
+ f.close_write
37
+ output = f.read
38
+ end
39
+ output
40
+ end
41
+
42
+ def resolution
43
+ case diagram_type
44
+ when "uml"
45
+ "print"
46
+ else
47
+ "normal"
48
+ end
49
+ end
50
+
51
+ def diagram_type
52
+ case @tag_name
53
+ when "uml"
54
+ "uml"
55
+ when "ditaa"
56
+ "ditaa"
57
+ when "salt"
58
+ "salt"
59
+ else
60
+ "uml"
61
+ end
62
+ end
63
+
64
+ end
65
+
66
+ end
67
+ end
68
+
69
+ Liquid::Template.register_tag('uml', Eyemask::Liquid::Uml)
70
+ Liquid::Template.register_tag('ditaa', Eyemask::Liquid::Uml)
71
+ Liquid::Template.register_tag('salt', Eyemask::Liquid::Uml)
72
+ Liquid::Template.register_tag('dot', Eyemask::Liquid::Uml)
@@ -0,0 +1,3 @@
1
+ module Eyemask
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,41 @@
1
+ ---
2
+ title: {{title}}
3
+ {%if subtitle %}subtitle: {{subtitle}} {% endif %}
4
+ {%unless authors.empty %}author: {% for author in authors %}{{author}}{%unless forloop.last %}, {% endunless %}{% endfor %} {% endunless %}
5
+ ---
6
+
7
+ # Features
8
+
9
+ {% if contents == empty %}
10
+ No features have been specified.
11
+ {% endif %}
12
+
13
+ {% for feature in contents %}
14
+ ## {{feature.name}}
15
+
16
+ {% relevel 2 %}
17
+ {{feature.description | uml }}
18
+ {% endrelevel %}
19
+
20
+ {% for scenario in feature.elements %}
21
+ ### {{ scenario.name }}
22
+
23
+ {% relevel 3 %}
24
+ {{scenario.description | uml }}
25
+ {% endrelevel %}
26
+
27
+ {% for step in scenario.steps %}
28
+ - **{{step.keyword | strip}}** {{step.name}}
29
+ {% if step.doc_string %}{% indent 4 %}
30
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
31
+ {{ step.doc_string.value }}
32
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
33
+ {% endindent %}{% endif %}
34
+ {% if step.rows %}{% indent 4 %}{% for row in step.rows %}
35
+ | {% for cell in row.cells %}{{ cell }} | {% endfor %}{% if forloop.first %}
36
+ |{% for i in row.cells %}---|{% endfor %}{% endif %}{% endfor %}{% endindent %}{% endif %}
37
+ {% endfor %}
38
+
39
+ {% endfor %}
40
+
41
+ {% endfor %}
@@ -0,0 +1,574 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>{{title}}: {{subtitle}}</title>
5
+ <link href='http://fonts.googleapis.com/css?family=Merriweather:400,300,300italic,700,400italic,700italic,900,900italic&subset=latin,latin-ext' rel='stylesheet' type='text/css'>
6
+ <link href='http://fonts.googleapis.com/css?family=Source+Code+Pro:200,300,400,500,600,700,900' rel='stylesheet' type='text/css'>
7
+ <style>
8
+ /***** BASELINE *****/
9
+ html {
10
+ font-size: 11pt;
11
+ }
12
+
13
+ body {
14
+ font-family: 'Merriweather', serif;
15
+ font-size: 2.4rem;
16
+ line-height: 1.6875;
17
+ }
18
+
19
+ h1,h2,h3,h4 {
20
+ font-family: 'Merriweather', serif;
21
+ margin: 0 0 16.875pt 0;
22
+ }
23
+
24
+ h1 {
25
+ font-size: 37.125pt;
26
+ font-weight: normal;
27
+ }
28
+
29
+ h2 {
30
+ font-size: 24.75pt;
31
+ font-weight: normal;
32
+ }
33
+
34
+ h3 {
35
+ font-size: 16.5pt;
36
+ font-weight: normal;
37
+ }
38
+
39
+ h4 {
40
+ font-size: 11pt;
41
+ }
42
+
43
+ title {
44
+ string-set: title content();
45
+ }
46
+
47
+ .resolution-print {
48
+ prince-image-resolution: 300dpi;
49
+ }
50
+
51
+ /***** COVER *****/
52
+
53
+ #cover {
54
+ padding-top: 33.75pt;
55
+ }
56
+
57
+ #cover .client {
58
+ border-bottom: 1pt solid #999;
59
+ margin-bottom: 0 !important;
60
+ letter-spacing: 0.2em;
61
+ font-family: 'Merriweather', serif;
62
+ font-size: 24.75pt;
63
+ font-variant: small-caps;
64
+ }
65
+
66
+ .doctitle {
67
+ font-family: 'Merriweather', serif;
68
+ font-size: 37.125pt;
69
+ font-weight: normal;
70
+ border-bottom: 1pt solid #999;
71
+ margin-top: 0 !important;
72
+ }
73
+
74
+ .version {
75
+ font-family: 'Merriweather', serif;
76
+ font-size: 16.875pt;
77
+ font-variant: small-caps;
78
+ font-weight: normal;
79
+ }
80
+
81
+ .authors::before {
82
+ display: block;
83
+ content: "Compiled by:";
84
+ font-size: 7.26pt;
85
+ font-weight: 200;
86
+ font-variant: small-caps;
87
+ letter-spacing: 0.2em;
88
+ }
89
+ .authors {
90
+ font-family: 'Merriweather', serif;
91
+ font-size: 11pt;
92
+ list-style: none;
93
+ padding: 0;
94
+ margin: 0;
95
+ }
96
+
97
+ .authors li {
98
+ padding-bottom: 2.6pt;
99
+ font-weight: 600;
100
+ }
101
+
102
+ .logo {
103
+ position: absolute;
104
+ bottom: 0;
105
+ }
106
+
107
+ /***** TABLE OF CONTENTS *****/
108
+
109
+ #frontmatter .chapter h2 {
110
+ string-set: header content();
111
+ }
112
+
113
+ .toc ol {
114
+ list-style: none;
115
+ }
116
+
117
+ .toc a {
118
+ text-decoration: none;
119
+ }
120
+
121
+ .toc a[href]::after {
122
+ content: leader(".") target-counter(attr(href), page)
123
+ }
124
+
125
+ .toc ol a[href]::before {
126
+ content: target-counter(attr(href), feature) ". ";
127
+ }
128
+
129
+ .toc ol ol a[href]::before {
130
+ content: target-counter(attr(href), feature) "." target-counter(attr(href), scenario) ". ";
131
+ }
132
+
133
+ /***** PARTS *****/
134
+
135
+ .part {
136
+ counter-increment: part;
137
+ counter-reset: feature 1 scenario;
138
+ }
139
+ .part h1 {
140
+ text-align: center;
141
+ margin-top: 88mm;
142
+ font-weight: normal;
143
+ font-variant: small-caps;
144
+ }
145
+
146
+ .part h1::before {
147
+ display: block;
148
+ margin: 0 auto;
149
+ font-size: 24.75pt;
150
+ font-weight: 200;
151
+ content: counter(part, upper-roman);
152
+ }
153
+
154
+ /***** FEATURES *****/
155
+
156
+ .feature + .feature {
157
+ counter-increment: feature;
158
+ counter-reset: scenario;
159
+ }
160
+
161
+ .feature header h2 {
162
+ page-break-after: avoid;
163
+ margin-top: 33.75pt;
164
+ font-weight: normal;
165
+ string-set: header "Feature " counter(feature) ". " content();
166
+ }
167
+
168
+ .feature h2::before {
169
+ page-break-after: avoid;
170
+ display: block;
171
+ margin: 0 auto;
172
+ font-size: 16.5pt;
173
+ font-variant: small-caps;
174
+ content: "Feature " counter(feature) "." ;
175
+ letter-spacing: 0.2em;
176
+ }
177
+
178
+ .scenario {
179
+ counter-increment: scenario;
180
+ margin-bottom: 16.875pt;
181
+ }
182
+ .scenario h3 {
183
+ page-break-after: avoid;
184
+ font-weight: normal;
185
+ }
186
+
187
+ .scenario h3::before {
188
+ page-break-after: avoid;
189
+ display: block;
190
+ margin: 0 auto;
191
+ font-size: 11pt;
192
+ font-variant: small-caps;
193
+ content: "Scenario " counter(feature) "." counter(scenario) ". ";
194
+ letter-spacing: 0.2em;
195
+ }
196
+
197
+ .steps ol {
198
+ margin-left: 0;
199
+ list-style: lower-roman;
200
+ }
201
+
202
+ .steps ol li p {
203
+ margin-top: 0 !important;
204
+ }
205
+
206
+ .steps ol li p:only-child {
207
+ margin: 0;
208
+ }
209
+
210
+ .highlight {
211
+ page-break-before: avoid;
212
+ }
213
+ .docstring {
214
+ page-break-before: avoid;
215
+ }
216
+
217
+ .steptable {
218
+ page-break-before: avoid;
219
+ }
220
+
221
+ /***** MATTER *****/
222
+
223
+ #cover {
224
+ page: blank;
225
+ }
226
+
227
+ #frontmatter {
228
+ page: frontmatter;
229
+ page-break-before: right;
230
+ }
231
+
232
+ #mainmatter {
233
+ page: auto;
234
+ counter-reset: page 1;
235
+ }
236
+
237
+ /***** SECTIONS *****/
238
+ .part {
239
+ page-break-before: right;
240
+ page: blank;
241
+ }
242
+ .feature {
243
+ page-break-before: right;
244
+ page: auto;
245
+ }
246
+
247
+ /***** SYNTAX HIGHLIGHTING *****/
248
+
249
+ .highlight table {
250
+ border: none;
251
+ margin: 0;
252
+ }
253
+
254
+ .highlight tr {
255
+ border: none;
256
+ }
257
+
258
+ .highlight pre {
259
+ background: none;
260
+ border: none;
261
+ margin: 0;
262
+ }
263
+
264
+ /***** PAGES *****/
265
+
266
+ @page {
267
+ size: a4;
268
+ margin: 33mm 23.33mm 66mm 46.66mm;
269
+ }
270
+
271
+ @page :left {
272
+ margin: 33mm 23.33mm 66mm 46.66mm;
273
+ @top-left {
274
+ font: 11pt 'Merriweather', serif;
275
+ content: string(title);
276
+ font-variant: small-caps;
277
+ vertical-align: bottom;
278
+ padding-bottom: 2em;
279
+ }
280
+
281
+ @bottom-left {
282
+ font: 11pt 'Merriweather', serif;
283
+ content: counter(page);
284
+ padding-top: 2em;
285
+ vertical-align: top;
286
+ }
287
+ }
288
+
289
+ @page :right {
290
+ margin: 33mm 46.66mm 66mm 23.33mm;
291
+ @top-right {
292
+ font: 11pt 'Merriweather', serif;
293
+ font-variant: small-caps;
294
+ content: string(header, first);
295
+ vertical-align: bottom;
296
+ padding-bottom: 2em;
297
+ }
298
+
299
+ @bottom-right {
300
+ font: 11pt 'Merriweather', serif;
301
+ content: counter(page);
302
+ text-align: right;
303
+ vertical-align: top;
304
+ padding-top: 2em;
305
+ }
306
+ }
307
+
308
+ @page frontmatter :left {
309
+ @top-left {
310
+ font: 11pt 'Merriweather', serif;
311
+ font-variant: small-caps;
312
+ content: string(title);
313
+ vertical-align: bottom;
314
+ padding-bottom: 2em;
315
+ }
316
+
317
+ @bottom-left {
318
+ font: 11pt 'Merriweather', serif;
319
+ content: counter(page, lower-roman);
320
+ padding-top: 2em;
321
+ vertical-align: top;
322
+ }
323
+ }
324
+
325
+ @page frontmatter :right {
326
+ @top-right {
327
+ font: 11pt 'Merriweather', serif;
328
+ font-variant: small-caps;
329
+ content: string(header, first);
330
+ vertical-align: bottom;
331
+ padding-bottom: 2em;
332
+ }
333
+
334
+ @bottom-right {
335
+ font: 11pt 'Merriweather', serif;
336
+ content: counter(page, lower-roman);
337
+ text-align: right;
338
+ vertical-align: top;
339
+ padding-top: 2em;
340
+ }
341
+ }
342
+
343
+ @page blank :left {
344
+ @top-left { content: normal }
345
+ @bottom-left { content: normal }
346
+ }
347
+
348
+ @page blank :right {
349
+ @top-right { content: normal }
350
+ @bottom-right { content: normal }
351
+ }
352
+
353
+ /***** OTHER *****/
354
+ /* ---- Tables ---- */
355
+
356
+ /* A clean textbook-like style with horizontal lines above and below and under
357
+ the header. Rows highlight on hover to help scanning the table on screen.
358
+ */
359
+
360
+ table
361
+ {
362
+ border-collapse: collapse;
363
+ border-spacing: 0; /* IE 6 */
364
+
365
+ border-bottom: 2pt solid #000;
366
+ border-top: 2pt solid #000; /* The caption on top will not have a bottom-border */
367
+
368
+ /* Center */
369
+ margin-left: auto;
370
+ margin-right: auto;
371
+ margin-bottom: 16.875pt;
372
+ }
373
+
374
+ thead /* Entire table header */
375
+ {
376
+ border-bottom: 1pt solid #000;
377
+ background-color: #ccc; /* Does this BG print well? */
378
+ }
379
+
380
+ tr.header /* Each header row */
381
+ {
382
+ }
383
+
384
+ tbody /* Entire table body */
385
+ {
386
+ }
387
+
388
+ /* Table body rows */
389
+
390
+ tr {
391
+ border-bottom: 0.5pt solid #000;
392
+ }
393
+ .steptable tbody tr:nth-child(2n)
394
+ {
395
+ /*background-color: #eee;*/
396
+ }
397
+
398
+
399
+ td, th /* Table cells and table header cells */
400
+ {
401
+ vertical-align: top; /* Word */
402
+ vertical-align: baseline; /* Others */
403
+ padding-left: 0.5em;
404
+ padding-right: 0.5em;
405
+ padding-top: 0.2em;
406
+ padding-bottom: 0.2em;
407
+ }
408
+
409
+ /* Code */
410
+
411
+ /* code {
412
+ display: block;
413
+ padding: 0.5em;
414
+ background-color: #ccc;
415
+ } */
416
+
417
+ pre,code,.highlight {
418
+ font-family: "Source Code Pro";
419
+ background-color: #eee;
420
+ }
421
+
422
+ pre, code
423
+ {
424
+ /* BEGIN word wrap */
425
+ /* Need all the following to word wrap instead of scroll box */
426
+ /* This will override the overflow:auto if present */
427
+ white-space: pre-wrap; /* css-3 */
428
+ white-space: -moz-pre-wrap !important; /* Mozilla, since 1999 */
429
+ white-space: -pre-wrap; /* Opera 4-6 */
430
+ white-space: -o-pre-wrap; /* Opera 7 */
431
+ word-wrap: break-word; /* Internet Explorer 5.5+ */
432
+ /* END word wrap */
433
+ }
434
+
435
+ pre, .highlight /* Code blocks */
436
+ {
437
+ /* Distinguish pre blocks from other text by more than the font with a background tint. */
438
+ padding: 0.5em; /* Since we have a background color */
439
+ border-radius: 5px; /* Softens it */
440
+ /* Give it a some definition */
441
+ border: 1px solid #ccc;
442
+ /* Set it off left and right, seems to look a bit nicer when we have a background */
443
+ margin-left: 0.5em;
444
+ margin-right: 0.5em;
445
+ }
446
+
447
+ figure img {
448
+ display: block;
449
+ margin-left: auto;
450
+ margin-right: auto;
451
+ }
452
+ </style>
453
+ </head>
454
+ <body>
455
+ <section id="cover">
456
+ <p class="client">{{title}}</p>
457
+ <h1 class="doctitle">{{subtitle}}</h1>
458
+ {% unless authors.empty %}<ul class="authors">
459
+ {% for author in authors %}<li>{{author}}</li>
460
+ {% endfor %}
461
+ </ul>{% endunless %}
462
+
463
+ {% if logo %}<div class="logo">
464
+ <img alt="" src="{{logo}}">
465
+ </div>{% endif %}
466
+
467
+ </section>
468
+
469
+ <section id="frontmatter">
470
+ <section class="chapter no-toc">
471
+ <header>
472
+ <h2>Table of Features</h2>
473
+ </header>
474
+
475
+ <nav class="toc table-of-features">
476
+ <ol class="features-list">
477
+ {% for feature in contents %}
478
+ <li><a href="#{{feature.id}}">{{feature.name}}</a>
479
+ <ol class="scenarios-list">
480
+ {% for scenario in feature.elements %}
481
+ <li><a href="#{{scenario.id}}">{{scenario.name}}</a></li>
482
+ {% endfor %}
483
+ </ol>
484
+ </li>
485
+ {% endfor %}
486
+ </ol>
487
+ </nav>
488
+
489
+ </section>
490
+
491
+ <section id="mainmatter">
492
+ <section class="part" id="features">
493
+ <header>
494
+ <h1>Features</h1>
495
+ </header>
496
+
497
+ {% for feature in contents %}
498
+ <section class="feature" id="{{feature.id}}">
499
+ <header>
500
+ <h2>{{feature.name}}</h2>
501
+ </header>
502
+
503
+ <div class="description">
504
+ {{ feature.description | parse | relevel:2 | markdown }}
505
+ </div>
506
+
507
+ {% for scenario in feature.elements %}
508
+ <section class="scenario" id="{{scenario.id}}">
509
+ <header>
510
+ <h3>{{scenario.name}}</h3>
511
+ </header>
512
+
513
+ <div class="description">
514
+ {{ scenario.description | parse | relevel:3 | markdown }}
515
+ </div>
516
+
517
+ {% unless scenario.steps.empty %}
518
+ <section class="steps">
519
+ {% unless scenario.description=="" %}
520
+ <header>
521
+ <h4>Steps</h4>
522
+ </header>
523
+ {% endunless %}
524
+ <ol>
525
+ {% for step in scenario.steps %}
526
+ <li class="step {{step.keyword | strip | downcase}}">
527
+ <p>
528
+ <strong class="keyword">{{step.keyword | strip}}</strong> {{step.name}}
529
+ </p>
530
+
531
+ {% if step.doc_string %}
532
+ {{ step.doc_string.value | highlight: step.doc_string.content_type }}
533
+ {% endif %}
534
+
535
+ {% if step.rows %}
536
+ <table class="steptable">
537
+ <thead>
538
+ <tr>
539
+ {% for cell in step.rows[0].cells %}
540
+ <th>{{ cell }}</th>
541
+ {% endfor %}
542
+ </tr>
543
+ </thead>
544
+ <tbody>
545
+ {% for row in step.rows %}
546
+ {% unless forloop.first %}
547
+ <tr>
548
+ {% for cell in row.cells %}
549
+ <td>{{ cell | escape_once }}</td>
550
+ {% endfor %}
551
+ </tr>
552
+ {% endunless %}
553
+ {% endfor %}
554
+ </tbody>
555
+ </table>
556
+ {% endif %}
557
+
558
+ </li>
559
+ {% endfor %}
560
+ </ol>
561
+ </section> <!-- Steps -->
562
+ {% endunless %}
563
+
564
+ </section> <!-- Scenario -->
565
+ {% endfor %}
566
+
567
+ </section> <!-- Feature -->
568
+ {% endfor %}
569
+
570
+ </section> <!-- Part -->
571
+
572
+ </section>
573
+ </body>
574
+ </html>