action_logic 0.2.0 → 0.2.1

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
  SHA1:
3
- metadata.gz: 46629f7e8b78b79da65d73f694f03ffd3598a836
4
- data.tar.gz: e7cd5893f3661781d40ed6050a10067e31d4df3e
3
+ metadata.gz: ec1c25ca6b1d98aead3c8da72aaa11ae58c1b9fe
4
+ data.tar.gz: c27b50ad7c730bcf5b370b3016b8dc8fabca1cc9
5
5
  SHA512:
6
- metadata.gz: a81e6790403bb1611887adc70072541414c8df853cbfae06474eeb6bcb4d481ba17fb29c8b79be8352e155dd554b455f164ad472cfdabdd84b7431ccac35f9a2
7
- data.tar.gz: 561ca45352089282b7a036013799664efc7787fd80f1b38adb7df8d522ee1ae8a72b6ed7c22d49ffa3a6a24490f3575adb422bd15c72a85478c92b17ed249586
6
+ metadata.gz: 8340bda2fb890fdea4c2cf4177763c347dfdcbc247ab4a49b1def06851cd99cfc633c3c9c671272a16ce7dd960fee432d9e4abc5af341a499d33a83202c5b61f
7
+ data.tar.gz: c9f53e0e7f74cb63618e1b064a940027166ba8f9165c9dbdf0ac4cd289a25e19ce90d0fbfaa34433a13d82a65c654c6cc8144ddd8d27b78158a4c58253b900b9
data/README.md CHANGED
@@ -162,9 +162,9 @@ To implement an `ActionTask` class you must define a `call` method. You can also
162
162
  class ActionTaskExample
163
163
  include ActionLogic::ActionTask
164
164
 
165
- validates_before :expected_attribute1 => { :type => :string },
166
- :expected_attribute2 => { :type => :integer, :presence => true }
167
- validates_after :example_attribute1 => { :type => :string, :presence => ->(example_attribute1) { !example_attribute1.empty? } }
165
+ validates_before :expected_attribute1 => { :type => String },
166
+ :expected_attribute2 => { :type => Fixnum, :presence => true }
167
+ validates_after :example_attribute1 => { :type => String, :presence => ->(example_attribute1) { !example_attribute1.empty? } }
168
168
 
169
169
  def call
170
170
  # adds `example_attribute1` to the shared `context` with the value "Example value"
