gherkin 1.0.3-java → 1.0.4-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History.txt +15 -6
 - data/README.rdoc +23 -0
 - data/Rakefile +1 -0
 - data/VERSION.yml +1 -1
 - data/features/step_definitions/gherkin_steps.rb +1 -1
 - data/features/step_definitions/{pretty_printer_steps.rb → pretty_listener_step.rb} +2 -2
 - data/gherkin.gemspec +24 -35
 - data/java/Gherkin.iml +8 -14
 - data/java/src/{gherkin → main/java/gherkin}/lexer/.gitignore +0 -0
 - data/lib/gherkin.rb +1 -1
 - data/lib/gherkin/c_lexer.rb +2 -2
 - data/lib/gherkin/{format → formatter}/argument.rb +1 -1
 - data/lib/gherkin/{tools → formatter}/colors.rb +1 -1
 - data/lib/gherkin/{format → formatter}/monochrome_format.rb +1 -1
 - data/lib/gherkin/{tools → formatter}/pretty_listener.rb +8 -9
 - data/lib/gherkin/i18n.rb +27 -5
 - data/lib/gherkin/i18n_lexer.rb +18 -44
 - data/lib/gherkin/parser/filter_listener.rb +191 -0
 - data/lib/gherkin/parser/parser.rb +142 -0
 - data/lib/gherkin/parser/sexp.rb +45 -0
 - data/lib/gherkin/parser/tag_expression.rb +46 -0
 - data/lib/gherkin/rb_lexer.rb +2 -2
 - data/ragel/lexer_common.rl.erb +1 -1
 - data/spec/gherkin/{format → formatter}/argument_spec.rb +2 -2
 - data/spec/gherkin/{tools → formatter}/colors_spec.rb +2 -2
 - data/spec/gherkin/{tools → formatter}/pretty_listener_spec.rb +5 -5
 - data/spec/gherkin/i18n_lexer_spec.rb +3 -3
 - data/spec/gherkin/parser/filter_listener_spec.rb +363 -0
 - data/spec/gherkin/parser/parser_spec.rb +35 -0
 - data/spec/gherkin/parser/tag_expression_spec.rb +120 -0
 - data/spec/gherkin/rb_lexer_spec.rb +0 -1
 - data/spec/gherkin/sexp_recorder.rb +3 -3
 - data/spec/gherkin/shared/lexer_spec.rb +19 -19
 - data/spec/gherkin/shared/tags_spec.rb +4 -4
 - data/tasks/bench.rake +2 -2
 - data/tasks/compile.rake +1 -1
 - data/tasks/ragel_task.rb +1 -1
 - metadata +25 -36
 - data/java/build.xml +0 -16
 - data/java/src/gherkin/FixJava.java +0 -37
 - data/java/src/gherkin/I18nLexer.java +0 -48
 - data/java/src/gherkin/Lexer.java +0 -5
 - data/java/src/gherkin/LexingError.java +0 -7
 - data/java/src/gherkin/Listener.java +0 -29
 - data/java/src/gherkin/Main.java +0 -17
 - data/java/src/gherkin/ParseError.java +0 -22
 - data/java/src/gherkin/Parser.java +0 -191
 - data/java/src/gherkin/formatter/Argument.java +0 -39
 - data/java/src/gherkin/formatter/ArgumentFormat.java +0 -17
 - data/java/src/gherkin/formatter/Colors.java +0 -7
 - data/java/src/gherkin/formatter/Formatter.java +0 -15
 - data/java/src/gherkin/formatter/PrettyFormatter.java +0 -219
 - data/java/src/gherkin/parser/StateMachineReader.java +0 -67
 - data/java/test/gherkin/formatter/ArgumentTest.java +0 -17
 - data/lib/gherkin/lexer.rb +0 -35
 - data/lib/gherkin/parser.rb +0 -19
 - data/lib/gherkin/rb_parser.rb +0 -125
 - data/spec/gherkin/parser_spec.rb +0 -33
 
| 
         @@ -0,0 +1,191 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'gherkin/parser/sexp'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'gherkin/parser/tag_expression'
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            module Gherkin
         
     | 
| 
      
 5 
     | 
    
         
            +
              module Parser
         
     | 
| 
      
 6 
     | 
    
         
            +
                # This class filters events based on filter criteria.
         
     | 
| 
      
 7 
     | 
    
         
            +
                class FilterListener
         
     | 
| 
      
 8 
     | 
    
         
            +
                  # Creates a new instance that replays events to +listener+, filtered by +filters+,
         
     | 
| 
      
 9 
     | 
    
         
            +
                  # a Hash that can contain:
         
     | 
| 
      
 10 
     | 
    
         
            +
                  #
         
     | 
| 
      
 11 
     | 
    
         
            +
                  # * <tt>:lines</tt> An Array of line numbers to filter on.
         
     | 
| 
      
 12 
     | 
    
         
            +
                  # * <tt>:name_regexen</tt> An Array of name regexen to filter on. Matches against :feature, :scenario, :scenario_outline and :examples
         
     | 
| 
      
 13 
     | 
    
         
            +
                  # * <tt>:tag_expression</tt> A TagExpression to filter on.
         
     | 
