farseer 0.6.0 → 0.7.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2700438309a0da4774a6b4c33aa2f8dc01a61e4ae6eae9db5b5d4bc917f45263
4
- data.tar.gz: da6f37d9b9582cfb731a39d6de9a7afbe4678b5e67df717008b8fdfa39281409
3
+ metadata.gz: 22cbc0c49fc2a306b2e0e7291dd58e09047bd2eef4b679d2be9f9e307c6db2e1
4
+ data.tar.gz: a3a1a49b2748d129931af363e3a4bcbb9fdbd174956de07a4de0daceb0cc07cb
5
5
  SHA512:
6
- metadata.gz: 9fdc000cff13a63b7ecd370d2a9f454736bc43a5b41ff4b001fdbc07a46ff5b6f2c17101eb27be07499c73b39faace6e00ca61ec04cfebac408054a16ba4cab2
7
- data.tar.gz: a147d2daafaa1205e316fdcb811ddd8ae78150d060cf890081bd7ad46f2566398fad6b6941711355f13e2f897e37ac290b877e9e418a138a78759beb2fa0eeb3
6
+ metadata.gz: 8b3bc436e67fcd46f61964cb6e3e70c7f3a8c374a1712680f4a91901daaf9ae071c79428ac40da19038619e8a05556cbbfd0167d43b5841020b082d730f909a6
7
+ data.tar.gz: 2303e7849b72c10e9353ff9faf362c3d8e0113f24247dbd95104ea45d2c5877e96bcf2444d402853909f14590f4a3c8295f813f99ebc23e1c4bbccbb33c11ae8
data/CHANGELOG.md CHANGED
@@ -7,6 +7,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.7.0] - 2024-06-04
11
+ ### Added
12
+ - `Farseer::And` to run a sequence of parsers that must all succeed.
13
+ - `Farseer::Or` to try multiple parsers until one works.
14
+ - `Farseer::Word` to parse a keyword at the beginning of a string.
15
+ - `Farseer::Regexp` to parse a token using `regexp`.
16
+ - `mutant` development dependency for mutation testing.
17
+ - Achieve `100%` mutation test coverage.
18
+ - `byebug` development dependency for debugging.
19
+
20
+ ### Removed
21
+ - All helper methods of `Farseer`.
22
+
23
+ ### Changed
24
+ - Update development dependencies.
25
+
10
26
  ## [0.6.0] - 2024-06-03
11
27
  ### Added
12
28
  - `Farseer::Opt` to parse `0` to `1` times the wrapped parser. (`?`)
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Farseer
4
+ class And
5
+ def initialize(*parsers)
6
+ @parsers = parsers.flatten
7
+ freeze
8
+ end
9
+
10
+ def parse(input)
11
+ return Maybe.none if @parsers.empty?
12
+
13
+ initial = Maybe.return(Result.new('', input))
14
+
15
+ @parsers.reduce(initial) do |maybe_acc, parser|
16
+ bind_accumulator(maybe_acc, parser)
17
+ end
18
+ end
19
+
20
+ def bind_accumulator(maybe_acc, parser)
21
+ maybe_acc.bind do |acc_result|
22
+ parse_with_rest(parser, acc_result)
23
+ end
24
+ end
25
+
26
+ def parse_with_rest(parser, acc_result)
27
+ parser.parse(acc_result.rest).bind do |result|
28
+ combine_results(acc_result, result)
29
+ end
30
+ end
31
+
32
+ def combine_results(acc_result, result)
33
+ combined_tokens = acc_result.token + result.token
34
+ Maybe.return(Result.new(combined_tokens, result.rest))
35
+ end
36
+ end
37
+ end
data/lib/farseer/any.rb CHANGED
@@ -8,13 +8,13 @@ module Farseer
8
8
  end
9
9
 
10
10
  def parse(input)
11
- helper(input)
11
+ helper(input, '')
12
12
  end
13
13
 
14
- def helper(input, tokens = [])
14
+ def helper(input, tokens)
15
15
  @parser.parse(input)
16
- .bind { |r| helper(r.rest, [*tokens, r.token]) }
17
- .map_none { Result.new(tokens.join, input) }
16
+ .bind { |r| helper(r.rest, tokens + r.token) }
17
+ .map_none { Result.new(tokens, input) }
18
18
  end
19
19
  end
20
20
  end
data/lib/farseer/chars.rb CHANGED
@@ -2,8 +2,8 @@
2
2
 
3
3
  module Farseer
4
4
  class Chars
5
- def initialize(chars)
6
- @chars = chars
5
+ def initialize(*chars)
6
+ @chars = chars.flatten
7
7
  freeze
8
8
  end
9
9
 
data/lib/farseer/many.rb CHANGED
@@ -9,13 +9,13 @@ module Farseer
9
9
 
10
10
  def parse(input)
11
11
  @parser.parse(input)
