module Cucumber::Glue::ProtoWorld

Defines the basic API methods availlable in all Cucumber step definitions.

You can, and probably should, extend this API with your own methods that make sense in your domain. For more on that, see {Cucumber::Glue::Dsl#World}

Constants

AnsiEscapes

Defines aliases for ANSI coloured output. Default colours can be overridden by defining a GHERKIN_COLORS variable in your shell, very much like how you can tweak the familiar POSIX command ls with $LSCOLORS: linux-sxs.org/housekeeping/lscolors.html

The colours that you can change are:

undefined

defaults to yellow

pending

defaults to yellow

pending_arg

defaults to yellow,bold

executing

defaults to grey

executing_arg

defaults to grey,bold

failed

defaults to red

failed_arg

defaults to red,bold

passed

defaults to green

passed_arg

defaults to green,bold

outline

defaults to cyan

outline_arg

defaults to cyan,bold

skipped

defaults to cyan

skipped_arg

defaults to cyan,bold

comment

defaults to grey

tag

defaults to cyan

For instance, if your shell has a black background and a green font (like the “Homebrew” settings for OS X' Terminal.app), you may want to override passed steps to be white instead of green. Examples:

export GHERKIN_COLORS="passed=white"
export GHERKIN_COLORS="passed=white,bold:passed_arg=white,bold,underline"

(If you're on Windows, use SET instead of export). To see what colours and effects are available, just run this in your shell:

ruby -e "require 'rubygems'; require 'term/ansicolor'; puts Term::ANSIColor.attributes"

Although not listed, you can also use grey

Public Class Methods

extended(object) click to toggle source
# File lib/cucumber/glue/proto_world.rb, line 128
def self.extended(object)
  # wrap the dynamically generated module so that we can document the methods
  # for yardoc, which doesn't like define_method.
  object.extend(ProtoWorld)
end
for(runtime, language) click to toggle source

Dynamially generate the API module, closuring the dependencies

# File lib/cucumber/glue/proto_world.rb, line 126
def self.for(runtime, language)
  Module.new do
    def self.extended(object)
      # wrap the dynamically generated module so that we can document the methods
      # for yardoc, which doesn't like define_method.
      object.extend(ProtoWorld)
    end

    # TODO: pass these in when building the module, instead of mutating them later
    # Extend the World with user-defined modules
    def add_modules!(world_modules, namespaced_world_modules)
      add_world_modules!(world_modules)
      add_namespaced_modules!(namespaced_world_modules)
    end

    define_method(:step) do |name, raw_multiline_arg = nil|
      location = Core::Ast::Location.of_caller
      runtime.invoke_dynamic_step(name, MultilineArgument.from(raw_multiline_arg, location))
    end

    define_method(:steps) do |steps_text|
      location = Core::Ast::Location.of_caller
      runtime.invoke_dynamic_steps(steps_text, language, location)
    end

    # rubocop:disable UnneededInterpolation
    define_method(:puts) do |*messages|
      # Even though they won't be output until later, converting the messages to
      # strings right away will protect them from modifications to their original
      # objects in the mean time
      messages.collect! { |message| "#{message}" }

      runtime.puts(*messages)
    end
    # rubocop:enable UnneededInterpolation

    define_method(:ask) do |question, timeout_seconds = 60|
      runtime.ask(question, timeout_seconds)
    end

    define_method(:embed) do |file, mime_type, label = 'Screenshot'|
      runtime.embed(file, mime_type, label)
    end

    # Prints the list of modules that are included in the World
    def inspect
      modules = [self.class]
      (class << self; self; end).instance_eval do
        modules += included_modules
      end
      modules << stringify_namespaced_modules
      format('#<%s:0x%x>', modules.join('+'), self.object_id)
    end

    private

    # @private
    def add_world_modules!(modules)
      modules.each do |world_module|
        extend(world_module)
      end
    end

    # @private
    def add_namespaced_modules!(modules)
      @__namespaced_modules = modules
      modules.each do |namespace, world_modules|
        world_modules.each do |world_module|
          variable_name = "@__#{namespace}_world"

          inner_world = if self.class.respond_to?(namespace)
                          instance_variable_get(variable_name)
                        else
                          Object.new
                        end
          instance_variable_set(variable_name,
                                inner_world.extend(world_module))
          self.class.send(:define_method, namespace) do
            instance_variable_get(variable_name)
          end
        end
      end
    end

    # @private
    def stringify_namespaced_modules
      @__namespaced_modules.map { |k, v| "#{v.join(',')} (as #{k})" }.join('+')
    end
  end
end

Public Instance Methods

add_modules!(world_modules, namespaced_world_modules) click to toggle source

TODO: pass these in when building the module, instead of mutating them later Extend the World with user-defined modules

# File lib/cucumber/glue/proto_world.rb, line 136
def add_modules!(world_modules, namespaced_world_modules)
  add_world_modules!(world_modules)
  add_namespaced_modules!(namespaced_world_modules)
end
add_namespaced_modules!(modules) click to toggle source

@private

# File lib/cucumber/glue/proto_world.rb, line 190
def add_namespaced_modules!(modules)
  @__namespaced_modules = modules
  modules.each do |namespace, world_modules|
    world_modules.each do |world_module|
      variable_name = "@__#{namespace}_world"

      inner_world = if self.class.respond_to?(namespace)
                      instance_variable_get(variable_name)
                    else
                      Object.new
                    end
      instance_variable_set(variable_name,
                            inner_world.extend(world_module))
      self.class.send(:define_method, namespace) do
        instance_variable_get(variable_name)
      end
    end
  end
end
add_world_modules!(modules) click to toggle source

@private

# File lib/cucumber/glue/proto_world.rb, line 183
def add_world_modules!(modules)
  modules.each do |world_module|
    extend(world_module)
  end
end
ask(question, timeout_seconds = 60) click to toggle source

Pause the tests and ask the operator for input

Calls superclass method
# File lib/cucumber/glue/proto_world.rb, line 87
def ask(question, timeout_seconds = 60)
  super
end
embed(file, mime_type, label = 'Screenshot') click to toggle source

Embed an image in the output

Calls superclass method
# File lib/cucumber/glue/proto_world.rb, line 92
def embed(file, mime_type, label = 'Screenshot')
  super
end
inspect() click to toggle source

Prints the list of modules that are included in the World

Calls superclass method
# File lib/cucumber/glue/proto_world.rb, line 116
def inspect
  super
end
pending(message = 'TODO') { || ... } click to toggle source

Mark the matched step as pending.

# File lib/cucumber/glue/proto_world.rb, line 97
def pending(message = 'TODO')
  if block_given?
    begin
      yield
    rescue Exception
      raise Pending, message
    end
    raise Pending, "Expected pending '#{message}' to fail. No Error was raised. No longer pending?"
  else
    raise Pending, message
  end
end
puts(*messages) click to toggle source

Print a message to the output.

@note Cucumber might surprise you with the behaviour of this method. Instead

of sending the output directly to STDOUT, Cucumber will intercept and cache
the message until the current step has finished, and then display it.

If you'd prefer to see the message immediately, call {Kernel.puts} instead.
Calls superclass method
# File lib/cucumber/glue/proto_world.rb, line 82
def puts(*messages)
  super
end
skip_this_scenario(message = 'Scenario skipped') click to toggle source

Skips this step and the remaining steps in the scenario

# File lib/cucumber/glue/proto_world.rb, line 111
def skip_this_scenario(message = 'Scenario skipped')
  raise Core::Test::Result::Skipped, message
end
step(name, raw_multiline_arg = nil) click to toggle source

Run a single Gherkin step @example Call another step

step "I am logged in"

@example Call a step with quotes in the name

step %{the user "Dave" is logged in}

@example Passing a table

step "the following users exist:", table(%{
  | name  | email           |
  | Matt  | matt@matt.com   |
  | Aslak | aslak@aslak.com |
})

@example Passing a multiline string

step "the email should contain:", "Dear sir,\nYou've won a prize!\n"

@param [String] name The name of the step @param [String,Cucumber::Ast::DocString,Cucumber::Ast::Table] multiline_argument

Calls superclass method
# File lib/cucumber/glue/proto_world.rb, line 28
def step(name, raw_multiline_arg = nil)
  super
end
steps(steps_text) click to toggle source

Run a snippet of Gherkin @example

steps %{
  Given the user "Susan" exists
  And I am logged in as "Susan"
}

@param [String] steps_text The Gherkin snippet to run

Calls superclass method
# File lib/cucumber/glue/proto_world.rb, line 39
def steps(steps_text)
  super
end
stringify_namespaced_modules() click to toggle source

@private

# File lib/cucumber/glue/proto_world.rb, line 211
def stringify_namespaced_modules
  @__namespaced_modules.map { |k, v| "#{v.join(',')} (as #{k})" }.join('+')
end
table(text_or_table, file = nil, line = 0) click to toggle source

Parse Gherkin into a {Cucumber::Ast::Table} object.

Useful in conjunction with the step method. @example Create a table

users = table(%{
  | name  | email           |
  | Matt  | matt@matt.com   |
  | Aslak | aslak@aslak.com |
})

@param [String] text_or_table The Gherkin string that represents the table Returns a Cucumber::MultilineArgument::DataTable for text_or_table, which can either be a String:

table(%{
  | account | description | amount |
  | INT-100 | Taxi        | 114    |
  | CUC-101 | Peeler      | 22     |
})

or a 2D Array:

table([
  %w{ account description amount },
  %w{ INT-100 Taxi        114    },
  %w{ CUC-101 Peeler      22     }
])
# File lib/cucumber/glue/proto_world.rb, line 70
def table(text_or_table, file = nil, line = 0)
  location = !file ? Core::Ast::Location.of_caller : Core::Ast::Location.new(file, line)
  MultilineArgument::DataTable.from(text_or_table, location)
end
to_s() click to toggle source

see {#inspect}

# File lib/cucumber/glue/proto_world.rb, line 121
def to_s
  inspect
end