u-attributes 0.14.0 → 1.0.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a1f5001cf28666ddb39188b98a736ef80375e7ff91367aa3a84183e524b698e2
4
- data.tar.gz: c260e6a0e12dd6d9edf251318b6667b3b13b7cd9d6964f8ff5defa80679b9a67
3
+ metadata.gz: b3daaa2daf1f8ce4a90b6053e8a5a35d5f066197a15b4353f8f5e09717639bba
4
+ data.tar.gz: '0499ade9185a2406a06acbc9d33b2e3de808ee23e5625af436253f0d654c7762'
5
5
  SHA512:
6
- metadata.gz: 3855b41867f2b635d2687766baf6c6bcdc15c5b7a149879b3640ea327071e45f564b1438a66dfbd7f11a90b6a7f9b6c7265b2b8d6732ad71b1a2203839113d14
7
- data.tar.gz: 3e322ab6d47de45fe6120969ae876be1fa936d6a639cbc7346ce70b5f400ad801d8a7b83640b864d80dd7f008327d9bc9d47af286a4feea59300a07aa3a459c2
6
+ metadata.gz: 8a8ca5c7ee283753e8cbc1a6bf43580d71d98578bb0462464753da03df03c4c2a967629ae54be767a35b5d25720d38b07b85b992546eead410fcbd2180b547f1
7
+ data.tar.gz: b1cf4055d9e3cc08c87d4fefe2a6b91797fcab85904f0697299cfd22525a0615a3e0d947339bac23ae3fd8b3113c11b05cd8c1609f38adaaaabb1b3781513e1a
data/.travis.yml CHANGED
@@ -1,18 +1,28 @@
1
- ---
2
- sudo: false
3
1
  language: ruby
4
- cache: bundler
2
+
3
+ sudo: false
4
+
5
5
  rvm:
6
- - 2.2.2
7
- - 2.3.0
8
- - 2.4.0
9
- - 2.5.0
10
- - 2.6.0
6
+ - 2.2.2
7
+ - 2.3.0
8
+ - 2.4.0
9
+ - 2.5.0
10
+ - 2.6.0
11
+
12
+ cache: bundler
13
+
11
14
  before_install:
12
15
  - gem uninstall -v '>= 2' -i $(rvm gemdir)@global -ax bundler || true
13
16
  - gem install bundler -v '< 2'
17
+
14
18
  install: bundle install --jobs=3 --retry=3
15
- env:
16
- - DISABLE_SIMPLECOV=true
17
- script: ./.travis.sh
18
19
 
20
+ before_script:
21
+ - curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
22
+ - chmod +x ./cc-test-reporter
23
+ - "./cc-test-reporter before-build"
24
+
25
+ script: "./.travis.sh"
26
+
27
+ after_success:
28
+ - "./cc-test-reporter after-build -t simplecov"
data/Gemfile CHANGED
@@ -1,7 +1,5 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
- gem 'simplecov', require: false, group: :test
4
-
5
3
  activemodel_version = ENV.fetch('ACTIVEMODEL_VERSION', '6.1')
6
4
 
7
5
  activemodel = case activemodel_version
@@ -20,9 +18,10 @@ if activemodel_version < '6.1'
20
18
  gem 'activesupport', activemodel, require: false
21
19
  end
22
20
 
23
- minitest = activemodel_version < '4.1' ? '~> 4.2' : '~> 5.0'
24
-
25
- gem 'minitest', minitest
21
+ group :test do
22
+ gem 'minitest', activemodel_version < '4.1' ? '~> 4.2' : '~> 5.0'
23
+ gem 'simplecov', require: false
24
+ end
26
25
 
27
26
  # Specify your gem's dependencies in u-attributes.gemspec
