u-attributes 2.5.0 → 2.6.0

Sign up to get free protection for your applications and to get access to all the features.
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