u-attributes 2.1.0 → 2.5.0

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