28
27
  gemspec
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- u-attributes (0.14.0)
4
+ u-attributes (1.0.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
data/README.md CHANGED
@@ -1,4 +1,7 @@
1
- [![Build Status](https://travis-ci.com/serradura/u-attributes.svg?branch=master)](https://travis-ci.com/serradura/u-attributes) [![Maintainability](https://api.codeclimate.com/v1/badges/b562e6b877a9edf4dbf6/maintainability)](https://codeclimate.com/github/serradura/u-attributes/maintainability)
1
+ [![Gem](https://img.shields.io/gem/v/u-attributes.svg?style=flat-square)](https://rubygems.org/gems/u-attributes)
2
+ [![Build Status](https://travis-ci.com/serradura/u-attributes.svg?branch=master)](https://travis-ci.com/serradura/u-attributes)
3
+ [![Maintainability](https://api.codeclimate.com/v1/badges/b562e6b877a9edf4dbf6/maintainability)](https://codeclimate.com/github/serradura/u-attributes/maintainability)
4
+ [![Test Coverage](https://api.codeclimate.com/v1/badges/b562e6b877a9edf4dbf6/test_coverage)](https://codeclimate.com/github/serradura/u-attributes/test_coverage)
2
5
 
3
6
  μ-attributes (Micro::Attributes)
4
7
  ================================
@@ -6,23 +9,25 @@
6
9
  This gem allows defining read-only attributes, that is, your objects will have only getters to access their attributes data.
7
10
 
8
11
  ## Table of contents
9
- - [μ-attributes (Micro::Attributes)](#%CE%BC-attributes-MicroAttributes)
10
- - [Table of contents](#Table-of-contents)
11
- - [Installation](#Installation)
12
- - [Usage](#Usage)
13
- - [How to require?](#How-to-require)
14
- - [How to define attributes?](#How-to-define-attributes)
15
- - [How to define multiple attributes?](#How-to-define-multiple-attributes)
16
- - [How to define attributes with a constructor to assign them?](#How-to-define-attributes-with-a-constructor-to-assign-them)
17
- - [How to query the attributes?](#How-to-query-the-attributes)
18
- - [Built-in extensions](#Built-in-extensions)
19
- - [ActiveModel::Validations extension](#ActiveModelValidations-extension)
20
- - [Diff extension](#Diff-extension)
21
- - [Initialize extension](#Initialize-extension)
22
- - [Development](#Development)
23
- - [Contributing](#Contributing)
24
- - [License](#License)
25
- - [Code of Conduct](#Code-of-Conduct)
12
+ - [μ-attributes (Micro::Attributes)](#%ce%bc-attributes-microattributes)
13
+ - [Table of contents](#table-of-contents)
14
+ - [Installation](#installation)
15
+ - [Usage](#usage)
16
+ - [How to require?](#how-to-require)
17
+ - [How to define attributes?](#how-to-define-attributes)
18
+ - [How to define multiple attributes?](#how-to-define-multiple-attributes)
19
+ - [How to define attributes with a constructor to assign them?](#how-to-define-attributes-with-a-constructor-to-assign-them)
20
+ - [How to inherit the attributes?](#how-to-inherit-the-attributes)
21
+ - [How to query the attributes?](#how-to-query-the-attributes)
22
+ - [Built-in extensions](#built-in-extensions)
23
+ - [ActiveModel::Validations extension](#activemodelvalidations-extension)
24
+ - [Diff extension](#diff-extension)
25
+ - [Initialize extension](#initialize-extension)
26
+ - [Strict initialize extension](#strict-initialize-extension)
27
+ - [Development](#development)
28
+ - [Contributing](#contributing)
29
+ - [License](#license)
30
+ - [Code of Conduct](#code-of-conduct)
26
31
 
27
32
  ## Installation
28
33
 
@@ -198,9 +203,40 @@ puts other_person.equal?(person) # false
198
203
  # Person.new(1)
199
204
  # ArgumentError (argument must be a Hash)
200
205
 
201
- ################
202
- # Inheritance #
203
- ################
206
+ #--------------------#
207
+ # Strict initializer #
208
+ #--------------------#
209
+
210
+ # Use .to_initialize! to forbids an instantiation without all keywords.
211
+
212
+ class StrictPerson
213
+ include Micro::Attributes.to_initialize!
214
+
215
+ attributes :age, name: 'John Doe'
216
+ end
217
+
218
+ StrictPerson.new({})
219
+
220
+ # The code above will raise:
221
+ # ArgumentError (missing keyword: :age)
222
+
223
+ person_without_age = StrictPerson.new(age: nil)
224
+
225
+ p person_without_age.name # "John Doe"
226
+ p person_without_age.age # nil
227
+
228
+ # Except for this validation when initializing,
229
+ # the `to_initialize!` method will works in the same ways of `to_initialize`.
230
+ ```
231
+
232
+ ### How to inherit the attributes?
233
+
234
+ ```ruby
235
+ class Person
236
+ include Micro::Attributes.to_initialize
237
+
238
+ attributes :age, name: 'John Doe'
239
+ end
204
240
 
205
241
  class Subclass < Person # Will preserve the parent class attributes
206
242
  attribute :foo
@@ -322,11 +358,11 @@ end
322
358
  # Note:
323
359
  # If `Micro::Attributes.features()` be invoked without arguments, a module with all features will be returned.
324
360
 
325
- # --------------------------------------------------------------------#
326
- # Using the .with() method alias and adding the initialize extension. #
327
- # --------------------------------------------------------------------#
361
+ #----------------------------------------------------------------------------#
362
+ # Using the .with() method alias and adding the strict initialize extension. #
363
+ #----------------------------------------------------------------------------#
328
364
  class Job
329
- include Micro::Attributes.with(:initialize, :diff)
365
+ include Micro::Attributes.with(:strict_initialize, :diff)
330
366
 
331
367
  attributes :id, state: 'sleeping'
332
368
  end
@@ -338,14 +374,26 @@ end
338
374
  # include Micro::Attributes.with() # ArgumentError (Invalid feature name! Available options: diff, initialize, activemodel_validations)
339
375
  # end
340
376
 
377
+ #===================================#
378
+ # Alternatives to the methods above #
379
+ #===================================#
380
+
341
381
  #---------------------------------------#
342
382
  # Via Micro::Attributes.to_initialize() #
343
383
  #---------------------------------------#
344
384
  class Job
345
- include Micro::Attributes.to_initialize(diff: false, activemodel_validations: true)
385
+ include Micro::Attributes.to_initialize(diff: true, activemodel_validations: true)
346
386
 
347
- attributes :id, state: 'sleeping'
348
- validates! :id, :state, presence: true
387
+ # Same of `include Micro::Attributes.with(:initialize, :diff, :activemodel_validations)`
388
+ end
389
+
390
+ #----------------------------------------#
391
+ # Via Micro::Attributes.to_initialize!() #
392
+ #----------------------------------------#
393
+ class Job
394
+ include Micro::Attributes.to_initialize!(diff: false, activemodel_validations: true)
395
+
396
+ # Same of `include Micro::Attributes.with(:strict_initialize, :activemodel_validations)`
349
397
  end
350
398
  ```
351
399
 
@@ -428,14 +476,19 @@ p job_changes.differences # {"state"=> {"from" => "sleeping", "to" => "running"}
428
476
 
429
477
  ```ruby
430
478
  class Job
431
- # include Micro::Attributes.features(:initialize)
432
479
  # include Micro::Attributes.with(:initialize)
433
480
  # include Micro::Attributes.feature(:initialize)
481
+ # include Micro::Attributes.features(:initialize)
434
482
  include Micro::Attributes.to_initialize
435
483
 
436
484
  attributes :id, :state
437
485
  end
438
486
 
487
+ job_null = Job.new({})
488
+
489
+ p job.id # nil
490
+ p job.state # nil
491
+
439
492
  job = Job.new(id: 1, state: 'sleeping')
440
493
 
441
494
  p job.id # 1
@@ -468,6 +521,50 @@ puts other_job.state # killed
468
521
  puts other_job.equal?(job) # false
469
522
  ```
470
523
 
524
+ ### Strict initialize extension
525
+
526
+ 1. Creates a constructor to assign the attributes.
527
+ 2. Adds methods to build new instances when some data was assigned.
528
+ 3. **Forbids missing keywords**.
529
+
530
+ ```ruby
531
+ class Job
532
+ # include Micro::Attributes.with(:strict_initialize)
533
+ # include Micro::Attributes.feature(:strict_initialize)
534
+ # include Micro::Attributes.features(:strict_initialize)
535
+ include Micro::Attributes.to_initialize!
536
+
537
+ attributes :id, :state
538
+ end
539
+ #----------------------------------------------------------------------------#
540
+ # The strict_initialize extension will require all the keys when initialize. #
541
+ #----------------------------------------------------------------------------#
542
+
543
+ Job.new({})
544
+
545
+ # The code above will raise:
546
+ # ArgumentError (missing keywords: :id, :state)
547
+
548
+ #---------------------------#
549
+ # Samples passing some data #
550
+ #---------------------------#
551
+
552
+ job_null = Job.new({})
553
+
554
+ p job.id # nil
555
+ p job.state # nil
556
+
557
+ job = Job.new(id: 1, state: 'sleeping')
558
+
559
+ p job.id # 1
560
+ p job.state # "sleeping"
561
+
562
+
563
+ # Note:
564
+ # This extension works like the `initialize` extension.
565
+ # So, look at its section to understand all the other features.
566
+ ```
567
+
471
568
  ## Development
472
569
 
473
570
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -0,0 +1,43 @@
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
@@ -5,18 +5,22 @@ require "micro/attributes/with"
5
5
  module Micro
6
6
  module Attributes
7
7
  module Features
8
- INVALID_FEATURES = 'Invalid feature name! Available options: :initialize, :diff, :activemodel_validations'.freeze
8
+ INVALID_FEATURES = 'Invalid feature name! Available options: :initialize, :strict_initialize, :diff, :activemodel_validations'.freeze
9
9
 
10
10
  OPTIONS = {
11
11
  # Features
12
12
  'diff' => With::Diff,
13
13
  'initialize' => With::Initialize,
14
+ 'strict_initialize' => With::StrictInitialize,
14
15
  'activemodel_validations' => With::ActiveModelValidations,
15
16
  # Combinations
16
17
  'diff:initialize' => With::DiffAndInitialize,
18
+ 'diff:strict_initialize' => With::DiffAndStrictInitialize,
17
19
  'activemodel_validations:diff' => With::ActiveModelValidationsAndDiff,
18
20
  'activemodel_validations:initialize' => With::ActiveModelValidationsAndInitialize,
19
- 'activemodel_validations:diff:initialize' => With::ActiveModelValidationsAndDiffAndInitialize
21
+ 'activemodel_validations:strict_initialize' => With::ActiveModelValidationsAndStrictInitialize,
22
+ 'activemodel_validations:diff:initialize' => With::ActiveModelValidationsAndDiffAndInitialize,
23
+ 'activemodel_validations:diff:strict_initialize' => With::ActiveModelValidationsAndDiffAndStrictInitialize
20
24
  }.freeze
21
25
 
22
26
  private_constant :OPTIONS
@@ -30,6 +34,13 @@ module Micro
30
34
  return option if option
31
35
  raise ArgumentError, INVALID_FEATURES
32
36
  end
37
+
38
+ def self.options(init, diff, activemodel_validations)
39
+ [init].tap do |options|
40
+ options << :diff if diff
41
+ options << :activemodel_validations if activemodel_validations
42
+ end
43
+ end
33
44
  end
34
45
  end
35
46
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Micro
4
4
  module Attributes
5
- VERSION = '0.14.0'.freeze
5
+ VERSION = '1.0.0'.freeze
6
6
  end
7
7
  end
@@ -3,6 +3,7 @@
3
3
  require 'micro/attributes/features/diff'
4
4
  require 'micro/attributes/features/initialize'
5
5
  require 'micro/attributes/features/activemodel_validations'
6
+ require 'micro/attributes/features/strict_initialize'
6
7
 
7
8
  module Micro
8
9
  module Attributes
@@ -31,6 +32,13 @@ module Micro
31
32
  end
32
33
  end
33
34
 
35
+ module StrictInitialize
36
+ def self.included(base)
37
+ base.send(:include, ::Micro::Attributes)
38
+ base.send(:include, ::Micro::Attributes::Features::StrictInitialize)
39
+ end
40
+ end
41
+
34
42
  #
35
43
  # Combinations
36
44
  #
@@ -42,6 +50,14 @@ module Micro
42
50
  end
43
51
  end
44
52
 
53
+ module DiffAndStrictInitialize
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)
58
+ end
59
+ end
60
+
45
61
  module ActiveModelValidationsAndDiff
46
62
  def self.included(base)
47
63
  base.send(:include, ::Micro::Attributes)
@@ -58,6 +74,14 @@ module Micro
58
74
  end
59
75
  end
60
76
 
77
+ module ActiveModelValidationsAndStrictInitialize
78
+ 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)
82
+ end
83
+ end
84
+
61
85
  module ActiveModelValidationsAndDiffAndInitialize
62
86
  def self.included(base)
63
87
  base.send(:include, ::Micro::Attributes)
@@ -66,6 +90,15 @@ module Micro
66
90
  base.send(:include, ::Micro::Attributes::Features::Diff)
67
91
  end
68
92
  end
93
+
94
+ module ActiveModelValidationsAndDiffAndStrictInitialize
95
+ 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)
100
+ end
101
+ end
69
102
  end
70
103
  end
71
104
  end
@@ -23,10 +23,11 @@ module Micro
23
23
  end
24
24
 
25
25
  def self.to_initialize(diff: false, activemodel_validations: false)
26
- options = [:initialize]
27
- options << :diff if diff
28
- options << :activemodel_validations if activemodel_validations
29
- features(*options)
26
+ features(*Features.options(:initialize, diff, activemodel_validations))
27
+ end
28
+
29
+ def self.to_initialize!(diff: false, activemodel_validations: false)
30
+ features(*Features.options(:strict_initialize, diff, activemodel_validations))
30
31
  end
31
32
 
32
33
  def self.with(*names)
@@ -41,18 +42,21 @@ module Micro
41
42
  names.empty? ? Features.all : Features.with(names)
42
43
  end
43
44
 
44
- def attributes=(arg)
45
- self.class.attributes_data(AttributesUtils.hash_argument!(arg)).each do |name, value|
46
- __attributes[name] = instance_variable_set("@#{name}", value) if attribute?(name)
47
- end
45
+ protected def attributes=(arg)
46
+ self.class
47
+ .attributes_data(AttributesUtils.hash_argument!(arg))
48
+ .each { |name, value| __attribute_set(name, value) }
49
+
48
50
  __attributes.freeze
49
51
  end
50
- protected :attributes=
51
52
 
52
- def __attributes
53
+ private def __attributes
53
54
  @__attributes ||= {}
54
55
  end
55
- private :__attributes
56
+
57
+ private def __attribute_set(name, value)
58
+ __attributes[name] = instance_variable_set("@#{name}", value) if attribute?(name)
59
+ end
56
60
 
57
61
  def attributes
58
62
  __attributes
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: 0.14.0
4
+ version: 1.0.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-07-27 00:00:00.000000000 Z
11
+ date: 2019-07-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -49,6 +49,7 @@ files:
49
49
  - lib/micro/attributes/features/activemodel_validations.rb
50
50
  - lib/micro/attributes/features/diff.rb
51
51
  - lib/micro/attributes/features/initialize.rb
52
+ - lib/micro/attributes/features/strict_initialize.rb
52
53
  - lib/micro/attributes/macros.rb
53
54
  - lib/micro/attributes/version.rb
54
55
  - lib/micro/attributes/with.rb