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