u-attributes 2.1.0 → 2.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/.travis.yml +1 -2
- data/README.md +180 -41
- data/lib/micro/attributes.rb +43 -23
- data/lib/micro/attributes/diff.rb +26 -14
- data/lib/micro/attributes/features.rb +128 -75
- data/lib/micro/attributes/features/accept.rb +132 -0
- data/lib/micro/attributes/features/accept/strict.rb +26 -0
- data/lib/micro/attributes/features/activemodel_validations.rb +54 -10
- data/lib/micro/attributes/features/initialize.rb +3 -8
- data/lib/micro/attributes/features/keys_as_symbol.rb +31 -0
- data/lib/micro/attributes/macros.rb +80 -13
- data/lib/micro/attributes/utils.rb +47 -14
- data/lib/micro/attributes/version.rb +1 -1
- data/u-attributes.gemspec +1 -1
- metadata +5 -4
- data/assets/u-attributes_logo_v1.png +0 -0
- data/lib/micro/attributes/with.rb +0 -100
@@ -3,13 +3,45 @@
|
|
3
3
|
module Micro::Attributes
|
4
4
|
module Features
|
5
5
|
module ActiveModelValidations
|
6
|
-
|
7
|
-
|
8
|
-
|
6
|
+
module Standard
|
7
|
+
private def __call_after_attributes_assign
|
8
|
+
run_validations!
|
9
|
+
end
|
10
|
+
end
|
9
11
|
|
10
|
-
|
11
|
-
|
12
|
-
|
12
|
+
module CheckActivemodelValidationErrors
|
13
|
+
private def __check_activemodel_validation_errors
|
14
|
+
return if errors.blank?
|
15
|
+
|
16
|
+
errors_hash = errors.to_hash
|
17
|
+
|
18
|
+
defined_attributes.each do |key|
|
19
|
+
value = Utils::Hashes.assoc(errors_hash, key)
|
20
|
+
|
21
|
+
@__attributes_errors[key] = value.join(', ') if value.present?
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
module WithAccept
|
27
|
+
include CheckActivemodelValidationErrors
|
28
|
+
|
29
|
+
private def __call_after_attributes_assign
|
30
|
+
run_validations! unless attributes_errors?
|
31
|
+
|
32
|
+
__check_activemodel_validation_errors
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
module WithAcceptStrict
|
37
|
+
include CheckActivemodelValidationErrors
|
38
|
+
|
39
|
+
private def __call_after_attributes_assign
|
40
|
+
__raise_error_if_found_attributes_errors if attributes_errors?
|
41
|
+
|
42
|
+
run_validations!
|
43
|
+
|
44
|
+
__check_activemodel_validation_errors
|
13
45
|
end
|
14
46
|
end
|
15
47
|
|
@@ -18,15 +50,27 @@ module Micro::Attributes
|
|
18
50
|
validate, validates = options.values_at(:validate, :validates)
|
19
51
|
|
20
52
|
self.validate(validate) if validate
|
21
|
-
self.validates(attr_name, validates) if validates
|
53
|
+
self.validates(attr_name, validates.dup) if validates
|
22
54
|
end
|
23
55
|
end
|
24
56
|
|
25
|
-
|
57
|
+
def self.included(base)
|
58
|
+
begin
|
59
|
+
require 'active_model'
|
60
|
+
|
61
|
+
base.send(:include, ::ActiveModel::Validations)
|
62
|
+
base.extend(ClassMethods)
|
26
63
|
|
27
|
-
|
28
|
-
|
64
|
+
case
|
65
|
+
when base <= Features::Accept::Strict then base.send(:include, WithAcceptStrict)
|
66
|
+
when base <= Features::Accept then base.send(:include, WithAccept)
|
67
|
+
else base.send(:include, Standard)
|
68
|
+
end
|
69
|
+
rescue LoadError
|
29
70
|
end
|
71
|
+
end
|
72
|
+
|
73
|
+
private_constant :Standard, :CheckActivemodelValidationErrors, :WithAccept, :WithAcceptStrict
|
30
74
|
end
|
31
75
|
end
|
32
76
|
end
|
@@ -7,22 +7,17 @@ module Micro::Attributes
|
|
7
7
|
base.class_eval(<<-RUBY)
|
8
8
|
def initialize(arg)
|
9
9
|
self.attributes = arg
|
10
|
-
__call_after_micro_attribute
|
11
10
|
end
|
12
11
|
RUBY
|
13
12
|
end
|
14
13
|
|
15
|
-
def with_attribute(key, val)
|
16
|
-
self.class.new(attributes.merge(key => val))
|
17
|
-
end
|
18
|
-
|
19
14
|
def with_attributes(arg)
|
20
15
|
self.class.new(attributes.merge(arg))
|
21
16
|
end
|
22
17
|
|
23
|
-
|
24
|
-
|
25
|
-
|
18
|
+
def with_attribute(key, val)
|
19
|
+
with_attributes(key => val)
|
20
|
+
end
|
26
21
|
end
|
27
22
|
end
|
28
23
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Micro::Attributes
|
4
|
+
module Features
|
5
|
+
module KeysAsSymbol
|
6
|
+
|
7
|
+
module ClassMethods
|
8
|
+
def attributes_access
|
9
|
+
:symbol
|
10
|
+
end
|
11
|
+
|
12
|
+
def __attribute_key_check__(value)
|
13
|
+
Kind::Of.(::Symbol, value)
|
14
|
+
end
|
15
|
+
|
16
|
+
def __attribute_key_transform__(value)
|
17
|
+
value
|
18
|
+
end
|
19
|
+
|
20
|
+
def __attributes_keys_transform__(hash)
|
21
|
+
Utils::Hashes.kind(hash)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.included(base)
|
26
|
+
base.send(:extend, ClassMethods)
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -7,6 +7,22 @@ module Micro
|
|
7
7
|
false
|
8
8
|
end
|
9
9
|
|
10
|
+
def attributes_access
|
11
|
+
:indifferent
|
12
|
+
end
|
13
|
+
|
14
|
+
def __attribute_key_check__(value)
|
15
|
+
value
|
16
|
+
end
|
17
|
+
|
18
|
+
def __attribute_key_transform__(value)
|
19
|
+
value.to_s
|
20
|
+
end
|
21
|
+
|
22
|
+
def __attributes_keys_transform__(hash)
|
23
|
+
Utils::Hashes.stringify_keys(hash)
|
24
|
+
end
|
25
|
+
|
10
26
|
# NOTE: can't be renamed! It is used by u-case v4.
|
11
27
|
def __attributes_data__
|
12
28
|
@__attributes_data__ ||= {}
|
@@ -16,18 +32,54 @@ module Micro
|
|
16
32
|
@__attributes_required__ ||= Set.new
|
17
33
|
end
|
18
34
|
|
19
|
-
def __attributes_required_add(name,
|
20
|
-
if
|
35
|
+
def __attributes_required_add(name, opt, hasnt_default)
|
36
|
+
if opt[:required] || (attributes_are_all_required? && hasnt_default)
|
21
37
|
__attributes_required__.add(name)
|
22
38
|
end
|
23
39
|
|
24
40
|
nil
|
25
41
|
end
|
26
42
|
|
27
|
-
|
28
|
-
|
43
|
+
module Options
|
44
|
+
PERMITTED = [
|
45
|
+
:default, :required,
|
46
|
+
:validate, :validates, # activemodel_validations
|
47
|
+
:accept, :reject, :allow_nil, :rejection_message # accept
|
48
|
+
].freeze
|
49
|
+
|
50
|
+
INVALID_MESSAGE = [
|
51
|
+
"Found one or more invalid options: %{invalid_options}\n\nThe valid ones are: ",
|
52
|
+
PERMITTED.map { |key| ":#{key}" }.join(', ')
|
53
|
+
].join.freeze
|
54
|
+
|
55
|
+
def self.check(opt)
|
56
|
+
invalid_keys = opt.keys - PERMITTED
|
57
|
+
|
58
|
+
return if invalid_keys.empty?
|
59
|
+
|
60
|
+
invalid_options = { invalid_options: invalid_keys.inspect.tr('[', '').tr(']', '') }
|
61
|
+
|
62
|
+
raise ArgumentError, (INVALID_MESSAGE % invalid_options)
|
63
|
+
end
|
29
64
|
|
30
|
-
|
65
|
+
def self.for_accept(opt)
|
66
|
+
allow_nil = opt[:allow_nil]
|
67
|
+
rejection_message = opt[:rejection_message]
|
68
|
+
|
69
|
+
return [:accept, opt[:accept], allow_nil, rejection_message] if opt.key?(:accept)
|
70
|
+
return [:reject, opt[:reject], allow_nil, rejection_message] if opt.key?(:reject)
|
71
|
+
|
72
|
+
Kind::Empty::ARRAY
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def __attributes_data_to_assign(name, opt)
|
77
|
+
hasnt_default = !opt.key?(:default)
|
78
|
+
|
79
|
+
[
|
80
|
+
hasnt_default ? __attributes_required_add(name, opt, hasnt_default) : opt[:default],
|
81
|
+
Options.for_accept(opt)
|
82
|
+
]
|
31
83
|
end
|
32
84
|
|
33
85
|
def __attributes
|
@@ -40,15 +92,18 @@ module Micro
|
|
40
92
|
attr_reader(name)
|
41
93
|
end
|
42
94
|
|
43
|
-
def __attribute_assign(key, can_overwrite,
|
44
|
-
name = key
|
95
|
+
def __attribute_assign(key, can_overwrite, opt)
|
96
|
+
name = __attribute_key_check__(__attribute_key_transform__(key))
|
97
|
+
|
98
|
+
Options.check(opt)
|
99
|
+
|
45
100
|
has_attribute = attribute?(name)
|
46
101
|
|
47
102
|
__attribute_reader(name) unless has_attribute
|
48
103
|
|
49
|
-
__attributes_data__[name] = __attributes_data_to_assign(name,
|
104
|
+
__attributes_data__[name] = __attributes_data_to_assign(name, opt) if can_overwrite || !has_attribute
|
50
105
|
|
51
|
-
__call_after_attribute_assign__(name,
|
106
|
+
__call_after_attribute_assign__(name, opt)
|
52
107
|
end
|
53
108
|
|
54
109
|
def __call_after_attribute_assign__(attr_name, options); end
|
@@ -56,12 +111,20 @@ module Micro
|
|
56
111
|
# NOTE: can't be renamed! It is used by u-case v4.
|
57
112
|
def __attributes_set_after_inherit__(arg)
|
58
113
|
arg.each do |key, val|
|
59
|
-
|
114
|
+
opt = if default = val[0]
|
115
|
+
requ_key, requ_val = val[1]
|
116
|
+
|
117
|
+
hash = requ_key ? { requ_key => requ_val } : {}
|
118
|
+
hash[:default] = default
|
119
|
+
hash
|
120
|
+
end
|
121
|
+
|
122
|
+
__attribute_assign(key, true, opt || Kind::Empty::HASH)
|
60
123
|
end
|
61
124
|
end
|
62
125
|
|
63
126
|
def attribute?(name)
|
64
|
-
__attributes.member?(name
|
127
|
+
__attributes.member?(__attribute_key_transform__(name))
|
65
128
|
end
|
66
129
|
|
67
130
|
def attribute(name, options = Kind::Empty::HASH)
|
@@ -72,9 +135,13 @@ module Micro
|
|
72
135
|
return __attributes.to_a if args.empty?
|
73
136
|
|
74
137
|
args.flatten!
|
138
|
+
|
139
|
+
options =
|
140
|
+
args.size > 1 && args.last.is_a?(::Hash) ? args.pop : Kind::Empty::HASH
|
141
|
+
|
75
142
|
args.each do |arg|
|
76
143
|
if arg.is_a?(String) || arg.is_a?(Symbol)
|
77
|
-
__attribute_assign(arg, false,
|
144
|
+
__attribute_assign(arg, false, options)
|
78
145
|
else
|
79
146
|
raise Kind::Error.new('String/Symbol'.freeze, arg)
|
80
147
|
end
|
@@ -92,7 +159,7 @@ module Micro
|
|
92
159
|
private_constant :WRONG_NUMBER_OF_ARGS
|
93
160
|
end
|
94
161
|
|
95
|
-
private_constant :ForSubclasses
|
162
|
+
private_constant :Options, :ForSubclasses
|
96
163
|
end
|
97
164
|
|
98
165
|
private_constant :Macros
|
@@ -1,25 +1,58 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
module Micro
|
4
|
-
module
|
5
|
-
module
|
6
|
-
def self.
|
7
|
-
|
3
|
+
module Micro::Attributes
|
4
|
+
module Utils
|
5
|
+
module Hashes
|
6
|
+
def self.kind(hash)
|
7
|
+
Kind::Of.(::Hash, hash)
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.stringify_keys(arg)
|
11
|
+
hash = kind(arg)
|
8
12
|
|
9
13
|
return hash if hash.empty?
|
14
|
+
return hash.transform_keys(&:to_s) if hash.respond_to?(:transform_keys)
|
10
15
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
+
hash.each_with_object({}) { |(key, val), memo| memo[key.to_s] = val }
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.symbolize_keys(arg)
|
20
|
+
hash = kind(arg)
|
21
|
+
|
22
|
+
return hash if hash.empty?
|
23
|
+
return hash.transform_keys(&:to_sym) if hash.respond_to?(:transform_keys)
|
24
|
+
|
25
|
+
hash.each_with_object({}) { |(key, val), memo| memo[key.to_sym] = val }
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.keys_as(type, hash)
|
29
|
+
return kind(hash) unless type
|
30
|
+
|
31
|
+
return symbolize_keys(hash) if type == Symbol || type == :symbol
|
32
|
+
return stringify_keys(hash) if type == String || type == :string
|
33
|
+
|
34
|
+
raise ArgumentError, 'argument must be one of these values: :symbol, :string, Symbol, String'.freeze
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.assoc(hash, key)
|
38
|
+
value = hash[key.to_s]
|
39
|
+
|
40
|
+
value.nil? ? hash[key.to_sym] : value
|
16
41
|
end
|
42
|
+
end
|
43
|
+
|
44
|
+
module ExtractAttribute
|
45
|
+
def self.call(object, key:)
|
46
|
+
return object.public_send(key) if object.respond_to?(key)
|
17
47
|
|
18
|
-
|
19
|
-
|
48
|
+
Hashes.assoc(object, key) if object.respond_to?(:[])
|
49
|
+
end
|
20
50
|
|
21
|
-
|
22
|
-
|
51
|
+
def self.from(object, keys:)
|
52
|
+
Kind::Of.(::Array, keys).each_with_object({}) do |key, memo|
|
53
|
+
memo[key] = call(object, key: key)
|
54
|
+
end
|
55
|
+
end
|
23
56
|
end
|
24
57
|
end
|
25
58
|
end
|
data/u-attributes.gemspec
CHANGED
@@ -20,7 +20,7 @@ Gem::Specification.new do |spec|
|
|
20
20
|
# Specify which files should be added to the gem when it is released.
|
21
21
|
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
22
22
|
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
|
23
|
-
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
23
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features|assets)/}) }
|
24
24
|
end
|
25
25
|
spec.bindir = 'exe'
|
26
26
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: u-attributes
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rodrigo Serradura
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-09-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: kind
|
@@ -76,20 +76,21 @@ files:
|
|
76
76
|
- LICENSE.txt
|
77
77
|
- README.md
|
78
78
|
- Rakefile
|
79
|
-
- assets/u-attributes_logo_v1.png
|
80
79
|
- bin/console
|
81
80
|
- bin/setup
|
82
81
|
- lib/micro/attributes.rb
|
83
82
|
- lib/micro/attributes/diff.rb
|
84
83
|
- lib/micro/attributes/features.rb
|
84
|
+
- lib/micro/attributes/features/accept.rb
|
85
|
+
- lib/micro/attributes/features/accept/strict.rb
|
85
86
|
- lib/micro/attributes/features/activemodel_validations.rb
|
86
87
|
- lib/micro/attributes/features/diff.rb
|
87
88
|
- lib/micro/attributes/features/initialize.rb
|
88
89
|
- lib/micro/attributes/features/initialize/strict.rb
|
90
|
+
- lib/micro/attributes/features/keys_as_symbol.rb
|
89
91
|
- lib/micro/attributes/macros.rb
|
90
92
|
- lib/micro/attributes/utils.rb
|
91
93
|
- lib/micro/attributes/version.rb
|
92
|
-
- lib/micro/attributes/with.rb
|
93
94
|
- lib/u-attributes.rb
|
94
95
|
- test.sh
|
95
96
|
- u-attributes.gemspec
|
Binary file
|
@@ -1,100 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'micro/attributes/features/diff'
|
4
|
-
require 'micro/attributes/features/initialize'
|
5
|
-
require 'micro/attributes/features/initialize/strict'
|
6
|
-
require 'micro/attributes/features/activemodel_validations'
|
7
|
-
|
8
|
-
module Micro
|
9
|
-
module Attributes
|
10
|
-
module With
|
11
|
-
#
|
12
|
-
# Features
|
13
|
-
#
|
14
|
-
module Diff
|
15
|
-
def self.included(base)
|
16
|
-
base.send(:include, ::Micro::Attributes)
|
17
|
-
base.send(:include, ::Micro::Attributes::Features::Diff)
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
module Initialize
|
22
|
-
def self.included(base)
|
23
|
-
base.send(:include, ::Micro::Attributes)
|
24
|
-
base.send(:include, ::Micro::Attributes::Features::Initialize)
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
module ActiveModelValidations
|
29
|
-
def self.included(base)
|
30
|
-
base.send(:include, ::Micro::Attributes)
|
31
|
-
base.send(:include, ::Micro::Attributes::Features::ActiveModelValidations)
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
module StrictInitialize
|
36
|
-
def self.included(base)
|
37
|
-
base.send(:include, Initialize)
|
38
|
-
base.send(:include, ::Micro::Attributes::Features::Initialize::Strict)
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
#
|
43
|
-
# Combinations
|
44
|
-
#
|
45
|
-
module DiffAndInitialize
|
46
|
-
def self.included(base)
|
47
|
-
base.send(:include, ::Micro::Attributes)
|
48
|
-
base.send(:include, ::Micro::Attributes::Features::Initialize)
|
49
|
-
base.send(:include, ::Micro::Attributes::Features::Diff)
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
module DiffAndStrictInitialize
|
54
|
-
def self.included(base)
|
55
|
-
base.send(:include, DiffAndInitialize)
|
56
|
-
base.send(:include, ::Micro::Attributes::Features::Initialize::Strict)
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
module ActiveModelValidationsAndDiff
|
61
|
-
def self.included(base)
|
62
|
-
base.send(:include, ::Micro::Attributes)
|
63
|
-
base.send(:include, ::Micro::Attributes::Features::ActiveModelValidations)
|
64
|
-
base.send(:include, ::Micro::Attributes::Features::Diff)
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
module ActiveModelValidationsAndInitialize
|
69
|
-
def self.included(base)
|
70
|
-
base.send(:include, ::Micro::Attributes)
|
71
|
-
base.send(:include, ::Micro::Attributes::Features::Initialize)
|
72
|
-
base.send(:include, ::Micro::Attributes::Features::ActiveModelValidations)
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
module ActiveModelValidationsAndStrictInitialize
|
77
|
-
def self.included(base)
|
78
|
-
base.send(:include, ActiveModelValidationsAndInitialize)
|
79
|
-
base.send(:include, ::Micro::Attributes::Features::Initialize::Strict)
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
module ActiveModelValidationsAndDiffAndInitialize
|
84
|
-
def self.included(base)
|
85
|
-
base.send(:include, ::Micro::Attributes)
|
86
|
-
base.send(:include, ::Micro::Attributes::Features::Initialize)
|
87
|
-
base.send(:include, ::Micro::Attributes::Features::ActiveModelValidations)
|
88
|
-
base.send(:include, ::Micro::Attributes::Features::Diff)
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
module ActiveModelValidationsAndDiffAndStrictInitialize
|
93
|
-
def self.included(base)
|
94
|
-
base.send(:include, ActiveModelValidationsAndDiffAndInitialize)
|
95
|
-
base.send(:include, ::Micro::Attributes::Features::Initialize::Strict)
|
96
|
-
end
|
97
|
-
end
|
98
|
-
end
|
99
|
-
end
|
100
|
-
end
|