trees 0.2.0 → 0.3.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.
Files changed (5) hide show
  1. checksums.yaml +4 -4
  2. data/lib/trees.rb +2 -2
  3. data/lib/trie.rb +47 -27
  4. data/lib/version.rb +1 -1
  5. metadata +1 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a1dc77a5635f0f3a070cad2a2de939adfd6d9e3550d4b4f3a25c34b567da0dca
4
- data.tar.gz: 04abe90dbcabe052c78a56581bf906596f8b6eb2c057985df0c4f364c9c5c8a9
3
+ metadata.gz: 1ac49d1c7aaa58a8ff86b29db7c2b7915c470094de6b3c1af4fbd4ad45adc597
4
+ data.tar.gz: 4a02b57c93cec8b8b42c36f39b158d0cca4c6d2a907b2c72bfdbfb38c5b57a74
5
5
  SHA512:
6
- metadata.gz: 4743bc99029f3fc8f7a3c21c58c2757b3916855d1f02a66db14a70fbfa73a44176406e75569bfb22a69001f6f2ba08b39f843051ba2f21f8578ff72837a6eb74
7
- data.tar.gz: 4dc45169e415cb0e705ae3fecdfd4f83b5652cdda893778ab05402f53339e638bda08f7d8fb86b142a1546a4231629d8446d71483701d739a72a5868f1eb3f34
6
+ metadata.gz: f37c39226cd76bfc232ef4933aa6221b8bf6069c90a0af11e2160dcbe62be6ba2072b63f7562c0b63e44f69eed949e380a59b58302cc52cbb2fa8d39e36429f7
7
+ data.tar.gz: 0b5c295977cb0b50c80c1c0fcbd271a5923f80943cc08efc0ded1ce333008723c21532c33c8e376adf6de5d718610b26b79f23d7fa3b0ee4b84d349fc0f0cd61
data/lib/trees.rb CHANGED
@@ -26,8 +26,8 @@ module Trees
26
26
  @current_line.execute = block
27
27
  end
28
28
 
29
- def run(args)
30
- results = trie.match(path: args.join(' '))
29
+ def run(tokens)
30
+ results = trie.match(tokens:)
31
31
 
32
32
  execute_block(results:)
33
33
  end
data/lib/trie.rb CHANGED
@@ -8,12 +8,13 @@ module Trees
8
8
  include LowType
9
9
 
10
10
  PARAM_DELIMITERS = [' ', ':'].freeze
11
- ARG_DELIMITERS = [' '].freeze
12
11
 
13
12
  attr_reader :root_node
14
13
 
15
14
  Result = Data.define(:line, :params)
16
15
 
16
+ class DuplicatePathError < StandardError; end
17
+
17
18
  def initialize
18
19
  @root_node = TrieNode.new
19
20
  end
@@ -33,35 +34,55 @@ module Trees
33
34
  current_node = current_node.upsert_child(key:)
34
35
  end
35
36
 
37
+ raise DuplicatePathError, "Path already defined: #{line.path}" if current_node.line
38
+
36
39
  current_node.line = line
37
40
  end
38
41
 
39
- def match(path:, current_node: @root_node, current_index: 0, params: {})
40
- return [] if (key = path[current_index]).nil?
42
+ def match(tokens:, current_node: @root_node, index: 0, offset: 0, params: {})
43
+ return [] if tokens.empty?
41
44
 
42
- results = []
45
+ [
46
+ *match_static(tokens:, current_node:, index:, offset:, params:),
47
+ *match_dynamic(tokens:, current_node:, index:, offset:, params:)
48
+ ]
49
+ end
43
50
 
44
- # Static path segment.
45
- if (child_node = current_node.child(key:))
46
- results << Result.new(line: child_node.line, params:) if child_node.line
47
- results = [*results, *match(path:, current_node: child_node, current_index: current_index + 1, params:)]
48
- end
51
+ private
52
+
53
+ # Match an input character with the trie or mimic the space character between tokens in the trie.
54
+ def match_static(tokens:, current_node:, index:, offset:, params:)
55
+ child_node = current_node.child(key: tokens[index][offset] || ' ')
56
+ return [] unless child_node
57
+
58
+ next_index, next_offset = advance(tokens:, index:, offset:)
59
+ result = end_match(child_node:, tokens:, index: next_index, offset: next_offset, params:)
60
+
61
+ [*result, *match(tokens:, current_node: child_node, index: next_index, offset: next_offset, params:)]
62
+ end
49
63
 
50
- # Dynamic path segment.
51
- current_node.params.each do |param|
64
+ # Dynamic path segment: capture the remainder of the current token.
65
+ def match_dynamic(tokens:, current_node:, index:, offset:, params:)
66
+ current_node.params.flat_map do |param|
52
67
  child_node = current_node.child(key: param)
68
+ arg, next_index, next_offset = capture_arg(tokens:, index:, offset:)
69
+ next_params = params.merge(param.delete_prefix(':').to_sym => arg)
53
70
 
54
- arg, next_index = capture_arg(start_index: current_index, path:)
55
- params[param.delete_prefix(':').to_sym] = arg
71
+ result = end_match(child_node:, tokens:, index: next_index, offset: next_offset, params: next_params)
56
72
 
57
- results << Result.new(line: child_node.line, params:) if child_node.line
58
- results = [*results, *match(path:, current_node: child_node, current_index: next_index, params:)]
73
+ [*result, *match(tokens:, current_node: child_node, index: next_index, offset: next_offset, params: next_params)]
59
74
  end
60
-
61
- results
62
75
  end
63
76
 
64
- private
77
+ # Match an end node.
78
+ # TODO: Match a mid node.
79
+ def end_match(child_node:, tokens:, index:, offset:, params:)
80
+ if child_node.line && tokens[index + 1].nil?
81
+ return [Result.new(line: child_node.line, params:)]
82
+ end
83
+
84
+ []
85
+ end
65
86
 
66
87
  def capture_param(path:)
67
88
  param = [':']
@@ -76,17 +97,16 @@ module Trees
76
97
  param.join
77
98
  end
78
99
 
79
- def capture_arg(start_index:, path:)
80
- next_index = start_index
81
- arg = []
100
+ def advance(tokens:, index:, offset:)
101
+ token = tokens[index]
82
102
 
83
- path[start_index...path.length].chars.each do |char|
84
- arg << char
85
- next_index += 1
86
- break if path[next_index].nil? || ARG_DELIMITERS.include?(path[next_index])
87
- end
103
+ offset < token.length ? [index, offset + 1] : [index + 1, 0]
104
+ end
105
+
106
+ def capture_arg(tokens:, index:, offset:)
107
+ token = tokens[index]
88
108
 
89
- [arg.join, next_index]
109
+ [token[offset..], index, token.length]
90
110
  end
91
111
  end
92
112
  end
data/lib/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Trees
4
- VERSION = '0.2.0'
4
+ VERSION = '0.3.0'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: trees
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - maedi