structurematch 0.1.0 → 0.1.1

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 (3) hide show
  1. checksums.yaml +4 -4
  2. data/lib/structurematch.rb +69 -26
  3. metadata +1 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c071ed38259f2735cad5b428fe364fa186e58ffb
4
- data.tar.gz: 569278eab25de5512e30d557a409830e4544568b
3
+ metadata.gz: 99e88855ccc4edb6ae03e0f7b6679d1cf40e253b
4
+ data.tar.gz: d1cb943a7475bc63a326f6d1d7d4402bffbb0185
5
5
  SHA512:
6
- metadata.gz: 210676dc6826c5bc18356469db5931ab733562829d5a64c4e1d61c76eb787d0a625cb6e83eda394c8813e5d73bdce6fd6518779d1f94810789d4d52dd5b590a8
7
- data.tar.gz: a29709b8af3237fd1a013a97ac32c71d40178d29580ebd748c85b36f5e1cf78dc57b86f7bba93cc878581be490329389c469fb8a80a7c06e4188bd3655ca8749
6
+ metadata.gz: 767925436ade0b040cdf96559a95db0e9b8eea1dda4077d7ebd8f9c8d12c4fc95cf2eeee9fd67a1b2b9408a1680bdb21ab95e5a30c7f106058d87aebd0fa63c2
7
+ data.tar.gz: 4d67cb27f30897e3997b8ed8658f7f38b3722301b04aaf601d6bea6fe6e910013c144741a88905ee26a7aa441b10829f3be4e78280c1ca934e824f631f5c3f4d
@@ -8,24 +8,31 @@
8
8
  class StructureMatch
9
9
 
10
10
  # Comparator handles the actual comparison operations that StructureMatch uses.
11
- # Comparators are initialized using a hash with the following structure:
12
- #
13
- # {
14
- # "op" => "operation"
15
- # "match" => "The value that the operation should work with"
16
- # }
17
- #
18
- # Comparator knows about the following tests:
19
- # "==","!=",">","<",">=","<=" --> The matching tests from Comparable.
20
- # "and" --> Returns true if all the submatches return true, false otherwise.
21
- # "or" --> Returns true if one of the submatches trturn true, false otherwise.
22
- # "and" and "or" require that "match" be an array of hashes that Comparator.new can process.
23
- # "not" --> Inverts its submatch. Requires that "match" be a hash that Comparator.new can process.
24
- # "range" --> Tests to see if a value is within a range of values.
25
- # Requires that "match" be a two-element array whose elements can be used to construct a Range.
26
- # "regex" --> Tests to see if a value matches a regular expression. "match" must be a regex.
27
- # "member" --> Tests to see if a value is within an array. "match" must be the array.
28
11
  class Comparator
12
+ # Comparators are initialized using a hash with the following structure:
13
+ #
14
+ # {
15
+ # "op" => "operation"
16
+ # "match" => "The value that the operation should work with"
17
+ # # Optional, defaults to 1 or the length of the matched thing (if array-ish)
18
+ # "score" => 1 # The score adjustment a match here gives.
19
+ # }
20
+ #
21
+ # Comparator knows about the following tests:
22
+ #
23
+ # "==","!=",">","<",">=","<=":: The matching tests from Comparable.
24
+ # "and":: Returns true if all the submatches return true, false otherwise.
25
+ # "or":: Returns true if one of the submatches return true, false otherwise.
26
+ # "and" and "or" require that "match" be an array of hashes that Comparator.new can process.
27
+ # "not":: Inverts its submatch. Requires that "match" be a hash that Comparator.new can process.
28
+ # "range":: Tests to see if a value is within a range of values.
29
+ # Requires that "match" be a two-element array whose elements can be used to construct a Range.
30
+ # "regex":: Tests to see if a value matches a regular expression. "match" must be a regex.
31
+ # The score on a matching regex will be the length of the MatchData by default, and the returned
32
+ # value will be matching MatchData.
33
+ # "member":: Tests to see if a value is within an array. "match" must be the array.
34
+ # If an array is passed to a member test, then scoring and the returned value will be the
35
+ # set intersection of the match array and the tested array.
29
36
  def initialize(op)
30
37
  raise "#{op.inspect} must be a Hash" unless op.kind_of?(Hash)
31
38
  unless ["==","!=",">","<",">=","<=","and","or","not","range","regex","member"].member?(op["op"])
