philter 1.0.0 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -0
- data/README.md +49 -36
- data/lib/philter.rb +19 -5
- data/lib/philter/array.rb +52 -0
- data/lib/philter/base.rb +28 -0
- data/lib/philter/evaluation.rb +115 -0
- data/lib/philter/search.rb +106 -0
- data/lib/version.rb +1 -1
- metadata +6 -4
- data/lib/array.rb +0 -40
- data/lib/base.rb +0 -191
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 872214969624e598ec099b000b4ada64ac9837f3
|
4
|
+
data.tar.gz: ba1d3f800772f91b3a8d8b08b06d87a68229d517
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dc93c8a4a407b0227b0e6795dcd060d01855b83a6f4b8896a1ca2957ae480288eeabecd0d71f8f3f5e254b9cc4cb86fb2a287417856784a899ab6c24ed168a6a
|
7
|
+
data.tar.gz: 64bc6efbc153e5e41ad99e0eb493046a1f9be0dcd859aa522f11ab423da36877058c2203de70034b42a291300cff791887a3dc5ccff4b1c0d54141c179cf8095
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
v1.1.0 [☰](https://github.com/marcomd/Philter/compare/v1.0.0...v1.1.0) May 26th, 2016
|
2
|
+
------------------------------
|
3
|
+
* Added debug mode to unit tests
|
4
|
+
* Changed files organization
|
5
|
+
* Improved code readibility
|
6
|
+
* Improved documentation
|
7
|
+
|
1
8
|
v1.0.0 [☰](https://github.com/marcomd/Philter/compare/v0.8.0...v1.0.0) May 25th, 2016
|
2
9
|
------------------------------
|
3
10
|
* Code revolution: more simple, secure and readable
|
data/README.md
CHANGED
@@ -64,32 +64,32 @@ require 'philter'
|
|
64
64
|
# Regular expression
|
65
65
|
[
|
66
66
|
{id: 1, name: 'Mark', email: 'mark@gmail.com' },
|
67
|
-
{id: 2, name: 'Larry', email: 'larry@gmail.com'
|
68
|
-
{id: 3, name: 'Bill', email: 'bill@live.com'
|
67
|
+
{id: 2, name: 'Larry', email: 'larry@gmail.com' },
|
68
|
+
{id: 3, name: 'Bill', email: 'bill@live.com' }
|
69
69
|
].philter email: /@gmail/
|
70
70
|
=> [{:id=>1, :name=>"Mark", :email=>"mark@gmail.com"}, {:id=>2, :name=>"Larry",:email=>"larry@gmail.com"}]
|
71
71
|
|
72
72
|
# Select attributes
|
73
73
|
[
|
74
74
|
{id: 1, name: 'Mark', email: 'mark@gmail.com' },
|
75
|
-
{id: 2, name: 'Larry', email: 'larry@gmail.com'
|
76
|
-
{id: 3, name: 'Bill', email: 'bill@live.com'
|
75
|
+
{id: 2, name: 'Larry', email: 'larry@gmail.com' },
|
76
|
+
{id: 3, name: 'Bill', email: 'bill@live.com' }
|
77
77
|
].philter({email: /@gmail/}, get: :name)
|
78
78
|
=> ["Mark", "Larry"]
|
79
79
|
|
80
|
-
# Philter with more attributes
|
80
|
+
# Philter with more attributes -and-
|
81
81
|
[
|
82
82
|
{id: 1, name: 'Mark', email: 'mark@gmail.com' },
|
83
|
-
{id: 2, name: 'Larry', email: 'larry@gmail.com'
|
84
|
-
{id: 3, name: 'Bill', email: 'bill@live.com'
|
83
|
+
{id: 2, name: 'Larry', email: 'larry@gmail.com' },
|
84
|
+
{id: 3, name: 'Bill', email: 'bill@live.com' }
|
85
85
|
].philter name: /M.+/, email: /@gmail/
|
86
86
|
=> [{:id=>1, :name=>"Mark", :email=>"mark@gmail.com"}]
|
87
87
|
|
88
|
-
# Philter with
|
88
|
+
# Philter with more attributes -or-
|
89
89
|
[
|
90
90
|
{id: 1, name: 'Mark', email: 'mark@gmail.com' },
|
91
|
-
{id: 2, name: 'Larry', email: 'larry@gmail.com'
|
92
|
-
{id: 3, name: 'Bill', email: 'bill@live.com'
|
91
|
+
{id: 2, name: 'Larry', email: 'larry@gmail.com' },
|
92
|
+
{id: 3, name: 'Bill', email: 'bill@live.com' }
|
93
93
|
].philter({name: /M.+/, email: /@live/}, or: true)
|
94
94
|
=> [{:id=>1, :name=>"Mark", :email=>"mark@gmail.com"}, {:id=>3, :name=>"Bill", :email=>"bill@live.com"}]
|
95
95
|
|
@@ -97,16 +97,16 @@ require 'philter'
|
|
97
97
|
# Select and update attributes
|
98
98
|
[
|
99
99
|
{id: 1, name: 'Mark', email: 'mark@gmail.com' },
|
100
|
-
{id: 2, name: 'Larry', email: 'larry@gmail.com'
|
101
|
-
{id: 3, name: 'Bill', email: 'bill@live.com'
|
100
|
+
{id: 2, name: 'Larry', email: 'larry@gmail.com' },
|
101
|
+
{id: 3, name: 'Bill', email: 'bill@live.com' }
|
102
102
|
].philter({email: /@gmail/}){|e| e[:name] << ' use gmail!'}
|
103
103
|
=> ["Mark use gmail!", "Larry use gmail!"]
|
104
104
|
|
105
105
|
# Add attributes
|
106
106
|
[
|
107
107
|
{id: 1, name: 'Mark', email: 'mark@gmail.com' },
|
108
|
-
{id: 2, name: 'Larry', email: 'larry@gmail.com'
|
109
|
-
{id: 3, name: 'Bill', email: 'bill@live.com'
|
108
|
+
{id: 2, name: 'Larry', email: 'larry@gmail.com' },
|
109
|
+
{id: 3, name: 'Bill', email: 'bill@live.com' }
|
110
110
|
].philter({email: /@gmail/}){|e| e[:surname] = 'unknown';e }
|
111
111
|
=> :try_yourself
|
112
112
|
```
|
@@ -114,27 +114,40 @@ require 'philter'
|
|
114
114
|
Get the trace with the option `debug: true`
|
115
115
|
|
116
116
|
```ruby
|
117
|
-
[
|
118
|
-
{id:
|
119
|
-
{id:
|
120
|
-
{
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
117
|
+
[{id: 1, name: 'Mark', email: 'mark@gmail.com'},
|
118
|
+
{id: 2, name: 'Bill', email: 'bill@live.com'},
|
119
|
+
{id: 3, name: 'Larry', email: 'larry@gmail.com'}
|
120
|
+
].philter({name: 'Mark', email: /\A.+gmail/}, debug: true)
|
121
|
+
|
122
|
+
--------------- Start debugging philter 1.1.0 ---------------
|
123
|
+
Search by Hash:
|
124
|
+
|
125
|
+
item {:id=>1, :name=>"Mark", :email=>"mark@gmail.com"} (Hash)
|
126
|
+
evaluating with hash
|
127
|
+
search: name: Mark (String)
|
128
|
+
.4 v1 item[name] item == value | Mark == Mark => x
|
129
|
+
search: email: (?-mix:\A.+gmail) (Regexp)
|
130
|
+
.1 v1 item[email] item =~ value | mark@gmail.com =~ (?-mix:\A.+gmail) => x
|
131
|
+
|
132
|
+
- SELECTED - (And)
|
133
|
+
|
134
|
+
item {:id=>2, :name=>"Bill", :email=>"bill@live.com"} (Hash)
|
135
|
+
evaluating with hash
|
136
|
+
search: name: Mark (String)
|
137
|
+
.4 v1 item[name] item == value | Bill == Mark
|
138
|
+
search: email: (?-mix:\A.+gmail) (Regexp)
|
139
|
+
.1 v1 item[email] item =~ value | bill@live.com =~ (?-mix:\A.+gmail)
|
140
|
+
|
141
|
+
item {:id=>3, :name=>"Larry", :email=>"larry@gmail.com"} (Hash)
|
142
|
+
evaluating with hash
|
143
|
+
search: name: Mark (String)
|
144
|
+
.4 v1 item[name] item == value | Larry == Mark
|
145
|
+
search: email: (?-mix:\A.+gmail) (Regexp)
|
146
|
+
.1 v1 item[email] item =~ value | larry@gmail.com =~ (?-mix:\A.+gmail) => x
|
147
|
+
|
148
|
+
--------------- End debugging philter 1.1.0 ---------------
|
149
|
+
1 item(s) found
|
150
|
+
=> [{:id=>1, :name=>"Mark", :email=>"mark@gmail.com"}]
|
138
151
|
```
|
139
152
|
|
140
153
|
### Rails
|
@@ -223,7 +236,7 @@ select: 0.078000 0.000000 0.078000 ( 0.073341)
|
|
223
236
|
|
224
237
|
```ruby
|
225
238
|
Benchmark.bmbm do |x|
|
226
|
-
x.report("philter: ") { 1_000.times { ar_test.philter '< 50'
|
239
|
+
x.report("philter: ") { 1_000.times { ar_test.philter '< 50' } }
|
227
240
|
x.report("select: ") { 1_000.times { ar_test.select {|item| item < 50} } }
|
228
241
|
end
|
229
242
|
|
data/lib/philter.rb
CHANGED
@@ -1,6 +1,20 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
# Philter
|
2
|
+
# Copyright (C) 2016 Marco Mastrodonato, m.mastrodonato@gmail.com
|
3
|
+
#
|
4
|
+
# This program is free software: you can redistribute it and/or modify
|
5
|
+
# it under the terms of the GNU General Public License as published by
|
6
|
+
# the Free Software Foundation, either version 3 of the License.
|
7
|
+
#
|
8
|
+
# This program is distributed in the hope that it will be useful,
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
11
|
+
# GNU General Public License for more details.
|
12
|
+
#
|
13
|
+
# You should have received a copy of the GNU General Public License
|
14
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
4
15
|
|
5
|
-
|
6
|
-
|
16
|
+
require_relative 'version'
|
17
|
+
require_relative 'philter/base'
|
18
|
+
require_relative 'philter/search'
|
19
|
+
require_relative 'philter/evaluation'
|
20
|
+
require_relative 'philter/array'
|
@@ -0,0 +1,52 @@
|
|
1
|
+
###################################
|
2
|
+
# Philter with passion
|
3
|
+
###################################
|
4
|
+
class Array
|
5
|
+
include Philter::Base
|
6
|
+
include Philter::Search
|
7
|
+
include Philter::Evaluation
|
8
|
+
|
9
|
+
# Have yourself indulging in the pleasure of philtering
|
10
|
+
def philter(search = nil, options = {}, &block)
|
11
|
+
options = { get: nil,
|
12
|
+
debug: false }.merge(options)
|
13
|
+
unless search
|
14
|
+
puts philter_help if options[:debug]
|
15
|
+
raise 'Specify search parameter!'
|
16
|
+
end
|
17
|
+
puts if options[:debug]
|
18
|
+
puts "#{'-' * 15} Start debugging philter #{Philter.version} #{'-' * 15}" if options[:debug]
|
19
|
+
items = self
|
20
|
+
apply_block = true
|
21
|
+
results =
|
22
|
+
case search.class.name
|
23
|
+
when 'Hash'
|
24
|
+
print ' Search by Hash:' if options[:debug]
|
25
|
+
phil_search_by_attributes(items, search, options)
|
26
|
+
when 'String'
|
27
|
+
print ' Search by String:' if options[:debug]
|
28
|
+
operator = phil_get_operator(search)
|
29
|
+
if operator
|
30
|
+
phil_search_with_operator(items, search, options)
|
31
|
+
else
|
32
|
+
puts " #{search} with grep" if options[:debug]
|
33
|
+
items.grep(search)
|
34
|
+
end
|
35
|
+
when 'Array'
|
36
|
+
print ' Search by Array:' if options[:debug]
|
37
|
+
phil_search_by_array(items, search, options)
|
38
|
+
else
|
39
|
+
puts " Search with grep: #{search}" if options[:debug]
|
40
|
+
apply_block = false
|
41
|
+
items.grep(search, &block)
|
42
|
+
end
|
43
|
+
|
44
|
+
puts "#{'-' * 15} End debugging philter #{Philter.version} #{'-' * 15}" if options[:debug]
|
45
|
+
puts " #{results.size} item(s) found" if options[:debug]
|
46
|
+
if block_given? && apply_block
|
47
|
+
results.map { |item| yield(item) }
|
48
|
+
else
|
49
|
+
results
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
data/lib/philter/base.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# Philter methods
|
2
|
+
module Philter
|
3
|
+
# It contains generic methods
|
4
|
+
module Base
|
5
|
+
private
|
6
|
+
|
7
|
+
# Show tips on usage
|
8
|
+
def philter_help
|
9
|
+
<<-HELP.gsub(/^ /, '')
|
10
|
+
*************************************************************************
|
11
|
+
Philter version #{Philter.version}
|
12
|
+
[].philter 'search', {options}
|
13
|
+
Examples:
|
14
|
+
[1,2,3].philter 1 => [1]
|
15
|
+
[1,2,3].philter [2,3] => [2, 3]
|
16
|
+
[{id: 1, name: 'Mark'},{id: 2, name: 'Bill'}].philter id: 1
|
17
|
+
Articles.philter id: 1
|
18
|
+
People.philter name: 'Mario'
|
19
|
+
People.philter email: /\A.+@gmail/
|
20
|
+
Use option get: to select an attribute
|
21
|
+
People.philter {id: 1}, get: :surname
|
22
|
+
Use option debug: to watch the selection
|
23
|
+
Articles.philter {id: 1}, debug: true
|
24
|
+
*************************************************************************
|
25
|
+
HELP
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
# Philter methods
|
2
|
+
module Philter
|
3
|
+
# It contains all the methods for selecting the items
|
4
|
+
module Evaluation
|
5
|
+
private
|
6
|
+
|
7
|
+
# Evaluate search attributes to any item
|
8
|
+
# in: item, search, options{debug:nil}
|
9
|
+
# out: true/false (if the item has been selected)
|
10
|
+
def phil_eval_attributes(item, search, options = {})
|
11
|
+
selected_or = nil
|
12
|
+
selected_and = true
|
13
|
+
search.each do |key, search_value|
|
14
|
+
# Every item must match with search options to be selected
|
15
|
+
puts " search: #{key}: #{search_value} " \
|
16
|
+
"(#{search_value.class.name})" if options[:debug]
|
17
|
+
case search_value.class.name
|
18
|
+
when 'Regexp'
|
19
|
+
# search: {email: /@gmail/}
|
20
|
+
print ' .1 ' if options[:debug]
|
21
|
+
selected = phil_evaluate item_value(item, key, options),
|
22
|
+
search_value,
|
23
|
+
options.merge(operator: '=~')
|
24
|
+
when 'Class'
|
25
|
+
# search: {code: String} or {code: Fixnum}
|
26
|
+
print ' .2 item.class == value | ' \
|
27
|
+
"#{item.class} == #{search_value}" if options[:debug]
|
28
|
+
selected = item_value(item, key, options).class == search_value
|
29
|
+
when 'Array'
|
30
|
+
# search: {id: [1,2]}
|
31
|
+
print ' .3 ' if options[:debug]
|
32
|
+
selected = search_value.include? item_value(item, key, options)
|
33
|
+
else
|
34
|
+
# search: {id: 2} or {id: '<3'} or any other operator
|
35
|
+
print ' .4 ' if options[:debug]
|
36
|
+
selected = phil_evaluate item_value(item, key, options),
|
37
|
+
search_value,
|
38
|
+
options.merge(operator: '==')
|
39
|
+
end
|
40
|
+
puts " #{selected && '=> x'}" if options[:debug]
|
41
|
+
selected_or = true if !selected_or && selected
|
42
|
+
selected_and = selected if selected_and
|
43
|
+
end
|
44
|
+
|
45
|
+
if options[:or]
|
46
|
+
puts " #{selected_or && '- SELECTED - (Or)'}" if options[:debug]
|
47
|
+
selected_or
|
48
|
+
else
|
49
|
+
puts " #{selected_and && '- SELECTED - (And)'}" if options[:debug]
|
50
|
+
selected_and
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# Provide the item's value
|
55
|
+
# in: item, attribute, options{debug:nil}
|
56
|
+
# out: the item's value
|
57
|
+
def item_value(item, attribute, options = {})
|
58
|
+
case item.class.name
|
59
|
+
when 'Hash' then
|
60
|
+
print " item[#{attribute}] = #{item[attribute]} " if options[:debug]
|
61
|
+
item[attribute]
|
62
|
+
when 'Fixnum', 'Float', 'Bignum', 'Symbol', 'String'
|
63
|
+
print " #{item.class.name} " if options[:debug]
|
64
|
+
print "#{item} " if options[:debug]
|
65
|
+
item
|
66
|
+
else
|
67
|
+
print " item.#{attribute} " if options[:debug]
|
68
|
+
if item.respond_to?(attribute)
|
69
|
+
print "= #{item.send(attribute)} " if options[:debug]
|
70
|
+
item.send(attribute)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# Evaluate a condition: item -operator- value
|
76
|
+
# in: item, value, options{operator:'==',debug:false}
|
77
|
+
# out: true/false
|
78
|
+
def phil_evaluate(item, value, options = {})
|
79
|
+
options = { operator: '==',
|
80
|
+
debug: false }.merge(options)
|
81
|
+
value, operator = phil_get_operator_value_cleaned value
|
82
|
+
operator ||= options[:operator]
|
83
|
+
print " item #{operator} value" if options[:debug]
|
84
|
+
print " | #{item} #{operator} #{value}" if options[:debug]
|
85
|
+
case operator
|
86
|
+
when '=~' then item.to_s =~ value
|
87
|
+
when '===' then item === value
|
88
|
+
when '==' then item == value
|
89
|
+
when '>=' then item >= value
|
90
|
+
when '<=' then item <= value
|
91
|
+
when '!=' then item != value
|
92
|
+
when '>' then item > value
|
93
|
+
when '<' then item < value
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
# Search an operator in value
|
98
|
+
# in: value
|
99
|
+
# out: value without operator, operator
|
100
|
+
def phil_get_operator_value_cleaned(value)
|
101
|
+
operator = phil_get_operator value
|
102
|
+
value = value.gsub(operator, '').to_i if operator
|
103
|
+
[value, operator]
|
104
|
+
end
|
105
|
+
|
106
|
+
# Search an operator by regexp (?:<=?|>=?|!=|==|===|=~)
|
107
|
+
# in: value
|
108
|
+
# out: operator
|
109
|
+
def phil_get_operator(str)
|
110
|
+
return unless str.is_a?(String)
|
111
|
+
regexp = '(?:<=?|>=?|!=|==|===|=~)'
|
112
|
+
str.match(/#{regexp}/).to_s if str =~ /#{regexp}/
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
# Philter methods
|
2
|
+
module Philter
|
3
|
+
# It contains methods to select array's items
|
4
|
+
module Search
|
5
|
+
private
|
6
|
+
|
7
|
+
# Called when search is a string with an operator
|
8
|
+
# in: search, options{debug:nil}
|
9
|
+
# out: array of selected items
|
10
|
+
def phil_search_with_operator(items, search, options = {})
|
11
|
+
puts " #{search} with operator" if options[:debug]
|
12
|
+
results = []
|
13
|
+
items.each do |item|
|
14
|
+
puts " item #{item.class.name} #{item}" if options[:debug]
|
15
|
+
selected = phil_evaluate item, search, options
|
16
|
+
puts " #{selected && '=> x'}" if options[:debug]
|
17
|
+
results << item if selected
|
18
|
+
end
|
19
|
+
results
|
20
|
+
end
|
21
|
+
|
22
|
+
# Called when search is an array
|
23
|
+
# in: search, options{debug:nil}
|
24
|
+
# out: array of selected items
|
25
|
+
def phil_search_by_array(items, search, options = {})
|
26
|
+
puts " #{search}" if options[:debug]
|
27
|
+
search_same_class = false
|
28
|
+
# Check if search's objects are all the same class
|
29
|
+
search.inject do |prev, cur|
|
30
|
+
search_same_class = prev.class == cur.class
|
31
|
+
cur
|
32
|
+
end
|
33
|
+
if search_same_class
|
34
|
+
items.select do |item|
|
35
|
+
if search.first.class.name == 'Class'
|
36
|
+
selected = search.include?(item.class)
|
37
|
+
puts " item: #{item} #{selected && '=> x'}" if options[:debug]
|
38
|
+
selected
|
39
|
+
else
|
40
|
+
selected = search.include?(item)
|
41
|
+
puts " item: #{item} #{selected && '=> x'}" if options[:debug]
|
42
|
+
selected
|
43
|
+
end
|
44
|
+
end
|
45
|
+
else
|
46
|
+
# If there are many classes in search, check every search item
|
47
|
+
search.each do |search_value|
|
48
|
+
items.select do |item|
|
49
|
+
if search_value.class.name == 'Class'
|
50
|
+
selected = search_value == item.class
|
51
|
+
puts " item: #{item} #{selected && '=> x'}" if options[:debug]
|
52
|
+
selected
|
53
|
+
else
|
54
|
+
selected = search_value == item
|
55
|
+
puts " item: #{item} #{selected && '=> x'}" if options[:debug]
|
56
|
+
selected
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# Search the search attribute in the item
|
64
|
+
# in: search, options{debug:nil}
|
65
|
+
# out: array of selected items
|
66
|
+
def phil_search_by_attributes(items, search, options = {})
|
67
|
+
puts " #{search}" if options[:debug]
|
68
|
+
results = []
|
69
|
+
items.each do |item|
|
70
|
+
selected = nil
|
71
|
+
# Evaluate each array's item
|
72
|
+
puts if options[:debug]
|
73
|
+
puts " item #{item} (#{item.class.name}) " if options[:debug]
|
74
|
+
case item.class.name
|
75
|
+
when 'Array'
|
76
|
+
puts ' item is an array => discarded' if options[:debug]
|
77
|
+
when 'Hash'
|
78
|
+
puts ' evaluating hash ' if options[:debug]
|
79
|
+
selected = phil_eval_attributes item, search, options
|
80
|
+
when 'Fixnum', 'Float', 'Bignum', 'Symbol', 'String'
|
81
|
+
print " evaluating #{item.class.name} " if options[:debug]
|
82
|
+
if options[:everywhere]
|
83
|
+
print ' => everywhere' if options[:debug]
|
84
|
+
selected = phil_eval_attributes item, search, options
|
85
|
+
else
|
86
|
+
print ' => discarded' if options[:debug]
|
87
|
+
end
|
88
|
+
else
|
89
|
+
puts " evaluating #{item.class.name}'s attributes" if options[:debug]
|
90
|
+
selected = phil_eval_attributes item, search, options
|
91
|
+
end
|
92
|
+
|
93
|
+
next unless selected
|
94
|
+
results <<
|
95
|
+
if options[:get] && item.respond_to?(options[:get])
|
96
|
+
item.send options[:get]
|
97
|
+
elsif options[:get] && item.respond_to?('[]')
|
98
|
+
item[options[:get]]
|
99
|
+
else
|
100
|
+
item
|
101
|
+
end
|
102
|
+
end
|
103
|
+
results
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
data/lib/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: philter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Marco Mastrodonato
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-05-
|
11
|
+
date: 2016-05-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: test-unit
|
@@ -35,9 +35,11 @@ files:
|
|
35
35
|
- CHANGELOG.md
|
36
36
|
- LICENSE
|
37
37
|
- README.md
|
38
|
-
- lib/array.rb
|
39
|
-
- lib/base.rb
|
40
38
|
- lib/philter.rb
|
39
|
+
- lib/philter/array.rb
|
40
|
+
- lib/philter/base.rb
|
41
|
+
- lib/philter/evaluation.rb
|
42
|
+
- lib/philter/search.rb
|
41
43
|
- lib/version.rb
|
42
44
|
homepage: https://github.com/marcomd/philter
|
43
45
|
licenses:
|
data/lib/array.rb
DELETED
@@ -1,40 +0,0 @@
|
|
1
|
-
class Array
|
2
|
-
include Philter::Base
|
3
|
-
def philter search=nil, options={}, &block
|
4
|
-
options = {
|
5
|
-
get: nil,
|
6
|
-
debug: false
|
7
|
-
}.merge(options)
|
8
|
-
unless search
|
9
|
-
puts philter_help if options[:debug]
|
10
|
-
raise "Specify search parameter!"
|
11
|
-
end
|
12
|
-
|
13
|
-
apply_block = true
|
14
|
-
results =
|
15
|
-
case search.class.name
|
16
|
-
when "Hash"
|
17
|
-
print " h. " if options[:debug]
|
18
|
-
phil_search_by_attributes search, options
|
19
|
-
when "String"
|
20
|
-
print " s. " if options[:debug]
|
21
|
-
operator = phil_get_operator search
|
22
|
-
operator ? phil_search_with_operator(search, operator: operator) : self.grep(search)
|
23
|
-
when "Array"
|
24
|
-
print " a. " if options[:debug]
|
25
|
-
phil_search_by_array search, options
|
26
|
-
else
|
27
|
-
puts " g. #{search}" if options[:debug]
|
28
|
-
apply_block = false
|
29
|
-
self.grep(search, &block)
|
30
|
-
end
|
31
|
-
|
32
|
-
puts "------------------" if options[:debug]
|
33
|
-
puts " #{results ? results.size : 'No'} item#{results && results.size == 1 ? '' : 's'} found" if options[:debug]
|
34
|
-
if block_given? && apply_block
|
35
|
-
results.map{|item| block.call(item)}
|
36
|
-
else
|
37
|
-
results
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
data/lib/base.rb
DELETED
@@ -1,191 +0,0 @@
|
|
1
|
-
module Philter
|
2
|
-
module Base
|
3
|
-
private
|
4
|
-
|
5
|
-
def phil_search_with_operator search, options={}
|
6
|
-
results = []
|
7
|
-
self.each do |item|
|
8
|
-
puts "item #{item.class.name} #{item}" if options[:debug]
|
9
|
-
selected = phil_evaluate item, search, options
|
10
|
-
puts " #{'=> X' if selected}" if options[:debug]
|
11
|
-
results << item if selected
|
12
|
-
end
|
13
|
-
results
|
14
|
-
end
|
15
|
-
|
16
|
-
def phil_search_by_array search, options={}
|
17
|
-
puts "search #{search} (#{search.class.name}) " if options[:debug]
|
18
|
-
search_same_class = false
|
19
|
-
search.inject{|prev, cur| search_same_class=prev.class == cur.class; cur }
|
20
|
-
if search_same_class
|
21
|
-
self.select do |item|
|
22
|
-
if search.first.class.name == 'Class'
|
23
|
-
search.include? item.class
|
24
|
-
else
|
25
|
-
search.include? item
|
26
|
-
end
|
27
|
-
end
|
28
|
-
else
|
29
|
-
# Check every search item
|
30
|
-
search.each do |search_value|
|
31
|
-
self.select do |item|
|
32
|
-
if search_value.class.name == 'Class'
|
33
|
-
search_value == item.class
|
34
|
-
else
|
35
|
-
search_value == item
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
def phil_search_by_attributes search, options={}
|
43
|
-
results = []
|
44
|
-
self.each do |item|
|
45
|
-
selected = nil
|
46
|
-
# Evaluate each array's item
|
47
|
-
puts "item #{item} (#{item.class.name}) " if options[:debug]
|
48
|
-
case item.class.name
|
49
|
-
when "Array"
|
50
|
-
print " a. discarded" if options[:debug]
|
51
|
-
when "Hash"
|
52
|
-
print " h. " if options[:debug]
|
53
|
-
selected = phil_apply_attributes item, search, options
|
54
|
-
when phil_base_objects
|
55
|
-
print " b. discarded" if options[:debug]
|
56
|
-
else
|
57
|
-
print " o. " if options[:debug]
|
58
|
-
selected = phil_apply_attributes item, search, options
|
59
|
-
end
|
60
|
-
# puts " #{'=> X' if selected}" if options[:debug]
|
61
|
-
if selected
|
62
|
-
results <<
|
63
|
-
if options[:get]
|
64
|
-
if item.respond_to? options[:get]
|
65
|
-
item.send options[:get]
|
66
|
-
elsif item.respond_to? '[]'
|
67
|
-
item[options[:get]]
|
68
|
-
end
|
69
|
-
else
|
70
|
-
item
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end
|
74
|
-
results
|
75
|
-
end
|
76
|
-
|
77
|
-
def phil_apply_attributes item, search, options={}
|
78
|
-
selected_or, selected_and = nil, true
|
79
|
-
search.each do |key, search_value|
|
80
|
-
# Every item must match with search options to be selected
|
81
|
-
puts " search: #{key}: #{search_value} (#{search_value.class.name})" if options[:debug]
|
82
|
-
case search_value.class.name
|
83
|
-
when 'Regexp'
|
84
|
-
# search: {email: /@gmail/}
|
85
|
-
print " .1 " if options[:debug]
|
86
|
-
selected = phil_evaluate item_value(item, key, options), search_value, options.merge(operator: '=~')
|
87
|
-
when 'Class'
|
88
|
-
# search: {code: String} or {code: Fixnum}
|
89
|
-
print " .2 item.class == value | #{item.class} == #{search_value}" if options[:debug]
|
90
|
-
selected = item_value(item, key, options).class == search_value
|
91
|
-
when 'Array'
|
92
|
-
# search: {id: [1,2]}
|
93
|
-
print " .3 " if options[:debug]
|
94
|
-
selected = search_value.include? item_value(item, key, options)
|
95
|
-
else
|
96
|
-
# search: {id: 2} or {id: '<3'} or any other operator
|
97
|
-
print " .4 " if options[:debug]
|
98
|
-
selected = phil_evaluate item_value(item, key, options), search_value, options.merge(operator: '==')
|
99
|
-
end
|
100
|
-
puts " #{'=> x' if selected}" if options[:debug]
|
101
|
-
selected_or = true if !selected_or && selected
|
102
|
-
selected_and = selected if selected_and
|
103
|
-
end
|
104
|
-
|
105
|
-
if options[:or]
|
106
|
-
puts " #{'=> X (Or)' if selected_or}" if options[:debug]
|
107
|
-
selected_or
|
108
|
-
else
|
109
|
-
puts " #{'=> X (And)' if selected_and}" if options[:debug]
|
110
|
-
selected_and
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
|
-
def item_value item, label, options={}
|
115
|
-
case item.class.name
|
116
|
-
when "Hash" then
|
117
|
-
print " v1 item[#{label}] " if options[:debug]
|
118
|
-
item[label]
|
119
|
-
when "Fixnum", "Float", "Bignum", "Symbol", "String"
|
120
|
-
print " v2 #{item.class.name} " if options[:debug]
|
121
|
-
if options[:everywhere]
|
122
|
-
print "#{item} " if options[:debug]
|
123
|
-
item
|
124
|
-
else
|
125
|
-
print "- " if options[:debug]
|
126
|
-
nil
|
127
|
-
end
|
128
|
-
else
|
129
|
-
print " v3 item.#{label} " if options[:debug]
|
130
|
-
item.send(label) if item.respond_to? label
|
131
|
-
end
|
132
|
-
end
|
133
|
-
|
134
|
-
def phil_evaluate item, value, options={}
|
135
|
-
options = {
|
136
|
-
operator: '==',
|
137
|
-
debug: false
|
138
|
-
}.merge(options)
|
139
|
-
operator = phil_get_operator value
|
140
|
-
value = operator ? value.gsub(operator,'').to_i : value
|
141
|
-
operator ||= options[:operator]
|
142
|
-
print " item #{operator} value" if options[:debug]
|
143
|
-
print " | #{item} #{operator} #{value}" if options[:debug]
|
144
|
-
case operator
|
145
|
-
when '=~' then item.to_s =~ value
|
146
|
-
when '==' then item == value
|
147
|
-
when '===' then item === value
|
148
|
-
when '>' then item > value
|
149
|
-
when '<' then item < value
|
150
|
-
when '>=' then item >= value
|
151
|
-
when '<=' then item <= value
|
152
|
-
when '!=' then item != value
|
153
|
-
end
|
154
|
-
end
|
155
|
-
|
156
|
-
def phil_get_operator exp
|
157
|
-
return unless exp.is_a? String
|
158
|
-
regexp = "(?:<=?|>=?|!=|==|===|=~)"
|
159
|
-
if exp =~ /#{regexp}/
|
160
|
-
exp.match(/#{regexp}/).to_s
|
161
|
-
else
|
162
|
-
nil
|
163
|
-
end
|
164
|
-
end
|
165
|
-
|
166
|
-
def phil_base_objects
|
167
|
-
return "Fixnum", "Float", "Bignum", "Symbol", "String"
|
168
|
-
end
|
169
|
-
|
170
|
-
def philter_help
|
171
|
-
<<-HELP.gsub(/^ /, '')
|
172
|
-
*************************************************************************
|
173
|
-
Philter version #{Philter.version}
|
174
|
-
[].philter 'search', {options}
|
175
|
-
Examples:
|
176
|
-
[1,2,3].philter 1 => [1]
|
177
|
-
[1,2,3].philter [2,3] => [2, 3]
|
178
|
-
[{id: 1, name: 'Mark'},{id: 2, name: 'Bill'}].philter id: 1
|
179
|
-
Articles.philter id: 1
|
180
|
-
People.philter name: 'Mario'
|
181
|
-
People.philter email: /\A.+@gmail/
|
182
|
-
Use option get: to select an attribute
|
183
|
-
People.philter {id: 1}, get: :surname
|
184
|
-
Use option debug: to watch the selection
|
185
|
-
Articles.philter {id: 1}, debug: true
|
186
|
-
*************************************************************************
|
187
|
-
HELP
|
188
|
-
end
|
189
|
-
|
190
|
-
end
|
191
|
-
end
|