u-attributes 1.2.0 → 2.2.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.
@@ -7,6 +7,7 @@ module Micro::Attributes
7
7
  base.class_eval(<<-RUBY)
8
8
  def initialize(arg)
9
9
  self.attributes = arg
10
+ __call_after_micro_attribute
10
11
  end
11
12
  RUBY
12
13
  end
@@ -18,6 +19,10 @@ module Micro::Attributes
18
19
  def with_attributes(arg)
19
20
  self.class.new(attributes.merge(arg))
20
21
  end
22
+
23
+ private
24
+
25
+ def __call_after_micro_attribute; end
21
26
  end
22
27
  end
23
28
  end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Micro::Attributes
4
+ module Features
5
+ module Initialize
6
+ module Strict
7
+ module ClassMethods
8
+ def attributes_are_all_required?
9
+ true
10
+ end
11
+ end
12
+
13
+ def self.included(base)
14
+ base.send(:extend, ClassMethods)
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -3,8 +3,31 @@
3
3
  module Micro
4
4
  module Attributes
5
5
  module Macros
6
- def __attributes_data
7
- @__attributes_data ||= {}
6
+ def attributes_are_all_required?
7
+ false
8
+ end
9
+
10
+ # NOTE: can't be renamed! It is used by u-case v4.
11
+ def __attributes_data__
12
+ @__attributes_data__ ||= {}
13
+ end
14
+
15
+ def __attributes_required__
16
+ @__attributes_required__ ||= Set.new
17
+ end
18
+
19
+ def __attributes_required_add(name, is_required, hasnt_default)
20
+ if is_required || (attributes_are_all_required? && hasnt_default)
21
+ __attributes_required__.add(name)
22
+ end
23
+
24
+ nil
25
+ end
26
+
27
+ def __attributes_data_to_assign(name, options)
28
+ hasnt_default = !options.key?(:default)
29
+
30
+ hasnt_default ? __attributes_required_add(name, options[:required], hasnt_default) : options[:default]
8
31
  end
9
32
 
10
33
  def __attributes
@@ -13,58 +36,69 @@ module Micro
13
36
 
14
37
  def __attribute_reader(name)
15
38
  __attributes.add(name)
39
+
16
40
  attr_reader(name)
17
41
  end
18
42
 
19
- def __attribute_set(key, value, can_overwrite)
43
+ def __attribute_assign(key, can_overwrite, options)
20
44
  name = key.to_s
21
45
  has_attribute = attribute?(name)
46
+
22
47
  __attribute_reader(name) unless has_attribute
23
- __attributes_data[name] = value if can_overwrite || !has_attribute
24
- end
25
48
 
26
- def __attributes_def(arg, can_overwrite)
27
- return __attribute_set(arg, nil, can_overwrite) unless arg.is_a?(::Hash)
28
- arg.each { |key, val| __attribute_set(key, val, can_overwrite) }
49
+ __attributes_data__[name] = __attributes_data_to_assign(name, options) if can_overwrite || !has_attribute
50
+
51
+ __call_after_attribute_assign__(name, options)
29
52
  end
30
53
 
31
- def __attributes_set(args, can_overwrite)
32
- args.flatten.each { |arg| __attributes_def(arg, can_overwrite) }
54
+ def __call_after_attribute_assign__(attr_name, options); end
55
+
56
+ # NOTE: can't be renamed! It is used by u-case v4.
57
+ def __attributes_set_after_inherit__(arg)
58
+ arg.each do |key, val|
59
+ __attribute_assign(key, true, val ? { default: val } : {})
60
+ end
33
61
  end
34
62
 
35
63
  def attribute?(name)
36
64
  __attributes.member?(name.to_s)
37
65
  end
38
66
 
39
- def attribute(name, value=nil)
40
- __attribute_set(name, value, false)
67
+ def attribute(name, options = Kind::Empty::HASH)
68
+ __attribute_assign(name, false, options)
41
69
  end
