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.
@@ -3,13 +3,45 @@
3
3
  module Micro::Attributes
4
4
  module Features
5
5
  module ActiveModelValidations
6
- def self.included(base)
7
- begin
8
- require 'active_model'
6
+ module Standard
7
+ private def __call_after_attributes_assign
8
+ run_validations!
9
+ end
10
+ end
9
11
 
10
- base.send(:include, ::ActiveModel::Validations)
11
- base.extend(ClassMethods)
12
- rescue LoadError
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
- private
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
- def __call_after_micro_attribute
28
- run_validations! if respond_to?(:run_validations!, true)
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
- private
24
-
25
- def __call_after_micro_attribute; end
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, is_required, hasnt_default)
20
- if is_required || (attributes_are_all_required? && hasnt_default)
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
- def __attributes_data_to_assign(name, options)
28
- hasnt_default = !options.key?(:default)
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
- hasnt_default ? __attributes_required_add(name, options[:required], hasnt_default) : options[:default]
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, options)
44
- name = key.to_s
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, options) if can_overwrite || !has_attribute
104
+ __attributes_data__[name] = __attributes_data_to_assign(name, opt) if can_overwrite || !has_attribute
50
105
 
51
- __call_after_attribute_assign__(name, options)
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
- __attribute_assign(key, true, val ? { default: val } : {})
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.to_s)
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, Kind::Empty::HASH)
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 Attributes
5
- module Utils
6
- def self.stringify_hash_keys(arg)
7
- hash = Kind::Of.(::Hash, arg)
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
- if hash.respond_to?(:transform_keys)
12
- hash.transform_keys { |key| key.to_s }
13
- else
14
- hash.each_with_object({}) { |(key, val), memo| memo[key.to_s] = val }
15
- end
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
- HashAccess = -> (hash, key) {
19
- return hash[key.to_s] unless hash[key.to_s].nil?
48
+ Hashes.assoc(object, key) if object.respond_to?(:[])
49
+ end
20
50
 
21
- hash[key.to_sym]
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
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Micro
4
4
  module Attributes
5
- VERSION = '2.1.0'.freeze
5
+ VERSION = '2.5.0'.freeze
6
6
  end
7
7
  end
@@ -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.1.0
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-08-23 00:00:00.000000000 Z
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
@@ -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