light_service-validated_context 0.1.1 → 0.2.2

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: 22770c4c6eeee16f8c3705709e653810d114a94f798c9408f1e5d6cb31d69af2
4
- data.tar.gz: 683201c0c625ebfa39b4cfeccbdb24d47fe4e246ea781fe32dd2ffc1983941b3
3
+ metadata.gz: d272960b5f0002c3b640bba8eeca1684477df3c65a6c7031f3169abcd97eb3f2
4
+ data.tar.gz: 13f2d1b53652113892ad2d5e93a34aefee19ed38901034e33ac9764590756289
5
5
  SHA512:
6
- metadata.gz: 8f33f7bd519557a9c3171b15312d4e902931c6ba8451cea28c6104b2ee490b0d44270d1e3678b06effd9e7dd9a75afd7738f853a11ef36df1ca4cd8692b23c33
7
- data.tar.gz: 537103640214323d3b77a835e74f59a626486b152d185586a534e9300d290e95ce28fbb49dfa9a3d82f76144feebe2cfd45a396997e863aa8ca78ab8918208b1
6
+ metadata.gz: 483f3c71553b51875b1e10d45c113f42ef3d93102658e7df5499bb912fffb810b9555fade2506eaf6e0c1bc4573b06f8b08b179ee1f2d6a336899f8e519d5aad
7
+ data.tar.gz: c0b8e60f94ad3dbeda5d3e10377633fb6dc248543176fda3d5e4353034e76c8b48804c855d7f9c0d778fe0a7180fa313ae313624fc8a26c1cc4257529cf67ce9
data/.rubocop.yml CHANGED
@@ -5,6 +5,7 @@ AllCops:
5
5
  TargetRubyVersion: 3.1
6
6
  Exclude:
7
7
  - "bin/*"
8
+ - 'vendor/bundle/**/*'
8
9
 
9
10
  Style/LambdaCall:
10
11
  Enabled: false
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- light_service-validated_context (0.1.1)
4
+ light_service-validated_context (0.2.2)
5
5
  dry-types (~> 1.7.0)
6
6
  light-service (>= 0.18.0)
7
7
  zeitwerk
data/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # LightService - ValidatedContext
2
2
 