42
70
 
43
71
  def attributes(*args)
44
72
  return __attributes.to_a if args.empty?
45
- __attributes_set(args, can_overwrite: false)
46
- end
47
73
 
48
- def attributes_data(arg)
49
- __attributes_data.merge(AttributesUtils.stringify_hash_keys!(arg))
74
+ args.flatten!
75
+
76
+ options =
77
+ args.size > 1 && args.last.is_a?(::Hash) ? args.pop : Kind::Empty::HASH
78
+
79
+ args.each do |arg|
80
+ if arg.is_a?(String) || arg.is_a?(Symbol)
81
+ __attribute_assign(arg, false, options)
82
+ else
83
+ raise Kind::Error.new('String/Symbol'.freeze, arg)
84
+ end
85
+ end
50
86
  end
51
87
 
88
+ # NOTE: can't be renamed! It is used by u-case v4.
52
89
  module ForSubclasses
53
90
  WRONG_NUMBER_OF_ARGS = 'wrong number of arguments (given 0, expected 1 or more)'.freeze
54
91
 
55
- def attribute!(name, value=nil)
56
- __attribute_set(name, value, true)
57
- end
58
-
59
- def attributes!(*args)
60
- return __attributes_set(args, can_overwrite: true) unless args.empty?
61
- raise ArgumentError, WRONG_NUMBER_OF_ARGS
92
+ def attribute!(name, options = Kind::Empty::HASH)
93
+ __attribute_assign(name, true, options)
62
94
  end
63
95
 
64
96
  private_constant :WRONG_NUMBER_OF_ARGS
65
97
  end
98
+
66
99
  private_constant :ForSubclasses
67
100
  end
101
+
68
102
  private_constant :Macros
69
103
  end
70
104
  end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Micro::Attributes
4
+ module Utils
5
+ module Hashes
6
+ def self.stringify_keys(arg)
7
+ hash = Kind::Of.(::Hash, arg)
8
+
9
+ return hash if hash.empty?
10
+ return hash.transform_keys(&:to_s) if hash.respond_to?(:transform_keys)
11
+
12
+ hash.each_with_object({}) { |(key, val), memo| memo[key.to_s] = val }
13
+ end
14
+
15
+ def self.get(hash, key)
16
+ value = hash[key.to_s]
17
+
18
+ value.nil? ? hash[key.to_sym] : value
19
+ end
20
+ end
21
+
22
+ module ExtractAttribute
23
+ def self.call(object, key:)
24
+ return object.public_send(key) if object.respond_to?(key)
25
+
26
+ Hashes.get(object, key) if object.respond_to?(:[])
27
+ end
28
+
29
+ def self.from(object, keys:)
30
+ Kind::Of.(::Array, keys).each_with_object({}) do |key, memo|
31
+ memo[key] = call(object, key: key)
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Micro
4
4
  module Attributes
5
- VERSION = '1.2.0'.freeze
5
+ VERSION = '2.2.0'.freeze
6
6
  end
7
7
  end
@@ -2,8 +2,8 @@
2
2
 
3
3
  require 'micro/attributes/features/diff'
4
4
  require 'micro/attributes/features/initialize'
5
+ require 'micro/attributes/features/initialize/strict'
5
6
  require 'micro/attributes/features/activemodel_validations'
6
- require 'micro/attributes/features/strict_initialize'
7
7
 
8
8
  module Micro
9
9
  module Attributes
@@ -27,7 +27,7 @@ module Micro
27
27
 
28
28
  module ActiveModelValidations
29
29
  def self.included(base)
30
- base.send(:include, ::Micro::Attributes)
30
+ base.send(:include, Initialize)
31
31
  base.send(:include, ::Micro::Attributes::Features::ActiveModelValidations)
32
32
  end
33
33
  end
@@ -35,7 +35,7 @@ module Micro
35
35
  module StrictInitialize