| 
      
 14 
     | 
    
         
            +
                  #
         
     | 
| 
      
 15 
     | 
    
         
            +
                  def initialize(listener, filters)
         
     | 
| 
      
 16 
     | 
    
         
            +
                    @listener = listener
         
     | 
| 
      
 17 
     | 
    
         
            +
                    @filter_method = detect_filter(filters)
         
     | 
| 
      
 18 
     | 
    
         
            +
                    
         
     | 
| 
      
 19 
     | 
    
         
            +
                    @meta_buffer = []
         
     | 
| 
      
 20 
     | 
    
         
            +
                    @feature_buffer = []
         
     | 
| 
      
 21 
     | 
    
         
            +
                    @scenario_buffer = []
         
     | 
| 
      
 22 
     | 
    
         
            +
                    @examples_buffer = []
         
     | 
| 
      
 23 
     | 
    
         
            +
                    @examples_rows_buffer = []
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                    @feature_tags = []
         
     | 
| 
      
 26 
     | 
    
         
            +
                    @scenario_tags = []
         
     | 
| 
      
 27 
     | 
    
         
            +
                    @example_tags = []
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                    @table_state = :step
         
     | 
| 
      
 30 
     | 
    
         
            +
                  end
         
     | 
| 
      
 31 
     | 
    
         
            +
                  
         
     | 
| 
      
 32 
     | 
    
         
            +
                  private
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                  def method_missing(*sexp_args)
         
     | 
| 
      
 35 
     | 
    
         
            +
                    sexp = Sexp.new(sexp_args)
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                    return sexp.replay(@listener) if no_filters?
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                    case(sexp.event)
         
     | 
| 
      
 40 
     | 
    
         
            +
                    when :tag
         
     | 
| 
      
 41 
     | 
    
         
            +
                      @meta_buffer << sexp
         
     | 
| 
      
 42 
     | 
    
         
            +
                    when :comment
         
     | 
| 
      
 43 
     | 
    
         
            +
                      @meta_buffer << sexp
         
     | 
| 
      
 44 
     | 
    
         
            +
                    when :feature
         
     | 
| 
      
 45 
     | 
    
         
            +
                      @feature_buffer = @meta_buffer
         
     | 
| 
      
 46 
     | 
    
         
            +
                      @feature_buffer << sexp
         
     | 
| 
      
 47 
     | 
    
         
            +
                      @feature_tags = extract_tags
         
     | 
| 
      
 48 
     | 
    
         
            +
                      @meta_buffer = []
         
     | 
| 
      
 49 
     | 
    
         
            +
                      @feature_ok = true if filter_match?(sexp)
         
     | 
| 
      
 50 
     | 
    
         
            +
                    when :background
         
     | 
| 
      
 51 
     | 
    
         
            +
                      @feature_buffer += @meta_buffer
         
     | 
| 
      
 52 
     | 
    
         
            +
                      @feature_buffer << sexp
         
     | 
| 
      
 53 
     | 
    
         
            +
                      @meta_buffer = []
         
     | 
| 
      
 54 
     | 
    
         
            +
                      @table_state = :background
         
     | 
| 
      
 55 
     | 
    
         
            +
                      @feature_ok = true if filter_match?(sexp)
         
     | 
| 
      
 56 
     | 
    
         
            +
                    when :scenario
         
     | 
| 
      
 57 
     | 
    
         
            +
                      replay_examples_rows_buffer
         
     | 
| 
      
 58 
     | 
    
         
            +
                      @scenario_buffer = @meta_buffer
         
     | 
| 
      
 59 
     | 
    
         
            +
                      @scenario_buffer << sexp
         
     | 
| 
      
 60 
     | 
    
         
            +
                      @scenario_tags = extract_tags
         
     | 
| 
      
 61 
     | 
    
         
            +
                      @example_tags = []
         
     | 
| 
      
 62 
     | 
    
         
            +
                      @meta_buffer = []
         
     | 
| 
      
 63 
     | 
    
         
            +
                      @scenario_ok = filter_match?(*@scenario_buffer) || tag_match?
         
     | 
| 
      
 64 
     | 
    
         
            +
                      @examples_ok = false
         
     | 
| 
      
 65 
     | 
    
         
            +
                      @table_state = :step
         
     | 
| 
      
 66 
     | 
    
         
            +
                    when :scenario_outline
         
     | 
| 
      
 67 
     | 
    
         
            +
                      replay_examples_rows_buffer
         
     | 
| 
      
 68 
     | 
    
         
            +
                      @scenario_buffer = @meta_buffer
         
     | 
| 
      
 69 
     | 
    
         
            +
                      @scenario_buffer << sexp
         
     | 
| 
      
 70 
     | 
    
         
            +
                      @scenario_tags = extract_tags
         
     | 
| 
      
 71 
     | 
    
         
            +
                      @example_tags = []
         
     | 
| 
      
 72 
     | 
    
         
            +
                      @meta_buffer = []
         
     | 
| 
      
 73 
     | 
    
         
            +
                      @scenario_ok = filter_match?(*@scenario_buffer)
         
     | 
| 
      
 74 
     | 
    
         
            +
                      @examples_ok = false
         
     | 
