lazy_lazer 0.4.0 → 0.5.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/.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')
|