macros4cuke 0.0.02 → 0.1.00

Sign up to get free protection for your applications and to get access to all the features.
@@ -4,14 +4,12 @@ Feature: Show the use of a basic macro
4
4
  As a Cuke user
5
5
  So that I enjoy writing scenario.
6
6
 
7
- # The background section is THE good place to define your macros.
8
- # Since the steps from this section are pre-pended to the steps of every scenario (outline),
9
- # the macros will be available to every scenario in the feature file.
10
- Background:
7
+
8
+ Scenario: Definition of a simple macro-step
11
9
  # The next step creates a macro(-step)
12
- # The syntax of the new macro-step is specified between the < ... > delimiters.
10
+ # The syntax of the new macro-step is specified between double quotes.
13
11
  # The steps to execute when the macro is used/invoked are listed in the multiline triple quotes arguments.
14
- Given I define the step <When I [log in]> to mean:
12
+ Given I define the step "When I [log in]" to mean:
15
13
  """
16
14
  Given I landed in the homepage
17
15
  When I click "Sign in"
@@ -4,15 +4,13 @@ Feature: Show the use of a basic macro with one argument
4
4
  As a Cuke user
5
5
  So that I enjoy writing scenario.
6
6
 
7
- # The background section is THE good place to define your macros.
8
- # Since the steps from this section are pre-pended to the steps of every scenario (outline),
9
- # the macros will be available to every scenario in the feature file.
10
- Background:
7
+
8
+ Scenario: Creating a basic scenario with one argument
11
9
  # The next step creates a macro(-step)
12
- # The syntax of the new macro-step is specified between the < ... > delimiters.
10
+ # The syntax of the new macro-step is specified between the double quotes.
13
11
  # The steps to execute when the macro is used/invoked are listed in the multiline triple quotes arguments.
14
12
  # The macro argument is put between double(triple) curly braces {{...}} as required by the Mustache template library.
15
- Given I define the step <When I [log in as {{userid}}]> to mean:
13
+ Given I define the step "When I [log in as {{userid}}]" to mean:
16
14
  """
17
15
  Given I landed in the homepage
18
16
  When I click "Sign in"
@@ -4,15 +4,12 @@ Feature: Show the use of a basic macro with multiple arguments
4
4
  As a Cuke user
5
5
  So that I enjoy writing scenario.
6
6
 
7
- # The background section is THE good place to define your macros.
8
- # Since the steps from this section are pre-pended to the steps of every scenario (outline),
9
- # the macros will be available to every scenario in the feature file.
10
- Background:
11
- # The next step creates a macro(-step)
12
- # The syntax of the new macro-step is specified between the < ... > delimiters.
7
+
8
+ Scenario: defining basic macro with multiple arguments
9
+ # The next step creates a macro(-step)double quotes.
13
10
  # The steps to execute when the macro is used/invoked are listed in the multiline triple quotes arguments.
14
11
  # The macro argument is put between double(triple) curly braces {{...}} as required by the Mustache template library.
15
- Given I define the step <When I [enter my userid {{userid}} and password {{password}}]> to mean:
12
+ Given I define the step "When I [enter my userid {{userid}} and password {{password}}]" to mean:
16
13
  """
17
14
  Given I landed in the homepage
18
15
  When I click "Sign in"
@@ -36,7 +33,7 @@ Invoked step: ... I click "Submit"
36
33
  """
37
34
 
