deco_lite 0.3.0 → 0.3.1

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: 40f7b315deefbdf848f9d2743d27e672d3916da793f0bd32a705c7d34acac1f9
4
- data.tar.gz: b283948784b3fd9b1a4eaef20b7f0ca26a7de9b2971042c04a01021be6195d10
3
+ metadata.gz: 8a87d5a79f738b49d45b51c0128b4c252853c683363e7525df836fc7c46e4953
4
+ data.tar.gz: 1f07c897d0f88cd3609a8e6a880d0ce91b71210ee8952eb29148370b2f49f092
5
5
  SHA512:
6
- metadata.gz: 37a1083dfa95d51ab710fff1bab946edcc5b9fa825e37bf7f29c7a0174198d913469c8ac17f82b795949425f7e068236c73ca2ed9df50aba45bdfa3ef7cf1d18
7
- data.tar.gz: f3fbb8ab71dad6720dae8dc25179977757d55f7b802c2016ffc673fcdd423b3f86d04a406bd9a4bade6233efb5120cad1d7c2d7176045f44ec78da911311419a
6
+ metadata.gz: afc6320e0a1e9060dda231249fe16e62bf62d56f11ad7ffa9c4c6a0f094ef866173655c4ee57a419b3c4b83d0d7b7639230db22459f3c2d81d78cc6c4da2dde2
7
+ data.tar.gz: 6db8e3cb9a634669667eb288f4a4343106ad9be71630c1a9e95af366649b86e88459d0b79f1c71e09345a75805e643aa1e1e3a2836e2045bd1191bd78484685c
data/CHANGELOG.md CHANGED
@@ -1,3 +1,8 @@
1
+ ### 0.3.1
2
+ * Changes
3
+ * Added `DecoLite::FieldRequireable::MISSING_REQUIRED_FIELD_ERROR_TYPE` for required field type errors.
4
+ * Update README.md with more examples.
5
+
1
6
  ### 0.3.0
2
7
  * Changes
3
8
  * `DecoLite::Model#new` how accepts a :hash named parameter that will load the Hash as if calling `DecoLite::Model.new.load!(hash: <hash>)`.
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- deco_lite (0.3.0)
4
+ deco_lite (0.3.1)
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)
data/README.md CHANGED
@@ -188,24 +188,117 @@ model.wife_info_address #=> 1 street, boonton, nj 07005
188
188
 
189
189
  #### Add validators to my model
190
190
 
191
- Simply add your `ActiveModel` validators just like you would any other `ActiveModel::Model` validator. However, be aware that (currently), any attribute (field) being validated that does not exist on the model, will raise a `NoMethodError` error:
191
+ 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.):
192
192
 
193
193
  ```ruby
194
194
  class Model < DecoLite::Model
195
195
  validates :first, :last, :address, presence: true
196
+ validates :age, numericality: true
196
197
  end
197
198
 
198
- model = Model.new(hash: { first: 'John', last: 'Doe' })
199
+ # No :address
200
+ model = Model.new(hash: { first: 'John', last: 'Doe', age: 25 })
201
+ model.respond_to? :address
202
+ #=> true
199
203
 
200
- # No :address; a NoMethodError error for :address will be raised.
201
- model.validate
202
- #=> undefined method 'address' for #<Model:0x00007f95931568c0 ... @field_names=[:first, :last], @first="John", @last="Doe", ...> (NoMethodError)
204
+ model.valid?
205
+ #=> false
206
+ model.errors.full_messages
207
+ #=> ["Address can't be blank"]
203
208
 
204
209
  model.load!(hash: { address: '123 park road, anytown, nj 01234' })
205
210
  model.validate
206
211
  #=> true
207
212
  ```
208
213
 
