compser 0.1.0 → 0.2.0
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.
- checksums.yaml +4 -4
- data/Gemfile.lock +2 -2
- data/README.md +35 -7
- data/examples/calculator.rb +76 -0
- data/examples/json-benchmark.rb +9 -3
- data/examples/json.rb +9 -2
- data/lib/compser/result.rb +2 -2
- data/lib/compser/state.rb +3 -3
- data/lib/compser/step/chomp_while.rb +3 -3
- data/lib/compser/step/drop.rb +0 -2
- data/lib/compser/step/lazy.rb +7 -0
- data/lib/compser/step/one_of.rb +2 -2
- data/lib/compser/step/sequence.rb +2 -5
- data/lib/compser/step.rb +10 -9
- data/lib/compser/version.rb +1 -1
- data/lib/compser.rb +1 -0
- metadata +5 -3
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 2772b2accc3f032d8ca438c0510c439d17bcd036339d33fbbb4c9aea8ac1292c
         | 
| 4 | 
            +
              data.tar.gz: cc6ee194f1f60bf428057eda00d43d7119d264939bea9acd54925b746d4d339f
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 360a5566bf3d8fd5621662ec57d2a744e68a001ca72b66890a9b8095ab06e4ed7a26eae7bd965fff3f47c5eb35f8ad6c297db591de513fc7fdbf56ee0040d79d
         | 
| 7 | 
            +
              data.tar.gz: 65eef3b42ac80f16fadfe202e9d46e3fc84c48ef95c0f2cb76c42a37e69995f62bf21976fd6fee59c7b55fd80ac837fc7e457a8447e99eabfd7fb15dcf3b9a7d
         | 
    
        data/Gemfile.lock
    CHANGED
    
    
    
        data/README.md
    CHANGED
    
    | @@ -14,6 +14,7 @@ and available building blocks you can use to compose more complex and sophistica | |