38
35
  Scenario: A macro invoking another macro (YES, it's possible!)
39
- Given I define the step <When I [enter my credentials]> to mean:
36
+ Given I define the step "When I [enter my credentials]" to mean:
40
37
  """
41
38
  {{! Notice that the next step is invoking the first macro above}}
42
39
  When I [enter my userid "guest" and password "unguessable"]
@@ -4,15 +4,13 @@ Feature: Show the use of a macro with multiple arguments in a table
4
4
  As a Cuke user
5
5
  So that I enjoy writing scenario.
6
6
 
7
- # The background section is THE good place to define your macros.
8
- # Since the steps from this section are pre-pended to the steps of every scenario (outline),
9
- # the macros will be available to every scenario in the feature file.
10
- Background:
7
+
8
+ Scenario: Defining a macro to be used with multiple arguments in a table
11
9
  # The next step creates a macro(-step)
12
- # The syntax of the new macro-step is specified between the < ... > delimiters.
10
+ # The syntax of the new macro-step is specified between double quotes.
13
11
  # The steps to execute when the macro is used/invoked are listed in the multiline triple quotes arguments.
14
12
  # The macro argument is put between double(triple) curly braces {{...}} as required by the Mustache template library.
15
- Given I define the step <When I [enter my credentials as]:> to mean:
13
+ Given I define the step "When I [enter my credentials as]:" to mean:
16
14
  """
17
15
  Given I landed in the homepage
18
16
  When I click "Sign in"
@@ -36,7 +36,6 @@ end # module
36
36
  World { Macros4Cuke::TracingWorld.new }
37
37
 
38
38
 
39
-
40
39
  # Macros4Cuke step two: extend the world object with the mix-in module
41
40
  # that adds the support for macros in Cucumber.
42
41
  World(Macros4Cuke::MacroStepSupport)
data/lib/macro_steps.rb CHANGED
@@ -3,69 +3,44 @@
3
3
 
4
4
 
5
5
 
6
- =begin This step is used to define a macro-step
7
- Example:
8
- Given I define the step <When I [create the following {{contactType}} contact]:> to mean:
9
- """
10
- # In the next step we use triple curly brace in order to get un-escaped text
11
- When I select "<type>" from "type"
12
- When I fill in "name" with "{{{name}}}"
13
- And I fill in "companyName" with "{{companyName}}"
14
- And I fill in "companyName2" with "{{companyName2}}"
15
- """
16
- =end
17
- Given(/^I define the step <When I \[([^\]]+\]:?)> to mean:$/) do |macro_phrase, template|
6
+ # This step is used to define a macro-step
7
+ # Example:
8
+ # Given I define the step "When I [log in as {{userid}}]" to mean:
9
+ # """
10
+ # Given I landed in the homepage
11
+ # When I click "Sign in"
12
+ # And I fill in "Username" with "{{userid}}"
13
+ # And I fill in "Password" with "unguessable"
14
+ # And I click "Submit"
15
+ # """
16
+
17
+ Given(/^I define the step "When I \[([^\]]+\]:?)" to mean:$/) do |macro_phrase, template|
18
18
  add_macro(macro_phrase, template)
19
19
  end
20
20
 
21
- =begin This step is used to invoke a simple macro-step
21
+ # This step is used to invoke a simple macro-step
22
22
  # Example:
23
- # Here we define a simple macro-step
24
- Given I define the step <When I [fly from {{origin}} to {{destination}} via {{waypoint}}]> to mean:
25
- """
26
- When I display the text "Departure: {{origin}}."
27
- When I display the text "Stop at: {{waypoint}}."
28
- When I display the text "Destination {{destination}}."
29
- """
30
- =end
23
+ # When I [log in as "guest"]
24
+ #
31
25
  When(/^I \[([^\]]+\])$/) do |macro_phrase|
32
- macro = find_macro(macro_phrase)
33
- raise StandardError, "Undefined macro step for '[#{macro_phrase}'." if macro.nil?
34
-
35
- # Retrieve macro argument names and their associated value from the table
36
- params = macro.validate_params(macro_phrase, nil)
37
-
38
- # Render the steps
39
- rendered_steps = macro.expand(params)
40
-
41
- # Execute the steps
42
- steps(rendered_steps)
26
+ invoke_macro(macro_phrase) # This will call the macro with the given phrase
43
27
  end
44
28
 
45
29
 
46
30
  # This step is used to invoke a macro-step with a table argument.
47
31
  # Example:
48
- # When I [create the following "Registrant" contact]:
49
- # |name|John Doe|
50
- # |city|Gotham City|
51
- # |street| Main street|
52
- # |street3| Small street|
32
+ # When I [enter my credentials as]:
33
+ # |userid |guest |
34
+ # |password|unguessable|
53
35
  When(/^I \[([^\]]+\]:)$/) do |macro_phrase, table_argument|
54
- macro = find_macro(macro_phrase)
55
- raise StandardError, "Undefined macro step for '#{macro_phrase}'." if macro.nil?
56
-
36
+ # Ensure that the second argument is of the correct type
57
37
  unless table_argument.kind_of?(Cucumber::Ast::Table)
58
- raise StandardError, "This step must have a table as an argument."
38
+ raise StandardError, "This step must have a data table as an argument."
59
39
  end
60
40
 
61
- # Retrieve macro argument names and their associated value from the table
62
- params = macro.validate_params(macro_phrase, table_argument.rows_hash())
63
-
64
- # Render the steps
65
- rendered_steps = macro.expand(params)
66
-
67
- # Execute the steps
68
- steps(rendered_steps)
41
+ # This will call the macro with the given phrase.
42
+ # The second argument consists of a hash with pairs of the kind: argument name => actual value
43
+ invoke_macro(macro_phrase, table_argument.rows_hash())
69
44
  end
