frozen_record 0.21.1 → 0.22.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: 0a25a269067396d2e6054a57c514b1251e39dca90928e7bdd837bfbb9ef8d2cf
4
- data.tar.gz: 77b55ee24e39590dd213c157b22e3707c8f551a051df34f516a1e9d061d4eb6a
3
+ metadata.gz: bfb835436fc605e43a6b928ae9e8149ec80f726dd0650801c3e1e2e4d46dba1d
4
+ data.tar.gz: 1b2d08e68b018cb8a0c18e68420dab5930c51c3cf42c559c841eb340b0b0226d
5
5
  SHA512:
6
- metadata.gz: a1d23916d54278598ec3ba29e5c1000f4adb0f13566db9be7900e5344199e36fe02254539a531a26d8b2d211e62f3916438c98032e7166795fbbf1681a170b91
7
- data.tar.gz: af66cb72d621f8d6008de238d7f0846bf576200437fbdead4cfcdd1d598af62ac4d29bd801efd14420bfddb4470301312eb992628e2c7185e21b8dbee0381f6e
6
+ metadata.gz: 8d7ae3739cc1a172d8a54e1f87513b307db69c937522032fbcf845a4f11141f7e373739f79c98e15216f6ce17ac4a0410cc6f72033b9a9cbb31ec260e650ea6c
7
+ data.tar.gz: 9f88ee2a8186533cbd8482704d2e02bc275e73af310b24801b7cebb37320ab6297038b3efa6368ea9ce0122de7aaaa56f1180fed4c9eefe1dc5de059e35ccbd0
data/README.md CHANGED
@@ -1,8 +1,6 @@
1
1
  # FrozenRecord
2
2
 
