philter 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 +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
|