class CukeModeler::Gherkin20Adapter

NOT A PART OF THE PUBLIC API An adapter that can convert the output of version 20.x of the cucumber-gherkin gem into input that is consumable by this gem.

Public Instance Methods

adapt(ast) click to toggle source

Adapts the given AST into the shape that this gem expects

# File lib/cuke_modeler/adapters/gherkin_20_adapter.rb, line 14
def adapt(ast)
  adapted_ast = {}

  # Saving off the original data and removing parsed data for child elements in order to avoid duplicating data
  save_original_data(adapted_ast, ast)
  clear_child_elements(adapted_ast, [[:feature], [:comments]])

  adapted_ast['comments'] = adapt_comments(ast)
  adapted_ast['feature'] = adapt_feature(ast.feature)

  adapted_ast
end
adapt_background(background_ast) click to toggle source

Adapts the AST sub-tree that is rooted at the given background node.

# File lib/cuke_modeler/adapters/gherkin_20_adapter.rb, line 50
def adapt_background(background_ast)
  adapted_background = {}

  # Saving off the original data and removing parsed data for child elements in order to avoid duplicating data
  save_original_data(adapted_background, background_ast)
  clear_child_elements(adapted_background, [[:background, :steps]])

  adapted_background['type'] = 'Background'
  adapted_background['keyword'] = background_ast.background.keyword
  adapted_background['name'] = background_ast.background.name
  adapted_background['description'] = background_ast.background.description
  adapted_background['line'] = background_ast.background.location.line

  adapted_background['steps'] = adapt_steps(background_ast.background)

  adapted_background
end
adapt_comment(comment_ast) click to toggle source

Adapts the AST sub-tree that is rooted at the given comment node.

# File lib/cuke_modeler/adapters/gherkin_20_adapter.rb, line 174
def adapt_comment(comment_ast)
  adapted_comment = {}

  # Saving off the original data
  save_original_data(adapted_comment, comment_ast)

  adapted_comment['text'] = comment_ast.text
  adapted_comment['line'] = comment_ast.location.line

  adapted_comment
end
adapt_doc_string(doc_string_ast) click to toggle source

Adapts the AST sub-tree that is rooted at the given doc string node.

# File lib/cuke_modeler/adapters/gherkin_20_adapter.rb, line 209
def adapt_doc_string(doc_string_ast)
  adapted_doc_string = {}

  # Saving off the original data
  save_original_data(adapted_doc_string, doc_string_ast)

  adapted_doc_string['value'] = doc_string_ast.content
  adapted_doc_string['content_type'] = doc_string_ast.media_type
  adapted_doc_string['line'] = doc_string_ast.location.line

  adapted_doc_string
end
adapt_example(example_ast) click to toggle source

Adapts the AST sub-tree that is rooted at the given example node.

# File lib/cuke_modeler/adapters/gherkin_20_adapter.rb, line 134
def adapt_example(example_ast)
  adapted_example = {}

  # Saving off the original data and removing parsed data for child elements in order to avoid duplicating data
  save_original_data(adapted_example, example_ast)
  clear_child_elements(adapted_example, [[:tags],
                                         [:table_header],
                                         [:table_body]])

  adapted_example['keyword'] = example_ast.keyword
  adapted_example['name'] = example_ast.name
  adapted_example['line'] = example_ast.location.line
  adapted_example['description'] = example_ast.description

  adapted_example['rows'] = []
  adapted_example['rows'] << adapt_table_row(example_ast.table_header) if example_ast.table_header

  example_ast.table_body&.each do |row|
    adapted_example['rows'] << adapt_table_row(row)
  end

  adapted_example['tags'] = adapt_tags(example_ast)

  adapted_example
end
adapt_feature(feature_ast) click to toggle source

Adapts the AST sub-tree that is rooted at the given feature node.

# File lib/cuke_modeler/adapters/gherkin_20_adapter.rb, line 28
def adapt_feature(feature_ast)
  return nil unless feature_ast

  adapted_feature = {}

  # Saving off the original data and removing parsed data for child elements in order to avoid duplicating data
  save_original_data(adapted_feature, feature_ast)
  clear_child_elements(adapted_feature, [[:tags],
                                         [:children]])

  adapted_feature['keyword'] = feature_ast.keyword
  adapted_feature['name'] = feature_ast.name
  adapted_feature['description'] = feature_ast.description
  adapted_feature['line'] = feature_ast.location.line

  adapted_feature['elements'] = adapt_child_elements(feature_ast)
  adapted_feature['tags'] = adapt_tags(feature_ast)

  adapted_feature
end
adapt_outline(test_ast) click to toggle source

Adapts the AST sub-tree that is rooted at the given outline node.

