deco_lite 0.3.2 → 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: 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