service_actor 3.1.2 → 3.3.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 +4 -4
 - data/README.md +111 -84
 - data/lib/service_actor/attributable.rb +3 -0
 - data/lib/service_actor/base.rb +13 -13
 - data/lib/service_actor/collectionable.rb +1 -1
 - data/lib/service_actor/conditionable.rb +1 -1
 - data/lib/service_actor/core.rb +10 -7
 - data/lib/service_actor/defaultable.rb +1 -1
 - data/lib/service_actor/error.rb +1 -1
 - data/lib/service_actor/nil_checkable.rb +7 -12
 - data/lib/service_actor/playable.rb +39 -23
 - data/lib/service_actor/result.rb +25 -2
 - data/lib/service_actor/type_checkable.rb +3 -3
 - data/lib/service_actor/version.rb +1 -1
 - data/lib/service_actor.rb +1 -1
 - metadata +13 -6
 
    
        checksums.yaml
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ---
         
     | 
| 
       2 
2 
     | 
    
         
             
            SHA256:
         
     | 
| 
       3 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       4 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: b1cffe28ea4e94682af7f8ee771ad803134e80ce17a9230552d13b4c169b20c7
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: 179b2cbf950872b1dbf46d3bd3b24bafbbc3bbb8cd32574f4dbad6a361958abd
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: 1e2804c9d25b20b853300d59976075c5ab451670b7e0b05986507e3e07fe9295efa79d3de34ef2d96a59a2f64154bebd4a88a5726ee308dbaed17c5fac2aa3a5
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: 5fc857d43785fe5c6bf5c3723dd91253f4e914f6dccfffc0c258504e306bd4ebc3992ef72a6d37ccc70b4420fba0f86da51165e5fbf0d153b3d64ba9c5bfb18d
         
     | 
    
        data/README.md
    CHANGED
    
    | 
         @@ -1,4 +1,4 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            #  
     | 
| 
      
 1 
     | 
    
         
            +
            # ServiceActor
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            
         
     | 
| 
       4 
4 
     | 
    
         | 
| 
         @@ -18,34 +18,40 @@ and controllers thin. 
     | 
|
| 
       18 
