macros4cuke 0.3.42 → 0.4.00
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/.rubocop.yml +20 -3
- data/CHANGELOG.md +15 -1
- data/examples/i18n/fr/features/step_definitions/use_macro_steps.rb +1 -1
- data/features/demo06.feature +75 -75
- data/features/demo07.feature +15 -0
- data/features/support/env.rb +6 -0
- data/features/support/macro_support.rb +2 -2
- data/lib/macro_steps.rb +19 -2
- data/lib/macros4cuke/coll-walker-factory.rb +119 -0
- data/lib/macros4cuke/constants.rb +1 -1
- data/lib/macros4cuke/exceptions.rb +23 -1
- data/lib/macros4cuke/formatter/all-notifications.rb +30 -0
- data/lib/macros4cuke/formatter/to-gherkin.rb +80 -0
- data/lib/macros4cuke/formatter/to-null.rb +86 -0
- data/lib/macros4cuke/formatter/to-trace.rb +100 -0
- data/lib/macros4cuke/formatting-service.rb +74 -0
- data/lib/macros4cuke/macro-collection.rb +3 -3
- data/lib/macros4cuke/macro-step-support.rb +1 -1
- data/lib/macros4cuke/macro-step.rb +10 -26
- data/lib/macros4cuke/templating/engine.rb +74 -29
- data/spec/macros4cuke/coll-walker-factory_spec.rb +269 -0
- data/spec/macros4cuke/formatter/to-gherkin_spec.rb +129 -0
- data/spec/macros4cuke/formatter/to-null_spec.rb +62 -0
- data/spec/macros4cuke/formatter/to-trace_spec.rb +155 -0
- data/spec/macros4cuke/formatting-service_spec.rb +138 -0
- data/spec/macros4cuke/macro-collection_spec.rb +7 -4
- data/spec/macros4cuke/macro-step-support_spec.rb +41 -24
- data/spec/macros4cuke/macro-step_spec.rb +13 -6
- data/spec/macros4cuke/templating/engine_spec.rb +11 -7
- data/spec/macros4cuke/templating/placeholder_spec.rb +1 -1
- data/spec/macros4cuke/templating/section_spec.rb +3 -1
- data/spec/macros4cuke/use-sample-collection.rb +79 -0
- data/spec/spec_helper.rb +3 -0
- metadata +15 -2
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
OGE0ZDcxMWQxOTgxYTljYThhY2ViYzg5NzIxN2E1OTNlMDU2OTk1ZQ==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
ZjhmNjQ0NWVlMzVkMWU0N2Y0ZDE2Y2Y1YmNiYWFiMDk1NTdlYjU0Nw==
|
7
7
|
!binary "U0hBNTEy":
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
M2MwYjllOWYxY2QxZDBlYTc0OWJkOGE4ZGQ3N2IwYjJhOGU0MzViMDc2ZWMx
|
10
|
+
ZGQ4N2FhYTU3ZWNjYmJkMjY5NzRiZmFjN2NmYjVjZmQxMDI0NDM2NDkzZjli
|
11
|
+
MWQ2MDlmYzljOWM2NmQzMGRmMDVkYjAwOTYxZDdmY2Q5YjBlNTY=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
ZjcyOWZlZWI0ZjU0Yzk4MjJkNGYwODAwMTU3YjE5YTc0N2VlZGZjNzRkZDQ0
|
14
|
+
YjVmYTNmNzhkMWY4ZDNiZmJlNWFiMzQ0NTQ5ZGE5NmM0MmU1MWM3ZTM4Yzhj
|
15
|
+
NDMzMzBlMDllNzg1NGNiN2Y1NzU2NWRkMzMzY2I0Zjk5Yjg5MDM=
|
data/.rubocop.yml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
AllCops:
|
2
2
|
Excludes:
|
3
3
|
- '*/examples/**'
|
4
|
-
- '*/
|
4
|
+
- '*/features/**'
|
5
5
|
|
6
6
|
|
7
7
|
AccessControl:
|
@@ -14,21 +14,38 @@ AsciiComments:
|
|
14
14
|
CaseIndentation:
|
15
15
|
Enabled: false
|
16
16
|
|
17
|
+
ClassLength:
|
18
|
+
Max: 200
|
19
|
+
CountComments: false
|
20
|
+
|
17
21
|
ConstantName:
|
18
22
|
Enabled: false
|
19
23
|
|
20
24
|
DefWithParentheses:
|
21
25
|
Enabled: false
|
22
26
|
|
27
|
+
Documentation:
|
28
|
+
Enabled: false
|
29
|
+
|
23
30
|
EmptyLines:
|
24
31
|
Enabled: false
|
25
32
|
|
26
33
|
Encoding:
|
27
34
|
Enabled: false
|
28
35
|
|
29
|
-
|
36
|
+
IndentationWidth :
|
37
|
+
Enabled: false
|
38
|
+
|
39
|
+
# Avoid methods longer than 50 lines of code
|
30
40
|
MethodLength:
|
31
|
-
Max:
|
41
|
+
Max: 50
|
42
|
+
CountComments: false
|
43
|
+
|
44
|
+
NumericLiterals:
|
45
|
+
Enabled: false
|
46
|
+
|
47
|
+
RaiseArgs:
|
48
|
+
Enabled: false
|
32
49
|
|
33
50
|
RedundantReturn:
|
34
51
|
Enabled: false
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,20 @@
|
|
1
|
+
### 0.4.00 / 2013-11-17
|
2
|
+
#### Version number bumped. New feature: to list all encountered macro definitions into a single feature file.
|
3
|
+
* [NEW] Sample `demo07.feature` file illustrates the new step that will list all macro definitions.
|
4
|
+
* [NEW] Class CollWalkerFactory. Creates specialized Enumerators that walk over the macro collection.
|
5
|
+
* [NEW] Module Formatter. Purpose: Grouping of all classes that render macro definitions
|
6
|
+
* [NEW] File `all-notifications.rb` List of macro collection visit events.
|
7
|
+
* [NEW] Class `ToGherkin` A macro-step formatter that outputs back into Gherkin format.
|
8
|
+
* [NEW] Class `ToNull` A macro-step formatter that outputs nothing.
|
9
|
+
* [NEW] Class `ToTrace` A macro-step formatter that outputs the macro collection visit events.
|
10
|
+
* [NEW] Class `Comment` to represent comments appearing in sub-steps source.
|
11
|
+
* [CHANGE] Method `Engine#parse` parses Gherkin comments into Comment objects.
|
12
|
+
* [CHANGE] File `.rubocop.yml`: Allow checks of spec files, override settings of some new cops.
|
13
|
+
* [CHANGE] Replaced calls to Kernel#raise by Kernel#fail
|
14
|
+
|
1
15
|
### 0.3.42 / 2013-10-04
|
2
16
|
* [CHANGE] File `macro_steps.rb`: Regular expression for defining step uses now the /x option.
|
3
|
-
* [FIX] File `.simplecov` Removal of
|
17
|
+
* [FIX] File `.simplecov` Removal of premature dependency to 'coveralls' gem
|
4
18
|
|
5
19
|
### 0.3.41 / 2013-10-03
|
6
20
|
* [CHANGE] File `env.rb`: Updated the exception handler when requiring `simplecov` to prevent the
|
@@ -18,7 +18,7 @@ Quand(/^j(?:e |')\[([^\]]+)\]:$/) do |macro_phrase, table_argument|
|
|
18
18
|
# Ensure that the second argument is of the correct type
|
19
19
|
unless table_argument.kind_of?(Cucumber::Ast::Table)
|
20
20
|
error_message = 'This step must have a data table as an argument.'
|
21
|
-
|
21
|
+
fail(Macros4Cuke::DataTableNotFound, error_message)
|
22
22
|
end
|
23
23
|
|
24
24
|
# This will call the macro with the given phrase.
|
data/features/demo06.feature
CHANGED
@@ -1,85 +1,85 @@
|
|
1
1
|
# File: demo06.feature
|
2
2
|
|
3
|
-
Feature:
|
3
|
+
Feature: Define conditional substeps in a macro-step.
|
4
4
|
As a Cuke user
|
5
|
-
So that I enjoy writing
|
5
|
+
So that I enjoy writing flexible scenarios.
|
6
6
|
|
7
7
|
|
8
|
-
Scenario: Defining a macro with conditional substeps
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
<?comment> And I fill in "comment" with "<comment>"</comment>
|
29
|
-
|
30
|
-
|
31
|
-
|
8
|
+
Scenario: Defining a macro with conditional substeps
|
9
|
+
Given I define the step "* I [fill in the form with]:" to mean:
|
10
|
+
"""
|
11
|
+
When I fill in "first_name" with "<firstname>"
|
12
|
+
And I fill in "last_name" with "<lastname>"
|
13
|
+
And I fill in "street_address" with "<street_address>"
|
14
|
+
And I fill in "zip" with "<postcode>"
|
15
|
+
And I fill in "city" with "<city>"
|
16
|
+
And I fill in "country" with "<country>"
|
17
|
+
|
18
|
+
# Let's assume that the e-mail field is optional.
|
19
|
+
# The step between the <?email>...<email> will be executed
|
20
|
+
# only when the argument <email> has a value assigned to it.
|
21
|
+
<?email>
|
22
|
+
And I fill in "email" with "<email>"
|
23
|
+
</email>
|
24
|
+
|
25
|
+
# Let's also assume that comment is also optional
|
26
|
+
# See the slightly different syntax: the conditional section
|
27
|
+
# <?comment>...<comment> may fit in a single line
|
28
|
+
<?comment> And I fill in "comment" with "<comment>"</comment>
|
29
|
+
And I click "Save"
|
30
|
+
"""
|
31
|
+
|
32
32
|
|
33
|
-
Scenario: An exception is forced by invoking the above macro with a triple quote string instead of a data table.
|
34
|
-
|
33
|
+
Scenario: An exception is forced by invoking the above macro with a triple quote string instead of a data table.
|
34
|
+
When I generate a DataTableNotFound exception
|
35
35
|
|
36
|
-
|
37
|
-
Scenario: Let's use the macro-step WITHOUT the optional argument values.
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
36
|
+
|
37
|
+
Scenario: Let's use the macro-step WITHOUT the optional argument values.
|
38
|
+
When I [fill in the form with]:
|
39
|
+
|firstname|Alice|
|
40
|
+
|lastname| Inn |
|
41
|
+
|street_address| 11, No Street|
|
42
|
+
|city| Nowhere-City|
|
43
|
+
|country|Wonderland|
|
44
|
+
# No e-mail
|
45
|
+
# No comment
|
46
46
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
Scenario: Let's use the macro-step WITH the optional argument values.
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
47
|
+
# The next step verifies that the optional steps from the macro were ignored.
|
48
|
+
Then I expect the following step trace:
|
49
|
+
"""
|
50
|
+
Invoked step: ... I fill in "first_name" with "Alice"
|
51
|
+
Invoked step: ... I fill in "last_name" with "Inn"
|
52
|
+
Invoked step: ... I fill in "street_address" with "11, No Street"
|
53
|
+
Invoked step: ... I fill in "zip" with ""
|
54
|
+
Invoked step: ... I fill in "city" with "Nowhere-City"
|
55
|
+
Invoked step: ... I fill in "country" with "Wonderland"
|
56
|
+
Invoked step: ... I click "Save"
|
57
|
+
"""
|
58
|
+
|
59
|
+
|
60
|
+
Scenario: Let's use the macro-step WITH the optional argument values.
|
61
|
+
# Redo, now with e-mail and comment
|
62
|
+
When I [fill in the form with]:
|
63
|
+
|firstname|Alice|
|
64
|
+
|lastname| Inn |
|
65
|
+
|street_address| 11, No Street|
|
66
|
+
|city| Nowhere-City|
|
67
|
+
|country|Wonderland|
|
68
|
+
# Here come the optional values
|
69
|
+
|email|alice.inn@wonder.land|
|
70
|
+
|comment|No comment!|
|
71
71
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
72
|
+
# The next step verifies that the optional steps from the macro were ignored.
|
73
|
+
Then I expect the following step trace:
|
74
|
+
"""
|
75
|
+
Invoked step: ... I fill in "first_name" with "Alice"
|
76
|
+
Invoked step: ... I fill in "last_name" with "Inn"
|
77
|
+
Invoked step: ... I fill in "street_address" with "11, No Street"
|
78
|
+
Invoked step: ... I fill in "zip" with ""
|
79
|
+
Invoked step: ... I fill in "city" with "Nowhere-City"
|
80
|
+
Invoked step: ... I fill in "country" with "Wonderland"
|
81
|
+
Invoked step: ... I fill in "email" with "alice.inn@wonder.land"
|
82
|
+
Invoked step: ... I fill in "comment" with "No comment!"
|
83
|
+
Invoked step: ... I click "Save"
|
84
|
+
"""
|
85
85
|
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# File: demo07.feature
|
2
|
+
|
3
|
+
Feature: Save all encountered macro-step definitions in a single file
|
4
|
+
As a prolific macro-step writer
|
5
|
+
So that I have an list of all macro-steps in a single place.
|
6
|
+
|
7
|
+
|
8
|
+
Scenario: Listing all encountered macro-steps definitions
|
9
|
+
|
10
|
+
# This step is bundled with Macro4Cuke as a convenience.
|
11
|
+
# The file "all_macros.feature" is created and saved when Cucumber completes.
|
12
|
+
# You should find the file in the folder where macros4cuke resides.
|
13
|
+
# If you use this step in your own Cucumber project,
|
14
|
+
# then the file will be placed in the project's root folder.
|
15
|
+
When I want to list all the macros in the file "all_macros.feature"
|
data/features/support/env.rb
CHANGED
@@ -4,12 +4,18 @@
|
|
4
4
|
# It also demonstrates what to do in your env.rb file
|
5
5
|
# to use the Macros4Cuke gem.
|
6
6
|
|
7
|
+
require 'pp'
|
8
|
+
require_relative '../../lib/macros4cuke/macro-collection'
|
9
|
+
require_relative '../../lib/macros4cuke/formatting-service'
|
10
|
+
require_relative '../../lib/macros4cuke/formatter/to-gherkin'
|
11
|
+
|
7
12
|
begin
|
8
13
|
require 'simplecov' # Development dependency only...
|
9
14
|
rescue LoadError => mute
|
10
15
|
mute # .... So gobble silently the exception if simplecov isn't installed.
|
11
16
|
end
|
12
17
|
|
18
|
+
|
13
19
|
module DemoMacros4Cuke # Use the module as a namespace
|
14
20
|
|
15
21
|
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# File: macro_support.rb
|
2
|
-
# Purpose: Add the support for macros in Cucumber.
|
2
|
+
# Purpose: Add the support for macros in a Cucumber project.
|
3
3
|
# This file is meant to be put next to the 'env.rb' file
|
4
|
-
# of your
|
4
|
+
# of your Cucumber project.
|
5
5
|
|
6
6
|
|
7
7
|
# Macros4Cuke step one: Load modules and classes from the gem.
|
data/lib/macro_steps.rb
CHANGED
@@ -26,7 +26,6 @@ Given(/^I\sdefine\sthe\sstep\s" # Fixed part of defining step
|
|
26
26
|
end
|
27
27
|
|
28
28
|
|
29
|
-
|
30
29
|
# This step is used to invoke a simple macro-step
|
31
30
|
# Example:
|
32
31
|
# When I [log in as "guest"]
|
@@ -37,6 +36,8 @@ end
|
|
37
36
|
|
38
37
|
|
39
38
|
# This step is used to invoke a macro-step with a data table argument.
|
39
|
+
# Notice the presence of an ending colon character ':'
|
40
|
+
# after the closing bracket ']'
|
40
41
|
# Example:
|
41
42
|
# When I [enter my credentials as]:
|
42
43
|
# |userid |guest |
|
@@ -44,7 +45,7 @@ end
|
|
44
45
|
When(/^I \[([^\]]+)\]:$/) do |macro_phrase, table_argument|
|
45
46
|
# Ensure that the second argument is of the correct type
|
46
47
|
unless table_argument.kind_of?(Cucumber::Ast::Table)
|
47
|
-
|
48
|
+
fail(Macros4Cuke::DataTableNotFound.new(macro_phrase))
|
48
49
|
end
|
49
50
|
|
50
51
|
# This will call the macro with the given phrase.
|
@@ -54,4 +55,20 @@ When(/^I \[([^\]]+)\]:$/) do |macro_phrase, table_argument|
|
|
54
55
|
end
|
55
56
|
|
56
57
|
|
58
|
+
# This step will list all the encountered macro-step definitions
|
59
|
+
# and will collect them in a single feature file.
|
60
|
+
# the file is saved in the current working directory
|
61
|
+
# when Cucumber is closing down.
|
62
|
+
When(/I want to list all the macros in the file "([^"]+)"$/) do |filepath|
|
63
|
+
at_exit do
|
64
|
+
output = File.open(filepath, 'w')
|
65
|
+
formatter = Macros4Cuke::Formatter::ToGherkin.new(output)
|
66
|
+
|
67
|
+
service = Macros4Cuke::FormattingService.new
|
68
|
+
service.register(formatter)
|
69
|
+
service.start!(Macros4Cuke::MacroCollection.instance)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
|
57
74
|
# End of file
|
@@ -0,0 +1,119 @@
|
|
1
|
+
# File: coll-walker-factory.rb
|
2
|
+
# Purpose: Implementation of the CollWalkerFactory class.
|
3
|
+
|
4
|
+
require_relative 'macro-collection'
|
5
|
+
|
6
|
+
module Macros4Cuke # Module used as a namespace
|
7
|
+
|
8
|
+
|
9
|
+
# A Coll(ection)WalkerFactory object is a factory that creates
|
10
|
+
# an enumerator that itself walks in the passed macro collection object.
|
11
|
+
# The walker performs a depth-first visit and yields visit events.
|
12
|
+
class CollWalkerFactory
|
13
|
+
# Structure used internally by the walker
|
14
|
+
StringNode = Struct.new(:event, :text, :extra)
|
15
|
+
|
16
|
+
def build_walker(aMacroCollection)
|
17
|
+
level = 0
|
18
|
+
collection = aMacroCollection
|
19
|
+
current_node = collection
|
20
|
+
backlog = collection.macro_steps.values
|
21
|
+
|
22
|
+
visitor = Enumerator.new do
|
23
|
+
|result_receiver| # 'result_receiver' is a Yielder
|
24
|
+
loop do
|
25
|
+
case current_node
|
26
|
+
when MacroCollection
|
27
|
+
result_receiver << [:on_collection, level, current_node]
|
28
|
+
level += 1
|
29
|
+
backlog << StringNode.new(:on_collection_end, nil)
|
30
|
+
|
31
|
+
when MacroStep
|
32
|
+
result_receiver << emit_on_step(current_node, level, backlog)
|
33
|
+
level += 1
|
34
|
+
|
35
|
+
when StringNode
|
36
|
+
level -= 1 if current_node.event.to_s =~ /_end$/
|
37
|
+
event = [current_node.event, level, current_node.text]
|
38
|
+
event << current_node.extra unless current_node.extra.nil?
|
39
|
+
result_receiver << event
|
40
|
+
|
41
|
+
when Templating::Engine
|
42
|
+
result_receiver << emit_on_renderer(current_node, level, backlog)
|
43
|
+
level += 1
|
44
|
+
|
45
|
+
when Templating::StaticText
|
46
|
+
result_receiver << [:on_static_text, level, current_node.source]
|
47
|
+
|
48
|
+
when Templating::Comment
|
49
|
+
result_receiver << [:on_comment, level, current_node.source]
|
50
|
+
|
51
|
+
when Templating::EOLine
|
52
|
+
result_receiver << [:on_eol, level, nil]
|
53
|
+
|
54
|
+
when Templating::Placeholder
|
55
|
+
result_receiver << [:on_placeholder, level, current_node.name]
|
56
|
+
|
57
|
+
when Templating::Section
|
58
|
+
result_receiver << emit_on_section(current_node, level, backlog)
|
59
|
+
level += 1
|
60
|
+
|
61
|
+
else
|
62
|
+
err_msg = "Don't know how to format a #{current_node.class}."
|
63
|
+
fail(InternalError, err_msg)
|
64
|
+
end
|
65
|
+
|
66
|
+
current_node = backlog.shift
|
67
|
+
break if current_node.nil?
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
|
72
|
+
return visitor
|
73
|
+
end
|
74
|
+
|
75
|
+
private
|
76
|
+
# Add children elements to the visit backlog
|
77
|
+
def add_children(anEnumerable, theBacklog)
|
78
|
+
anEnumerable.reverse.each do |elem|
|
79
|
+
theBacklog.unshift(elem)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
# Generate an on_step event
|
84
|
+
def emit_on_step(current_node, nesting_level, backlog)
|
85
|
+
backlog.unshift(StringNode.new(:on_step_end, nil))
|
86
|
+
backlog.unshift(current_node.renderer)
|
87
|
+
# Does the step use a table argument?
|
88
|
+
use_table = current_node.key =~ /_T$/ ? true : false
|
89
|
+
backlog.unshift(StringNode.new(:on_phrase, current_node.phrase, use_table))
|
90
|
+
|
91
|
+
return [:on_step, nesting_level, current_node]
|
92
|
+
end
|
93
|
+
|
94
|
+
# Generate an on_renderer event
|
95
|
+
def emit_on_renderer(current_node, nesting_level, backlog)
|
96
|
+
backlog.unshift(StringNode.new(:on_renderer_end, nil))
|
97
|
+
add_children(current_node.representation, backlog)
|
98
|
+
backlog.unshift(StringNode.new(:on_source, current_node.source))
|
99
|
+
|
100
|
+
return [:on_renderer, nesting_level, current_node]
|
101
|
+
end
|
102
|
+
|
103
|
+
|
104
|
+
# Generate an on_section event
|
105
|
+
def emit_on_section(current_node, nesting_level, backlog)
|
106
|
+
backlog.unshift(StringNode.new(:on_section_end, nil))
|
107
|
+
add_children(current_node.children, backlog)
|
108
|
+
|
109
|
+
return [:on_section, nesting_level, current_node.name]
|
110
|
+
end
|
111
|
+
|
112
|
+
|
113
|
+
|
114
|
+
|
115
|
+
end # class
|
116
|
+
|
117
|
+
end # module
|
118
|
+
|
119
|
+
# End of file
|