frozen_record 0.20.0 → 0.22.1
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 +31 -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 +63 -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 +22 -3
- data/spec/spec_helper.rb +11 -10
- data/spec/support/country.rb +4 -0
- 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: 1f9b741714b43651cc824bf8fe992752dd4425f2357eaf6a995531cc37b3a224
|
4
|
+
data.tar.gz: c3700095fba0b7f56722e3b4ee515a81fed36542fc8e1dadc3854610a32f4ff1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6783fd2e014e11c2348cab5ab4926b12edf5927f347f311d4e7ecea80ab556db2952489c4e9a607936e3d32e052b89874050895c3fb27816c8a907bda7656d9d
|
7
|
+
data.tar.gz: 6afe414bdce72a1eb9ed68f780af2f20dde1e4aa43b155a5542096a64361434716b14cbaface580de7893e1e15416b6daffe4b875e30878c9acdffce9b1e5662
|
@@ -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,41 @@ 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 supports_freeze
|
58
|
+
def load_file(path)
|
59
|
+
YAML.load_file(path, freeze: true) || Dedup::EMPTY_ARRAY
|
60
|
+
end
|
61
|
+
|
62
|
+
def load_string(yaml)
|
63
|
+
YAML.load(yaml, freeze: true) || Dedup::EMPTY_ARRAY
|
64
|
+
end
|
65
|
+
else
|
66
|
+
def load_file(path)
|
67
|
+
Dedup.deep_intern!(YAML.load_file(path) || Dedup::EMPTY_ARRAY)
|
68
|
+
end
|
69
|
+
|
70
|
+
def load_string(yaml)
|
71
|
+
Dedup.deep_intern!(YAML.load(yaml) || Dedup::EMPTY_ARRAY)
|
72
|
+
end
|
73
|
+
end
|
46
74
|
end
|
47
75
|
end
|
48
76
|
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
|
|
@@ -227,22 +228,23 @@ module FrozenRecord
|
|
227
228
|
super
|
228
229
|
end
|
229
230
|
end
|
231
|
+
ruby2_keywords :method_missing if respond_to?(:ruby2_keywords, true)
|
230
232
|
|
231
233
|
def delegate_to_class(*args, &block)
|
232
234
|
scoping { @klass.public_send(*args, &block) }
|
233
235
|
end
|
234
236
|
|
235
237
|
def array_delegable?(method)
|
236
|
-
Array.method_defined?(method) && DISALLOWED_ARRAY_METHODS.
|
238
|
+
Array.method_defined?(method) && !DISALLOWED_ARRAY_METHODS.include?(method)
|
237
239
|
end
|
238
240
|
|
239
241
|
def where!(criterias)
|
240
|
-
@where_values += criterias.map { |k, v| [k.to_s, v] }
|
242
|
+
@where_values += criterias.map { |k, v| [k.to_s, Matcher.for(v)] }
|
241
243
|
self
|
242
244
|
end
|
243
245
|
|
244
246
|
def where_not!(criterias)
|
245
|
-
@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)] }
|
246
248
|
self
|
247
249
|
end
|
248
250
|
|
@@ -265,9 +267,62 @@ module FrozenRecord
|
|
265
267
|
|
266
268
|
private
|
267
269
|
|
268
|
-
|
269
|
-
|
270
|
-
|
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
|
271
326
|
end
|
272
327
|
end
|
273
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
|
@@ -193,6 +207,11 @@ describe 'querying' do
|
|
193
207
|
expect(countries.length).to be == 0
|
194
208
|
end
|
195
209
|
|
210
|
+
it 'is chainable with methods of the form `def method(*args, **kargs)' do
|
211
|
+
countries = Country.republics.continent_and_capital('Europe', capital: 'Paris')
|
212
|
+
expect(countries.length).to be == 1
|
213
|
+
end
|
214
|
+
|
196
215
|
it 'can be used with arrays' do
|
197
216
|
countries = Country.where(id: [1,2])
|
198
217
|
expect(countries.length).to be == 2
|
@@ -410,7 +429,7 @@ describe 'querying' do
|
|
410
429
|
|
411
430
|
end
|
412
431
|
|
413
|
-
describe '.as_json' do
|
432
|
+
describe '.as_json', exclude_minimal: true do
|
414
433
|
|
415
434
|
it 'serialize the results' do
|
416
435
|
json = Country.all.as_json
|
@@ -440,8 +459,8 @@ describe 'querying' do
|
|
440
459
|
it 'returns true when the same scope has be rechained' do
|
441
460
|
scope_a = Country.nato.republics.nato.republics
|
442
461
|
scope_b = Country.republics.nato
|
443
|
-
expect(scope_a.instance_variable_get(:@where_values)).to be == [['nato', true], ['king', nil], ['nato', true], ['king', nil]]
|
444
|
-
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]]
|
445
464
|
expect(scope_a).to be == scope_b
|
446
465
|
end
|
447
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
|
|
data/spec/support/country.rb
CHANGED
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.1
|
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-04-30 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.1.4
|
172
134
|
signing_key:
|
173
135
|
specification_version: 4
|
174
136
|
summary: ActiveRecord like interface to read only access and query static YAML files
|