u-attributes 2.5.0 → 2.6.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 +1 -1
- data/lib/micro/attributes.rb +34 -14
- data/lib/micro/attributes/features/accept.rb +1 -1
- data/lib/micro/attributes/macros.rb +116 -60
- data/lib/micro/attributes/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 484a7b770e8ae7dd141c7538e2bc50c1b82beb63e24ee53dd9f9445cbd91f057
|
4
|
+
data.tar.gz: 3d555771a3deba711dc4995cd12674461b94c82e65ccbdd9bba215d354adaa52
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fc5f65eb1a10c5172f0b6a1fa5296f4470e024fa42559cfe0d64d89d0a07c0c203ae28ce1b66afae741669a8073b1c6cbb7d05d5373874946afefca6620d7874
|
7
|
+
data.tar.gz: db8895b0a85d803de7ec04f81fc83fb98eac4b487ed4224e7fb7b6bda3d66293758ce416341dddbd40ae630dfb96d4d26cdd380990a3fca2580df931b459311a
|
data/README.md
CHANGED
@@ -85,7 +85,7 @@ gem 'u-attributes'
|
|
85
85
|
|
86
86
|
| u-attributes | branch | ruby | activemodel |
|
87
87
|
| -------------- | ------- | -------- | ------------- |
|
88
|
-
| 2.
|
88
|
+
| 2.6.0 | main | >= 2.2.0 | >= 3.2, < 6.1 |
|
89
89
|
| 1.2.0 | v1.x | >= 2.2.0 | >= 3.2, < 6.1 |
|
90
90
|
|
91
91
|
> **Note**: The activemodel is an optional dependency, this module [can be enabled](#activemodelvalidation-extension) to validate the attributes.
|
data/lib/micro/attributes.rb
CHANGED
@@ -15,7 +15,7 @@ module Micro
|
|
15
15
|
|
16
16
|
base.class_eval do
|
17
17
|
private_class_method :__attributes, :__attribute_reader
|
18
|
-
private_class_method :__attribute_assign, :
|
18
|
+
private_class_method :__attribute_assign, :__attributes_groups
|
19
19
|
private_class_method :__attributes_required_add, :__attributes_data_to_assign
|
20
20
|
end
|
21
21
|
|
@@ -38,8 +38,8 @@ module Micro
|
|
38
38
|
Features.all
|
39
39
|
end
|
40
40
|
|
41
|
-
def attribute?(name)
|
42
|
-
self.class.attribute?(name)
|
41
|
+
def attribute?(name, include_all = false)
|
42
|
+
self.class.attribute?(name, include_all)
|
43
43
|
end
|
44
44
|
|
45
45
|
def attribute(name)
|
@@ -53,10 +53,12 @@ module Micro
|
|
53
53
|
def attribute!(name, &block)
|
54
54
|
attribute(name) { |name| return block ? block[name] : name }
|
55
55
|
|
56
|
-
raise NameError,
|
56
|
+
raise NameError, __attribute_access_error_message(name)
|
57
57
|
end
|
58
58
|
|
59
|
-
def defined_attributes
|
59
|
+
def defined_attributes(option = nil)
|
60
|
+
return self.class.attributes_by_visibility if option == :by_visibility
|
61
|
+
|
60
62
|
@defined_attributes ||= self.class.attributes
|
61
63
|
end
|
62
64
|
|
@@ -107,6 +109,12 @@ module Micro
|
|
107
109
|
Utils::ExtractAttribute.from(other, keys: defined_attributes)
|
108
110
|
end
|
109
111
|
|
112
|
+
def __attribute_access_error_message(name)
|
113
|
+
return "tried to access a private attribute `#{name}" if attribute?(name, true)
|
114
|
+
|
115
|
+
"undefined attribute `#{name}"
|
116
|
+
end
|
117
|
+
|
110
118
|
def __attribute_key(value)
|
111
119
|
self.class.__attribute_key_transform__(value)
|
112
120
|
end
|
@@ -115,26 +123,38 @@ module Micro
|
|
115
123
|
@__attributes ||= {}
|
116
124
|
end
|
117
125
|
|
118
|
-
FetchValueToAssign = -> (value,
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
126
|
+
FetchValueToAssign = -> (value, attribute_data, keep_proc = false) do
|
127
|
+
default = attribute_data[0]
|
128
|
+
|
129
|
+
value_to_assign =
|
130
|
+
if default.is_a?(Proc) && !keep_proc
|
131
|
+
default.arity > 0 ? default.call(value) : default.call
|
132
|
+
else
|
133
|
+
value.nil? ? default : value
|
134
|
+
end
|
135
|
+
|
136
|
+
return value_to_assign unless to_freeze = attribute_data[2]
|
137
|
+
return value_to_assign.freeze if to_freeze == true
|
138
|
+
return value_to_assign.dup.freeze if to_freeze == :after_dup
|
139
|
+
return value_to_assign.clone.freeze if to_freeze == :after_clone
|
140
|
+
|
141
|
+
raise NotImplementedError
|
124
142
|
end
|
125
143
|
|
126
144
|
def __attributes_assign(hash)
|
127
145
|
self.class.__attributes_data__.each do |name, attribute_data|
|
128
|
-
__attribute_assign(name, hash[name], attribute_data) if attribute?(name)
|
146
|
+
__attribute_assign(name, hash[name], attribute_data) if attribute?(name, true)
|
129
147
|
end
|
130
148
|
|
131
149
|
__attributes.freeze
|
132
150
|
end
|
133
151
|
|
134
152
|
def __attribute_assign(name, initialize_value, attribute_data)
|
135
|
-
value_to_assign = FetchValueToAssign.(initialize_value, attribute_data
|
153
|
+
value_to_assign = FetchValueToAssign.(initialize_value, attribute_data)
|
154
|
+
|
155
|
+
ivar_value = instance_variable_set("@#{name}", value_to_assign)
|
136
156
|
|
137
|
-
__attributes[name] =
|
157
|
+
__attributes[name] = ivar_value if attribute_data[3] == :public
|
138
158
|
end
|
139
159
|
|
140
160
|
MISSING_KEYWORD = 'missing keyword'.freeze
|
@@ -38,7 +38,7 @@ module Micro::Attributes
|
|
38
38
|
def __attribute_assign(key, initialize_value, attribute_data)
|
39
39
|
validation_data = attribute_data[1]
|
40
40
|
|
41
|
-
value_to_assign = FetchValueToAssign.(initialize_value, attribute_data
|
41
|
+
value_to_assign = FetchValueToAssign.(initialize_value, attribute_data, KeepProc.(validation_data))
|
42
42
|
|
43
43
|
value = __attributes[key] = instance_variable_set("@#{key}", value_to_assign)
|
44
44
|
|
@@ -3,6 +3,60 @@
|
|
3
3
|
module Micro
|
4
4
|
module Attributes
|
5
5
|
module Macros
|
6
|
+
module Options
|
7
|
+
PERMITTED = [
|
8
|
+
:default, :required, :freeze, :protected, :private, # for all
|
9
|
+
:validate, :validates, # for ext: activemodel_validations
|
10
|
+
:accept, :reject, :allow_nil, :rejection_message # for ext: accept
|
11
|
+
].freeze
|
12
|
+
|
13
|
+
INVALID_MESSAGE = [
|
14
|
+
"Found one or more invalid options: %{invalid_options}\n\nThe valid ones are: ",
|
15
|
+
PERMITTED.map { |key| ":#{key}" }.join(', ')
|
16
|
+
].join.freeze
|
17
|
+
|
18
|
+
def self.check(opt)
|
19
|
+
invalid_keys = opt.keys - PERMITTED
|
20
|
+
|
21
|
+
return if invalid_keys.empty?
|
22
|
+
|
23
|
+
invalid_options = { invalid_options: invalid_keys.inspect.tr('[', '').tr(']', '') }
|
24
|
+
|
25
|
+
raise ArgumentError, (INVALID_MESSAGE % invalid_options)
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.for_accept(opt)
|
29
|
+
allow_nil = opt[:allow_nil]
|
30
|
+
rejection_message = opt[:rejection_message]
|
31
|
+
|
32
|
+
return [:accept, opt[:accept], allow_nil, rejection_message] if opt.key?(:accept)
|
33
|
+
return [:reject, opt[:reject], allow_nil, rejection_message] if opt.key?(:reject)
|
34
|
+
|
35
|
+
Kind::Empty::ARRAY
|
36
|
+
end
|
37
|
+
|
38
|
+
ALL = 0
|
39
|
+
PUBLIC = 1
|
40
|
+
PRIVATE = 2
|
41
|
+
PROTECTED = 3
|
42
|
+
REQUIRED = 4
|
43
|
+
|
44
|
+
def self.visibility_index(opt)
|
45
|
+
return PRIVATE if opt[:private]
|
46
|
+
return PROTECTED if opt[:protected]
|
47
|
+
PUBLIC
|
48
|
+
end
|
49
|
+
|
50
|
+
VISIBILITY_NAMES = { PUBLIC => :public, PRIVATE => :private, PROTECTED => :protected }.freeze
|
51
|
+
|
52
|
+
def self.visibility_name_from_index(visibility_index)
|
53
|
+
VISIBILITY_NAMES[visibility_index]
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.private?(visibility); visibility == PRIVATE; end
|
57
|
+
def self.protected?(visibility); visibility == PROTECTED; end
|
58
|
+
end
|
59
|
+
|
6
60
|
def attributes_are_all_required?
|
7
61
|
false
|
8
62
|
end
|
@@ -11,6 +65,22 @@ module Micro
|
|
11
65
|
:indifferent
|
12
66
|
end
|
13
67
|
|
68
|
+
def __attributes_groups
|
69
|
+
@__attributes_groups ||= [
|
70
|
+
Set.new, # all
|
71
|
+
Set.new, # public
|
72
|
+
[], # private
|
73
|
+
[], # protected
|
74
|
+
Set.new, # required
|
75
|
+
]
|
76
|
+
end
|
77
|
+
|
78
|
+
def __attributes; __attributes_groups[Options::ALL]; end
|
79
|
+
|
80
|
+
def __attributes_public; __attributes_groups[Options::PUBLIC]; end
|
81
|
+
|
82
|
+
def __attributes_required__; __attributes_groups[Options::REQUIRED]; end
|
83
|
+
|
14
84
|
def __attribute_key_check__(value)
|
15
85
|
value
|
16
86
|
end
|
@@ -28,8 +98,14 @@ module Micro
|
|
28
98
|
@__attributes_data__ ||= {}
|
29
99
|
end
|
30
100
|
|
31
|
-
def
|
32
|
-
|
101
|
+
def __attribute_reader(name, visibility_index)
|
102
|
+
attr_reader(name)
|
103
|
+
|
104
|
+
__attributes.add(name)
|
105
|
+
__attributes_groups[visibility_index] << name
|
106
|
+
|
107
|
+
private(name) if Options.private?(visibility_index)
|
108
|
+
protected(name) if Options.protected?(visibility_index)
|
33
109
|
end
|
34
110
|
|
35
111
|
def __attributes_required_add(name, opt, hasnt_default)
|
@@ -40,91 +116,63 @@ module Micro
|
|
40
116
|
nil
|
41
117
|
end
|
42
118
|
|
43
|
-
|
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
|
64
|
-
|
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)
|
119
|
+
def __attributes_data_to_assign(name, opt, visibility_index)
|
77
120
|
hasnt_default = !opt.key?(:default)
|
78
121
|
|
122
|
+
default = hasnt_default ? __attributes_required_add(name, opt, hasnt_default) : opt[:default]
|
123
|
+
|
79
124
|
[
|
80
|
-
|
81
|
-
Options.for_accept(opt)
|
125
|
+
default,
|
126
|
+
Options.for_accept(opt),
|
127
|
+
opt[:freeze],
|
128
|
+
Options.visibility_name_from_index(visibility_index)
|
82
129
|
]
|
83
130
|
end
|
84
131
|
|
85
|
-
def
|
86
|
-
@__attributes ||= Set.new
|
87
|
-
end
|
88
|
-
|
89
|
-
def __attribute_reader(name)
|
90
|
-
__attributes.add(name)
|
91
|
-
|
92
|
-
attr_reader(name)
|
93
|
-
end
|
132
|
+
def __call_after_attribute_assign__(attr_name, options); end
|
94
133
|
|
95
134
|
def __attribute_assign(key, can_overwrite, opt)
|
96
135
|
name = __attribute_key_check__(__attribute_key_transform__(key))
|
97
136
|
|
98
137
|
Options.check(opt)
|
99
138
|
|
100
|
-
has_attribute = attribute?(name)
|
139
|
+
has_attribute = attribute?(name, true)
|
140
|
+
|
141
|
+
visibility_index = Options.visibility_index(opt)
|
101
142
|
|
102
|
-
__attribute_reader(name) unless has_attribute
|
143
|
+
__attribute_reader(name, visibility_index) unless has_attribute
|
103
144
|
|
104
|
-
|
145
|
+
if can_overwrite || !has_attribute
|
146
|
+
__attributes_data__[name] = __attributes_data_to_assign(name, opt, visibility_index)
|
147
|
+
end
|
105
148
|
|
106
149
|
__call_after_attribute_assign__(name, opt)
|
107
150
|
end
|
108
151
|
|
109
|
-
def __call_after_attribute_assign__(attr_name, options); end
|
110
|
-
|
111
152
|
# NOTE: can't be renamed! It is used by u-case v4.
|
112
153
|
def __attributes_set_after_inherit__(arg)
|
113
154
|
arg.each do |key, val|
|
114
|
-
opt =
|
115
|
-
requ_key, requ_val = val[1]
|
155
|
+
opt = {}
|
116
156
|
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
157
|
+
default = val[0]
|
158
|
+
accept_key, accept_val = val[1]
|
159
|
+
freeze, visibility = val[2], val[3]
|
160
|
+
|
161
|
+
opt[:default] = default if default
|
162
|
+
opt[accept_key] = accept_val if accept_key
|
163
|
+
opt[:freeze] = freeze if freeze
|
164
|
+
opt[visibility] = true if visibility != :public
|
121
165
|
|
122
166
|
__attribute_assign(key, true, opt || Kind::Empty::HASH)
|
123
167
|
end
|
124
168
|
end
|
125
169
|
|
126
|
-
def attribute?(name)
|
127
|
-
|
170
|
+
def attribute?(name, include_all = false)
|
171
|
+
key = __attribute_key_transform__(name)
|
172
|
+
|
173
|
+
return __attributes.member?(key) if include_all
|
174
|
+
|
175
|
+
__attributes_public.member?(key)
|
128
176
|
end
|
129
177
|
|
130
178
|
def attribute(name, options = Kind::Empty::HASH)
|
@@ -148,6 +196,14 @@ module Micro
|
|
148
196
|
end
|
149
197
|
end
|
150
198
|
|
199
|
+
def attributes_by_visibility
|
200
|
+
{
|
201
|
+
public: __attributes_groups[Options::PUBLIC].to_a,
|
202
|
+
private: __attributes_groups[Options::PRIVATE].dup,
|
203
|
+
protected: __attributes_groups[Options::PROTECTED].dup
|
204
|
+
}
|
205
|
+
end
|
206
|
+
|
151
207
|
# NOTE: can't be renamed! It is used by u-case v4.
|
152
208
|
module ForSubclasses
|
153
209
|
WRONG_NUMBER_OF_ARGS = 'wrong number of arguments (given 0, expected 1 or more)'.freeze
|
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.6.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-09-
|
11
|
+
date: 2020-09-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: kind
|