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 +4 -4
- data/CHANGELOG.md +16 -0
- data/lib/farseer/and.rb +37 -0
- data/lib/farseer/any.rb +4 -4
- data/lib/farseer/chars.rb +2 -2
- data/lib/farseer/many.rb +5 -5
- data/lib/farseer/opt.rb +3 -2
- data/lib/farseer/or.rb +24 -0
- data/lib/farseer/regexp.rb +23 -0
- data/lib/farseer/result.rb +2 -2
- data/lib/farseer/version.rb +1 -1
- data/lib/farseer/word.rb +17 -0
- data/lib/farseer.rb +0 -19
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 22cbc0c49fc2a306b2e0e7291dd58e09047bd2eef4b679d2be9f9e307c6db2e1
|
4
|
+
data.tar.gz: a3a1a49b2748d129931af363e3a4bcbb9fdbd174956de07a4de0daceb0cc07cb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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. (`?`)
|
data/lib/farseer/and.rb
ADDED
@@ -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,
|
17
|
-
.map_none { Result.new(tokens
|
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
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,
|
12
|
+
.bind { |r| helper(r.rest, r.token) }
|
13
13
|
end
|
14
14
|
|
15
|
-
def helper(input, tokens
|
16
|
-
|
17
|
-
|
18
|
-
|
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
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
|
data/lib/farseer/result.rb
CHANGED
data/lib/farseer/version.rb
CHANGED
data/lib/farseer/word.rb
ADDED
@@ -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.
|
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-
|
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
|