| 
      
 75 
     | 
    
         
            +
                      @table_state = :step
         
     | 
| 
      
 76 
     | 
    
         
            +
                    when :examples
         
     | 
| 
      
 77 
     | 
    
         
            +
                      replay_examples_rows_buffer
         
     | 
| 
      
 78 
     | 
    
         
            +
                      @examples_buffer = @meta_buffer
         
     | 
| 
      
 79 
     | 
    
         
            +
                      @examples_buffer << sexp
         
     | 
| 
      
 80 
     | 
    
         
            +
                      @example_tags = extract_tags
         
     | 
| 
      
 81 
     | 
    
         
            +
                      @meta_buffer = []
         
     | 
| 
      
 82 
     | 
    
         
            +
                      @examples_rows_buffer = []
         
     | 
| 
      
 83 
     | 
    
         
            +
                      @examples_ok = filter_match?(*@examples_buffer) || tag_match?
         
     | 
| 
      
 84 
     | 
    
         
            +
                      @table_state = :examples
         
     | 
| 
      
 85 
     | 
    
         
            +
                    when :step
         
     | 
| 
      
 86 
     | 
    
         
            +
                      case(@table_state)
         
     | 
| 
      
 87 
     | 
    
         
            +
                      when :background
         
     | 
| 
      
 88 
     | 
    
         
            +
                        @feature_buffer += @meta_buffer
         
     | 
| 
      
 89 
     | 
    
         
            +
                        @feature_buffer << sexp
         
     | 
| 
      
 90 
     | 
    
         
            +
                        @meta_buffer = []
         
     | 
| 
      
 91 
     | 
    
         
            +
                        @feature_ok = true if filter_match?(sexp)
         
     | 
| 
      
 92 
     | 
    
         
            +
                      else
         
     | 
| 
      
 93 
     | 
    
         
            +
                        @scenario_buffer << sexp
         
     | 
| 
      
 94 
     | 
    
         
            +
                        @scenario_ok ||= filter_match?(*@scenario_buffer)
         
     | 
| 
      
 95 
     | 
    
         
            +
                        @table_state = :step
         
     | 
| 
      
 96 
     | 
    
         
            +
                      end
         
     | 
| 
      
 97 
     | 
    
         
            +
                    when :row
         
     | 
| 
      
 98 
     | 
    
         
            +
                      case(@table_state)
         
     | 
| 
      
 99 
     | 
    
         
            +
                      when :examples
         
     | 
| 
      
 100 
     | 
    
         
            +
                        unless header_row_already_buffered?
         
     | 
| 
      
 101 
     | 
    
         
            +
                          @examples_buffer << sexp
         
     | 
| 
      
 102 
     | 
    
         
            +
                          @examples_ok = true if filter_match?(*@examples_buffer)
         
     | 
| 
      
 103 
     | 
    
         
            +
                        else
         
     | 
| 
      
 104 
     | 
    
         
            +
                          @examples_rows_buffer << sexp if @scenario_ok || @examples_ok || @feature_ok || filter_match?(sexp)
         
     | 
| 
      
 105 
     | 
    
         
            +
                        end
         
     | 
| 
      
 106 
     | 
    
         
            +
                      when :step
         
     | 
| 
      
 107 
     | 
    
         
            +
                        @scenario_buffer << sexp
         
     | 
| 
      
 108 
     | 
    
         
            +
                        @scenario_ok ||= filter_match?(*@scenario_buffer)
         
     | 
| 
      
 109 
     | 
    
         
            +
                      when :background
         
     | 
| 
      
 110 
     | 
    
         
            +
                        @feature_buffer += @meta_buffer
         
     | 
| 
      
 111 
     | 
    
         
            +
                        @feature_buffer << sexp
         
     | 
| 
      
 112 
     | 
    
         
            +
                        @meta_buffer = []
         
     | 
| 
      
 113 
     | 
    
         
            +
                      else
         
     | 
| 
      
 114 
     | 
    
         
            +
                        raise "Bad table_state:#{@table_state.inspect}"
         
     | 
| 
      
 115 
     | 
    
         
            +
                      end
         
     | 
| 
      
 116 
     | 
    
         
            +
                    when :py_string
         
     | 
| 
      
 117 
     | 
    
         
            +
                      @scenario_buffer << sexp
         
     | 
| 
      
 118 
     | 
    
         
            +
                      @scenario_ok ||= filter_match?(*@scenario_buffer)
         
     | 
| 
      
 119 
     | 
    
         
            +
                    when :eof
         
     | 
| 
      
 120 
     | 
    
         
            +
                      replay_examples_rows_buffer
         
     | 
| 
      
 121 
     | 
    
         
            +
                      sexp.replay(@listener)
         
     | 
| 
      
 122 
     | 
    
         
            +
                      return
         
     | 
| 
      
 123 
     | 
    
         
            +
                    else
         
     | 
| 
      
 124 
     | 
    
         
            +
                      super
         
     | 
| 
      
 125 
     | 
    
         
            +
                    end
         
     | 
| 
      
 126 
     | 
    
         
            +
             
     | 
| 
      
 127 
     | 
    
         
            +
                    if @scenario_ok || @examples_ok || @feature_ok
         
     | 