@@ -179,30 +179,37 @@ result = ActionTaskExample.execute(:expected_attribute1 => "example", :expected_
179
179
  result # => #<ActionLogic::ActionContext expected_attribute1="example", expected_attribute2=123, status=:success, example_attribute1="New value from context attributes: example 123">
180
180
  ```
181
181
 
182
- The `ActionTaskExample` is invoked using the static method `execute` which takes an optional hash of attributes that is converted into an `ActionContext`. Assuming the before validations are satisfied, the `call` method is invoked. In the body of the `call` method the `ActionTask` can access the shared `ActionContext` instance via a `context` object. This shared `context` object allows for getting and setting attributes as needed. When the `call` method returns, the `context` is validated against any defined after validations, and the `context` is then returned to the caller.
182
+ The `ActionTaskExample` is invoked using the static method `execute` which takes an optional hash of attributes that is converted into an `ActionContext`.
183
+ Assuming the before validations are satisfied, the `call` method is invoked. In the body of the `call` method the `ActionTask` can access the shared `ActionContext`
184
+ instance via a `context` object. This shared `context` object allows for getting and setting attributes as needed. When the `call` method returns, the `context`
185
+ is validated against any defined after validations, and the `context` is then returned to the caller.
183
186
 
184
187
  The diagram below is a visual representation of how an `ActionTask` is evaluted when its `execute` method is invoked from a caller:
185
188
 
186
189
  <img src="https://raw.githubusercontent.com/rewinfrey/action_logic/master/resources/action_task_diagram.png" />
187
190
 
188
- Although this example is for the `ActionTask` abstraction, `ActionUseCase` and `ActionCoordinator` follow the same pattern. The difference is that `ActionUseCase` is designed to organize multiple `ActionTasks`, and `ActionCoordinator` is designed to organize many `ActionUseCases`.
191
+ Although this example is for the `ActionTask` abstraction, `ActionUseCase` and `ActionCoordinator` follow the same pattern. The difference is that `ActionUseCase`
192
+ is designed to organize multiple `ActionTasks`, and `ActionCoordinator` is designed to organize many `ActionUseCases`.
189
193
 
190
194
  ### ActionUseCase
191
195
 
192
- As business logic grows in complexity the number of steps or tasks required to fulfill that business logic tends to increase. Managing this complexity is a problem every team must face. Abstractions can help teams of varying experience levels work together and promote code that remains modular and simple to understand and extend. `ActionUseCase` represents a layer of abstraction that organizes multiple `ActionTasks` and executes each `ActionTask` in the order they are defined. Each task receives the same shared `context` so tasks can be composed together.
196
+ As business logic grows in complexity the number of steps or tasks required to fulfill that business logic tends to increase. Managing this complexity is a problem every team must face.
197
+ Abstractions can help teams of varying experience levels work together and promote code that remains modular and simple to understand and extend. `ActionUseCase` represents a layer of
198
+ abstraction that organizes multiple `ActionTasks` and executes each `ActionTask` in the order they are defined. Each task receives the same shared `context` so tasks can be composed together.
193
199
 
194
- To implement an `ActionUseCase` class you must define a `call` method and a `tasks` method. You also can specify any before, after or around validations or an error handler. The following is an example showcasing how an `ActionUseCase` class organizes the execution of multiple `ActionTasks` and defines before and after validations on the shared `context`:
200
+ To implement an `ActionUseCase` class you must define a `call` method and a `tasks` method. You also can specify any before, after or around validations or an error handler.
201
+ The following is an example showcasing how an `ActionUseCase` class organizes the execution of multiple `ActionTasks` and defines before and after validations on the shared `context`:
195
202
 
196
203
  ```ruby
197
204
  class ActionUseCaseExample
198
205
  include ActionLogic::ActionUseCase
199
206
 
200
- validates_before :expected_attribute1 => { :type => :string },
201
- :expected_attribute2 => { :type => :integer, :presence => true }
202
- validates_after :example_task1 => { :type => :boolean, :presence => true },
203
- :example_task2 => { :type => :boolean, :presence => true },
204
- :example_task3 => { :type => :boolean, :presence => true },
205
- :example_usecase1 => { :type => :boolean, :presence => true }
207
+ validates_before :expected_attribute1 => { :type => String },
208
+ :expected_attribute2 => { :type => Fixnum, :presence => true }
209
+ validates_after :example_task1 => { :type => TrueClass, :presence => true },
210
+ :example_task2 => { :type => TrueClass, :presence => true },
211
+ :example_task3 => { :type => TrueClass, :presence => true },
212
+ :example_usecase1 => { :type => TrueClass, :presence => true }
206
213
 
207
214
  # The `call` method is invoked prior to invoking any of the ActionTasks defined by the `tasks` method.
208
215
  # The purpose of the `call` method allows us to prepare the shared `context` prior to invoking the ActionTasks.
@@ -220,7 +227,7 @@ end
220
227
 
221
228
  class ActionTaskExample1
222
229
  include ActionLogic::ActionTask
223
- validates_after :example_task1 => { :type => :boolean, :presence => true }
230
+ validates_after :example_task1 => { :type => TrueClass, :presence => true }
224
231
 
225
232
  def call
226
233
  context # => #<ActionLogic::ActionContext expected_attribute1="example", expected_attribute2=123, status=:success, example_usecase1=true>
@@ -230,7 +237,7 @@ end
230
237
 
231
238
  class ActionTaskExample2
232
239
  include ActionLogic::ActionTask
233
- validates_after :example_task2 => { :type => :boolean, :presence => true }
240
+ validates_after :example_task2 => { :type => TrueClass, :presence => true }
234
241
 
235
242
  def call
236
243
  context # => #<ActionLogic::ActionContext expected_attribute1="example", expected_attribute2=123, status=:success, example_usecase1=true, example_task1=true>
@@ -240,7 +247,7 @@ end
240
247
 
241
248
  class ActionTaskExample3
242
249
  include ActionLogic::ActionTask
243
- validates_after :example_task3 => { :type => :boolean, :presence => true }
250
+ validates_after :example_task3 => { :type => TrueClass, :presence => true }
244
251
 
245
252
  def call
246
253
  context # => #<ActionLogic::ActionContext expected_attribute1="example", expected_attribute2=123, status=:success, example_usecase1=true, example_task1=true, example_task2=true>
@@ -254,17 +261,24 @@ result = ActionUseCaseExample.execute(:expected_attribute1 => "example", :expect
254
261
  result # => #<ActionLogic::ActionContext expected_attribute1="example", expected_attribute2=123, status=:success, example_usecase1=true, example_task1=true, example_task2=true, example_task3=true>
255
262
  ```
256
263
 
257
- By following the value of the shared `context` from the `ActionUseCaseExample` to each of the `ActionTask` classes, it is possible to see how the shared `context` is mutated to accomodate the various attributes and their values each execution context adds to the `context`. It also reveals the order in which the `ActionTasks` are evaluated, and indicates that the `call` method of the `ActionUseCaseExample` is invoked prior to any of the `ActionTasks` defined in the `tasks` method.
264
+ By following the value of the shared `context` from the `ActionUseCaseExample` to each of the `ActionTask` classes, it is possible to see how the shared `context`
265
+ is mutated to accomodate the various attributes and their values each execution context adds to the `context`. It also reveals the order in which the `ActionTasks`
266
+ are evaluated, and indicates that the `call` method of the `ActionUseCaseExample` is invoked prior to any of the `ActionTasks` defined in the `tasks` method.
258
267
 
259
- To help visualize the flow of execution when an `ActionUseCase` is invoked, this diagram aims to illustrate the relationship between `ActionUseCase` and `ActionTasks` and the order in which operations are performed:
268
+ To help visualize the flow of execution when an `ActionUseCase` is invoked, this diagram aims to illustrate the relationship between `ActionUseCase` and `ActionTasks`
269
+ and the order in which operations are performed:
260
270
 
261
271
  <img src="https://raw.githubusercontent.com/rewinfrey/action_logic/master/resources/action_use_case_diagram.png" />
262
272
 
263
273
  ### ActionCoordinator
264
274
 
265
- Sometimes the behavior we wish our Ruby or Rails application to provide requires us to coordinate work between various domains of our application's business logic. The `ActionCoordinator` abstraction is intended to help coordinate multiple `ActionUseCases` by allowing you to define a plan of which `ActionUseCases` to invoke depending on the outcome of each `ActionUseCase` execution. The `ActionCoordinator` abstraction is the highest level of abstraction in `ActionLogic`.
275
+ Sometimes the behavior we wish our Ruby or Rails application to provide requires us to coordinate work between various domains of our application's business logic.
276
+ The `ActionCoordinator` abstraction is intended to help coordinate multiple `ActionUseCases` by allowing you to define a plan of which `ActionUseCases` to invoke
277
+ depending on the outcome of each `ActionUseCase` execution. The `ActionCoordinator` abstraction is the highest level of abstraction in `ActionLogic`.
266
278
 
267
- To implement an `ActionCoordinator` class, you must define a `call` method in addition to a `plan` method. The purpose of the `plan` method is to define a state transition map that links together the various `ActionUseCase` classes the `ActionCoordinator` is organizing, as well as allowing you to define error or halt scenarios based on the result of each `ActionUseCase`. The following code example demonstrates a simple `ActionCoordinator`:
279
+ To implement an `ActionCoordinator` class, you must define a `call` method in addition to a `plan` method. The purpose of the `plan` method is to define a state
280
+ transition map that links together the various `ActionUseCase` classes the `ActionCoordinator` is organizing, as well as allowing you to define error or halt
281
+ scenarios based on the result of each `ActionUseCase`. The following code example demonstrates a simple `ActionCoordinator`:
268
282
 
269
283
  ```ruby
270
284
  class ActionCoordinatorExample
@@ -289,7 +303,7 @@ end
289
303
  class ActionUseCaseExample1
290
304
  include ActionLogic::ActionUseCase
291
305
 
292
- validates_before :required_attribute1 => { :type => :string }
306
+ validates_before :required_attribute1 => { :type => String }
293
307
 
294
308
  def call
295
309
  context # => #<ActionLogic::ActionContext status=:success, required_attribute1="required attribute 1", required_attribute2="required attribute 2">
@@ -305,7 +319,7 @@ end
305
319
  class ActionUseCaseExample2
306
320
  include ActionLogic::ActionUseCase
307
321
 
308
- validates_before :required_attribute2 => { :type => :string }
322
+ validates_before :required_attribute2 => { :type => String }
309
323
 
310
324
  def call
311
325
  context # => #<ActionLogic::ActionContext status=:success, required_attribute1="required attribute 1", required_attribute2="required attribute 2", example_usecase1=true, example_task1=true>
@@ -334,7 +348,7 @@ end
334
348
 
335
349
  class ActionTaskExample1
336
350
  include ActionLogic::ActionTask
337
- validates_after :example_task1 => { :type => :boolean, :presence => true }
351
+ validates_after :example_task1 => { :type => TrueClass, :presence => true }
338
352
 
339
353
  def call
340
354
  context # => #<ActionLogic::ActionContext status=:success, required_attribute1="required attribute 1", required_attribute2="required attribute 2", example_usecase1=true>
@@ -344,7 +358,7 @@ end
344
358
 
345
359
  class ActionTaskExample2
346
360
  include ActionLogic::ActionTask
347
- validates_after :example_task2 => { :type => :boolean, :presence => true }
361
+ validates_after :example_task2 => { :type => TrueClass, :presence => true }
348
362
 
349
363
  def call
350
364
  context # => #<ActionLogic::ActionContext status=:success, required_attribute1="required attribute 1", required_attribute2="required attribute 2", example_usecase1=true, example_task1=true, example_usecase2=true>
@@ -360,9 +374,9 @@ result # => #<ActionLogic::ActionContext status=:success, required_attribute1="r
360
374
  <img src="https://raw.githubusercontent.com/rewinfrey/action_logic/master/resources/action_coordinator_diagram.png" />
361
375
 
362
376
  ### Succeeding an `ActionContext`
363
- By default, the value of the `status` attribute of instances of `ActionContext` is `:success`. Normally this is useful information for the caller of an `ActionTask`, `ActionUseCase` or `ActionCoordinator`
364
- because it informs the caller that the various execution context(s) were successful. In other words, a `:success` status indicates that none of the execution contexts had a failure
365
- or halted execution.
377
+ By default, the value of the `status` attribute of instances of `ActionContext` is `:success`. Normally this is useful information for the caller of an `ActionTask`,
378
+ `ActionUseCase` or `ActionCoordinator` because it informs the caller that the various execution context(s) were successful. In other words, a `:success` status
379
+ indicates that none of the execution contexts had a failure or halted execution.
366
380
 
367
381
  ### Failing an `ActionContext`
368
382
  Using `context.fail!` does two important things: it immediately stops the execution of any proceeding business logic (prevents any additional `ActionTasks` from executing)
@@ -589,20 +603,22 @@ of `ActionContext`. To understand the default types `ActionLogic` validates agai
589
603
  class ActionTaskExample
590
604
  include ActionLogic::ActionTask
591
605
 
592
- validates_after :integer_test => { :type => :integer },
593
- :float_test => { :type => :float },
594
- :string_test => { :type => :string },
595
- :bool_test => { :type => :boolean },
596
- :hash_test => { :type => :hash },
597
- :array_test => { :type => :array },
598
- :symbol_test => { :type => :symbol },
599
- :nil_test => { :type => :nil }
606
+ validates_after :integer_test => { :type => Fixnum },
607
+ :float_test => { :type => Float },
608
+ :string_test => { :type => String },
609
+ :truthy_test => { :type => TrueClass },
610
+ :falsey_test => { :type => FalseClass },
611
+ :hash_test => { :type => Hash },
612
+ :array_test => { :type => Array },
613
+ :symbol_test => { :type => Symbol },
614
+ :nil_test => { :type => NilClass }
600
615
 
601
616
  def call
602
617
  context.integer_test = 123
603
618
  context.float_test = 1.0
604
619
  context.string_test = "test"
605
- context.bool_test = true
620
+ context.truthy_test = true
621
+ context.falsey_test = false
606
622
  context.hash_test = {}
607
623
  context.array_test = []
608
624
  context.symbol_test = :symbol
@@ -616,7 +632,8 @@ result # => #<ActionLogic::ActionContext status=:success,
616
632
  # integer_test=123,
617
633
  # float_test=1.0,
618
634
  # string_test="test",
619
- # bool_test=true,
635
+ # truthy_test=true,
636
+ # falsey_test=false,
620
637
  # hash_test={},
621
638
  # array_test=[],
622
639
  # symbol_test=:symbol,
@@ -624,7 +641,7 @@ result # => #<ActionLogic::ActionContext status=:success,
624
641
  ```
625
642
 
626
643
  It's important to point out that Ruby's `true` and `false` are not `Boolean` but `TrueClass` and `FalseClass` respectively. Additionally, `nil`'s type is `NilClass` in Ruby.
627
- To simplify the way these validations work for `true` or `false`, type validations expect the symbol `:boolean` as the `:type`. `nil` is validated simply with the `:nil` `:type`.
644
+ Also potentially surprising to some is that Ruby's integer type is of class `Fixnum`, but floats are of class `Float`.
628
645
 
629
646
  As we saw with attribute validations, if an attribute's value does not conform to the type expected, `ActionLogic` will raise an `ActionLogic::AttributeTypeError`
630
647
  with a detailed description about which attribute's value failed the validation:
@@ -633,14 +650,14 @@ with a detailed description about which attribute's value failed the validation:
633
650
  class ActionTaskExample
634
651
  include ActionLogic::ActionTask
635
652
 
636
- validates_after :integer_test => { :type => :integer }
653
+ validates_after :integer_test => { :type => Fixnum }
637
654
 
638
655
  def call
639
656
  context.integer_test = 1.0
640
657
  end
641
658
  end
642
659
 
643
- ActionTaskExample.execute # ~> ["Attribute: integer_test with value: 1.0 was expected to be of type integer but is float"] (ActionLogic::AttributeTypeError)
660
+ ActionTaskExample.execute # ~> ["Attribute: integer_test with value: 1.0 was expected to be of type Fixnum but is Float"] (ActionLogic::AttributeTypeError)
644
661
  ```
645
662
 
646
663
  In addition to the above default types it is possible to also validate against user defined types.
@@ -657,7 +674,7 @@ end
657
674
  class ActionTaskExample
658
675
  include ActionLogic::ActionTask
659
676
 
660
- validates_after :example_attribute => { :type => :exampleclass }
677
+ validates_after :example_attribute => { :type => ExampleClass }
661
678
 
662
679
  def call
663
680
  context.example_attribute = ExampleClass.new
@@ -670,8 +687,7 @@ result # => #<ActionLogic::ActionContext status=:success, example_attribute=#<Ex
670
687
  ```
671
688
 
672
689
  In the above example, a custom class `ExampleClass` is defined. In order to type validate against this class, the required format for the name of the class is simply
673
- the lowercase version of the class as a symbol. `ExampleClass` becomes `:exampleclass`, `UserAttributes` becomes `:userattributes`,
674
- `ReallyLongClassNameThatBreaks80ColumnsInVimRule` becomes `:reallylongclassnamethatbreaks80columnsinvimrule` and so on.
690
+ the class constant `ExampleClass`.
675
691
 
676
692
  If a custom type validation fails, `ActionLogic` provides the same `ActionLogic::AttributeTypeError` with a detailed explanation about what attribute is in violation
677
693
  of the type validation:
@@ -686,14 +702,14 @@ end
686
702
  class ActionTaskExample
687
703
  include ActionLogic::ActionTask
688
704
 
689
- validates_after :example_attribute => { :type => :exampleclass }
705
+ validates_after :example_attribute => { :type => ExampleClass }
690
706
 
691
707
  def call
692
708
  context.example_attribute = OtherClass.new
693
709
  end
694
710
  end
695
711
 
696
- ActionTaskExample.execute # ~> ["Attribute: example_attribute with value: #<OtherClass:0x007fb5ca04edb8> was expected to be of type exampleclass but is otherclass"] (ActionLogic::AttributeTypeError)
712
+ ActionTaskExample.execute # ~> ["Attribute: example_attribute with value: #<OtherClass:0x007fb5ca04edb8> was expected to be of type ExampleClass but is OtherClass"] (ActionLogic::AttributeTypeError)
697
713
  ```
698
714
 
699
715
  Attribute and type validations are very helpful, but in some situations this is not enough. Additionally, `ActionLogic` provides presence validation so you can also verify that
@@ -796,7 +812,7 @@ validation on a single attribute:
796
812
  class ActionTaskExample
797
813
  include ActionLogic::ActionTask
798
814
 
799
- validates_before :example_attribute => { :type => :array, :presence => ->(attribute) { attribute.any? } }
815
+ validates_before :example_attribute => { :type => Array, :presence => ->(attribute) { attribute.any? } }
800
816
 
801
817
  def call
802
818
  end
@@ -813,8 +829,8 @@ The following example illustrates how to specify a before validation for multipl
813
829
  class ActionTaskExample
814
830
  include ActionLogic::ActionTask
815
831
 
816
- validates_before :example_attribute => { :type => :array, :presence => ->(attribute) { attribute.any? } },
817
- :example_attribute2 => { :type => :integer }
832
+ validates_before :example_attribute => { :type => Array, :presence => ->(attribute) { attribute.any? } },
833
+ :example_attribute2 => { :type => Fixnum }
818
834
 
819
835
  def call
820
836
  end
@@ -838,7 +854,7 @@ validation on a single attribute:
838
854
  class ActionTaskExample
839
855
  include ActionLogic::ActionTask
840
856
 
841
- validates_after :example_attribute => { :type => :array, :presence => ->(attribute) { attribute.any? } }
857
+ validates_after :example_attribute => { :type => Array, :presence => ->(attribute) { attribute.any? } }
842
858
 
843
859
  def call
844
860
  context.example_attribute = [1, 2, 3]
@@ -855,8 +871,8 @@ The following example illustrates how to specify an after validation for multipl
855
871
  class ActionTaskExample
856
872
  include ActionLogic::ActionTask
857
873
 
858
- validates_after :example_attribute => { :type => :array, :presence => ->(attribute) { attribute.any? } },
859
- :example_attribute2 => { :type => :integer }
874
+ validates_after :example_attribute => { :type => Array, :presence => ->(attribute) { attribute.any? } },
875
+ :example_attribute2 => { :type => Fixnum }
860
876
 
861
877
  def call
862
878
  context.example_attribute = [1, 2, 3]
@@ -882,7 +898,7 @@ validation on a single attribute:
882
898
  class ActionTaskExample
883
899
  include ActionLogic::ActionTask
884
900
 
885
- validates_around :example_attribute => { :type => :array, :presence => ->(attribute) { attribute.any? } }
901
+ validates_around :example_attribute => { :type => Array, :presence => ->(attribute) { attribute.any? } }
886
902
 
887
903
  def call
888
904
  end
@@ -898,8 +914,8 @@ The following example illustrates how to specify an around validation for multip
898
914
  class ActionTaskExample
899
915
  include ActionLogic::ActionTask
900
916
 
901
- validates_around :example_attribute => { :type => :array, :presence => ->(attribute) { attribute.any? } },
902
- :example_attribute2 => { :type => :integer }
917
+ validates_around :example_attribute => { :type => Array, :presence => ->(attribute) { attribute.any? } },
918
+ :example_attribute2 => { :type => Fixnum }
903
919
 
904
920
  def call
905
921
  end
@@ -59,7 +59,7 @@ module ActionLogic
59
59
  expected_attributes = validations.keys || []
60
60
  missing_attributes = expected_attributes - existing_attributes
61
61
 
62
- raise ActionLogic::MissingAttributeError.new(missing_attributes) if missing_attributes.any?
62
+ raise ActionLogic::MissingAttributeError.new(error_message_format(missing_attributes.join(", ") + " attributes are missing")) if missing_attributes.any?
63
63
  end
64
64
 
65
65
  def validate_types!(validations)
@@ -74,7 +74,7 @@ module ActionLogic
74
74
  collection
75
75
  end
76
76
 
77
- raise ActionLogic::AttributeTypeError.new(type_errors) if type_errors.any?
77
+ raise ActionLogic::AttributeTypeError.new(error_message_format(type_errors.join(", "))) if type_errors.any?
78
78
  end
79
79
 
80
80
  def validate_presence!(validations)
@@ -88,7 +88,7 @@ module ActionLogic
88
88
  elsif expected_validation[:presence].class == Proc
89
89
  collection << "Attribute: #{expected_attribute} is missing value in context but custom presence validation was specified" unless expected_validation[:presence].call(context[expected_attribute])
90
90
  else
91
- raise ActionLogic::UnrecognizablePresenceValidatorError.new("Presence validator: #{expected_validation[:presence]} is not a supported format")
91
+ raise ActionLogic::UnrecognizablePresenceValidatorError.new(error_message_format("Presence validator: #{expected_validation[:presence]} is not a supported format"))
92
92
  end
93
93
 
94
94
  collection
@@ -96,5 +96,9 @@ module ActionLogic
96
96
 
97
97
  raise ActionLogic::PresenceError.new(presence_errors) if presence_errors.any?
98
98
  end
99
+
100
+ def error_message_format(error_string)
101
+ "context: #{self.class} message: #{error_string}"
102
+ end
99
103
  end
100
104
  end
@@ -1,3 +1,3 @@
1
1
  module ActionLogic
2
- VERSION = '0.2.0'
2
+ VERSION = '0.2.1'
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: action_logic
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rick Winfrey