frozen_record 0.20.1 → 0.22.2
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/.github/workflows/main.yml +32 -0
- data/README.md +0 -2
- data/benchmark/querying +34 -0
- data/frozen_record.gemspec +0 -3
- data/lib/frozen_record.rb +2 -27
- data/lib/frozen_record/backends/empty.json +1 -0
- data/lib/frozen_record/backends/json.rb +21 -3
- data/lib/frozen_record/backends/yaml.rb +39 -3
- data/lib/frozen_record/base.rb +12 -15
- data/lib/frozen_record/compact.rb +6 -11
- data/lib/frozen_record/index.rb +4 -5
- data/lib/frozen_record/minimal.rb +27 -0
- data/lib/frozen_record/scope.rb +62 -8
- data/lib/frozen_record/serialization.rb +13 -0
- data/lib/frozen_record/version.rb +1 -1
- data/spec/frozen_record_spec.rb +26 -0
- data/spec/scope_spec.rb +17 -3
- data/spec/spec_helper.rb +11 -10
- metadata +8 -46
- data/.travis.yml +0 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 46d80cfe87901ec547852256bff7eed06ac990a7bb9705b93fa13464354c5af5
|
4
|
+
data.tar.gz: 63f48c770a8e86d867382f0333f1c5d6d48b64ece3b849717fd840945f0781ff
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0a5c7c217742022ff5d23532cc54c04f040ae83e9e05c191783a49db5012c2c95f2815a85a8743e00bd467bbff9fb451d94ba5a75cdd80bde71dee66ccb2a256
|
7
|
+
data.tar.gz: 587dc2bcd6cec261cd53c9be8cfe696b7f4944d1c55b5cea55945b7826112eed2829a323c617c906dfcd039d72578e4b4ba5cb790a1ba1131277c6076dafcafc
|
@@ -0,0 +1,32 @@
|
|
1
|
+
name: CI
|
2
|
+
|
3
|
+
on: [push, pull_request]
|
4
|
+
|
5
|
+
jobs:
|
6
|
+
build:
|
7
|
+
runs-on: ubuntu-latest
|
8
|
+
strategy:
|
9
|
+
matrix:
|
10
|
+
ruby: [ '2.5', '2.6', '2.7', '3.0' ]
|
11
|
+
minimal: [ false, true ]
|
12
|
+
name: Ruby ${{ matrix.ruby }} tests, minimal=${{ matrix.minimal }}
|
13
|
+
steps:
|
14
|
+
- uses: actions/checkout@v2
|
15
|
+
- name: Setup Ruby
|
16
|
+
uses: ruby/setup-ruby@v1
|
17
|
+
with:
|
18
|
+
ruby-version: ${{ matrix.ruby }}
|
19
|
+
- uses: actions/cache@v2
|
20
|
+
with:
|
21
|
+
path: vendor/bundle
|
22
|
+
key: ${{ runner.os }}-${{ matrix.ruby }}-gems-${{ hashFiles('Gemfile', 'frozen_record.gemspec') }}
|
23
|
+
restore-keys: |
|
24
|
+
${{ runner.os }}-${{ matrix.ruby }}-gems-
|
25
|
+
- name: Bundle install
|
26
|
+
run: |
|
27
|
+
gem install bundler
|
28
|
+
bundle install --jobs 4 --retry 3 --path=vendor/bundle
|
29
|
+
- name: Run tests
|
30
|
+
env:
|
31
|
+
MINIMAL: ${{ matrix.minimal }}
|
32
|
+
run: bundle exec rake
|
data/README.md
CHANGED
@@ -1,8 +1,6 @@
|
|
1
1
|
# FrozenRecord
|
2
2
|
|
3
3
|
[](http://travis-ci.org/byroot/frozen_record)
|
4
|
-
[](https://codeclimate.com/github/byroot/frozen_record)
|
5
|
-
[](https://coveralls.io/r/byroot/frozen_record)
|
6
4
|
[](http://badge.fury.io/rb/frozen_record)
|
7
5
|
|
8
6
|
ActiveRecord-like interface for **read only** access to static data files.
|
data/benchmark/querying
ADDED
@@ -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
|
data/frozen_record.gemspec
CHANGED
@@ -22,9 +22,6 @@ Gem::Specification.new do |spec|
|
|
22
22
|
spec.add_runtime_dependency 'activemodel'
|
23
23
|
spec.add_runtime_dependency 'dedup'
|
24
24
|
|
25
|
-
spec.add_development_dependency 'bundler'
|
26
25
|
spec.add_development_dependency 'rake'
|
27
26
|
spec.add_development_dependency 'rspec'
|
28
|
-
spec.add_development_dependency 'pry'
|
29
|
-
spec.add_development_dependency 'coveralls'
|
30
27
|
end
|
data/lib/frozen_record.rb
CHANGED
@@ -1,30 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require '
|
4
|
-
require '
|
5
|
-
require 'active_support/all'
|
6
|
-
require 'active_model'
|
7
|
-
|
8
|
-
require 'dedup'
|
9
|
-
|
10
|
-
require 'frozen_record/version'
|
11
|
-
require 'frozen_record/scope'
|
12
|
-
require 'frozen_record/index'
|
13
|
-
require 'frozen_record/base'
|
14
|
-
require 'frozen_record/compact'
|
15
|
-
|
16
|
-
module FrozenRecord
|
17
|
-
RecordNotFound = Class.new(StandardError)
|
18
|
-
|
19
|
-
class << self
|
20
|
-
attr_accessor :deprecated_yaml_erb_backend
|
21
|
-
|
22
|
-
def eager_load!
|
23
|
-
Base.descendants.each(&:eager_load!)
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
self.deprecated_yaml_erb_backend = true
|
28
|
-
end
|
29
|
-
|
3
|
+
require 'frozen_record/minimal'
|
4
|
+
require 'frozen_record/serialization'
|
30
5
|
require 'frozen_record/railtie' if defined?(Rails)
|
@@ -0,0 +1 @@
|
|
1
|
+
true
|
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
require 'json'
|
2
3
|
|
3
4
|
module FrozenRecord
|
4
5
|
module Backends
|
@@ -9,9 +10,26 @@ module FrozenRecord
|
|
9
10
|
"#{model_name.underscore.pluralize}.json"
|
10
11
|
end
|
11
12
|
|
12
|
-
|
13
|
-
|
14
|
-
|
13
|
+
if JSON.respond_to?(:load_file)
|
14
|
+
supports_freeze = begin
|
15
|
+
JSON.load_file(File.expand_path('../empty.json', __FILE__), freeze: true)
|
16
|
+
rescue ArgumentError
|
17
|
+
false
|
18
|
+
end
|
19
|
+
|
20
|
+
if supports_freeze
|
21
|
+
def load(file_path)
|
22
|
+
JSON.load_file(file_path, freeze: true) || Dedup::EMPTY_ARRAY
|
23
|
+
end
|
24
|
+
else
|
25
|
+
def load(file_path)
|
26
|
+
Dedup.deep_intern!(JSON.load_file(file_path) || Dedup::EMPTY_ARRAY)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
else
|
30
|
+
def load(file_path)
|
31
|
+
Dedup.deep_intern!(JSON.parse(File.read(file_path)) || Dedup::EMPTY_ARRAY)
|
32
|
+
end
|
15
33
|
end
|
16
34
|
end
|
17
35
|
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.
|
@@ -34,15 +36,49 @@ module FrozenRecord
|
|
34
36
|
end
|
35
37
|
end
|
36
38
|
|
37
|
-
|
39
|
+
load_string(yml_data)
|
38
40
|
else
|
39
41
|
if file_path.end_with?('.erb')
|
40
|
-
|
42
|
+
load_string(ERB.new(File.read(file_path)).result)
|
41
43
|
else
|
42
|
-
|
44
|
+
load_file(file_path)
|
43
45
|
end
|
44
46
|
end
|
45
47
|
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
supports_freeze = begin
|
52
|
+
YAML.load_file(File.expand_path('../empty.json', __FILE__), freeze: true)
|
53
|
+
rescue ArgumentError
|
54
|
+
false
|
55
|
+
end
|
56
|
+
|
57
|
+
if YAML.respond_to?(:unsafe_load_file)
|
58
|
+
def load_file(path)
|
59
|
+
YAML.unsafe_load_file(path, freeze: true) || Dedup::EMPTY_ARRAY
|
60
|
+
end
|
61
|
+
|
62
|
+
def load_string(yaml)
|
63
|
+
YAML.unsafe_load(yaml, freeze: true) || Dedup::EMPTY_ARRAY
|
64
|
+
end
|
65
|
+
elsif supports_freeze
|
66
|
+
def load_file(path)
|
67
|
+
YAML.load_file(path, freeze: true) || Dedup::EMPTY_ARRAY
|
68
|
+
end
|
69
|
+
|
70
|
+
def load_string(yaml)
|
71
|
+
YAML.load(yaml, freeze: true) || Dedup::EMPTY_ARRAY
|
72
|
+
end
|
73
|
+
else
|
74
|
+
def load_file(path)
|
75
|
+
Dedup.deep_intern!(YAML.load_file(path) || Dedup::EMPTY_ARRAY)
|
76
|
+
end
|
77
|
+
|
78
|
+
def load_string(yaml)
|
79
|
+
Dedup.deep_intern!(YAML.load(yaml) || Dedup::EMPTY_ARRAY)
|
80
|
+
end
|
81
|
+
end
|
46
82
|
end
|
47
83
|
end
|
48
84
|
end
|
data/lib/frozen_record/base.rb
CHANGED
@@ -1,9 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'set'
|
4
3
|
require 'active_support/descendants_tracker'
|
5
4
|
require 'frozen_record/backends'
|
6
|
-
require 'objspace'
|
7
5
|
|
8
6
|
module FrozenRecord
|
9
7
|
class Base
|
@@ -11,11 +9,6 @@ module FrozenRecord
|
|
11
9
|
extend ActiveModel::Naming
|
12
10
|
include ActiveModel::Conversion
|
13
11
|
include ActiveModel::AttributeMethods
|
14
|
-
include ActiveModel::Serializers::JSON
|
15
|
-
|
16
|
-
if defined? ActiveModel::Serializers::Xml
|
17
|
-
include ActiveModel::Serializers::Xml
|
18
|
-
end
|
19
12
|
|
20
13
|
FIND_BY_PATTERN = /\Afind_by_(\w+)(!?)/
|
21
14
|
FALSY_VALUES = [false, nil, 0, -''].to_set
|
@@ -52,7 +45,7 @@ module FrozenRecord
|
|
52
45
|
alias_method :set_default_attributes, :default_attributes=
|
53
46
|
private :set_default_attributes
|
54
47
|
def default_attributes=(default_attributes)
|
55
|
-
set_default_attributes(Dedup.deep_intern!(default_attributes.
|
48
|
+
set_default_attributes(Dedup.deep_intern!(default_attributes.transform_keys(&:to_s)))
|
56
49
|
end
|
57
50
|
|
58
51
|
alias_method :set_primary_key, :primary_key=
|
@@ -90,8 +83,9 @@ module FrozenRecord
|
|
90
83
|
store[:scope] = scope
|
91
84
|
end
|
92
85
|
|
93
|
-
delegate :find, :find_by_id, :find_by, :find_by!, :where, :first, :first!, :last, :last!,
|
94
|
-
:minimum, :maximum, :average, :sum, :count,
|
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
|
95
89
|
|
96
90
|
def file_path
|
97
91
|
raise ArgumentError, "You must define `#{name}.base_path`" unless base_path
|
@@ -146,8 +140,9 @@ module FrozenRecord
|
|
146
140
|
|
147
141
|
@records ||= begin
|
148
142
|
records = backend.load(file_path)
|
149
|
-
|
150
|
-
|
143
|
+
if default_attributes
|
144
|
+
records = records.map { |r| assign_defaults!(r.dup).freeze }.freeze
|
145
|
+
end
|
151
146
|
@attributes = list_attributes(records).freeze
|
152
147
|
define_attribute_methods(@attributes.to_a)
|
153
148
|
records = records.map { |r| load(r) }.freeze
|
@@ -164,7 +159,7 @@ module FrozenRecord
|
|
164
159
|
private :load
|
165
160
|
|
166
161
|
def new(attrs = {})
|
167
|
-
load(assign_defaults!(attrs.
|
162
|
+
load(assign_defaults!(attrs.transform_keys(&:to_s)))
|
168
163
|
end
|
169
164
|
|
170
165
|
private
|
@@ -206,7 +201,9 @@ module FrozenRecord
|
|
206
201
|
def list_attributes(records)
|
207
202
|
attributes = Set.new
|
208
203
|
records.each do |record|
|
209
|
-
|
204
|
+
record.each_key do |key|
|
205
|
+
attributes.add(key)
|
206
|
+
end
|
210
207
|
end
|
211
208
|
attributes
|
212
209
|
end
|
@@ -245,7 +242,7 @@ module FrozenRecord
|
|
245
242
|
private
|
246
243
|
|
247
244
|
def attribute?(attribute_name)
|
248
|
-
FALSY_VALUES.
|
245
|
+
!FALSY_VALUES.include?(self[attribute_name]) && self[attribute_name].present?
|
249
246
|
end
|
250
247
|
|
251
248
|
def attribute_method?(attribute_name)
|
@@ -13,8 +13,9 @@ module FrozenRecord
|
|
13
13
|
|
14
14
|
@records ||= begin
|
15
15
|
records = backend.load(file_path)
|
16
|
-
|
17
|
-
|
16
|
+
if default_attributes
|
17
|
+
records = records.map { |r| assign_defaults!(r.dup).freeze }.freeze
|
18
|
+
end
|
18
19
|
@attributes = list_attributes(records).freeze
|
19
20
|
build_attributes_cache
|
20
21
|
define_attribute_methods(@attributes.to_a)
|
@@ -24,14 +25,8 @@ module FrozenRecord
|
|
24
25
|
end
|
25
26
|
end
|
26
27
|
|
27
|
-
|
28
|
-
|
29
|
-
owner << "attr_reader #{attr.inspect}"
|
30
|
-
end
|
31
|
-
else
|
32
|
-
def define_method_attribute(attr)
|
33
|
-
generated_attribute_methods.attr_reader(attr)
|
34
|
-
end
|
28
|
+
def define_method_attribute(attr, **)
|
29
|
+
generated_attribute_methods.attr_reader(attr)
|
35
30
|
end
|
36
31
|
|
37
32
|
attr_reader :_attributes_cache
|
@@ -73,7 +68,7 @@ module FrozenRecord
|
|
73
68
|
|
74
69
|
def attribute?(attribute_name)
|
75
70
|
val = self[attribute_name]
|
76
|
-
Base::FALSY_VALUES.
|
71
|
+
!Base::FALSY_VALUES.include?(val) && val.present?
|
77
72
|
end
|
78
73
|
end
|
79
74
|
end
|
data/lib/frozen_record/index.rb
CHANGED
@@ -19,12 +19,11 @@ module FrozenRecord
|
|
19
19
|
false
|
20
20
|
end
|
21
21
|
|
22
|
-
def query(
|
23
|
-
|
24
|
-
|
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
|
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'yaml'
|
4
|
+
require 'set'
|
5
|
+
require 'active_model'
|
6
|
+
|
7
|
+
require 'dedup'
|
8
|
+
|
9
|
+
require 'frozen_record/version'
|
10
|
+
require 'frozen_record/scope'
|
11
|
+
require 'frozen_record/index'
|
12
|
+
require 'frozen_record/base'
|
13
|
+
require 'frozen_record/compact'
|
14
|
+
|
15
|
+
module FrozenRecord
|
16
|
+
RecordNotFound = Class.new(StandardError)
|
17
|
+
|
18
|
+
class << self
|
19
|
+
attr_accessor :deprecated_yaml_erb_backend
|
20
|
+
|
21
|
+
def eager_load!
|
22
|
+
Base.descendants.each(&:eager_load!)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
self.deprecated_yaml_erb_backend = true
|
27
|
+
end
|
data/lib/frozen_record/scope.rb
CHANGED
@@ -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,
|
191
|
-
!@where_not_values.any? { |attr,
|
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
|
|
@@ -234,16 +235,16 @@ module FrozenRecord
|
|
234
235
|
end
|
235
236
|
|
236
237
|
def array_delegable?(method)
|
237
|
-
Array.method_defined?(method) && DISALLOWED_ARRAY_METHODS.
|
238
|
+
Array.method_defined?(method) && !DISALLOWED_ARRAY_METHODS.include?(method)
|
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
|
-
|
270
|
-
|
271
|
-
|
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
|
data/spec/frozen_record_spec.rb
CHANGED
@@ -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
|
@@ -415,7 +429,7 @@ describe 'querying' do
|
|
415
429
|
|
416
430
|
end
|
417
431
|
|
418
|
-
describe '.as_json' do
|
432
|
+
describe '.as_json', exclude_minimal: true do
|
419
433
|
|
420
434
|
it 'serialize the results' do
|
421
435
|
json = Country.all.as_json
|
@@ -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
@@ -1,16 +1,16 @@
|
|
1
1
|
lib = File.expand_path('../lib', __FILE__)
|
2
2
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
3
|
|
4
|
-
|
5
|
-
require '
|
6
|
-
require '
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
4
|
+
minimal = ENV['MINIMAL'] == 'true'
|
5
|
+
require 'objspace'
|
6
|
+
require 'time'
|
7
|
+
|
8
|
+
if minimal
|
9
|
+
require 'frozen_record/minimal'
|
10
|
+
else
|
11
|
+
require 'frozen_record'
|
12
|
+
end
|
13
|
+
|
14
14
|
require 'frozen_record/test_helper'
|
15
15
|
|
16
16
|
FrozenRecord::Base.base_path = File.join(File.dirname(__FILE__), 'fixtures')
|
@@ -22,6 +22,7 @@ FrozenRecord.eager_load!
|
|
22
22
|
RSpec.configure do |config|
|
23
23
|
config.run_all_when_everything_filtered = true
|
24
24
|
config.filter_run :focus
|
25
|
+
config.filter_run_excluding :exclude_minimal if minimal
|
25
26
|
|
26
27
|
config.order = 'random'
|
27
28
|
|
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.
|
4
|
+
version: 0.22.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jean Boussier
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-07-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activemodel
|
@@ -38,20 +38,6 @@ dependencies:
|
|
38
38
|
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
|
-
- !ruby/object:Gem::Dependency
|
42
|
-
name: bundler
|
43
|
-
requirement: !ruby/object:Gem::Requirement
|
44
|
-
requirements:
|
45
|
-
- - ">="
|
46
|
-
- !ruby/object:Gem::Version
|
47
|
-
version: '0'
|
48
|
-
type: :development
|
49
|
-
prerelease: false
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
51
|
-
requirements:
|
52
|
-
- - ">="
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
version: '0'
|
55
41
|
- !ruby/object:Gem::Dependency
|
56
42
|
name: rake
|
57
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -80,34 +66,6 @@ dependencies:
|
|
80
66
|
- - ">="
|
81
67
|
- !ruby/object:Gem::Version
|
82
68
|
version: '0'
|
83
|
-
- !ruby/object:Gem::Dependency
|
84
|
-
name: pry
|
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
|
-
- !ruby/object:Gem::Dependency
|
98
|
-
name: coveralls
|
99
|
-
requirement: !ruby/object:Gem::Requirement
|
100
|
-
requirements:
|
101
|
-
- - ">="
|
102
|
-
- !ruby/object:Gem::Version
|
103
|
-
version: '0'
|
104
|
-
type: :development
|
105
|
-
prerelease: false
|
106
|
-
version_requirements: !ruby/object:Gem::Requirement
|
107
|
-
requirements:
|
108
|
-
- - ">="
|
109
|
-
- !ruby/object:Gem::Version
|
110
|
-
version: '0'
|
111
69
|
description:
|
112
70
|
email:
|
113
71
|
- jean.boussier@gmail.com
|
@@ -115,26 +73,30 @@ executables: []
|
|
115
73
|
extensions: []
|
116
74
|
extra_rdoc_files: []
|
117
75
|
files:
|
76
|
+
- ".github/workflows/main.yml"
|
118
77
|
- ".gitignore"
|
119
78
|
- ".rspec"
|
120
|
-
- ".travis.yml"
|
121
79
|
- Gemfile
|
122
80
|
- LICENSE.txt
|
123
81
|
- README.md
|
124
82
|
- Rakefile
|
125
83
|
- benchmark/attribute-read
|
126
84
|
- benchmark/memory-usage
|
85
|
+
- benchmark/querying
|
127
86
|
- benchmark/setup.rb
|
128
87
|
- frozen_record.gemspec
|
129
88
|
- lib/frozen_record.rb
|
130
89
|
- lib/frozen_record/backends.rb
|
90
|
+
- lib/frozen_record/backends/empty.json
|
131
91
|
- lib/frozen_record/backends/json.rb
|
132
92
|
- lib/frozen_record/backends/yaml.rb
|
133
93
|
- lib/frozen_record/base.rb
|
134
94
|
- lib/frozen_record/compact.rb
|
135
95
|
- lib/frozen_record/index.rb
|
96
|
+
- lib/frozen_record/minimal.rb
|
136
97
|
- lib/frozen_record/railtie.rb
|
137
98
|
- lib/frozen_record/scope.rb
|
99
|
+
- lib/frozen_record/serialization.rb
|
138
100
|
- lib/frozen_record/test_helper.rb
|
139
101
|
- lib/frozen_record/version.rb
|
140
102
|
- spec/fixtures/animals.json
|
@@ -168,7 +130,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
168
130
|
- !ruby/object:Gem::Version
|
169
131
|
version: '0'
|
170
132
|
requirements: []
|
171
|
-
rubygems_version: 3.
|
133
|
+
rubygems_version: 3.3.0.dev
|
172
134
|
signing_key:
|
173
135
|
specification_version: 4
|
174
136
|
summary: ActiveRecord like interface to read only access and query static YAML files
|