deco_lite 0.3.2 → 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: b5b5ed040bd367962dd57760a6a0e572b60485ba1d2d3630980ff1a090ca9075
4
- data.tar.gz: 76402762f17d93fd53495ddabf86487803b0014971db007f61f505727e933f56
3
+ metadata.gz: 00c4b0e5c7169ef19c7f3f43ddc01a13b542f542f6f42d8b84e14e648ea1dea1
4
+ data.tar.gz: a092f920b44a0c0274e0b39e7a4674f8ebc00ae81893a135dcfde274acf3ccd0
5
5
  SHA512:
6
- metadata.gz: 584e1c07a160370bc9548e7a41dbaa9adcbee757a35a37925d02accf4ebe71d24cd9d2932e706724f5d8d64e8d98ff77f223224de27e5a0d817eb2675fea81ca
7
- data.tar.gz: 6a49a3ab8bdcb947341697577e130dd667c508095578536e8d003cfa1424f8e090f3c40e9ddc1376a3337cdcc9a26a02e836bc901c0ae36da39a8acaaae8cc46
6
+ metadata.gz: 817c072e966c9ce994c10cc7113f1c6dbbf8653e9ca84af330903fc7f82187f3df4e995516871085a77f9de7c89eac2d0ba2f1a1a67dfbf5f8821406d7652c4e
7
+ data.tar.gz: 8878462c837f7e6e312ce0d9f6184ee3cab4c4cc564dd2d8aa49d1ac8954129e3d5ae9f0dde89ef9b3faffa4dd817d2e81065397163182c67414ee5266fae118
data/CHANGELOG.md CHANGED
@@ -1,3 +1,13 @@
1
+ ### 1.0.0
2
+ * Breaking changes
3
+ * Removed `FieldRequireable` and moved this code to the `Model` class because determination of required fields loaded is now determined in the `Model` class, rather than checking the existance of model attributes.
4
+ * Removed `RequiredFieldsOptionable` since determination of whether or not required fields were loaded no longer depends on the existance of model attributes, this option was removed. `Model#required_fields` model attributes can now be created unconditionally, and still determine whether or not reqired fields were loaded or not.
5
+ * Since `FieldRequireable` has been removed, along with `#required_fields`, the `Model#required_fields` can now be overridden or manipulated to designate required fields. Required fields will cause validtion to fail if those fields are not loaded into the model like before.
6
+ * The reason for the aforementioned changes is that the whole paradigm to validate "required fields" (i.e. fields required when loading a Hash) based on model attributes introduced complexity/awkwardness in using the `DecoLite::Model` class, as well as complexity in the `DecoLite` codebase. These changes makes things simpler and cleaner.
7
+ * Remove deprecated `DecoLite::Model#load`. Use `DecoLite::Model#load!` instead.
8
+ * Changes
9
+ * Update README.md file accordingly.
10
+
1
11
  ### 0.3.2
2
12
  * Changes
3
13
  * Refactor FieldAssignable to remove call to FieldCreatable#create_field_accessor as this breaks single responsibility rule; which, in this case, makes sense to remove. FieldCreatable#create_field_accessor can be called wherever creation of a attr_accessor is needed.
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- deco_lite (0.3.1)
4
+ deco_lite (1.0.0)
5
5
  activemodel (~> 7.0, >= 7.0.3.1)
6
6
  activesupport (~> 7.0, >= 7.0.3.1)
7
7
  immutable_struct_ex (~> 0.2.0)
@@ -25,7 +25,7 @@ GEM
25
25
  docile (1.4.0)
26
26
  i18n (1.12.0)
27
27
  concurrent-ruby (~> 1.0)
28
- immutable_struct_ex (0.2.2)
28
+ immutable_struct_ex (0.2.3)
29
29
  json (2.6.2)
30
30
  kwalify (0.7.2)
31
31
  mad_flatter (1.0.1.pre.beta)
@@ -63,7 +63,7 @@ GEM
63
63
  diff-lcs (>= 1.2.0, < 2.0)