| 
      
 128 
     | 
    
         
            +
                      replay_buffers
         
     | 
| 
      
 129 
     | 
    
         
            +
                    end
         
     | 
| 
      
 130 
     | 
    
         
            +
                  end
         
     | 
| 
      
 131 
     | 
    
         
            +
             
     | 
| 
      
 132 
     | 
    
         
            +
                  def detect_filter(filters)
         
     | 
| 
      
 133 
     | 
    
         
            +
                    @filters = filters
         
     | 
| 
      
 134 
     | 
    
         
            +
                    raise "Bad filter: #{filters.inspect}" if filters.map{|filter| filter.class}.uniq.length > 1
         
     | 
| 
      
 135 
     | 
    
         
            +
                    @filter_method = case(filters[0])
         
     | 
| 
      
 136 
     | 
    
         
            +
                    when Fixnum 
         
     | 
| 
      
 137 
     | 
    
         
            +
                      :line_match?
         
     | 
| 
      
 138 
     | 
    
         
            +
                    when Regexp 
         
     | 
| 
      
 139 
     | 
    
         
            +
                      :name_match?
         
     | 
| 
      
 140 
     | 
    
         
            +
                    when String 
         
     | 
| 
      
 141 
     | 
    
         
            +
                      TagExpression.new(*filters)
         
     | 
| 
      
 142 
     | 
    
         
            +
                    end
         
     | 
| 
      
 143 
     | 
    
         
            +
                  end
         
     | 
| 
      
 144 
     | 
    
         
            +
             
     | 
| 
      
 145 
     | 
    
         
            +
                  def no_filters?
         
     | 
| 
      
 146 
     | 
    
         
            +
                    @filters.empty?
         
     | 
| 
      
 147 
     | 
    
         
            +
                  end
         
     | 
| 
      
 148 
     | 
    
         
            +
             
     | 
| 
      
 149 
     | 
    
         
            +
                  def header_row_already_buffered?
         
     | 
| 
      
 150 
     | 
    
         
            +
                    return false unless @examples_buffer.any?
         
     | 
| 
      
 151 
     | 
    
         
            +
                    @examples_buffer[-1].event == :row
         
     | 
| 
      
 152 
     | 
    
         
            +
                  end
         
     | 
| 
      
 153 
     | 
    
         
            +
                  
         
     | 
| 
      
 154 
     | 
    
         
            +
                  def filter_match?(*sexps)
         
     | 
| 
      
 155 
     | 
    
         
            +
                    return false unless[:name_match?, :line_match?].include?(@filter_method)
         
     | 
| 
      
 156 
     | 
    
         
            +
                    sexps.detect{|sexp| sexp.__send__(@filter_method, @filters)}
         
     | 
| 
      
 157 
     | 
    
         
            +
                  end
         
     | 
| 
      
 158 
     | 
    
         
            +
             
     | 
| 
      
 159 
     | 
    
         
            +
                  def tag_match?
         
     | 
| 
      
 160 
     | 
    
         
            +
                    return false unless TagExpression === @filter_method
         
     | 
| 
      
 161 
     | 
    
         
            +
                    @filter_method.eval(*current_tags)
         
     | 
| 
      
 162 
     | 
    
         
            +
                  end
         
     | 
| 
      
 163 
     | 
    
         
            +
             
     | 
| 
      
 164 
     | 
    
         
            +
                  def replay_buffers
         
     | 
| 
      
 165 
     | 
    
         
            +
                    (@feature_buffer + @scenario_buffer).each do |sexp| 
         
     | 
| 
      
 166 
     | 
    
         
            +
                      sexp.replay(@listener)
         
     | 
| 
      
 167 
     | 
    
         
            +
                    end
         
     | 
| 
      
 168 
     | 
    
         
            +
                    @feature_buffer = []
         
     | 
| 
      
 169 
     | 
    
         
            +
                    @scenario_buffer = [] 
         
     | 
| 
      
 170 
     | 
    
         
            +
                  end
         
     | 
| 
      
 171 
     | 
    
         
            +
             
     | 
| 
      
 172 
     | 
    
         
            +
                  def replay_examples_rows_buffer
         
     | 
| 
      
 173 
     | 
    
         
            +
                    if @examples_rows_buffer.any?
         
     | 
| 
      
 174 
     | 
    
         
            +
                      replay_buffers
         
     | 
| 
      
 175 
     | 
    
         
            +
                      (@examples_buffer + @examples_rows_buffer).each do |sexp|
         
     | 
| 
      
 176 
     | 
    
         
            +
                        sexp.replay(@listener)
         
     | 
| 
      
 177 
     | 
    
         
            +
                      end
         
     | 
| 
      
 178 
     | 
    
         
            +
                      @examples_rows_buffer = []
         
     | 
| 
      
 179 
     | 
    
         
            +
                    end
         
     | 
| 
      
 180 
     | 
    
         
            +
                  end
         
     | 
| 
      
 181 
     | 
    
         
            +
                  
         
     | 
| 
      
 182 
     | 
    
         
            +
                  def current_tags
         
     | 
| 
      
 183 
     | 
    
         
            +
                    @feature_tags + @scenario_tags + @example_tags
         
     | 
| 
      
 184 
     | 
    
         
            +
                  end
         
     | 
