Klimi's new dotfiles with stow.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

148 lines
4.0 KiB

require 'rubygems'
gem 'ruby_parser'
# >= 2.11.8 because of https://github.com/cucumber/gherkin/commit/90121f513000b89fce4d24c4e7dfdae00a5b177f
gem 'gherkin', '>= 2.11.8', '< 4.0.0'
require 'ruby_parser'
require 'yaml'
require 'gherkin'
require 'gherkin/formatter/json_formatter'
class StepExtractor < Gherkin::Formatter::JSONFormatter
def initialize
super(StringIO.new)
end
# returns a Hash describing step at the line or nil if nothing
# executable found
def step_at(line)
@feature_hashes[0]['elements'].each do |element|
element['steps'].each do |step|
if step['line'] == line
if element['examples']
rows = element['examples'][0]['rows'].each
header = rows.next['cells']
examples = []
loop do
row = rows.next['cells']
example = {}
row.each_with_index do |val, idx|
example[header[idx]] = val
end
examples.push(example)
end
step['examples'] = examples
end
return step
end
end
end
nil
end
end
class Step
attr_reader :file, :line, :regexp
def initialize(regexp, file, line)
@file, @line = file, line
self.regexp = regexp
end
def regexp=(value)
@regexp =
case value
when String
pieces, regexp = [], value.dup
regexp.gsub!(/\$\w+/) { |match| pieces << match; "TOKEN" }
regexp.gsub!(/(?=\{)(.*?)(\})/, "TOKEN")
regexp = Regexp.escape(regexp)
regexp.gsub!(/TOKEN/) { |match| "(.*)" }
Regexp.new("^#{regexp}$")
when Regexp
value
else
STDERR.puts "Warning: invalid parameter to Given/When/Then on #{file}:#{line}. Expected Regexp or String, got #{value.class} #{value.inspect}"
Regexp.new(/^INVALID PARAM$/)
end
end
def match?(text)
@regexp.match(text)
end
end
class StepParser
attr_accessor :steps, :file
def initialize(file, keywords)
@file = file
@steps = []
@keywords = keywords
extract_steps(RubyParser.new.parse(File.read(file)))
end
def extract_steps(sexp)
return unless sexp.is_a?(Sexp)
case sexp.first
when :block
sexp[1..-1].each do |child_sexp|
extract_steps(child_sexp)
end
when :iter
child_sexp = sexp[1]
return unless child_sexp[0] == :call && @keywords.include?(child_sexp[2])
regexp = child_sexp[3][1]
@steps << Step.new(regexp, file, child_sexp.line)
else
sexp.each do |child|
extract_steps(child)
end
end
end
end
iso_code, feature_path, line, step_search_path, step_search_path_extra, = ARGV
extractor = StepExtractor.new
parser = Gherkin::Parser::Parser.new(extractor, true, 'root', false, iso_code)
parser.parse(IO.read(feature_path), feature_path, 0)
step_info = extractor.step_at(line.to_i)
inputs = if step_info['examples']
# If the step has example placeholders, we should substitute them
# and provide user a choice
placeholders = step_info['examples'].first.keys.map { |key| %r(<(#{key})>) }
step_info['examples'].map do |example|
step_info['name'].gsub(Regexp.union(placeholders)) do |p|
example[p.gsub(/[<>]/, '')]
end
end.uniq
else
[step_info['name']]
end
quick_exit = inputs.size == 1
def results_to_alist(results)
results.uniq! { |(_, file, line)| [file, line]}
pairs = results.reduce("") do |acc, (input, file, line)|
acc << sprintf("(%s . %s)", input.inspect, [file, line].join(":").inspect)
end
"(#{pairs})"
end
results = []
keywords = Gherkin::I18n.get(iso_code).step_keywords[1..-1].map { |k| k.strip.to_sym }
files = Dir[step_search_path]
files.push(*Dir[step_search_path_extra]) if !step_search_path_extra.nil?
files.each_with_index do |file, i|
StepParser.new(file, keywords).steps.each do |step|
inputs.each do |input_text|
if step.match?(input_text)
results.push([input_text, step.file, step.line])
if quick_exit
print results_to_alist(results)
exit
end
end
end
end
end
print results_to_alist(results)