12
- .bind { |r| helper(r.rest, [r.token]) }
12
+ .bind { |r| helper(r.rest, r.token) }
13
13
  end
14
14
 
15
- def helper(input, tokens = [])
16
- @parser.parse(input)
17
- .bind { |r| helper(r.rest, [*tokens, r.token]) }
18
- .map_none { Result.new(tokens.join, input) }
15
+ def helper(input, tokens)
16
+ parse(input)
17
+ .bind { |r| helper(r.rest, tokens + r.token) }
18
+ .map_none { Result.new(tokens, input) }
19
19
  end
20
20
  end
21
21
  end
data/lib/farseer/opt.rb CHANGED
@@ -8,8 +8,9 @@ module Farseer
8
8
  end
9
9
 
10
10
  def parse(input)
11
- @parser.parse(input)
12
- .map_none { Result.new('', input) }
11
+ @parser
12
+ .parse(input)
13
+ .map_none { Result.new('', input) }
13
14
  end
14
15
  end
15
16
  end
data/lib/farseer/or.rb ADDED
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Farseer
4
+ class Or
5
+ def initialize(*parsers)
6
+ @parsers = parsers.flatten
7
+ freeze
8
+ end
9
+
10
+ def parse(input)
11
+ case @parsers.length
12
+ when 0 then Maybe.none
13
+ when 1 then @parsers.first.parse(input)
14
+ else parse_helper(input)
15
+ end
16
+ end
17
+
18
+ def parse_helper(input)
19
+ @parsers.reduce do |acc, parser|
20
+ acc.parse(input).bind_none { parser.parse(input) }
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Farseer
4
+ class Regexp
5
+ WS_REGEXP = /^(?'token'\s*)(?'rest'.*)$/
6
+ RegexpError = Class.new(ArgumentError)
7
+
8
+ def initialize(regexp)
9
+ raise RegexpError unless regexp.names == ['token', 'rest']
10
+
11
+ @regexp = regexp
12
+ freeze
13
+ end
14
+
15
+ WS = new(WS_REGEXP)
16
+
17
+ def parse(input)
18
+ match = input.match(@regexp)
19
+
20
+ Maybe.return(Result.new(match[:token], match[:rest]))
21
+ end
22
+ end
23
+ end
@@ -11,8 +11,8 @@ module Farseer
11
11
 
12
12
  def eql?(other)
13
13
  self.class.eql?(other.class) and
14
- self.token.eql?(other.token) and
15
- self.rest.eql?(other.rest)
14
+ token.eql?(other.token) and
15
+ rest.eql?(other.rest)
16
16
  end
17
17
  alias == eql?
18
18
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Farseer
4
- VERSION = '0.6.0'
4
+ VERSION = '0.7.0'
5
5
  public_constant :VERSION
6
6
  end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Farseer
4
+ class Word
5
+ def initialize(word)
6
+ @word = word
7
+ freeze
8
+ end
9
+
10
+ def parse(input)
11
+ case
12
+ when input.start_with?(@word) then Maybe.return(Result.new(@word, input[@word.length..]))
13
+ else Maybe.none
14
+ end
15
+ end
16
+ end
17
+ end
data/lib/farseer.rb CHANGED
@@ -6,26 +6,7 @@ loader = Zeitwerk::Loader::for_gem
6
6
  loader.setup
7
7
 
8
8
  module Farseer
9
- WS_REGEX = /^(\s*)(.*)$/
10
9
  Maybe = Muina::Maybe
11
-
12
- def self.any_char_parser
13
- ->(chars, input) { Chars.new(chars).parse(input) }
14
- .curry
15
- end
16
-
17
- def self.char_parser
18
- ->(char, input) { Char.new(char).parse(input) }
19
- .curry
20
- end
21
-
22
- def self.ws_parser
23
- ->(input) {
24
- match = input.match(WS_REGEX)
25
-
26
- Maybe.return(Result.new(match[1], match[2]))
27
- }
28
- end
29
10
  end
30
11
 
31
12
  loader.eager_load
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: farseer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - vaporyhumo
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-06-03 00:00:00.000000000 Z
11
+ date: 2024-06-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: muina
@@ -50,13 +50,17 @@ files:
50
50
  - README.md
51
51
  - SECURITY.md
52
52
  - lib/farseer.rb
53
+ - lib/farseer/and.rb
53
54
  - lib/farseer/any.rb
54
55
  - lib/farseer/char.rb
55
56
  - lib/farseer/chars.rb
56
57
  - lib/farseer/many.rb
57
58
  - lib/farseer/opt.rb
59
+ - lib/farseer/or.rb
60
+ - lib/farseer/regexp.rb
58
61
  - lib/farseer/result.rb
59
62
  - lib/farseer/version.rb
63
+ - lib/farseer/word.rb
60
64
  homepage: https://github.com/vaporyhumo/farseer
61
65
  licenses:
62
66
  - Unlicense