214
+ #### Validate whether or not certain fields were loaded
215
+
216
+ 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.
217
+
218
+ 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:
219
+ - Create a `DecoLite::Model` subclass.
220
+ - Override the `DecoLite::Model#required_fields` method to return the field names you want to validate.
221
+ - Use the `required_fields: nil` option when instantiating your model object.
222
+ - 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.
223
+
224
+ For example:
225
+
226
+ ```ruby
227
+ class Model < DecoLite::Model
228
+ # :age field is optional and it's value is optional.
229
+ validates :age, numericality: { only_integer: true }, allow_blank: true
230
+
231
+ def required_fields
232
+ # We want to ensure attr_accessors are created for these fields.
233
+ %i(first last address)
234
+ end
235
+ end
236
+
237
+ # Option "required_fields: :auto" is the default which will automatically create
238
+ # attr_accessors for fields returned from DecoLite::Model#required_fields, so we
239
+ # need to set this option to nil (i.e. required_fields: nil).
240
+ model = Model.new(options: { required_fields: nil })
241
+
242
+ model.validate
243
+ #=> false
244
+ model.errors.full_messages
245
+ #=> ["First field is missing", "Last field is missing", "Address field is missing"]
246
+
247
+ user = { first: 'John', last: 'Doe', address: '123 anystreet, anytown, nj 01234'}
248
+ model.load!(hash: user)
249
+ model.validate
250
+ #=> false
251
+ model.errors.full_messages
252
+ #=> ["Age is not a number"]
253
+ ```
254
+ #### Validate whether or not certain fields were loaded _and_ validate the data associated with these same fields
255
+
256
+ 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.
257
+
258
+ 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.
259
+
260
+ For example:
261
+
262
+ ```ruby
263
+ class Model < DecoLite::Model
264
+ def required_fields
265
+ %i(first last address age)
266
+ end
267
+
268
+ def validate_required_fields
269
+ super
270
+
271
+ first = self.try(:first)
272
+ errors.add(:first, "can't be blank") if first.nil?
273
+
274
+ last = self.try(:last)
275
+ errors.add(:last, "can't be blank") if last.nil?
276
+
277
+ address = self.try(:address)
278
+ errors.add(:address, "can't be blank") if address.nil?
279
+
280
+ age = self.try(:age)
281
+ errors.add(:age, "can't be blank") if age.nil?
282
+ errors.add(:age, 'is not a number') unless /\d+/ =~ age
283
+ end
284
+ end
285
+ model = Model.new(options: { required_fields: nil })
286
+
287
+ model.validate
288
+ #=> false
289
+
290
+ model.errors.full_messages
291
+ #=> ["First field is missing",
292
+ "Last field is missing",
293
+ "Address field is missing",
294
+ "Age field is missing",
295
+ "First can't be blank",
296
+ "Last can't be blank",
297
+ "Address can't be blank",
298
+ "Age can't be blank",
299
+ "Age is not a number"]
300
+ ```
301
+
209
302
  #### Manually define attributes (fields) on my model
210
303
 
211
304
  Manually defining attributes on your subclass is possible, although there doesn't seem a valid reason to do so, since you can just use `DecoLite::Model#load!` to wire all this up for you automatically. However, if there _were_ a need to do this, you must add your `attr_reader` to the `DecoLite::Model@field_names` array, or an error will be raised _provided_ there are any conflicting field names being loaded using `DecoLite::Model#load!`. Note that the aforementioned error will be raised regardless of whether or not you set `options: { fields: :merge }`. This is because DecoLite considers any existing model attributes _not_ added to the model via `load!`to be native to the model object, and therefore will not allow you to create attr_accessors for existing model attributes because this can potentially be dangerous.
@@ -4,6 +4,8 @@ module DecoLite
4
4
  # Provides methods to manage fields that must be defined from
5
5
  # the dynamically loaded data.
6
6
  module FieldRequireable
7
+ MISSING_REQUIRED_FIELD_ERROR_TYPE = :missing_required_field
8
+
7
9
  # Returns field names that will be used to validate the presence of
8
10
  # dynamically created fields from loaded objects.
9
11
  #
@@ -23,7 +25,7 @@ module DecoLite
23
25
  required_fields.each do |field_name|
24
26
  next if required_field_exist? field_name: field_name
25
27
 
26
- errors.add(field_name, 'field is missing', type: :missing_required_field)
28
+ errors.add(field_name, 'field is missing', type: MISSING_REQUIRED_FIELD_ERROR_TYPE)
27
29
  end
28
30
  end
29
31
 
@@ -2,5 +2,5 @@
2
2
 
3
3
  # Defines the version of this gem.
4
4
  module DecoLite
5
- VERSION = '0.3.0'
5
+ VERSION = '0.3.1'
6
6
  end
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.0
4
+ version: 0.3.1
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-26 00:00:00.000000000 Z
11
+ date: 2022-08-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel