service_actor 1.0.0 → 1.1.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: a16f2ccd8bf0d2e83d5cb9ec163c81b9df3be06515cb716138049f9d33420759
4
- data.tar.gz: bfb6c4dca34cb64fa3c8ce84b085faa85547c1a554f241ccf49d92a7a67d012b
3
+ metadata.gz: 1f46ecd0093a05e45fe0bc3ba11a69a8b282b82f4945ab05ff9f5cd1cd32e35e
4
+ data.tar.gz: 91f2c49e081eba4abbebceaef9abc131c3e8ad1c84a723846d144e2c8a890dff
5
5
  SHA512:
6
- metadata.gz: 18df62d093865eefd2acd8a9d3567c1379be5c097c087b6c2d2eee1dc8cf0485e5b0b6f712b11a19492eca3465b48ba0281de7b88130e170681923ec3cc2086c
7
- data.tar.gz: 80df1b4cc8269802cfe217663fa16ed907103a1b3e4b8ee42d1d01ac08c47a571f4993439f27d1065fbbb38738132be459b042aadfd04bdfe229bb6a2a4dbc27
6
+ metadata.gz: bee18ffff2ffbf4eb185b28ab16c519ca30e09af6ba61773009d553c563e9dbdf903aa7c5d6a66b3a4c8a49886f00337b474e1e1376f207f81d1cbe268f3f29b
7
+ data.tar.gz: 68e99c61d126b23877cfc4497a4c830b343e1170f49b027013da7a68062d85f644f689ad389d4c584e5b39206cac66a4cb6ab9e359ac9f65a309832c14dab060
data/README.md CHANGED
@@ -83,19 +83,24 @@ result.greeting # => "Have a wonderful day!"
83
83
  Inputs can have defaults:
84
84
 
85
85
  ```rb
86
- class PrintWelcome < Actor
87
- input :user
86
+ class BuildGreeting < Actor
88
87
  input :adjective, default: "wonderful"
89
88
  input :length_of_time, default: -> { ["day", "week", "month"].sample }
90
89
 
91
90
  output :greeting
92
91
 
93
92
  def call
94
- context.greeting = "Hello #{name}! Have a #{adjective} #{length_of_time}!"
93
+ context.greeting = "Have a #{adjective} #{length_of_time}!"
95
94
  end
96
95
  end
97
96
  ```
98
97
 
98
+ This lets you call the actor without specifying those keys:
99
+
100
+ ```rb
101
+ BuildGreeting.call.greeting # => "Have a wonderful week!"
102
+ ```
103
+
99
104
  ### Types
100
105
 
101
106
  Inputs can define a type, or an array of possible types it must match:
@@ -109,10 +114,22 @@ class UpdateUser < Actor
109
114
  end
110
115
  ```
111
116
 
117
+ ### Required
118
+
119
+ To check that an input must not be `nil`, flag it as required.
120
+
121
+ ```rb
122
+ class UpdateUser < Actor
123
+ input :user, required: true
124
+
125
+ # …
126
+ end
127
+ ```
128
+
112
129
  ### Conditions
113
130
 
114
- If types don't cut it, you can add small conditions with the name of your choice
115
- under `must`:
131
+ You can also add conditions that the inputs must verify, with the name of your
132
+ choice under `must`:
116
133
 
117
134
  ```rb
118
135
  class UpdateAdminUser < Actor
@@ -125,7 +142,7 @@ end
125
142
 
126
143
  ### Result
127
144
 
128
- All actors are successful by default. To stop its execution and mark is as
145
+ All actors are successful by default. To stop the execution and mark an actor as
129
146
  having failed, use `fail!`:
130
147
 
131
148
  ```rb
@@ -143,11 +160,10 @@ class UpdateUser
143
160
  end
144
161
  ```
145
162
 
