trie_matcher 1.0.0 → 1.1.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
  SHA1:
3
- metadata.gz: 4825d60fa8f9fc8493b6ba2d420306ba24a157c5
4
- data.tar.gz: 31cf3a39e649f988e711bbff24dc3af0318b9f45
3
+ metadata.gz: 5315d69c65616a5d7ff6d608f1bdeb6584ac1907
4
+ data.tar.gz: 97ee1b5ec00f18bd74d1c8773c593a6a02e8ce56
5
5
  SHA512:
6
- metadata.gz: d0f0695f7791ab6c9d7e814ddc38119a9d13eb9786b8c51a93ec4f59807f709117c638f163c9d161a0aa86b6dcdffd47396b908b0e068348e9cd869bfbfc4850
7
- data.tar.gz: 2311159b3187eae2a82650641a510f7830a21f2756b886a1971c754d1c4423fb7ca43bc808193dbc2e2409fcfc84bdb7a45fd7e564c4901c0bb9f443b0cebb06
6
+ metadata.gz: f7f960eb2dc46fab205c154ab44fb1159b2a70c4d0a434dd34e4af3de12529dc58b3165525d06f5fe5eaf639fcade2e95c183fb26d92f890414f4d6e23ca3a28
7
+ data.tar.gz: 46b3096cce0312b9b2ca9c76f1054278b042f3d3338cf16dcefa02e44ae79e2b2b5da3436f77a4c846017736a9de9037495e2a90a6e29eb471eda2e2c8851aef
@@ -0,0 +1,37 @@
1
+ require File.expand_path("../trie_matcher", __dir__)
2
+
3
+ # Convenience class for matching specific patterns, accelerated by a static prefix.
4
+ #
5
+ # This is extremely useful for matching complex patterns such as user agents or url routes
6
+ class TrieMatcher::PatternMatcher
7
+ # Build an empty pattern matcher
8
+ def initialize
9
+ @trie = TrieMatcher.new
10
+ end
11
+
12
+ # Register a pattern, along with a static prefix
13
+ #
14
+ # @param prefix [String] a static prefix that indicates this pattern should be tested
15
+ # @param pattern [Regexp] a pattern to test against
16
+ # @yield [match] executed if a positive match is made
17
+ # @yieldparam match [MatchData] the match data from the pattern
18
+ def add_pattern(prefix, pattern, &block)
19
+ @trie[prefix] ||= {}
20
+ @trie[prefix][pattern] = block
21
+ end
22
+
23
+ # Match a string against all registered patterns efficiently.
24
+ #
25
+ # Calls the block registered against any matching pattern, and passes in the match data
26
+ #
27
+ # @param string [String] the string to match against
28
+ def match(string)
29
+ result = @trie[string]
30
+ return nil unless result
31
+ result.each do |pattern, block|
32
+ match = pattern.match(string)
33
+ block.call(match) if match
34
+ end
35
+ end
36
+
37
+ end
@@ -1,3 +1,3 @@
1
1
  class TrieMatcher
2
- VERSION = "1.0.0"
2
+ VERSION = "1.1.0"
3
3
  end
data/lib/trie_matcher.rb CHANGED
@@ -1,30 +1,43 @@
1
1
  require File.expand_path("trie_matcher/version", __dir__)
2
2
 
3
+ # Trie implementation that acts as a weak mapping
4
+ #
5
+ # Values can be stored for a given prefix, and are returned for the longest prefix.
6
+ # Lookup searches for longer prefixes optimistically, so saturated tries with many lexemes in them will be less efficient
3
7
  class TrieMatcher
8
+ # Build an empty trie
4
9
  def initialize
5
10
  @root = { nodes: {}, value: nil}
6
11
  end
7
12
 
8
- def []=(key, value)
13
+ # Store a prefix in the trie, and associate a value with it
14
+ #
15
+ # @param prefix [String]
16
+ # @param value [Object] a value to return if prefix is the longest prefix on lookup
17
+ # @return [Object] the value that was set
18
+ def []=(prefix, value)
9
19
  current = @root
10
- current_key = key
20
+ current_prefix = prefix
11
21
 
12
- while current_key != ""
13
- current, current_key = find_canididate_insertion_node(current, current_key)
22
+ while current_prefix != ""
23
+ current, current_prefix = find_canididate_insertion_node(current, current_prefix)
14
24
  end
15
25
 
16
26
  current[:value] = value
17
27
  return value
18
28
  end
19
29
 
20
-
21
- def [](key)
30
+ # Perform a prefix search. Will return the value associated with the longest prefix
31
+ #
32
+ # @param prefix [String] what to check for a prefix in
33
+ # @return [Object] the value associated with the longest matching prefix in this trie
34
+ def [](prefix)
22
35
  current = @root
23
- current_key = key
36
+ current_prefix = prefix
24
37
 
25
- while current != nil && current_key != ""
38
+ while current != nil && current_prefix != ""
26
39
  previous = current
27
- current, current_key = next_node(current, current_key)
40
+ current, current_prefix = next_node(current, current_prefix)
28
41
  end
29
42
 
30
43
  return current[:value] if current
@@ -32,6 +45,7 @@ class TrieMatcher
32
45
  end
33
46
 
34
47
  private
48
+ # get the node for insertion, splitting shared prefixes into subnodes if necessary
35
49
  def find_canididate_insertion_node(current, key)
36
50
  # look for a common prefix
37
51
  current[:nodes].keys.find do |prefix|
@@ -60,4 +60,11 @@ describe TrieMatcher do
60
60
  expect(t["cats"]).to be 1
61
61
  end
62
62
 
63
+ it 'should return the more specific prefix value' do
64
+ t = TrieMatcher.new
65
+ t["cat"] = 1
66
+ t["catch"] = 2
67
+ expect(t["catcher"]).to be 2
68
+ end
69
+
63
70
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: trie_matcher
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Steven Karas
@@ -67,6 +67,7 @@ files:
67
67
  - README.md
68
68
  - Rakefile
69
69
  - lib/trie_matcher.rb
70
+ - lib/trie_matcher/pattern_matcher.rb
70
71
  - lib/trie_matcher/version.rb
71
72
  - spec/spec_helper.rb
72
73
  - spec/trie_matcher_spec.rb