class Macros4Cuke::MacroStep
A macro-step object is a Cucumber step that is itself an aggregation of lower-level sub-steps. When a macro-step is used in a scenario, then its execution is equivalent to the execution of its sub-steps. A macro-step may have zero or more arguments. The actual values bound to these arguments are passed to the sub-steps at execution time.
Constants
- BuiltinParameters
The set of predefined macro argument constant values.
Attributes
The list of macro argument names (as appearing in the substeps AND in the macro phrase).
Unique key of the macro as derived from the macro phrase.
The sentence fragment that defines the syntax of the macro-step
The list of macro arguments that appears in the macro phrase.
A template engine that expands the sub-steps upon request.
Public Class Methods
Compute the identifier of the macro from the given macro phrase. A macro phrase is a text that may contain zero or more placeholders. In definition mode, a placeholder is delimited by chevrons <..>. In invokation mode, a value bound to a placeholder is delimited by double quotes. The rule for building the identifying key are:
-
Leading and trailing space(s) are removed.
-
Each underscore character is removed.
-
Every sequence of one or more space(s) is converted into an underscore
-
Each placeholder (i.e. = delimiters + enclosed text)
is converted into a letter X.
-
when useTable is true, concatenate: _T
@example:
Consider the macro phrase: 'create the following "contactType" contact' The resulting macro_key is: 'create_the_following_X_contact_T'
@param aMacroPhrase [String] The text from the macro step definition
that is between the square brackets.
@param useTable [boolean] A flag indicating whether a table
should be used to pass actual values.
@param mode [:definition, :invokation] @return [String] the key of the phrase/macro.
# File lib/macros4cuke/macro-step.rb, line 82 def self.macro_key(aMacroPhrase, useTable, mode) stripped_phrase = aMacroPhrase.strip # Remove leading ... trailing space(s) # Remove every underscore stripped_phrase.delete!('_') # Replace all consecutive whitespaces by an underscore stripped_phrase.gsub!(/\s+/, '_') # Determine the pattern to isolate # each argument/parameter with its delimiters pattern = case mode when :definition /<(?:[^\\<>]|\\.)*>/ when :invokation /"([^\\"]|\\.)*"/ end # Each text between quotes or chevron is replaced by the letter X normalized = stripped_phrase.gsub(pattern, 'X') key = normalized + (useTable ? '_T' : '') return key end
Constructor. @param aMacroPhrase The text from the macro step definition
that is between the square brackets.
@param theSubsteps [String] The source text of the steps to be expanded
upon macro invokation.
@param useTable [boolean] A flag indicating whether a data table
must be used to pass actual values.
# File lib/macros4cuke/macro-step.rb, line 46 def initialize(aMacroPhrase, theSubsteps, useTable) @phrase = aMacroPhrase @key = self.class.macro_key(aMacroPhrase, useTable, :definition) # Retrieve the macro arguments embedded in the phrase. @phrase_args = scan_arguments(aMacroPhrase, :definition) @renderer = Templating::Engine.new(theSubsteps) substeps_vars = renderer.variables @args = validate_phrase_args(@phrase_args, substeps_vars) @args.concat(substeps_vars) @args.uniq! end
Public Instance Methods
Render the steps from the template, given the values taken by the parameters @param aPhrase [String] an instance of the macro phrase. @param rawData [Array or nil] An Array with couples of the form: [macro argument name, a value].
Multiple rows with same argument name are acceptable.
# File lib/macros4cuke/macro-step.rb, line 115 def expand(aPhrase, rawData) params = validate_params(aPhrase, rawData) # Add built-in constants if necessary. params = BuiltinParameters.merge(params) return renderer.render(nil, params) end
Private Instance Methods
Retrieve from the macro phrase, all the text between <..> or double quotes. Returns an array. Each of its elements corresponds to quoted text. Example: aMacroPhrase = 'a “qualifier” text with “quantity” placeholders.' Results in : [“qualifier”, “quantity”]
- aMacroPhrase
-
A phrase
- mode
-
one of the following: :definition, :invokation
# File lib/macros4cuke/macro-step.rb, line 180 def scan_arguments(aMacroPhrase, mode) # determine the syntax of the arguments/parameters # as a regular expression with one capturing group pattern = case mode when :definition /<((?:[^\\<>]|\\.)*)>/ # /{{{([^}]*)}}}|{{([^}]*)}}/ # Two capturing groups!... when :invokation /"((?:[^\\"]|\\.)*)"/ end raw_result = aMacroPhrase.scan(pattern) args = raw_result.flatten.compact # Replace escaped quotes by quote character. args.map! { |arg| arg.sub(/\\"/, '"') } if mode == :invokation return args end
Return true, if the macro-step requires a data table to pass actual values of the arguments.
# File lib/macros4cuke/macro-step.rb, line 224 def use_table?() return key =~ /_T$/ end
Build a Hash from the given raw data. @param aPhrase [String] an instance of the macro phrase. @param rawData [Array or nil] An Array with coupples of the form: [macro argument name, a value]. Multiple rows with same argument name are acceptable.
# File lib/macros4cuke/macro-step.rb, line 131 def validate_params(aPhrase, rawData) macro_parameters = {} # Retrieve the value(s) per variable in the phrase. quoted_values = scan_arguments(aPhrase, :invokation) quoted_values.each_with_index do |val, index| macro_parameters[phrase_args[index]] = val end if rawData rawData.each do |a_row| (a_key, value) = validate_row(a_row, macro_parameters) if macro_parameters.include? a_key if macro_parameters[a_key].is_a?(Array) macro_parameters[a_key] << value else macro_parameters[a_key] = [macro_parameters[a_key], value] end else macro_parameters[a_key] = value end end end return macro_parameters end
Check for inconsistencies between the argument names in the phrase and the substeps part.
# File lib/macros4cuke/macro-step.rb, line 201 def validate_phrase_args(thePhraseArgs, substepsVars) # Error when the phrase names an argument that never occurs in the substeps thePhraseArgs.each do |phrase_arg| next if substepsVars.include? phrase_arg raise(UselessPhraseArgument.new(phrase_arg)) end # Error when a substep has an argument that never appears in the phrase # and the macro-step does not use data table. unless use_table? substepsVars.each do |substep_arg| next if thePhraseArgs.include?(substep_arg) || BuiltinParameters.include?(substep_arg) raise(UnreachableSubstepArgument.new(substep_arg)) end end return thePhraseArgs.dup end
Validate a row from the data table. Return the validated row. @param a_row [Array] A 2-elements Array (i.e. a couple) of the form: [macro argument name, a value]. @param params [Hash] The pairs phrase argument name => value
# File lib/macros4cuke/macro-step.rb, line 163 def validate_row(a_row, params) (a_key, value) = a_row raise(UnknownArgumentError.new(a_key)) unless args.include? a_key if (phrase_args.include? a_key) && (params[a_key] != value) raise(AmbiguousArgumentValue.new(a_key, params[a_key], value)) end return a_row end