u-attributes 1.0.1 → 2.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Micro::Attributes
4
+ module Features
5
+ module Initialize
6
+ module Strict
7
+ MISSING_KEYWORD = 'missing keyword'.freeze
8
+ MISSING_KEYWORDS = 'missing keywords'.freeze
9
+
10
+ protected def attributes=(arg)
11
+ arg_hash = Utils.stringify_hash_keys(arg)
12
+ att_data = self.class.__attributes_data__
13
+
14
+ attributes_missing!(ref: att_data, arg: arg_hash)
15
+
16
+ __attributes_set(arg_hash, att_data)
17
+ end
18
+
19
+ private def attributes_missing!(ref:, arg:)
20
+ missing_keys = attributes_missing(ref, arg)
21
+
22
+ return if missing_keys.empty?
23
+
24
+ label = missing_keys.size == 1 ? MISSING_KEYWORD : MISSING_KEYWORDS
25
+
26
+ raise ArgumentError, "#{label}: #{missing_keys.join(', ')}"
27
+ end
28
+
29
+ private def attributes_missing(ref, arg)
30
+ ref.each_with_object([]) do |(key, val), memo|
31
+ memo << ":#{key}" if val.nil? && !arg.has_key?(key)
32
+ end
33
+ end
34
+
35
+ private_constant :MISSING_KEYWORD, :MISSING_KEYWORDS
36
+ end
37
+ end
38
+ end
39
+ end
@@ -3,8 +3,8 @@
3
3
  module Micro
4
4
  module Attributes
5
5
  module Macros
6
- def __attributes_data
7
- @__attributes_data ||= {}
6
+ def __attributes_data__
7
+ @__attributes_data__ ||= {}
8
8
  end
9
9
 
10
10
  def __attributes
@@ -13,58 +13,60 @@ module Micro
13
13
 
14
14
  def __attribute_reader(name)
15
15
  __attributes.add(name)
16
+
16
17
  attr_reader(name)
17
18
  end
18
19
 
19
- def __attribute_set(key, value, can_overwrite)
20
+ def __attribute_set(key, can_overwrite, options)
20
21
  name = key.to_s
21
22
  has_attribute = attribute?(name)
23
+
22
24
  __attribute_reader(name) unless has_attribute
23
- __attributes_data[name] = value if can_overwrite || !has_attribute
24
- end
25
+ __attributes_data__[name] = options[:default] if can_overwrite || !has_attribute
25
26
 
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) }
27
+ __call_after_attribute_set__(name, options)
29
28
  end
30
29
 
31
- def __attributes_set(args, can_overwrite)
32
- args.flatten.each { |arg| __attributes_def(arg, can_overwrite) }
30
+ def __call_after_attribute_set__(attr_name, options); end
31
+
32
+ def __attributes_set_after_inherit__(arg)
33
+ arg.each { |key, val| __attribute_set(key, true, default: val) }
33
34
  end
34
35
 
35
36
  def attribute?(name)
36
37
  __attributes.member?(name.to_s)
37
38
  end
38
39
 
39
- def attribute(name, value=nil)
40
- __attribute_set(name, value, false)
40
+ def attribute(name, options = Kind::Empty::HASH)
41
+ __attribute_set(name, false, options)
41
42
  end
42
43
 
43
44
  def attributes(*args)
44
45
  return __attributes.to_a if args.empty?
45
- __attributes_set(args, can_overwrite: false)
46
- end
47
46
 
48
- def attributes_data(arg)
49
- __attributes_data.merge(AttributesUtils.stringify_hash_keys!(arg))
47
+ args.flatten!
48
+ args.each do |arg|
49
+ if arg.is_a?(String) || arg.is_a?(Symbol)
50
+ __attribute_set(arg, false, Kind::Empty::HASH)
51
+ else
52
+ raise Kind::Error.new('String/Symbol'.freeze, arg)
53
+ end
54
+ end
50
55
  end
51
56
 
52
57
  module ForSubclasses
53
58
  WRONG_NUMBER_OF_ARGS = 'wrong number of arguments (given 0, expected 1 or more)'.freeze
54
59
 
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
60
+ def attribute!(name, options = Kind::Empty::HASH)
61
+ __attribute_set(name, true, options)
62
62
  end
63
63
 
64
64
  private_constant :WRONG_NUMBER_OF_ARGS
65
65
  end
66
+
66
67
  private_constant :ForSubclasses
67
68
  end
69
+
68
70
  private_constant :Macros
69
71
  end
70
72
  end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Micro
4
+ module Attributes
5
+ module Utils
6
+ def self.stringify_hash_keys(arg)
7
+ hash = Kind::Of.(::Hash, arg)
8
+
9
+ return hash if hash.empty?
10
+
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
+ end
17
+ end
18
+ end
19
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Micro
4
4
  module Attributes
5
- VERSION = '1.0.1'.freeze
5
+ VERSION = '2.0.1'.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
@@ -34,8 +34,8 @@ module Micro
34
34
 
35
35
  module StrictInitialize
36
36
  def self.included(base)
37
- base.send(:include, ::Micro::Attributes)
38
- base.send(:include, ::Micro::Attributes::Features::StrictInitialize)
37
+ base.send(:include, Initialize)
38
+ base.send(:include, ::Micro::Attributes::Features::Initialize::Strict)
39
39
  end
40
40
  end
41
41
 
@@ -52,9 +52,8 @@ module Micro
52
52
 
53
53
  module DiffAndStrictInitialize