| 
      
 185 
     | 
    
         
            +
             
     | 
| 
      
 186 
     | 
    
         
            +
                  def extract_tags
         
     | 
| 
      
 187 
     | 
    
         
            +
                    @meta_buffer.select { |sexp| sexp.event == :tag }.map { |sexp| sexp.keyword }
         
     | 
| 
      
 188 
     | 
    
         
            +
                  end
         
     | 
| 
      
 189 
     | 
    
         
            +
                end
         
     | 
| 
      
 190 
     | 
    
         
            +
              end
         
     | 
| 
      
 191 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,142 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Gherkin
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Parser
         
     | 
| 
      
 3 
     | 
    
         
            +
                class ParseError < StandardError
         
     | 
| 
      
 4 
     | 
    
         
            +
                  def initialize(state, new_state, expected_states, line)
         
     | 
| 
      
 5 
     | 
    
         
            +
                    super("Parse error on line #{line}. Found #{new_state} when expecting one of: #{expected_states.join(', ')}. (Current state: #{state}).")
         
     | 
| 
      
 6 
     | 
    
         
            +
                  end
         
     | 
| 
      
 7 
     | 
    
         
            +
                end
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                class Parser
         
     | 
| 
      
 10 
     | 
    
         
            +
                  def self.new(listener, raise_on_error=false, machine_name='root')
         
     | 
| 
      
 11 
     | 
    
         
            +
                    if defined?(JRUBY_VERSION)
         
     | 
| 
      
 12 
     | 
    
         
            +
                      require 'gherkin.jar'
         
     | 
| 
      
 13 
     | 
    
         
            +
                      Java::GherkinParser::Parser.new(listener, raise_on_error, machine_name)
         
     | 
| 
      
 14 
     | 
    
         
            +
                    else
         
     | 
| 
      
 15 
     | 
    
         
            +
                      super
         
     | 
| 
      
 16 
     | 
    
         
            +
                    end
         
     | 
| 
      
 17 
     | 
    
         
            +
                  end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                  # Initialize the parser. +machine_name+ refers to a state machine table.
         
     | 
| 
      
 20 
     | 
    
         
            +
                  def initialize(listener, raise_on_error, machine_name)
         
     | 
| 
      
 21 
     | 
    
         
            +
                    @listener = listener
         
     | 
| 
      
 22 
     | 
    
         
            +
                    @raise_on_error = raise_on_error
         
     | 
| 
      
 23 
     | 
    
         
            +
                    @machines = []
         
     | 
| 
      
 24 
     | 
    
         
            +
                    push_machine(machine_name)
         
     | 
| 
      
 25 
     | 
    
         
            +
                  end
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                  # Doesn't yet fall back to super
         
     | 
| 
      
 28 
     | 
    
         
            +
                  def method_missing(method, *args)
         
     | 
| 
      
 29 
     | 
    
         
            +
                    # TODO: Catch exception and call super
         
     | 
| 
      
 30 
     | 
    
         
            +
                    if(event(method.to_s, args[-1]))
         
     | 
| 
      
 31 
     | 
    
         
            +
                      @listener.send(method, *args)
         
     | 
| 
      
 32 
     | 
    
         
            +
                    end
         
     | 
| 
      
 33 
     | 
    
         
            +
                  end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                  def event(ev, line)
         
     | 
| 
      
 36 
     | 
    
         
            +
                    machine.event(ev, line) do |state, expected|
         
     | 
| 
      
 37 
     | 
    
         
            +
                      if @raise_on_error
         
     | 
| 
      
 38 
     | 
    
         
            +
                        raise ParseError.new(state, ev, expected, line)
         
     | 
| 
      
 39 
     | 
    
         
            +
                      else
         
     | 
| 
      
 40 
     | 
    
         
            +
                        @listener.syntax_error(state, ev, expected, line)
         
     | 
| 
      
 41 
     | 
    
         
            +
                        return false
         
     | 
| 
      
 42 
     | 
    
         
            +
                      end
         
     | 
| 
      
 43 
     | 
    
         
            +
                    end
         
     | 
| 
      
 44 
     | 
    
         
            +
                    true
         
     | 
| 
      
 45 
     | 
    
         
            +
                  end
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                  def push_machine(name)
         
     | 
| 
      
 48 
     | 
    
         
            +
                    @machines.push(Machine.new(self, name))
         
     | 
| 
      
 49 
     | 
    
         
            +
                  end
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
                  def pop_machine
         
     | 
| 
      
 52 
     | 
    
         
            +
                    @machines.pop
         
     | 
| 
      
 53 
     | 
    
         
            +
                  end
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
                  def machine
         
     | 
| 
      
 56 
     | 
    
         
            +
                    @machines[-1]
         
     | 
| 
      
 57 
     | 
    
         
            +
                  end
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
                  def expected
         
     | 
| 
      
 60 
     | 
    
         
            +
                    machine.expected
         
     | 
| 
      
 61 
     | 
    
         
            +
                  end
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
      
 63 
     | 
    
         
            +
                  def force_state(state)
         
     | 
| 
      
 64 
     | 
    
         
            +
                    machine.instance_variable_set('@state', state)
         
     | 