36
36
  def self.included(base)
37
37
  base.send(:include, Initialize)
38
- base.send(:include, ::Micro::Attributes::Features::StrictInitialize)
38
+ base.send(:include, ::Micro::Attributes::Features::Initialize::Strict)
39
39
  end
40
40
  end
41
41
 
@@ -53,7 +53,7 @@ module Micro
53
53
  module DiffAndStrictInitialize
54
54
  def self.included(base)
55
55
  base.send(:include, DiffAndInitialize)
56
- base.send(:include, ::Micro::Attributes::Features::StrictInitialize)
56
+ base.send(:include, ::Micro::Attributes::Features::Initialize::Strict)
57
57
  end
58
58
  end
59
59
 
@@ -76,7 +76,7 @@ module Micro
76
76
  module ActiveModelValidationsAndStrictInitialize
77
77
  def self.included(base)
78
78
  base.send(:include, ActiveModelValidationsAndInitialize)
79
- base.send(:include, ::Micro::Attributes::Features::StrictInitialize)
79
+ base.send(:include, ::Micro::Attributes::Features::Initialize::Strict)
80
80
  end
81
81
  end
82
82
 
@@ -92,7 +92,7 @@ module Micro
92
92
  module ActiveModelValidationsAndDiffAndStrictInitialize
93
93
  def self.included(base)
94
94
  base.send(:include, ActiveModelValidationsAndDiffAndInitialize)
95
- base.send(:include, ::Micro::Attributes::Features::StrictInitialize)
95
+ base.send(:include, ::Micro::Attributes::Features::Initialize::Strict)
96
96
  end
97
97
  end
98
98
  end
@@ -1,28 +1,35 @@
1
1
 
2
- lib = File.expand_path("../lib", __FILE__)
2
+ lib = File.expand_path('../lib', __FILE__)
3
3
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require "micro/attributes/version"
4
+ require 'micro/attributes/version'
5
5
 
6
6
  Gem::Specification.new do |spec|
7
- spec.name = "u-attributes"
7
+ spec.name = 'u-attributes'
8
8
  spec.version = Micro::Attributes::VERSION
9
- spec.authors = ["Rodrigo Serradura"]
10
- spec.email = ["rodrigo.serradura@gmail.com"]
9
+ spec.authors = ['Rodrigo Serradura']
10
+ spec.email = ['rodrigo.serradura@gmail.com']
11
11
 
12
- spec.summary = %q{Define read-only attributes}
13
- spec.description = %q{This gem allows defining read-only attributes, that is, your objects will have only getters to access their attributes data.}
14
- spec.homepage = "https://github.com/serradura/u-attributes"
15
- spec.license = "MIT"
12
+ spec.summary = %q{Create "immutable" objects. No setters, just getters!}
13
+ spec.description =
14
+ "This gem allows you to define \"immutable\" objects, and your objects will have only getters and no setters. "\
15
+ "So, if you change some object attribute, you will have a new object instance. " \
16
+ "That is, you transform the object instead of modifying it."
17
+ spec.homepage = 'https://github.com/serradura/u-attributes'
18
+ spec.license = 'MIT'
16
19
 
17
20
  # Specify which files should be added to the gem when it is released.
18
21
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
19
22
  spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
