macros4cuke 0.3.42 → 0.4.00

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.
Files changed (35) hide show
  1. checksums.yaml +8 -8
  2. data/.rubocop.yml +20 -3
  3. data/CHANGELOG.md +15 -1
  4. data/examples/i18n/fr/features/step_definitions/use_macro_steps.rb +1 -1
  5. data/features/demo06.feature +75 -75
  6. data/features/demo07.feature +15 -0
  7. data/features/support/env.rb +6 -0
  8. data/features/support/macro_support.rb +2 -2
  9. data/lib/macro_steps.rb +19 -2
  10. data/lib/macros4cuke/coll-walker-factory.rb +119 -0
  11. data/lib/macros4cuke/constants.rb +1 -1
  12. data/lib/macros4cuke/exceptions.rb +23 -1
  13. data/lib/macros4cuke/formatter/all-notifications.rb +30 -0
  14. data/lib/macros4cuke/formatter/to-gherkin.rb +80 -0
  15. data/lib/macros4cuke/formatter/to-null.rb +86 -0
  16. data/lib/macros4cuke/formatter/to-trace.rb +100 -0
  17. data/lib/macros4cuke/formatting-service.rb +74 -0
  18. data/lib/macros4cuke/macro-collection.rb +3 -3
  19. data/lib/macros4cuke/macro-step-support.rb +1 -1
  20. data/lib/macros4cuke/macro-step.rb +10 -26
  21. data/lib/macros4cuke/templating/engine.rb +74 -29
  22. data/spec/macros4cuke/coll-walker-factory_spec.rb +269 -0
  23. data/spec/macros4cuke/formatter/to-gherkin_spec.rb +129 -0
  24. data/spec/macros4cuke/formatter/to-null_spec.rb +62 -0
  25. data/spec/macros4cuke/formatter/to-trace_spec.rb +155 -0
  26. data/spec/macros4cuke/formatting-service_spec.rb +138 -0
  27. data/spec/macros4cuke/macro-collection_spec.rb +7 -4
  28. data/spec/macros4cuke/macro-step-support_spec.rb +41 -24
  29. data/spec/macros4cuke/macro-step_spec.rb +13 -6
  30. data/spec/macros4cuke/templating/engine_spec.rb +11 -7
  31. data/spec/macros4cuke/templating/placeholder_spec.rb +1 -1
  32. data/spec/macros4cuke/templating/section_spec.rb +3 -1
  33. data/spec/macros4cuke/use-sample-collection.rb +79 -0
  34. data/spec/spec_helper.rb +3 -0
  35. metadata +15 -2
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- N2ExZjg4MDU0MGUwOTdjYjRmNGI1Yjg2OTk5MzRhMjM3YWNkZjFmYQ==
4
+ OGE0ZDcxMWQxOTgxYTljYThhY2ViYzg5NzIxN2E1OTNlMDU2OTk1ZQ==
5
5
  data.tar.gz: !binary |-
6
- MDgxZTMyMWI5MTU1NzI5NzlmMGU4ZDhiZmY1NjQ4MWEzNDQzMmJkOQ==
6
+ ZjhmNjQ0NWVlMzVkMWU0N2Y0ZDE2Y2Y1YmNiYWFiMDk1NTdlYjU0Nw==
7
7
  !binary "U0hBNTEy":
8
8
  metadata.gz: !binary |-
9
- MzlhNDE3NWUwZTYyZDNjMmMxZTVlNWY1NjNhMmY2NjU4ZjQ0YWI1M2Y5MDlh
10
- NmNmYTZiNzAwZThhYTM1MWRjYTQ0MmYwMzIyNmRkZmNhOWU1OWFmMTIyZjU1
11
- ODMwMDFiODFiNjE0OTljZTlmOWQxOWIyNGU3N2RmOGQ3ZjA0YWI=
9
+ M2MwYjllOWYxY2QxZDBlYTc0OWJkOGE4ZGQ3N2IwYjJhOGU0MzViMDc2ZWMx
10
+ ZGQ4N2FhYTU3ZWNjYmJkMjY5NzRiZmFjN2NmYjVjZmQxMDI0NDM2NDkzZjli
11
+ MWQ2MDlmYzljOWM2NmQzMGRmMDVkYjAwOTYxZDdmY2Q5YjBlNTY=
12
12
  data.tar.gz: !binary |-
13
- MjczZTNjNGY3YzM0Njk3ZGM4OTBkMDYwNmQ4ZDYyNjg0ZDdlYTU5ZjE3ZThh
14
- M2E3YjI1Y2IxYTVjODcyN2UzMzkwYjMyMmY1NmY0YWRmMGQ3ZjgwM2I5NjUw
15
- ZGI2NWRkNzZkOTY3YmI4ODE3OWE3ZTY1MDIwM2YyZDlhMDY3ZTY=
13
+ ZjcyOWZlZWI0ZjU0Yzk4MjJkNGYwODAwMTU3YjE5YTc0N2VlZGZjNzRkZDQ0
14
+ YjVmYTNmNzhkMWY4ZDNiZmJlNWFiMzQ0NTQ5ZGE5NmM0MmU1MWM3ZTM4Yzhj
15
+ NDMzMzBlMDllNzg1NGNiN2Y1NzU2NWRkMzMzY2I0Zjk5Yjg5MDM=
data/.rubocop.yml CHANGED
@@ -1,7 +1,7 @@
1
1
  AllCops:
2
2
  Excludes:
3
3
  - '*/examples/**'
4
- - '*/spec/**'
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
- # Avoid methods longer than 30 lines of code
36
+ IndentationWidth :
37
+ Enabled: false
38
+
39
+ # Avoid methods longer than 50 lines of code
30
40
  MethodLength:
31
- Max: 30
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 premataure dependency to 'coveralls' gem
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
- raise Macros4Cuke::DataTableNotFound, error_message
21
+ fail(Macros4Cuke::DataTableNotFound, error_message)
22
22
  end
23
23
 
24
24
  # This will call the macro with the given phrase.
@@ -1,85 +1,85 @@
1
1
  # File: demo06.feature
2
2
 
3
- Feature: Show how to define conditional substeps in a macro-step.
3
+ Feature: Define conditional substeps in a macro-step.
4
4
  As a Cuke user
5
- So that I enjoy writing scenario.
5
+ So that I enjoy writing flexible scenarios.
6
6
 
7
7
 
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
- # 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
-
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
- When I generate a DataTableNotFound exception
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
- 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
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
- # 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!|
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
- # 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
- """
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"
@@ -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 Cucumeber project.
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
- raise Macros4Cuke::DataTableNotFound.new(macro_phrase)
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