3
3
  [![Build Status](https://secure.travis-ci.org/byroot/frozen_record.svg)](http://travis-ci.org/byroot/frozen_record)
4
- [![Code Climate](https://codeclimate.com/github/byroot/frozen_record.svg)](https://codeclimate.com/github/byroot/frozen_record)
5
- [![Coverage Status](https://coveralls.io/repos/byroot/frozen_record/badge.svg)](https://coveralls.io/r/byroot/frozen_record)
6
4
  [![Gem Version](https://badge.fury.io/rb/frozen_record.svg)](http://badge.fury.io/rb/frozen_record)
7
5
 
8
6
  ActiveRecord-like interface for **read only** access to static data files.
@@ -0,0 +1,34 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require_relative 'setup'
5
+
6
+ records = FrozenRecord::Backends::Yaml.load(Country.file_path)
7
+ large_records = 100.times.flat_map do |i|
8
+ records.map do |record|
9
+ new_record = record.dup
10
+ new_record['id'] += 10 * i
11
+ new_record['name'] += i.to_s
12
+ new_record
13
+ end
14
+ end
15
+
16
+ File.write('/tmp/frozen-record-bench-countries.yml', YAML.dump(large_records))
17
+
18
+ class LargeCountry < Country
19
+ class << self
20
+ def file_path
21
+ '/tmp/frozen-record-bench-countries.yml'
22
+ end
23
+ end
24
+ end
25
+
26
+ puts "=== simple scalar match ==="
27
+ Benchmark.ips do |x|
28
+ x.report('simple') { LargeCountry.nato.size }
29
+ end
30
+
31
+ puts "=== range match ==="
32
+ Benchmark.ips do |x|
33
+ x.report('range') { LargeCountry.where(density: 100...200).size }
34
+ end
@@ -24,6 +24,4 @@ Gem::Specification.new do |spec|
24
24
 
25
25
  spec.add_development_dependency 'rake'
26
26
  spec.add_development_dependency 'rspec'
27
- spec.add_development_dependency 'pry'
28
- spec.add_development_dependency 'coveralls'
29
27
  end
@@ -3,6 +3,8 @@
3
3
  module FrozenRecord
4
4
  module Backends
5
5
  module Yaml
6
+ autoload :ERB, 'erb'
7
+
6
8
  extend self
7
9
 
8
10
  # Transforms the model name into a valid filename.
@@ -83,8 +83,9 @@ module FrozenRecord
83
83
  store[:scope] = scope
84
84
  end
85
85
 
86
- delegate :find, :find_by_id, :find_by, :find_by!, :where, :first, :first!, :last, :last!, :pluck, :ids, :order, :limit, :offset,
87
- :minimum, :maximum, :average, :sum, :count, to: :current_scope
86
+ delegate :each, :find, :find_each, :find_by_id, :find_by, :find_by!, :where, :first, :first!, :last, :last!,
87
+ :pluck, :ids, :order, :limit, :offset, :minimum, :maximum, :average, :sum, :count,
88
+ to: :current_scope
88
89
 
89
90
  def file_path
90
91
  raise ArgumentError, "You must define `#{name}.base_path`" unless base_path
@@ -200,7 +201,9 @@ module FrozenRecord
200
201
  def list_attributes(records)
201
202
  attributes = Set.new
202
203
  records.each do |record|
203
- attributes.merge(record.keys)
204
+ record.each_key do |key|
205
+ attributes.add(key)
206
+ end
204
207
  end
205
208
  attributes
206
209
  end
@@ -19,12 +19,11 @@ module FrozenRecord
19
19
  false
20
20
  end
21
21
 
22
- def query(value)
23
- case value
24
- when Array, Range
25
- lookup_multi(value)
22
+ def query(matcher)
23
+ if matcher.ranged?
24
+ lookup_multi(matcher.value)
26
25
  else
27
- lookup(value)
26
+ lookup(matcher.value)
28
27
  end
29
28
  end
30
29
 
@@ -9,6 +9,7 @@ module FrozenRecord
9
9
  ].to_set
10
10
 
11
11
  delegate :first, :last, :length, :collect, :map, :each, :all?, :include?, :to_ary, :to_json, :as_json, :count, to: :to_a
12
+ alias_method :find_each, :each
12
13
  if defined? ActiveModel::Serializers::Xml
13
14
  delegate :to_xml, to: :to_a
14
15
  end
@@ -187,8 +188,8 @@ module FrozenRecord
187
188
  end
188
189
 
189
190
  records.select do |record|
190
- unindexed_where_values.all? { |attr, value| compare_value(record[attr], value) } &&
191
- !@where_not_values.any? { |attr, value| compare_value(record[attr], value) }
191
+ unindexed_where_values.all? { |attr, matcher| matcher.match?(record[attr]) } &&
192
+ !@where_not_values.any? { |attr, matcher| matcher.match?(record[attr]) }
192
193
  end
193
194
  end
194
195
 
@@ -238,12 +239,12 @@ module FrozenRecord
238
239
  end
239
240
 
240
241
  def where!(criterias)
241
- @where_values += criterias.map { |k, v| [k.to_s, v] }
242
+ @where_values += criterias.map { |k, v| [k.to_s, Matcher.for(v)] }
242
243
  self
243
244
  end
244
245
 
245
246
  def where_not!(criterias)
246
- @where_not_values += criterias.map { |k, v| [k.to_s, v] }
247
+ @where_not_values += criterias.map { |k, v| [k.to_s, Matcher.for(v)] }
247
248
  self
248
249
  end
249
250
 
@@ -266,9 +267,62 @@ module FrozenRecord
266
267
 
267
268
  private
268
269
 
269
- def compare_value(actual, requested)
270
- return actual == requested unless requested.is_a?(Array) || requested.is_a?(Range)
271
- requested.include?(actual)
270
+ class Matcher
271
+ class << self
272
+ def for(value)
273
+ case value
274
+ when Array
275
+ IncludeMatcher.new(value)
276
+ when Range
277
+ CoverMatcher.new(value)
278
+ else
279
+ new(value)
280
+ end
281
+ end
282
+ end
283
+
284
+ attr_reader :value
285
+
286
+ def hash
287
+ self.class.hash ^ value.hash
288
+ end
289
+
290
+ def initialize(value)
291
+ @value = value
292
+ end
293
+
294
+ def ranged?
295
+ false
296
+ end
297
+
298
+ def match?(other)
299
+ @value == other
300
+ end
301
+
302
+ def ==(other)
303
+ self.class == other.class && value == other.value
304
+ end
305
+ alias_method :eql?, :==
306
+ end
307
+
308
+ class IncludeMatcher < Matcher
309
+ def ranged?
310
+ true
311
+ end
312
+
313
+ def match?(other)
314
+ @value.include?(other)
315
+ end
316
+ end
317
+
318
+ class CoverMatcher < Matcher
319
+ def ranged?
320
+ true
321
+ end
322
+
323
+ def match?(other)
324
+ @value.cover?(other)
325
+ end
272
326
  end
273
327
  end
274
328
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module FrozenRecord
4
- VERSION = '0.21.1'
4
+ VERSION = '0.22.0'
5
5
  end
@@ -90,6 +90,32 @@ RSpec.shared_examples 'main' do
90
90
 
91
91
  end
92
92
 
93
+ describe '.each' do
94
+
95
+ it 'yields the records one by one' do
96
+ count = 0
97
+ Country.each do |country|
98
+ expect(country).to be_a Country
99
+ count += 1
100
+ end
101
+ expect(count).to be == Country.count
102
+ end
103
+
104
+ end
105
+
106
+ describe '.find_each' do
107
+
108
+ it 'yields the records one by one' do
109
+ count = 0
110
+ Country.find_each do |country|
111
+ expect(country).to be_a Country
112
+ count += 1
113
+ end
114
+ expect(count).to be == Country.count
115
+ end
116
+
117
+ end
118
+
93
119
  describe '.memsize' do
94
120
 
95
121
  it 'retuns the records memory footprint' do
data/spec/scope_spec.rb CHANGED
@@ -180,6 +180,20 @@ describe 'querying' do
180
180
 
181
181
  end
182
182
 
183
+ describe '.find_each' do
184
+
185
+ it 'yields the records one by one' do
186
+ scope = Country.where(name: 'France')
187
+ count = 0
188
+ scope.find_each do |country|
189
+ expect(country).to be_a Country
190
+ count += 1
191
+ end
192
+ expect(count).to be == 1
193
+ end
194
+
195
+ end
196
+
183
197
  describe '.where' do
184
198
 
185
199
  it 'returns the records that match given criterias' do
@@ -445,8 +459,8 @@ describe 'querying' do
445
459
  it 'returns true when the same scope has be rechained' do
446
460
  scope_a = Country.nato.republics.nato.republics
447
461
  scope_b = Country.republics.nato
448
- expect(scope_a.instance_variable_get(:@where_values)).to be == [['nato', true], ['king', nil], ['nato', true], ['king', nil]]
449
- expect(scope_b.instance_variable_get(:@where_values)).to be == [['king', nil], ['nato', true]]
462
+ expect(scope_a.instance_variable_get(:@where_values).map { |k, v| [k, v.value] }).to be == [['nato', true], ['king', nil], ['nato', true], ['king', nil]]
463
+ expect(scope_b.instance_variable_get(:@where_values).map { |k, v| [k, v.value] }).to be == [['king', nil], ['nato', true]]
450
464
  expect(scope_a).to be == scope_b
451
465
  end
452
466
  end
data/spec/spec_helper.rb CHANGED
@@ -2,16 +2,6 @@ lib = File.expand_path('../lib', __FILE__)
2
2
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
3
 
4
4
  minimal = ENV['MINIMAL'] == 'true'
5
-
6
- require 'pry'
7
- require 'simplecov'
8
- require 'coveralls'
9
- SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
10
- SimpleCov::Formatter::HTMLFormatter,
11
- Coveralls::SimpleCov::Formatter
12
- ]
13
- SimpleCov.start
14
-
15
5
  require 'objspace'
16
6
 
17
7
  if minimal
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: frozen_record
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.21.1
4
+ version: 0.22.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jean Boussier
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-01-27 00:00:00.000000000 Z
11
+ date: 2021-04-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel
@@ -66,34 +66,6 @@ dependencies:
66
66
  - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
- - !ruby/object:Gem::Dependency
70
- name: pry
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - ">="
74
- - !ruby/object:Gem::Version
75
- version: '0'
76
- type: :development
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - ">="
81
- - !ruby/object:Gem::Version
82
- version: '0'
83
- - !ruby/object:Gem::Dependency
84
- name: coveralls
85
- requirement: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - ">="
88
- - !ruby/object:Gem::Version
89
- version: '0'
90
- type: :development
91
- prerelease: false
92
- version_requirements: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - ">="
95
- - !ruby/object:Gem::Version
96
- version: '0'
97
69
  description:
98
70
  email:
99
71
  - jean.boussier@gmail.com
@@ -110,6 +82,7 @@ files:
110
82
  - Rakefile
111
83
  - benchmark/attribute-read
112
84
  - benchmark/memory-usage
85
+ - benchmark/querying
113
86
  - benchmark/setup.rb
114
87
  - frozen_record.gemspec
115
88
  - lib/frozen_record.rb