active_enumerable 0.1.0 → 0.1.1
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/README.md +29 -5
- data/lib/active_enumerable.rb +21 -1
- data/lib/active_enumerable/base.rb +44 -0
- data/lib/active_enumerable/comparable.rb +11 -0
- data/lib/active_enumerable/enumerable.rb +9 -0
- data/lib/active_enumerable/finder.rb +39 -0
- data/lib/active_enumerable/method_caller.rb +21 -0
- data/lib/active_enumerable/queries.rb +234 -0
- data/lib/active_enumerable/record_not_found.rb +4 -0
- data/lib/active_enumerable/scopes.rb +52 -0
- data/lib/active_enumerable/version.rb +1 -1
- data/lib/active_enumerable/where.rb +99 -0
- metadata +12 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 016716ccb116b9441ef93f1d0698201c9b41ac50
|
4
|
+
data.tar.gz: a164e13d533c2aa282b9d7663ee65f1a28b8ea17
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7ab10d01e6738b89b9f375b1a1df9156f5cf8c2a3f96b026e698f244c232fd73a9188adc3523d678c721bb995b5902620e0b04dc4647c6fb90148e26f3112cb1
|
7
|
+
data.tar.gz: cb3a52fd97b0aae04319d7749e8df84b23fa9b30747cbc54c861f90b9c0d009ee6ba695e6dfb6a4db185fe541999e524ce5d72b86c799afc94a7ebdf4aac4c47
|
data/README.md
CHANGED
@@ -1,8 +1,6 @@
|
|
1
1
|
# ActiveEnumerable
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
TODO: Delete this and the text above, and describe your gem
|
3
|
+
Include ActiveRecord like query methods to Ruby enumerable collections.
|
6
4
|
|
7
5
|
## Installation
|
8
6
|
|
@@ -22,7 +20,33 @@ Or install it yourself as:
|
|
22
20
|
|
23
21
|
## Usage
|
24
22
|
|
25
|
-
|
23
|
+
```ruby
|
24
|
+
require "active_enumerable"
|
25
|
+
|
26
|
+
class Customers
|
27
|
+
include ActiveEnumerable
|
28
|
+
|
29
|
+
scope :unpaid, -> { where(paid: false).or(credit: 0) }
|
30
|
+
end
|
31
|
+
|
32
|
+
customers = Customers.new([{paid: true, credit: 1000}, {paid: false, credit: 2000}, {paid: false, credit: 0}])
|
33
|
+
|
34
|
+
customers.unpaid
|
35
|
+
# => <#Customers [{:paid=>false, :credit=>2000}, {:paid=>false, :credit=>0}]]>
|
36
|
+
|
37
|
+
customers.scope { select { |y| y > 1000 } }
|
38
|
+
#=> <#Customers [{paid: true, credit: 1000}, {paid: false, credit: 2000}]>
|
39
|
+
|
40
|
+
customers.sum(:credit)
|
41
|
+
#=> 3000
|
42
|
+
|
43
|
+
customers.create({paid: true, credit: 1500}) # defaults to Hash creations
|
44
|
+
|
45
|
+
Customers.item_class = Customer
|
46
|
+
|
47
|
+
customers.create({paid: true, credit: 1500}).to_a.last
|
48
|
+
#=> <#Customer paid: true, credit: 1500>
|
49
|
+
```
|
26
50
|
|
27
51
|
## Development
|
28
52
|
|
@@ -32,7 +56,7 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
|
|
32
56
|
|
33
57
|
## Contributing
|
34
58
|
|
35
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/
|
59
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/zeisler/active_enumerable. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](contributor-covenant.org) code of conduct.
|
36
60
|
|
37
61
|
|
38
62
|
## License
|
data/lib/active_enumerable.rb
CHANGED
@@ -1,5 +1,25 @@
|
|
1
1
|
require "active_enumerable/version"
|
2
|
+
require "active_enumerable/base"
|
3
|
+
require "active_enumerable/comparable"
|
4
|
+
require "active_enumerable/enumerable"
|
5
|
+
require "active_enumerable/finder"
|
6
|
+
require "active_enumerable/method_caller"
|
7
|
+
require "active_enumerable/scopes"
|
8
|
+
require "active_enumerable/where"
|
9
|
+
require "active_enumerable/queries"
|
2
10
|
|
3
11
|
module ActiveEnumerable
|
4
|
-
|
12
|
+
include Base
|
13
|
+
include Enumerable
|
14
|
+
include Comparable
|
15
|
+
include Queries
|
16
|
+
include Scopes
|
17
|
+
|
18
|
+
module ClassMethods
|
19
|
+
include Scopes::ClassMethods
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.included(base)
|
23
|
+
base.extend(ClassMethods)
|
24
|
+
end
|
5
25
|
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module ActiveEnumerable
|
2
|
+
module Base
|
3
|
+
def initialize(collection=[])
|
4
|
+
@to_a = collection.to_ary
|
5
|
+
end
|
6
|
+
|
7
|
+
attr_reader :to_a
|
8
|
+
|
9
|
+
# @private
|
10
|
+
def __new_relation__(collection)
|
11
|
+
self.class.new(collection)
|
12
|
+
end
|
13
|
+
|
14
|
+
def create(attributes)
|
15
|
+
add(if (klass = self.class.item_class)
|
16
|
+
klass.new(attributes)
|
17
|
+
else
|
18
|
+
attributes
|
19
|
+
end)
|
20
|
+
end
|
21
|
+
|
22
|
+
def add(item)
|
23
|
+
to_a << item
|
24
|
+
end
|
25
|
+
|
26
|
+
def all
|
27
|
+
self
|
28
|
+
end
|
29
|
+
|
30
|
+
module ClassMethods
|
31
|
+
def item_class
|
32
|
+
@item_class
|
33
|
+
end
|
34
|
+
|
35
|
+
def item_class=(klass)
|
36
|
+
@item_class = klass
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.included(base)
|
41
|
+
base.extend(ClassMethods)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module ActiveEnumerable
|
2
|
+
# @private
|
3
|
+
class Finder
|
4
|
+
def initialize(record)
|
5
|
+
@method_caller = MethodCaller.new(record)
|
6
|
+
end
|
7
|
+
|
8
|
+
def is_of(conditions={})
|
9
|
+
conditions.all? do |col, match|
|
10
|
+
if match.is_a? Hash
|
11
|
+
hash_match(col, match)
|
12
|
+
elsif match.is_a? ::Enumerable
|
13
|
+
any_match(col, match)
|
14
|
+
else
|
15
|
+
compare(col, match)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def hash_match(col, match)
|
23
|
+
next_record = @method_caller.call(col)
|
24
|
+
if next_record.is_a? Array
|
25
|
+
next_record.any? { |record| Finder.new(record).is_of(match) }
|
26
|
+
else
|
27
|
+
Finder.new(next_record).is_of(match)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def any_match(col, match)
|
32
|
+
match.any? { |m| compare(col, m) }
|
33
|
+
end
|
34
|
+
|
35
|
+
def compare(col, match)
|
36
|
+
@method_caller.call(col) == match
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module ActiveEnumerable
|
2
|
+
# @private
|
3
|
+
class MethodCaller
|
4
|
+
attr_reader :object, :raise_no_method
|
5
|
+
|
6
|
+
def initialize(object, raise_no_method: true)
|
7
|
+
@object = object
|
8
|
+
@raise_no_method = raise_no_method
|
9
|
+
end
|
10
|
+
|
11
|
+
def call(method)
|
12
|
+
if object.is_a? Hash
|
13
|
+
object.fetch(method)
|
14
|
+
else
|
15
|
+
object.public_send(method)
|
16
|
+
end
|
17
|
+
rescue NoMethodError, KeyError => e
|
18
|
+
raise e if raise_no_method
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,234 @@
|
|
1
|
+
module ActiveEnumerable
|
2
|
+
module Queries
|
3
|
+
include ActiveEnumerable::Where
|
4
|
+
|
5
|
+
# Find by id - This can either be a specific id (1), a list of ids (1, 5, 6), or an array of ids ([5, 6, 10]).
|
6
|
+
# If no record can be found for all of the listed ids, then RecordNotFound will be raised. If the primary key
|
7
|
+
# is an integer, find by id coerces its arguments using +to_i+.
|
8
|
+
#
|
9
|
+
# <#ActiveEnumerable>.find(1) # returns the object for ID = 1
|
10
|
+
# <#ActiveEnumerable>.find(1, 2, 6) # returns an array for objects with IDs in (1, 2, 6)
|
11
|
+
# <#ActiveEnumerable>.find([7, 17]) # returns an array for objects with IDs in (7, 17)
|
12
|
+
# <#ActiveEnumerable>.find([1]) # returns an array for the object with ID = 1
|
13
|
+
#
|
14
|
+
# <tt>ActiveEnumerable::RecordNotFound</tt> will be raised if one or more ids are not found.
|
15
|
+
def find(ids)
|
16
|
+
raise RecordNotFound.new("Couldn't find #{self.name} without an ID") if ids.nil?
|
17
|
+
results = [*ids].map do |id|
|
18
|
+
find_by!(id: id.to_i)
|
19
|
+
end
|
20
|
+
return __new_relation__(results) if ids.class == Array
|
21
|
+
results.first
|
22
|
+
end
|
23
|
+
|
24
|
+
# Updates all records with details given if they match a set of conditions supplied, limits and order can
|
25
|
+
# also be supplied.
|
26
|
+
#
|
27
|
+
# ==== Parameters
|
28
|
+
#
|
29
|
+
# * +updates+ - A string, array, or hash.
|
30
|
+
#
|
31
|
+
# ==== Examples
|
32
|
+
#
|
33
|
+
# # Update all customers with the given attributes
|
34
|
+
# <#ActiveEnumerable>.update_all wants_email: true
|
35
|
+
#
|
36
|
+
# # Update all books with 'Rails' in their title
|
37
|
+
# <#ActiveEnumerable>.where(title: 'Rails').update_all(author: 'David')
|
38
|
+
#
|
39
|
+
# # Update all books that match conditions, but limit it to 5 ordered by date
|
40
|
+
# <#ActiveEnumerable>.where(title: 'Rails').order(:created_at).limit(5).update_all(author: 'David')
|
41
|
+
def update_all(attributes)
|
42
|
+
all.each { |i| i.update(attributes) }
|
43
|
+
end
|
44
|
+
|
45
|
+
# Updates an object (or multiple objects) and saves it.
|
46
|
+
#
|
47
|
+
# ==== Parameters
|
48
|
+
#
|
49
|
+
# * +id+ - This should be the id or an array of ids to be updated.
|
50
|
+
# * +attributes+ - This should be a hash of attributes or an array of hashes.
|
51
|
+
#
|
52
|
+
# ==== Examples
|
53
|
+
#
|
54
|
+
# # Updates one record
|
55
|
+
# <#ActiveEnumerable>.update(15, user_name: 'Samuel', group: 'expert')
|
56
|
+
#
|
57
|
+
# # Updates multiple records
|
58
|
+
# people = { 1 => { "first_name" => "David" }, 2 => { "first_name" => "Jeremy" } }
|
59
|
+
# <#ActiveEnumerable>.update(people.keys, people.values)
|
60
|
+
def update(id, attributes)
|
61
|
+
if id.is_a?(Array)
|
62
|
+
id.map.with_index { |one_id, idx| update(one_id, attributes[idx]) }
|
63
|
+
else
|
64
|
+
object = find(id)
|
65
|
+
object.update(attributes)
|
66
|
+
object
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# Finds the first record matching the specified conditions. There
|
71
|
+
# is no implied ordering so if order matters, you should specify it
|
72
|
+
# yourself.
|
73
|
+
#
|
74
|
+
# If no record is found, returns <tt>nil</tt>.
|
75
|
+
#
|
76
|
+
# <#ActiveEnumerable>.find_by name: 'Spartacus', rating: 4
|
77
|
+
def find_by(conditions = {})
|
78
|
+
to_a.detect do |record|
|
79
|
+
Finder.new(record).is_of(conditions)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
# Like <tt>find_by</tt>, except that if no record is found, raises
|
84
|
+
# an <tt>ActiveEnumerable::RecordNotFound</tt> error.
|
85
|
+
def find_by!(conditions={})
|
86
|
+
result = find_by(conditions)
|
87
|
+
if result.nil?
|
88
|
+
raise RecordNotFound.new("Couldn't find #{self.name} with '#{conditions.keys.first}'=#{conditions.values.first}")
|
89
|
+
end
|
90
|
+
result
|
91
|
+
end
|
92
|
+
|
93
|
+
# Finds the first record with the given attributes, or creates a record
|
94
|
+
# with the attributes if one is not found:
|
95
|
+
#
|
96
|
+
# # Find the first user named "Penélope" or create a new one.
|
97
|
+
# <#ActiveEnumerable>.find_or_create_by(first_name: 'Penélope')
|
98
|
+
# # => #<User id: 1, first_name: "Penélope", last_name: nil>
|
99
|
+
#
|
100
|
+
# # Find the first user named "Penélope" or create a new one.
|
101
|
+
# # We already have one so the existing record will be returned.
|
102
|
+
# <#ActiveEnumerable>.find_or_create_by(first_name: 'Penélope')
|
103
|
+
# # => #<User id: 1, first_name: "Penélope", last_name: nil>
|
104
|
+
#
|
105
|
+
# This method accepts a block, which is passed down to +create+. The last example
|
106
|
+
# above can be alternatively written this way:
|
107
|
+
#
|
108
|
+
# # Find the first user named "Scarlett" or create a new one with a
|
109
|
+
# # different last name.
|
110
|
+
# <#ActiveEnumerable>.find_or_create_by(first_name: 'Scarlett') do |user|
|
111
|
+
# user.last_name = 'Johansson'
|
112
|
+
# end
|
113
|
+
# # => #<User id: 2, first_name: "Scarlett", last_name: "Johansson">
|
114
|
+
#
|
115
|
+
def find_or_create_by(attributes, &block)
|
116
|
+
find_by(attributes) || create(attributes, &block)
|
117
|
+
end
|
118
|
+
|
119
|
+
alias_method :find_or_create_by!, :find_or_create_by
|
120
|
+
|
121
|
+
# Like <tt>find_or_create_by</tt>, but calls <tt>new</tt> instead of <tt>create</tt>.
|
122
|
+
def find_or_initialize_by(attributes, &block)
|
123
|
+
find_by(attributes) || new(attributes, &block)
|
124
|
+
end
|
125
|
+
|
126
|
+
# Count the records.
|
127
|
+
#
|
128
|
+
# <#ActiveEnumerable>.count
|
129
|
+
# # => the total count of all people
|
130
|
+
#
|
131
|
+
# <#ActiveEnumerable>.count(:age)
|
132
|
+
# # => returns the total count of all people whose age is not nil
|
133
|
+
def count(name = nil)
|
134
|
+
return all.size if name.nil?
|
135
|
+
where.not(name => nil).size
|
136
|
+
end
|
137
|
+
|
138
|
+
# Specifies a limit for the number of records to retrieve.
|
139
|
+
#
|
140
|
+
# <#ActiveEnumerable>.limit(10)
|
141
|
+
def limit(num)
|
142
|
+
relation = __new_relation__(all.take(num))
|
143
|
+
relation.send(:set_from_limit)
|
144
|
+
relation
|
145
|
+
end
|
146
|
+
|
147
|
+
# Calculates the sum of values on a given attribute. The value is returned
|
148
|
+
# with the same data type of the attribute, 0 if there's no row.
|
149
|
+
#
|
150
|
+
# <#ActiveEnumerable>.sum(:age) # => 4562
|
151
|
+
def sum(key)
|
152
|
+
values = values_by_key(key)
|
153
|
+
values.inject(0) do |sum, n|
|
154
|
+
sum + (n || 0)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
# Calculates the average value on a given attribute. Returns +nil+ if there's
|
159
|
+
# no row.
|
160
|
+
#
|
161
|
+
# <#ActiveEnumerable>.average(:age) # => 35.8
|
162
|
+
def average(key)
|
163
|
+
values = values_by_key(key)
|
164
|
+
total = values.inject { |sum, n| sum + n }
|
165
|
+
BigDecimal.new(total) / BigDecimal.new(values.count)
|
166
|
+
end
|
167
|
+
|
168
|
+
# Calculates the minimum value on a given attribute. The value is returned
|
169
|
+
# with the same data type of the attribute, or +nil+ if there's no row.
|
170
|
+
#
|
171
|
+
# <#ActiveEnumerable>.minimum(:age) # => 7
|
172
|
+
def minimum(key)
|
173
|
+
values_by_key(key).min_by { |i| i }
|
174
|
+
end
|
175
|
+
|
176
|
+
# Calculates the maximum value on a given attribute. The value is returned
|
177
|
+
# with the same data type of the attribute, or +nil+ if there's no row.
|
178
|
+
#
|
179
|
+
# <#ActiveEnumerable>.maximum(:age) # => 93
|
180
|
+
def maximum(key)
|
181
|
+
values_by_key(key).max_by { |i| i }
|
182
|
+
end
|
183
|
+
|
184
|
+
# Allows to specify an order attribute:
|
185
|
+
#
|
186
|
+
# <#ActiveEnumerable>.order('name')
|
187
|
+
#
|
188
|
+
# <#ActiveEnumerable>.order(:name)
|
189
|
+
def order(key)
|
190
|
+
__new_relation__(all.sort_by { |item| MethodCaller.new(item).call(key) })
|
191
|
+
end
|
192
|
+
|
193
|
+
# Reverse the existing order clause on the relation.
|
194
|
+
#
|
195
|
+
# <#ActiveEnumerable>.order('name').reverse_order
|
196
|
+
def reverse_order
|
197
|
+
__new_relation__(to_a.reverse)
|
198
|
+
end
|
199
|
+
|
200
|
+
# Returns a chainable relation with zero records.
|
201
|
+
#
|
202
|
+
# Any subsequent condition chained to the returned relation will continue
|
203
|
+
# generating an empty relation.
|
204
|
+
#
|
205
|
+
# Used in cases where a method or scope could return zero records but the
|
206
|
+
# result needs to be chainable.
|
207
|
+
#
|
208
|
+
# For example:
|
209
|
+
#
|
210
|
+
# @posts = current_user.visible_posts.where(name: params[:name])
|
211
|
+
# # => the visible_posts method is expected to return a chainable Relation
|
212
|
+
#
|
213
|
+
# def visible_posts
|
214
|
+
# case role
|
215
|
+
# when 'Country Manager'
|
216
|
+
# <#ActiveEnumerable>.where(country: country)
|
217
|
+
# when 'Reviewer'
|
218
|
+
# <#ActiveEnumerable>.published
|
219
|
+
# when 'Bad User'
|
220
|
+
# <#ActiveEnumerable>.none # It can't be chained if [] is returned.
|
221
|
+
# end
|
222
|
+
# end
|
223
|
+
#
|
224
|
+
def none
|
225
|
+
__new_relation__([])
|
226
|
+
end
|
227
|
+
|
228
|
+
private
|
229
|
+
|
230
|
+
def values_by_key(key)
|
231
|
+
all.map { |obj| obj.send(key) }
|
232
|
+
end
|
233
|
+
end
|
234
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module ActiveEnumerable
|
2
|
+
module Scopes
|
3
|
+
def method_missing(meth, *args, &block)
|
4
|
+
if create_scope_method(meth)
|
5
|
+
send(meth, *args, &block)
|
6
|
+
else
|
7
|
+
super
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def respond_to_missing?(meth, include_private = false)
|
12
|
+
if create_scope_method(meth)
|
13
|
+
true
|
14
|
+
else
|
15
|
+
super
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def create_scope_method(meth)
|
20
|
+
if (scope = self.class.__scoped_methods__.find { |a| a.first == meth })
|
21
|
+
self.define_singleton_method(scope.first) do
|
22
|
+
scope(&scope.last)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def scope(&block)
|
28
|
+
result = instance_exec(&block)
|
29
|
+
if result.is_a? Array
|
30
|
+
__new_relation__(result)
|
31
|
+
else
|
32
|
+
result
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
private :create_scope_method
|
37
|
+
|
38
|
+
module ClassMethods
|
39
|
+
def scope(name, block)
|
40
|
+
__scoped_methods__ << [name, block]
|
41
|
+
end
|
42
|
+
|
43
|
+
def __scoped_methods__
|
44
|
+
@__scoped_methods__ ||= []
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.included(base)
|
49
|
+
base.extend(ClassMethods)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
module ActiveEnumerable
|
2
|
+
module Where
|
3
|
+
class WhereNotChain
|
4
|
+
def initialize(collection, parent_class)
|
5
|
+
@collection = collection
|
6
|
+
@parent_class = parent_class
|
7
|
+
end
|
8
|
+
|
9
|
+
# Returns a new relation expressing WHERE + NOT condition according to
|
10
|
+
# the conditions in the arguments.
|
11
|
+
#
|
12
|
+
# #not accepts conditions as a string, array, or hash. See Where#where for
|
13
|
+
# more details on each format.
|
14
|
+
#
|
15
|
+
# <#ActiveEnumerable>.where.not(name: "Jon")
|
16
|
+
# <#ActiveEnumerable>.where.not(name: nil)
|
17
|
+
# <#ActiveEnumerable>.where.not(name: %w(Ko1 Nobu))
|
18
|
+
# <#ActiveEnumerable>.where.not(name: "Jon", role: "admin")
|
19
|
+
def not(conditions={})
|
20
|
+
@parent_class.call(@collection.reject do |record|
|
21
|
+
Finder.new(record).is_of(conditions)
|
22
|
+
end)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# Returns a new relation, which is the result of filtering the current relation
|
27
|
+
# according to the conditions in the arguments.
|
28
|
+
#
|
29
|
+
# === hash
|
30
|
+
#
|
31
|
+
# #where will accept a hash condition, in which the keys are fields and the values
|
32
|
+
# are values to be searched for.
|
33
|
+
#
|
34
|
+
# Fields can be symbols or strings. Values can be single values, arrays, or ranges.
|
35
|
+
#
|
36
|
+
# <#ActiveEnumerable>.where({ name: "Joe", email: "joe@example.com" })
|
37
|
+
#
|
38
|
+
# <#ActiveEnumerable>.where({ name: ["Alice", "Bob"]})
|
39
|
+
#
|
40
|
+
# <#ActiveEnumerable>.where({ created_at: (Time.now.midnight - 1.day)..Time.now.midnight })
|
41
|
+
#
|
42
|
+
# <#ActiveEnumerable>.where(contracts:[{ created_at: (Time.now.midnight - 1.day)..Time.now.midnight }])
|
43
|
+
#
|
44
|
+
# .or
|
45
|
+
#
|
46
|
+
# Returns a new relation, which is the logical union of this relation and the one passed as an
|
47
|
+
# argument.
|
48
|
+
#
|
49
|
+
# The two relations must be structurally compatible: they must be scoping the same model, and
|
50
|
+
# they must differ only by #where.
|
51
|
+
#
|
52
|
+
# <#ActiveEnumerable>.where(id: 1).or(<#ActiveEnumerable>.where(author_id: 3))
|
53
|
+
#
|
54
|
+
# Additional conditions can be passed to where in hash form.
|
55
|
+
#
|
56
|
+
# <#ActiveEnumerable>.where(id: 1).or(author_id: 3)
|
57
|
+
#
|
58
|
+
def where(conditions=nil)
|
59
|
+
return WhereNotChain.new(all, method(:__new_relation__)) if conditions.nil?
|
60
|
+
enable_or create_where_relation(conditions, to_a.select do |record|
|
61
|
+
Finder.new(record).is_of(conditions)
|
62
|
+
end)
|
63
|
+
end
|
64
|
+
|
65
|
+
def enable_or(relation)
|
66
|
+
pre_where_to_a = to_a
|
67
|
+
relation.define_singleton_method(:or) do |conditions_or_relation|
|
68
|
+
conditions = get_conditions(conditions_or_relation)
|
69
|
+
or_result = create_where_relation(where_conditions, pre_where_to_a).where(conditions)
|
70
|
+
create_where_relation(or_result.where_conditions, relation.to_a.concat(or_result.to_a).uniq)
|
71
|
+
end
|
72
|
+
relation
|
73
|
+
end
|
74
|
+
|
75
|
+
private :enable_or
|
76
|
+
|
77
|
+
def get_conditions(conditions_or_relation)
|
78
|
+
if conditions_or_relation.respond_to?(:where_conditions)
|
79
|
+
conditions_or_relation.where_conditions
|
80
|
+
else
|
81
|
+
conditions_or_relation
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
private :get_conditions
|
86
|
+
|
87
|
+
def where_conditions
|
88
|
+
@where_conditions ||= {}
|
89
|
+
end
|
90
|
+
|
91
|
+
def create_where_relation(conditions, array)
|
92
|
+
nr = __new_relation__(array)
|
93
|
+
nr.where_conditions.merge!(conditions)
|
94
|
+
nr
|
95
|
+
end
|
96
|
+
|
97
|
+
private :create_where_relation
|
98
|
+
end
|
99
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: active_enumerable
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dustin Zeisler
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-02-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -72,7 +72,16 @@ files:
|
|
72
72
|
- bin/console
|
73
73
|
- bin/setup
|
74
74
|
- lib/active_enumerable.rb
|
75
|
+
- lib/active_enumerable/base.rb
|
76
|
+
- lib/active_enumerable/comparable.rb
|
77
|
+
- lib/active_enumerable/enumerable.rb
|
78
|
+
- lib/active_enumerable/finder.rb
|
79
|
+
- lib/active_enumerable/method_caller.rb
|
80
|
+
- lib/active_enumerable/queries.rb
|
81
|
+
- lib/active_enumerable/record_not_found.rb
|
82
|
+
- lib/active_enumerable/scopes.rb
|
75
83
|
- lib/active_enumerable/version.rb
|
84
|
+
- lib/active_enumerable/where.rb
|
76
85
|
homepage: https://github.com/zeisler/active_enumerable
|
77
86
|
licenses:
|
78
87
|
- MIT
|
@@ -93,7 +102,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
93
102
|
version: '0'
|
94
103
|
requirements: []
|
95
104
|
rubyforge_project:
|
96
|
-
rubygems_version: 2.
|
105
|
+
rubygems_version: 2.2.5
|
97
106
|
signing_key:
|
98
107
|
specification_version: 4
|
99
108
|
summary: Gives ActiveRecord like querying methods to ruby enumerable objects.
|