macros4cuke 0.5.15 → 0.5.16
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +83 -37
- data/.ruby-version +1 -1
- data/.travis.yml +10 -9
- data/CHANGELOG.md +9 -0
- data/Gemfile +3 -4
- data/LICENSE.txt +1 -1
- data/README.md +0 -1
- data/Rakefile +1 -1
- data/appveyor.yml +14 -9
- data/examples/demo/features/step_definitions/step_defs.rb +1 -1
- data/examples/demo/features/support/env.rb +20 -29
- data/examples/demo/features/support/use_macros4cuke.rb +1 -4
- data/examples/i18n/fr/features/step_definitions/demo_steps.rb +1 -2
- data/examples/i18n/fr/features/step_definitions/macro_steps_fr.rb +3 -7
- data/examples/i18n/fr/features/support/use_macros4cuke.rb +1 -4
- data/examples/i18n/nl/features/step_definitions/demo_steps.rb +1 -3
- data/examples/i18n/nl/features/step_definitions/macro_steps_nl.rb +2 -3
- data/examples/i18n/nl/features/support/use_macros4cuke.rb +1 -4
- data/lib/macro_steps.rb +2 -2
- data/lib/macros4cuke/application.rb +0 -1
- data/lib/macros4cuke/cli/cmd-line.rb +2 -3
- data/lib/macros4cuke/coll-walker-factory.rb +0 -1
- data/lib/macros4cuke/constants.rb +1 -1
- data/lib/macros4cuke/formatter/all-notifications.rb +15 -15
- data/lib/macros4cuke/formatter/to-gherkin.rb +1 -2
- data/lib/macros4cuke/formatting-service.rb +0 -2
- data/lib/macros4cuke/macro-collection.rb +0 -3
- data/lib/macros4cuke/macro-step-support.rb +0 -2
- data/lib/macros4cuke/macro-step.rb +1 -6
- data/lib/macros4cuke/templating/engine.rb +5 -8
- data/lib/macros4cuke/templating/section.rb +0 -3
- data/spec/macros4cuke/application_spec.rb +2 -2
- data/spec/macros4cuke/cli/cmd-line_spec.rb +3 -3
- data/spec/macros4cuke/formatting-service_spec.rb +4 -11
- data/spec/macros4cuke/macro-collection_spec.rb +1 -1
- data/spec/macros4cuke/macro-step-support_spec.rb +1 -1
- data/spec/macros4cuke/macro-step_spec.rb +6 -6
- data/spec/macros4cuke/templating/engine_spec.rb +5 -5
- data/spec/macros4cuke/templating/section_spec.rb +1 -1
- data/spec/macros4cuke/use-sample-collection.rb +0 -1
- metadata +9 -23
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7fa6f77c0a5b399e4370a1c32cce2f010d8c6e51
|
4
|
+
data.tar.gz: ca6cec55d6b05408130568b2e2622ef72346ee5e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7c267ffa13b3a2962631fceb384d84a73b563560a4814e489a375a65b0610a123ccfcc6cba8f6616180e29f2710ec7fd3e5e872f42e5f7d8cc194f783294da8a
|
7
|
+
data.tar.gz: c5cb85a360829982b46ad8b98658e18203d79eac8c405b3c7ded5b9deaa8ad55d35042d466394554c05cb5770376c61a41f30dd7eb34fb976d57be4858e4de2a
|
data/.rubocop.yml
CHANGED
@@ -1,94 +1,140 @@
|
|
1
1
|
AllCops:
|
2
2
|
Exclude:
|
3
|
-
- 'examples/**/*'
|
4
3
|
- 'features/**/*'
|
4
|
+
- 'exp/**/*'
|
5
5
|
- 'gems/**/*'
|
6
6
|
- 'lab/**/*'
|
7
7
|
|
8
|
-
AbcSize:
|
9
|
-
Max: 45
|
10
|
-
|
11
8
|
# This is disabled because some demos use UTF-8
|
12
9
|
AsciiComments:
|
13
10
|
Enabled: false
|
14
|
-
|
11
|
+
|
15
12
|
Attr:
|
16
13
|
Enabled: false
|
17
|
-
|
14
|
+
|
18
15
|
BlockComments:
|
19
16
|
Enabled: false
|
20
|
-
|
17
|
+
|
21
18
|
CaseIndentation:
|
22
|
-
|
19
|
+
EnforcedStyle: end
|
23
20
|
IndentOneStep: true
|
24
21
|
|
25
22
|
# Rubocop enforces the use of is_a? instead of kind_of?
|
26
23
|
# Which is contrary to modelling practice.
|
27
24
|
ClassCheck:
|
28
25
|
Enabled: false
|
29
|
-
|
26
|
+
|
30
27
|
ClassLength:
|
31
28
|
Max: 250
|
32
|
-
CountComments: false
|
29
|
+
CountComments: false
|
33
30
|
|
34
|
-
ConstantName:
|
31
|
+
ConstantName:
|
35
32
|
Enabled: false
|
36
|
-
|
33
|
+
|
37
34
|
CyclomaticComplexity:
|
38
35
|
Enabled: false
|
39
|
-
|
40
|
-
DefWithParentheses:
|
36
|
+
|
37
|
+
DefWithParentheses:
|
41
38
|
Enabled: false
|
42
|
-
|
39
|
+
|
43
40
|
Documentation:
|
44
41
|
Enabled: false
|
45
|
-
|
42
|
+
|
46
43
|
EmptyLines:
|
47
|
-
Enabled: false
|
44
|
+
Enabled: false
|
48
45
|
|
49
46
|
Encoding:
|
50
47
|
Enabled: false
|
51
48
|
|
52
|
-
|
49
|
+
EndOfLine:
|
50
|
+
Enabled: false
|
51
|
+
# SupportedStyles: lf
|
52
|
+
|
53
|
+
|
54
|
+
IndentationWidth:
|
53
55
|
Enabled: false
|
54
56
|
|
55
|
-
|
57
|
+
Layout/BlockAlignment:
|
58
|
+
Enabled: false
|
59
|
+
|
60
|
+
Layout/ClosingHeredocIndentation:
|
56
61
|
Enabled: false
|
57
62
|
|
63
|
+
# Enabled after end of support of Rubies < 2.3
|
64
|
+
Layout/IndentHeredoc:
|
65
|
+
Enabled: false
|
66
|
+
|
67
|
+
Layout/SpaceInsideArrayLiteralBrackets:
|
68
|
+
Enabled: false
|
69
|
+
|
70
|
+
Metrics/AbcSize:
|
71
|
+
Max: 50
|
72
|
+
|
73
|
+
Metrics/BlockLength:
|
74
|
+
Max: 50
|
58
75
|
|
59
76
|
# Avoid methods longer than 50 lines of code
|
60
|
-
MethodLength:
|
77
|
+
Metrics/MethodLength:
|
78
|
+
Max: 50
|
79
|
+
CountComments: false
|
80
|
+
|
81
|
+
# Avoid modules longer than 200 lines of code
|
82
|
+
Metrics/ModuleLength:
|
83
|
+
CountComments: false
|
84
|
+
Max: 200
|
85
|
+
|
86
|
+
Metrics/PerceivedComplexity:
|
87
|
+
Enabled: true
|
61
88
|
Max: 50
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
89
|
+
|
90
|
+
# Disable this because it produces false negatives
|
91
|
+
Naming/HeredocDelimiterNaming:
|
92
|
+
Enabled: false
|
93
|
+
|
94
|
+
Naming/FileName:
|
95
|
+
Enabled: false
|
96
|
+
|
97
|
+
Naming/MethodName:
|
98
|
+
Enabled: false
|
99
|
+
|
100
|
+
Naming/UncommunicativeBlockParamName:
|
101
|
+
Enabled: false
|
102
|
+
|
103
|
+
Naming/UncommunicativeMethodParamName:
|
104
|
+
Enabled: false
|
105
|
+
|
68
106
|
NonNilCheck:
|
69
107
|
Enabled: false
|
70
108
|
|
71
109
|
NumericLiterals:
|
72
110
|
Enabled: false
|
111
|
+
|
112
|
+
RaiseArgs:
|
113
|
+
Enabled: false
|
114
|
+
|
115
|
+
RedundantReturn:
|
116
|
+
Enabled: false
|
117
|
+
|
118
|
+
Style/CommentedKeyword:
|
119
|
+
Enabled: false
|
73
120
|
|
74
|
-
|
75
|
-
|
121
|
+
Style/ConditionalAssignment:
|
122
|
+
Enabled: false
|
76
123
|
|
77
|
-
|
124
|
+
Style/Lambda:
|
78
125
|
Enabled: false
|
79
126
|
|
80
|
-
|
127
|
+
Style/MissingRespondToMissing:
|
81
128
|
Enabled: false
|
82
129
|
|
83
|
-
|
84
|
-
EnforcedStyle: mixed
|
85
|
-
AllowInnerSlashes: false
|
86
|
-
|
87
|
-
SpaceInsideBrackets:
|
130
|
+
Style/StderrPuts:
|
88
131
|
Enabled: false
|
89
132
|
|
90
133
|
TrailingWhitespace:
|
91
134
|
Enabled: false
|
92
|
-
|
135
|
+
|
93
136
|
VariableName:
|
94
|
-
Enabled: false
|
137
|
+
Enabled: false
|
138
|
+
|
139
|
+
VariableNumber:
|
140
|
+
Enabled: false
|
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
2.2.0
|
data/.travis.yml
CHANGED
@@ -1,14 +1,15 @@
|
|
1
1
|
language: ruby
|
2
2
|
rvm:
|
3
|
-
-
|
4
|
-
-
|
5
|
-
- 2.
|
6
|
-
- 2.
|
7
|
-
- 2.
|
8
|
-
- 2.
|
9
|
-
-
|
10
|
-
|
11
|
-
|
3
|
+
- 2.6.0
|
4
|
+
- 2.5.3
|
5
|
+
- 2.4.5
|
6
|
+
- 2.3.8
|
7
|
+
- 2.2.10
|
8
|
+
- 2.1.10
|
9
|
+
- 2.0.0-p648
|
10
|
+
- ruby-head
|
11
|
+
- jruby-9.1.9.0
|
12
|
+
- jruby-head
|
12
13
|
matrix:
|
13
14
|
allow_failures:
|
14
15
|
- rvm: ruby-head
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
### 0.5.16 / 2019-01-4
|
2
|
+
- Maintenance release.
|
3
|
+
|
4
|
+
* [CHANGE] Code re-styling to please Rubocop 0.62.0.
|
5
|
+
* [CHANGE] File `.travis.yml`: updated Ruby versions.
|
6
|
+
* [CHANGE] File `appveyor.yml` updated Ruby versions.
|
7
|
+
* [CHANGE] File `README.me` removal obsolete badge.
|
8
|
+
* [CHANGE] File `LICENSE.txt` Updated copyright years.
|
9
|
+
|
1
10
|
### 0.5.15 / 2016-12-21
|
2
11
|
* [NEW] File `appveyor.yml`: Added AppVeyor CI so that Macros4Cuke builds also
|
3
12
|
can be tested on Windows. This complements the Travis CI which runs on Linux.
|
data/Gemfile
CHANGED
@@ -1,10 +1,9 @@
|
|
1
1
|
source 'https://rubygems.org'
|
2
|
-
# Prevent Bundler to load the dependencies from our .gemspec file
|
3
2
|
|
4
|
-
gem 'cucumber',
|
3
|
+
gem 'cucumber', '~> 3.0'
|
5
4
|
|
6
5
|
group :development do
|
7
6
|
gem 'rake', '>= 10.0.0'
|
8
|
-
gem 'rspec', '
|
9
|
-
gem 'simplecov', '>= 0.
|
7
|
+
gem 'rspec', '~> 3.0'
|
8
|
+
gem 'simplecov', '>= 0.8.0'
|
10
9
|
end
|
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
@@ -8,7 +8,6 @@ _Extend Cucumber with macro-steps._
|
|
8
8
|
[![Windows Build status](https://ci.appveyor.com/api/projects/status/amsdudnqo1jqfody?svg=true)](https://ci.appveyor.com/project/famished-tiger/macros4cuke)
|
9
9
|
[![Code Climate](https://codeclimate.com/github/famished-tiger/Macros4Cuke.png)](https://codeclimate.com/github/famished-tiger/Macros4Cuke.png)
|
10
10
|
[![Gem Version](https://badge.fury.io/rb/macros4cuke.png)](http://badge.fury.io/rb/macros4cuke)
|
11
|
-
[![Dependency Status](https://gemnasium.com/famished-tiger/Macros4Cuke.png)](https://gemnasium.com/famished-tiger/Macros4Cuke)
|
12
11
|
[![License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat)](https://github.com/famished-tiger/Macros4Cuke/blob/master/LICENSE.txt)
|
13
12
|
|
14
13
|
__Macros4Cuke__ is a Cucumber extension that adds a macro facility for your Cucumber scenarios.
|
data/Rakefile
CHANGED
data/appveyor.yml
CHANGED
@@ -2,19 +2,24 @@ version: '{build}'
|
|
2
2
|
max_jobs: 3
|
3
3
|
environment:
|
4
4
|
matrix:
|
5
|
-
- Ruby_version:
|
6
|
-
- Ruby_version:
|
7
|
-
- Ruby_version:
|
8
|
-
- Ruby_version: 21-x64
|
9
|
-
- Ruby_version: 22
|
5
|
+
- Ruby_version: 25-x64
|
6
|
+
- Ruby_version: 24-x64
|
7
|
+
- Ruby_version: 23-x64
|
10
8
|
- Ruby_version: 22-x64
|
9
|
+
- Ruby_version: 21-x64
|
10
|
+
- Ruby_version: 200-x64
|
11
|
+
- Ruby_version: 25
|
12
|
+
- Ruby_version: 24
|
11
13
|
- Ruby_version: 23
|
12
|
-
- Ruby_version:
|
14
|
+
- Ruby_version: 22
|
15
|
+
- Ruby_version: 21
|
16
|
+
- Ruby_version: 200
|
17
|
+
|
13
18
|
install:
|
14
|
-
- cmd: >-
|
15
19
|
SET PATH=C:\Ruby%Ruby_version%\bin;%PATH%
|
20
|
+
bundle install --retry=3 --clean --force
|
16
21
|
|
17
|
-
bundle install --retry=3 --clean
|
18
22
|
build: off
|
23
|
+
|
19
24
|
test_script:
|
20
|
-
-
|
25
|
+
- bundle exec rake
|
@@ -1,37 +1,28 @@
|
|
1
1
|
# File: env.rb
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
#
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
#
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
# Replace every \" sequence by genuine "
|
23
|
-
unescaped = someText.gsub(/\\"/, '"')
|
24
|
-
$stderr.puts(unescaped)
|
25
|
-
end
|
26
|
-
|
27
|
-
|
28
|
-
end # class
|
29
|
-
|
3
|
+
module DemoMacros4Cuke # Use the module as a namespace
|
4
|
+
# Class created just for testing and demonstration purposes.
|
5
|
+
# Its instance, will record the output emitted by the steps.
|
6
|
+
class TracingWorld
|
7
|
+
# Will contain the text emitted by the steps
|
8
|
+
attr_reader(:trace_steps)
|
9
|
+
|
10
|
+
def initialize()
|
11
|
+
# Constructor
|
12
|
+
@trace_steps = []
|
13
|
+
end
|
14
|
+
|
15
|
+
# Write the given text to the error console
|
16
|
+
def show(someText)
|
17
|
+
# Replace every \" sequence by genuine "
|
18
|
+
unescaped = someText.gsub(/\\"/, '"')
|
19
|
+
$stderr.puts(unescaped)
|
20
|
+
end
|
21
|
+
end # class
|
30
22
|
end # module
|
31
23
|
|
32
24
|
# For testing purpose we override the default Cucumber behaviour
|
33
25
|
# making our world object an instance of the TracingWorld class
|
34
26
|
World { DemoMacros4Cuke::TracingWorld.new }
|
35
27
|
|
36
|
-
|
37
|
-
# End of file
|
28
|
+
# End of file
|
@@ -1,12 +1,9 @@
|
|
1
|
-
# encoding: utf-8 You should see a paragraph character: §
|
2
1
|
# File: use_macros4cuke.rb
|
3
2
|
# Purpose: Add the support for macros in Cucumber.
|
4
3
|
# This file is meant to be put next to the 'env.rb' file
|
5
4
|
# of your Cucumber project.
|
6
5
|
|
7
|
-
|
8
6
|
# Load modules, classes and step definitions from the macros4cuke gem
|
9
7
|
require 'macros4cuke/cucumber'
|
10
8
|
|
11
|
-
|
12
|
-
# End of file
|
9
|
+
# End of file
|
@@ -1,25 +1,21 @@
|
|
1
|
-
# encoding: utf-8
|
2
1
|
# "Traduction" en Français des macro-pas de Macros4Cuke
|
3
|
-
#
|
4
|
-
|
2
|
+
# Des définitions de pas faisant directement appel à l'API de Macros4Cuke
|
5
3
|
|
6
4
|
Etantdonné(/^que je crée le pas "(?:Soit|Quand|Alors) j(?:e |')\[((?:[^\\\]]|\\.)+)\](:?)" qui équivaut à:$/) do |macro_phrase, colon_capture, template|
|
7
5
|
use_table = (colon_capture == ':')
|
8
6
|
add_macro(macro_phrase, template, use_table)
|
9
7
|
end
|
10
8
|
|
11
|
-
|
12
9
|
Quand(/^j(?:e |')\[((?:[^\\\]]|\\.)+)\]$/) do |macro_phrase|
|
13
10
|
# This will call the macro with the given phrase
|
14
11
|
invoke_macro(macro_phrase)
|
15
12
|
end
|
16
13
|
|
17
|
-
|
18
14
|
Quand(/^j(?:e |')\[([^\]]+)\]:$/) do |macro_phrase, table_argument|
|
19
15
|
# Ensure that the second argument is of the correct type
|
20
16
|
unless table_argument.kind_of?(Cucumber::Ast::Table)
|
21
17
|
error_message = 'Ce pas doit avoir un tableau comme paramètre.'
|
22
|
-
|
18
|
+
raise(Macros4Cuke::DataTableNotFound, error_message)
|
23
19
|
end
|
24
20
|
|
25
21
|
# This will call the macro with the given phrase.
|
@@ -28,4 +24,4 @@ Quand(/^j(?:e |')\[([^\]]+)\]:$/) do |macro_phrase, table_argument|
|
|
28
24
|
invoke_macro(macro_phrase, table_argument.raw)
|
29
25
|
end
|
30
26
|
|
31
|
-
# End of file
|
27
|
+
# End of file
|
@@ -1,12 +1,9 @@
|
|
1
|
-
# encoding: utf-8 You should see a paragraph character: §
|
2
1
|
# File: use_macros4cuke.rb
|
3
2
|
# Purpose: Add the support for macros in Cucumber.
|
4
3
|
# This file is meant to be put next to the 'env.rb' file
|
5
4
|
# of your Cucumber project.
|
6
5
|
|
7
|
-
|
8
6
|
# Load modules, classes and step definitions from the macros4cuke gem
|
9
7
|
require 'macros4cuke/cucumber'
|
10
8
|
|
11
|
-
|
12
|
-
# End of file
|
9
|
+
# End of file
|
@@ -1,9 +1,7 @@
|
|
1
|
-
# encoding: utf-8
|
2
1
|
# Een paar stappen definities.
|
3
2
|
|
4
3
|
require 'stringio'
|
5
4
|
|
6
|
-
|
7
5
|
Als(/^ik "(.*?)" op het scherm afdruk$/) do |some_text|
|
8
6
|
$stderr.puts some_text
|
9
7
|
end
|
@@ -18,4 +16,4 @@ Dan(/^verwacht ik te zien:$/) do |result|
|
|
18
16
|
@output.string.should == result
|
19
17
|
end
|
20
18
|
|
21
|
-
# End of file
|
19
|
+
# End of file
|
@@ -1,4 +1,3 @@
|
|
1
|
-
# encoding: utf-8
|
2
1
|
# "Vertaling" in het Nederlands van macrostappen van Macros4Cuke
|
3
2
|
# Dit zijn stappen definities dat rechstreeks het API van Macros4Cuke gebruiken
|
4
3
|
|
@@ -19,7 +18,7 @@ Als(/^ik \[([^\]]+)\]:$/) do |macro_phrase, table_argument|
|
|
19
18
|
# Ensure that the second argument is of the correct type
|
20
19
|
unless table_argument.kind_of?(Cucumber::Ast::Table)
|
21
20
|
error_message = 'Deze stap vereist een tabel als parameter.'
|
22
|
-
|
21
|
+
raise(Macros4Cuke::DataTableNotFound, error_message)
|
23
22
|
end
|
24
23
|
|
25
24
|
# This will call the macro with the given phrase.
|
@@ -28,4 +27,4 @@ Als(/^ik \[([^\]]+)\]:$/) do |macro_phrase, table_argument|
|
|
28
27
|
invoke_macro(macro_phrase, table_argument.raw)
|
29
28
|
end
|
30
29
|
|
31
|
-
# End of file
|
30
|
+
# End of file
|
@@ -1,12 +1,9 @@
|
|
1
|
-
# encoding: utf-8 You should see a paragraph character: §
|
2
1
|
# File: use_macros4cuke.rb
|
3
2
|
# Purpose: Add the support for macros in Cucumber.
|
4
3
|
# This file is meant to be put next to the 'env.rb' file
|
5
4
|
# of your Cucumber project.
|
6
5
|
|
7
|
-
|
8
6
|
# Load modules, classes and step definitions from the macros4cuke gem
|
9
7
|
require 'macros4cuke/cucumber'
|
10
8
|
|
11
|
-
|
12
|
-
# End of file
|
9
|
+
# End of file
|
data/lib/macro_steps.rb
CHANGED
@@ -20,10 +20,10 @@ require_relative './macros4cuke/formatter/to-gherkin'
|
|
20
20
|
# The regexp has two capturing group: one for the phrase,
|
21
21
|
# a second for the terminating colon (:)
|
22
22
|
# The regular expression uses the /x option in order to split it in pieces
|
23
|
-
Given(
|
23
|
+
Given(/^I\sdefine\sthe\sstep\s" # Fixed part of defining step
|
24
24
|
(?:Given|When|Then|\*)\s # ... A keyword that starts the new step
|
25
25
|
I\s\[((?:[^\\\]]|\\.)+)\](:?) # ...I followed by text in square brackets
|
26
|
-
"\sto\smean
|
26
|
+
"\sto\smean:$/x) do |macro_phrase, colon_capture, template|
|
27
27
|
use_table = (colon_capture == ':')
|
28
28
|
add_macro(macro_phrase, template, use_table)
|
29
29
|
end
|
@@ -60,7 +60,6 @@ class Application
|
|
60
60
|
# Write file contents to file in binary mode in order to avoid eol
|
61
61
|
# consisting of CRLF
|
62
62
|
File.open(destination, 'wb') { |theFile| theFile.write(file_text) }
|
63
|
-
|
64
63
|
rescue Macros4Cuke::CmdLineError => exc
|
65
64
|
$stderr.puts exc.message
|
66
65
|
exit
|
@@ -23,7 +23,7 @@ class CmdLine
|
|
23
23
|
For help about the command-line syntax, do:
|
24
24
|
macros4cuke --help
|
25
25
|
END_MSG
|
26
|
-
|
26
|
+
.freeze
|
27
27
|
# A Hash with the result of the command-line parse.
|
28
28
|
attr_reader(:options)
|
29
29
|
|
@@ -77,11 +77,9 @@ EOS
|
|
77
77
|
rescue Macros4Cuke::CmdLineError => exc
|
78
78
|
$stderr.puts exc.message
|
79
79
|
exit
|
80
|
-
|
81
80
|
rescue OptionParser::InvalidOption => exc
|
82
81
|
$stderr.puts exc.message
|
83
82
|
exit
|
84
|
-
|
85
83
|
rescue OptionParser::MissingArgument => exc
|
86
84
|
err_msg = ''
|
87
85
|
exc.args.each do |arg|
|
@@ -112,6 +110,7 @@ EOS
|
|
112
110
|
unless path.exist?
|
113
111
|
raise DirectoryNotFound.new(path.relative_path_from(Pathname.getwd))
|
114
112
|
end
|
113
|
+
|
115
114
|
path
|
116
115
|
end
|
117
116
|
|
@@ -4,21 +4,21 @@ module Macros4Cuke # Module used as a namespace
|
|
4
4
|
# Namespace for all formatters of MacroCollection and MacroStep objects
|
5
5
|
module Formatter
|
6
6
|
# The list of all formatting notifications
|
7
|
-
AllNotifications = [
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
7
|
+
AllNotifications = %i[
|
8
|
+
on_collection
|
9
|
+
on_collection_end
|
10
|
+
on_step
|
11
|
+
on_step_end
|
12
|
+
on_phrase
|
13
|
+
on_renderer
|
14
|
+
on_renderer_end
|
15
|
+
on_source
|
16
|
+
on_static_text
|
17
|
+
on_eol
|
18
|
+
on_comment
|
19
|
+
on_placeholder
|
20
|
+
on_section
|
21
|
+
on_section_end
|
22
22
|
].freeze
|
23
23
|
end # module
|
24
24
|
end # module
|
@@ -21,7 +21,7 @@ class ToGherkin
|
|
21
21
|
|
22
22
|
# Tell which notifications this formatter subscribes to.
|
23
23
|
def implements()
|
24
|
-
return [
|
24
|
+
return %i[on_collection on_step on_step_end on_phrase on_source]
|
25
25
|
end
|
26
26
|
|
27
27
|
def on_collection(_, _)
|
@@ -43,7 +43,6 @@ class ToGherkin
|
|
43
43
|
io.puts ''
|
44
44
|
end
|
45
45
|
|
46
|
-
|
47
46
|
def on_phrase(aLevel, aPhraseText, useTable)
|
48
47
|
suffix = useTable ? ':' : ''
|
49
48
|
io.print "#{indentation(aLevel)}Given I define the step "
|
@@ -16,14 +16,12 @@ class FormattingService
|
|
16
16
|
# Link to a factory of walker objects that visit macro collections
|
17
17
|
attr_reader(:walker_factory)
|
18
18
|
|
19
|
-
|
20
19
|
# Constructor.
|
21
20
|
def initialize()
|
22
21
|
@formatters = []
|
23
22
|
@walker_factory = CollWalkerFactory.new
|
24
23
|
end
|
25
24
|
|
26
|
-
|
27
25
|
# Register a formatter.
|
28
26
|
# Raises an exception when the formatter implements
|
29
27
|
# an unknown formatting event.
|
@@ -15,7 +15,6 @@ class MacroCollection
|
|
15
15
|
# @!attribute [r] macro_steps.
|
16
16
|
# A Hash with pairs of the form: macro key => MacroStep object
|
17
17
|
|
18
|
-
|
19
18
|
# Add a new macro.
|
20
19
|
# Pre-condition: there is no existing macro with the same key.
|
21
20
|
# @param aPhrase [String] The text that is enclosed between
|
@@ -51,7 +50,6 @@ class MacroCollection
|
|
51
50
|
return macro.expand(aPhrase, rawData)
|
52
51
|
end
|
53
52
|
|
54
|
-
|
55
53
|
# Clear/remove all macro definitions from the collection.
|
56
54
|
# Post-condition: we are back to the same situation as
|
57
55
|
# no macro was ever defined.
|
@@ -59,7 +57,6 @@ class MacroCollection
|
|
59
57
|
macro_steps.clear
|
60
58
|
end
|
61
59
|
|
62
|
-
|
63
60
|
# Read accessor for the @macro_steps attribute.
|
64
61
|
def macro_steps()
|
65
62
|
@macro_steps ||= {}
|
@@ -28,7 +28,6 @@ module MacroStepSupport
|
|
28
28
|
MacroCollection.instance.add_macro(aPhrase, aTemplate, useTable)
|
29
29
|
end
|
30
30
|
|
31
|
-
|
32
31
|
# Invoke a macro with given phrase and (optionally) a table of values
|
33
32
|
# @param aPhraseInstance [String] an instance of the macro phrase.
|
34
33
|
# That is, the text between [...] and with zero or more actual values.
|
@@ -49,7 +48,6 @@ module MacroStepSupport
|
|
49
48
|
steps(rendered_steps)
|
50
49
|
end
|
51
50
|
|
52
|
-
|
53
51
|
# Clear (remove) all the macro-step definitions.
|
54
52
|
# After this, we are in the same situation when no macro-step
|
55
53
|
# was ever defined.
|
@@ -50,13 +50,11 @@ class MacroStep
|
|
50
50
|
@renderer = Templating::Engine.new(theSubsteps)
|
51
51
|
substeps_vars = renderer.variables
|
52
52
|
|
53
|
-
|
54
53
|
@args = validate_phrase_args(@phrase_args, substeps_vars)
|
55
54
|
@args.concat(substeps_vars)
|
56
55
|
@args.uniq!
|
57
56
|
end
|
58
57
|
|
59
|
-
|
60
58
|
# Compute the identifier of the macro from the given macro phrase.
|
61
59
|
# A macro phrase is a text that may contain zero or more placeholders.
|
62
60
|
# In definition mode, a placeholder is delimited by chevrons <..>.
|
@@ -88,7 +86,6 @@ class MacroStep
|
|
88
86
|
# Replace all consecutive whitespaces by an underscore
|
89
87
|
stripped_phrase.gsub!(/\s+/, '_')
|
90
88
|
|
91
|
-
|
92
89
|
# Determine the pattern to isolate
|
93
90
|
# each argument/parameter with its delimiters
|
94
91
|
pattern = case mode
|
@@ -107,7 +104,6 @@ class MacroStep
|
|
107
104
|
return key
|
108
105
|
end
|
109
106
|
|
110
|
-
|
111
107
|
# Render the steps from the template, given the values
|
112
108
|
# taken by the parameters
|
113
109
|
# @param aPhrase [String] an instance of the macro phrase.
|
@@ -172,7 +168,6 @@ class MacroStep
|
|
172
168
|
return a_row
|
173
169
|
end
|
174
170
|
|
175
|
-
|
176
171
|
# Retrieve from the macro phrase, all the text between <..> or double quotes.
|
177
172
|
# Returns an array. Each of its elements corresponds to quoted text.
|
178
173
|
# Example:
|
@@ -205,6 +200,7 @@ class MacroStep
|
|
205
200
|
# Error when the phrase names an argument that never occurs in the substeps
|
206
201
|
thePhraseArgs.each do |phrase_arg|
|
207
202
|
next if substepsVars.include? phrase_arg
|
203
|
+
|
208
204
|
raise(UselessPhraseArgument.new(phrase_arg))
|
209
205
|
end
|
210
206
|
# Error when a substep has an argument that never appears in the phrase
|
@@ -221,7 +217,6 @@ class MacroStep
|
|
221
217
|
return thePhraseArgs.dup
|
222
218
|
end
|
223
219
|
|
224
|
-
|
225
220
|
# Return true, if the macro-step requires a data table
|
226
221
|
# to pass actual values of the arguments.
|
227
222
|
def use_table?()
|
@@ -63,7 +63,7 @@ class Engine
|
|
63
63
|
# tag/placeholder name => actual value.
|
64
64
|
# @return [String] The rendition of the template given
|
65
65
|
# the passed argument values.
|
66
|
-
def render(aContextObject = Object.new, theLocals)
|
66
|
+
def render(aContextObject = Object.new, theLocals = {})
|
67
67
|
return '' if @representation.empty?
|
68
68
|
|
69
69
|
prev = nil
|
@@ -81,7 +81,6 @@ class Engine
|
|
81
81
|
return result
|
82
82
|
end
|
83
83
|
|
84
|
-
|
85
84
|
# Retrieve all placeholder names that appear in the template.
|
86
85
|
# @return [Array] The list of placeholder names.
|
87
86
|
def variables()
|
@@ -154,8 +153,8 @@ class Engine
|
|
154
153
|
|
155
154
|
raise(StandardError, "Missing closing chevron '>'.") if unbalance == 1
|
156
155
|
end
|
157
|
-
|
158
|
-
private
|
156
|
+
|
157
|
+
private
|
159
158
|
|
160
159
|
# Create the internal representation of the given template.
|
161
160
|
def compile(aSourceTemplate)
|
@@ -168,7 +167,7 @@ class Engine
|
|
168
167
|
line_items.each do |(kind, text)|
|
169
168
|
# A tag text cannot be empty nor blank
|
170
169
|
next if (kind != :dynamic) || !text.strip.empty?
|
171
|
-
|
170
|
+
|
172
171
|
raise(EmptyArgumentError.new(line.strip))
|
173
172
|
end
|
174
173
|
|
@@ -212,7 +211,6 @@ class Engine
|
|
212
211
|
return line_rep
|
213
212
|
end
|
214
213
|
|
215
|
-
|
216
214
|
# Apply rule: if last item in line is an end of section marker,
|
217
215
|
# then place eoline before that item.
|
218
216
|
# Otherwise, end the line with a eoline marker.
|
@@ -226,7 +224,6 @@ class Engine
|
|
226
224
|
end
|
227
225
|
end
|
228
226
|
|
229
|
-
|
230
227
|
# @param aCouple [Array] a two-element array of the form: [kind, text]
|
231
228
|
# Where kind must be one of :static, :dynamic
|
232
229
|
def compile_couple(aCouple)
|
@@ -241,7 +238,6 @@ class Engine
|
|
241
238
|
return result
|
242
239
|
end
|
243
240
|
|
244
|
-
|
245
241
|
# Parse the contents of a tag entry.
|
246
242
|
# @param aText [String] The text that is enclosed between chevrons.
|
247
243
|
def parse_tag(aText)
|
@@ -308,6 +304,7 @@ class Engine
|
|
308
304
|
raise(StandardError, msg_prefix + msg)
|
309
305
|
end
|
310
306
|
return if marker.name == sections.last.name
|
307
|
+
|
311
308
|
msg = "doesn't match current section '#{sections.last.name}'."
|
312
309
|
raise(StandardError, msg_prefix + msg)
|
313
310
|
end
|
@@ -42,7 +42,6 @@ class Section < UnaryElement
|
|
42
42
|
return all_vars.flatten.uniq
|
43
43
|
end
|
44
44
|
|
45
|
-
|
46
45
|
# Render the placeholder given the passed arguments.
|
47
46
|
# This method has the same signature as the {Engine#render} method.
|
48
47
|
# @return [String] The text value assigned to the placeholder.
|
@@ -53,7 +52,6 @@ class Section < UnaryElement
|
|
53
52
|
end
|
54
53
|
end # class
|
55
54
|
|
56
|
-
|
57
55
|
# A specialized section in a template for which its rendition
|
58
56
|
# depends on the (in)existence of an actual value bound to the variable name.
|
59
57
|
class ConditionalSection < Section
|
@@ -88,7 +86,6 @@ class ConditionalSection < Section
|
|
88
86
|
return result
|
89
87
|
end
|
90
88
|
|
91
|
-
|
92
89
|
# @return [String] The original text representation of the tag.
|
93
90
|
def to_s()
|
94
91
|
return "<?#{name}>"
|
@@ -72,7 +72,7 @@ describe Application do
|
|
72
72
|
file_path = './test_dir/features/support'
|
73
73
|
file_name = 'use_macros4cuke.rb'
|
74
74
|
|
75
|
-
subject.run!(%w
|
75
|
+
subject.run!(%w[--setup ./test_dir])
|
76
76
|
expect(File.exist?(file_path + '/' + file_name)).to be true
|
77
77
|
|
78
78
|
File.delete(file_path + '/' + file_name)
|
@@ -84,7 +84,7 @@ describe Application do
|
|
84
84
|
|
85
85
|
file_path = '/test_dir/features/support'
|
86
86
|
file_name = 'use_macros4cuke.rb'
|
87
|
-
args = %w
|
87
|
+
args = %w[--setup ./test_dir]
|
88
88
|
mydir = File.dirname(__FILE__)
|
89
89
|
|
90
90
|
expect { subject.run!(args) }.not_to raise_error
|
@@ -154,7 +154,7 @@ Cannot find the directory 'not_a_dir'.
|
|
154
154
|
END_MESSAGE
|
155
155
|
|
156
156
|
# Application is stopped
|
157
|
-
args = %w
|
157
|
+
args = %w[--setup not_a_dir]
|
158
158
|
expect { subject.parse!(args) }.to raise_error(SystemExit)
|
159
159
|
|
160
160
|
# Error message text is displayed
|
@@ -170,7 +170,7 @@ END_MESSAGE
|
|
170
170
|
Error in command-line:
|
171
171
|
Cannot find the directory 'test_dir/features'.
|
172
172
|
END_MESSAGE
|
173
|
-
args = %w
|
173
|
+
args = %w[--setup ./test_dir]
|
174
174
|
|
175
175
|
# Application is stopped
|
176
176
|
expect { subject.parse!(args) }.to raise_error(SystemExit)
|
@@ -198,7 +198,7 @@ END_MESSAGE
|
|
198
198
|
mk_subdir('test_dir/features/support')
|
199
199
|
|
200
200
|
expected = { setup: [Pathname.getwd + 'test_dir/features/support'] }
|
201
|
-
expect(subject.parse!(%w
|
201
|
+
expect(subject.parse!(%w[--setup ./test_dir])).to eq(expected)
|
202
202
|
|
203
203
|
file_path = expected[:setup].first
|
204
204
|
Dir.rmdir(file_path)
|
@@ -64,12 +64,8 @@ describe FormattingService do
|
|
64
64
|
end
|
65
65
|
|
66
66
|
it 'should complain when a formatter uses an unknown formatting event' do
|
67
|
-
notifications = [
|
68
|
-
|
69
|
-
:on_collection_end,
|
70
|
-
:non_standard,
|
71
|
-
:on_step,
|
72
|
-
:on_step_end
|
67
|
+
notifications = %i[
|
68
|
+
on_collection on_collection_end non_standard on_step on_step_end
|
73
69
|
]
|
74
70
|
formatter = double('formatter')
|
75
71
|
expect(formatter).to receive(:implements).once.and_return(notifications)
|
@@ -82,11 +78,8 @@ describe FormattingService do
|
|
82
78
|
it 'should support formatters using a subset of possible notifications' do
|
83
79
|
# Case: formatter that supports a few notifications only
|
84
80
|
formatter1 = double('formatter')
|
85
|
-
supported_notifications = [
|
86
|
-
|
87
|
-
:on_collection_end,
|
88
|
-
:on_step,
|
89
|
-
:on_step_end
|
81
|
+
supported_notifications = %i[
|
82
|
+
on_collection on_collection_end on_step on_step_end
|
90
83
|
]
|
91
84
|
expect(formatter1).to receive(:implements)
|
92
85
|
.at_least(69).times
|
@@ -46,7 +46,7 @@ SNIPPET
|
|
46
46
|
|
47
47
|
it 'should return the rendition of a given macro-step' do
|
48
48
|
phrase = '[enter my credentials]'
|
49
|
-
input_values = [ %w
|
49
|
+
input_values = [ %w[userid nobody], %w[password no-secret] ]
|
50
50
|
rendered = singleton.render_steps(phrase, input_values)
|
51
51
|
expected = <<-SNIPPET
|
52
52
|
Given I landed in the homepage
|
@@ -78,7 +78,7 @@ SNIPPET
|
|
78
78
|
|
79
79
|
it "should call the 'steps' method with substeps and variables" do
|
80
80
|
# Notice that the call syntax can be used inside step definitions
|
81
|
-
world.invoke_macro(phrase1, [%w
|
81
|
+
world.invoke_macro(phrase1, [%w[userid nobody], %w[password none]])
|
82
82
|
|
83
83
|
# Check that the 'steps' method was indeed called with correct argument
|
84
84
|
param_assignments = { '<userid>' => 'nobody', '<password>' => 'none' }
|
@@ -60,11 +60,11 @@ SNIPPET
|
|
60
60
|
end
|
61
61
|
|
62
62
|
it 'should know the tags(placeholders) from its phrase' do
|
63
|
-
expect(subject.phrase_args).to eq(%w
|
63
|
+
expect(subject.phrase_args).to eq(%w[userid])
|
64
64
|
end
|
65
65
|
|
66
66
|
it 'should know the tags(placeholders) from its phrase and template' do
|
67
|
-
expect(subject.args).to eq(%w
|
67
|
+
expect(subject.args).to eq(%w[userid password])
|
68
68
|
end
|
69
69
|
end # context
|
70
70
|
|
@@ -72,7 +72,7 @@ SNIPPET
|
|
72
72
|
context 'Provided services:' do
|
73
73
|
let(:phrase_instance) { 'enter my credentials as "nobody"' }
|
74
74
|
it 'should render the substeps' do
|
75
|
-
text = subject.expand(phrase_instance, [ %w
|
75
|
+
text = subject.expand(phrase_instance, [ %w[password no-secret] ])
|
76
76
|
expectation = <<-SNIPPET
|
77
77
|
Given I landed in the homepage
|
78
78
|
When I click "Sign in"
|
@@ -100,7 +100,7 @@ SNIPPET
|
|
100
100
|
|
101
101
|
it 'should un-escape the double-quotes for phrase arguments' do
|
102
102
|
specific_phrase = 'enter my credentials as "quotable\""'
|
103
|
-
text = subject.expand(specific_phrase, [ %w
|
103
|
+
text = subject.expand(specific_phrase, [ %w[password no-secret] ])
|
104
104
|
expectation = <<-SNIPPET
|
105
105
|
Given I landed in the homepage
|
106
106
|
When I click "Sign in"
|
@@ -117,7 +117,7 @@ SNIPPET
|
|
117
117
|
# Error case: there is no macro argument called <unknown>
|
118
118
|
exc = UnknownArgumentError
|
119
119
|
msg = "Unknown macro-step argument 'unknown'."
|
120
|
-
args = [ %w
|
120
|
+
args = [ %w[unknown anything] ]
|
121
121
|
expect { subject.expand(phrase_instance, args) }.to raise_error(exc, msg)
|
122
122
|
end
|
123
123
|
|
@@ -127,7 +127,7 @@ SNIPPET
|
|
127
127
|
phrase = 'enter my credentials as "nobody"'
|
128
128
|
exc = AmbiguousArgumentValue
|
129
129
|
msg = "The macro argument 'userid' has value 'nobody' and 'someone'."
|
130
|
-
args = [ %w
|
130
|
+
args = [ %w[userid someone], %w[password no-secret] ]
|
131
131
|
expect { subject.expand(phrase, args) }.to raise_error(exc, msg)
|
132
132
|
end
|
133
133
|
|
@@ -154,14 +154,14 @@ SNIPPET
|
|
154
154
|
|
155
155
|
it 'should complain if a tag misses an closing chevron' do
|
156
156
|
sample_text = 'begin <some_tag\> end'
|
157
|
-
exc = StandardError
|
157
|
+
exc = StandardError
|
158
158
|
err_msg = "Missing closing chevron '>'."
|
159
159
|
expect { Engine.parse(sample_text) }.to raise_error(exc, err_msg)
|
160
160
|
end
|
161
161
|
|
162
162
|
it 'should complain if a text misses an opening chevron' do
|
163
163
|
sample_text = 'begin <some_tag> > end'
|
164
|
-
exc = StandardError
|
164
|
+
exc = StandardError
|
165
165
|
err_msg = "Missing opening chevron '<'."
|
166
166
|
expect { Engine.parse(sample_text) }.to raise_error(exc, err_msg)
|
167
167
|
end
|
@@ -197,7 +197,7 @@ SNIPPET
|
|
197
197
|
elements = instance.instance_variable_get(:@representation)
|
198
198
|
sections = elements.select { |e| e.is_a?(Section) }
|
199
199
|
names = sections.map(&:to_s)
|
200
|
-
expect(names).to eq(%w
|
200
|
+
expect(names).to eq(%w[<?address> <?birthdate> <?dummy>])
|
201
201
|
end
|
202
202
|
|
203
203
|
it 'should complain when a placeholder is empty or blank' do
|
@@ -243,7 +243,7 @@ SNIPPET
|
|
243
243
|
context 'Provided services:' do
|
244
244
|
it 'should know the variable(s) it contains' do
|
245
245
|
# Case using the sample template
|
246
|
-
expect(subject.variables).to be == %w
|
246
|
+
expect(subject.variables).to be == %w[userid password]
|
247
247
|
|
248
248
|
# Case of an empty source template text
|
249
249
|
instance = Engine.new ''
|
@@ -329,7 +329,7 @@ SNIPPET
|
|
329
329
|
|
330
330
|
|
331
331
|
it 'should render multivalued actuals' do
|
332
|
-
locals = { 'userid' => %w
|
332
|
+
locals = { 'userid' => %w[johndoe yeti] } # Silly case
|
333
333
|
|
334
334
|
rendered_text = subject.render(Object.new, locals)
|
335
335
|
expected = <<-SNIPPET
|
metadata
CHANGED
@@ -1,29 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: macros4cuke
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.16
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dimitri Geshef
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2019-01-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: cucumber
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: '3.0'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - "
|
24
|
+
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
26
|
+
version: '3.0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rake
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -58,28 +58,14 @@ dependencies:
|
|
58
58
|
requirements:
|
59
59
|
- - ">="
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: 0.
|
62
|
-
type: :development
|
63
|
-
prerelease: false
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
65
|
-
requirements:
|
66
|
-
- - ">="
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
version: 0.7.0
|
69
|
-
- !ruby/object:Gem::Dependency
|
70
|
-
name: rubygems
|
71
|
-
requirement: !ruby/object:Gem::Requirement
|
72
|
-
requirements:
|
73
|
-
- - ">="
|
74
|
-
- !ruby/object:Gem::Version
|
75
|
-
version: 2.0.0
|
61
|
+
version: 0.8.0
|
76
62
|
type: :development
|
77
63
|
prerelease: false
|
78
64
|
version_requirements: !ruby/object:Gem::Requirement
|
79
65
|
requirements:
|
80
66
|
- - ">="
|
81
67
|
- !ruby/object:Gem::Version
|
82
|
-
version:
|
68
|
+
version: 0.8.0
|
83
69
|
description: Expand Cucumber with macro-steps.
|
84
70
|
email: famished.tiger@yahoo.com
|
85
71
|
executables:
|
@@ -204,7 +190,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
204
190
|
version: '0'
|
205
191
|
requirements: []
|
206
192
|
rubyforge_project:
|
207
|
-
rubygems_version: 2.6.
|
193
|
+
rubygems_version: 2.6.13
|
208
194
|
signing_key:
|
209
195
|
specification_version: 4
|
210
196
|
summary: Add your own macro-steps to Cucumber scenarios
|