@@ -34,6 +41,8 @@ class StructureMatch
34
41
  raise "#{op.inspect} must have a match key" unless op.has_key?("match")
35
42
  @op = op["op"].dup.freeze
36
43
  @match = op["match"]
44
+ @score = op["score"].to_i
45
+ @score = nil if @score == 0
37
46
  case @op
38
47
  when "and","or"
39
48
  raise "#{op.inspect} match key must be an array of submatches" unless @match.kind_of?(Array)
@@ -47,13 +56,14 @@ class StructureMatch
47
56
  end
48
57
  end
49
58
 
50
- # test tests to see if v matches @match.
59
+ # Takes a single argument which is the value to be tested.
60
+ #
51
61
  # It returns a two-element array:
52
62
  # [score,val]
53
- # score is the score adjustment factor for this test
54
- # val is the value that test returns. It is usually the value that was passed in,
55
- # except for regular expressions (which return the MatchData) and array & array
56
- # comparisons performed by member (which returns the set intersection of the arrays)
63
+ # score:: the score adjustment factor for this test
64
+ # val:: the value that test returns. It is usually the value that was passed in,
65
+ # except for regular expressions (which return the MatchData) and array & array
66
+ # comparisons performed by member (which returns the set intersection of the arrays)
57
67
  def test(v=true)
58
68
  case @op
59
69
  when "and" then [_t(@match.all?{|m|m.test(v)[0]}),v]
@@ -62,11 +72,11 @@ class StructureMatch
62
72
  when "range" then [_t(@match === v),v]
63
73
  when "regex"
64
74
  r = @match.match(v)
65
- [r.nil? ? -1 : r.length, r]
75
+ [r.nil? ? -1 : @score || r.length, r]
66
76
  when "member"
67
77
  if v.kind_of?(Array)
68
78
  r = @match & v
69
- [r.empty? ? -1 : r.length, r]
79
+ [r.empty? ? -1 : @score || r.length, r]
70
80
  else
71
81
  [_t(@match.member?(v)),v]
72
82
  end
@@ -83,10 +93,37 @@ class StructureMatch
83
93
 
84
94
  private
85
95
  def _t(v)
86
- v ? 1 : -1
96
+ v ? @score || 1 : -1
87
97
  end
88
98
  end
89
99
 
100
+ # StructureMatchers are initialized by passing in an example nested hash that maps out what
101
+ # StructureMatch should dig through, bind matching values, and how to score the matches it found.
102
+ # As an example:
103
+ # StructureMatch.new("foo" => "bar",
104
+ # "numbermatch" => 5,
105
+ # "regexmatch" => {
106
+ # "__sm_leaf" => true,
107
+ # "op"=> "regex",
108
+ # "match" => "foo(bar)"},
109
+ # "ormatch" => {
110
+ # "__sm_leaf" => true,
111
+ # "op" => "or",
112
+ # "match" => [
113
+ # {
114
+ # "op" => ">",
115
+ # "match" => 7
116
+ # },
117
+ # {
118
+ # "op" => "<",
119
+ # "match" => 10}]})
120
+ # will create a matcher that perfectly matches the following JSON:
121
+ # { "foo": "bar",
122
+ # "numbermatch": 5,
123
+ # "regexmatch": "foobar",
124
+ # "ormatch": 8
125
+ # }
126
+ # This match will be assigned a score of 5.
90
127
  def initialize(matcher)
91
128
  raise "#{matcher.inspect} must be a Hash" unless matcher.kind_of?(Hash)
92
129
  @matchers = Hash.new
@@ -108,6 +145,12 @@ class StructureMatch
108
145
  end
109
146
  end
110
147
 
148
+ # Takes a (possibly nested) hash that is a result of parsing JSON and matches what it can,
149
+ # assigning a score in the process.
150
+ #
151
+ # Returns a two-entry array in the form of [binds,score]:
152
+ # binds:: The nested hash corresponding to the matched values from val.
153
+ # score:: The score assigned to this match.
111
154
  def bind(val)
112
155
  raise "Must pass a Hash to StructureMatch.bind" unless val.kind_of?(Hash)
113
156
  score = 0
@@ -131,7 +174,7 @@ class StructureMatch
131
174
  [binds,score]
132
175
  end
133
176
 
134
-
177
+ # Runs bind on val and returns just the score component.
135
178
  def score(val)
136
179
  bind(val)[1]
137
180
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: structurematch
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Victor Lowther