| 14 14 | 
             
              * [`map`](#map)
         | 
| 15 15 | 
             
              * [`one_of`](#one_of)
         | 
| 16 16 | 
             
              * [`sequence`](#sequence)
         | 
| 17 | 
            +
              * [`lazy`](#lazy)
         | 
| 17 18 | 
             
              * [`spaces`](#spaces)
         | 
| 18 19 | 
             
              * [`chomp_if`](#chomp_if)
         | 
| 19 20 | 
             
              * [`chomp_while`](#chomp_while)
         | 
| @@ -51,7 +52,7 @@ parser.parse('123a') # => Bad<...> | |
| 51 52 | 
             
            parser.parse('0x1A') # => Bad<...>
         | 
| 52 53 |  | 
| 53 54 |  | 
| 54 | 
            -
            # negative integers with '-' prefix
         | 
| 55 | 
            +
            # support negative integers with '-' prefix
         | 
| 55 56 | 
             
            def my_integer
         | 
| 56 57 | 
             
              take(:one_of, [
         | 
| 57 58 | 
             
                map(->(x) { x * -1 }).drop(:token, '-').take(:integer),
         | 
| @@ -176,6 +177,31 @@ parser.parse('12,')        # => Bad<...> | |
| 176 177 | 
             
            parser.parse(',12')        # => Bad<...>
         | 
| 177 178 | 
             
            ```
         | 
| 178 179 |  | 
| 180 | 
            +
            #### `lazy`
         | 
| 181 | 
            +
             | 
| 182 | 
            +
            Wraps a parser in a lazy-evaluated proc. Use `lazy` to build recursive parsers.
         | 
| 183 | 
            +
             | 
| 184 | 
            +
            ```ruby
         | 
| 185 | 
            +
            ToList = ->(*integers) { integers }
         | 
| 186 | 
            +
             | 
| 187 | 
            +
            CommaSeparatedInteger = -> do
         | 
| 188 | 
            +
              take(:integer)
         | 
| 189 | 
            +
                .drop(:spaces)
         | 
| 190 | 
            +
                .take(:one_of, [
         | 
| 191 | 
            +
                  drop(:token, ',').drop(:spaces).take(:lazy, CommaSeparatedInteger),
         | 
| 192 | 
            +
                  succeed
         | 
| 193 | 
            +
                ])
         | 
| 194 | 
            +
            end
         | 
| 195 | 
            +
             | 
| 196 | 
            +
            parser = map(ToList).take(CommaSeparatedInteger.call())
         | 
| 197 | 
            +
             | 
| 198 | 
            +
            parser.parse('12, 23, 34') # => Good<[12, 23, 34]>
         | 
| 199 | 
            +
            parser.parse('123')        # => Good<[123]>
         | 
| 200 | 
            +
             | 
| 201 | 
            +
            parser.parse('12,')        # => Bad<...>
         | 
| 202 | 
            +
            parser.parse(',12')        # => Bad<...>
         | 
| 203 | 
            +
            ```
         | 
| 204 | 
            +
             | 
| 179 205 | 
             
            #### `spaces`
         | 
| 180 206 |  | 
| 181 207 | 
             
            Chompes zero or more blankspaces, line breaks and tabs. Always succeeds.
         | 
| @@ -210,12 +236,14 @@ parser.parse('cccdd').state # => State<good?: true, offset: 0, chomped: ''> | |
| 210 236 | 
             
            ## Benchmark
         | 
| 211 237 |  | 
| 212 238 | 
             
            The following result is a benchark of a [JSON parser](https://github.com/luizpvas/Compser/blob/main/examples/json.rb) I implemented
         | 
| 213 | 
            -
            with this library. I ran the benchmark with and without YJIT, and compared the result against  | 
| 239 | 
            +
            with this library. I ran the benchmark with and without YJIT, and compared the result against `JSON.parse` (native C implementation) and [Parsby](https://github.com/jolmg/parsby).
         | 
| 214 240 |  | 
| 215 | 
            -
            The benchmark parses a 1,5kb payload  | 
| 241 | 
            +
            [The benchmark](https://github.com/luizpvas/compser/blob/main/examples/json-benchmark.rb) parses a 1,5kb payload 100 times.
         | 
| 216 242 |  | 
| 217 | 
            -
            Implementation | Time |  | 
| 243 | 
            +
            Implementation | Time | Comparison to `JSON.parse`
         | 
| 218 244 | 
             
            :---:|:---:|:---:
         | 
| 219 | 
            -
            `JSON.parse` | 
| 220 | 
            -
            ` | 
| 221 | 
            -
            ` | 
| 245 | 
            +
            `JSON.parse`                              | 0.00067s | -
         | 
| 246 | 
            +
            `Compser::Json.parse` (with YJIT)         | 0.216s   | 322x slower
         | 
| 247 | 
            +
            `Compser::Json.parse`                     | 0.268s   | 400x slower
         | 
| 248 | 
            +
            `Parsby::Example::JsonParser` (with YJIT) | 24.19s   | 36100x slower
         | 
| 249 | 
            +
            `Parsby::Example::JsonParser`             | 27.22s   | 40626x slower
         | 
| @@ -0,0 +1,76 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require_relative "../lib/compser"
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            module Compser::Calculator
         | 
| 6 | 
            +
              extend Compser
         | 
| 7 | 
            +
              extend self
         | 
| 8 | 
            +
             | 
| 9 | 
            +
              def evaluate(...)
         | 
| 10 | 
            +
                expression.parse(...)
         | 
| 11 | 
            +
              end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
              OPERATORS = {
         | 
| 14 | 
            +
                "+" => ->(a, b) { a + b },
         | 
| 15 | 
            +
                "-" => ->(a, b) { a - b },
         | 
| 16 | 
            +
                "*" => ->(a, b) { a * b },
         | 
| 17 | 
            +
                "/" => ->(a, b) { a / b }
         | 
| 18 | 
            +
              }.freeze
         | 
| 19 | 
            +
             | 
| 20 | 
            +
              Evaluate = ->(*args) {
         | 
| 21 | 
            +
                result = args.shift
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                while args.any?
         | 
| 24 | 
            +
                  oprt = args.shift
         | 
| 25 | 
            +
                  expr = args.shift
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                  result = OPERATORS.fetch(oprt).call(result, expr)
         | 
| 28 | 
            +
                end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                result
         | 
| 31 | 
            +
              }
         | 
| 32 | 
            +
             | 
| 33 | 
            +
              ExpressionHelper = ->(continue, done) do
         | 
| 34 | 
            +
                take(:one_of, [
         | 
| 35 | 
            +
                  take(operator).drop(:spaces).take(value).drop(:spaces).and_then(continue),
         | 
| 36 | 
            +
                  done
         | 
| 37 | 
            +
                ])
         | 
| 38 | 
            +
              end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
              def expression
         | 
| 41 | 
            +
                map(Evaluate)
         | 
| 42 | 
            +
                  .take(value)
         | 
| 43 | 
            +
                  .drop(:spaces)
         | 
| 44 | 
            +
                  .take(:sequence, ExpressionHelper)
         | 
| 45 | 
            +
              end
         | 
| 46 | 
            +
             | 
| 47 | 
            +
              def value
         | 
| 48 | 
            +
                take(:one_of, [
         | 
| 49 | 
            +
                  drop(:token, "(").drop(:spaces).take(:lazy, -> { expression }).drop(:spaces).drop(:token, ")"),
         | 
| 50 | 
            +
                  number
         | 
| 51 | 
            +
                ])
         | 
| 52 | 
            +
              end
         | 
| 53 | 
            +
             | 
| 54 | 
            +
              def operator
         | 
| 55 | 
            +
                take(:chomp_if, ->(c) { OPERATORS.key?(c) })
         | 
| 56 | 
            +
                  .and_then { |state| state.good!(state.consume_chomped) }
         | 
| 57 | 
            +
              end
         | 
| 58 | 
            +
             | 
| 59 | 
            +
              def number
         | 
| 60 | 
            +
                take(:one_of, [
         | 
| 61 | 
            +
                  map(->(n) { n * -1 }).drop(:token, "-").take(:decimal),
         | 
| 62 | 
            +
                  take(:decimal)
         | 
| 63 | 
            +
                ])
         | 
| 64 | 
            +
              end
         | 
| 65 | 
            +
            end
         | 
| 66 | 
            +
             | 
| 67 | 
            +
            calc = ->(input) { input + " = " + sprintf("%.2f", Compser::Calculator.evaluate(input).value) }
         | 
| 68 | 
            +
             | 
| 69 | 
            +
            puts calc.("1 + 1")
         | 
| 70 | 
            +
            puts calc.("1 + 2 + 3")
         | 
| 71 | 
            +
            puts calc.("3 * 3 / 2")
         | 
| 72 | 
            +
            puts calc.("0.1 + 0.2")
         | 
| 73 | 
            +
            puts calc.("2 + 2 * 4")
         | 
| 74 | 
            +
            puts calc.("(2 + 2) * 4")
         | 
| 75 | 
            +
            puts calc.("((((10))))")
         | 
| 76 | 
            +
            puts calc.("((((10))+5))")
         | 
    
        data/examples/json-benchmark.rb
    CHANGED
    
    | @@ -1,16 +1,22 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            require_relative "json"
         | 
| 2 4 | 
             
            require "json"
         | 
| 3 5 | 
             
            require "benchmark"
         | 
| 6 | 
            +
            require "stringio"
         | 
| 7 | 
            +
            require "parsby"
         | 
| 8 | 
            +
            require "parsby/example/json_parser"
         | 
| 4 9 |  | 
| 5 10 | 
             
            json = File.read("./json-payload.json")
         | 
| 6 11 |  | 
| 7 | 
            -
            n =  | 
| 12 | 
            +
            n = 100
         | 
| 8 13 |  | 
| 9 | 
            -
             | 
| 14 | 
            +
            5000.times do; Compser::Json.parse(json); end
         | 
| 10 15 |  | 
| 11 16 | 
             
            Benchmark.bm do |x|
         | 
| 12 | 
            -
              x.report(" | 
| 17 | 
            +
              x.report("Compser::Json.parse") { n.times do; Compser::Json.parse(json); end }
         | 
| 13 18 | 
             
              x.report("JSON.parse")   { n.times do; ::JSON.parse(json); end }
         | 
| 19 | 
            +
              x.report("Parsby")       { n.times do; Parsby::Example::JsonParser.parse(json); end }
         | 
| 14 20 | 
             
            end
         | 
| 15 21 |  | 
| 16 22 | 
             
            puts RubyVM::YJIT.runtime_stats
         | 
    
        data/examples/json.rb
    CHANGED
    
    | @@ -1,6 +1,8 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            require_relative "../lib/compser"
         | 
| 2 4 |  | 
| 3 | 
            -
            module  | 
| 5 | 
            +
            module Compser::Json
         | 
| 4 6 | 
             
              extend Compser
         | 
| 5 7 | 
             
              extend self
         | 
| 6 8 |  | 
| @@ -10,9 +12,10 @@ module MyJson | |
| 10 12 |  | 
| 11 13 | 
             
              def value
         | 
| 12 14 | 
             
                take(:one_of, [
         | 
| 13 | 
            -
                   | 
| 15 | 
            +
                  null,
         | 
| 14 16 | 
             
                  number,
         | 
| 15 17 | 
             
                  boolean,
         | 
| 18 | 
            +
                  take(:double_quoted_string),
         | 
| 16 19 | 
             
                  array,
         | 
| 17 20 | 
             
                  object
         | 
| 18 21 | 
             
                ])
         | 
| @@ -57,6 +60,10 @@ module MyJson | |
| 57 60 | 
             
                  .drop(:token, "]")
         | 
| 58 61 | 
             
              end
         | 
| 59 62 |  | 
| 63 | 
            +
              def null
         | 
| 64 | 
            +
                map(-> { nil }).drop(:token, "null")
         | 
| 65 | 
            +
              end
         | 
| 66 | 
            +
             | 
| 60 67 | 
             
              def number
         | 
| 61 68 | 
             
                take(:one_of, [
         | 
| 62 69 | 
             
                  map(->(x) { x * -1 }).drop(:token, "-").take(:decimal),
         | 
    
        data/lib/compser/result.rb
    CHANGED
    
    | @@ -1,12 +1,12 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 3 | 
             
            module Compser::Result
         | 
| 4 | 
            -
              Good = Data.define(: | 
| 4 | 
            +
              Good = Data.define(:value) do
         | 
| 5 5 | 
             
                def good? = true
         | 
| 6 6 | 
             
                def bad?  = false
         | 
| 7 7 | 
             
              end
         | 
| 8 8 |  | 
| 9 | 
            -
              Bad = Data.define(: | 
| 9 | 
            +
              Bad = Data.define(:message) do
         | 
| 10 10 | 
             
                def bad?  = true
         | 
| 11 11 | 
             
                def good? = false
         | 
| 12 12 | 
             
              end
         | 
    
        data/lib/compser/state.rb
    CHANGED
    
    | @@ -9,7 +9,7 @@ class Compser::State | |
| 9 9 | 
             
                @line = 0
         | 
| 10 10 | 
             
                @column = 0
         | 
| 11 11 | 
             
                @chomped = ::String.new("")
         | 
| 12 | 
            -
                @result_stack = [Compser::Result::Good.new( | 
| 12 | 
            +
                @result_stack = [Compser::Result::Good.new(nil)]
         | 
| 13 13 | 
             
              end
         | 
| 14 14 |  | 
| 15 15 | 
             
              def result
         | 
| @@ -76,12 +76,12 @@ class Compser::State | |
| 76 76 | 
             
              def good(value)
         | 
| 77 77 | 
             
                return value if value.is_a?(Compser::Result::Good)
         | 
| 78 78 |  | 
| 79 | 
            -
                Compser::Result::Good.new( | 
| 79 | 
            +
                Compser::Result::Good.new(value)
         | 
| 80 80 | 
             
              end
         | 
| 81 81 |  | 
| 82 82 | 
             
              def bad(message)
         | 
| 83 83 | 
             
                return message if message.is_a?(Compser::Result::Bad)
         | 
| 84 84 |  | 
| 85 | 
            -
                Compser::Result::Bad.new( | 
| 85 | 
            +
                Compser::Result::Bad.new(message)
         | 
| 86 86 | 
             
              end
         | 
| 87 87 | 
             
            end
         | 
    
        data/lib/compser/step/drop.rb
    CHANGED
    
    
    
        data/lib/compser/step/one_of.rb
    CHANGED
    
    | @@ -9,8 +9,8 @@ class Compser::Step | |
| 9 9 | 
             
                branches.each_with_index do |branch, index|
         | 
| 10 10 | 
             
                  state = branch.call(state)
         | 
| 11 11 |  | 
| 12 | 
            -
                  return  | 
| 13 | 
            -
                  return  | 
| 12 | 
            +
                  return if savepoint.has_changes?
         | 
| 13 | 
            +
                  return if index == branches.size - 1 # is last
         | 
| 14 14 |  | 
| 15 15 | 
             
                  savepoint.rollback
         | 
| 16 16 | 
             
                end
         | 
| @@ -16,11 +16,8 @@ class Compser::Step | |
| 16 16 | 
             
                  state = helper.call(continue, done).call(state)
         | 
| 17 17 | 
             
                end
         | 
| 18 18 |  | 
| 19 | 
            -
                return  | 
| 20 | 
            -
             | 
| 21 | 
            -
                if state.good? && state.__sequence__ == DONE
         | 
| 22 | 
            -
                  return state
         | 
| 23 | 
            -
                end
         | 
| 19 | 
            +
                return if state.bad?
         | 
| 20 | 
            +
                return if state.__sequence__ == DONE
         | 
| 24 21 |  | 
| 25 22 | 
             
                state.bad!("unbound sequence")
         | 
| 26 23 | 
             
              end
         | 
    
        data/lib/compser/step.rb
    CHANGED
    
    | @@ -8,6 +8,7 @@ class Compser::Step | |
| 8 8 | 
             
                double_quoted_string: DoubleQuotedString,
         | 
| 9 9 | 
             
                integer:              Integer,
         | 
| 10 10 | 
             
                keyword:              Keyword.curry,
         | 
| 11 | 
            +
                lazy:                 Lazy.curry,
         | 
| 11 12 | 
             
                one_of:               OneOf.curry,
         | 
| 12 13 | 
             
                problem:              Problem.curry,
         | 
| 13 14 | 
             
                sequence:             Sequence.curry,
         | 
| @@ -27,7 +28,7 @@ class Compser::Step | |
| 27 28 | 
             
              def call(state)
         | 
| 28 29 | 
             
                results_before = state.result_stack.size
         | 
| 29 30 |  | 
| 30 | 
            -
                 | 
| 31 | 
            +
                @steps.each do |step|
         | 
| 31 32 | 
             
                  return state if state.bad?
         | 
| 32 33 |  | 
| 33 34 | 
             
                  step.call(state)
         | 
| @@ -49,11 +50,11 @@ class Compser::Step | |
| 49 50 |  | 
| 50 51 | 
             
                step =
         | 
| 51 52 | 
             
                  case first
         | 
| 52 | 
            -
                  when Proc | 
| 53 | 
            +
                  when Proc          then first
         | 
| 53 54 | 
             
                  when Compser::Step then first
         | 
| 54 | 
            -
                  when Symbol | 
| 55 | 
            -
                  when nil | 
| 56 | 
            -
                  else | 
| 55 | 
            +
                  when Symbol        then STEPS.fetch(args.first).call(*rest)
         | 
| 56 | 
            +
                  when nil           then block ? block : raise(ArgumentError, "expected a callable") 
         | 
| 57 | 
            +
                  else               raise ArgumentError, "expected a callable, got #{args.inspect}"
         | 
| 57 58 | 
             
                  end
         | 
| 58 59 |  | 
| 59 60 | 
             
                @steps << step
         | 
| @@ -68,11 +69,11 @@ class Compser::Step | |
| 68 69 |  | 
| 69 70 | 
             
                step =
         | 
| 70 71 | 
             
                  case first
         | 
| 71 | 
            -
                  when Proc | 
| 72 | 
            +
                  when Proc          then Drop.(first)
         | 
| 72 73 | 
             
                  when Compser::Step then Drop.(first)
         | 
| 73 | 
            -
                  when Symbol | 
| 74 | 
            -
                  when nil | 
| 75 | 
            -
                  else | 
| 74 | 
            +
                  when Symbol        then Drop.(STEPS.fetch(first).call(*rest))
         | 
| 75 | 
            +
                  when nil           then block ? Drop.(block) : raise(ArgumentError, "expected a callable") 
         | 
| 76 | 
            +
                  else               raise ArgumentError, "expected a callable"
         | 
| 76 77 | 
             
                  end
         | 
| 77 78 |  | 
| 78 79 | 
             
                @steps << step
         | 
    
        data/lib/compser/version.rb
    CHANGED
    
    
    
        data/lib/compser.rb
    CHANGED
    
    | @@ -11,6 +11,7 @@ require_relative "compser/step/double_quoted_string" | |
| 11 11 | 
             
            require_relative "compser/step/drop"
         | 
| 12 12 | 
             
            require_relative "compser/step/integer"
         | 
| 13 13 | 
             
            require_relative "compser/step/keyword"
         | 
| 14 | 
            +
            require_relative "compser/step/lazy"
         | 
| 14 15 | 
             
            require_relative "compser/step/one_of"
         | 
| 15 16 | 
             
            require_relative "compser/step/problem"
         | 
| 16 17 | 
             
            require_relative "compser/step/sequence"
         | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: compser
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0. | 
| 4 | 
            +
              version: 0.2.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Luiz Vasconcellos
         | 
| 8 8 | 
             
            autorequire: 
         | 
| 9 9 | 
             
            bindir: exe
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2023-10- | 
| 11 | 
            +
            date: 2023-10-15 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies: []
         | 
| 13 13 | 
             
            description: 
         | 
| 14 14 | 
             
            email:
         | 
| @@ -24,6 +24,7 @@ files: | |
| 24 24 | 
             
            - LICENSE.txt
         | 
| 25 25 | 
             
            - README.md
         | 
| 26 26 | 
             
            - Rakefile
         | 
| 27 | 
            +
            - examples/calculator.rb
         | 
| 27 28 | 
             
            - examples/json-benchmark.rb
         | 
| 28 29 | 
             
            - examples/json-payload.json
         | 
| 29 30 | 
             
            - examples/json.rb
         | 
| @@ -39,6 +40,7 @@ files: | |
| 39 40 | 
             
            - lib/compser/step/drop.rb
         | 
| 40 41 | 
             
            - lib/compser/step/integer.rb
         | 
| 41 42 | 
             
            - lib/compser/step/keyword.rb
         | 
| 43 | 
            +
            - lib/compser/step/lazy.rb
         | 
| 42 44 | 
             
            - lib/compser/step/one_of.rb
         | 
| 43 45 | 
             
            - lib/compser/step/problem.rb
         | 
| 44 46 | 
             
            - lib/compser/step/sequence.rb
         | 
| @@ -70,5 +72,5 @@ requirements: [] | |
| 70 72 | 
             
            rubygems_version: 3.4.10
         | 
| 71 73 | 
             
            signing_key: 
         | 
| 72 74 | 
             
            specification_version: 4
         | 
| 73 | 
            -
            summary:  | 
| 75 | 
            +
            summary: Compser is a parser builder library for Ruby.
         | 
| 74 76 | 
             
            test_files: []
         |