18 
     | 
    
         
             
              - [Conditions](#conditions)
         
     | 
| 
       19 
19 
     | 
    
         
             
              - [Allow nil](#allow-nil)
         
     | 
| 
       20 
20 
     | 
    
         
             
              - [Types](#types)
         
     | 
| 
       21 
     | 
    
         
            -
              - [ 
     | 
| 
      
 21 
     | 
    
         
            +
              - [Fail](#fail)
         
     | 
| 
       22 
22 
     | 
    
         
             
            - [Play actors in a sequence](#play-actors-in-a-sequence)
         
     | 
| 
       23 
23 
     | 
    
         
             
              - [Rollback](#rollback)
         
     | 
| 
       24 
     | 
    
         
            -
              - [ 
     | 
| 
      
 24 
     | 
    
         
            +
              - [Inline actors](#inline-actors)
         
     | 
| 
       25 
25 
     | 
    
         
             
              - [Play conditions](#play-conditions)
         
     | 
| 
       26 
26 
     | 
    
         
             
            - [Testing](#testing)
         
     | 
| 
       27 
27 
     | 
    
         
             
            - [Build your own actor](#build-your-own-actor)
         
     | 
| 
       28 
28 
     | 
    
         
             
            - [Influences](#influences)
         
     | 
| 
       29 
29 
     | 
    
         
             
            - [Thanks](#thanks)
         
     | 
| 
       30 
     | 
    
         
            -
            - [Development](#development)
         
     | 
| 
       31 
30 
     | 
    
         
             
            - [Contributing](#contributing)
         
     | 
| 
       32 
31 
     | 
    
         
             
            - [License](#contributing)
         
     | 
| 
       33 
32 
     | 
    
         | 
| 
       34 
33 
     | 
    
         
             
            ## Installation
         
     | 
| 
       35 
34 
     | 
    
         | 
| 
       36 
     | 
    
         
            -
            Add  
     | 
| 
      
 35 
     | 
    
         
            +
            Add the gem to your application’s Gemfile by executing:
         
     | 
| 
       37 
36 
     | 
    
         | 
| 
       38 
     | 
    
         
            -
            ``` 
     | 
| 
       39 
     | 
    
         
            -
             
     | 
| 
       40 
     | 
    
         
            -
            gem 'service_actor'
         
     | 
| 
      
 37 
     | 
    
         
            +
            ```sh
         
     | 
| 
      
 38 
     | 
    
         
            +
            bundle add service_actor
         
     | 
| 
       41 
39 
     | 
    
         
             
            ```
         
     | 
| 
       42 
40 
     | 
    
         | 
| 
       43 
     | 
    
         
            -
             
     | 
| 
      
 41 
     | 
    
         
            +
            ### Extensions
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
            For **Rails generators**, you can use the
         
     | 
| 
       44 
44 
     | 
    
         
             
            [service_actor-rails](https://github.com/sunny/actor-rails) gem:
         
     | 
| 
       45 
45 
     | 
    
         | 
| 
       46 
     | 
    
         
            -
            ``` 
     | 
| 
       47 
     | 
    
         
            -
             
     | 
| 
       48 
     | 
    
         
            -
             
     | 
| 
      
 46 
     | 
    
         
            +
            ```sh
         
     | 
| 
      
 47 
     | 
    
         
            +
            bundle add service_actor-rails
         
     | 
| 
      
 48 
     | 
    
         
            +
            ```
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
            For **TTY prompts**, you can use the
         
     | 
| 
      
 51 
     | 
    
         
            +
            [service_actor-promptable](https://github.com/pboling/service_actor-promptable) gem:
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
            ```sh
         
     | 
| 
      
 54 
     | 
    
         
            +
            bundle add service_actor-promptable
         
     | 
| 
       49 
55 
     | 
    
         
             
            ```
         
     | 
| 
       50 
56 
     | 
    
         | 
| 
       51 
57 
     | 
    
         
             
            ## Usage
         
     | 
| 
         @@ -69,9 +75,10 @@ Trigger them in your application with `.call`: 
     | 
|
| 
       69 
75 
     | 
    
         
             
            SendNotification.call # => <ServiceActor::Result…>
         
     | 
| 
       70 
76 
     | 
    
         
             
            ```
         
     | 
| 
       71 
77 
     | 
    
         | 
| 
       72 
     | 
    
         
            -
            When called,  
     | 
| 
       73 
     | 
    
         
            -
            actors to accept and return multiple arguments. Let 
     | 
| 
       74 
     | 
    
         
            -
            and then we 
     | 
| 
      
 78 
     | 
    
         
            +
            When called, an actor returns a result. Reading and writing to this result allows
         
     | 
| 
      
 79 
     | 
    
         
            +
            actors to accept and return multiple arguments. Let’s find out how to do that
         
     | 
| 
      
 80 
     | 
    
         
            +
            and then we’ll see how to
         
     | 
| 
      
 81 
     | 
    
         
            +
            [chain multiple actors togethor](#play-actors-in-a-sequence).
         
     | 
| 
       75 
82 
     | 
    
         | 
| 
       76 
83 
     | 
    
         
             
            ### Inputs
         
     | 
| 
       77 
84 
     | 
    
         | 
| 
         @@ -103,7 +110,7 @@ class BuildGreeting < Actor 
     | 
|
| 
       103 
110 
     | 
    
         
             
              output :greeting
         
     | 
| 
       104 
111 
     | 
    
         | 
| 
       105 
112 
     | 
    
         
             
              def call
         
     | 
| 
       106 
     | 
    
         
            -
                self.greeting =  
     | 
| 
      
 113 
     | 
    
         
            +
                self.greeting = "Have a wonderful day!"
         
     | 
| 
       107 
114 
     | 
    
         
             
              end
         
     | 
| 
       108 
115 
     | 
    
         
             
            end
         
     | 
| 
       109 
116 
     | 
    
         
             
            ```
         
     | 
| 
         @@ -111,8 +118,19 @@ end 
     | 
|
| 
       111 
118 
     | 
    
         
             
            The result you get from calling an actor will include the outputs you set:
         
     | 
| 
       112 
119 
     | 
    
         | 
| 
       113 
120 
     | 
    
         
             
            ```rb
         
     | 
| 
       114 
     | 
    
         
            -
             
     | 
| 
       115 
     | 
    
         
            -
             
     | 
| 
      
 121 
     | 
    
         
            +
            actor = BuildGreeting.call
         
     | 
| 
      
 122 
     | 
    
         
            +
            actor.greeting # => "Have a wonderful day!"
         
     | 
| 
      
 123 
     | 
    
         
            +
            ```
         
     | 
| 
      
 124 
     | 
    
         
            +
             
     | 
| 
      
 125 
     | 
    
         
            +
            For every output there is also a boolean method ending with `?` to test its
         
     | 
| 
      
 126 
     | 
    
         
            +
            presence:
         
     | 
| 
      
 127 
     | 
    
         
            +
             
     | 
| 
      
 128 
     | 
    
         
            +
            ```rb
         
     | 
| 
      
 129 
     | 
    
         
            +
            if actor.greeting?
         
     | 
| 
      
 130 
     | 
    
         
            +
              puts "Greetings is truthy"
         
     | 
| 
      
 131 
     | 
    
         
            +
            else
         
     | 
| 
      
 132 
     | 
    
         
            +
              puts "Greetings is falsey"
         
     | 
| 
      
 133 
     | 
    
         
            +
            end
         
     | 
| 
       116 
134 
     | 
    
         
             
            ```
         
     | 
| 
       117 
135 
     | 
    
         | 
| 
       118 
136 
     | 
    
         
             
            ### Defaults
         
     | 
| 
         @@ -122,8 +140,8 @@ Inputs can be marked as optional by providing a default: 
     | 
|
| 
       122 
140 
     | 
    
         
             
            ```rb
         
     | 
| 
       123 
141 
     | 
    
         
             
            class BuildGreeting < Actor
         
     | 
| 
       124 
142 
     | 
    
         
             
              input :name
         
     | 
| 
       125 
     | 
    
         
            -
              input :adjective, default:  
     | 
| 
       126 
     | 
    
         
            -
              input :length_of_time, default: -> { [ 
     | 
| 
      
 143 
     | 
    
         
            +
              input :adjective, default: "wonderful"
         
     | 
| 
      
 144 
     | 
    
         
            +
              input :length_of_time, default: -> { ["day", "week", "month"].sample }
         
     | 
| 
       127 
145 
     | 
    
         | 
| 
       128 
146 
     | 
    
         
             
              output :greeting
         
     | 
| 
       129 
147 
     | 
    
         | 
| 
         @@ -136,21 +154,20 @@ end 
     | 
|
| 
       136 
154 
     | 
    
         
             
            This lets you call the actor without specifying those keys:
         
     | 
| 
       137 
155 
     | 
    
         | 
| 
       138 
156 
     | 
    
         
             
            ```rb
         
     | 
| 
       139 
     | 
    
         
            -
             
     | 
| 
       140 
     | 
    
         
            -
             
     | 
| 
      
 157 
     | 
    
         
            +
            actor = BuildGreeting.call(name: "Jim")
         
     | 
| 
      
 158 
     | 
    
         
            +
            actor.greeting # => "Have a wonderful week Jim!"
         
     | 
| 
       141 
159 
     | 
    
         
             
            ```
         
     | 
| 
       142 
160 
     | 
    
         | 
| 
       143 
161 
     | 
    
         
             
            If an input does not have a default, it will raise a error:
         
     | 
| 
       144 
162 
     | 
    
         | 
| 
       145 
163 
     | 
    
         
             
            ```rb
         
     | 
| 
       146 
     | 
    
         
            -
             
     | 
| 
      
 164 
     | 
    
         
            +
            BuildGreeting.call
         
     | 
| 
       147 
165 
     | 
    
         
             
            => ServiceActor::ArgumentError: Input name on BuildGreeting is missing.
         
     | 
| 
       148 
166 
     | 
    
         
             
            ```
         
     | 
| 
       149 
167 
     | 
    
         | 
| 
       150 
168 
     | 
    
         
             
            ### Conditions
         
     | 
| 
       151 
169 
     | 
    
         | 
| 
       152 
     | 
    
         
            -
            You can ensure an input is included in a collection by using `in 
     | 
| 
       153 
     | 
    
         
            -
            yet):
         
     | 
| 
      
 170 
     | 
    
         
            +
            You can ensure an input is included in a collection by using `in`:
         
     | 
| 
       154 
171 
     | 
    
         | 
| 
       155 
172 
     | 
    
         
             
            ```rb
         
     | 
| 
       156 
173 
     | 
    
         
             
            class Pay < Actor
         
     | 
| 
         @@ -169,7 +186,7 @@ You can also add custom conditions with the name of your choice by using `must`: 
     | 
|
| 
       169 
186 
     | 
    
         
             
            class UpdateAdminUser < Actor
         
     | 
| 
       170 
187 
     | 
    
         
             
              input :user,
         
     | 
| 
       171 
188 
     | 
    
         
             
                    must: {
         
     | 
| 
       172 
     | 
    
         
            -
                      be_an_admin: -> 
     | 
| 
      
 189 
     | 
    
         
            +
                      be_an_admin: -> user { user.admin? }
         
     | 
| 
       173 
190 
     | 
    
         
             
                    }
         
     | 
| 
       174 
191 
     | 
    
         | 
| 
       175 
192 
     | 
    
         
             
              # …
         
     | 
| 
         @@ -192,12 +209,12 @@ end 
     | 
|
| 
       192 
209 
     | 
    
         | 
| 
       193 
210 
     | 
    
         
             
            ### Types
         
     | 
| 
       194 
211 
     | 
    
         | 
| 
       195 
     | 
    
         
            -
            Sometimes it can help to have a quick way of making sure we didn 
     | 
| 
      
 212 
     | 
    
         
            +
            Sometimes it can help to have a quick way of making sure we didn’t mess up our
         
     | 
| 
       196 
213 
     | 
    
         
             
            inputs.
         
     | 
| 
       197 
214 
     | 
    
         | 
| 
       198 
215 
     | 
    
         
             
            For that you can use the `type` option and giving a class or an array
         
     | 
| 
       199 
     | 
    
         
            -
            of possible classes. If the input or output doesn 
     | 
| 
       200 
     | 
    
         
            -
             
     | 
| 
      
 216 
     | 
    
         
            +
            of possible classes. If the input or output doesn’t match these types, an
         
     | 
| 
      
 217 
     | 
    
         
            +
            error is raised.
         
     | 
| 
       201 
218 
     | 
    
         | 
| 
       202 
219 
     | 
    
         
             
            ```rb
         
     | 
| 
       203 
220 
     | 
    
         
             
            class UpdateUser < Actor
         
     | 
| 
         @@ -208,14 +225,13 @@ class UpdateUser < Actor 
     | 
|
| 
       208 
225 
     | 
    
         
             
            end
         
     | 
| 
       209 
226 
     | 
    
         
             
            ```
         
     | 
| 
       210 
227 
     | 
    
         | 
| 
       211 
     | 
    
         
            -
            You may also use strings instead of constants, such as `type:  
     | 
| 
      
 228 
     | 
    
         
            +
            You may also use strings instead of constants, such as `type: "User"`.
         
     | 
| 
       212 
229 
     | 
    
         | 
| 
       213 
230 
     | 
    
         
             
            When using a type condition, `allow_nil` defaults to `false`.
         
     | 
| 
       214 
231 
     | 
    
         | 
| 
       215 
     | 
    
         
            -
            ###  
     | 
| 
      
 232 
     | 
    
         
            +
            ### Fail
         
     | 
| 
       216 
233 
     | 
    
         | 
| 
       217 
     | 
    
         
            -
             
     | 
| 
       218 
     | 
    
         
            -
            mark an actor as having failed, use `fail!`:
         
     | 
| 
      
 234 
     | 
    
         
            +
            To stop the execution and mark an actor as having failed, use `fail!`:
         
     | 
| 
       219 
235 
     | 
    
         | 
| 
       220 
236 
     | 
    
         
             
            ```rb
         
     | 
| 
       221 
237 
     | 
    
         
             
            class UpdateUser
         
     | 
| 
         @@ -225,7 +241,7 @@ class UpdateUser 
     | 
|
| 
       225 
241 
     | 
    
         
             
              def call
         
     | 
| 
       226 
242 
     | 
    
         
             
                user.attributes = attributes
         
     | 
| 
       227 
243 
     | 
    
         | 
| 
       228 
     | 
    
         
            -
                fail!(error:  
     | 
| 
      
 244 
     | 
    
         
            +
                fail!(error: "Invalid user") unless user.valid?
         
     | 
| 
       229 
245 
     | 
    
         | 
| 
       230 
246 
     | 
    
         
             
                # …
         
     | 
| 
       231 
247 
     | 
    
         
             
              end
         
     | 
| 
         @@ -235,7 +251,8 @@ end 
     | 
|
| 
       235 
251 
     | 
    
         
             
            This will raise an error in your app with the given data added to the result.
         
     | 
| 
       236 
252 
     | 
    
         | 
| 
       237 
253 
     | 
    
         
             
            To test for the success of your actor instead of raising an exception, use
         
     | 
| 
       238 
     | 
    
         
            -
            `.result` instead of `.call 
     | 
| 
      
 254 
     | 
    
         
            +
            `.result` instead of `.call`. You can then call `success?` or `failure?` on
         
     | 
| 
      
 255 
     | 
    
         
            +
            the result.
         
     | 
| 
       239 
256 
     | 
    
         | 
| 
       240 
257 
     | 
    
         
             
            For example in a Rails controller:
         
     | 
| 
       241 
258 
     | 
    
         | 
| 
         @@ -243,17 +260,17 @@ For example in a Rails controller: 
     | 
|
| 
       243 
260 
     | 
    
         
             
            # app/controllers/users_controller.rb
         
     | 
| 
       244 
261 
     | 
    
         
             
            class UsersController < ApplicationController
         
     | 
| 
       245 
262 
     | 
    
         
             
              def create
         
     | 
| 
       246 
     | 
    
         
            -
                 
     | 
| 
       247 
     | 
    
         
            -
                if  
     | 
| 
       248 
     | 
    
         
            -
                  redirect_to  
     | 
| 
      
 263 
     | 
    
         
            +
                actor = UpdateUser.result(user: user, attributes: user_attributes)
         
     | 
| 
      
 264 
     | 
    
         
            +
                if actor.success?
         
     | 
| 
      
 265 
     | 
    
         
            +
                  redirect_to actor.user
         
     | 
| 
       249 
266 
     | 
    
         
             
                else
         
     | 
| 
       250 
     | 
    
         
            -
                  render :new, notice:  
     | 
| 
      
 267 
     | 
    
         
            +
                  render :new, notice: actor.error
         
     | 
| 
       251 
268 
     | 
    
         
             
                end
         
     | 
| 
       252 
269 
     | 
    
         
             
              end
         
     | 
| 
       253 
270 
     | 
    
         
             
            end
         
     | 
| 
       254 
271 
     | 
    
         
             
            ```
         
     | 
| 
       255 
272 
     | 
    
         | 
| 
       256 
     | 
    
         
            -
             
     | 
| 
      
 273 
     | 
    
         
            +
            The keys you add to `fail!` will be added to the result, for example you could
         
     | 
| 
       257 
274 
     | 
    
         
             
            do: `fail!(error_type: "validation", error_code: "uv52", …)`.
         
     | 
| 
       258 
275 
     | 
    
         | 
| 
       259 
276 
     | 
    
         
             
            ## Play actors in a sequence
         
     | 
| 
         @@ -264,7 +281,7 @@ actor can use `play` to call other actors: 
     | 
|
| 
       264 
281 
     | 
    
         
             
            ```rb
         
     | 
| 
       265 
282 
     | 
    
         
             
            class PlaceOrder < Actor
         
     | 
| 
       266 
283 
     | 
    
         
             
              play CreateOrder,
         
     | 
| 
       267 
     | 
    
         
            -
                    
     | 
| 
      
 284 
     | 
    
         
            +
                   PayOrder,
         
     | 
| 
       268 
285 
     | 
    
         
             
                   SendOrderConfirmation,
         
     | 
| 
       269 
286 
     | 
    
         
             
                   NotifyAdmins
         
     | 
| 
       270 
287 
     | 
    
         
             
            end
         
     | 
| 
         @@ -300,30 +317,55 @@ Rollback is only called on the _previous_ actors in `play` and is not called on 
     | 
|
| 
       300 
317 
     | 
    
         
             
            the failing actor itself. Actors should be kept to a single purpose and not have
         
     | 
| 
       301 
318 
     | 
    
         
             
            anything to clean up if they call `fail!`.
         
     | 
| 
       302 
319 
     | 
    
         | 
| 
       303 
     | 
    
         
            -
            ###  
     | 
| 
      
 320 
     | 
    
         
            +
            ### Inline actors
         
     | 
| 
       304 
321 
     | 
    
         | 
| 
       305 
     | 
    
         
            -
             
     | 
| 
       306 
     | 
    
         
            -
             
     | 
| 
      
 322 
     | 
    
         
            +
            For small work or preparing the result set for the next actors, you can create
         
     | 
| 
      
 323 
     | 
    
         
            +
            inline actors by using lambdas. Each lambda has access to the shared result. For
         
     | 
| 
      
 324 
     | 
    
         
            +
            example:
         
     | 
| 
       307 
325 
     | 
    
         | 
| 
       308 
326 
     | 
    
         
             
            ```rb
         
     | 
| 
       309 
     | 
    
         
            -
            class  
     | 
| 
       310 
     | 
    
         
            -
               
     | 
| 
      
 327 
     | 
    
         
            +
            class PayOrder < Actor
         
     | 
| 
      
 328 
     | 
    
         
            +
              input :order
         
     | 
| 
      
 329 
     | 
    
         
            +
             
     | 
| 
      
 330 
     | 
    
         
            +
              play -> actor { actor.order.currency ||= "EUR" },
         
     | 
| 
       311 
331 
     | 
    
         
             
                   CreatePayment,
         
     | 
| 
       312 
     | 
    
         
            -
                    
     | 
| 
       313 
     | 
    
         
            -
                    
     | 
| 
      
 332 
     | 
    
         
            +
                   UpdateOrderBalance,
         
     | 
| 
      
 333 
     | 
    
         
            +
                   -> actor { Logger.info("Order #{actor.order.id} paid") }
         
     | 
| 
       314 
334 
     | 
    
         
             
            end
         
     | 
| 
       315 
335 
     | 
    
         
             
            ```
         
     | 
| 
       316 
336 
     | 
    
         | 
| 
       317 
     | 
    
         
            -
             
     | 
| 
       318 
     | 
    
         
            -
            result for the next actors. If you want to do more work before, or after the
         
     | 
| 
       319 
     | 
    
         
            -
            whole `play`, you can also override the `call` method. For example:
         
     | 
| 
      
 337 
     | 
    
         
            +
            You can also call instance methods. For example:
         
     | 
| 
       320 
338 
     | 
    
         | 
| 
       321 
339 
     | 
    
         
             
            ```rb
         
     | 
| 
       322 
     | 
    
         
            -
            class  
     | 
| 
      
 340 
     | 
    
         
            +
            class PayOrder < Actor
         
     | 
| 
      
 341 
     | 
    
         
            +
              input :order
         
     | 
| 
      
 342 
     | 
    
         
            +
             
     | 
| 
      
 343 
     | 
    
         
            +
              play :assign_default_currency,
         
     | 
| 
      
 344 
     | 
    
         
            +
                   CreatePayment,
         
     | 
| 
      
 345 
     | 
    
         
            +
                   UpdateOrderBalance,
         
     | 
| 
      
 346 
     | 
    
         
            +
                   :log_payment
         
     | 
| 
      
 347 
     | 
    
         
            +
             
     | 
| 
      
 348 
     | 
    
         
            +
              private
         
     | 
| 
      
 349 
     | 
    
         
            +
             
     | 
| 
      
 350 
     | 
    
         
            +
              def assign_default_currency
         
     | 
| 
      
 351 
     | 
    
         
            +
                order.currency ||= "EUR"
         
     | 
| 
      
 352 
     | 
    
         
            +
              end
         
     | 
| 
      
 353 
     | 
    
         
            +
             
     | 
| 
      
 354 
     | 
    
         
            +
              def log_payment
         
     | 
| 
      
 355 
     | 
    
         
            +
                Logger.info("Order #{order.id} paid")
         
     | 
| 
      
 356 
     | 
    
         
            +
              end
         
     | 
| 
      
 357 
     | 
    
         
            +
            end
         
     | 
| 
      
 358 
     | 
    
         
            +
            ```
         
     | 
| 
      
 359 
     | 
    
         
            +
             
     | 
| 
      
 360 
     | 
    
         
            +
            If you want to do work around the whole actor, you can also override the `call`
         
     | 
| 
      
 361 
     | 
    
         
            +
            method. For example:
         
     | 
| 
      
 362 
     | 
    
         
            +
             
     | 
| 
      
 363 
     | 
    
         
            +
            ```rb
         
     | 
| 
      
 364 
     | 
    
         
            +
            class PayOrder < Actor
         
     | 
| 
       323 
365 
     | 
    
         
             
              # …
         
     | 
| 
       324 
366 
     | 
    
         | 
| 
       325 
367 
     | 
    
         
             
              def call
         
     | 
| 
       326 
     | 
    
         
            -
                Time.with_timezone( 
     | 
| 
      
 368 
     | 
    
         
            +
                Time.with_timezone("Paris") do
         
     | 
| 
       327 
369 
     | 
    
         
             
                  super
         
     | 
| 
       328 
370 
     | 
    
         
             
                end
         
     | 
| 
       329 
371 
     | 
    
         
             
              end
         
     | 
| 
         @@ -338,12 +380,10 @@ Actors in a play can be called conditionally: 
     | 
|
| 
       338 
380 
     | 
    
         
             
            class PlaceOrder < Actor
         
     | 
| 
       339 
381 
     | 
    
         
             
              play CreateOrder,
         
     | 
| 
       340 
382 
     | 
    
         
             
                   Pay
         
     | 
| 
       341 
     | 
    
         
            -
              play NotifyAdmins, if: -> 
     | 
| 
      
 383 
     | 
    
         
            +
              play NotifyAdmins, if: -> actor { actor.order.amount > 42 }
         
     | 
| 
       342 
384 
     | 
    
         
             
            end
         
     | 
| 
       343 
385 
     | 
    
         
             
            ```
         
     | 
| 
       344 
386 
     | 
    
         | 
| 
       345 
     | 
    
         
            -
            You can use this to trigger an early success.
         
     | 
| 
       346 
     | 
    
         
            -
             
     | 
| 
       347 
387 
     | 
    
         
             
            ### Fail on argument error
         
     | 
| 
       348 
388 
     | 
    
         | 
| 
       349 
389 
     | 
    
         
             
            By default, errors on inputs will raise an error, even when using `.result`
         
     | 
| 
         @@ -354,6 +394,8 @@ catch the exception to treat it as an actor failure: 
     | 
|
| 
       354 
394 
     | 
    
         
             
            class PlaceOrder < Actor
         
     | 
| 
       355 
395 
     | 
    
         
             
              fail_on ServiceActor::ArgumentError
         
     | 
| 
       356 
396 
     | 
    
         | 
| 
      
 397 
     | 
    
         
            +
              input :currency, in: ["EUR", "USD"]
         
     | 
| 
      
 398 
     | 
    
         
            +
             
     | 
| 
       357 
399 
     | 
    
         
             
              # …
         
     | 
| 
       358 
400 
     | 
    
         
             
            end
         
     | 
| 
       359 
401 
     | 
    
         
             
            ```
         
     | 
| 
         @@ -368,11 +410,11 @@ make it easier for you to test your application. 
     | 
|
| 
       368 
410 
     | 
    
         | 
| 
       369 
411 
     | 
    
         
             
            ## Build your own actor
         
     | 
| 
       370 
412 
     | 
    
         | 
| 
       371 
     | 
    
         
            -
            If you application already uses  
     | 
| 
       372 
     | 
    
         
            -
            changing the gem 
     | 
| 
      
 413 
     | 
    
         
            +
            If you application already uses a class called “Actor”, you can build your own
         
     | 
| 
      
 414 
     | 
    
         
            +
            by changing the gem’s require statement:
         
     | 
| 
       373 
415 
     | 
    
         | 
| 
       374 
416 
     | 
    
         
             
            ```rb
         
     | 
| 
       375 
     | 
    
         
            -
            gem  
     | 
| 
      
 417 
     | 
    
         
            +
            gem "service_actor", require: "service_actor/base"
         
     | 
| 
       376 
418 
     | 
    
         
             
            ```
         
     | 
| 
       377 
419 
     | 
    
         | 
| 
       378 
420 
     | 
    
         
             
            And building your own class to inherit from:
         
     | 
| 
         @@ -387,11 +429,11 @@ end 
     | 
|
| 
       387 
429 
     | 
    
         | 
| 
       388 
430 
     | 
    
         
             
            This gem is heavily influenced by
         
     | 
| 
       389 
431 
     | 
    
         
             
            [Interactor](https://github.com/collectiveidea/interactor) ♥.
         
     | 
| 
       390 
     | 
    
         
            -
            Some key differences make  
     | 
| 
      
 432 
     | 
    
         
            +
            Some key differences make Actor unique:
         
     | 
| 
       391 
433 
     | 
    
         | 
| 
       392 
434 
     | 
    
         
             
            - Does not [hide errors when an actor fails inside another
         
     | 
| 
       393 
435 
     | 
    
         
             
              actor](https://github.com/collectiveidea/interactor/issues/170).
         
     | 
| 
       394 
     | 
    
         
            -
            - Requires you to document  
     | 
| 
      
 436 
     | 
    
         
            +
            - Requires you to document arguments with `input` and `output`.
         
     | 
| 
       395 
437 
     | 
    
         
             
            - Defaults to raising errors on failures: actor uses `call` and `result`
         
     | 
| 
       396 
438 
     | 
    
         
             
              instead of `call!` and `call`. This way, the _default_ is to raise an error
         
     | 
| 
       397 
439 
     | 
    
         
             
              and failures are not hidden away because you forgot to use `!`.
         
     | 
| 
         @@ -400,7 +442,8 @@ Some key differences make `actor` unique: 
     | 
|
| 
       400 
442 
     | 
    
         
             
              `context.foo = `, `fail!` vs `context.fail!`.
         
     | 
| 
       401 
443 
     | 
    
         
             
            - Shorter setup syntax: inherit from `< Actor` vs having to `include Interactor`
         
     | 
| 
       402 
444 
     | 
    
         
             
              and `include Interactor::Organizer`.
         
     | 
| 
       403 
     | 
    
         
            -
            - Organizers allow lambdas, being called multiple times, 
     | 
| 
      
 445 
     | 
    
         
            +
            - Organizers allow lambdas, instance methods, being called multiple times,
         
     | 
| 
      
 446 
     | 
    
         
            +
              and having conditions.
         
     | 
| 
       404 
447 
     | 
    
         
             
            - Allows early success with conditions inside organizers.
         
     | 
| 
       405 
448 
     | 
    
         
             
            - No `before`, `after` and `around` hooks, prefer using `play` with lambdas or
         
     | 
| 
       406 
449 
     | 
    
         
             
              overriding `call`.
         
     | 
| 
         @@ -413,33 +456,17 @@ migration. 
     | 
|
| 
       413 
456 
     | 
    
         
             
            Thank you to @nicoolas25, @AnneSottise & @williampollet for the early thoughts
         
     | 
| 
       414 
457 
     | 
    
         
             
            and feedback on this gem.
         
     | 
| 
       415 
458 
     | 
    
         | 
| 
       416 
     | 
    
         
            -
             
     | 
| 
       417 
     | 
    
         
            -
             
     | 
| 
       418 
     | 
    
         
            -
            ## Development
         
     | 
| 
      
 459 
     | 
    
         
            +
            Thank you to the wonderful
         
     | 
| 
      
 460 
     | 
    
         
            +
            [contributors](https://github.com/sunny/actor/graphs/contributors).
         
     | 
| 
       419 
461 
     | 
    
         | 
| 
       420 
     | 
    
         
            -
             
     | 
| 
       421 
     | 
    
         
            -
            `bin/rake` to run the tests and linting. You can also run `bin/console` for an
         
     | 
| 
       422 
     | 
    
         
            -
            interactive prompt.
         
     | 
| 
       423 
     | 
    
         
            -
             
     | 
| 
       424 
     | 
    
         
            -
            To release a new version, update the version number in `version.rb`, and in the
         
     | 
| 
       425 
     | 
    
         
            -
            `CHANGELOG.md`. Update the `README.md` if there are missing segments, make sure
         
     | 
| 
       426 
     | 
    
         
            -
            tests and linting are pristine by calling `bundle && bin/rake`, then create a
         
     | 
| 
       427 
     | 
    
         
            -
            commit for this version.
         
     | 
| 
       428 
     | 
    
         
            -
             
     | 
| 
       429 
     | 
    
         
            -
            You can then run `rake release`, which will assign a git tag, push using git,
         
     | 
| 
       430 
     | 
    
         
            -
            and push the gem to [rubygems.org](https://rubygems.org).
         
     | 
| 
      
 462 
     | 
    
         
            +
            Photo by [Lloyd Dirks](https://unsplash.com/photos/4SLz_RCk6kQ).
         
     | 
| 
       431 
463 
     | 
    
         | 
| 
       432 
464 
     | 
    
         
             
            ## Contributing
         
     | 
| 
       433 
465 
     | 
    
         | 
| 
       434 
     | 
    
         
            -
             
     | 
| 
       435 
     | 
    
         
            -
            [ 
     | 
| 
       436 
     | 
    
         
            -
             
     | 
| 
       437 
     | 
    
         
            -
            This project is intended to be a safe, welcoming space for collaboration, and
         
     | 
| 
       438 
     | 
    
         
            -
            everyone interacting in the project’s codebase and issue tracker is expected to
         
     | 
| 
       439 
     | 
    
         
            -
            adhere to the [Contributor Covenant code of
         
     | 
| 
       440 
     | 
    
         
            -
            conduct](https://github.com/sunny/actor/blob/main/CODE_OF_CONDUCT.md).
         
     | 
| 
      
 466 
     | 
    
         
            +
            See
         
     | 
| 
      
 467 
     | 
    
         
            +
            [CONTRIBUTING.md](https://github.com/sunny/actor/blob/main/CONTRIBUTING.md).
         
     | 
| 
       441 
468 
     | 
    
         | 
| 
       442 
469 
     | 
    
         
             
            ## License
         
     | 
| 
       443 
470 
     | 
    
         | 
| 
       444 
471 
     | 
    
         
             
            The gem is available as open source under the terms of the
         
     | 
| 
       445 
     | 
    
         
            -
            [MIT License](https:// 
     | 
| 
      
 472 
     | 
    
         
            +
            [MIT License](https://choosealicense.com/licenses/mit/).
         
     | 
    
        data/lib/service_actor/base.rb
    CHANGED
    
    | 
         @@ -1,23 +1,23 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # frozen_string_literal: true
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            # Exceptions
         
     | 
| 
       4 
     | 
    
         
            -
            require  
     | 
| 
       5 
     | 
    
         
            -
            require  
     | 
| 
       6 
     | 
    
         
            -
            require  
     | 
| 
      
 4 
     | 
    
         
            +
            require "service_actor/error"
         
     | 
| 
      
 5 
     | 
    
         
            +
            require "service_actor/failure"
         
     | 
| 
      
 6 
     | 
    
         
            +
            require "service_actor/argument_error"
         
     | 
| 
       7 
7 
     | 
    
         | 
| 
       8 
8 
     | 
    
         
             
            # Core
         
     | 
| 
       9 
     | 
    
         
            -
            require  
     | 
| 
       10 
     | 
    
         
            -
            require  
     | 
| 
       11 
     | 
    
         
            -
            require  
     | 
| 
       12 
     | 
    
         
            -
            require  
     | 
| 
      
 9 
     | 
    
         
            +
            require "service_actor/core"
         
     | 
| 
      
 10 
     | 
    
         
            +
            require "service_actor/attributable"
         
     | 
| 
      
 11 
     | 
    
         
            +
            require "service_actor/playable"
         
     | 
| 
      
 12 
     | 
    
         
            +
            require "service_actor/result"
         
     | 
| 
       13 
13 
     | 
    
         | 
| 
       14 
14 
     | 
    
         
             
            # Concerns
         
     | 
| 
       15 
     | 
    
         
            -
            require  
     | 
| 
       16 
     | 
    
         
            -
            require  
     | 
| 
       17 
     | 
    
         
            -
            require  
     | 
| 
       18 
     | 
    
         
            -
            require  
     | 
| 
       19 
     | 
    
         
            -
            require  
     | 
| 
       20 
     | 
    
         
            -
            require  
     | 
| 
      
 15 
     | 
    
         
            +
            require "service_actor/type_checkable"
         
     | 
| 
      
 16 
     | 
    
         
            +
            require "service_actor/nil_checkable"
         
     | 
| 
      
 17 
     | 
    
         
            +
            require "service_actor/conditionable"
         
     | 
| 
      
 18 
     | 
    
         
            +
            require "service_actor/defaultable"
         
     | 
| 
      
 19 
     | 
    
         
            +
            require "service_actor/collectionable"
         
     | 
| 
      
 20 
     | 
    
         
            +
            require "service_actor/failable"
         
     | 
| 
       21 
21 
     | 
    
         | 
| 
       22 
22 
     | 
    
         
             
            module ServiceActor
         
     | 
| 
       23 
23 
     | 
    
         
             
              module Base
         
     | 
    
        data/lib/service_actor/core.rb
    CHANGED
    
    | 
         @@ -9,9 +9,9 @@ module ServiceActor 
     | 
|
| 
       9 
9 
     | 
    
         
             
                module ClassMethods
         
     | 
| 
       10 
10 
     | 
    
         
             
                  # Call an actor with a given result. Returns the result.
         
     | 
| 
       11 
11 
     | 
    
         
             
                  #
         
     | 
| 
       12 
     | 
    
         
            -
                  #   CreateUser.call(name:  
     | 
| 
       13 
     | 
    
         
            -
                  def call( 
     | 
| 
       14 
     | 
    
         
            -
                    result = Result.to_result( 
     | 
| 
      
 12 
     | 
    
         
            +
                  #   CreateUser.call(name: "Joe")
         
     | 
| 
      
 13 
     | 
    
         
            +
                  def call(result = nil, **arguments)
         
     | 
| 
      
 14 
     | 
    
         
            +
                    result = Result.to_result(result).merge!(arguments)
         
     | 
| 
       15 
15 
     | 
    
         
             
                    new(result)._call
         
     | 
| 
       16 
16 
     | 
    
         
             
                    result
         
     | 
| 
       17 
17 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -19,9 +19,9 @@ module ServiceActor 
     | 
|
| 
       19 
19 
     | 
    
         
             
                  # Call an actor with arguments. Returns the result and does not raise on
         
     | 
| 
       20 
20 
     | 
    
         
             
                  # failure.
         
     | 
| 
       21 
21 
     | 
    
         
             
                  #
         
     | 
| 
       22 
     | 
    
         
            -
                  #   CreateUser.result(name:  
     | 
| 
       23 
     | 
    
         
            -
                  def result( 
     | 
| 
       24 
     | 
    
         
            -
                    call( 
     | 
| 
      
 22 
     | 
    
         
            +
                  #   CreateUser.result(name: "Joe")
         
     | 
| 
      
 23 
     | 
    
         
            +
                  def result(result = nil, **arguments)
         
     | 
| 
      
 24 
     | 
    
         
            +
                    call(result, **arguments)
         
     | 
| 
       25 
25 
     | 
    
         
             
                  rescue Failure => e
         
     | 
| 
       26 
26 
     | 
    
         
             
                    e.result
         
     | 
| 
       27 
27 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -38,12 +38,15 @@ module ServiceActor 
     | 
|
| 
       38 
38 
     | 
    
         
             
                # To implement in your actors.
         
     | 
| 
       39 
39 
     | 
    
         
             
                def rollback; end
         
     | 
| 
       40 
40 
     | 
    
         | 
| 
      
 41 
     | 
    
         
            +
                # This method is used internally to override behavior on call. Overriding
         
     | 
| 
      
 42 
     | 
    
         
            +
                # `call` instead would mean that end-users have to call `super` in their
         
     | 
| 
      
 43 
     | 
    
         
            +
                # actors.
         
     | 
| 
       41 
44 
     | 
    
         
             
                # :nodoc:
         
     | 
| 
       42 
45 
     | 
    
         
             
                def _call
         
     | 
| 
       43 
46 
     | 
    
         
             
                  call
         
     | 
| 
       44 
47 
     | 
    
         
             
                end
         
     | 
| 
       45 
48 
     | 
    
         | 
| 
       46 
     | 
    
         
            -
                 
     | 
| 
      
 49 
     | 
    
         
            +
                protected
         
     | 
| 
       47 
50 
     | 
    
         | 
| 
       48 
51 
     | 
    
         
             
                # Returns the current context from inside an actor.
         
     | 
| 
       49 
52 
     | 
    
         
             
                attr_reader :result
         
     | 
    
        data/lib/service_actor/error.rb
    CHANGED
    
    
| 
         @@ -16,11 +16,11 @@ module ServiceActor 
     | 
|
| 
       16 
16 
     | 
    
         | 
| 
       17 
17 
     | 
    
         
             
                module PrependedMethods
         
     | 
| 
       18 
18 
     | 
    
         
             
                  def _call
         
     | 
| 
       19 
     | 
    
         
            -
                    check_context_for_nil(self.class.inputs, origin:  
     | 
| 
      
 19 
     | 
    
         
            +
                    check_context_for_nil(self.class.inputs, origin: "input")
         
     | 
| 
       20 
20 
     | 
    
         | 
| 
       21 
21 
     | 
    
         
             
                    super
         
     | 
| 
       22 
22 
     | 
    
         | 
| 
       23 
     | 
    
         
            -
                    check_context_for_nil(self.class.outputs, origin:  
     | 
| 
      
 23 
     | 
    
         
            +
                    check_context_for_nil(self.class.outputs, origin: "output")
         
     | 
| 
       24 
24 
     | 
    
         
             
                  end
         
     | 
| 
       25 
25 
     | 
    
         | 
| 
       26 
26 
     | 
    
         
             
                  private
         
     | 
| 
         @@ -31,20 +31,15 @@ module ServiceActor 
     | 
|
| 
       31 
31 
     | 
    
         | 
| 
       32 
32 
     | 
    
         
             
                      raise ArgumentError,
         
     | 
| 
       33 
33 
     | 
    
         
             
                            "The #{origin} \"#{name}\" on #{self.class} does not allow " \
         
     | 
| 
       34 
     | 
    
         
            -
                             
     | 
| 
      
 34 
     | 
    
         
            +
                            "nil values"
         
     | 
| 
       35 
35 
     | 
    
         
             
                    end
         
     | 
| 
       36 
36 
     | 
    
         
             
                  end
         
     | 
| 
       37 
37 
     | 
    
         | 
| 
       38 
38 
     | 
    
         
             
                  def allow_nil?(options)
         
     | 
| 
       39 
     | 
    
         
            -
                    if options.key?(:allow_nil)
         
     | 
| 
       40 
     | 
    
         
            -
             
     | 
| 
       41 
     | 
    
         
            -
             
     | 
| 
       42 
     | 
    
         
            -
             
     | 
| 
       43 
     | 
    
         
            -
                    elsif options[:type]
         
     | 
| 
       44 
     | 
    
         
            -
                      false
         
     | 
| 
       45 
     | 
    
         
            -
                    else
         
     | 
| 
       46 
     | 
    
         
            -
                      true
         
     | 
| 
       47 
     | 
    
         
            -
                    end
         
     | 
| 
      
 39 
     | 
    
         
            +
                    return options[:allow_nil] if options.key?(:allow_nil)
         
     | 
| 
      
 40 
     | 
    
         
            +
                    return true if options.key?(:default) && options[:default].nil?
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
                    !options[:type]
         
     | 
| 
       48 
43 
     | 
    
         
             
                  end
         
     | 
| 
       49 
44 
     | 
    
         
             
                end
         
     | 
| 
       50 
45 
     | 
    
         
             
              end
         
     | 
| 
         @@ -2,7 +2,7 @@ 
     | 
|
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            module ServiceActor
         
     | 
| 
       4 
4 
     | 
    
         
             
              # Play class method to call a series of actors with the same result. On
         
     | 
| 
       5 
     | 
    
         
            -
              # failure, calls rollback on  
     | 
| 
      
 5 
     | 
    
         
            +
              # failure, calls rollback on actors that succeeded.
         
     | 
| 
       6 
6 
     | 
    
         
             
              #
         
     | 
| 
       7 
7 
     | 
    
         
             
              #   class CreateUser < Actor
         
     | 
| 
       8 
8 
     | 
    
         
             
              #     play SaveUser,
         
     | 
| 
         @@ -16,23 +16,19 @@ module ServiceActor 
     | 
|
| 
       16 
16 
     | 
    
         
             
                end
         
     | 
| 
       17 
17 
     | 
    
         | 
| 
       18 
18 
     | 
    
         
             
                module ClassMethods
         
     | 
| 
       19 
     | 
    
         
            -
                  def inherited(child)
         
     | 
| 
       20 
     | 
    
         
            -
                    super
         
     | 
| 
       21 
     | 
    
         
            -
             
     | 
| 
       22 
     | 
    
         
            -
                    play_actors.each do |actor|
         
     | 
| 
       23 
     | 
    
         
            -
                      child.play_actors << actor
         
     | 
| 
       24 
     | 
    
         
            -
                    end
         
     | 
| 
       25 
     | 
    
         
            -
                  end
         
     | 
| 
       26 
     | 
    
         
            -
             
     | 
| 
       27 
19 
     | 
    
         
             
                  def play(*actors, **options)
         
     | 
| 
       28 
     | 
    
         
            -
                    actors 
     | 
| 
       29 
     | 
    
         
            -
                      play_actors.push({ actor: actor, **options })
         
     | 
| 
       30 
     | 
    
         
            -
                    end
         
     | 
| 
      
 20 
     | 
    
         
            +
                    play_actors.push(actors: actors, **options)
         
     | 
| 
       31 
21 
     | 
    
         
             
                  end
         
     | 
| 
       32 
22 
     | 
    
         | 
| 
       33 
23 
     | 
    
         
             
                  def play_actors
         
     | 
| 
       34 
24 
     | 
    
         
             
                    @play_actors ||= []
         
     | 
| 
       35 
25 
     | 
    
         
             
                  end
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                  def inherited(child)
         
     | 
| 
      
 28 
     | 
    
         
            +
                    super
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                    child.play_actors.concat(play_actors)
         
     | 
| 
      
 31 
     | 
    
         
            +
                  end
         
     | 
| 
       36 
32 
     | 
    
         
             
                end
         
     | 
| 
       37 
33 
     | 
    
         | 
| 
       38 
34 
     | 
    
         
             
                module PrependedMethods
         
     | 
| 
         @@ -40,7 +36,7 @@ module ServiceActor 
     | 
|
| 
       40 
36 
     | 
    
         
             
                    self.class.play_actors.each do |options|
         
     | 
| 
       41 
37 
     | 
    
         
             
                      next if options[:if] && !options[:if].call(result)
         
     | 
| 
       42 
38 
     | 
    
         | 
| 
       43 
     | 
    
         
            -
                       
     | 
| 
      
 39 
     | 
    
         
            +
                      options[:actors].each { |actor| play_actor(actor) }
         
     | 
| 
       44 
40 
     | 
    
         
             
                    end
         
     | 
| 
       45 
41 
     | 
    
         
             
                  rescue Failure
         
     | 
| 
       46 
42 
     | 
    
         
             
                    rollback
         
     | 
| 
         @@ -48,9 +44,9 @@ module ServiceActor 
     | 
|
| 
       48 
44 
     | 
    
         
             
                  end
         
     | 
| 
       49 
45 
     | 
    
         | 
| 
       50 
46 
     | 
    
         
             
                  def rollback
         
     | 
| 
       51 
     | 
    
         
            -
                    return unless @ 
     | 
| 
      
 47 
     | 
    
         
            +
                    return unless defined?(@played_actors)
         
     | 
| 
       52 
48 
     | 
    
         | 
| 
       53 
     | 
    
         
            -
                    @ 
     | 
| 
      
 49 
     | 
    
         
            +
                    @played_actors.each do |actor|
         
     | 
| 
       54 
50 
     | 
    
         
             
                      next unless actor.respond_to?(:rollback)
         
     | 
| 
       55 
51 
     | 
    
         | 
| 
       56 
52 
     | 
    
         
             
                      actor.rollback
         
     | 
| 
         @@ -60,15 +56,35 @@ module ServiceActor 
     | 
|
| 
       60 
56 
     | 
    
         
             
                  private
         
     | 
| 
       61 
57 
     | 
    
         | 
| 
       62 
58 
     | 
    
         
             
                  def play_actor(actor)
         
     | 
| 
       63 
     | 
    
         
            -
                     
     | 
| 
       64 
     | 
    
         
            -
                      actor  
     | 
| 
       65 
     | 
    
         
            -
                      actor 
     | 
| 
       66 
     | 
    
         
            -
             
     | 
| 
       67 
     | 
    
         
            -
             
     | 
| 
       68 
     | 
    
         
            -
             
     | 
| 
       69 
     | 
    
         
            -
             
     | 
| 
      
 59 
     | 
    
         
            +
                    play_service_actor(actor) ||
         
     | 
| 
      
 60 
     | 
    
         
            +
                      play_method(actor) ||
         
     | 
| 
      
 61 
     | 
    
         
            +
                      play_interactor(actor) ||
         
     | 
| 
      
 62 
     | 
    
         
            +
                      actor.call(result)
         
     | 
| 
      
 63 
     | 
    
         
            +
                  end
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
                  def play_service_actor(actor)
         
     | 
| 
      
 66 
     | 
    
         
            +
                    return unless actor.is_a?(Class)
         
     | 
| 
      
 67 
     | 
    
         
            +
                    return unless actor.ancestors.include?(ServiceActor::Core)
         
     | 
| 
      
 68 
     | 
    
         
            +
             
     | 
| 
      
 69 
     | 
    
         
            +
                    actor = actor.new(result)
         
     | 
| 
      
 70 
     | 
    
         
            +
                    actor._call
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
                    (@played_actors ||= []).unshift(actor)
         
     | 
| 
      
 73 
     | 
    
         
            +
                  end
         
     | 
| 
      
 74 
     | 
    
         
            +
             
     | 
| 
      
 75 
     | 
    
         
            +
                  def play_method(actor)
         
     | 
| 
      
 76 
     | 
    
         
            +
                    return unless actor.is_a?(Symbol)
         
     | 
| 
      
 77 
     | 
    
         
            +
             
     | 
| 
      
 78 
     | 
    
         
            +
                    send(actor)
         
     | 
| 
      
 79 
     | 
    
         
            +
             
     | 
| 
      
 80 
     | 
    
         
            +
                    true
         
     | 
| 
      
 81 
     | 
    
         
            +
                  end
         
     | 
| 
      
 82 
     | 
    
         
            +
             
     | 
| 
      
 83 
     | 
    
         
            +
                  def play_interactor(actor)
         
     | 
| 
      
 84 
     | 
    
         
            +
                    return unless actor.is_a?(Class)
         
     | 
| 
      
 85 
     | 
    
         
            +
                    return unless actor.ancestors.map(&:name).include?("Interactor")
         
     | 
| 
       70 
86 
     | 
    
         | 
| 
       71 
     | 
    
         
            -
                    ( 
     | 
| 
      
 87 
     | 
    
         
            +
                    result.merge!(actor.call(result).to_h)
         
     | 
| 
       72 
88 
     | 
    
         
             
                  end
         
     | 
| 
       73 
89 
     | 
    
         
             
                end
         
     | 
| 
       74 
90 
     | 
    
         
             
              end
         
     | 
    
        data/lib/service_actor/result.rb
    CHANGED
    
    | 
         @@ -1,6 +1,6 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # frozen_string_literal: true
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
     | 
    
         
            -
            require  
     | 
| 
      
 3 
     | 
    
         
            +
            require "ostruct"
         
     | 
| 
       4 
4 
     | 
    
         | 
| 
       5 
5 
     | 
    
         
             
            module ServiceActor
         
     | 
| 
       6 
6 
     | 
    
         
             
              # Represents the context of an actor, holding the data from both its inputs
         
     | 
| 
         @@ -47,9 +47,32 @@ module ServiceActor 
     | 
|
| 
       47 
47 
     | 
    
         
             
                  to_h[name]
         
     | 
| 
       48 
48 
     | 
    
         
             
                end
         
     | 
| 
       49 
49 
     | 
    
         | 
| 
       50 
     | 
    
         
            -
                #  
     | 
| 
      
 50 
     | 
    
         
            +
                # Defined here to override the method on `Object`.
         
     | 
| 
       51 
51 
     | 
    
         
             
                def display
         
     | 
| 
       52 
52 
     | 
    
         
             
                  to_h.fetch(:display)
         
     | 
| 
       53 
53 
     | 
    
         
             
                end
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
                private
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                def respond_to_missing?(method_name, include_private = false)
         
     | 
| 
      
 58 
     | 
    
         
            +
                  method_name.to_s.end_with?("?") || super
         
     | 
| 
      
 59 
     | 
    
         
            +
                end
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
                def method_missing(symbol, *args)
         
     | 
| 
      
 62 
     | 
    
         
            +
                  attribute = symbol.to_s.chomp("?")
         
     | 
| 
      
 63 
     | 
    
         
            +
             
     | 
| 
      
 64 
     | 
    
         
            +
                  if symbol.to_s.end_with?("?") && respond_to?(attribute)
         
     | 
| 
      
 65 
     | 
    
         
            +
                    define_singleton_method symbol do
         
     | 
| 
      
 66 
     | 
    
         
            +
                      attribute_value = send(attribute.to_sym)
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
                      # Same as ActiveSupport’s #present?
         
     | 
| 
      
 69 
     | 
    
         
            +
                      attribute_value.respond_to?(:empty?) ? !attribute_value.empty? : !!attribute_value
         
     | 
| 
      
 70 
     | 
    
         
            +
                    end
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
                    return send(symbol)
         
     | 
| 
      
 73 
     | 
    
         
            +
                  end
         
     | 
| 
      
 74 
     | 
    
         
            +
             
     | 
| 
      
 75 
     | 
    
         
            +
                  super symbol, *args
         
     | 
| 
      
 76 
     | 
    
         
            +
                end
         
     | 
| 
       54 
77 
     | 
    
         
             
              end
         
     | 
| 
       55 
78 
     | 
    
         
             
            end
         
     | 
| 
         @@ -7,7 +7,7 @@ module ServiceActor 
     | 
|
| 
       7 
7 
     | 
    
         
             
              # Example:
         
     | 
| 
       8 
8 
     | 
    
         
             
              #
         
     | 
| 
       9 
9 
     | 
    
         
             
              #   class ReduceOrderAmount < Actor
         
     | 
| 
       10 
     | 
    
         
            -
              #     input :order, type:  
     | 
| 
      
 10 
     | 
    
         
            +
              #     input :order, type: "Order"
         
     | 
| 
       11 
11 
     | 
    
         
             
              #     input :amount, type: [Integer, Float]
         
     | 
| 
       12 
12 
     | 
    
         
             
              #     input :bonus_applied, type: [TrueClass FalseClass]
         
     | 
| 
       13 
13 
     | 
    
         
             
              #   end
         
     | 
| 
         @@ -18,11 +18,11 @@ module ServiceActor 
     | 
|
| 
       18 
18 
     | 
    
         | 
| 
       19 
19 
     | 
    
         
             
                module PrependedMethods
         
     | 
| 
       20 
20 
     | 
    
         
             
                  def _call
         
     | 
| 
       21 
     | 
    
         
            -
                    check_type_definitions(self.class.inputs, kind:  
     | 
| 
      
 21 
     | 
    
         
            +
                    check_type_definitions(self.class.inputs, kind: "Input")
         
     | 
| 
       22 
22 
     | 
    
         | 
| 
       23 
23 
     | 
    
         
             
                    super
         
     | 
| 
       24 
24 
     | 
    
         | 
| 
       25 
     | 
    
         
            -
                    check_type_definitions(self.class.outputs, kind:  
     | 
| 
      
 25 
     | 
    
         
            +
                    check_type_definitions(self.class.outputs, kind: "Output")
         
     | 
| 
       26 
26 
     | 
    
         
             
                  end
         
     | 
| 
       27 
27 
     | 
    
         | 
| 
       28 
28 
     | 
    
         
             
                  private
         
     | 
    
        data/lib/service_actor.rb
    CHANGED
    
    
    
        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: 3. 
     | 
| 
      
 4 
     | 
    
         
            +
              version: 3.3.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:  
     | 
| 
      
 11 
     | 
    
         
            +
            date: 2022-07-18 00:00:00.000000000 Z
         
     | 
| 
       12 
12 
     | 
    
         
             
            dependencies:
         
     | 
| 
       13 
13 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       14 
14 
     | 
    
         
             
              name: rspec
         
     | 
| 
         @@ -53,19 +53,25 @@ dependencies: 
     | 
|
| 
       53 
53 
     | 
    
         
             
                  - !ruby/object:Gem::Version
         
     | 
| 
       54 
54 
     | 
    
         
             
                    version: '0'
         
     | 
| 
       55 
55 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       56 
     | 
    
         
            -
              name: rubocop
         
     | 
| 
      
 56 
     | 
    
         
            +
              name: rubocop-lts
         
     | 
| 
       57 
57 
     | 
    
         
             
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
       58 
58 
     | 
    
         
             
                requirements:
         
     | 
| 
      
 59 
     | 
    
         
            +
                - - "~>"
         
     | 
| 
      
 60 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 61 
     | 
    
         
            +
                    version: '12.0'
         
     | 
| 
       59 
62 
     | 
    
         
             
                - - ">="
         
     | 
| 
       60 
63 
     | 
    
         
             
                  - !ruby/object:Gem::Version
         
     | 
| 
       61 
     | 
    
         
            -
                    version:  
     | 
| 
      
 64 
     | 
    
         
            +
                    version: 12.0.1
         
     | 
| 
       62 
65 
     | 
    
         
             
              type: :development
         
     | 
| 
       63 
66 
     | 
    
         
             
              prerelease: false
         
     | 
| 
       64 
67 
     | 
    
         
             
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
       65 
68 
     | 
    
         
             
                requirements:
         
     | 
| 
      
 69 
     | 
    
         
            +
                - - "~>"
         
     | 
| 
      
 70 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 71 
     | 
    
         
            +
                    version: '12.0'
         
     | 
| 
       66 
72 
     | 
    
         
             
                - - ">="
         
     | 
| 
       67 
73 
     | 
    
         
             
                  - !ruby/object:Gem::Version
         
     | 
| 
       68 
     | 
    
         
            -
                    version:  
     | 
| 
      
 74 
     | 
    
         
            +
                    version: 12.0.1
         
     | 
| 
       69 
75 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       70 
76 
     | 
    
         
             
              name: rubocop-rspec
         
     | 
| 
       71 
77 
     | 
    
         
             
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
         @@ -156,6 +162,7 @@ metadata: 
     | 
|
| 
       156 
162 
     | 
    
         
             
              homepage_uri: https://github.com/sunny/actor
         
     | 
| 
       157 
163 
     | 
    
         
             
              source_code_uri: https://github.com/sunny/actor
         
     | 
| 
       158 
164 
     | 
    
         
             
              changelog_uri: https://github.com/sunny/actor/blob/main/CHANGELOG.md
         
     | 
| 
      
 165 
     | 
    
         
            +
              rubygems_mfa_required: 'true'
         
     | 
| 
       159 
166 
     | 
    
         
             
            post_install_message: 
         
     | 
| 
       160 
167 
     | 
    
         
             
            rdoc_options: []
         
     | 
| 
       161 
168 
     | 
    
         
             
            require_paths:
         
     | 
| 
         @@ -171,7 +178,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement 
     | 
|
| 
       171 
178 
     | 
    
         
             
                - !ruby/object:Gem::Version
         
     | 
| 
       172 
179 
     | 
    
         
             
                  version: '0'
         
     | 
| 
       173 
180 
     | 
    
         
             
            requirements: []
         
     | 
| 
       174 
     | 
    
         
            -
            rubygems_version: 3.1. 
     | 
| 
      
 181 
     | 
    
         
            +
            rubygems_version: 3.1.6
         
     | 
| 
       175 
182 
     | 
    
         
             
            signing_key: 
         
     | 
| 
       176 
183 
     | 
    
         
             
            specification_version: 4
         
     | 
| 
       177 
184 
     | 
    
         
             
            summary: Service objects for your application logic
         
     |