# File lib/cuke_modeler/adapters/gherkin_20_adapter.rb, line 111
def adapt_outline(test_ast)
  adapted_outline = {}

  # Saving off the original data and removing parsed data for child elements in order to avoid duplicating data
  save_original_data(adapted_outline, test_ast)
  clear_child_elements(adapted_outline, [[:scenario, :tags],
                                         [:scenario, :steps],
                                         [:scenario, :examples]])

  adapted_outline['type'] = 'ScenarioOutline'
  adapted_outline['keyword'] = test_ast.scenario.keyword
  adapted_outline['name'] = test_ast.scenario.name
  adapted_outline['description'] = test_ast.scenario.description
  adapted_outline['line'] = test_ast.scenario.location.line

  adapted_outline['tags'] = adapt_tags(test_ast.scenario)
  adapted_outline['steps'] = adapt_steps(test_ast.scenario)
  adapted_outline['examples'] = adapt_examples(test_ast.scenario)

  adapted_outline
end
adapt_rule(rule_ast) click to toggle source

Adapts the AST sub-tree that is rooted at the given rule node.

# File lib/cuke_modeler/adapters/gherkin_20_adapter.rb, line 69
def adapt_rule(rule_ast)
  adapted_rule = {}

  # Saving off the original data and removing parsed data for child elements in order to avoid duplicating data
  save_original_data(adapted_rule, rule_ast)
  clear_child_elements(adapted_rule, [[:rule, :tags],
                                      [:rule, :children]])

  adapted_rule['type'] = 'Rule'
  adapted_rule['keyword'] = rule_ast.rule.keyword
  adapted_rule['name'] = rule_ast.rule.name
  adapted_rule['description'] = rule_ast.rule.description
  adapted_rule['line'] = rule_ast.rule.location.line

  adapted_rule['elements'] = adapt_child_elements(rule_ast.rule)
  adapted_rule['tags'] = adapt_tags(rule_ast.rule)

  adapted_rule
end
adapt_scenario(test_ast) click to toggle source

Adapts the AST sub-tree that is rooted at the given scenario node.

# File lib/cuke_modeler/adapters/gherkin_20_adapter.rb, line 90
def adapt_scenario(test_ast)
  adapted_scenario = {}

  # Saving off the original data and removing parsed data for child elements in order to avoid duplicating data
  save_original_data(adapted_scenario, test_ast)
  clear_child_elements(adapted_scenario, [[:scenario, :tags],
                                          [:scenario, :steps]])

  adapted_scenario['type'] = 'Scenario'
  adapted_scenario['keyword'] = test_ast.scenario.keyword
  adapted_scenario['name'] = test_ast.scenario.name
  adapted_scenario['description'] = test_ast.scenario.description
  adapted_scenario['line'] = test_ast.scenario.location.line

  adapted_scenario['tags'] = adapt_tags(test_ast.scenario)
  adapted_scenario['steps'] = adapt_steps(test_ast.scenario)

  adapted_scenario
end
adapt_step(step_ast) click to toggle source

Adapts the AST sub-tree that is rooted at the given step node.

# File lib/cuke_modeler/adapters/gherkin_20_adapter.rb, line 187
def adapt_step(step_ast)
  adapted_step = {}

  # Saving off the original data and removing parsed data for child elements in order to avoid duplicating data
  save_original_data(adapted_step, step_ast)
  clear_child_elements(adapted_step, [[:data_table],
                                      [:doc_string]])

  adapted_step['keyword'] = step_ast.keyword
  adapted_step['name'] = step_ast.text
  adapted_step['line'] = step_ast.location.line

  if step_ast.doc_string
    adapted_step['doc_string'] = adapt_doc_string(step_ast.doc_string)
  elsif step_ast.data_table
    adapted_step['table'] = adapt_step_table(step_ast.data_table)
  end

  adapted_step
end
adapt_step_table(step_table_ast) click to toggle source

Adapts the AST sub-tree that is rooted at the given table node.

# File lib/cuke_modeler/adapters/gherkin_20_adapter.rb, line 223
def adapt_step_table(step_table_ast)
  adapted_step_table = {}

  # Saving off the original data and removing parsed data for child elements in order to avoid duplicating data
  save_original_data(adapted_step_table, step_table_ast)
  clear_child_elements(adapted_step_table, [[:rows]])

  adapted_step_table['rows'] = []
  step_table_ast.rows.each do |row|
    adapted_step_table['rows'] << adapt_table_row(row)
  end
  adapted_step_table['line'] = step_table_ast.location.line

  adapted_step_table
end
adapt_table_cell(cell_ast) click to toggle source

Adapts the AST sub-tree that is rooted at the given cell node.

