u-attributes 0.14.0 → 1.0.0

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