farseer 0.6.0 → 0.8.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: 656cdb47ea0c930c3706c4ecb11eba8df657c4890e84a5537ba7e1aa4bcb1624
4
+ data.tar.gz: 14ec99cefd66715c3d2338fabb10ef56c8e371d2aacef140a835761e42057440
5
5
  SHA512:
6
- metadata.gz: 9fdc000cff13a63b7ecd370d2a9f454736bc43a5b41ff4b001fdbc07a46ff5b6f2c17101eb27be07499c73b39faace6e00ca61ec04cfebac408054a16ba4cab2
7
- data.tar.gz: a147d2daafaa1205e316fdcb811ddd8ae78150d060cf890081bd7ad46f2566398fad6b6941711355f13e2f897e37ac290b877e9e418a138a78759beb2fa0eeb3
6
+ metadata.gz: d658b63d11e9c0aac8ffda570a1a2ab43e225645433a178981fb1850a7d6e23cf98027684e86354974082719655dad75c4b7d14386b5013e007c1bac3ad53092
7
+ data.tar.gz: e9fec41b0d13895de5c9404997f7cf6474fbda1370584806b35caa426d4c2204761650a8a874b11efbb645fc5b941fa7ba1fd9888f8334bc59472af8b7d13b7b
data/CHANGELOG.md CHANGED
@@ -7,6 +7,32 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.8.0] - 2024-06-04
11
+ ### Added
12
+ - `Farseer::Map` which is a parser with a callback to map the resulting token
13
+ into something else.
14
+ - `Farseer::MapFactory` which adds `#map`, a factory method for new parsers with
15
+ callbacks. It creates a new instance of `Farseer::Map`.
16
+ - Included `Farseer::MapFactory` into all parsers.
17
+
18
+
19
+ ## [0.7.0] - 2024-06-04
20
+ ### Added
21
+ - `Farseer::And` to run a sequence of parsers that must all succeed.
22
+ - `Farseer::Or` to try multiple parsers until one works.
23
+ - `Farseer::Word` to parse a keyword at the beginning of a string.
24
+ - `Farseer::Regexp` to parse a token using `regexp`.
25
+ - `mutant` development dependency for mutation testing.
26
+ - Achieve `100%` mutation test coverage.
27
+ - `byebug` development dependency for debugging.
28
+
29
+ ### Removed
30
+ - All helper methods of `Farseer`.
31
+
32
+ ### Changed
33
+ - Update development dependencies.
34
+
35
+
10
36
  ## [0.6.0] - 2024-06-03
11
37
  ### Added
12
38
  - `Farseer::Opt` to parse `0` to `1` times the wrapped parser. (`?`)
@@ -21,6 +47,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
21
47
  ### Changed
22
48
  - Updated development dependencies
23
49
 
50
+
24
51
  ## [0.5.0] - 2024-06-03
25
52
  ### Added
26
53
  - `Farseer::Char` as a single character parser.
@@ -38,6 +65,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
38
65
  ### Changed
39
66
  - Update `muina` version requirement to `~> 0.5`
40
67
 
68
+
41
69
  ## [0.4.0] - 2024-06-03
42
70
  ### Added
43
71
  - `Farseer.any_char_parser` to parse a single character from a given set.
@@ -48,6 +76,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
48
76
  - Stop using `module_function` and change methods into singleton methods.
49
77
  - Update `bundler` version.
50
78
 
79
+
51
80
  ## [0.3.0] - 2024-06-02
52
81
  ### Added
53
82
  - `Farseer#ws_parser` to parse all leading whitespace.
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Farseer
4
+ class And
5
+ include MapFactory
6
+
7
+ def initialize(*parsers)
8
+ @parsers = parsers.flatten
9
+ freeze
10
+ end
11
+
12
+ def parse(input)
13
+ return Maybe.none if @parsers.empty?
14
+
15
+ initial = Maybe.return(Result.new('', input))
16
+
17
+ @parsers.reduce(initial) do |maybe_acc, parser|
18
+ bind_accumulator(maybe_acc, parser)
19
+ end
20
+ end
21
+
22
+ def bind_accumulator(maybe_acc, parser)
23
+ maybe_acc.bind do |acc_result|
24
+ parse_with_rest(parser, acc_result)
25
+ end
26
+ end
27
+
28
+ def parse_with_rest(parser, acc_result)
29
+ parser.parse(acc_result.rest).bind do |result|
30
+ combine_results(acc_result, result)
31
+ end
32
+ end
33
+
34
+ def combine_results(acc_result, result)
35
+ combined_tokens = acc_result.token + result.token
36
+ Maybe.return(Result.new(combined_tokens, result.rest))
37
+ end
38
+ end
39
+ end
data/lib/farseer/any.rb CHANGED
@@ -2,19 +2,21 @@
2
2
 
3
3
  module Farseer
4
4
  class Any
5
+ include MapFactory
6
+
5
7
  def initialize(parser)
6
8
  @parser = parser
7
9
  freeze
8
10
  end
9
11
 
10
12
  def parse(input)
11
- helper(input)
13
+ helper(input, '')
12
14
  end
13
15
 
