lazy_lazer 0.4.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +9 -17
- data/CONTRIBUTING.md +1 -2
- data/Guardfile +1 -1
- data/README.md +14 -14
- data/Rakefile +1 -1
- data/lazy_lazer.gemspec +4 -5
- data/lib/lazy_lazer/errors.rb +5 -2
- data/lib/lazy_lazer/internal_model.rb +106 -0
- data/lib/lazy_lazer/key_metadata.rb +55 -0
- data/lib/lazy_lazer/version.rb +1 -1
- data/lib/lazy_lazer.rb +65 -100
- metadata +12 -11
- data/bin/_guard-core +0 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f0bb53bdbc623da087097264074c47c222d9ab6e
|
4
|
+
data.tar.gz: 1101bfd58d2f18f34f5ede3921051fe7a38a760a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c9de14b8ec203392509baee6eee477dc556b9e693c4939ad7db35ef1dde161ecf354dd90ea85d59ab11f1967dcc8288e3fa90e3dd19d519dd411971a8872438e
|
7
|
+
data.tar.gz: 6ce926069ff709433528540c92e2ba6a1e0b161d76a533659d96f12e9137f49518a8761aca9b01064b95b720cf9b5fc49e2c15bbbcd7287fe13e6f4b59b6a048
|
data/.rubocop.yml
CHANGED
@@ -1,24 +1,16 @@
|
|
1
|
+
# Rubocop configuration based on the Relaxed Ruby Style (with some changes).
|
1
2
|
AllCops:
|
2
|
-
TargetRubyVersion: 2.
|
3
|
+
TargetRubyVersion: 2.4
|
3
4
|
|
5
|
+
# I just want to convert stuff to boolean.
|
6
|
+
Style/DoubleNegation:
|
7
|
+
Enabled: false
|
8
|
+
|
9
|
+
# Widescreen monitors are now a thing.
|
4
10
|
Metrics/LineLength:
|
5
11
|
Max: 100
|
6
12
|
|
7
|
-
#
|
8
|
-
Style/NumericPredicate:
|
9
|
-
Enabled: false
|
10
|
-
|
11
|
-
# Stop rubocop from complaining about large `describe` blocks.
|
13
|
+
# Allow long describe blocks.
|
12
14
|
Metrics/BlockLength:
|
13
15
|
Exclude:
|
14
|
-
- spec/**/*_spec.rb
|
15
|
-
|
16
|
-
# Lower severity of complexity metrics.
|
17
|
-
Metrics/AbcSize:
|
18
|
-
Severity: refactor
|
19
|
-
Metrics/CyclomaticComplexity:
|
20
|
-
Severity: refactor
|
21
|
-
Metrics/PerceivedComplexity:
|
22
|
-
Severity: refactor
|
23
|
-
Metrics/MethodLength:
|
24
|
-
Severity: refactor
|
16
|
+
- 'spec/**/*_spec.rb'
|
data/CONTRIBUTING.md
CHANGED
@@ -16,8 +16,7 @@ hi there thanks for contributing to lazy_lazer
|
|
16
16
|
|
17
17
|
**tests**
|
18
18
|
|
19
|
-
- lazy_lazer is
|
20
|
-
- there are ~110 lines of source code and ~230 lines of tests
|
19
|
+
- lazy_lazer is test-driven (just for external classes tho)
|
21
20
|
- consider running `./bin/guard` during development
|
22
21
|
- run `rake` and make sure that it passes
|
23
22
|
|
data/Guardfile
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
guard :rspec, cmd: 'bundle exec rspec --format progress' do
|
3
|
+
guard :rspec, cmd: 'bundle exec rspec --format progress --fail-fast' do
|
4
4
|
watch(%r{^spec/.+_spec\.rb$})
|
5
5
|
watch(%r{^lib/(.+)\.rb$}) { 'spec' }
|
6
6
|
watch('spec/spec_helper.rb') { 'spec' }
|
data/README.md
CHANGED
@@ -8,10 +8,11 @@ require 'lazy_lazer'
|
|
8
8
|
class User
|
9
9
|
include LazyLazer
|
10
10
|
|
11
|
-
property :id, required
|
11
|
+
property :id, :required
|
12
12
|
property :email, default: 'unknown@example.com'
|
13
|
-
property :created_at, from:
|
13
|
+
property :created_at, from: :creation_time_utc, with: ->(t) { Time.at(t) }
|
14
14
|
property :age, with: :to_i
|
15
|
+
property :twitter_handle, :nil
|
15
16
|
property :favorite_ice_cream
|
16
17
|
|
17
18
|
def lazer_reload
|
@@ -22,10 +23,11 @@ end
|
|
22
23
|
|
23
24
|
user = User.new(id: 152, creation_time_utc: 1500000000, age: '21')
|
24
25
|
|
25
|
-
user.id
|
26
|
-
user.email
|
27
|
-
user.created_at
|
28
|
-
user.age
|
26
|
+
user.id #=> 152
|
27
|
+
user.email #=> "unknown@example.com"
|
28
|
+
user.created_at #=> 2017-07-14 03:40:00 +0100
|
29
|
+
user.age #=> 21
|
30
|
+
user.twitter_handle #=> nil
|
29
31
|
|
30
32
|
user.favorite_ice_cream #=> "chocolate"
|
31
33
|
user.favorite_ice_cream #=> "chocolate"
|
@@ -33,12 +35,10 @@ user.reload.favorite_ice_cream #=> "vanilla"
|
|
33
35
|
```
|
34
36
|
|
35
37
|
<p align="center">
|
36
|
-
|
37
|
-
<a href="https://github.com/avinashbot/lazy_lazer/blob/master/
|
38
|
-
|
39
|
-
|
40
|
-
<a href="https://github.com/avinashbot/redd">redd</a>
|
41
|
-
|
42
|
-
logo font is
|
43
|
-
<a href="https://www.behance.net/gallery/3588289/Zaguatica">zaguatica</a>
|
38
|
+
<a href="http://www.rubydoc.info/github/avinashbot/lazy_lazer/master">documentation</a> -
|
39
|
+
<a href="https://github.com/avinashbot/lazy_lazer/blob/master/CONTRIBUTING.md">contributing</a> -
|
40
|
+
<a href="https://github.com/avinashbot/lazy_lazer/blob/master/LICENSE.txt">mit licensed</a>
|
41
|
+
<br>
|
42
|
+
created for <a href="https://github.com/avinashbot/redd">redd</a> -
|
43
|
+
logo font is <a href="https://www.behance.net/gallery/3588289/Zaguatica">zaguatica</a>
|
44
44
|
</p>
|
data/Rakefile
CHANGED
data/lazy_lazer.gemspec
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
# coding: utf-8
|
2
1
|
# frozen_string_literal: true
|
3
2
|
|
4
3
|
lib = File.expand_path('../lib', __FILE__)
|
@@ -24,10 +23,10 @@ Gem::Specification.new do |spec|
|
|
24
23
|
spec.require_paths = ['lib']
|
25
24
|
|
26
25
|
spec.add_development_dependency 'bundler', '~> 1.15'
|
27
|
-
spec.add_development_dependency 'rake', '~>
|
28
|
-
spec.add_development_dependency 'rspec', '~> 3.
|
29
|
-
spec.add_development_dependency 'rubocop', '~> 0.
|
30
|
-
spec.add_development_dependency 'pry', '~> 0.
|
26
|
+
spec.add_development_dependency 'rake', '~> 12.1'
|
27
|
+
spec.add_development_dependency 'rspec', '~> 3.6'
|
28
|
+
spec.add_development_dependency 'rubocop', '~> 0.50'
|
29
|
+
spec.add_development_dependency 'pry', '~> 0.11'
|
31
30
|
spec.add_development_dependency 'guard', '~> 2.14'
|
32
31
|
spec.add_development_dependency 'guard-rspec', '~> 4.7'
|
33
32
|
end
|
data/lib/lazy_lazer/errors.rb
CHANGED
@@ -1,9 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module LazyLazer
|
4
|
+
# The base class for all model errors.
|
5
|
+
class ModelError < StandardError; end
|
6
|
+
|
4
7
|
# This is raised when a required attribute isn't included.
|
5
|
-
class RequiredAttribute <
|
8
|
+
class RequiredAttribute < ModelError; end
|
6
9
|
|
7
10
|
# Raised when a missing attribute is called but a default isn't present.
|
8
|
-
class MissingAttribute <
|
11
|
+
class MissingAttribute < ModelError; end
|
9
12
|
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module LazyLazer
|
4
|
+
# A delegator for internal operations.
|
5
|
+
class InternalModel
|
6
|
+
# Create an internal model with a reference to a public model.
|
7
|
+
# @param key_metadata [Hash<Symbol, KeyMetadata>] a reference to a property hash
|
8
|
+
# @param parent [LazyLazer] a reference to a LazyLazer model
|
9
|
+
def initialize(key_metadata, parent)
|
10
|
+
@key_metadata = key_metadata
|
11
|
+
@parent = parent
|
12
|
+
@source_hash = {}
|
13
|
+
@cache_hash = {}
|
14
|
+
end
|
15
|
+
|
16
|
+
# Verify that all the keys marked as required are present.
|
17
|
+
# @raise RequiredAttribute if a required attribute is missing
|
18
|
+
# @return [void]
|
19
|
+
def verify_required!
|
20
|
+
@key_metadata.each do |key_name, meta|
|
21
|
+
next if !meta.required? || @source_hash.key?(meta.source_key)
|
22
|
+
raise RequiredAttribute, "#{@parent} requires `#{key_name}`"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# Converts all unconverted keys and packages them as a hash.
|
27
|
+
# @return [Hash] the converted hash
|
28
|
+
def to_h
|
29
|
+
todo = @key_metadata.keys - @cache_hash.keys
|
30
|
+
todo.each_with_object(@cache_hash) { |key, cache| cache[key] = load_key_from_source(key) }.dup
|
31
|
+
end
|
32
|
+
|
33
|
+
# Get the value of a key (fetching it from the cache if possible)
|
34
|
+
# @param key_name [Symbol] the name of the key
|
35
|
+
# @return [Object] the returned value
|
36
|
+
# @raise MissingAttribute if the attribute wasn't found and there isn't a default
|
37
|
+
def fetch(key_name)
|
38
|
+
@cache_hash[key_name] ||= load_key_from_source(key_name)
|
39
|
+
end
|
40
|
+
|
41
|
+
# Merge a hash into the model.
|
42
|
+
# @param attributes [Hash<Symbol, Object>] the attributes to merge
|
43
|
+
# @return [nil]
|
44
|
+
def merge!(attributes)
|
45
|
+
@cache_hash.clear
|
46
|
+
@source_hash.merge!(attributes)
|
47
|
+
nil
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
# Load the key and apply transformations to it, skipping the cache.
|
53
|
+
# @param key_name [Symbol] the key name
|
54
|
+
# @return [Object] the returned value
|
55
|
+
# @raise MissingAttribute if the attribute wasn't found and there isn't a default
|
56
|
+
def load_key_from_source(key_name)
|
57
|
+
meta = ensure_metadata_exists(key_name)
|
58
|
+
ensure_key_is_loaded(meta.source_key, meta.runtime_required?)
|
59
|
+
raw_value = @source_hash.fetch(meta.source_key) { fetch_default(meta.default) }
|
60
|
+
transform_value(raw_value, meta.transform)
|
61
|
+
end
|
62
|
+
|
63
|
+
# Ensure the metadata is found.
|
64
|
+
# @param key_name [Symbol] the property name
|
65
|
+
# @return [KeyMetadata] the key metadata, if found
|
66
|
+
# @raise MissingAttribute if the key metadata wasn't found
|
67
|
+
def ensure_metadata_exists(key_name)
|
68
|
+
return @key_metadata[key_name] if @key_metadata.key?(key_name)
|
69
|
+
raise MissingAttribute, "`#{key_name}` isn't defined for #{@parent}"
|
70
|
+
end
|
71
|
+
|
72
|
+
# Reloads the model if a key isn't loaded and possibly errors if the key still isn't there.
|
73
|
+
# @param source_key [Symbol] the key that should be loaded
|
74
|
+
# @param runtime_required [Boolean] whether to raise an error if the key is not loaded
|
75
|
+
# @return [void]
|
76
|
+
# @raise MissingAttribute if runtime_required is true and the key can't be loaded.
|
77
|
+
def ensure_key_is_loaded(source_key, runtime_required)
|
78
|
+
@parent.reload if !@source_hash.key?(source_key) && !@parent.fully_loaded?
|
79
|
+
return if @source_hash.key?(source_key) || !runtime_required
|
80
|
+
raise MissingAttribute, "`#{source_key} is missing for #{@parent}`"
|
81
|
+
end
|
82
|
+
|
83
|
+
# Apply a transformation to a value.
|
84
|
+
# @param value [Object] a value
|
85
|
+
# @param transform [nil, Proc, Symbol] a transform type
|
86
|
+
# @return [Object] the transformed value
|
87
|
+
def transform_value(value, transform)
|
88
|
+
case transform
|
89
|
+
when nil
|
90
|
+
value
|
91
|
+
when Proc
|
92
|
+
@parent.instance_exec(value, &transform)
|
93
|
+
when Symbol
|
94
|
+
value.public_send(transform)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
# Run the default proc and return its value, if applicable.
|
99
|
+
# @param default [Proc, Object] a proc to run, or an object to return
|
100
|
+
# @return [Object] the processed value
|
101
|
+
def fetch_default(default)
|
102
|
+
return @parent.instance_exec(&default) if default.is_a?(Proc)
|
103
|
+
default
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'errors'
|
4
|
+
|
5
|
+
module LazyLazer
|
6
|
+
# Simple PORO for key metadata. Yay value objects!
|
7
|
+
class KeyMetadata
|
8
|
+
# @return [Symbol] the key to fetch the value from
|
9
|
+
attr_reader :source_key
|
10
|
+
|
11
|
+
# @return [Proc, Object] the default value or generator
|
12
|
+
attr_reader :default
|
13
|
+
|
14
|
+
# @return [Proc, Symbol, nil] the method or proc that transforms the return value
|
15
|
+
attr_reader :transform
|
16
|
+
|
17
|
+
# Load attributes from a {LazyLazer::ClassMethods#property} method signature.
|
18
|
+
# @see LazyLazer::ClassMethods#property
|
19
|
+
def self.from_options(key_name, *boolean_options, **options)
|
20
|
+
boolean_options.each_with_object(options) { |sym, hsh| hsh[sym] = true }
|
21
|
+
KeyMetadata.new(
|
22
|
+
source_key: options[:from] || key_name,
|
23
|
+
required: !!options[:required],
|
24
|
+
runtime_required: !options.key?(:default) && !options[:nil],
|
25
|
+
transform: options[:with],
|
26
|
+
default: options[:default]
|
27
|
+
)
|
28
|
+
end
|
29
|
+
|
30
|
+
# Create a new KeyMetadata value object with all the properties.
|
31
|
+
# @param source_key [Symbol] the key to fetch the value from
|
32
|
+
# @param required [Boolean] whether the key must exist when creating the model
|
33
|
+
# @param runtime_required [Boolean] whether the key must exist when loaded
|
34
|
+
# @param default [Proc, Object] the default value or generator
|
35
|
+
# @param transform [Proc, Symbol, nil] the method or proc that transforms the return value
|
36
|
+
def initialize(source_key:, required:, runtime_required:, default:, transform:)
|
37
|
+
@source_key = source_key
|
38
|
+
@required = required
|
39
|
+
@runtime_required = runtime_required
|
40
|
+
@default = default
|
41
|
+
@transform = transform
|
42
|
+
freeze
|
43
|
+
end
|
44
|
+
|
45
|
+
# @return [Boolean] whether the key must exist when creating the model
|
46
|
+
def required?
|
47
|
+
@required
|
48
|
+
end
|
49
|
+
|
50
|
+
# @return [Boolean] whether the key must exist when loaded
|
51
|
+
def runtime_required?
|
52
|
+
@runtime_required
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
data/lib/lazy_lazer/version.rb
CHANGED
data/lib/lazy_lazer.rb
CHANGED
@@ -1,9 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative 'lazy_lazer/version'
|
4
3
|
require_relative 'lazy_lazer/errors'
|
4
|
+
require_relative 'lazy_lazer/internal_model'
|
5
|
+
require_relative 'lazy_lazer/key_metadata'
|
6
|
+
require_relative 'lazy_lazer/version'
|
5
7
|
|
6
|
-
#
|
8
|
+
# LazyLazer.
|
9
|
+
# Include this module into your class to infuse it with lazer powers.
|
10
|
+
#
|
11
|
+
# @see LazyLazer::ClassMethods your model's class methods
|
12
|
+
# @see LazyLazer::InstanceMethods your model's instance methods
|
7
13
|
module LazyLazer
|
8
14
|
# Hook into `include LazyLazer`.
|
9
15
|
# @param base [Module] the object to include the methods in
|
@@ -11,22 +17,7 @@ module LazyLazer
|
|
11
17
|
def self.included(base)
|
12
18
|
base.extend(ClassMethods)
|
13
19
|
base.include(InstanceMethods)
|
14
|
-
base.instance_variable_set(
|
15
|
-
:@lazer_metadata,
|
16
|
-
properties: [],
|
17
|
-
required: {},
|
18
|
-
default: {},
|
19
|
-
from: {},
|
20
|
-
with: {}
|
21
|
-
)
|
22
|
-
end
|
23
|
-
|
24
|
-
# Get the source key from an instance
|
25
|
-
# @param instance [Object] the instance
|
26
|
-
# @param key [Symbol] the property key
|
27
|
-
# @return [Symbol] the source key if found or the passed key if not found
|
28
|
-
def self.source_key(instance, key)
|
29
|
-
instance.class.lazer_metadata[:from].fetch(key, key)
|
20
|
+
base.instance_variable_set(:@lazer_metadata, {})
|
30
21
|
end
|
31
22
|
|
32
23
|
# The methods to extend the class with.
|
@@ -35,7 +26,7 @@ module LazyLazer
|
|
35
26
|
# @param klass [Class] the subclass
|
36
27
|
# @return [void]
|
37
28
|
def inherited(klass)
|
38
|
-
klass.instance_variable_set(:@lazer_metadata, @lazer_metadata)
|
29
|
+
klass.instance_variable_set(:@lazer_metadata, @lazer_metadata.dup)
|
39
30
|
end
|
40
31
|
|
41
32
|
# @return [Hash<Symbol, Hash>] the lazer configuration for this model
|
@@ -45,19 +36,28 @@ module LazyLazer
|
|
45
36
|
|
46
37
|
# Define a property.
|
47
38
|
# @param name [Symbol] the name of the property method
|
39
|
+
# @param bool_options [Array<Symbol>] options that are set to true
|
48
40
|
# @param options [Hash] the options to create the property with
|
49
41
|
# @option options [Boolean] :required (false) whether existence of this property should be
|
50
42
|
# checked on model creation
|
43
|
+
# @option options [Boolean] :nil (false) shortcut for default: nil
|
51
44
|
# @option options [Object, Proc] :default the default value to return if not provided
|
52
|
-
# @option options [Symbol] :from the key in the source object to get the property from
|
53
|
-
# @option options [Proc, Symbol] :with an optional transformation to apply to the value
|
54
|
-
# @note both :required and :default can't be provided
|
45
|
+
# @option options [Symbol] :from (name) the key in the source object to get the property from
|
46
|
+
# @option options [Proc, Symbol, nil] :with an optional transformation to apply to the value
|
55
47
|
# @return [Symbol] the name of the created property
|
56
|
-
|
57
|
-
|
48
|
+
#
|
49
|
+
# @example
|
50
|
+
# class MyModel
|
51
|
+
# include LazyLazer
|
52
|
+
#
|
53
|
+
# property :id, :required
|
54
|
+
# property :timestamp, with: ->(i) { Time.at(i) }
|
55
|
+
# property :created_at, default: ->() { Time.now }
|
56
|
+
# property :camel_case, from: :camelCase
|
57
|
+
# end
|
58
|
+
def property(name, *bool_options, **options)
|
58
59
|
sym_name = name.to_sym
|
59
|
-
@lazer_metadata[
|
60
|
-
options.each_pair { |option, value| @lazer_metadata[option][sym_name] = value }
|
60
|
+
@lazer_metadata[sym_name] = KeyMetadata.from_options(sym_name, *bool_options, **options)
|
61
61
|
define_method(sym_name) { read_attribute(sym_name) }
|
62
62
|
end
|
63
63
|
end
|
@@ -67,119 +67,84 @@ module LazyLazer
|
|
67
67
|
# Create a new instance of the class from a set of source attributes.
|
68
68
|
# @param attributes [Hash] the model attributes
|
69
69
|
# @return [void]
|
70
|
+
# @raise RequiredAttribute if an attribute marked as required wasn't found
|
70
71
|
def initialize(attributes = {})
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
@_lazer_source = attributes.dup
|
78
|
-
@_lazer_cache = {}
|
72
|
+
@_lazer_model = InternalModel.new(self.class.lazer_metadata, self)
|
73
|
+
@_lazer_model.merge!(attributes)
|
74
|
+
@_lazer_model.verify_required!
|
75
|
+
@_lazer_writethrough = {}
|
76
|
+
@_lazer_loaded = false
|
79
77
|
end
|
80
78
|
|
81
79
|
# Converts all the attributes that haven't been converted yet and returns the final hash.
|
82
|
-
# @param strict [Boolean] whether to fully load all attributes
|
83
80
|
# @return [Hash] a hash representation of the model
|
84
|
-
def to_h
|
85
|
-
|
86
|
-
todo = self.class.lazer_metadata[:properties] - @_lazer_cache.keys
|
87
|
-
todo.each { |k| read_attribute(k) }
|
88
|
-
end
|
89
|
-
@_lazer_cache
|
90
|
-
end
|
91
|
-
|
92
|
-
# @abstract Provides reloading behaviour for lazy loading.
|
93
|
-
# @return [Hash] the result of reloading the hash
|
94
|
-
def lazer_reload
|
95
|
-
self.fully_loaded = true
|
96
|
-
{}
|
81
|
+
def to_h
|
82
|
+
@_lazer_model.to_h
|
97
83
|
end
|
98
84
|
|
99
85
|
# Reload the object. Calls {#lazer_reload}, then merges the results into the internal store.
|
100
86
|
# Also clears out the internal cache.
|
101
87
|
# @return [self] the updated object
|
102
88
|
def reload
|
103
|
-
new_attributes = lazer_reload
|
104
|
-
@
|
105
|
-
@_lazer_cache = {}
|
89
|
+
new_attributes = lazer_reload.to_h
|
90
|
+
@_lazer_model.merge!(new_attributes)
|
106
91
|
self
|
107
92
|
end
|
108
93
|
|
109
94
|
# Return the value of the attribute.
|
110
|
-
# @param
|
95
|
+
# @param key_name [Symbol] the attribute name
|
96
|
+
# @return [Object] the returned value
|
111
97
|
# @raise MissingAttribute if the key was not found
|
112
|
-
def read_attribute(
|
113
|
-
|
114
|
-
return @
|
115
|
-
|
116
|
-
# Converts the property into the lookup key.
|
117
|
-
source_key = LazyLazer.source_key(self, name)
|
118
|
-
|
119
|
-
# Reloads if a key that should be there isn't.
|
120
|
-
reload if !@_lazer_source.key?(source_key) &&
|
121
|
-
self.class.lazer_metadata[:properties].include?(name) &&
|
122
|
-
!fully_loaded?
|
123
|
-
|
124
|
-
# Complains if even after reloading, the key is missing (and there's no default).
|
125
|
-
if !@_lazer_source.key?(source_key) && !self.class.lazer_metadata[:default].key?(name)
|
126
|
-
raise MissingAttribute, "`#{source_key}` missing for #{self}"
|
127
|
-
end
|
128
|
-
|
129
|
-
# Gets the value or gets the default.
|
130
|
-
value_or_default = @_lazer_source.fetch(source_key) do
|
131
|
-
default = self.class.lazer_metadata[:default][name]
|
132
|
-
default.is_a?(Proc) ? instance_exec(&default) : default
|
133
|
-
end
|
134
|
-
|
135
|
-
# Transforms the result using :with, if found.
|
136
|
-
transformer = self.class.lazer_metadata[:with][name]
|
137
|
-
coerced =
|
138
|
-
case transformer
|
139
|
-
when Symbol
|
140
|
-
value_or_default.public_send(transformer)
|
141
|
-
when Proc
|
142
|
-
instance_exec(value_or_default, &transformer)
|
143
|
-
else
|
144
|
-
value_or_default
|
145
|
-
end
|
146
|
-
|
147
|
-
# Add to cache and return the result.
|
148
|
-
@_lazer_cache[name] = coerced
|
98
|
+
def read_attribute(key_name)
|
99
|
+
symbol_key = key_name.to_sym
|
100
|
+
return @_lazer_writethrough[symbol_key] if @_lazer_writethrough.key?(symbol_key)
|
101
|
+
@_lazer_model.fetch(symbol_key)
|
149
102
|
end
|
150
103
|
|
151
|
-
# Return the value of the attribute, returning nil if not found
|
152
|
-
# @param
|
153
|
-
|
154
|
-
|
104
|
+
# Return the value of the attribute, returning nil if not found.
|
105
|
+
# @param key_name [Symbol] the attribute name
|
106
|
+
# @return [Object] the returned value
|
107
|
+
def [](key_name)
|
108
|
+
read_attribute(key_name)
|
155
109
|
rescue MissingAttribute
|
156
110
|
nil
|
157
111
|
end
|
158
112
|
|
159
113
|
# Update an attribute.
|
160
|
-
# @param
|
114
|
+
# @param key_name [Symbol] the attribute to update
|
161
115
|
# @param value [Object] the new value
|
162
|
-
|
163
|
-
|
116
|
+
# @return [Object] the written value
|
117
|
+
def write_attribute(key_name, value)
|
118
|
+
@_lazer_writethrough[key_name] = value
|
164
119
|
end
|
165
120
|
|
166
121
|
# Update multiple attributes at once.
|
167
122
|
# @param new_attributes [Hash<Symbol, Object>] the new attributes
|
123
|
+
# @return [self] the updated object
|
168
124
|
def assign_attributes(new_attributes)
|
169
125
|
new_attributes.each { |key, value| write_attribute(key, value) }
|
126
|
+
self
|
170
127
|
end
|
171
128
|
alias attributes= assign_attributes
|
172
129
|
|
173
130
|
# @return [Boolean] whether the object is done with lazy loading
|
174
131
|
def fully_loaded?
|
175
|
-
@
|
132
|
+
@_lazer_loaded
|
176
133
|
end
|
177
134
|
|
178
135
|
private
|
179
136
|
|
180
|
-
# @
|
181
|
-
|
182
|
-
|
137
|
+
# @abstract Provides reloading behaviour for lazy loading.
|
138
|
+
# @return [Hash] the result of reloading the hash
|
139
|
+
def lazer_reload
|
140
|
+
fully_loaded!
|
141
|
+
{}
|
142
|
+
end
|
143
|
+
|
144
|
+
# Mark the model as fully loaded.
|
145
|
+
# @return [void]
|
146
|
+
def fully_loaded!
|
147
|
+
@_lazer_loaded = true
|
183
148
|
end
|
184
149
|
end
|
185
150
|
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.
|
4
|
+
version: 0.5.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-
|
11
|
+
date: 2017-09-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -30,56 +30,56 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
33
|
+
version: '12.1'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '
|
40
|
+
version: '12.1'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rspec
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
45
|
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '3.
|
47
|
+
version: '3.6'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '3.
|
54
|
+
version: '3.6'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: rubocop
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
59
|
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: '0.
|
61
|
+
version: '0.50'
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version: '0.
|
68
|
+
version: '0.50'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: pry
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
73
|
- - "~>"
|
74
74
|
- !ruby/object:Gem::Version
|
75
|
-
version: '0.
|
75
|
+
version: '0.11'
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
80
|
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version: '0.
|
82
|
+
version: '0.11'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
84
|
name: guard
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -124,13 +124,14 @@ files:
|
|
124
124
|
- LICENSE.txt
|
125
125
|
- README.md
|
126
126
|
- Rakefile
|
127
|
-
- bin/_guard-core
|
128
127
|
- bin/console
|
129
128
|
- bin/guard
|
130
129
|
- bin/setup
|
131
130
|
- lazy_lazer.gemspec
|
132
131
|
- lib/lazy_lazer.rb
|
133
132
|
- lib/lazy_lazer/errors.rb
|
133
|
+
- lib/lazy_lazer/internal_model.rb
|
134
|
+
- lib/lazy_lazer/key_metadata.rb
|
134
135
|
- lib/lazy_lazer/version.rb
|
135
136
|
- logo.png
|
136
137
|
homepage: https://github.com/avinashbot/lazy_lazer
|
data/bin/_guard-core
DELETED
@@ -1,18 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
# frozen_string_literal: true
|
3
|
-
|
4
|
-
#
|
5
|
-
# This file was generated by Bundler.
|
6
|
-
#
|
7
|
-
# The application '_guard-core' is installed as part of a gem, and
|
8
|
-
# this file is here to facilitate running it.
|
9
|
-
#
|
10
|
-
|
11
|
-
require 'pathname'
|
12
|
-
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile',
|
13
|
-
Pathname.new(__FILE__).realpath)
|
14
|
-
|
15
|
-
require 'rubygems'
|
16
|
-
require 'bundler/setup'
|
17
|
-
|
18
|
-
load Gem.bin_path('guard', '_guard-core')
|