class Lucid::ContextLoader::Orchestrator

Public Class Methods

new(user_interface, context={}) click to toggle source
# File lib/lucid/orchestrator.rb, line 30
def initialize(user_interface, context={})
  @context = Context.parse(context)
  @runtime_facade = ContextLoader::Facade.new(self, user_interface)
  @unsupported_languages = []
  @supported_languages = []
  @language_map = {}
end

Public Instance Methods

around(scenario, block) click to toggle source
# File lib/lucid/orchestrator.rb, line 121
def around(scenario, block)
  @supported_languages.reverse.inject(block) do |blk, programming_language|
    proc do
      programming_language.around(scenario) do
        blk.call(scenario)
      end
    end
  end.call
end
configure(new_context) click to toggle source
# File lib/lucid/orchestrator.rb, line 38
def configure(new_context)
  @context = Context.parse(new_context)
end
fire_hook(name, *args) click to toggle source
# File lib/lucid/orchestrator.rb, line 115
def fire_hook(name, *args)
  @supported_languages.each do |programming_language|
    programming_language.send(name, *args)
  end
end
invoke(step_name, multiline_argument=nil) click to toggle source
# File lib/lucid/orchestrator.rb, line 54
def invoke(step_name, multiline_argument=nil)
  multiline_argument = Lucid::AST::MultilineArgument.from(multiline_argument)
  begin
    step_match(step_name).invoke(multiline_argument)
  rescue Exception => e
    e.nested! if Undefined === e
    raise e
  end
end
invoke_steps(steps_text, i18n, file_colon_line) click to toggle source

Invokes a series of steps steps_text. Example:

invoke(%Q{
  Given lucid exists
  Then test specs can be executed
})
# File lib/lucid/orchestrator.rb, line 48
def invoke_steps(steps_text, i18n, file_colon_line)
  file, line = file_colon_line.split(':')
  parser = Gherkin::Parser::Parser.new(StepInvoker.new(self), true, 'steps', false, i18n.iso_code)
  parser.parse(steps_text, file, line.to_i)
end
load_code_language(type) click to toggle source

The orchestrator will register the the code language and load up an implementation of that language. There is a provision to make sure that the language is not already registered.

@param type [String] the type of file, passed in as an extension value @return [Object] language class

# File lib/lucid/orchestrator.rb, line 70
def load_code_language(type)
  return @language_map[type] if @language_map[type]
  lucid_language = create_object_of("Lucid::Interface#{type.capitalize}::#{type.capitalize}Language")
  language = lucid_language.new(@runtime_facade)
  @supported_languages << language
  @language_map[type] = language
  language
end
load_files(files) click to toggle source

The orchestrator will load only the loadable execution context files. This is how the orchestrator will, quite literally, orchestrate the execution of specs with the code logic that supports those specs.

@param files [Array] all files gathering for the execution context @see Lucid::ContextLoader.load_execution_context

# File lib/lucid/orchestrator.rb, line 85
def load_files(files)
  log.info("Orchestrator Load Files:\n")
  files.each do |file|
    load_file(file)
  end
  log.info("\n")
end
load_files_from_paths(paths) click to toggle source
# File lib/lucid/orchestrator.rb, line 93
def load_files_from_paths(paths)
  files = paths.map { |path| Dir["#{path}/**/*"] }.flatten
  load_files files
end
matcher_text(step_keyword, step_name, multiline_arg_class) click to toggle source
# File lib/lucid/orchestrator.rb, line 104
def matcher_text(step_keyword, step_name, multiline_arg_class)
  load_code_language('rb') if unknown_programming_language?
  @supported_languages.map do |programming_language|
    programming_language.matcher_text(step_keyword, step_name, multiline_arg_class, @context.matcher_type)
  end.join("\n")
end
step_definitions() click to toggle source
# File lib/lucid/orchestrator.rb, line 131
def step_definitions
  @supported_languages.map do |programming_language|
    programming_language.step_definitions
  end.flatten
