lazy_lazer 0.7.2 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +9 -6
- data/lib/lazy_lazer.rb +6 -2
- data/lib/lazy_lazer/internal_model.rb +62 -44
- data/lib/lazy_lazer/key_metadata.rb +6 -6
- data/lib/lazy_lazer/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 55bf334bce0c909389956b65961ebb47509dc3bf
|
4
|
+
data.tar.gz: d13f32962f1218f44213c5221488396c2a3de4a5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 48988bc8b686edf6080fc1468d09ac7385cd77eefec05a7d370657d7248e02ce125c4546cae6940f201dc5349e6235783f4020c8a2c35de800ee616e3428de80
|
7
|
+
data.tar.gz: e212429d02a6b1de380196d92fab5a79097c32032b9e9fa86edef7e3c4d4fe5a94b5e168ef46c512f92dc86575dc393ea02dc7f66e20db4059c764f9da996ede
|
data/README.md
CHANGED
@@ -15,13 +15,17 @@ class User
|
|
15
15
|
property :twitter_handle, :nil
|
16
16
|
property :favorite_ice_cream
|
17
17
|
|
18
|
-
def
|
18
|
+
def say_flavor!
|
19
19
|
if exists_locally?(:favorite_ice_cream)
|
20
20
|
puts "#{name} currently likes #{favorite_ice_cream}."
|
21
21
|
else
|
22
22
|
puts "#{name} doesn't have a favorite ice cream flavor yet."
|
23
23
|
end
|
24
|
-
|
24
|
+
end
|
25
|
+
|
26
|
+
def try_another_flavor!
|
27
|
+
delete_attribute(:favorite_ice_cream)
|
28
|
+
not_fully_loaded!
|
25
29
|
puts "#{name} just tried #{favorite_ice_cream}. They love it!"
|
26
30
|
end
|
27
31
|
|
@@ -35,7 +39,7 @@ end
|
|
35
39
|
|
36
40
|
user = User.new(name: 'Blinky', creation_time_utc: 1500000000, age: '21')
|
37
41
|
|
38
|
-
user.name
|
42
|
+
user.name #=> "Blinky"
|
39
43
|
user.email #=> "unknown@example.com"
|
40
44
|
user.created_at #=> 2017-07-14 03:40:00 +0100
|
41
45
|
user.age #=> 21
|
@@ -45,9 +49,8 @@ user.favorite_ice_cream #=> "chocolate"
|
|
45
49
|
user.favorite_ice_cream #=> "chocolate"
|
46
50
|
user.reload.favorite_ice_cream #=> "vanilla"
|
47
51
|
|
48
|
-
user.
|
49
|
-
#=> Blinky
|
50
|
-
#=> Blinky just tried strawberry. They love it!
|
52
|
+
user.say_flavor! #=> Blinky currently likes vanilla.
|
53
|
+
user.try_another_flavor! #=> Blinky just tried strawberry. They love it!
|
51
54
|
```
|
52
55
|
|
53
56
|
<p align="center">
|
data/lib/lazy_lazer.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'forwardable'
|
4
|
+
|
3
5
|
require_relative 'lazy_lazer/errors'
|
4
6
|
require_relative 'lazy_lazer/internal_model'
|
5
7
|
require_relative 'lazy_lazer/key_metadata_store'
|
@@ -62,8 +64,10 @@ module LazyLazer
|
|
62
64
|
module InstanceMethods
|
63
65
|
extend Forwardable
|
64
66
|
|
65
|
-
def_delegators :@_lazer_model,
|
66
|
-
|
67
|
+
def_delegators :@_lazer_model,
|
68
|
+
:to_h, :inspect, :read_attribute, :write_attribute, :delete_attribute,
|
69
|
+
:fully_loaded?, :fully_loaded!, :not_fully_loaded!, :exists_locally?
|
70
|
+
private :fully_loaded!, :not_fully_loaded!, :exists_locally?
|
67
71
|
|
68
72
|
# Create a new instance of the class from a set of source attributes.
|
69
73
|
# @param attributes [Hash] the model attributes
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'set'
|
4
|
+
|
3
5
|
module LazyLazer
|
4
6
|
# A delegator for internal operations.
|
5
7
|
class InternalModel
|
@@ -9,39 +11,35 @@ module LazyLazer
|
|
9
11
|
def initialize(key_metadata, parent)
|
10
12
|
@key_metadata = key_metadata
|
11
13
|
@parent = parent
|
12
|
-
@
|
13
|
-
@
|
14
|
-
@
|
14
|
+
@cache = {}
|
15
|
+
@source = {}
|
16
|
+
@writethrough = {}
|
15
17
|
@fully_loaded = false
|
16
18
|
end
|
17
19
|
|
18
20
|
# Converts all unconverted keys and packages them as a hash.
|
19
21
|
# @return [Hash] the converted hash
|
20
|
-
def to_h
|
21
|
-
|
22
|
-
todo
|
23
|
-
|
22
|
+
def to_h(strict: false)
|
23
|
+
todo = @key_metadata.keys - @cache.keys
|
24
|
+
todo.each do |key|
|
25
|
+
strict ? load_key_strict(key) : load_key_lenient(key)
|
26
|
+
end
|
27
|
+
@cache.dup
|
24
28
|
end
|
25
29
|
|
26
30
|
# @return [String] the string representation of the parent
|
27
31
|
def inspect
|
28
32
|
"#<#{@parent.class.name} (#{@fully_loaded ? 'loaded' : 'unloaded'}): [" + \
|
29
|
-
@
|
33
|
+
@cache.keys.join(', ') + ']>'
|
30
34
|
end
|
31
35
|
|
32
36
|
# Whether the key doesn't need to be lazily loaded.
|
33
37
|
# @param key_name [Symbol] the key to check
|
34
38
|
# @return [Boolean] whether the key exists locally.
|
35
39
|
def exists_locally?(key_name)
|
40
|
+
return true if @cache.key?(key_name) || @writethrough.key?(key_name)
|
36
41
|
meta = ensure_metadata_exists(key_name)
|
37
|
-
@
|
38
|
-
end
|
39
|
-
|
40
|
-
# Mark a key as tainted, forcing a reload on the next lookup.
|
41
|
-
# @param key_name [Symbol] the key to invalidate
|
42
|
-
# @return [void]
|
43
|
-
def invalidate(key_name)
|
44
|
-
@invalidated.add(key_name)
|
42
|
+
@source.key?(meta.source_key)
|
45
43
|
end
|
46
44
|
|
47
45
|
# Get the value of a key (fetching it from the cache if possible)
|
@@ -49,12 +47,7 @@ module LazyLazer
|
|
49
47
|
# @return [Object] the returned value
|
50
48
|
# @raise MissingAttribute if the attribute wasn't found and there isn't a default
|
51
49
|
def read_attribute(key_name)
|
52
|
-
|
53
|
-
if @invalidated.include?(key_name_sym)
|
54
|
-
@parent.reload
|
55
|
-
@invalidated.delete(key_name_sym)
|
56
|
-
end
|
57
|
-
@cache_hash[key_name_sym] ||= load_key_from_source(key_name_sym)
|
50
|
+
@cache.fetch(key_name) { load_key_strict(key_name) }
|
58
51
|
end
|
59
52
|
|
60
53
|
# Update an attribute.
|
@@ -62,10 +55,21 @@ module LazyLazer
|
|
62
55
|
# @param new_value [Object] the new value
|
63
56
|
# @return [Object] the written value
|
64
57
|
def write_attribute(key_name, new_value)
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
58
|
+
meta = ensure_metadata_exists(key_name)
|
59
|
+
@source.delete(meta.source_key)
|
60
|
+
@writethrough[key_name] = @cache[key_name] = new_value
|
61
|
+
end
|
62
|
+
|
63
|
+
# Delete an attribute
|
64
|
+
# @param key_name [Symbol] the name of the key
|
65
|
+
# @return [void]
|
66
|
+
def delete_attribute(key_name)
|
67
|
+
key_name_sym = key_name.to_sym
|
68
|
+
meta = ensure_metadata_exists(key_name_sym)
|
69
|
+
@cache.delete(key_name)
|
70
|
+
@writethrough.delete(key_name)
|
71
|
+
@source.delete(meta.source_key)
|
72
|
+
nil
|
69
73
|
end
|
70
74
|
|
71
75
|
# Mark the model as fully loaded.
|
@@ -91,7 +95,7 @@ module LazyLazer
|
|
91
95
|
# @return [void]
|
92
96
|
def verify_required!
|
93
97
|
@key_metadata.required_properties.each do |key_name|
|
94
|
-
next if @
|
98
|
+
next if @source.key?(@key_metadata.get(key_name).source_key)
|
95
99
|
raise RequiredAttribute, "#{@parent} requires `#{key_name}`"
|
96
100
|
end
|
97
101
|
end
|
@@ -106,8 +110,8 @@ module LazyLazer
|
|
106
110
|
# @api private
|
107
111
|
# @param attributes [Hash<Symbol, Object>] the attributes to merge
|
108
112
|
def merge!(attributes)
|
109
|
-
@
|
110
|
-
@
|
113
|
+
@cache.clear
|
114
|
+
@source.merge!(attributes)
|
111
115
|
end
|
112
116
|
|
113
117
|
private
|
@@ -116,11 +120,36 @@ module LazyLazer
|
|
116
120
|
# @param key_name [Symbol] the key name
|
117
121
|
# @return [Object] the returned value
|
118
122
|
# @raise MissingAttribute if the attribute wasn't found and there isn't a default
|
119
|
-
def
|
123
|
+
def load_key_strict(key_name)
|
120
124
|
meta = ensure_metadata_exists(key_name)
|
121
|
-
|
122
|
-
|
123
|
-
|
125
|
+
reload_if_missing(key_name, meta.source_key)
|
126
|
+
if !exists_locally?(key_name) && !meta.default_provided?
|
127
|
+
raise MissingAttribute, "`#{meta.source_key} is missing for #{@parent}`"
|
128
|
+
end
|
129
|
+
parse_key(meta, key_name)
|
130
|
+
end
|
131
|
+
|
132
|
+
# Load the key and apply transformations to it, skipping the cache.
|
133
|
+
# @param key_name [Symbol] the key name
|
134
|
+
# @return [Object] the returned value
|
135
|
+
def load_key_lenient(key_name)
|
136
|
+
meta = ensure_metadata_exists(key_name)
|
137
|
+
reload_if_missing(key_name, meta.source_key)
|
138
|
+
parse_key(meta, key_name)
|
139
|
+
end
|
140
|
+
|
141
|
+
def reload_if_missing(key_name, source_key)
|
142
|
+
@parent.reload if !@writethrough.key?(key_name) && !@source.key?(source_key) && !@fully_loaded
|
143
|
+
end
|
144
|
+
|
145
|
+
def parse_key(meta, key_name)
|
146
|
+
if @source.key?(meta.source_key)
|
147
|
+
@cache[key_name] = transform_value(@source[meta.source_key], meta.transform)
|
148
|
+
elsif @writethrough.key?(key_name)
|
149
|
+
@cache[key_name] = @writethrough[key_name]
|
150
|
+
elsif meta.default_provided?
|
151
|
+
@cache[key_name] = fetch_default(meta.default)
|
152
|
+
end
|
124
153
|
end
|
125
154
|
|
126
155
|
# Ensure the metadata is found.
|
@@ -132,17 +161,6 @@ module LazyLazer
|
|
132
161
|
raise MissingAttribute, "`#{key_name}` isn't defined for #{@parent}"
|
133
162
|
end
|
134
163
|
|
135
|
-
# Reloads the model if a key isn't loaded and possibly errors if the key still isn't there.
|
136
|
-
# @param source_key [Symbol] the key that should be loaded
|
137
|
-
# @param runtime_required [Boolean] whether to raise an error if the key is not loaded
|
138
|
-
# @return [void]
|
139
|
-
# @raise MissingAttribute if runtime_required is true and the key can't be loaded.
|
140
|
-
def ensure_key_is_loaded(source_key, runtime_required)
|
141
|
-
@parent.reload if !@source_hash.key?(source_key) && !@fully_loaded
|
142
|
-
return if @source_hash.key?(source_key) || !runtime_required
|
143
|
-
raise MissingAttribute, "`#{source_key} is missing for #{@parent}`"
|
144
|
-
end
|
145
|
-
|
146
164
|
# Apply a transformation to a value.
|
147
165
|
# @param value [Object] a value
|
148
166
|
# @param transform [nil, Proc, Symbol] a transform type
|
@@ -11,8 +11,8 @@ module LazyLazer
|
|
11
11
|
# @return [Boolean] whether the key must exist when creating the model
|
12
12
|
attr_writer :required
|
13
13
|
|
14
|
-
# @return [Boolean] whether
|
15
|
-
attr_writer :
|
14
|
+
# @return [Boolean] whether a default was provided
|
15
|
+
attr_writer :default_provided
|
16
16
|
|
17
17
|
# @return [Proc, Object] the default value or generator
|
18
18
|
attr_accessor :default
|
@@ -26,7 +26,7 @@ module LazyLazer
|
|
26
26
|
boolean_options.each_with_object(options) { |sym, hsh| hsh[sym] = true }
|
27
27
|
self.source_key = options[:from] || key_name
|
28
28
|
self.required = !!options[:required]
|
29
|
-
self.
|
29
|
+
self.default_provided = options.key?(:default) || options[:nil]
|
30
30
|
self.transform = options[:with]
|
31
31
|
self.default = options[:default]
|
32
32
|
end
|
@@ -36,9 +36,9 @@ module LazyLazer
|
|
36
36
|
@required
|
37
37
|
end
|
38
38
|
|
39
|
-
# @return [Boolean] whether
|
40
|
-
def
|
41
|
-
@
|
39
|
+
# @return [Boolean] whether no default was provided
|
40
|
+
def default_provided?
|
41
|
+
@default_provided
|
42
42
|
end
|
43
43
|
end
|
44
44
|
end
|
data/lib/lazy_lazer/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lazy_lazer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.8.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Avinash Dwarapu
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-10-
|
11
|
+
date: 2017-10-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|