filter_matcher 0.0.1 → 0.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.
data/README.md CHANGED
@@ -36,43 +36,63 @@ First we need to specify how we want to filter our data to find the best match.
36
36
 
37
37
  Lets say the most important is the name. If name filter finds a single result then this is a match. We can define the filter like:
38
38
 
39
- def name_filter(collection, name)
40
- collection.select { |element| element[:name] == name }
39
+ m.filter do |col|
40
+ col.select { |element| element[:name] == name }
41
41
  end
42
42
 
43
- The filter has to be named in the convention: <what_it_filters>_filter
44
-
45
43
  If this is not sufficient we run another filter on the result of the previous one. Lets define another filter, saying that the second most important thing to find a match is age.
46
44
 
47
- def age_filter(collection, age)
48
- collection.select { |element| element[:age] == age}
45
+ m.filter do |col|
46
+ col.select { |element| element[:age] == age}
49
47
  end
50
48
 
51
49
  Simple and very similar to the previous one. Filters can have any logic you need. Lets define the last one - homepage filter.
52
50
 
53
- def homepage_filter(collection, homepage)
54
- collection.select { |element| element[:homepage] == homepage }
51
+ m.filter do |col|
52
+ col.select { |element| element[:homepage] == homepage }
55
53
  end
56
54
 
57
- Now, in order to run them all on the collection, we run the filter_and_match method:
55
+ Now, in order to run them all on the collection, we run the matcher method:
58
56
 
59
57
  @input.each do |input|
60
58
  collection = @db
61
59
 
62
- filter_and_match collection, {
63
- :by_name => input[:name],
64
- :by_age => input[:age],
65
- :by_homepage => input[:homepage]
66
- }
60
+ matcher(collection) do |m|
61
+ m.filter do |col|
62
+ col.select { |element| element[:name] == input[:name] }
63
+ end
64
+
65
+ m.filter do |col|
66
+ col.select { |element| element[:age] == input[:age]}
67
+ end
68
+
69
+ m.filter do |col|
70
+ col.select { |element| element[:homepage] == input[:homepage] }
71
+ end
72
+
73
+ m.match do |element|
74
+ element[:matched] = true
75
+ end
76
+ end
67
77
  end
68
78
 
69
79
  If any filter returns an empty result then next filter is given the collection of the last not empty result or the original data itself.
80
+ If a single result will be found the match block will be triggered. In this example we just change the entry's flag:
81
+
82
+ m.match do |element|
83
+ element[:matched] = true
84
+ end
70
85
 
71
- If a single result will be found the elemnt_matched method will be triggered. In this example we just change the entry's flag:
86
+ The expected result is the db matched like:
72
87
 
73
- def element_matched(element)
74
- element[:matched] = true
75
- end
88
+ db == [
89
+ {:id => 1, :name => "John", :age => 33, :homepage => "www.johny.com", :matched => false}
90
+ {:id => 2, :name => "Mike", :age => 30, :homepage => "www.mikes.com", :matched => false}
91
+ {:id => 3, :name => "Johny", :age => 25, :homepage => "www.johny.com", :matched => false}
92
+ {:id => 4, :name => "Mike", :age => 30, :homepage => "www.realmike.com", :matched => true}
93
+ {:id => 5, :name => "Dan", :age => 25, :homepage => "www.danny.com", :matched => true}
94
+ {:id => 6, :name => "Dan", :age => 40, :homepage => "www.fakedanny.com", :matched => false}
95
+ ]
76
96
 
77
97
  Full PeopleMatcher class example, that is responsible only for the matching is shown below:
78
98
 
@@ -85,38 +105,60 @@ Full PeopleMatcher class example, that is responsible only for the matching is s
85
105
  @db, @input = db, input
86
106
  end
87
107
 
108
+ #
109
+ # run filters on all data for every input element
110
+ #
88
111
  def match
89
112
  @input.each do |input|
90
113
  collection = @db
91
114
 
