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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 77feb46739d312dbc726ab9291c19b7d1d585a44
4
- data.tar.gz: a9a5ffda84ee0ed882b7944d7a7767e59d8efeb9
3
+ metadata.gz: 55bf334bce0c909389956b65961ebb47509dc3bf
4
+ data.tar.gz: d13f32962f1218f44213c5221488396c2a3de4a5
5
5
  SHA512:
6
- metadata.gz: 8c4ec41ef8145e740c889200494831016cbb543f3fe1231bc93105a477bedcb765c242abc78f3307fabf8e791692da9a071b1dd991056c552c84ea2a216bffbf
7
- data.tar.gz: e067e5cd6cde812fd9731b02ba4a4e5ee98a6a3bd630ae2241ef5d1f35f4d933ab526143b5acb77801deae4e5e5ae16067b9f7f062e12f41e875d3f56085e8ec
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 try_another_flavor!
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
- invalidate(:favorite_ice_cream)
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 #=> 'Blinky'
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.try_another_flavor!
49
- #=> Blinky currently likes vanilla.
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, :to_h, :inspect, :read_attribute, :write_attribute, :fully_loaded?, :fully_loaded!, :not_fully_loaded!, :invalidate, :exists_locally?
66
- private :fully_loaded!, :not_fully_loaded!, :invalidate, :exists_locally?
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
- @invalidated = Set.new
13
- @source_hash = {}
14
- @cache_hash = {}
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
- return @cache_hash if fully_loaded?
22
- todo = @key_metadata.keys - @cache_hash.keys
23
- todo.each_with_object(@cache_hash) { |key, cache| cache[key] = load_key_from_source(key) }.dup
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
- @cache_hash.keys.join(', ') + ']>'
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
- @source_hash.key?(meta.source_key)
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
- key_name_sym = key_name.to_sym
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
- unless @key_metadata.contains?(key_name)
66
- raise ArgumentError, "#{key_name} is not a valid attribute for #{parent}"
67
- end
68
- @cache_hash[key_name] = new_value
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 @source_hash.key?(@key_metadata.get(key_name).source_key)
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
- @cache_hash.clear
110
- @source_hash.merge!(attributes)
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 load_key_from_source(key_name)
123
+ def load_key_strict(key_name)
120
124
  meta = ensure_metadata_exists(key_name)
121
- ensure_key_is_loaded(meta.source_key, meta.runtime_required?)
122
- return fetch_default(meta.default) unless @source_hash.key?(meta.source_key)
123
- transform_value(@source_hash[meta.source_key], meta.transform)
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 the key must exist when loaded
15
- attr_writer :runtime_required
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.runtime_required = !options.key?(:default) && !options[:nil]
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 the key must exist when loaded
40
- def runtime_required?
41
- @runtime_required
39
+ # @return [Boolean] whether no default was provided
40
+ def default_provided?
41
+ @default_provided
42
42
  end
43
43
  end
44
44
  end
@@ -2,5 +2,5 @@
2
2
 
3
3
  module LazyLazer
4
4
  # The gem's semantic version number.
5
- VERSION = '0.7.2'
5
+ VERSION = '0.8.0'
6
6
  end
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.7.2
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-02 00:00:00.000000000 Z
11
+ date: 2017-10-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler