service_actor 1.0.0 → 1.1.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: 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