| 
      
 65 
     | 
    
         
            +
                  end
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
      
 67 
     | 
    
         
            +
                  class Machine
         
     | 
| 
      
 68 
     | 
    
         
            +
                    def initialize(parser, name)
         
     | 
| 
      
 69 
     | 
    
         
            +
                      @parser = parser
         
     | 
| 
      
 70 
     | 
    
         
            +
                      @name = name
         
     | 
| 
      
 71 
     | 
    
         
            +
                      @transition_map = transition_map(name)
         
     | 
| 
      
 72 
     | 
    
         
            +
                      @state = name
         
     | 
| 
      
 73 
     | 
    
         
            +
                    end
         
     | 
| 
      
 74 
     | 
    
         
            +
             
     | 
| 
      
 75 
     | 
    
         
            +
                    def event(ev, line)
         
     | 
| 
      
 76 
     | 
    
         
            +
                      states = @transition_map[@state]
         
     | 
| 
      
 77 
     | 
    
         
            +
                      raise "Unknown state: #{@state.inspect} for machine #{@name}" if states.nil?
         
     | 
| 
      
 78 
     | 
    
         
            +
                      new_state = states[ev]
         
     | 
| 
      
 79 
     | 
    
         
            +
                      case new_state
         
     | 
| 
      
 80 
     | 
    
         
            +
                      when "E"
         
     | 
| 
      
 81 
     | 
    
         
            +
                        yield @state, expected
         
     | 
| 
      
 82 
     | 
    
         
            +
                      when /push\((.+)\)/
         
     | 
| 
      
 83 
     | 
    
         
            +
                        @parser.push_machine($1)
         
     | 
| 
      
 84 
     | 
    
         
            +
                        @parser.event(ev, line)
         
     | 
| 
      
 85 
     | 
    
         
            +
                      when "pop()"
         
     | 
| 
      
 86 
     | 
    
         
            +
                        @parser.pop_machine()
         
     | 
| 
      
 87 
     | 
    
         
            +
                        @parser.event(ev, line)
         
     | 
| 
      
 88 
     | 
    
         
            +
                      else
         
     | 
| 
      
 89 
     | 
    
         
            +
                        raise "Unknown transition: #{ev.inspect} among #{states.inspect} for machine #{@name}" if new_state.nil?
         
     | 
| 
      
 90 
     | 
    
         
            +
                        @state = new_state
         
     | 
| 
      
 91 
     | 
    
         
            +
                      end
         
     | 
| 
      
 92 
     | 
    
         
            +
                    end
         
     | 
| 
      
 93 
     | 
    
         
            +
             
     | 
| 
      
 94 
     | 
    
         
            +
                    def expected
         
     | 
| 
      
 95 
     | 
    
         
            +
                      allowed = @transition_map[@state].find_all { |_, action| action != "E" }
         
     | 
| 
      
 96 
     | 
    
         
            +
                      allowed.collect { |state| state[0] }.sort - ['eof']
         
     | 
| 
      
 97 
     | 
    
         
            +
                    end
         
     | 
| 
      
 98 
     | 
    
         
            +
             
     | 
| 
      
 99 
     | 
    
         
            +
                    private
         
     | 
| 
      
 100 
     | 
    
         
            +
             
     | 
| 
      
 101 
     | 
    
         
            +
                    @@transition_maps = {}
         
     | 
| 
      
 102 
     | 
    
         
            +
             
     | 
| 
      
 103 
     | 
    
         
            +
                    def transition_map(name)
         
     | 
| 
      
 104 
     | 
    
         
            +
                      @@transition_maps[name] ||= build_transition_map(name)
         
     | 
| 
      
 105 
     | 
    
         
            +
                    end
         
     | 
| 
      
 106 
     | 
    
         
            +
             
     | 
| 
      
 107 
     | 
    
         
            +
                    def build_transition_map(name)
         
     | 
| 
      
 108 
     | 
    
         
            +
                      table = transition_table(name)
         
     | 
| 
      
 109 
     | 
    
         
            +
                      events = table.shift[1..-1]
         
     | 
| 
      
 110 
     | 
    
         
            +
                      table.inject({}) do |machine, actions|
         
     | 
| 
      
 111 
     | 
    
         
            +
                        state = actions.shift
         
     | 
| 
      
 112 
     | 
    
         
            +
                        machine[state] = Hash[*events.zip(actions).flatten]
         
     | 
| 
      
 113 
     | 
    
         
            +
                        machine
         
     | 
| 
      
 114 
     | 
    
         
            +
                      end
         
     | 
| 
      
 115 
     | 
    
         
            +
                    end
         
     | 
| 
      
 116 
     | 
    
         
            +
             
     | 
| 
      
 117 
     | 
    
         
            +
                    def transition_table(name)
         
     | 
| 
      
 118 
     | 
    
         
            +
                      state_machine_reader = StateMachineReader.new
         
     | 
| 
      
 119 
     | 
    
         
            +
                      lexer = Gherkin::I18n.new('en').lexer(state_machine_reader, false)
         
     | 
| 
      
 120 
     | 
    
         
            +
                      lexer.scan(File.read(File.dirname(__FILE__) + "/#{name}.txt"))
         
     | 