3
+ [![Ruby](https://github.com/pioneerskies/light_service-validated_context/actions/workflows/main.yml/badge.svg?branch=main)](https://github.com/pioneerskies/light_service-validated_context/actions/workflows/main.yml)
4
+
3
5
  This gem _patches_ `light-service` gem implementing validated keys
4
6
  for `expects` and `promises` action's macros.
5
7
 
@@ -37,16 +39,22 @@ And then execute:
37
39
 
38
40
  $ bundle install
39
41
 
42
+ Would you need to manualy require the gem, here's the syntax:
43
+
44
+ ```ruby
45
+ require 'light_service/validated_context'
46
+ ```
47
+
40
48
  ## Usage
41
49
 
42
50
  ```ruby
43
51
  class ActionOne
44
52
  extend LightService::Action
45
53
 
46
- expects VK.(:email, Types::Strict::String)
47
- expects VK.(:age, Types::Coercible::Integer.constrained(gt: 30))
48
- expects VK.(:ary, Types::Array.of(Types::Strict::Symbol).constrained(min_size: 1))
49
- promises VK.(:text, Types::Strict::String.constrained(max_size: 10).default('foobar'))
54
+ expects VK.new(:email, Types::Strict::String)
55
+ expects VK.new(:age, Types::Coercible::Integer.constrained(gt: 30))
56
+ expects VK.new(:ary, Types::Array.of(Types::Strict::Symbol).constrained(min_size: 1))
57
+ promises VK.new(:text, Types::Strict::String.constrained(max_size: 10).default('foobar'))
50
58
 
51
59
  executed do |context|
52
60
  # something happens
@@ -75,6 +83,70 @@ form to avoid name collisions.
75
83
 
76
84
  You can find more usage example in `spec/support/test_doubles.rb`
77
85
 
86
+ ## Why validation matters?
87
+
88
+ In OO programming there's a rule (strict or "of thumb", IDK) that says to "never" instantiate an
89
+ invalid object whenever the object self has the concept of _validity_ for itself. This rule takes
90
+ sense to my eyes whenever I'm working with an object already initialized and in memory, but I cannot
91
+ trust its internal status.
92
+
93
+ Taken that `light-service` doesn't work on instances, but it works on classes and class methods
94
+ having a more functional and stateless approach, side effects of having invalid state in the context
95
+ (which is The state of an Action/Organizer) are mostly the same.
96
+
97
+ Rewording: if I cannot trust the state, given
98
+ the state is internal or delegated to a context object, I'll have to to a bunch of validation-oriented
99
+ logical branches into my logic. E.g.:
100
+
101
+ ```ruby
102
+ class HugAFriend
103
+ extend LightService::Action
104
+
105
+ expects :friend
106
+
107
+ executed do |context|
108
+ context.friend.hug if context.friend.respond_to?(:hug)
109
+ end
110
+ end
111
+ ```
112
+
113
+ The `if` in this uber-trivial example exists just due to lack of trust on the state.
114
+
115
+ Let's re-imagine the code given an `executed` block that totally trusts the context:
116
+
117
+
118
+ ```ruby
119
+ class HugAFriend
120
+ extend LightService::Action
121
+
122
+ expects VK.new(:friend, Types.Instance(Friend))
123
+ # Or a less usual approach could be to trust duck typing
124
+ # expects VK.new(:friend, Types::Interface(:hug))
125
+
126
+ executed do |context|
127
+ context.friend.hug
128
+ end
129
+ end
130
+ ```
131
+
132
+ ## Comparison with similar gems
133
+
134
+ This is a comparison table I've done using my own limited experience w/ other solutions
135
+ and/or reading projects' READMEs. Don't take my word for it. And if I was wrong understanding
136
+ some features, feel free to drop me a line on Mastodon [@alessandrofazzi@mastodon.uno](https://mastodon.uno/@alessandrofazzi)
137
+
138
+ | Feature | adomokos/light-service | sunny/actor | collectiveidea/interactor | AaronLasseigne/active_interaction | pioneerskies/light_service-validated_context/ |
139
+ | ------------------------- | ---------------------- | ---------------------------------------------------- | ------------------------- | --------------------------------- | --------------------------------------------- |
140
+ | presence | ✅ | ✅ | ❌ | ⚠️ Only input, not output | ✅ |
141
+ | static default | ✅ | ✅ | ❌ | ✅ | ✅ |
142
+ | dynamic default | ✅ | ✅ | ❌ | ✅ | ✅ |
143
+ | raise or fail control | ❌ | ✅ | ❌ | ❓ | ❌ |
144
+ | type check | ❌ | ✅ | ❌ | ✅ | ✅ |
145
+ | data structure type check | ❌ | ❌ | ❌ | ❌ | ✅ |
146
+ | optional | ⚠️ through `default` | ✅ through `allow_nil` (which defaults to `true` 🤔 ❓) | ❌ | ⚠️ through `default` | ✅ |
147
+ | built-in | ✅ | ✅ | ❌ | ❌ ActiveModel::Validation | ❌ Dry::Types |
148
+
149
+
78
150
  ## Development
79
151
 
80
152
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ValidatedContext
4
- module ContextOverrides
4
+ module Context
5
5
  def define_accessor_methods_for_keys(keys)
6
6
  super keys.map(&:to_sym)
7
7
  end
@@ -3,15 +3,29 @@
3
3
  module ValidatedContext
4
4
  module ExpectedKeyVerifier
5
5
  def keys
6
+ keys_as_symbols
7
+ end
8
+
9
+ def keys_as_symbols
6
10
  action.expected_keys.map do |key|
7
11
  next key unless key.is_a?(LightService::Context::ValidatedKey)
8
12
 
9
- key.label
13
+ key.to_sym
10
14
  end
11
15
  end
12
16
 
13
17
  def raw_keys
14
18
  action.expected_keys
15
19
  end
20
+
21
+ def throw_error_predicate(keys)
22
+ type_check_and_coerce_keys!(raw_keys)
23
+
24
+ keys_are_all_present = are_all_keys_in_context?(keys)
25
+
26
+ return false if are_all_keys_valid? && keys_are_all_present
27
+
28
+ true
29
+ end
16
30
  end
17
31
  end
@@ -2,38 +2,28 @@
2
2
 
3
3
  module ValidatedContext
4
4
  module KeyVerifier
5
- def are_all_keys_valid?(validated_keys)
5
+ def type_check_and_coerce_keys!(keys)
6
6
  errors = []
7
7
 
8
- validated_keys.each do |key|
8
+ keys.each do |key|
9
9
  next unless key.is_a?(LightService::Context::ValidatedKey)
10
10
 
11
11
  begin
12
12
  context[key.label] = key.type[context[key.label] || Dry::Types::Undefined]
13
13
  rescue Dry::Types::CoercionError => e
14
- errors << e.message
14
+ errors << "[#{action}][:#{key.label}] #{e.message}"
15
15
  end
16
16
  end
17
-
18
- [errors.none?, errors]
17
+ # debugger
18
+ @validation_errors = errors
19
19
  end
20
20
 
21
- def are_all_keys_in_context?(keys)
22
- keys_are_all_valid, validation_errors = are_all_keys_valid?(raw_keys)
23
-
24
- not_found_keys = keys_not_found(keys)
25
- keys_are_all_present = not_found_keys.none?
26
-
27
- return true if keys_are_all_valid && keys_are_all_present
28
-
29
- msg = if !keys_are_all_present
30
- error_message
31
- elsif !keys_are_all_valid
32
- validation_errors.join(', ')
33
- end
21
+ def are_all_keys_valid?
22
+ @validation_errors.none?
23
+ end
34
24
 
35
- LightService::Configuration.logger.error msg
36
- raise error_to_throw, msg
25
+ def error_message
26
+ @validation_errors.join(', ')
37
27
  end
38
28
  end
39
29
  end
@@ -3,15 +3,29 @@
3
3
  module ValidatedContext
4
4
  module PromisedKeyVerifier
5
5
  def keys
6
- action.promised_keys.map do |key|
6
+ keys_as_symbols
7
+ end
8
+
9
+ def keys_as_symbols
10
+ raw_keys.map do |key|
7
11
  next key unless key.is_a?(LightService::Context::ValidatedKey)
8
12
 
9
- key.label
13
+ key.to_sym
10
14
  end
11
15
  end
12
16
 
13
17
  def raw_keys
14
18
  action.promised_keys
15
19
  end
20
+
21
+ def throw_error_predicate(keys)
22
+ type_check_and_coerce_keys!(raw_keys)
23
+
24
+ keys_are_all_present = are_all_keys_in_context?(keys)
25
+
26
+ return false if are_all_keys_valid? && keys_are_all_present
27
+
28
+ true
29
+ end
16
30
  end
17
31
  end
@@ -2,10 +2,6 @@
2
2
 
3
3
  module ValidatedContext
4
4
  ValidatedKey = Struct.new(:label, :type) do
5
- def self.call(*args)
6
- new(*args)
7
- end
8
-
9
5
  def to_sym
10
6
  label.to_sym
11
7
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module LightService
4
4
  module ValidatedContext
5
- VERSION = "0.1.1"
5
+ VERSION = "0.2.2"
6
6
  end
7
7
  end
@@ -12,15 +12,17 @@ module ValidatedContext; end
12
12
  module LightService
13
13
  class Context
14
14
  ValidatedKey = ::ValidatedContext::ValidatedKey
15
- prepend ::ValidatedContext::ContextOverrides
15
+ prepend ::ValidatedContext::Context
16
16
 
17
- class ExpectedKeyVerifier
17
+ class KeyVerifier
18
18
  prepend ::ValidatedContext::KeyVerifier
19
+ end
20
+
21
+ class ExpectedKeyVerifier
19
22
  prepend ::ValidatedContext::ExpectedKeyVerifier
20
23
  end
21
24
 
22
25
  class PromisedKeyVerifier
23
- prepend ::ValidatedContext::KeyVerifier
24
26
  prepend ::ValidatedContext::PromisedKeyVerifier
25
27
  end
26
28
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: light_service-validated_context
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - "'Alessandro Fazzi'"
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-11-29 00:00:00.000000000 Z
11
+ date: 2022-11-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dry-types
@@ -67,7 +67,7 @@ files:
67
67
  - README.md
68
68
  - Rakefile
69
69
  - lib/light_service/validated_context.rb
70
- - lib/light_service/validated_context/context_overrides.rb
70
+ - lib/light_service/validated_context/context.rb
71
71
  - lib/light_service/validated_context/expected_key_verifier.rb
72
72
  - lib/light_service/validated_context/key_verifier.rb
73
73
  - lib/light_service/validated_context/promised_key_verifier.rb