54
54
  def self.included(base)
55
- base.send(:include, ::Micro::Attributes)
56
- base.send(:include, ::Micro::Attributes::Features::StrictInitialize)
57
- base.send(:include, ::Micro::Attributes::Features::Diff)
55
+ base.send(:include, DiffAndInitialize)
56
+ base.send(:include, ::Micro::Attributes::Features::Initialize::Strict)
58
57
  end
59
58
  end
60
59
 
@@ -76,9 +75,8 @@ module Micro
76
75
 
77
76
  module ActiveModelValidationsAndStrictInitialize
78
77
  def self.included(base)
79
- base.send(:include, ::Micro::Attributes)
80
- base.send(:include, ::Micro::Attributes::Features::StrictInitialize)
81
- base.send(:include, ::Micro::Attributes::Features::ActiveModelValidations)
78
+ base.send(:include, ActiveModelValidationsAndInitialize)
79
+ base.send(:include, ::Micro::Attributes::Features::Initialize::Strict)
82
80
  end
83
81
  end
84
82
 
@@ -93,10 +91,8 @@ module Micro
93
91
 
94
92
  module ActiveModelValidationsAndDiffAndStrictInitialize
95
93
  def self.included(base)
96
- base.send(:include, ::Micro::Attributes)
97
- base.send(:include, ::Micro::Attributes::Features::StrictInitialize)
98
- base.send(:include, ::Micro::Attributes::Features::ActiveModelValidations)
99
- base.send(:include, ::Micro::Attributes::Features::Diff)
94
+ base.send(:include, ActiveModelValidationsAndDiffAndInitialize)
95
+ base.send(:include, ::Micro::Attributes::Features::Initialize::Strict)
100
96
  end
101
97
  end
102
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.0.1
4
+ version: 2.0.1
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-07-31 00:00:00.000000000 Z
11
+ date: 2020-08-21 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,20 @@ 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
44
79
  - bin/console
45
80
  - bin/setup
46
81
  - lib/micro/attributes.rb
47
- - lib/micro/attributes/attributes_utils.rb
82
+ - lib/micro/attributes/diff.rb
48
83
  - lib/micro/attributes/features.rb
49
84
  - lib/micro/attributes/features/activemodel_validations.rb
50
85
  - lib/micro/attributes/features/diff.rb
51
86
  - lib/micro/attributes/features/initialize.rb
52
- - lib/micro/attributes/features/strict_initialize.rb
87
+ - lib/micro/attributes/features/initialize/strict.rb
53
88
  - lib/micro/attributes/macros.rb
89
+ - lib/micro/attributes/utils.rb
54
90
  - lib/micro/attributes/version.rb
55
91
  - lib/micro/attributes/with.rb
56
92
  - lib/u-attributes.rb
@@ -75,8 +111,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
75
111
  - !ruby/object:Gem::Version
76
112
  version: '0'
77
113
  requirements: []
78
- rubygems_version: 3.0.3
114
+ rubygems_version: 3.0.6
79
115
  signing_key:
80
116
  specification_version: 4
81
- summary: Define read-only attributes
117
+ summary: Create "immutable" objects. No setters, just getters!
82
118
  test_files: []
@@ -1,29 +0,0 @@
1
- PATH
2
- remote: .
3
- specs:
4
- u-attributes (1.0.1)
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
@@ -1,21 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Micro
4
- module Attributes
5
- module AttributesUtils
6
- ARGUMENT_ERROR_MSG = 'argument must be a Hash'.freeze
7
-
8
- def self.hash_argument!(arg)
9
- return arg if arg.is_a?(Hash)
10
-
11
- raise ArgumentError, ARGUMENT_ERROR_MSG
12
- end
13
-
14
- def self.stringify_hash_keys!(arg)
15
- hash_argument!(arg).each_with_object({}) do |(key, val), memo|
16
- memo[key.to_s] = val
17
- end
18
- end
19
- end
20
- end
21
- end
@@ -1,43 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Micro::Attributes
4
- module Features
5
- module StrictInitialize
6
- MISSING_KEYWORD = 'missing keyword'.freeze
7
- MISSING_KEYWORDS = 'missing keywords'.freeze
8
-
9
- def self.included(base)
10
- base.send(:include, ::Micro::Attributes::Features::Initialize)
11
- end
12
-
13
- protected def attributes=(arg)
14
- arg_hash = AttributesUtils.stringify_hash_keys!(arg)
15
- att_data = self.class.attributes_data({})
16
-
17
- attributes_missing!(ref: att_data, arg: arg_hash)
18
-
19
- att_data.merge(arg_hash).each { |name, value| __attribute_set(name, value) }
20
-
21
- __attributes.freeze
22
- end
23
-
24
- private def attributes_missing!(ref:, arg:)
25
- missing_keys = attributes_missing(ref, arg)
26
-
27
- return if missing_keys.empty?
28
-
29
- label = missing_keys.size == 1 ? MISSING_KEYWORD : MISSING_KEYWORDS
30
-
31
- raise ArgumentError, "#{label}: #{missing_keys.join(', ')}"
32
- end
33
-
34
- private def attributes_missing(ref, arg)
35
- ref.each_with_object([]) do |(key, val), memo|
36
- memo << ":#{key}" if val.nil? && !arg.has_key?(key)
37
- end
38
- end
39
-
40
- private_constant :MISSING_KEYWORD, :MISSING_KEYWORDS
41
- end
42
- end
43
- end