70
45
 
71
46
 
@@ -3,7 +3,7 @@
3
3
 
4
4
  module Macros4Cuke # Module used as a namespace
5
5
  # This constant keeps the current version of the gem.
6
- Version = '0.0.02'
6
+ Version = '0.1.00'
7
7
 
8
8
  Description = "Macros for Cucumber"
9
9
 
@@ -0,0 +1,46 @@
1
+ # encoding: utf-8 -- You should see a paragraph character: §
2
+ # File: exceptions.rb
3
+
4
+ module Macros4Cuke # Module used as a namespace
5
+
6
+ # Base class for any exception explicitly raised in the Macros4Cuke methods.
7
+ class Macros4CukeError < StandardError
8
+ end # class
9
+
10
+ # Raised when one attempts to define a new macro
11
+ # that has the same phrase as an existing macro.
12
+ class DuplicateMacroError < Macros4CukeError
13
+ def initialize(aPhrase)
14
+ super("A macro-step with phrase '[#{aPhrase}' already exist.")
15
+ end
16
+ end # class
17
+
18
+
19
+
20
+ # Raised when one invokes a macro-step with an unknown phrase.
21
+ class UnknownMacroError < Macros4CukeError
22
+ def initialize(aPhrase)
23
+ super("Unknown macro-step with phrase: '[#{aPhrase}'.")
24
+ end
25
+ end # class
26
+
27
+
28
+
29
+ # Raised when one invokes a macro-step with an argument
30
+ # that has an unknown name.
31
+ class UnknownArgumentError < Macros4CukeError
32
+ def initialize(argName)
33
+ super("Unknown macro argument #{argName}.")
34
+ end
35
+ end # class
36
+
37
+
38
+ # Raised when Macros4Cuke encountered an issue
39
+ # that it can't handle properly.
40
+ class InternalError < Macros4CukeError
41
+ end # class
42
+
43
+
44
+ end # module
45
+
46
+ # End of file
@@ -0,0 +1,81 @@
1
+ # File: macro-collection.rb
2
+ # Purpose: Implementation of the MacroCollection class.
3
+
4
+ require 'singleton' # We'll use the Singleton design pattern for this class.
5
+ require_relative "macro-step"
6
+
7
+ module Macros4Cuke # Module used as a namespace
8
+
9
+ # Represents a container of macros.
10
+ # It gather all the macros encountered by Cucumber while "executing" the feature files.
11
+ class MacroCollection
12
+ include Singleton # Use the Singleton design pattern.
13
+
14
+ # A Hash with pairs of the form: phrase => MacroStep object
15
+ attr_reader(:macro_steps)
16
+
17
+ # Init the pool if it was not done yet.
18
+ def init()
19
+ @macro_steps = {} if @macro_steps.nil?
20
+ end
21
+
22
+ public
23
+ # Return true iff the host has a macro with the given key.
24
+ def has_macro?(aPhrase, mode)
25
+ key = MacroStep::macro_key(aPhrase, mode)
26
+ return @macro_steps.include? key
27
+ end
28
+
29
+
30
+ # Add a new macro.
31
+ # Pre-condition: there is no existing macro with the same key.
32
+ # [aPhrase] The text that is enclosed between the square brackets.
33
+ # [aTemplate] A text that consists of a sequence of Cucumber steps.
34
+ # These steps
35
+ def add_macro(aPhrase, aTemplate)
36
+ new_macro = MacroStep.new(aPhrase, aTemplate)
37
+
38
+ # Prevent collision of macros (macros with same phrase).
39
+ # This can occur if a macro was defined in a background section.
40
+ # An exception is raised if the phrase syntax of both macros are the
41
+ if find_macro(aPhrase)
42
+ pp find_macro(aPhrase)
43
+ raise DuplicateMacroError.new(aPhrase)
44
+ end
45
+
46
+ @macro_steps[new_macro.name] = new_macro
47
+
48
+ end
49
+
50
+ # Render the steps associated to the macro with given phrase
51
+ # and (optionally) given a table of values.
52
+ # Return the rendered steps as a text.
53
+ # [aPhrase] an instance of the macro phrase.
54
+ # [rawData] An Array of couples.
55
+ # Each couple is of the form: argument name, a value.
56
+ # Multiple rows with same argument name are acceptable.
57
+ def render_steps(aPhrase, rawData = nil)
58
+
59
+ macro = find_macro(aPhrase)
60
+ raise UnknownMacroError.new(aPhrase) if macro.nil?
61
+
62
+ # Retrieve macro argument names and their associated value from the table
63
+ params = macro.validate_params(aPhrase, rawData)
64
+
65
+ # Render the steps
66
+ rendered_steps = macro.expand(params)
67
+
68
+ end
69
+
70
+ private
71
+ # Retrieve the macro, given a phrase.
72
+ def find_macro(aMacroPhrase)
73
+ return @macro_steps[MacroStep::macro_key(aMacroPhrase, :invokation)]
74
+ end
75
+
76
+ end # class
77
+
78
+ end # module
79
+
80
+
81
+ # End of file
@@ -1,46 +1,48 @@
1
1
  # File: macro-step-support.rb