146
- You can then test for the success by calling your actor with `.result` instead
147
- of `.call`. This will let you test for `success?` or `failure?` on the context
148
- instead of raising an exception.
163
+ This will raise an error in your app.
149
164
 
150
- For example in a Rails controller:
165
+ To test for the success instead of raising, you can use `.result` instead of
166
+ `.call`. For example in a Rails controller:
151
167
 
152
168
  ```rb
153
169
  # app/controllers/users_controller.rb
@@ -166,7 +182,7 @@ end
166
182
  ### Play
167
183
 
168
184
  An actor can call actors in sequence by using `play`. Each actor will hand over
169
- the context to the next actor.
185
+ the same context to the next actor.
170
186
 
171
187
  ```rb
172
188
  class PlaceOrder < Actor
@@ -182,8 +198,8 @@ end
182
198
  When using `play`, if one of the actors calls `fail!`, the following actors will
183
199
  not be called.
184
200
 
185
- Also, any _previous_ actor that succeeded will call the `rollback` method, if
186
- you defined one.
201
+ Also, all the _previous_ actors that succeeded will have their `rollback`
202
+ method triggered. For example:
187
203
 
188
204
  ```rb
189
205
  class CreateOrder < Actor
@@ -199,12 +215,12 @@ end
199
215
 
200
216
  ### Early success
201
217
 
202
- When using `play` you can use `succeed!` so that the following actors will not
203
- be called, but still consider the actor to be successful.
218
+ When using `play` you can use `succeed!` to stop the execution of the following
219
+ actors, but still consider the actor to be successful.
204
220
 
205
221
  ### Lambdas
206
222
 
207
- You can call inline actions using lambdas:
223
+ You can use inline actions using lambdas:
208
224
 
209
225
  ```rb
210
226
  class Pay
@@ -264,9 +280,7 @@ However there a a few key differences which make `actor` unique:
264
280
  - Multiple organizers.
265
281
  - Conditions inside organizers.
266
282
  - No `before`, `after` and `around` hooks. Prefer simply overriding `call` with `super` which allows wrapping the whole method.
