active_hash 2.3.0 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +3 -0
- data/README.md +8 -0
- data/active_hash.gemspec +1 -0
- data/lib/active_hash.rb +1 -0
- data/lib/active_hash/base.rb +7 -94
- data/lib/active_hash/relation.rb +128 -0
- data/lib/active_hash/version.rb +1 -1
- metadata +16 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 495ecea300cebeef38e96068866a539533b308e1799937aa9efdb8786e66eaf3
|
4
|
+
data.tar.gz: a149a1dc1d69ef1f416393384c7a2d8b7adbae874ca26d3f23b4c219d0df5514
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3206ab8403d58c5578fc5b4238a3834ea3fee6fe462618651d7e5377138855df959dec91df632c2882d00bd41b107ab9c46821f6724201cfc9547e0621d6d5bb
|
7
|
+
data.tar.gz: ce189a601b0800ead8e4e0586b72c008272fca5c55bd7da8bac536f28804fd9cb832550bd20a186095070b4fcb5401cdbe691408087ad5b32d1a23406e189fcf
|
data/CHANGELOG
CHANGED
@@ -1,3 +1,6 @@
|
|
1
|
+
2019-09-28 (v3.0.0)
|
2
|
+
- Make #where chainable [#178](https://github.com/zilkey/active_hash/pull/178)
|
3
|
+
|
1
4
|
2019-09-28 (v2.3.0)
|
2
5
|
- Add ::scope method (inspired by ActiveRecord) [#173](https://github.com/zilkey/active_hash/pull/173)
|
3
6
|
- Let `.find(nil)` raise ActiveHash::RecordNotFound (inspired by ActiveRecord) [#174](https://github.com/zilkey/active_hash/pull/174)
|
data/README.md
CHANGED
@@ -15,6 +15,14 @@ ActiveHash also ships with:
|
|
15
15
|
* ActiveFile: a base class that you can use to create file data sources
|
16
16
|
* ActiveYaml: a base class that will turn YAML into a hash and load the data into an ActiveHash object
|
17
17
|
|
18
|
+
## !!! Important notice !!!
|
19
|
+
We have changed returned value to chainable by v3.0.0. It's not just an `Array` instance anymore.
|
20
|
+
If it breaks your application, please report us on [issues](https://github.com/zilkey/active_hash/issues), and use v2.x.x as following..
|
21
|
+
|
22
|
+
```ruby
|
23
|
+
gem 'active_hash', '~> 2.3.0'
|
24
|
+
```
|
25
|
+
|
18
26
|
## Installation
|
19
27
|
|
20
28
|
Bundler:
|
data/active_hash.gemspec
CHANGED
data/lib/active_hash.rb
CHANGED
data/lib/active_hash/base.rb
CHANGED
@@ -23,7 +23,7 @@ module ActiveHash
|
|
23
23
|
end
|
24
24
|
|
25
25
|
def not(options)
|
26
|
-
return @
|
26
|
+
return @scope if options.blank?
|
27
27
|
|
28
28
|
# use index if searching by id
|
29
29
|
if options.key?(:id) || options.key?("id")
|
@@ -32,9 +32,11 @@ module ActiveHash
|
|
32
32
|
end
|
33
33
|
return candidates if options.blank?
|
34
34
|
|
35
|
-
(candidates || @records || []).reject do |record|
|
35
|
+
filtered_records = (candidates || @records || []).reject do |record|
|
36
36
|
match_options?(record, options)
|
37
37
|
end
|
38
|
+
|
39
|
+
ActiveHash::Relation.new(@scope.klass, filtered_records, {})
|
38
40
|
end
|
39
41
|
|
40
42
|
def match_options?(record, options)
|
@@ -182,76 +184,11 @@ module ActiveHash
|
|
182
184
|
record
|
183
185
|
end
|
184
186
|
|
185
|
-
def all(options={})
|
186
|
-
|
187
|
-
where(options[:conditions])
|
188
|
-
else
|
189
|
-
@records ||= []
|
190
|
-
end
|
191
|
-
end
|
192
|
-
|
193
|
-
def where(options = :chain)
|
194
|
-
if options == :chain
|
195
|
-
return WhereChain.new(self)
|
196
|
-
elsif options.blank?
|
197
|
-
return @records
|
198
|
-
end
|
199
|
-
|
200
|
-
# use index if searching by id
|
201
|
-
if options.key?(:id) || options.key?("id")
|
202
|
-
ids = (options.delete(:id) || options.delete("id"))
|
203
|
-
ids = range_to_array(ids) if ids.is_a?(Range)
|
204
|
-
candidates = Array.wrap(ids).map { |id| find_by_id(id) }.compact
|
205
|
-
end
|
206
|
-
return candidates if options.blank?
|
207
|
-
|
208
|
-
(candidates || @records || []).select do |record|
|
209
|
-
match_options?(record, options)
|
210
|
-
end
|
211
|
-
end
|
212
|
-
|
213
|
-
def find_by(options)
|
214
|
-
where(options).first
|
187
|
+
def all(options = {})
|
188
|
+
ActiveHash::Relation.new(self, @records || [], options[:conditions] || {})
|
215
189
|
end
|
216
190
|
|
217
|
-
|
218
|
-
find_by(options) || (raise RecordNotFound.new("Couldn't find #{name}"))
|
219
|
-
end
|
220
|
-
|
221
|
-
def match_options?(record, options)
|
222
|
-
options.all? do |col, match|
|
223
|
-
if match.kind_of?(Array)
|
224
|
-
match.any? { |v| normalize(v) == normalize(record[col]) }
|
225
|
-
else
|
226
|
-
normalize(record[col]) == normalize(match)
|
227
|
-
end
|
228
|
-
end
|
229
|
-
end
|
230
|
-
|
231
|
-
private :match_options?
|
232
|
-
|
233
|
-
def normalize(v)
|
234
|
-
v.respond_to?(:to_sym) ? v.to_sym : v
|
235
|
-
end
|
236
|
-
|
237
|
-
private :normalize
|
238
|
-
|
239
|
-
def range_to_array(range)
|
240
|
-
return range.to_a unless range.end.nil?
|
241
|
-
|
242
|
-
e = data.last[:id]
|
243
|
-
(range.begin..e).to_a
|
244
|
-
end
|
245
|
-
|
246
|
-
private :range_to_array
|
247
|
-
|
248
|
-
def count
|
249
|
-
all.length
|
250
|
-
end
|
251
|
-
|
252
|
-
def pluck(*column_names)
|
253
|
-
column_names.map { |column_name| all.map(&column_name.to_sym) }.inject(&:zip)
|
254
|
-
end
|
191
|
+
delegate :where, :find, :find_by, :find_by!, :find_by_id, :count, :pluck, :first, :last, to: :all
|
255
192
|
|
256
193
|
def transaction
|
257
194
|
yield
|
@@ -269,30 +206,6 @@ module ActiveHash
|
|
269
206
|
@records = []
|
270
207
|
end
|
271
208
|
|
272
|
-
def find(id, * args)
|
273
|
-
case id
|
274
|
-
when :all
|
275
|
-
all
|
276
|
-
when :first
|
277
|
-
all(*args).first
|
278
|
-
when Array
|
279
|
-
id.map { |i| find(i) }
|
280
|
-
when nil
|
281
|
-
raise RecordNotFound.new("Couldn't find #{name} without an ID")
|
282
|
-
else
|
283
|
-
find_by_id(id) || begin
|
284
|
-
raise RecordNotFound.new("Couldn't find #{name} with ID=#{id}")
|
285
|
-
end
|
286
|
-
end
|
287
|
-
end
|
288
|
-
|
289
|
-
def find_by_id(id)
|
290
|
-
index = record_index[id.to_s]
|
291
|
-
index and @records[index]
|
292
|
-
end
|
293
|
-
|
294
|
-
delegate :first, :last, :to => :all
|
295
|
-
|
296
209
|
def fields(*args)
|
297
210
|
options = args.extract_options!
|
298
211
|
args.each do |field|
|
@@ -0,0 +1,128 @@
|
|
1
|
+
module ActiveHash
|
2
|
+
class Relation
|
3
|
+
include Enumerable
|
4
|
+
|
5
|
+
delegate :each, to: :records # Make Enumerable work
|
6
|
+
delegate :equal?, :==, :===, :eql?, to: :records
|
7
|
+
delegate :empty?, :length, :first, :second, :third, :last, to: :records
|
8
|
+
|
9
|
+
def initialize(klass, all_records, query_hash = nil)
|
10
|
+
self.klass = klass
|
11
|
+
self.all_records = all_records
|
12
|
+
self.query_hash = query_hash
|
13
|
+
self.records_dirty = false
|
14
|
+
self
|
15
|
+
end
|
16
|
+
|
17
|
+
def where(query_hash = :chain)
|
18
|
+
return ActiveHash::Base::WhereChain.new(self) if query_hash == :chain
|
19
|
+
|
20
|
+
self.records_dirty = true unless query_hash.nil? || query_hash.keys.empty?
|
21
|
+
self.query_hash.merge!(query_hash || {})
|
22
|
+
self
|
23
|
+
end
|
24
|
+
|
25
|
+
def all(options = {})
|
26
|
+
if options.has_key?(:conditions)
|
27
|
+
where(options[:conditions])
|
28
|
+
else
|
29
|
+
where({})
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def find_by(options)
|
34
|
+
where(options).first
|
35
|
+
end
|
36
|
+
|
37
|
+
def find_by!(options)
|
38
|
+
find_by(options) || (raise RecordNotFound.new("Couldn't find #{klass.name}"))
|
39
|
+
end
|
40
|
+
|
41
|
+
def find(id, *args)
|
42
|
+
case id
|
43
|
+
when :all
|
44
|
+
all
|
45
|
+
when :first
|
46
|
+
all(*args).first
|
47
|
+
when Array
|
48
|
+
id.map { |i| find(i) }
|
49
|
+
when nil
|
50
|
+
raise RecordNotFound.new("Couldn't find #{klass.name} without an ID")
|
51
|
+
else
|
52
|
+
find_by_id(id) || begin
|
53
|
+
raise RecordNotFound.new("Couldn't find #{klass.name} with ID=#{id}")
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def find_by_id(id)
|
59
|
+
index = klass.send(:record_index)[id.to_s] # TODO: Make index in Base publicly readable instead of using send?
|
60
|
+
index and records[index]
|
61
|
+
end
|
62
|
+
|
63
|
+
def count
|
64
|
+
length
|
65
|
+
end
|
66
|
+
|
67
|
+
def pluck(*column_names)
|
68
|
+
column_names.map { |column_name| all.map(&column_name.to_sym) }.inject(&:zip)
|
69
|
+
end
|
70
|
+
|
71
|
+
def reload
|
72
|
+
@records = filter_all_records_by_query_hash
|
73
|
+
end
|
74
|
+
|
75
|
+
attr_reader :query_hash, :klass, :all_records, :records_dirty
|
76
|
+
|
77
|
+
private
|
78
|
+
|
79
|
+
attr_writer :query_hash, :klass, :all_records, :records_dirty
|
80
|
+
|
81
|
+
def records
|
82
|
+
if @records.nil? || records_dirty
|
83
|
+
reload
|
84
|
+
else
|
85
|
+
@records
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def filter_all_records_by_query_hash
|
90
|
+
self.records_dirty = false
|
91
|
+
return all_records if query_hash.blank?
|
92
|
+
|
93
|
+
# use index if searching by id
|
94
|
+
if query_hash.key?(:id) || query_hash.key?("id")
|
95
|
+
ids = (query_hash.delete(:id) || query_hash.delete("id"))
|
96
|
+
ids = range_to_array(ids) if ids.is_a?(Range)
|
97
|
+
candidates = Array.wrap(ids).map { |id| klass.find_by_id(id) }.compact
|
98
|
+
end
|
99
|
+
|
100
|
+
return candidates if query_hash.blank?
|
101
|
+
|
102
|
+
(candidates || all_records || []).select do |record|
|
103
|
+
match_options?(record, query_hash)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def match_options?(record, options)
|
108
|
+
options.all? do |col, match|
|
109
|
+
if match.kind_of?(Array)
|
110
|
+
match.any? { |v| normalize(v) == normalize(record[col]) }
|
111
|
+
else
|
112
|
+
normalize(record[col]) == normalize(match)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def normalize(v)
|
118
|
+
v.respond_to?(:to_sym) ? v.to_sym : v
|
119
|
+
end
|
120
|
+
|
121
|
+
def range_to_array(range)
|
122
|
+
return range.to_a unless range.end.nil?
|
123
|
+
|
124
|
+
e = records.last[:id]
|
125
|
+
(range.begin..e).to_a
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
data/lib/active_hash/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: active_hash
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 3.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jeff Dean
|
@@ -45,6 +45,20 @@ dependencies:
|
|
45
45
|
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: 5.0.0
|
48
|
+
- !ruby/object:Gem::Dependency
|
49
|
+
name: pry
|
50
|
+
requirement: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
48
62
|
description: Includes the ability to specify data using hashes, yml files or JSON
|
49
63
|
files
|
50
64
|
email: jeff@zilkey.com
|
@@ -61,6 +75,7 @@ files:
|
|
61
75
|
- lib/active_file/multiple_files.rb
|
62
76
|
- lib/active_hash.rb
|
63
77
|
- lib/active_hash/base.rb
|
78
|
+
- lib/active_hash/relation.rb
|
64
79
|
- lib/active_hash/version.rb
|
65
80
|
- lib/active_json/base.rb
|
66
81
|
- lib/active_yaml/aliases.rb
|