2
2
 
3
- require_relative "macro-step"
3
+ require_relative "exceptions"
4
+ require_relative "macro-collection"
4
5
 
5
6
  module Macros4Cuke # Module used as a namespace
6
7
 
7
- # Mix-in module that should be extending World objects of Cucumber.
8
- # Synopsis (in env.rb):
9
- module MacroStepSupport
8
+ # Mix-in module that should be extending World objects in Cucumber.
9
+ # Synopsis (in env.rb):
10
+ # require 'macros4cuke'
11
+ # ...
12
+ # World(Macros4Cuke::MacroStepSupport) # Extend the world object with this module.
13
+ #
14
+ module MacroStepSupport
10
15
 
11
16
  # Callback invoked when a World object is extend(ed) with this module.
12
17
  def self.extended(world)
13
- # Add & initialize an instance variable for macro support.
14
- world.clear_macro_steps()
18
+ # Add & initialize an instance variable for macro support.
19
+ MacroCollection::instance.init()
15
20
  end
16
21
 
17
-
22
+
18
23
  public
19
- # Remove all macro steps
20
- def clear_macro_steps()
21
- @macro_steps = {}
22
- end
23
-
24
- # Return true iff the host has a macro with the given key.
25
- def has_macro?(aMacroPhrase, mode)
26
- key = MacroStep::macro_key(aMacroPhrase, mode)
27
- return @macro_steps.include? key
28
- end
29
-
24
+
30
25
  # Add a new macro.
31
26
  # Pre-condition: there is no existing macro with the same key.
27
+ # [aPhrase] The text that is enclosed between the square brackets.
28
+ # [aTemplate] A text that consists of a sequence of Cucumber steps.
29
+ # These steps
32
30
  def add_macro(aPhrase, aTemplate)
33
- if has_macro?(aPhrase, :definition)
34
- raise StandardError, "Macro step for '[#{aPhrase}' already exist."
35
- else
36
- new_macro = MacroStep.new(aPhrase, aTemplate)
37
- @macro_steps[new_macro.name] = new_macro
38
- end
31
+ MacroCollection::instance.add_macro(aPhrase, aTemplate)
39
32
  end
33
+
40
34
 
41
- # Retrieve the macro, given a phrase.
42
- def find_macro(aMacroPhrase)
43
- return @macro_steps[MacroStep::macro_key(aMacroPhrase, :invokation)]
35
+ # Invoke a macro with given phrase and (optionally) a table of values
36
+ # [aPhrase] an instance of the macro phrase.
37
+ # [rawData] An Array of couples.
38
+ # Each couple is of the form: argument name, a value.
39
+ # Multiple rows with same argument name are acceptable.
40
+ def invoke_macro(aPhrase, rawData = nil)
41
+ # Generate a text rendition of the step to be executed.
42
+ rendered_steps = MacroCollection::instance.render_steps(aPhrase, rawData)
43
+
44
+ # Execute the steps
45
+ steps(rendered_steps)
44
46
  end
45
47
 
46
48
  end # module
@@ -5,7 +5,8 @@ require 'mustache' # Load the Mustache template library
5
5
 
6
6
  module Macros4Cuke # Module used as a namespace
7
7
 
8
- # In essence, a macro step object represents a Cucumber step that stands for a sequence of steps.
8
+ # In essence, a macro step object represents a Cucumber step that is itself
9
+ # an aggregation of lower-level Cucumber steps.
9
10
  class MacroStep
10
11
  # A Mustache instance that expands the steps upon request.
11
12
  attr_reader(:renderer)
@@ -18,6 +19,7 @@ class MacroStep
18
19
 
19
20
  # The list of macro argument names (as appearing in the Mustache template and in the macro phrase).
20
21
  attr_reader(:args)
22
+
21
23
 
22
24
  # Constructor.