20
23
  `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
21
24
  end
22
- spec.bindir = "exe"
25
+ spec.bindir = 'exe'
23
26
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
24
- spec.require_paths = ["lib"]
27
+ spec.require_paths = ['lib']
25
28
 
26
29
  spec.required_ruby_version = '>= 2.2.0'
27
- spec.add_development_dependency "rake", "~> 10.0"
30
+
31
+ spec.add_runtime_dependency 'kind', '>= 3.0', '< 5.0'
32
+
33
+ spec.add_development_dependency 'bundler'
34
+ spec.add_development_dependency 'rake', '~> 13.0'
28
35
  end
metadata CHANGED
@@ -1,31 +1,67 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: u-attributes
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 2.2.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: 2019-08-08 00:00:00.000000000 Z
11
+ date: 2020-09-02 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: kind
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '3.0'
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '5.0'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: '3.0'
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '5.0'
33
+ - !ruby/object:Gem::Dependency
34
+ name: bundler
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '0'
40
+ type: :development
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
13
47
  - !ruby/object:Gem::Dependency
14
48
  name: rake
15
49
  requirement: !ruby/object:Gem::Requirement
16
50
  requirements:
17
51
  - - "~>"
18
52
  - !ruby/object:Gem::Version
19
- version: '10.0'
53
+ version: '13.0'
20
54
  type: :development
21
55
  prerelease: false
22
56
  version_requirements: !ruby/object:Gem::Requirement
23
57
  requirements:
24
58
  - - "~>"
25
59
  - !ruby/object:Gem::Version
26
- version: '10.0'
27
- description: This gem allows defining read-only attributes, that is, your objects
28
- will have only getters to access their attributes data.
60
+ version: '13.0'
61
+ description: This gem allows you to define "immutable" objects, and your objects will
62
+ have only getters and no setters. So, if you change some object attribute, you will
63
+ have a new object instance. That is, you transform the object instead of modifying
64
+ it.
29
65
  email:
30
66
  - rodrigo.serradura@gmail.com
31
67
  executables: []
@@ -37,20 +73,21 @@ files:
37
73
  - ".travis.yml"
38
74
  - CODE_OF_CONDUCT.md
39
75
  - Gemfile
40
- - Gemfile.lock
41
76
  - LICENSE.txt
42
77
  - README.md
43
78
  - Rakefile
79
+ - assets/u-attributes_logo_v1.png
44
80
  - bin/console
45
81
  - bin/setup
46
82
  - lib/micro/attributes.rb
47
- - lib/micro/attributes/attributes_utils.rb
83
+ - lib/micro/attributes/diff.rb
48
84
  - lib/micro/attributes/features.rb
49
85
  - lib/micro/attributes/features/activemodel_validations.rb
50
86
  - lib/micro/attributes/features/diff.rb
51
87
  - lib/micro/attributes/features/initialize.rb
52
- - lib/micro/attributes/features/strict_initialize.rb
88
+ - lib/micro/attributes/features/initialize/strict.rb
53
89
  - lib/micro/attributes/macros.rb
90
+ - lib/micro/attributes/utils.rb
54
91
  - lib/micro/attributes/version.rb
55
92
  - lib/micro/attributes/with.rb
56
93
  - lib/u-attributes.rb
@@ -75,8 +112,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
75
112
  - !ruby/object:Gem::Version
76
113
  version: '0'
77
114
  requirements: []
78
- rubygems_version: 3.0.3
115
+ rubygems_version: 3.0.6
79
116
  signing_key:
80
117
  specification_version: 4
81
- summary: Define read-only attributes
118
+ summary: Create "immutable" objects. No setters, just getters!
82
119
  test_files: []
@@ -1,29 +0,0 @@
1
- PATH
2
- remote: .
3
- specs:
4
- u-attributes (1.2.0)
5
-
6
- GEM
7
- remote: https://rubygems.org/
8
- specs:
9
- docile (1.3.2)
10
- json (2.2.0)
11
- minitest (5.11.3)
12
- rake (10.5.0)
13
- simplecov (0.17.0)
14
- docile (~> 1.1)
15
- json (>= 1.8, < 3)
16
- simplecov-html (~> 0.10.0)
17
- simplecov-html (0.10.2)
18
-
19
- PLATFORMS
20
- ruby
21
-
22
- DEPENDENCIES
23
- minitest (~> 5.0)
24
- rake (~> 10.0)
25
- simplecov
26
- u-attributes!
27
-
28
- BUNDLED WITH
29
- 1.17.3