macros4cuke 0.3.42 → 0.4.00

Sign up to get free protection for your applications and to get access to all the features.
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