14
- def helper(input, tokens = [])
16
+ def helper(input, tokens)
15
17
  @parser.parse(input)
16
- .bind { |r| helper(r.rest, [*tokens, r.token]) }
17
- .map_none { Result.new(tokens.join, input) }
18
+ .bind { |r| helper(r.rest, tokens + r.token) }
19
+ .map_none { Result.new(tokens, input) }
18
20
  end
19
21
  end
20
22
  end
data/lib/farseer/char.rb CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  module Farseer
4
4
  class Char
5
+ include MapFactory
6
+
5
7
  def initialize(char)
6
8
  @char = char
7
9
  freeze
data/lib/farseer/chars.rb CHANGED
@@ -2,8 +2,10 @@
2
2
 
3
3
  module Farseer
4
4
  class Chars
5
- def initialize(chars)
6
- @chars = chars
5
+ include MapFactory
6
+
7
+ def initialize(*chars)
8
+ @chars = chars.flatten
7
9
  freeze
8
10
  end
9
11
 
data/lib/farseer/many.rb CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  module Farseer
4
4
  class Many
5
+ include MapFactory
6
+
5
7
  def initialize(parser)
6
8
  @parser = parser
7
9
  freeze
@@ -9,13 +11,13 @@ module Farseer
9
11
 
10
12
  def parse(input)
11
13
  @parser.parse(input)
12
- .bind { |r| helper(r.rest, [r.token]) }
14
+ .bind { |r| helper(r.rest, r.token) }
13
15
  end
14
16
 
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) }
17
+ def helper(input, tokens)
18
+ parse(input)
19
+ .bind { |r| helper(r.rest, tokens + r.token) }
20
+ .map_none { Result.new(tokens, input) }
19
21
  end
20
22
  end
21
23
  end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Farseer
4
+ class Map
5
+ include MapFactory
6
+
7
+ def initialize(parser, &map)
8
+ @parser = parser
9
+ @map = map
10
+ freeze
11
+ end
12
+
13
+ def parse(input)
14
+ @parser.parse(input).map { |r| Result.new(@map.call(r.token), r.rest) }
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,7 @@
1
+ module Farseer
2
+ module MapFactory
3
+ def map(&)
4
+ Map.new(self, &)
5
+ end
6
+ end
7
+ end
data/lib/farseer/opt.rb CHANGED
@@ -2,14 +2,17 @@
2
2
 
3
3
  module Farseer
4
4
  class Opt
5
+ include MapFactory
6
+
5
7
  def initialize(parser)
6
8
  @parser = parser
7
9
  freeze
8
10
  end
9
11
 
10
12
  def parse(input)
11
- @parser.parse(input)
12
- .map_none { Result.new('', input) }
13
+ @parser
14
+ .parse(input)
15
+ .map_none { Result.new('', input) }
13
16
  end
14
17
  end
15
18
  end
data/lib/farseer/or.rb ADDED
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Farseer
4
+ class Or
5
+ include MapFactory
6
+
7
+ def initialize(*parsers)
8
+ @parsers = parsers.flatten
9
+ freeze
10
+ end
11
+
12
+ def parse(input)
13
+ case @parsers.length
14
+ when 0 then Maybe.none
15
+ when 1 then @parsers.first.parse(input)
16
+ else parse_helper(input)
17
+ end
18
+ end
19
+
20
+ def parse_helper(input)
21
+ @parsers.reduce do |acc, parser|
22
+ acc.parse(input).bind_none { parser.parse(input) }
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Farseer
4
+ class Regexp
5
+ include MapFactory
6
+
7
+ WS_REGEXP = /^(?'token'\s*)(?'rest'.*)$/
8
+ RegexpError = Class.new(ArgumentError)
9
+
10
+ def initialize(regexp)
11
+ raise RegexpError unless regexp.names == ['token', 'rest']
12
+
13
+ @regexp = regexp
14
+ freeze
15
+ end
16
+
17
+ WS = new(WS_REGEXP)
18
+
19
+ def parse(input)
20
+ match = input.match(@regexp)
21
+
22
+ Maybe.return(Result.new(match[:token], match[:rest]))
23
+ end
24
+ end
25
+ 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.8.0'
5
5
  public_constant :VERSION
6
6
  end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Farseer
4
+ class Word
5
+ include MapFactory
6
+
7
+ def initialize(word)
8
+ @word = word
9
+ freeze
10
+ end
11
+
12
+ def parse(input)
13
+ case
14
+ when input.start_with?(@word) then Maybe.return(Result.new(@word, input[@word.length..]))
15
+ else Maybe.none
16
+ end
17
+ end
18
+ end
19
+ 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.8.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-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: muina
@@ -50,13 +50,19 @@ 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
58
+ - lib/farseer/map.rb
59
+ - lib/farseer/map_factory.rb
57
60
  - lib/farseer/opt.rb
61
+ - lib/farseer/or.rb
62
+ - lib/farseer/regexp.rb
58
63
  - lib/farseer/result.rb
59
64
  - lib/farseer/version.rb
65
+ - lib/farseer/word.rb
60
66
  homepage: https://github.com/vaporyhumo/farseer
61
67
  licenses:
62
68
  - Unlicense