92
- filter_and_match collection, {
93
- :by_name => input[:name],
94
- :by_age => input[:age],
95
- :by_homepage => input[:homepage]
96
- }
115
+ matcher(collection) do |m|
116
+ m.filter do |col|
117
+ col.select { |element| element[:name] == input[:name] }
118
+ end
119
+
120
+ m.filter do |col|
121
+ col.select { |element| element[:age] == input[:age]}
122
+ end
123
+
124
+ m.filter do |col|
125
+ col.select { |element| element[:homepage] == input[:homepage] }
126
+ end
127
+
128
+ m.match do |element|
129
+ element[:matched] = true
130
+ end
131
+ end
97
132
  end
98
133
  end
134
+ end
99
135
 
100
- private
136
+ Visual example
137
+ ==
138
+ Filtering a collection
101
139
 
102
- def name_filter(collection, name)
103
- collection.select { |element| element[:name] == name }
104
- end
140
+ [1,2,3] --first_filter--> [2,3] ---second_filter--> [2] -> match
105
141
 
106
- def age_filter(collection, age)
107
- collection.select { |element| element[:age] == age}
108
- end
142
+ [1,2,3] --first_filter--> [] --> [1,2,3] --second_filter--> [3] -> match
109
143
 
110
- def homepage_filter(collection, homepage)
111
- collection.select { |element| element[:homepage] == homepage }
112
- end
144
+ [1,2,3] --first_filter--> [1,2] --second_filter--> [1,2] --third_filter--> [1] -> match
113
145
 
114
- def element_matched(element)
115
- element[:matched] = true
116
- end
117
- end
146
+ [1,2,3] --first_filter--> [] --> [1,2,3] --second_filter--> [] --> [1,2,3] --third_filter--> [] -> no match
147
+
148
+ [1,2,3] --first_filter--> [1,2,3] --second_filter--> [2,3] --third_filter--> [2,3] -> no match
149
+
150
+ Filtering real data by SQL or JS
151
+ ==
152
+
153
+ Remeber that often you can filter your data much more efficient with DB languages. This filtering method should be used when the filtering logic is highly application-dependent. Good SQL query (or smart map reduce) before application filter-matching is always a better approach.
118
154
 
119
155
  Feel free to contribute or give any feedback
120
156
  ==
121
157
 
122
158
  Did you find it usefull any how? Please let me know, and if you can want to improve it just send me a pull request.
