require 'gherkin/rubify' require 'gherkin/tag_expression' require 'gherkin/formatter/regexp_filter' require 'gherkin/formatter/line_filter' require 'gherkin/formatter/model' module Gherkin module Formatter class FilterFormatter include Rubify def initialize(formatter, filters) @formatter = formatter @filter = detect_filter(filters) @feature_tags = [] @feature_element_tags = [] @examples_tags = [] @feature_events = [] @background_events = [] @feature_element_events = [] @examples_events = [] end def feature(statement, uri) @feature_tags = statement.tags @feature_name = statement.name @feature_events = [[:feature, statement, uri]] end def background(statement) @feature_element_name = statement.name @feature_element_range = statement.line_range @background_events = [[:background, statement]] end def scenario(statement) replay! @feature_element_tags = statement.tags @feature_element_name = statement.name @feature_element_range = statement.line_range @feature_element_events = [[:scenario, statement]] @examples_events.clear end def scenario_outline(statement) replay! @feature_element_tags = statement.tags @feature_element_name = statement.name @feature_element_range = statement.line_range @feature_element_events = [[:scenario_outline, statement]] @examples_events.clear end def examples(statement, examples_rows) replay! @examples_tags = statement.tags @examples_name = statement.name table_body_range = examples_rows.to_a[1].line..examples_rows.to_a[-1].line @examples_range = statement.line_range.first..table_body_range.last if(LineFilter === @filter && @filter.eval([table_body_range])) examples_rows = @filter.filter_table_body_rows(examples_rows) end @examples_events = [[:examples, statement, examples_rows]] end def step(statement, multiline_arg, result) args = [:step, statement, multiline_arg, result] if @feature_element_events.any? @feature_element_events << args else @background_events << args end if LineFilter === @filter step_range = statement.line_range case rubify(multiline_arg) when Model::PyString step_range = step_range.first..multiline_arg.line_range.last when Array step_range = step_range.first..multiline_arg.to_a[-1].line end @feature_element_range = @feature_element_range.first..step_range.last end end def eof replay! @formatter.eof end private def detect_filter(filters) raise "Inconsistent filters: #{filters.inspect}" if filters.map{|filter| filter.class}.uniq.length > 1 case(filters[0]) when Fixnum LineFilter.new(filters) when Regexp RegexpFilter.new(filters) when String TagExpression.new(filters) end end def replay! case @filter when TagExpression background_ok = false feature_element_ok = @filter.eval(tag_names(@feature_tags.to_a + @feature_element_tags.to_a)) examples_ok = @filter.eval(tag_names(@feature_tags.to_a + @feature_element_tags.to_a + @examples_tags.to_a)) if @examples_tags when RegexpFilter background_ok = @filter.eval([@background_name]) if @background_name feature_element_ok = @filter.eval([@feature_element_name]) examples_ok = @filter.eval([@feature_element_name, @examples_name]) if @examples_name when LineFilter background_ok = @filter.eval([@background_range]) if @background_range feature_element_ok = @filter.eval([@feature_element_range]) if @feature_element_range examples_ok = @filter.eval([@feature_element_range, @examples_range]) if @examples_range end if background_ok || feature_element_ok || examples_ok replay_events!(@feature_events) replay_events!(@background_events) if feature_element_ok || examples_ok replay_events!(@feature_element_events) if examples_ok replay_events!(@examples_events) end end end end def tag_names(tags) tags.to_a.uniq.map{|tag| tag.name} end def replay_events!(events) events.each do |event| @formatter.__send__(*event) end events.clear end end end end