| 
      
 121 
     | 
    
         
            +
                      state_machine_reader.rows
         
     | 
| 
      
 122 
     | 
    
         
            +
                    end
         
     | 
| 
      
 123 
     | 
    
         
            +
             
     | 
| 
      
 124 
     | 
    
         
            +
                    class StateMachineReader
         
     | 
| 
      
 125 
     | 
    
         
            +
                      attr_reader :rows
         
     | 
| 
      
 126 
     | 
    
         
            +
             
     | 
| 
      
 127 
     | 
    
         
            +
                      def initialize
         
     | 
| 
      
 128 
     | 
    
         
            +
                        @rows = []
         
     | 
| 
      
 129 
     | 
    
         
            +
                      end
         
     | 
| 
      
 130 
     | 
    
         
            +
             
     | 
| 
      
 131 
     | 
    
         
            +
                      def row(row, line_number)
         
     | 
| 
      
 132 
     | 
    
         
            +
                        @rows << row
         
     | 
| 
      
 133 
     | 
    
         
            +
                      end
         
     | 
| 
      
 134 
     | 
    
         
            +
             
     | 
| 
      
 135 
     | 
    
         
            +
                      def eof
         
     | 
| 
      
 136 
     | 
    
         
            +
                      end
         
     | 
| 
      
 137 
     | 
    
         
            +
                    end
         
     | 
| 
      
 138 
     | 
    
         
            +
             
     | 
| 
      
 139 
     | 
    
         
            +
                  end
         
     | 
| 
      
 140 
     | 
    
         
            +
                end
         
     | 
| 
      
 141 
     | 
    
         
            +
              end
         
     | 
| 
      
 142 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,45 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Gherkin
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Parser
         
     | 
| 
      
 3 
     | 
    
         
            +
                class Sexp < Array
         
     | 
| 
      
 4 
     | 
    
         
            +
                  def initialize(*args)
         
     | 
| 
      
 5 
     | 
    
         
            +
                    super
         
     | 
| 
      
 6 
     | 
    
         
            +
                    self[1] = self[1].to_a if event == :row # Special JRuby handling
         
     | 
| 
      
 7 
     | 
    
         
            +
                  end
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                  def event
         
     | 
| 
      
 10 
     | 
    
         
            +
                    self[0]
         
     | 
| 
      
 11 
     | 
    
         
            +
                  end
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                  def keyword
         
     | 
| 
      
 14 
     | 
    
         
            +
                    self[1]
         
     | 
| 
      
 15 
     | 
    
         
            +
                  end
         
     | 
| 
      
 16 
     | 
    
         
            +
                  
         
     | 
| 
      
 17 
     | 
    
         
            +
                  def line_match?(lines)
         
     | 
| 
      
 18 
     | 
    
         
            +
                    lines.include?(line)
         
     | 
| 
      
 19 
     | 
    
         
            +
                  end
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                  def name_match?(name_regexen)
         
     | 
| 
      
 22 
     | 
    
         
            +
                    return false unless [:feature, :scenario, :scenario_outline, :examples].include?(event)
         
     | 
| 
      
 23 
     | 
    
         
            +
                    name_regexen.detect{|name_regex| name =~ name_regex}
         
     | 
| 
      
 24 
     | 
    
         
            +
                  end
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                  def replay(listener)
         
     | 
| 
      
 27 
     | 
    
         
            +
                    listener.__send__(event, *args)
         
     | 
| 
      
 28 
     | 
    
         
            +
                  end
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                private
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                  def name
         
     | 
| 
      
 33 
     | 
    
         
            +
                    self[2]
         
     | 
| 
      
 34 
     | 
    
         
            +
                  end
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
                  def line
         
     | 
| 
      
 37 
     | 
    
         
            +
                    self[-1]
         
     | 
| 
      
 38 
     | 
    
         
            +
                  end
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
                  def args
         
     | 
| 
      
 41 
     | 
    
         
            +
                    self[1..-1]
         
     | 
| 
      
 42 
     | 
    
         
            +
                  end
         
     | 
| 
      
 43 
     | 
    
         
            +
                end
         
     | 
| 
      
 44 
     | 
    
         
            +
              end
         
     | 
| 
      
 45 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,46 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Gherkin
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Parser
         
     | 
| 
      
 3 
     | 
    
         
            +
                class TagExpression
         
     | 
| 
      
 4 
     | 
    
         
            +
                  attr_reader :limits
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
                  def initialize(*tag_expressions)
         
     | 
| 
      
 7 
     | 
    
         
            +
                    @ands = []
         
     | 
| 
      
 8 
     | 
    
         
            +
                    @limits = {}
         
     | 
| 
      
 9 
     | 
    
         
            +
                    tag_expressions.each do |expr|
         
     | 
| 
      
 10 
     | 
    
         
            +
                      add(expr.strip.split(/\s*,\s*/))
         
     | 
| 
      
 11 
     | 
    
         
            +
                    end
         
     | 
| 
      
 12 
     | 
    
         
            +
                  end
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                  def empty?
         
     | 
| 
      
 15 
     | 
    
         
            +
                    @ands.empty?
         
     | 
| 
      
 16 
     | 
    
         
            +
                  end
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                  def eval(*tags)
         
     | 