# File lib/cuke_modeler/adapters/gherkin_20_adapter.rb, line 258
def adapt_table_cell(cell_ast)
  adapted_cell = {}

  # Saving off the original data
  save_original_data(adapted_cell, cell_ast)

  adapted_cell['value'] = cell_ast.value
  adapted_cell['line'] = cell_ast.location.line

  adapted_cell
end
adapt_table_row(table_row_ast) click to toggle source

Adapts the AST sub-tree that is rooted at the given row node.

# File lib/cuke_modeler/adapters/gherkin_20_adapter.rb, line 240
def adapt_table_row(table_row_ast)
  adapted_table_row = {}

  # Saving off the original data and removing parsed data for child elements in order to avoid duplicating data
  save_original_data(adapted_table_row, table_row_ast)
  clear_child_elements(adapted_table_row, [[:cells]])

  adapted_table_row['line'] = table_row_ast.location.line

  adapted_table_row['cells'] = []
  table_row_ast.cells.each do |row|
    adapted_table_row['cells'] << adapt_table_cell(row)
  end

  adapted_table_row
end
adapt_tag(tag_ast) click to toggle source

Adapts the AST sub-tree that is rooted at the given tag node.

# File lib/cuke_modeler/adapters/gherkin_20_adapter.rb, line 161
def adapt_tag(tag_ast)
  adapted_tag = {}

  # Saving off the original data
  save_original_data(adapted_tag, tag_ast)

  adapted_tag['name'] = tag_ast.name
  adapted_tag['line'] = tag_ast.location.line

  adapted_tag
end

Private Instance Methods

adapt_child_elements(element_ast) click to toggle source
# File lib/cuke_modeler/adapters/gherkin_20_adapter.rb, line 290
def adapt_child_elements(element_ast)
  adapted_children = []

  element_ast.children.each do |child_element|
    adapted_children << if child_element.background
                          adapt_background(child_element)
                        elsif child_element.respond_to?(:rule) && child_element.rule
                          adapt_rule(child_element)
                        else
                          adapt_test(child_element)
                        end
  end

  adapted_children
end
adapt_comments(file_ast) click to toggle source
# File lib/cuke_modeler/adapters/gherkin_20_adapter.rb, line 274
def adapt_comments(file_ast)
  file_ast.comments.map { |comment| adapt_comment(comment) }
end
adapt_examples(element_ast) click to toggle source
# File lib/cuke_modeler/adapters/gherkin_20_adapter.rb, line 286
def adapt_examples(element_ast)
  element_ast.examples.map { |example| adapt_example(example) }
end
adapt_steps(element_ast) click to toggle source
# File lib/cuke_modeler/adapters/gherkin_20_adapter.rb, line 282
def adapt_steps(element_ast)
  element_ast.steps.map { |step| adapt_step(step) }
end
adapt_tags(element_ast) click to toggle source
# File lib/cuke_modeler/adapters/gherkin_20_adapter.rb, line 278
def adapt_tags(element_ast)
  element_ast.tags.map { |tag| adapt_tag(tag) }
end
adapt_test(test_ast) click to toggle source
# File lib/cuke_modeler/adapters/gherkin_20_adapter.rb, line 306
def adapt_test(test_ast)
  if test_has_examples?(test_ast) || test_uses_outline_keyword?(test_ast)
    adapt_outline(test_ast)
  else
    adapt_scenario(test_ast)
  end
end
clear_child_elements(ast, child_paths) click to toggle source
# File lib/cuke_modeler/adapters/gherkin_20_adapter.rb, line 314
def clear_child_elements(ast, child_paths)
  # rubocop:disable Security/Eval - This is not blind data
  child_paths.each do |traversal_path|
    # Wipe the value if it's there but don't add any attributes to the object if it didn't already have them
    if eval("ast['cuke_modeler_parsing_data'].#{traversal_path.join('.')}", binding, __FILE__, __LINE__)
      property_path = traversal_path[0..-2].join('.')
      eval("ast['cuke_modeler_parsing_data']#{property_path.empty? ? '' : '.' + property_path}.instance_variable_set(\"@#{traversal_path.last}\", nil)", binding, __FILE__, __LINE__) # rubocop:disable Layout/LineLength
    end
  end
  # rubocop:enable Security/Eval
end
test_has_examples?(ast_node) click to toggle source
# File lib/cuke_modeler/adapters/gherkin_20_adapter.rb, line 326
def test_has_examples?(ast_node)
  ast_node.scenario.examples.any?
end
test_uses_outline_keyword?(test_ast) click to toggle source
# File lib/cuke_modeler/adapters/gherkin_20_adapter.rb, line 330
def test_uses_outline_keyword?(test_ast)
  Parsing.dialects[Parsing.dialect]['scenarioOutline'].include?(test_ast.scenario.keyword)
end