lazy_lazer 0.7.2 → 0.8.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 +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
|