159
+
160
+ Contributors
161
+ ==
162
+
163
+ [Albert Llop](https://github.com/mrsimo)
164
+ [Sebastian Röbke](https://github.com/boosty)
@@ -1,23 +1,35 @@
1
1
  module FilterMatcher
2
+ class Filterer
3
+ def initialize(collection)
4
+ @collection = collection
5
+ @filters = []
6
+ end
7
+
8
+ def filter(&block)
9
+ @filters << block
10
+ end
11
+
12
+ def match(&block)
13
+ @match = block
14
+ end
2
15
 
3
- #
4
- # define filter in a class that uses this module
5
- # named like:
6
- # - name_filter
7
- # - age_filter
8
- #
9
- # they should a filtered array
10
- #
16
+ def process
17
+ @filters.each do |filter|
18
+ filtered = filter.call(@collection)
19
+ @collection = filtered.empty? ? @collection : filtered
11
20
 
12
- def filter_and_match(collection, filters)
13
- filters.each do |key, param|
14
- method_name = key.to_s.tr('by_', '') + "_filter"
15
- filtered = send(method_name.to_sym, collection, param)
16
- collection = filtered.empty? ? collection : filtered
17
- if collection.size == 1
18
- element_matched(collection.first)
19
- break
21
+ if @collection.size == 1
22
+ @match.call(@collection.first)
23
+ break
24
+ end
20
25
  end
21
26
  end
22
27
  end
28
+
29
+ def matcher(collection)
30
+ filterer = Filterer.new(collection)
31
+ yield filterer
32
+
33
+ filterer.process
34
+ end
23
35
  end
@@ -1,3 +1,3 @@
1
1
  module FilterMatcher
2
- VERSION = "0.0.1"
2
+ VERSION = "0.1.0"
3
3
  end
@@ -0,0 +1,49 @@
1
+ #
2
+ # example class that uses filter matcher module
3
+ #
4
+ # @db:
5
+ # represents data from which machter tries to filter
6
+ # a single result
7
+ #
8
+ # @input:
9
+ # criteria for maching
10
+ #
11
+
12
+ require 'filter_matcher'
13
+
14
+ class PeopleMatcher
15
+ include FilterMatcher
16
+
17
+ attr_reader :db
18
+
19
+ def initialize(db, input)
20
+ @db, @input = db, input
21
+ end
22
+
23
+ #
24
+ # run filters on all data for every input element
25
+ #
26
+ def match
27
+ @input.each do |input|
28
+ collection = @db
29
+
30
+ matcher(collection) do |m|
31
+ m.filter do |col|
32
+ col.select { |element| element[:name] == input[:name] }
33
+ end
34
+
35
+ m.filter do |col|
36
+ col.select { |element| element[:age] == input[:age]}
37
+ end
38
+
39
+ m.filter do |col|
40
+ col.select { |element| element[:homepage] == input[:homepage] }
41
+ end
42
+
43
+ m.match do |element|
44
+ element[:matched] = true
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -1,6 +1,6 @@
1
1
  require 'bundler/setup'
2
2
  require 'test/unit'
3
- require 'filter_matcher/people_matcher'
3
+ require File.expand_path(File.dirname(__FILE__) + '/people_matcher')
4
4
 
5
5
  class PeopleMatcherTest < Test::Unit::TestCase
6
6
  def setup
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: filter_matcher
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.0.1
5
+ version: 0.1.0
6
6
  platform: ruby
7
7
  authors:
8
8
  - Jakub Godawa
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2011-07-16 00:00:00 +02:00
13
+ date: 2011-07-19 00:00:00 +02:00
14
14
  default_executable:
15
15
  dependencies: []
16
16
 
@@ -35,8 +35,8 @@ files:
35
35
  - filter_matcher.gemspec
36
36
  - lib/filter_matcher.rb
37
37
  - lib/filter_matcher/filter_matcher.rb
38
- - lib/filter_matcher/people_matcher.rb
39
38
  - lib/filter_matcher/version.rb
39
+ - test/people_matcher.rb
40
40
  - test/people_matcher_test.rb
41
41
  has_rdoc: true
42
42
  homepage: http://github.com/vysogot/filter_matcher
@@ -67,4 +67,5 @@ signing_key:
67
67
  specification_version: 3
68
68
  summary: FilterMatcher makes it easy to find a match in a collection
69
69
  test_files:
70
+ - test/people_matcher.rb
70
71
  - test/people_matcher_test.rb
@@ -1,71 +0,0 @@
1
- #
2
- # example class that uses filter matcher module
3
- #
4
- # @db:
5
- # represents data from which machter tries to filter
6
- # a single result
7
- #
8
- # @input:
9
- # criteria for maching
10
- #
11
-
12
- require 'filter_matcher'
13
-
14
- class PeopleMatcher
15
- include FilterMatcher
16
-
17
- attr_reader :db
18
-
19
- def initialize(db, input)
20
- @db, @input = db, input
21
- end
22
-
23
- #
24
- # run filters on all data for every input element
25
- #
26
- def match
27
- @input.each do |input|
28
- collection = @db
29
-
30
- #
31
- # filters are run sequentially until they find
32
- # a single result
33
- #
34
- # they are called by the following convention:
35
- # :by_<what_it_filters => paramters of <what_it_filters>_filter method
36
- #
37
- # when one of the filters reveal a single result
38
- # next filters are not run for current input
39
- #
40
- filter_and_match collection, {
41
- :by_name => input[:name],
42
- :by_age => input[:age],
43
- :by_homepage => input[:homepage]
44
- }
45
- end
46
- end
47
-
48
- private
49
-
50
- #
51
- # filters are named by the following convention:
52
- # <what_it_filters>_filter
53
- #
54
- # every filter should return a filtered result
55
- #
56
- def name_filter(collection, name)
57
- collection.select { |element| element[:name] == name }
58
- end
59
-
60
- def age_filter(collection, age)
61
- collection.select { |element| element[:age] == age}
62
- end
63
-
64
- def homepage_filter(collection, homepage)
65
- collection.select { |element| element[:homepage] == homepage }
66
- end
67
-
68
- def element_matched(element)
69
- element[:matched] = true
70
- end
71
- end