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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e84505bccf077a25c58e6e57c7fe5ed5e626a0990bf7018711936d4d40374d8a
4
- data.tar.gz: c4da9c5f5c3af7b5eb55747a91ee292052cef9cb7cfb134337a91d901534dceb
3
+ metadata.gz: 495ecea300cebeef38e96068866a539533b308e1799937aa9efdb8786e66eaf3
4
+ data.tar.gz: a149a1dc1d69ef1f416393384c7a2d8b7adbae874ca26d3f23b4c219d0df5514
5
5
  SHA512:
6
- metadata.gz: b03cc2c6bf1826e6e95a4277434127bed837808bcfdf1f82bbd8ad888b05f9d11e248eff8577cd0e9d51c6d2ace1d1e7688be1ddf3e09dcb38bc161b622c81a8
7
- data.tar.gz: fe93b20edaa8152c0448ce071c9d782edb3ded08b716708309678aba1a33b513c9bb9505693a9751a7497e3cd08f44fb18ec3f314c1d040a2b08262479eb1748
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:
@@ -45,5 +45,6 @@ Gem::Specification.new do |s|
45
45
  ].flatten
46
46
  s.test_files = s.files.grep(%r{^(test|spec|features)/})
47
47
  s.add_runtime_dependency('activesupport', '>= 5.0.0')
48
+ s.add_development_dependency "pry"
48
49
  s.required_ruby_version = '>= 2.4.0'
49
50
  end
@@ -12,6 +12,7 @@ rescue LoadError
12
12
  end
13
13
 
14
14
  require 'active_hash/base'
15
+ require 'active_hash/relation'
15
16
  require 'active_file/multiple_files'
16
17
  require 'active_file/hash_and_array_files'
17
18
  require 'active_file/base'
@@ -23,7 +23,7 @@ module ActiveHash
23
23
  end
24
24
 
25
25
  def not(options)
26
- return @records if options.blank?
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
- if options.has_key?(:conditions)
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
- def find_by!(options)
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
@@ -1,5 +1,5 @@
1
1
  module ActiveHash
2
2
  module Gem
3
- VERSION = "2.3.0"
3
+ VERSION = "3.0.0"
4
4
  end
5
5
  end
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: 2.3.0
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