end
step_match(step_name, name_to_report=nil) click to toggle source
# File lib/lucid/orchestrator.rb, line 137
def step_match(step_name, name_to_report=nil)
  @match_cache ||= {}

  match = @match_cache[[step_name, name_to_report]]
  return match if match

  @match_cache[[step_name, name_to_report]] = step_match_without_cache(step_name, name_to_report)
end
unknown_programming_language?() click to toggle source
# File lib/lucid/orchestrator.rb, line 111
def unknown_programming_language?
  @supported_languages.empty?
end
unmatched_step_definitions() click to toggle source
# File lib/lucid/orchestrator.rb, line 98
def unmatched_step_definitions
  @supported_languages.map do |programming_language|
    programming_language.unmatched_step_definitions
  end.flatten
end

Private Instance Methods

best_matches(step_name, step_matches) click to toggle source
# File lib/lucid/orchestrator.rb, line 166
def best_matches(step_name, step_matches)
  no_groups      = step_matches.select {|step_match| step_match.args.length == 0}
  max_arg_length = step_matches.map {|step_match| step_match.args.length }.max
  top_groups     = step_matches.select {|step_match| step_match.args.length == max_arg_length }

  if no_groups.any?
    longest_regexp_length = no_groups.map {|step_match| step_match.text_length }.max
    no_groups.select {|step_match| step_match.text_length == longest_regexp_length }
  elsif top_groups.any?
    shortest_capture_length = top_groups.map {|step_match| step_match.args.inject(0) {|sum, c| sum + c.to_s.length } }.min
    top_groups.select {|step_match| step_match.args.inject(0) {|sum, c| sum + c.to_s.length } == shortest_capture_length }
  else
    top_groups
  end
end
get_language_for(file) click to toggle source

The orchestrator will attempt to get the programming language for a specific code file, unless that code file is marked as being an unsupported language. An object is returned if the code file was part of a supported language. If an object is returned it will be an object of this sort:

Lucid::InterfaceRb::RbLanguage

@param file [String] relative path/file reference from the spec repo @return [nil or class] full class reference if found, nil otherwise

# File lib/lucid/orchestrator.rb, line 210
def get_language_for(file)
  extension = File.extname(file)[1..-1]

  if extension
    return nil if @unsupported_languages.index(extension)
    begin
      load_code_language(extension)
    rescue LoadError => e
      log.info("Unable to load '#{extension}' language for file #{file}: #{e.message}\n")
      @unsupported_languages << extension
      nil
    end
  else
    nil
  end
end
guess_step_matches?() click to toggle source
# File lib/lucid/orchestrator.rb, line 156
def guess_step_matches?
  @context.guess?
end
load_file(file) click to toggle source

For each execution context file, the orchestrator will determine the code language associated with the file.

@param file [String] relative path/file reference from the spec repo

# File lib/lucid/orchestrator.rb, line 186
def load_file(file)
  language = get_language_for(file)

  if language.nil?
    log.info("  * #{file} [NOT SUPPORTED]\n")
  else
    log.info("  * #{file}\n")
    language.load_code_file(file)
  end
end
log() click to toggle source
# File lib/lucid/orchestrator.rb, line 197
def log
  Lucid.logger
end
matches(step_name, name_to_report) click to toggle source
# File lib/lucid/orchestrator.rb, line 160
def matches(step_name, name_to_report)
  @supported_languages.map do |programming_language|
    programming_language.step_matches(step_name, name_to_report).to_a
  end.flatten
end
step_match_without_cache(step_name, name_to_report=nil) click to toggle source
# File lib/lucid/orchestrator.rb, line 148
def step_match_without_cache(step_name, name_to_report=nil)
  matches = matches(step_name, name_to_report)
  raise Undefined.new(step_name) if matches.empty?
  matches = best_matches(step_name, matches) if matches.size > 1 && guess_step_matches?
  raise Ambiguous.new(step_name, matches, guess_step_matches?) if matches.size > 1
  matches[0]
end