64
64
  rspec-support (~> 3.11.0)
65
65
  rspec-support (3.11.0)
66
- rubocop (1.35.0)
66
+ rubocop (1.35.1)
67
67
  json (~> 2.3)
68
68
  parallel (~> 1.10)
69
69
  parser (>= 3.1.2.1)
@@ -107,4 +107,4 @@ DEPENDENCIES
107
107
  simplecov (~> 0.21.2)
108
108
 
109
109
  BUNDLED WITH
110
- 2.2.17
110
+ 2.3.22
data/README.md CHANGED
@@ -13,13 +13,9 @@
13
13
 
14
14
  ## Introduction
15
15
 
16
- DecoLite is in development. I wouldn't expect breaking changes before v1.0.0; however, I can't completely rule this out. Currently, DecoLite only supports Hashes whose keys are `Symbols`, contain no embedded spaces, and conform to Ruby `attr_accessor` naming conventions. However, I might try work out a reasonable solution for all this in future releases if the need is there.
16
+ _Deco_ is a little gem that allows you to use the provided `DecoLite::Model` class (`include ActiveModel::Model`) to dynamically create Decorator class objects. Inherit from `DecoLite::Model` to create your own unique classes with custom functionality. A `DecoLite::Model` includes `ActiveModel::Model`, so validation can be applied using [ActiveModel validation helpers](https://api.rubyonrails.org/v6.1.3/classes/ActiveModel/Validations/HelperMethods.html) you are familiar with; or, you can roll your own - just like any other ActiveModel.
17
17
 
18
- TBD: Documentation regarding `DecoLite::Model` options, `DecoLite::Model#load!` options: how these work, and how they play together (e.g. options `fields: :merge` and `fields: :strict` for example; in the meantime, see the specs).
19
-
20
- _Deco_ is a little gem that allows you to use the provided `DecoLite::Model` class (`include ActiveModel::Model`) to create Decorator classes which can be instantiated and used. Inherit from `DecoLite::Model` to create your own unique classes with custom functionality. A `DecoLite::Model` includes `ActiveModel::Model`, so validation can be applied using [ActiveModel validation helpers](https://api.rubyonrails.org/v6.1.3/classes/ActiveModel/Validations/HelperMethods.html) you are familiar with; or, you can roll your own - just like any other ActiveModel.
21
-
22
- A `DecoLite::Model` will allow you to consume a Ruby Hash that you supply via the initializer (`DecoLite::Model#new`) or via the `DecoLite::Model#load!` method. Your supplied Ruby Hashes are used to create `attr_accessor` attributes (_"fields"_) on the model. Each attribute created, is then assigned its value from the Hash loaded.
18
+ A `DecoLite::Model` will allow you to consume a Ruby Hash that you supply via the initializer (`DecoLite::Model#new`) or via the `DecoLite::Model#load!` method. Your supplied Ruby Hashes are used to create `attr_accessor` attributes (_"fields"_) on the model. Each attribute created, is then assigned its value from the Hash loaded. Any number of hashes can be consumed using the `DecoLite::Model#load!` method.
23
19
 
24
20
  `attr_accessor` names created are _mangled_ to include namespacing. This creates unique attribute names for nested Hashes that may include non-unique keys. For example:
25
21
 
@@ -34,7 +30,7 @@ family = {
34
30
  }
35
31
  }
36
32
  ```
37
- Given the above example, DecoLite will produce the following `attr_accessors` on the `DecoLite::Model` object when loaded, and assign the values:
33
+ Given the above example, DecoLite will produce the following `attr_accessors` on the `DecoLite::Model` object and assign the values:
38
34
 
39
35
  ```ruby
40
36
  # Or DecoLite::Model.new.load!(hash: family)
@@ -53,17 +49,21 @@ model.wife_age #=> 30
53
49
  model.respond_to? :wife_age= #=> true
54
50
  ```
55
51
 
56
- `DecoLite::Model#load!` can be called _multiple times_, on the same model, with different Hashes. This could potentially cause `attr_accessor` name clashes. In order to ensure unique `attr_accessor` names, a _"namespace"_ may be _explicitly_ provided to ensure uniqueness. For example, continuing from the previous example; if we were to call `DecoLite::Model#load!` a _second time_ with the following Hash, it would produce `attr_accessor` name clashes:
52
+ `DecoLite::Model#load!` can be called _multiple times_, on the same model, with different Hashes. This could potentially cause `attr_accessor` name clashes. In order to ensure unique `attr_accessor` names, a _"namespace"_ may be _explicitly_ provided to ensure uniqueness.
53
+
54
+ For example, **continuing from the previous example;** if we were to call `DecoLite::Model#load!` a _second time_ with the following Hash, this would potentially produce `attr_accessor` name clashes:
57
55
 
58
56
  ```ruby
59
57
  grandpa = {
60
58
  name: 'Henry Doe',
61
59
  age: 85,
62
60
  }
63
- # The :name and :age Hash keys above will produce :name/:name= and :age/:age= attr_accessors and clash because these were already added to the model when "John Doe" was loaded with the first call to DecoLite::Model.new(hash: family).
61
+ # The :name and :age Hash keys above will produce :name/:name= and :age/:age= attr_accessors
62
+ # and clash because these were already added to the model when "John Doe" was loaded with
63
+ # the first call to DecoLite::Model.new(hash: family).
64
64
  ```
65
65
 
66
- However, passing a `namespace:` option (for example `namespace: :grandpa`) to the `DecoLite::Model#load!` method, would produce the following `attr_accessors`, ensuring their uniqueness:
66
+ However, passing a `:namespace` option (for example `namespace: :grandpa`) to the `DecoLite::Model#load!` method, would produce the following `attr_accessors`, ensuring their uniqueness:
67
67
 
68
68
  ```ruby
69
69
  model.load!(hash: grandpa, options: { namespace: :grandpa })
@@ -88,6 +88,11 @@ model.respond_to? :wife_name= #=> true
88
88
  model.wife_age #=> 30
89
89
  model.respond_to? :wife_age= #=> true
90
90
  ```
91
+
92
+ ### For more examples and usage
93
+
94
+ For more examples and usage, see the [Examples and usage](#examples-and-usage) and [Mode examples and usage](#more-examples-and-usage) sections; there is also an "I want to..." section with examples you might encounter when using `DecoLite`.
95
+
91
96
  ## Use cases
92
97
 
93
98
  ### General
@@ -187,7 +192,7 @@ model.wife_info_address #=> 1 street, boonton, nj 07005
187
192
 
188
193
  #### Add validators to my model
189
194
 
190
- Simply add your `ActiveModel` validators just like you would any other `ActiveModel::Model` validator. However, be aware that (currently), any attribute (field) having an _explicit validation_ associated with it, will automatically cause an `attr_accessor` to be created for that field; this is to avoid `NoMethodErrors` when calling a validation method on the model (e.g. `#valid?`, `#validate`, etc.):
195
+ Simply add your `ActiveModel` validators just like you would any other `ActiveModel::Model` validator. However, be aware that (currently), any attribute (field) having an _explicit validation_ associated with it, will automatically cause an `attr_accessor` to be created for that field; this is to avoid `NoMethodErrors` when calling a validation method on the model (e.g. `#valid?`, `#validate`, etc.) *before* the data is loaded to create the associated `attr_accessors`:
191
196
 
192
197
  ```ruby
193
198
  class Model < DecoLite::Model
@@ -212,13 +217,11 @@ model.validate
212
217
 
213
218
  #### Validate whether or not certain fields were loaded
214
219
 
215
- To be clear, this has nothing to do with the _data_ associated with the fields loaded; rather, this has to do with whether or not the _fields themselves_ were created as attributes on your model as a result of loading data into your model. If you simply want to validate the _data_ loaded into your model, simply add `ActiveModel` validation, just like you would any other `ActiveModel` model, see the [Add validators to my model](#add-validators-to-my-model) section.
220
+ To be clear, this example does not validate the _data_ associated with the fields loaded; rather, this example validates whether or not the _fields themselves_ were loaded into your model, and as a result, `attr_accessors` created. If you only want to validate the _data_ loaded into your model, simply add `ActiveModel` validation, just like you would any other `ActiveModel` model, see the [Add validators to my model](#add-validators-to-my-model) section.
216
221
 
217
- If you want to validate whether or not particular _fields_ were added to your model as attributes (i.e. `attr_accessor`), as a result of `#load!`ing data into your model, you need to do a few things:
222
+ If you want to validate whether or not particular _fields_ were added to your model as attributes (`attr_accessor`), as a result of `#load!`ing data into your model, you need to add the required field names to the `DecoLite::Model#required_fields` attribute, or use inheritance:
218
223
  - Create a `DecoLite::Model` subclass.
219
- - Override the `DecoLite::Model#required_fields` method to return the field names you want to validate.
220
- - Use the `required_fields: nil` option when instantiating your model object.
221
- - DO NOT add `ActiveModel` validators that _explicitly_ reference any field returned from `DecoLite::Model#required_fields`; this will cause `attr_accessors` to be created for these fields; consequently, `DecoLite::FieldRequireable#validate_required_fields` will _never_ return any errors because these fields will exist as attributes on your model. In other words, do not add `validates :first, :last, :address, presence: true` to your model if you need to validate whether or not the data you load into your model included fields :first, :last and :address.
224
+ - Override the `DecoLite::Model#required_fields` method and return an Array of field names represented by `Symbols` you want to validate.
222
225
 
223
226
  For example:
224
227
 
@@ -228,22 +231,34 @@ class Model < DecoLite::Model
228
231
  validates :age, numericality: { only_integer: true }, allow_blank: true
229
232
 
230
233
  def required_fields
231
- # We want to ensure attr_accessors are created for these fields.
232
- %i(first last address)
234
+ # We want to ensure these fields were included as Hash keys during loading.
235
+ %i[first last address]
233
236
  end
234
237
  end
235
238
 
236
- # Option "required_fields: :auto" is the default which will automatically create
237
- # attr_accessors for fields returned from DecoLite::Model#required_fields, so we
238
- # need to set this option to nil (i.e. required_fields: nil).
239
- model = Model.new(options: { required_fields: nil })
239
+ model = Model.new
240
240
 
241
241
  model.validate
242
242
  #=> false
243
243
  model.errors.full_messages
244
244
  #=> ["First field is missing", "Last field is missing", "Address field is missing"]
245
245
 
246
- user = { first: 'John', last: 'Doe', address: '123 anystreet, anytown, nj 01234'}
246
+ # If we load data that includes :first, :last, and :address Hash keys even with
247
+ # nil data, our ":<field> field is missing" errors go away; in this scenario,
248
+ # we're validating the presence of the FIELDS, not the data associated with
249
+ # these fields!
250
+ model.load!(hash: { first: nil, last: nil, address: nil })
251
+ model.validate
252
+ #=> true
253
+ model.errors.full_messages
254
+ #=> []
255
+
256
+ user = {
257
+ first: 'John',
258
+ last: 'Doe',
259
+ address: '123 anystreet, anytown, nj 01234',
260
+ age: 'x'
261
+ }
247
262
  model.load!(hash: user)
248
263
  model.validate
249
264
  #=> false
@@ -254,34 +269,19 @@ model.errors.full_messages
254
269
 
255
270
  If you simply want to validate the _data_ loaded into your model, simply add `ActiveModel` validation, just like you would any other `ActiveModel` model, see the [Add validators to my model](#add-validators-to-my-model) section.
256
271
 
257
- If you want to validate whether or not particular fields were loaded _and_ field data associated with these same fields, you'll have to use custom validation (e.g. override `DecoLite::FieldRequireable#validate_required_fields` and manually add your own validation and errors). This is because `DecoLite::Model#new` will automatically create `attr_accessors` for any attribute (field) that has an _explicit_ `ActiveModel` validation associated with it, and return false positives when you validate your model. In addition to this, you will need to do several other things outlined in the [Validate whether or not certain fields were loaded](#validate-whether-or-not-certain-fields-were-loaded) section.
272
+ If you want to validate whether or not particular fields were loaded _and_ field data associated with these same fields, you simply need to add the required fields and any other validation(s).
258
273
 
259
274
  For example:
260
275
 
261
276
  ```ruby
262
277
  class Model < DecoLite::Model
263
- def required_fields
264
- %i(first last address age)
265
- end
266
-
267
- def validate_required_fields
268
- super
269
-
270
- first = self.try(:first)
271
- errors.add(:first, "can't be blank") if first.nil?
278
+ validates :first, :last, :address, :age, presence: true
272
279
 
273
- last = self.try(:last)
274
- errors.add(:last, "can't be blank") if last.nil?
275
-
276
- address = self.try(:address)
277
- errors.add(:address, "can't be blank") if address.nil?
278
-
279
- age = self.try(:age)
280
- errors.add(:age, "can't be blank") if age.nil?
281
- errors.add(:age, 'is not a number') unless /\d+/ =~ age
280
+ def required_fields
281
+ %i[first last address age]
282
282
  end
283
283
  end
284
- model = Model.new(options: { required_fields: nil })
284
+ model = Model.new
285
285
 
286
286
  model.validate
287
287
  #=> false
@@ -311,24 +311,26 @@ class JustBecauseYouCanDoesntMeanYouShould < DecoLite::Model
311
311
  def initialize(options: {})
312
312
  super
313
313
 
314
- @field_names = %i(existing_field)
314
+ @field_names = %i[existing_field]
315
315
  end
316
316
  end
317
317
  ```
318
318
 
319
- However, the above is unnecessary as this can be easily accomplished using `DecoLite::Model#load!`:
319
+ However, the above is unnecessary as this can be easily accomplished by passing a `Hash` to the initializer or by using `DecoLite::Model#load!`:
320
+
320
321
  ```ruby
321
- model = Class.new(DecoLite::Model).new.load!(hash:{ existing_field: :existing_field_value })
322
+ model = Class.new(DecoLite::Model).new(hash:{ existing_field: :value })
322
323
 
323
324
  model.field_names
324
325
  #=> [:existing_field]
325
326
 
326
327
  model.existing_field
327
- #=> :existing_field_value
328
+ #=> :value
328
329
 
329
330
  model.respond_to? :existing_field=
330
331
  #=> true
331
332
  ```
333
+
332
334
  ## Installation
333
335
 
334
336
  Add this line to your application's Gemfile:
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative 'field_name_namespaceable'
4
- require_relative 'field_requireable'
5
4
  require_relative 'fields_optionable'
6
5
 
7
6
  module DecoLite
@@ -10,7 +9,6 @@ module DecoLite
10
9
  module FieldConflictable
11
10
  include FieldNameNamespaceable
12
11
  include FieldsOptionable
13
- include FieldRequireable
14
12
 
15
13
  def validate_field_conflicts!(field_name:, options:)
16
14
  return unless field_conflict?(field_name: field_name, options: options)
@@ -10,14 +10,12 @@ module DecoLite
10
10
  auto_attr_accessors.present?
11
11
  end
12
12
 
13
- # This method returns a Hash of fields that are implicitly defined either
14
- # through ActiveModel validators or by returning them from the
15
- # #required_fields Array.
13
+ # This method returns a Hash of fields that are implicitly defined
14
+ # through ActiveModel validators.
16
15
  def auto_attr_accessors
17
16
  return @auto_attr_accessors.dup if defined?(@auto_attr_accessors)
18
17
 
19
18
  @auto_attr_accessors = self.class.validators.map(&:attributes)
20
- @auto_attr_accessors.concat(required_fields) if options.required_fields_auto?
21
19
  @auto_attr_accessors = auto_attr_accessors_assign
22
20
  end
23
21
 
@@ -21,7 +21,10 @@ module DecoLite
21
21
  load_service.execute(hash: hash, options: load_service_options).tap do |service_hash|
22
22
  service_hash.each_pair do |field_name, value|
23
23
  create_field_accessor field_name: field_name, options: deco_lite_options
24
- field_names << field_name unless field_names.include? field_name
24
+ unless field_names.include? field_name
25
+ yield field_name if block_given?
26
+ field_names << field_name
27
+ end
25
28
  set_field_value(field_name: field_name, value: value, options: deco_lite_options)
26
29
  end
27
30
  end
@@ -3,7 +3,6 @@
3
3
  require 'active_model'
4
4
  require_relative 'field_assignable'
5
5
  require_relative 'field_names_persistable'
6
- require_relative 'field_requireable'
7
6
  require_relative 'fields_auto_attr_accessable'
8
7
  require_relative 'hash_loadable'
9
8
  require_relative 'hashable'
@@ -17,14 +16,13 @@ module DecoLite
17
16
  include ActiveModel::Model
18
17
  include FieldAssignable
19
18
  include FieldNamesPersistable
20
- include FieldRequireable
21
19
  include FieldsAutoloadable
22
20
  include HashLoadable
23
21
  include Hashable
24
22
  include ModelNameable
25
23
  include Optionable
26
24
 
27
- validate :validate_required_fields
25
+ MISSING_REQUIRED_FIELD_ERROR_TYPE = :missing_required_field
28
26
 
29
27
  def initialize(hash: {}, options: {})
30
28
  # Accept whatever options are sent, but make sure
@@ -36,27 +34,60 @@ module DecoLite
36
34
 
37
35
  hash ||= {}
38
36
 
39
- auto_fields = auto_attr_accessors.merge(hash)
40
- load!(hash: auto_fields, options: options) if hash.present? || auto_attr_accessors?
37
+ load_hash!(hash: hash, options: options) if hash.present?
38
+
39
+ load_hash!(hash: auto_attr_accessors, options: options, add_loaded_fields: false) if auto_attr_accessors?
40
+ end
41
+
42
+ validate :validate_required_fields
43
+
44
+ # Returns field names that will be used to validate whether or not
45
+ # these fields were loaded from hashes upon construction (#new) or
46
+ # via #load!.
47
+ #
48
+ # You must override this method if you want to return field names that
49
+ # are required to be present.
50
+ def required_fields
51
+ @required_fields ||= %i[]
41
52
  end
42
53
 
43
54
  def load!(hash:, options: {})
55
+ load_hash! hash: hash, options: options
56
+ end
57
+
58
+ private
59
+
60
+ attr_writer :required_fields
61
+
62
+ def loaded_fields
63
+ @loaded_fields ||= []
64
+ end
65
+
66
+ def load_hash!(hash:, options: {}, add_loaded_fields: true)
44
67
  # Merge options into the default options passed through the
45
68
  # constructor; these will override any options passed in when
46
69
  # this object was created, allowing us to retain any defaut
47
70
  # options while loading, but also provide option customization
48
71
  # of options when needed.
49
72
  options = Options.with_defaults(options, defaults: self.options)
50
- load_hash(hash: hash, deco_lite_options: options)
73
+ load_hash(hash: hash, deco_lite_options: options) do |loaded_field|
74
+ loaded_fields << loaded_field if add_loaded_fields
75
+ end
51
76
 
52
77
  self
53
78
  end
54
79
 
55
- def load(hash:, options: {})
56
- puts 'WARNING: DecoLite::Model#load will be deprecated in a future release; ' \
57
- 'use DecoLite::Model#load! instead!'
80
+ # Validator for field names. This validator simply checks to make
81
+ # sure that the field was created, which can only occur if:
82
+ # A) The field was defined on the model explicitly (e.g. attr_accessor :field).
83
+ # B) The field was created as a result of loading data dynamically.
84
+ def validate_required_fields
85
+ required_fields.each do |field_name|
86
+ next if loaded_fields.include? field_name
58
87
 
59
- load!(hash: hash, options: options)
88
+ errors.add(field_name, 'field is missing',
89
+ type: self.class::MISSING_REQUIRED_FIELD_ERROR_TYPE)
90
+ end
60
91
  end
61
92
  end
62
93
  end
@@ -24,10 +24,6 @@ module DecoLite
24
24
  def namespace?
25
25
  namespace.present? || false
26
26
  end
27
-
28
- def required_fields_auto?
29
- required_fields == OPTION_REQUIRED_FIELDS_AUTO
30
- end
31
27
  end
32
28
  validate_options! options: immutable_struct_ex.to_h
33
29
  immutable_struct_ex
@@ -2,19 +2,16 @@
2
2
 
3
3
  require_relative 'fields_optionable'
4
4
  require_relative 'namespace_optionable'
5
- require_relative 'required_fields_optionable'
6
5
 
7
6
  module DecoLite
8
7
  # Defines default options and their optionn values.
9
8
  module OptionsDefaultable
10
9
  include DecoLite::FieldsOptionable
11
10
  include DecoLite::NamespaceOptionable
12
- include DecoLite::RequiredFieldsOptionable
13
11
 
14
12
  DEFAULT_OPTIONS = {
15
13
  OPTION_FIELDS => OPTION_FIELDS_DEFAULT,
16
- OPTION_NAMESPACE => OPTION_NAMESPACE_DEFAULT,
17
- OPTION_REQUIRED_FIELDS => OPTION_REQUIRED_FIELDS_DEFAULT
14
+ OPTION_NAMESPACE => OPTION_NAMESPACE_DEFAULT
18
15
  }.freeze
19
16
  end
20
17
  end
@@ -2,16 +2,14 @@
2
2
 
3
3
  require_relative 'fields_optionable'
4
4
  require_relative 'namespace_optionable'
5
- require_relative 'required_fields_optionable'
6
5
 
7
6
  module DecoLite
8
7
  # Methods to validate options.
9
8
  module OptionsValidatable
10
9
  include DecoLite::FieldsOptionable
11
10
  include DecoLite::NamespaceOptionable
12
- include DecoLite::RequiredFieldsOptionable
13
11
 
14
- OPTIONS = [OPTION_FIELDS, OPTION_NAMESPACE, OPTION_REQUIRED_FIELDS].freeze
12
+ OPTIONS = [OPTION_FIELDS, OPTION_NAMESPACE].freeze
15
13
 
16
14
  def validate_options!(options:)
17
15
  raise ArgumentError, 'options is not a Hash' unless options.is_a? Hash
@@ -21,7 +19,6 @@ module DecoLite
21
19
  validate_option_keys! options: options
22
20
  validate_option_fields! fields: options[OPTION_FIELDS]
23
21
  validate_option_namespace! namespace: options[OPTION_NAMESPACE]
24
- validate_option_required_fields! required_fields: options[OPTION_REQUIRED_FIELDS]
25
22
  end
26
23
 
27
24
  def validate_options_present!(options:)
@@ -48,14 +45,5 @@ module DecoLite
48
45
  raise ArgumentError, 'option :namespace value or type is invalid. A Symbol was expected, ' \
49
46
  "but '#{namespace}' (#{namespace.class}) was received."
50
47
  end
51
-
52
- def validate_option_required_fields!(required_fields:)
53
- # :required_fields is optional.
54
- return if required_fields.blank? || OPTION_REQUIRED_FIELDS_VALUES.include?(required_fields)
55
-
56
- raise ArgumentError,
57
- "option :fields_required value or type is invalid. #{OPTION_REQUIRED_FIELDS_VALUES} (Symbol) " \
58
- "was expected, but '#{required_fields}' (#{required_fields.class}) was received."
59
- end
60
48
  end
61
49
  end
@@ -2,5 +2,5 @@
2
2
 
3
3
  # Defines the version of this gem.
4
4
  module DecoLite
5
- VERSION = '0.3.2'
5
+ VERSION = '1.0.0'
6
6
  end
data/lib/deco_lite.rb CHANGED
@@ -5,7 +5,6 @@ require_relative 'deco_lite/field_conflictable'
5
5
  require_relative 'deco_lite/field_creatable'
6
6
  require_relative 'deco_lite/field_name_namespaceable'
7
7
  require_relative 'deco_lite/field_names_persistable'
8
- require_relative 'deco_lite/field_requireable'
9
8
  require_relative 'deco_lite/field_retrievable'
10
9
  require_relative 'deco_lite/fields_optionable'
11
10
  require_relative 'deco_lite/hash_loadable'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: deco_lite
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.2
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gene M. Angelo, Jr.
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-08-29 00:00:00.000000000 Z
11
+ date: 2022-09-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel
@@ -263,7 +263,6 @@ files:
263
263
  - lib/deco_lite/field_creatable.rb
264
264
  - lib/deco_lite/field_name_namespaceable.rb
265
265
  - lib/deco_lite/field_names_persistable.rb
266
- - lib/deco_lite/field_requireable.rb
267
266
  - lib/deco_lite/field_retrievable.rb
268
267
  - lib/deco_lite/field_validatable.rb
269
268
  - lib/deco_lite/fields_auto_attr_accessable.rb
@@ -277,7 +276,6 @@ files:
277
276
  - lib/deco_lite/options.rb
278
277
  - lib/deco_lite/options_defaultable.rb
279
278
  - lib/deco_lite/options_validatable.rb
280
- - lib/deco_lite/required_fields_optionable.rb
281
279
  - lib/deco_lite/version.rb
282
280
  homepage: https://github.com/gangelo/deco_lite
283
281
  licenses:
@@ -298,7 +296,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
298
296
  - !ruby/object:Gem::Version
299
297
  version: '0'
300
298
  requirements: []
301
- rubygems_version: 3.2.15
299
+ rubygems_version: 3.3.22
302
300
  signing_key:
303
301
  specification_version: 4
304
302
  summary: Dynamically creates an active model from a Hash.
@@ -1,37 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module DecoLite
4
- # Provides methods to manage fields that must be defined from
5
- # the dynamically loaded data.
6
- module FieldRequireable
7
- MISSING_REQUIRED_FIELD_ERROR_TYPE = :missing_required_field
8
-
9
- # Returns field names that will be used to validate the presence of
10
- # dynamically created fields from loaded objects.
11
- #
12
- # You must override this method if you want to return field names that
13
- # are required to be present. You may simply return a static array, but
14
- # if you want to dynamically manipulate this field, return a variable.
15
- def required_fields
16
- # @required_fields ||= []
17
- []
18
- end
19
-
20
- # Validator for field names. This validator simply checks to make
21
- # sure that the field was created, which can only occur if:
22
- # A) The field was defined on the model explicitly (e.g. attr_accessor :field).
23
- # B) The field was created as a result of loading data dynamically.
24
- def validate_required_fields
25
- required_fields.each do |field_name|
26
- next if required_field_exist? field_name: field_name
27
-
28
- errors.add(field_name, 'field is missing', type: MISSING_REQUIRED_FIELD_ERROR_TYPE)
29
- end
30
- end
31
-
32
- # :reek:ManualDispatch - method added dynamically; this is the best way to check.
33
- def required_field_exist?(field_name:)
34
- respond_to?(field_name) && respond_to?("#{field_name}=".to_sym)
35
- end
36
- end
37
- end
@@ -1,15 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module DecoLite
4
- # Defines the fields option hash key and acceptable hash key values.
5
- module RequiredFieldsOptionable
6
- # The option hash key for this option.
7
- OPTION_REQUIRED_FIELDS = :required_fields
8
- # The valid option values for this option key.
9
- OPTION_REQUIRED_FIELDS_AUTO = :auto
10
- # The default value for this option.
11
- OPTION_REQUIRED_FIELDS_DEFAULT = OPTION_REQUIRED_FIELDS_AUTO
12
- # The valid option key values for this option.
13
- OPTION_REQUIRED_FIELDS_VALUES = [OPTION_REQUIRED_FIELDS_AUTO].freeze
14
- end
15
- end