| 
      
 19 
     | 
    
         
            +
                    return true if @ands.flatten.empty?
         
     | 
| 
      
 20 
     | 
    
         
            +
                    vars = Hash[*tags.map{|tag| [tag, true]}.flatten]
         
     | 
| 
      
 21 
     | 
    
         
            +
                    !!Kernel.eval(ruby_expression)
         
     | 
| 
      
 22 
     | 
    
         
            +
                  end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                private
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                  def add(tags)
         
     | 
| 
      
 27 
     | 
    
         
            +
                    negatives, positives = tags.partition{|tag| tag =~ /^~/}
         
     | 
| 
      
 28 
     | 
    
         
            +
                    positive_limits = Hash[*positives.map{|positive| tag, limit = positive.split(':'); [tag, limit ? limit.to_i : nil]}.flatten]
         
     | 
| 
      
 29 
     | 
    
         
            +
                    @limits.merge!(positive_limits)
         
     | 
| 
      
 30 
     | 
    
         
            +
                    @ands << (negatives + positive_limits.keys)
         
     | 
| 
      
 31 
     | 
    
         
            +
                  end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                  def ruby_expression
         
     | 
| 
      
 34 
     | 
    
         
            +
                    "(" + @ands.map do |ors|
         
     | 
| 
      
 35 
     | 
    
         
            +
                      ors.map do |tag|
         
     | 
| 
      
 36 
     | 
    
         
            +
                        if tag =~ /^~(.*)/
         
     | 
| 
      
 37 
     | 
    
         
            +
                          "!vars['#{$1}']"
         
     | 
| 
      
 38 
     | 
    
         
            +
                        else
         
     | 
| 
      
 39 
     | 
    
         
            +
                          "vars['#{tag}']"
         
     | 
| 
      
 40 
     | 
    
         
            +
                        end
         
     | 
| 
      
 41 
     | 
    
         
            +
                      end.join("||")
         
     | 
| 
      
 42 
     | 
    
         
            +
                    end.join(")&&(") + ")"
         
     | 
| 
      
 43 
     | 
    
         
            +
                  end
         
     | 
| 
      
 44 
     | 
    
         
            +
                end
         
     | 
| 
      
 45 
     | 
    
         
            +
              end
         
     | 
| 
      
 46 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/gherkin/rb_lexer.rb
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            module Gherkin
         
     | 
| 
       2 
2 
     | 
    
         
             
              module RbLexer
         
     | 
| 
       3 
     | 
    
         
            -
                def self.[]( 
     | 
| 
       4 
     | 
    
         
            -
                  name =  
     | 
| 
      
 3 
     | 
    
         
            +
                def self.[](i18n_language_name)
         
     | 
| 
      
 4 
     | 
    
         
            +
                  name = i18n_language_name.gsub(/[\s-]/, '')
         
     | 
| 
       5 
5 
     | 
    
         
             
                  require "gherkin/rb_lexer/#{name}"
         
     | 
| 
       6 
6 
     | 
    
         
             
                  i18n_lexer_class_name = name.capitalize
         
     | 
| 
       7 
7 
     | 
    
         
             
                  const_get(i18n_lexer_class_name)
         
     | 
    
        data/ragel/lexer_common.rl.erb
    CHANGED
    
    | 
         @@ -27,7 +27,7 @@ 
     | 
|
| 
       27 
27 
     | 
    
         
             
              Step = space* I18N_Step %begin_content ^EOL+ %store_step_content :> EOL+;
         
     | 
| 
       28 
28 
     | 
    
         
             
              Comment = space* '#' >begin_content ^EOL* %store_comment_content :> EOL+;
         
     | 
| 
       29 
29 
     | 
    
         | 
| 
       30 
     | 
    
         
            -
              Tag = ( '@' [^@\r\n\t ]+ >begin_content ) %store_tag_content;
         
     | 
| 
      
 30 
     | 
    
         
            +
              Tag = ( ('@' [^@\r\n\t ]+) >begin_content ) %store_tag_content;
         
     | 
| 
       31 
31 
     | 
    
         
             
              Tags = space* (Tag space*)+ EOL+;
         
     | 
| 
       32 
32 
     | 
    
         | 
| 
       33 
33 
     | 
    
         
             
              StartRow = space* '|' >start_row;
         
     | 
| 
         @@ -1,9 +1,9 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # encoding: utf-8
         
     | 
| 
       2 
2 
     | 
    
         
             
            require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
         
     | 
| 
       3 
     | 
    
         
            -
            require 'gherkin/ 
     | 
| 
      
 3 
     | 
    
         
            +
            require 'gherkin/formatter/argument'
         
     | 
| 
       4 
4 
     | 
    
         | 
| 
       5 
5 
     | 
    
         
             
            module Gherkin
         
     | 
| 
       6 
     | 
    
         
            -
              module  
     | 
| 
      
 6 
     | 
    
         
            +
              module Formatter
         
     | 
| 
       7 
7 
     | 
    
         
             
                class BracketFormat
         
     | 
| 
       8 
8 
     | 
    
         
             
                  class << self
         
     | 
| 
       9 
9 
     | 
    
         
             
                    def new
         
     |