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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 01dbce30afd7d116e15ea5985e5012d86f2bd110b017394151086df322e9b7ed
4
- data.tar.gz: 4004e27e835cc216807b2fb2781a15911c16f2ba20e509b7c36188a8b6021f95
3
+ metadata.gz: 484a7b770e8ae7dd141c7538e2bc50c1b82beb63e24ee53dd9f9445cbd91f057
4
+ data.tar.gz: 3d555771a3deba711dc4995cd12674461b94c82e65ccbdd9bba215d354adaa52
5
5
  SHA512:
6
- metadata.gz: ca177ca900f63a07901366612f5ef545512db4e8f9b48bea6482403af6346324784910fa9dca963e681449a1d3b583b173317890b76e8a2e03fd46b58af32006
7
- data.tar.gz: 44372485364d637906d1dad476fc58a98cf228c33e252012af320e7e1da36b82db3943eb635ed34dff211908088f6fc8fe3c2de8a1b9a418f62f8e8b3e1596ed
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.5.0 | main | >= 2.2.0 | >= 3.2, < 6.1 |
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.
@@ -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, :__attributes_data_to_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, "undefined attribute `#{name}"
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, default, keep_proc = false) do
119
- if default.is_a?(Proc) && !keep_proc
120
- default.arity > 0 ? default.call(value) : default.call
121
- else
122
- value.nil? ? default : value
123
- end
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[0])
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] = instance_variable_set("@#{name}", value_to_assign)
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[0], KeepProc.(validation_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 __attributes_required__
32
- @__attributes_required__ ||= Set.new
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
- 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
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
- hasnt_default ? __attributes_required_add(name, opt, hasnt_default) : opt[:default],
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 __attributes
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
- __attributes_data__[name] = __attributes_data_to_assign(name, opt) if can_overwrite || !has_attribute
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 = if default = val[0]
115
- requ_key, requ_val = val[1]
155
+ opt = {}
116
156
 
117
- hash = requ_key ? { requ_key => requ_val } : {}
118
- hash[:default] = default
119
- hash
120
- end
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
- __attributes.member?(__attribute_key_transform__(name))
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
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Micro
4
4
  module Attributes
5
- VERSION = '2.5.0'.freeze
5
+ VERSION = '2.6.0'.freeze
6
6
  end
7
7
  end
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.5.0
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-22 00:00:00.000000000 Z
11
+ date: 2020-09-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: kind