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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 752a73c7c043fd49ebb875fca66209e6865b1f17
4
- data.tar.gz: 2c010a42446deff32ac4edc8bb2a0934333f8910
3
+ metadata.gz: 872214969624e598ec099b000b4ada64ac9837f3
4
+ data.tar.gz: ba1d3f800772f91b3a8d8b08b06d87a68229d517
5
5
  SHA512:
6
- metadata.gz: db08c41adc22da507100dba892ed3329a0d2e6e7a352cd459408ad30cb078fafd06988d228c646a111d2cdd4e606e9e80591b8445611d53f9b1026b88b96e506
7
- data.tar.gz: 4449e25ad6b6a348d15edb3ae3292b16bb95eef9f52749598a1cfc486f613a6186decc62a481c8bd9d28da1a55e321bad169cde3ff15bed5492844ce9334d24f
6
+ metadata.gz: dc93c8a4a407b0227b0e6795dcd060d01855b83a6f4b8896a1ca2957ae480288eeabecd0d71f8f3f5e254b9cc4cb86fb2a287417856784a899ab6c24ed168a6a
7
+ data.tar.gz: 64bc6efbc153e5e41ad99e0eb493046a1f9be0dcd859aa522f11ab423da36877058c2203de70034b42a291300cff791887a3dc5ccff4b1c0d54141c179cf8095
@@ -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 an attribute or another
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: 1, name: 'Mark' },
119
- {id: 2, name: 'Larry' },
120
- {id: 3, name: 'Bill' }
121
- ].philter({id: [1,3]}, debug: true)
122
- # You will get a trace
123
- item Hash {:id=>1, :name=>"Mark"}
124
- a. search: Array [:id, [1, 3]]
125
- 1.y label: Symbol .2 Hash[:id] == value | 1 == 1 => X
126
- 1.y label: Symbol .2 Hash[:id] == value | 1 == 3
127
- item Hash {:id=>2, :name=>"Larry"}
128
- a. search: Array [:id, [1, 3]]
129
- 1.y label: Symbol .2 Hash[:id] == value | 2 == 1
130
- 1.y label: Symbol .2 Hash[:id] == value | 2 == 3
131
- item Hash {:id=>3, :name=>"Bill"}
132
- a. search: Array [:id, [1, 3]]
133
- 1.y label: Symbol .2 Hash[:id] == value | 3 == 1
134
- 1.y label: Symbol .2 Hash[:id] == value | 3 == 3 => X
135
- ------------------
136
- 2 items found
137
- => [{:id=>1, :name=>"Mark"}, {:id=>3, :name=>"Bill"}]
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
 
@@ -1,6 +1,20 @@
1
- require_relative 'version'
2
- require_relative 'base'
3
- require_relative 'array'
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
- module Philter
6
- end
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
@@ -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
@@ -1,5 +1,5 @@
1
1
  module Philter
2
2
  def self.version
3
- "1.0.0"
3
+ "1.1.0"
4
4
  end
5
5
  end
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.0.0
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-25 00:00:00.000000000 Z
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:
@@ -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
@@ -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