23
25
  # [aMacroPhrase]
@@ -106,7 +108,7 @@ class MacroStep
106
108
 
107
109
  unless rawData.nil?
108
110
  rawData.each do |(key, value)|
109
- raise StandardError,"Unknown macro argument #{key}." unless @args.include? key
111
+ raise UnknownArgumentError.new(key) unless @args.include? key
110
112
  if macro_parameters.include? key
111
113
  if macro_parameters[key].kind_of?(Array)
112
114
  macro_parameters[key] << value
@@ -122,6 +124,7 @@ class MacroStep
122
124
  return macro_parameters
123
125
  end
124
126
 
127
+
125
128
 
126
129
  private
127
130
  # Retrieve from the macro phrase, all the text between "mustaches" or double quotes.
@@ -140,7 +143,7 @@ private
140
143
  when :invokation
141
144
  /"([^"]*)"/
142
145
  else
143
- raise Standard, "Internal error: Unknown mode argument #{mode}"
146
+ raise InternalError, "Internal error: Unknown mode argument #{mode}"
144
147
  end
145
148
  raw_result = aMacroPhrase.scan(pattern)
146
149
  return raw_result.flatten.compact
@@ -152,7 +155,7 @@ private
152
155
  def add_tags_multi(tokens)
153
156
  first_token = tokens.shift
154
157
  unless first_token == :multi
155
- raise StandardError, "Expecting a :multi token instead of a #{first_token}"
158
+ raise InternalError, "Expecting a :multi token instead of a #{first_token}"
156
159
  end
157
160
 
158
161
  tokens.each do |an_opcode|
@@ -166,7 +169,7 @@ private
166
169
  when String
167
170
  #Do nothing...
168
171
  else
169
- raise StandardError, "Unknown Mustache token type #{an_opcode.first}"
172
+ raise InternalError, "Unknown Mustache token type #{an_opcode.first}"
170
173
  end
171
174
  end
172
175
  end
@@ -178,8 +181,8 @@ private
178
181
  case mustache_opcode[0]
179
182
  when :etag
180
183
  triplet = mustache_opcode[1]
181
- raise StandardError, "expected 'mustache' token instead of '#{triplet[0]}'" unless triplet[0] == :mustache
182
- raise StandardError, "expected 'fetch' token instead of '#{triplet[1]}'" unless triplet[1] == :fetch
184
+ raise InternalError, "expected 'mustache' token instead of '#{triplet[0]}'" unless triplet[0] == :mustache
185
+ raise InternalError, "expected 'fetch' token instead of '#{triplet[1]}'" unless triplet[1] == :fetch
183
186
  @args << triplet.last
184
187
 
185
188
  when :fetch
@@ -189,7 +192,7 @@ private
189
192
  add_tags_section(mustache_opcode)
190
193
 
191
194
  else
192
- raise StandardError, "Unknown Mustache token type #{mustache_opcode.first}"
195
+ raise InternalError, "Unknown Mustache token type #{mustache_opcode.first}"
193
196
  end
194
197
  end
195
198
 
@@ -208,7 +211,7 @@ private
208
211
  when String
209
212
  return
210
213
  else
211
- raise StandardError, "Unknown Mustache token type #{op.first}"
214
+ raise InternalError, "Unknown Mustache token type #{op.first}"
212
215
  end
213
216
  end
214
217
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: macros4cuke
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.02
4
+ version: 0.1.00
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-04-21 00:00:00.000000000 Z
12
+ date: 2013-04-22 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake
@@ -60,8 +60,8 @@ dependencies:
60
60
  - !ruby/object:Gem::Version
61
61
  version: '0'
62
62
  description: ! "\tMacros4Cuke is a lightweight library that adds a macro facility
63
- your Cucumber scenarios.\n In short, you will be able to create new steps that
64
- will replace a sequence of lower-level steps. \n"
63
+ your Cucumber scenarios.\n In short, you can create new steps that replace a sequence
64
+ of lower-level steps. \n"
65
65
  email: famished.tiger@yahoo.com
66
66
  executables: []
67
67
  extensions: []
@@ -74,6 +74,8 @@ files:
74
74
  - lib/macros4cuke.rb
75
75
  - lib/macro_steps.rb
76
76
  - lib/macros4cuke/constants.rb
77
+ - lib/macros4cuke/exceptions.rb
78
+ - lib/macros4cuke/macro-collection.rb
77
79
  - lib/macros4cuke/macro-step-support.rb
78
80
  - lib/macros4cuke/macro-step.rb
79
81
  - features/demo01.feature