267
- - [Does not rely on `OpenStruct`](https://github.com/collectiveidea/interactor/issues/183)
268
- - Does not print warnings on Ruby 2.7.
269
-
283
+ - [Fixes issues with `OpenStruct`](https://github.com/collectiveidea/interactor/issues/183)
270
284
 
271
285
  ## Development
272
286
 
data/lib/actor/context.rb CHANGED
@@ -2,34 +2,28 @@
2
2
 
3
3
  class Actor
4
4
  # Represents the result of an action.
5
- class Context
5
+ class Context < OpenStruct
6
6
  def self.to_context(data)
7
7
  return data if data.is_a?(self)
8
8
 
9
- new(data)
10
- end
11
-
12
- def initialize(data = {})
13
- @data = data.dup
14
- end
15
-
16
- def ==(other)
17
- other.class == self.class && data == other.data
9
+ new(data.to_h)
18
10
  end
19
11
 
20
12
  def inspect
21
- "<ActorContext #{data.inspect}>"
13
+ "<ActorContext #{to_h}>"
22
14
  end
23
15
 
24
16
  def fail!(context = {})
25
17
  merge!(context)
26
- data[:failure?] = true
18
+ merge!(failure?: true)
19
+
27
20
  raise Actor::Failure, self
28
21
  end
29
22
 
30
23
  def succeed!(context = {})
31
24
  merge!(context)
32
- data[:failure?] = false
25
+ merge!(failure?: false)
26
+
33
27
  raise Actor::Success, self
34
28
  end
35
29
 
@@ -38,55 +32,28 @@ class Actor
38
32
  end
39
33
 
40
34
  def failure?
41
- data.fetch(:failure?, false)
35
+ super || false
42
36
  end
43
37
 
44
38
  def merge!(context)
45
- data.merge!(context)
39
+ context.each_pair do |key, value|
40
+ self[key] = value
41
+ end
46
42
 
47
43
  self
48
44
  end
49
45
 
50
46
  def key?(name)
51
- data.key?(name)
47
+ to_h.key?(name)
52
48
  end
53
49
 
54
50
  def [](name)
55
- data[name]
51
+ to_h[name]
56
52
  end
57
53
 
58
54
  # Redefined here to override the method on `Object`.
59
55
  def display
60
- data.fetch(:display)
61
- end
62
-
63
- protected
64
-
65
- attr_reader :data
66
-
67
- private
68
-
69
- # rubocop:disable Style/MethodMissingSuper
70
- def method_missing(name, *arguments, **)
71
- if name =~ /=$/
72
- key = name.to_s.sub('=', '').to_sym
73
- data[key] = arguments.first
74
- else
75
- data[name]
76
- end
77
- end
78
- # rubocop:enable Style/MethodMissingSuper
79
-
80
- def respond_to_missing?(*_arguments)
81
- true
82
- end
83
-
84
- def context_get(key)
85
- data[key]
86
- end
87
-
88
- def context_set(key, value)
89
- data[key] = value
56
+ to_h.fetch(:display)
90
57
  end
91
58
  end
92
59
  end
@@ -2,6 +2,7 @@
2
2
 
3
3
  class Actor
4
4
  # Adds the `default:` option to inputs. Accepts regular values and lambdas.
5
+ # If no default is set and the value has not been given, raises an error.
5
6
  #
6
7
  # Example:
7
8
  #
@@ -12,7 +13,11 @@ class Actor
12
13
  module Defaultable
13
14
  def before
14
15
  self.class.inputs.each do |name, input|
15
- next if !input.key?(:default) || @context.key?(name)
16
+ next if @context.key?(name)
17
+
18
+ unless input.key?(:default)
19
+ raise ArgumentError, "Input #{name} on #{self.class} is missing."
20
+ end
16
21
 
17
22
  default = input[:default]
18
23
  default = default.call if default.respond_to?(:call)
@@ -27,17 +27,17 @@ class Actor
27
27
 
28
28
  attr_reader :context, :readers, :setters
29
29
 
30
- def method_missing(name, *arguments, **options)
31
- return super unless context.respond_to?(name)
32
-
30
+ # rubocop:disable Style/MethodMissingSuper
31
+ def method_missing(name, *arguments, &block)
33
32
  unless available_methods.include?(name)
34
33
  raise ArgumentError, "Cannot call #{name} on #{inspect}"
35
34
  end
36
35
 
37
- context.public_send(name, *arguments)
36
+ context.public_send(name, *arguments, &block)
38
37
  end
38
+ # rubocop:enable Style/MethodMissingSuper
39
39
 
40
- def respond_to_missing?(name, *_arguments)
40
+ def respond_to_missing?(name, _include_private = false)
41
41
  available_methods.include?(name)
42
42
  end
43
43
 
@@ -60,7 +60,7 @@ class Actor
60
60
  private
61
61
 
62
62
  def play_actor(actor)
63
- if actor.respond_to?(:new)
63
+ if actor.is_a?(Class) && actor.ancestors.include?(Actor)
64
64
  actor = actor.new(@context)
65
65
  actor.run
66
66
  else
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Actor
4
- # Adds `required:` checking to inputs and outputs.
4
+ # Ensure your inputs and outputs are not nil by adding `required: true`.
5
5
  #
6
6
  # Example:
7
7
  #
data/lib/actor/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Actor
4
- VERSION = '1.0.0'
4
+ VERSION = '1.1.0'
5
5
  end
data/lib/service_actor.rb CHANGED
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'ostruct'
4
+
3
5
  require 'actor/failure'
4
6
  require 'actor/success'
5
7
  require 'actor/context'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: service_actor
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sunny Ripert
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-03-15 00:00:00.000000000 Z
11
+ date: 2020-03-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec