active_hash 2.3.0 → 3.0.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
  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