snfoil-context 0.0.2 → 0.0.4
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/.fasterer.yml +22 -0
 - data/.github/workflows/main.yml +6 -3
 - data/.rubocop.yml +1 -0
 - data/README.md +167 -84
 - data/lib/snfoil/context/structure.rb +19 -9
 - data/lib/snfoil/context/version.rb +1 -1
 - data/lib/snfoil/context.rb +42 -32
 - data/snfoil-context.gemspec +5 -3
 - metadata +34 -3
 
    
        checksums.yaml
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ---
         
     | 
| 
       2 
2 
     | 
    
         
             
            SHA256:
         
     | 
| 
       3 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       4 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: a9996ed485265b54e92858f7471b6ed2ccfc3970b6ab7bed338f0b3ab729d240
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: 2427755a9b61cf1fad8ddc48eaa6e5c1e7da651b6c6b8f760f6594e1a973c471
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: d8e89dc09f5d1a1ca531487b04e9392c5323330c232d9f3a72946c4130ead35425451a2bec1d7a522702c414cdd7cb08ea85447f60d89a72a948fda27f17d667
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: a1f773ecb81a5a4ee2ffce81b3bf350c49e18078ba465f35e4ed824b01587dd5a9d5fc4897131a1c4b93fe9675655c086d489c9d99e0c05615af139f4644d13f
         
     | 
    
        data/.fasterer.yml
    ADDED
    
    | 
         @@ -0,0 +1,22 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            speedups:
         
     | 
| 
      
 2 
     | 
    
         
            +
              rescue_vs_respond_to: true
         
     | 
| 
      
 3 
     | 
    
         
            +
              module_eval: true
         
     | 
| 
      
 4 
     | 
    
         
            +
              shuffle_first_vs_sample: true
         
     | 
| 
      
 5 
     | 
    
         
            +
              for_loop_vs_each: true
         
     | 
| 
      
 6 
     | 
    
         
            +
              each_with_index_vs_while: false
         
     | 
| 
      
 7 
     | 
    
         
            +
              map_flatten_vs_flat_map: true
         
     | 
| 
      
 8 
     | 
    
         
            +
              reverse_each_vs_reverse_each: true
         
     | 
| 
      
 9 
     | 
    
         
            +
              select_first_vs_detect: true
         
     | 
| 
      
 10 
     | 
    
         
            +
              sort_vs_sort_by: true
         
     | 
| 
      
 11 
     | 
    
         
            +
              fetch_with_argument_vs_block: true
         
     | 
| 
      
 12 
     | 
    
         
            +
              keys_each_vs_each_key: true
         
     | 
| 
      
 13 
     | 
    
         
            +
              hash_merge_bang_vs_hash_brackets: true
         
     | 
| 
      
 14 
     | 
    
         
            +
              block_vs_symbol_to_proc: true
         
     | 
| 
      
 15 
     | 
    
         
            +
              proc_call_vs_yield: true
         
     | 
| 
      
 16 
     | 
    
         
            +
              gsub_vs_tr: true
         
     | 
| 
      
 17 
     | 
    
         
            +
              select_last_vs_reverse_detect: true
         
     | 
| 
      
 18 
     | 
    
         
            +
              getter_vs_attr_reader: true
         
     | 
| 
      
 19 
     | 
    
         
            +
              setter_vs_attr_writer: true
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
            exclude_paths:
         
     | 
| 
      
 22 
     | 
    
         
            +
              - 'vendor/**/*.rb'
         
     | 
    
        data/.github/workflows/main.yml
    CHANGED
    
    | 
         @@ -1,5 +1,5 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            name: build
         
     | 
| 
       2 
     | 
    
         
            -
            on: 
     | 
| 
      
 2 
     | 
    
         
            +
            on:
         
     | 
| 
       3 
3 
     | 
    
         
             
              push:
         
     | 
| 
       4 
4 
     | 
    
         
             
                branches: [ main ]
         
     | 
| 
       5 
5 
     | 
    
         
             
              pull_request:
         
     | 
| 
         @@ -11,7 +11,7 @@ jobs: 
     | 
|
| 
       11 
11 
     | 
    
         | 
| 
       12 
12 
     | 
    
         
             
                strategy:
         
     | 
| 
       13 
13 
     | 
    
         
             
                  matrix:
         
     | 
| 
       14 
     | 
    
         
            -
                    ruby-version: [2.7, 2.6, 2.5]
         
     | 
| 
      
 14 
     | 
    
         
            +
                    ruby-version: [2.7, 2.6, 2.5, '3.0']
         
     | 
| 
       15 
15 
     | 
    
         | 
| 
       16 
16 
     | 
    
         
             
                steps:
         
     | 
| 
       17 
17 
     | 
    
         
             
                  - uses: actions/checkout@v2
         
     | 
| 
         @@ -43,4 +43,7 @@ jobs: 
     | 
|
| 
       43 
43 
     | 
    
         
             
                    run: bundle install
         
     | 
| 
       44 
44 
     | 
    
         
             
                  - name: Run rubocop
         
     | 
| 
       45 
45 
     | 
    
         
             
                    run: bundle exec rubocop
         
     | 
| 
       46 
     | 
    
         
            -
             
     | 
| 
      
 46 
     | 
    
         
            +
                  - name: Run fasterer
         
     | 
| 
      
 47 
     | 
    
         
            +
                    run: bundle exec fasterer
         
     | 
| 
      
 48 
     | 
    
         
            +
                  - name: Run bundle audit
         
     | 
| 
      
 49 
     | 
    
         
            +
                    run: bundle exec bundle audit check --update
         
     | 
    
        data/.rubocop.yml
    CHANGED
    
    
    
        data/README.md
    CHANGED
    
    | 
         @@ -2,7 +2,7 @@ 
     | 
|
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
             [](https://codeclimate.com/github/limited-effort/snfoil-context/maintainability)
         
     | 
| 
       4 
4 
     | 
    
         | 
| 
       5 
     | 
    
         
            -
            SnFoil Contexts are a simple way to  
     | 
| 
      
 5 
     | 
    
         
            +
            SnFoil Contexts are a simple way to ensure a workflow pipeline can be easily established end extended.  It helps by creating a workflow, allowing additional steps at specific intervals, and reacting to success or failure, you should find your code being more maintainable and testable.
         
     | 
| 
       6 
6 
     | 
    
         | 
| 
       7 
7 
     | 
    
         
             
            ## Installation
         
     | 
| 
       8 
8 
     | 
    
         | 
| 
         @@ -15,7 +15,47 @@ gem 'snfoil-context' 
     | 
|
| 
       15 
15 
     | 
    
         
             
            ## Usage
         
     | 
| 
       16 
16 
     | 
    
         
             
            While contexts are powerful, they aren't a magic bullet.  Each function should strive to only contain a single purpose.  This also has the added benefit of outlining some basic tests - if it is in a function it should have a related test.
         
     | 
| 
       17 
17 
     | 
    
         | 
| 
       18 
     | 
    
         
            -
             
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
            ### Quickstart Example
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 22 
     | 
    
         
            +
            require 'snfoil/context'
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
            class TokenContext
         
     | 
| 
      
 25 
     | 
    
         
            +
              include SnFoil::Context
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
              action(:create) { |options| options[:object].save }
         
     | 
| 
      
 28 
     | 
    
         
            +
              action(:expire) { |options| options[:object].update(expired_at: Time.current) }
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
              # inject created_by
         
     | 
| 
      
 31 
     | 
    
         
            +
              setup_create { |options| options[:params][:created_by] = entity }
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
              # initialize token
         
     | 
| 
      
 34 
     | 
    
         
            +
              before_create do |options|
         
     | 
| 
      
 35 
     | 
    
         
            +
                options[:object] = Token.create(options[:params])
         
     | 
| 
      
 36 
     | 
    
         
            +
                options
         
     | 
| 
      
 37 
     | 
    
         
            +
              end
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
              # send token email
         
     | 
| 
      
 40 
     | 
    
         
            +
              after_create_success { |options| TokenMailer.new(token: option[:object]) }
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
              # log expiration error
         
     | 
| 
      
 43 
     | 
    
         
            +
              after_expire_failure { |options| ErrorLogger.notify(error: options[:object].errors) }
         
     | 
| 
      
 44 
     | 
    
         
            +
            end
         
     | 
| 
      
 45 
     | 
    
         
            +
            ```
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
            ### Initialize
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
            When you `new` up a SnFoil Context you should provide the entity running the actions.  This will usually be a user but you can pass in anything.  This will be accessible from within the context as `entity`.
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 53 
     | 
    
         
            +
              TokenContext.new(current_user)
         
     | 
| 
      
 54 
     | 
    
         
            +
            ```
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
            ### Actions
         
     | 
| 
      
 57 
     | 
    
         
            +
            Actions are a group of hookable intervals that create a workflow around a single primary function.
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
       19 
59 
     | 
    
         
             
            To start you will need to define an action.  
         
     | 
| 
       20 
60 
     | 
    
         | 
| 
       21 
61 
     | 
    
         
             
            Arguments:
         
     | 
| 
         @@ -30,18 +70,32 @@ require 'snfoil/context' 
     | 
|
| 
       30 
70 
     | 
    
         
             
            class TokenContext
         
     | 
| 
       31 
71 
     | 
    
         
             
              include SnFoil::Context
         
     | 
| 
       32 
72 
     | 
    
         | 
| 
       33 
     | 
    
         
            -
               
     | 
| 
      
 73 
     | 
    
         
            +
              ...
         
     | 
| 
      
 74 
     | 
    
         
            +
             
     | 
| 
      
 75 
     | 
    
         
            +
              action(:expire) { |options| options[:object].update(expired_at: Time.current) }
         
     | 
| 
       34 
76 
     | 
    
         
             
            end
         
     | 
| 
       35 
77 
     | 
    
         
             
            ```
         
     | 
| 
       36 
78 
     | 
    
         | 
| 
       37 
     | 
    
         
            -
            This will generate the  
     | 
| 
      
 79 
     | 
    
         
            +
            This will generate the intervals of the pipeline.  In this example the following get made:
         
     | 
| 
       38 
80 
     | 
    
         
             
            * setup_expire
         
     | 
| 
       39 
81 
     | 
    
         
             
            * before_expire
         
     | 
| 
       40 
82 
     | 
    
         
             
            * after_expire_success
         
     | 
| 
       41 
83 
     | 
    
         
             
            * after_expire_failure
         
     | 
| 
       42 
84 
     | 
    
         
             
            * after_expire
         
     | 
| 
       43 
85 
     | 
    
         | 
| 
       44 
     | 
    
         
            -
             
     | 
| 
      
 86 
     | 
    
         
            +
            Now you can trigger the workflow by calling the action as a method on an instance of the context.
         
     | 
| 
      
 87 
     | 
    
         
            +
             
     | 
| 
      
 88 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 89 
     | 
    
         
            +
            class TokenContext
         
     | 
| 
      
 90 
     | 
    
         
            +
              include SnFoil::Context
         
     | 
| 
      
 91 
     | 
    
         
            +
             
     | 
| 
      
 92 
     | 
    
         
            +
              action(:expire) { |options| options[:object].update(expired_at: Time.current) }
         
     | 
| 
      
 93 
     | 
    
         
            +
            end
         
     | 
| 
      
 94 
     | 
    
         
            +
             
     | 
| 
      
 95 
     | 
    
         
            +
            TokenContext.new(current_user).expire(object: current_token)
         
     | 
| 
      
 96 
     | 
    
         
            +
            ```
         
     | 
| 
      
 97 
     | 
    
         
            +
             
     | 
| 
      
 98 
     | 
    
         
            +
            If you want to reuse the primary action or just prefer methods, you can pass in the method name you would like to call, rather than providing a block.  If a method name and a block are provided, the block is ignored. 
         
     | 
| 
       45 
99 
     | 
    
         | 
| 
       46 
100 
     | 
    
         | 
| 
       47 
101 
     | 
    
         
             
            ```ruby
         
     | 
| 
         @@ -59,10 +113,10 @@ class TokenContext 
     | 
|
| 
       59 
113 
     | 
    
         
             
            end
         
     | 
| 
       60 
114 
     | 
    
         
             
            ```
         
     | 
| 
       61 
115 
     | 
    
         | 
| 
       62 
     | 
    
         
            -
            #### Primary  
     | 
| 
       63 
     | 
    
         
            -
            The primary  
     | 
| 
      
 116 
     | 
    
         
            +
            #### Primary Function
         
     | 
| 
      
 117 
     | 
    
         
            +
            The primary function is the function that determines whether or not the action is successful.  To do this, the primary function must always return a truthy value if the action was successful, or a falsey one if it failed.
         
     | 
| 
       64 
118 
     | 
    
         | 
| 
       65 
     | 
    
         
            -
            The primary  
     | 
| 
      
 119 
     | 
    
         
            +
            The primary function is passed one argument which is the return value of the closest preceding interval function.
         
     | 
| 
       66 
120 
     | 
    
         | 
| 
       67 
121 
     | 
    
         
             
            ```ruby
         
     | 
| 
       68 
122 
     | 
    
         
             
            # lib/contexts/token_context
         
     | 
| 
         @@ -85,67 +139,67 @@ class TokenContext 
     | 
|
| 
       85 
139 
     | 
    
         
             
            end
         
     | 
| 
       86 
140 
     | 
    
         
             
            ```
         
     | 
| 
       87 
141 
     | 
    
         | 
| 
       88 
     | 
    
         
            -
            #### Intervals
         
     | 
| 
       89 
     | 
    
         
            -
            The following are the intervals SnFoil Contexts  
     | 
| 
      
 142 
     | 
    
         
            +
            #### Action Intervals
         
     | 
| 
      
 143 
     | 
    
         
            +
            The following are the intervals SnFoil Contexts set up in the order they occur.  The suggested uses are just very simple examples.  You can chain contexts to setup very complex interactions in a very easy-to-manage workflow.
         
     | 
| 
       90 
144 
     | 
    
         | 
| 
       91 
145 
     | 
    
         
             
            <table>
         
     | 
| 
       92 
     | 
    
         
            -
             
     | 
| 
       93 
     | 
    
         
            -
             
     | 
| 
       94 
     | 
    
         
            -
             
     | 
| 
       95 
     | 
    
         
            -
             
     | 
| 
       96 
     | 
    
         
            -
             
     | 
| 
       97 
     | 
    
         
            -
             
     | 
| 
       98 
     | 
    
         
            -
             
     | 
| 
       99 
     | 
    
         
            -
             
     | 
| 
       100 
     | 
    
         
            -
             
     | 
| 
       101 
     | 
    
         
            -
             
     | 
| 
       102 
     | 
    
         
            -
             
     | 
| 
       103 
     | 
    
         
            -
             
     | 
| 
       104 
     | 
    
         
            -
             
     | 
| 
       105 
     | 
    
         
            -
             
     | 
| 
       106 
     | 
    
         
            -
             
     | 
| 
       107 
     | 
    
         
            -
             
     | 
| 
       108 
     | 
    
         
            -
             
     | 
| 
       109 
     | 
    
         
            -
             
     | 
| 
       110 
     | 
    
         
            -
             
     | 
| 
       111 
     | 
    
         
            -
             
     | 
| 
       112 
     | 
    
         
            -
             
     | 
| 
       113 
     | 
    
         
            -
             
     | 
| 
       114 
     | 
    
         
            -
             
     | 
| 
       115 
     | 
    
         
            -
             
     | 
| 
       116 
     | 
    
         
            -
             
     | 
| 
       117 
     | 
    
         
            -
             
     | 
| 
       118 
     | 
    
         
            -
             
     | 
| 
       119 
     | 
    
         
            -
             
     | 
| 
       120 
     | 
    
         
            -
             
     | 
| 
       121 
     | 
    
         
            -
             
     | 
| 
       122 
     | 
    
         
            -
             
     | 
| 
       123 
     | 
    
         
            -
             
     | 
| 
       124 
     | 
    
         
            -
             
     | 
| 
       125 
     | 
    
         
            -
             
     | 
| 
       126 
     | 
    
         
            -
             
     | 
| 
       127 
     | 
    
         
            -
             
     | 
| 
       128 
     | 
    
         
            -
             
     | 
| 
       129 
     | 
    
         
            -
             
     | 
| 
       130 
     | 
    
         
            -
             
     | 
| 
       131 
     | 
    
         
            -
             
     | 
| 
       132 
     | 
    
         
            -
             
     | 
| 
       133 
     | 
    
         
            -
             
     | 
| 
       134 
     | 
    
         
            -
             
     | 
| 
       135 
     | 
    
         
            -
             
     | 
| 
       136 
     | 
    
         
            -
             
     | 
| 
       137 
     | 
    
         
            -
             
     | 
| 
       138 
     | 
    
         
            -
             
     | 
| 
       139 
     | 
    
         
            -
             
     | 
| 
       140 
     | 
    
         
            -
             
     | 
| 
      
 146 
     | 
    
         
            +
              <thead>
         
     | 
| 
      
 147 
     | 
    
         
            +
                <th>Name</th>
         
     | 
| 
      
 148 
     | 
    
         
            +
                <th>Suggested Use</th>
         
     | 
| 
      
 149 
     | 
    
         
            +
              </thead>
         
     | 
| 
      
 150 
     | 
    
         
            +
              <tbody>
         
     | 
| 
      
 151 
     | 
    
         
            +
                <tr>
         
     | 
| 
      
 152 
     | 
    
         
            +
                  <td>setup_<action></td>
         
     | 
| 
      
 153 
     | 
    
         
            +
                  <td>
         
     | 
| 
      
 154 
     | 
    
         
            +
                    <div>* find or create a model</div>
         
     | 
| 
      
 155 
     | 
    
         
            +
                    <div>* setup params needed later in the action</div>
         
     | 
| 
      
 156 
     | 
    
         
            +
                    <div>* set scoping </div>
         
     | 
| 
      
 157 
     | 
    
         
            +
                  </td>
         
     | 
| 
      
 158 
     | 
    
         
            +
                </tr>
         
     | 
| 
      
 159 
     | 
    
         
            +
                <tr>
         
     | 
| 
      
 160 
     | 
    
         
            +
                  <td>before_<action></td>
         
     | 
| 
      
 161 
     | 
    
         
            +
                  <td>
         
     | 
| 
      
 162 
     | 
    
         
            +
                    <div>* alter model or set attributes</div>
         
     | 
| 
      
 163 
     | 
    
         
            +
                  </td>
         
     | 
| 
      
 164 
     | 
    
         
            +
                </tr>
         
     | 
| 
      
 165 
     | 
    
         
            +
                <tr>
         
     | 
| 
      
 166 
     | 
    
         
            +
                  <td>primary action</td>
         
     | 
| 
      
 167 
     | 
    
         
            +
                  <td>
         
     | 
| 
      
 168 
     | 
    
         
            +
                    <div>* persist database changes</div>
         
     | 
| 
      
 169 
     | 
    
         
            +
                    <div>* make primary network call</div>
         
     | 
| 
      
 170 
     | 
    
         
            +
                  </td>
         
     | 
| 
      
 171 
     | 
    
         
            +
                </tr>
         
     | 
| 
      
 172 
     | 
    
         
            +
                <tr>
         
     | 
| 
      
 173 
     | 
    
         
            +
                  <td>after_<action>_success</td>
         
     | 
| 
      
 174 
     | 
    
         
            +
                  <td>
         
     | 
| 
      
 175 
     | 
    
         
            +
                    <div>* setup additional relationships</div>
         
     | 
| 
      
 176 
     | 
    
         
            +
                    <div>* success specific logging</div>
         
     | 
| 
      
 177 
     | 
    
         
            +
                  </td>
         
     | 
| 
      
 178 
     | 
    
         
            +
                </tr>
         
     | 
| 
      
 179 
     | 
    
         
            +
                <tr>
         
     | 
| 
      
 180 
     | 
    
         
            +
                  <td>after_<action>_failure</td>
         
     | 
| 
      
 181 
     | 
    
         
            +
                  <td>
         
     | 
| 
      
 182 
     | 
    
         
            +
                    <div>* cleanup failed remenants</div>
         
     | 
| 
      
 183 
     | 
    
         
            +
                    <div>* call bug tracker</div>
         
     | 
| 
      
 184 
     | 
    
         
            +
                    <div>* failure specific logging</div>
         
     | 
| 
      
 185 
     | 
    
         
            +
                  </td>
         
     | 
| 
      
 186 
     | 
    
         
            +
                </tr>
         
     | 
| 
      
 187 
     | 
    
         
            +
                <tr>
         
     | 
| 
      
 188 
     | 
    
         
            +
                  <td>after_<action></td>
         
     | 
| 
      
 189 
     | 
    
         
            +
                  <td>
         
     | 
| 
      
 190 
     | 
    
         
            +
                    <div>* perform necessary required cleanup</div>
         
     | 
| 
      
 191 
     | 
    
         
            +
                    <div>* log outcome</div>
         
     | 
| 
      
 192 
     | 
    
         
            +
                  </td>
         
     | 
| 
      
 193 
     | 
    
         
            +
                </tr>
         
     | 
| 
      
 194 
     | 
    
         
            +
              </tbody>
         
     | 
| 
       141 
195 
     | 
    
         
             
            <table>
         
     | 
| 
       142 
196 
     | 
    
         | 
| 
       143 
197 
     | 
    
         | 
| 
       144 
198 
     | 
    
         
             
            #### Hook and Method Design
         
     | 
| 
       145 
199 
     | 
    
         | 
| 
       146 
     | 
    
         
            -
            SnFoil Contexts try hard to not store variables longer than necessary.  To facilitate this we have  
     | 
| 
      
 200 
     | 
    
         
            +
            SnFoil Contexts try hard to not store variables longer than necessary.  To facilitate this we have chosen to pass an object (we normally use a hash called options) to each hook and method, and the return from the hook or method is passed down the chain to the next hook or method.  
         
     | 
| 
       147 
201 
     | 
    
         | 
| 
       148 
     | 
    
         
            -
            The only method or block that does not get its value  
     | 
| 
      
 202 
     | 
    
         
            +
            The only method or block that does not get its value passed down the chain is the primary action - which must always return a truthy value of whether or not the action was successful.
         
     | 
| 
       149 
203 
     | 
    
         | 
| 
       150 
204 
     | 
    
         
             
            #### Hooks
         
     | 
| 
       151 
205 
     | 
    
         
             
            Hooks make it very easy to compose multiple actions that need to occur in a specific order.  You can have as many repeated hooks as you would like.  This makes defining single responsibility hooks very simple, and they will get called in the order they are defined.
         
     | 
| 
         @@ -156,29 +210,29 @@ Hooks make it very easy to compose multiple actions that need to occur in a spec 
     | 
|
| 
       156 
210 
     | 
    
         
             
            ```ruby
         
     | 
| 
       157 
211 
     | 
    
         
             
            # Call the webhooks for third party integrations
         
     | 
| 
       158 
212 
     | 
    
         
             
            after_expire_success do |options|
         
     | 
| 
       159 
     | 
    
         
            -
             
     | 
| 
       160 
     | 
    
         
            -
             
     | 
| 
      
 213 
     | 
    
         
            +
              call_webhook_for_model(options[:object])
         
     | 
| 
      
 214 
     | 
    
         
            +
              options
         
     | 
| 
       161 
215 
     | 
    
         
             
            end
         
     | 
| 
       162 
216 
     | 
    
         | 
| 
       163 
217 
     | 
    
         
             
            # Commit business logic to internal process
         
     | 
| 
       164 
218 
     | 
    
         
             
            after_expire_success do |options|
         
     | 
| 
       165 
     | 
    
         
            -
             
     | 
| 
       166 
     | 
    
         
            -
             
     | 
| 
      
 219 
     | 
    
         
            +
              finalize_business_logic(options[:object])
         
     | 
| 
      
 220 
     | 
    
         
            +
              options
         
     | 
| 
       167 
221 
     | 
    
         
             
            end
         
     | 
| 
       168 
222 
     | 
    
         | 
| 
       169 
223 
     | 
    
         
             
            # notify error tracker
         
     | 
| 
       170 
224 
     | 
    
         
             
            after_expire_error do |options|
         
     | 
| 
       171 
     | 
    
         
            -
             
     | 
| 
       172 
     | 
    
         
            -
             
     | 
| 
      
 225 
     | 
    
         
            +
              notify_errors(options[:object].errors)
         
     | 
| 
      
 226 
     | 
    
         
            +
              options
         
     | 
| 
       173 
227 
     | 
    
         
             
            end
         
     | 
| 
       174 
228 
     | 
    
         
             
            ```
         
     | 
| 
       175 
229 
     | 
    
         | 
| 
       176 
230 
     | 
    
         
             
            #### Methods
         
     | 
| 
       177 
     | 
    
         
            -
            Methods allow users to create inheritable actions that occur in a specific order.  Methods will always run after their hook counterpart.  Since these are inheritable, you can chain needed actions  
     | 
| 
      
 231 
     | 
    
         
            +
            Methods allow users to create inheritable actions that occur in a specific order.  Methods will always run after their hook counterpart.  Since these are inheritable, you can chain needed actions through the parent hierarchy by using the `super` keyword.   These are very useful when you need to have something always happen at the end of an Interval.
         
     | 
| 
       178 
232 
     | 
    
         | 
| 
       179 
233 
     | 
    
         
             
            <strong>Important Note</strong> Methods <u>always</u> need to return the options hash at the end.
         
     | 
| 
       180 
234 
     | 
    
         | 
| 
       181 
     | 
    
         
            -
            <i>Author's opinion:</i> While  
     | 
| 
      
 235 
     | 
    
         
            +
            <i>Author's opinion:</i> While simpler than hooks, they do not allow for as clean of a composition as hooks.
         
     | 
| 
       182 
236 
     | 
    
         | 
| 
       183 
237 
     | 
    
         
             
            ##### Example
         
     | 
| 
       184 
238 
     | 
    
         | 
| 
         @@ -186,21 +240,21 @@ Methods allow users to create inheritable actions that occur in a specific order 
     | 
|
| 
       186 
240 
     | 
    
         
             
            # Call the webhooks for third party integrations
         
     | 
| 
       187 
241 
     | 
    
         
             
            # Commit business logic to internal process
         
     | 
| 
       188 
242 
     | 
    
         
             
            def after_expire_success(**options)
         
     | 
| 
       189 
     | 
    
         
            -
             
     | 
| 
      
 243 
     | 
    
         
            +
              options = super
         
     | 
| 
       190 
244 
     | 
    
         | 
| 
       191 
     | 
    
         
            -
             
     | 
| 
       192 
     | 
    
         
            -
             
     | 
| 
      
 245 
     | 
    
         
            +
              call_webhook_for_model(options[:object])
         
     | 
| 
      
 246 
     | 
    
         
            +
              finalize_business_logic(options[:object])
         
     | 
| 
       193 
247 
     | 
    
         | 
| 
       194 
     | 
    
         
            -
             
     | 
| 
      
 248 
     | 
    
         
            +
              options
         
     | 
| 
       195 
249 
     | 
    
         
             
            end
         
     | 
| 
       196 
250 
     | 
    
         | 
| 
       197 
251 
     | 
    
         
             
            # notify error tracker
         
     | 
| 
       198 
252 
     | 
    
         
             
            def after_expire_error(**options)
         
     | 
| 
       199 
     | 
    
         
            -
             
     | 
| 
      
 253 
     | 
    
         
            +
              options = super
         
     | 
| 
       200 
254 
     | 
    
         | 
| 
       201 
     | 
    
         
            -
             
     | 
| 
      
 255 
     | 
    
         
            +
              notify_errors(options[:object].errors)
         
     | 
| 
       202 
256 
     | 
    
         | 
| 
       203 
     | 
    
         
            -
             
     | 
| 
      
 257 
     | 
    
         
            +
              options
         
     | 
| 
       204 
258 
     | 
    
         
             
            end
         
     | 
| 
       205 
259 
     | 
    
         
             
            ```
         
     | 
| 
       206 
260 
     | 
    
         | 
| 
         @@ -209,10 +263,10 @@ The original purpose of all of SnFoil was to ensure there was a good consistent 
     | 
|
| 
       209 
263 
     | 
    
         | 
| 
       210 
264 
     | 
    
         
             
            These authorization hooks are always called twice.  Once after `setup_<action>` and once after `before_<action>`
         
     | 
| 
       211 
265 
     | 
    
         | 
| 
       212 
     | 
    
         
            -
            The `authorize` method functions much like primary action except the first argument is usually the name of action you are authorizing.
         
     | 
| 
      
 266 
     | 
    
         
            +
            The `authorize` method functions much like primary action except the first argument is usually the name of the action you are authorizing.
         
     | 
| 
       213 
267 
     | 
    
         | 
| 
       214 
268 
     | 
    
         
             
            Arguments:
         
     | 
| 
       215 
     | 
    
         
            -
            * `name` - The name of this action to be authorized.  If  
     | 
| 
      
 269 
     | 
    
         
            +
            * `name` - The name of this action to be authorized.  If omitted, all actions without a specific associated authorize will use this
         
     | 
| 
       216 
270 
     | 
    
         
             
            * `with` - Keyword Param - The method name of the primary action.  Either this or a block is required
         
     | 
| 
       217 
271 
     | 
    
         
             
            * `block` - Block -  The block of the primary action.  Either this or with is required
         
     | 
| 
       218 
272 
     | 
    
         | 
| 
         @@ -225,13 +279,13 @@ class TokenContext 
     | 
|
| 
       225 
279 
     | 
    
         | 
| 
       226 
280 
     | 
    
         
             
              action :expire, with: :expire_token
         
     | 
| 
       227 
281 
     | 
    
         | 
| 
       228 
     | 
    
         
            -
              authorize 
     | 
| 
      
 282 
     | 
    
         
            +
              authorize(:expire) { |_options| :entity.is_admin? }
         
     | 
| 
       229 
283 
     | 
    
         | 
| 
       230 
284 
     | 
    
         
             
              ...
         
     | 
| 
       231 
285 
     | 
    
         
             
            end
         
     | 
| 
       232 
286 
     | 
    
         
             
            ```
         
     | 
| 
       233 
287 
     | 
    
         | 
| 
       234 
     | 
    
         
            -
            You can also call authorize without an action name.  This will have all action authorize with the provided method or block unless there is a more specific authorize action configured.   
     | 
| 
      
 288 
     | 
    
         
            +
            You can also call authorize without an action name.  This will have all action authorize with the provided method or block unless there is a more specific authorize action configured.  It's probably easier explained with an example
         
     | 
| 
       235 
289 
     | 
    
         | 
| 
       236 
290 
     | 
    
         | 
| 
       237 
291 
     | 
    
         
             
            ```ruby
         
     | 
| 
         @@ -245,15 +299,44 @@ class TokenContext 
     | 
|
| 
       245 
299 
     | 
    
         
             
              action :search, with: :query_tokens #=> will authorize by checking the entity is a user
         
     | 
| 
       246 
300 
     | 
    
         
             
              action :show, with: :find_token #=> will authorize by checking the entity is a user
         
     | 
| 
       247 
301 
     | 
    
         | 
| 
       248 
     | 
    
         
            -
              authorize 
     | 
| 
       249 
     | 
    
         
            -
              authorize { | 
     | 
| 
      
 302 
     | 
    
         
            +
              authorize(:expire) { |_options| entity.is_admin? }
         
     | 
| 
      
 303 
     | 
    
         
            +
              authorize { |_options| entity.is_user? }
         
     | 
| 
       250 
304 
     | 
    
         | 
| 
       251 
305 
     | 
    
         
             
              ...
         
     | 
| 
       252 
306 
     | 
    
         
             
            end
         
     | 
| 
       253 
307 
     | 
    
         
             
            ```
         
     | 
| 
       254 
308 
     | 
    
         | 
| 
       255 
309 
     | 
    
         
             
            #### Why before and after?
         
     | 
| 
       256 
     | 
    
         
            -
            Simply to make sure the entity  
     | 
| 
      
 310 
     | 
    
         
            +
            Simply to make sure the entity is allowed access to the primary target and is allowed to make the requested alterations/interactions.
         
     | 
| 
      
 311 
     | 
    
         
            +
             
     | 
| 
      
 312 
     | 
    
         
            +
            ### Intervals
         
     | 
| 
      
 313 
     | 
    
         
            +
            There might be a situation where you don't need a before, after, success or failure, and just need a single name pipeline you can hook into. `interval` allows you to create a single action-like segment.
         
     | 
| 
      
 314 
     | 
    
         
            +
             
     | 
| 
      
 315 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 316 
     | 
    
         
            +
            class TokenContext
         
     | 
| 
      
 317 
     | 
    
         
            +
              include SnFoil::Context
         
     | 
| 
      
 318 
     | 
    
         
            +
             
     | 
| 
      
 319 
     | 
    
         
            +
              interval :demo
         
     | 
| 
      
 320 
     | 
    
         
            +
             
     | 
| 
      
 321 
     | 
    
         
            +
              demo do |options|
         
     | 
| 
      
 322 
     | 
    
         
            +
                ... # Logic Here
         
     | 
| 
      
 323 
     | 
    
         
            +
             
     | 
| 
      
 324 
     | 
    
         
            +
                options
         
     | 
| 
      
 325 
     | 
    
         
            +
              end
         
     | 
| 
      
 326 
     | 
    
         
            +
             
     | 
| 
      
 327 
     | 
    
         
            +
              demo do |options|
         
     | 
| 
      
 328 
     | 
    
         
            +
                ... # Additional Steps here
         
     | 
| 
      
 329 
     | 
    
         
            +
             
     | 
| 
      
 330 
     | 
    
         
            +
                options
         
     | 
| 
      
 331 
     | 
    
         
            +
              end
         
     | 
| 
      
 332 
     | 
    
         
            +
            end
         
     | 
| 
      
 333 
     | 
    
         
            +
            ```
         
     | 
| 
      
 334 
     | 
    
         
            +
             
     | 
| 
      
 335 
     | 
    
         
            +
            Just like for an action SnFoil allows you to define both hooks and a method.  To run this interval you call it using the `run_interval` method.
         
     | 
| 
      
 336 
     | 
    
         
            +
             
     | 
| 
      
 337 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 338 
     | 
    
         
            +
            TokenContext.new(entity).run_interval(:demo, **options)
         
     | 
| 
      
 339 
     | 
    
         
            +
            ```
         
     | 
| 
       257 
340 
     | 
    
         | 
| 
       258 
341 
     | 
    
         
             
            ## Development
         
     | 
| 
       259 
342 
     | 
    
         | 
| 
         @@ -271,4 +354,4 @@ The gem is available as open source under the terms of the [Apache 2 License](ht 
     | 
|
| 
       271 
354 
     | 
    
         | 
| 
       272 
355 
     | 
    
         
             
            ## Code of Conduct
         
     | 
| 
       273 
356 
     | 
    
         | 
| 
       274 
     | 
    
         
            -
            Everyone interacting in the Snfoil::Context project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/limited-effort/snfoil-context/blob/main/CODE_OF_CONDUCT.md).
         
     | 
| 
      
 357 
     | 
    
         
            +
            Everyone interacting in the Snfoil::Context project's codebases, issue trackers, chat rooms, and mailing lists is expected to follow the [code of conduct](https://github.com/limited-effort/snfoil-context/blob/main/CODE_OF_CONDUCT.md).
         
     | 
| 
         @@ -28,15 +28,25 @@ module SnFoil 
     | 
|
| 
       28 
28 
     | 
    
         
             
                  extend ActiveSupport::Concern
         
     | 
| 
       29 
29 
     | 
    
         | 
| 
       30 
30 
     | 
    
         
             
                  class_methods do
         
     | 
| 
       31 
     | 
    
         
            -
                     
     | 
| 
      
 31 
     | 
    
         
            +
                    attr_accessor :snfoil_authorizations
         
     | 
| 
       32 
32 
     | 
    
         | 
| 
       33 
33 
     | 
    
         
             
                    def authorize(action_name = nil, with: nil, &block)
         
     | 
| 
       34 
     | 
    
         
            -
                      @ 
     | 
| 
      
 34 
     | 
    
         
            +
                      @snfoil_authorizations ||= {}
         
     | 
| 
       35 
35 
     | 
    
         
             
                      action_name = action_name&.to_sym
         
     | 
| 
       36 
36 
     | 
    
         | 
| 
       37 
     | 
    
         
            -
                       
     | 
| 
      
 37 
     | 
    
         
            +
                      if @snfoil_authorizations[action_name]
         
     | 
| 
      
 38 
     | 
    
         
            +
                        raise SnFoil::Context::Error, "#{name} already has authorize defined for #{action_name || ':default'}"
         
     | 
| 
      
 39 
     | 
    
         
            +
                      end
         
     | 
| 
       38 
40 
     | 
    
         | 
| 
       39 
     | 
    
         
            -
                      @ 
     | 
| 
      
 41 
     | 
    
         
            +
                      @snfoil_authorizations[action_name] = { method: with, block: block }
         
     | 
| 
      
 42 
     | 
    
         
            +
                    end
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
                    def inherited(subclass)
         
     | 
| 
      
 45 
     | 
    
         
            +
                      super
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                      instance_variables.grep(/@snfoil_.+/).each do |i|
         
     | 
| 
      
 48 
     | 
    
         
            +
                        subclass.instance_variable_set(i, instance_variable_get(i).dup)
         
     | 
| 
      
 49 
     | 
    
         
            +
                      end
         
     | 
| 
       40 
50 
     | 
    
         
             
                    end
         
     | 
| 
       41 
51 
     | 
    
         
             
                  end
         
     | 
| 
       42 
52 
     | 
    
         | 
| 
         @@ -47,8 +57,8 @@ module SnFoil 
     | 
|
| 
       47 
57 
     | 
    
         
             
                  end
         
     | 
| 
       48 
58 
     | 
    
         | 
| 
       49 
59 
     | 
    
         
             
                  def authorize(name, **options)
         
     | 
| 
       50 
     | 
    
         
            -
                    configured_call = self.class. 
     | 
| 
       51 
     | 
    
         
            -
                    configured_call ||= self.class. 
     | 
| 
      
 60 
     | 
    
         
            +
                    configured_call = self.class.snfoil_authorizations&.fetch(name.to_sym, nil)
         
     | 
| 
      
 61 
     | 
    
         
            +
                    configured_call ||= self.class.snfoil_authorizations&.fetch(nil, nil)
         
     | 
| 
       52 
62 
     | 
    
         | 
| 
       53 
63 
     | 
    
         
             
                    if configured_call
         
     | 
| 
       54 
64 
     | 
    
         
             
                      run_hook(configured_call, **options)
         
     | 
| 
         @@ -65,12 +75,12 @@ module SnFoil 
     | 
|
| 
       65 
75 
     | 
    
         | 
| 
       66 
76 
     | 
    
         
             
                    return send(hook[:method], **options) if hook[:method]
         
     | 
| 
       67 
77 
     | 
    
         | 
| 
       68 
     | 
    
         
            -
                    instance_exec 
     | 
| 
      
 78 
     | 
    
         
            +
                    instance_exec(**options, &hook[:block])
         
     | 
| 
       69 
79 
     | 
    
         
             
                  end
         
     | 
| 
       70 
80 
     | 
    
         | 
| 
       71 
81 
     | 
    
         
             
                  def hook_valid?(hook, **options)
         
     | 
| 
       72 
     | 
    
         
            -
                    return false if !hook[:if].nil? && hook[:if].call(options) == false
         
     | 
| 
       73 
     | 
    
         
            -
                    return false if !hook[:unless].nil? && hook[:unless].call(options) == true
         
     | 
| 
      
 82 
     | 
    
         
            +
                    return false if !hook[:if].nil? && hook[:if].call(**options) == false
         
     | 
| 
      
 83 
     | 
    
         
            +
                    return false if !hook[:unless].nil? && hook[:unless].call(**options) == true
         
     | 
| 
       74 
84 
     | 
    
         | 
| 
       75 
85 
     | 
    
         
             
                    true
         
     | 
| 
       76 
86 
     | 
    
         
             
                  end
         
     | 
    
        data/lib/snfoil/context.rb
    CHANGED
    
    | 
         @@ -1,6 +1,6 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # frozen_string_literal: true
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
     | 
    
         
            -
            # Copyright 2021 Matthew Howes
         
     | 
| 
      
 3 
     | 
    
         
            +
            # Copyright 2021 Matthew Howes, Cliff Campbell
         
     | 
| 
       4 
4 
     | 
    
         | 
| 
       5 
5 
     | 
    
         
             
            # Licensed under the Apache License, Version 2.0 (the "License");
         
     | 
| 
       6 
6 
     | 
    
         
             
            # you may not use this file except in compliance with the License.
         
     | 
| 
         @@ -35,20 +35,27 @@ module SnFoil 
     | 
|
| 
       35 
35 
     | 
    
         | 
| 
       36 
36 
     | 
    
         
             
                class_methods do
         
     | 
| 
       37 
37 
     | 
    
         
             
                  def action(name, with: nil, &block)
         
     | 
| 
       38 
     | 
    
         
            -
                    raise SnFoil::Context::Error, "action #{name} already defined for #{self.name}" if (@ 
     | 
| 
      
 38 
     | 
    
         
            +
                    raise SnFoil::Context::Error, "action #{name} already defined for #{self.name}" if (@snfoil_actions ||= []).include?(name)
         
     | 
| 
       39 
39 
     | 
    
         | 
| 
       40 
     | 
    
         
            -
                    @ 
     | 
| 
       41 
     | 
    
         
            -
                     
     | 
| 
      
 40 
     | 
    
         
            +
                    @snfoil_actions << name
         
     | 
| 
      
 41 
     | 
    
         
            +
                    define_workflow(name)
         
     | 
| 
       42 
42 
     | 
    
         
             
                    define_action_primary(name, with, block)
         
     | 
| 
       43 
43 
     | 
    
         
             
                  end
         
     | 
| 
       44 
     | 
    
         
            -
                end
         
     | 
| 
       45 
44 
     | 
    
         | 
| 
       46 
     | 
    
         
            -
             
     | 
| 
       47 
     | 
    
         
            -
             
     | 
| 
       48 
     | 
    
         
            -
             
     | 
| 
       49 
     | 
    
         
            -
                   
     | 
| 
      
 45 
     | 
    
         
            +
                  def interval(name)
         
     | 
| 
      
 46 
     | 
    
         
            +
                    define_singleton_methods(name)
         
     | 
| 
      
 47 
     | 
    
         
            +
                    define_instance_methods(name)
         
     | 
| 
      
 48 
     | 
    
         
            +
                  end
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                  def intervals(*names)
         
     | 
| 
      
 51 
     | 
    
         
            +
                    names.each { |name| interval(name) }
         
     | 
| 
      
 52 
     | 
    
         
            +
                  end
         
     | 
| 
      
 53 
     | 
    
         
            +
                end
         
     | 
| 
       50 
54 
     | 
    
         | 
| 
       51 
     | 
    
         
            -
             
     | 
| 
      
 55 
     | 
    
         
            +
                def run_interval(interval, **options)
         
     | 
| 
      
 56 
     | 
    
         
            +
                  hooks = self.class.instance_variable_get("@snfoil_#{interval}_hooks") || []
         
     | 
| 
      
 57 
     | 
    
         
            +
                  options = hooks.reduce(options) { |opts, hook| run_hook(hook, **opts) }
         
     | 
| 
      
 58 
     | 
    
         
            +
                  send(interval, **options)
         
     | 
| 
       52 
59 
     | 
    
         
             
                end
         
     | 
| 
       53 
60 
     | 
    
         | 
| 
       54 
61 
     | 
    
         
             
                private
         
     | 
| 
         @@ -56,38 +63,35 @@ module SnFoil 
     | 
|
| 
       56 
63 
     | 
    
         
             
                # rubocop:disable reason:  These are builder/mapping methods that are just too complex to simplify without
         
     | 
| 
       57 
64 
     | 
    
         
             
                # making them more complex.  If anyone has a better way please let me know
         
     | 
| 
       58 
65 
     | 
    
         
             
                class_methods do # rubocop:disable Metrics/BlockLength
         
     | 
| 
      
 66 
     | 
    
         
            +
                  def define_workflow(name)
         
     | 
| 
      
 67 
     | 
    
         
            +
                    interval format('setup_%s', name)
         
     | 
| 
      
 68 
     | 
    
         
            +
                    interval format('before_%s', name)
         
     | 
| 
      
 69 
     | 
    
         
            +
                    interval format('after_%s_success', name)
         
     | 
| 
      
 70 
     | 
    
         
            +
                    interval format('after_%s_failure', name)
         
     | 
| 
      
 71 
     | 
    
         
            +
                    interval format('after_%s', name)
         
     | 
| 
      
 72 
     | 
    
         
            +
                  end
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
       59 
74 
     | 
    
         
             
                  def define_action_primary(name, method, block) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
         
     | 
| 
       60 
     | 
    
         
            -
                    define_method(name) do  
     | 
| 
       61 
     | 
    
         
            -
                      options[:action]  
     | 
| 
       62 
     | 
    
         
            -
             
     | 
| 
      
 75 
     | 
    
         
            +
                    define_method(name) do |*_args, **options| # rubocop:disable Metrics/MethodLength
         
     | 
| 
      
 76 
     | 
    
         
            +
                      options[:action] ||= name.to_sym
         
     | 
| 
      
 77 
     | 
    
         
            +
             
     | 
| 
      
 78 
     | 
    
         
            +
                      options = run_interval(format('setup_%s', name), **options)
         
     | 
| 
       63 
79 
     | 
    
         
             
                      authorize(name, **options) if respond_to?(:authorize)
         
     | 
| 
       64 
80 
     | 
    
         | 
| 
       65 
     | 
    
         
            -
                      options =  
     | 
| 
      
 81 
     | 
    
         
            +
                      options = run_interval(format('before_%s', name), **options)
         
     | 
| 
       66 
82 
     | 
    
         
             
                      authorize(name, **options) if respond_to?(:authorize)
         
     | 
| 
       67 
83 
     | 
    
         | 
| 
       68 
84 
     | 
    
         
             
                      options = if run_action_primary(method, block, **options)
         
     | 
| 
       69 
     | 
    
         
            -
                                   
     | 
| 
      
 85 
     | 
    
         
            +
                                  run_interval(format('after_%s_success', name), **options)
         
     | 
| 
       70 
86 
     | 
    
         
             
                                else
         
     | 
| 
       71 
     | 
    
         
            -
                                   
     | 
| 
      
 87 
     | 
    
         
            +
                                  run_interval(format('after_%s_failure', name), **options)
         
     | 
| 
       72 
88 
     | 
    
         
             
                                end
         
     | 
| 
       73 
     | 
    
         
            -
                       
     | 
| 
      
 89 
     | 
    
         
            +
                      run_interval(format('after_%s', name), **options)
         
     | 
| 
       74 
90 
     | 
    
         
             
                    end
         
     | 
| 
       75 
91 
     | 
    
         
             
                  end
         
     | 
| 
       76 
92 
     | 
    
         | 
| 
       77 
     | 
    
         
            -
                  def  
     | 
| 
       78 
     | 
    
         
            -
                     
     | 
| 
       79 
     | 
    
         
            -
                    hook_builder('before_%s', name)
         
     | 
| 
       80 
     | 
    
         
            -
                    hook_builder('after_%s_success', name)
         
     | 
| 
       81 
     | 
    
         
            -
                    hook_builder('after_%s_failure', name)
         
     | 
| 
       82 
     | 
    
         
            -
                    hook_builder('after_%s', name)
         
     | 
| 
       83 
     | 
    
         
            -
                  end
         
     | 
| 
       84 
     | 
    
         
            -
             
     | 
| 
       85 
     | 
    
         
            -
                  def hook_builder(name_format, name)
         
     | 
| 
       86 
     | 
    
         
            -
                    assign_singleton_methods format(name_format, name),
         
     | 
| 
       87 
     | 
    
         
            -
                                             format("#{name_format}_hooks", name)
         
     | 
| 
       88 
     | 
    
         
            -
                  end
         
     | 
| 
       89 
     | 
    
         
            -
             
     | 
| 
       90 
     | 
    
         
            -
                  def assign_singleton_methods(method_name, singleton_var)
         
     | 
| 
      
 93 
     | 
    
         
            +
                  def define_singleton_methods(method_name)
         
     | 
| 
      
 94 
     | 
    
         
            +
                    singleton_var = "snfoil_#{method_name}_hooks"
         
     | 
| 
       91 
95 
     | 
    
         
             
                    instance_variable_set("@#{singleton_var}", [])
         
     | 
| 
       92 
96 
     | 
    
         
             
                    define_singleton_method(singleton_var) { instance_variable_get("@#{singleton_var}") }
         
     | 
| 
       93 
97 
     | 
    
         
             
                    define_singleton_method(method_name) do |method = nil, **options, &block|
         
     | 
| 
         @@ -99,12 +103,18 @@ module SnFoil 
     | 
|
| 
       99 
103 
     | 
    
         
             
                                                                      unless: options[:unless] }
         
     | 
| 
       100 
104 
     | 
    
         
             
                    end
         
     | 
| 
       101 
105 
     | 
    
         
             
                  end
         
     | 
| 
      
 106 
     | 
    
         
            +
             
     | 
| 
      
 107 
     | 
    
         
            +
                  def define_instance_methods(method_name)
         
     | 
| 
      
 108 
     | 
    
         
            +
                    define_method(method_name) do |**options|
         
     | 
| 
      
 109 
     | 
    
         
            +
                      options
         
     | 
| 
      
 110 
     | 
    
         
            +
                    end
         
     | 
| 
      
 111 
     | 
    
         
            +
                  end
         
     | 
| 
       102 
112 
     | 
    
         
             
                end
         
     | 
| 
       103 
113 
     | 
    
         | 
| 
       104 
114 
     | 
    
         
             
                def run_action_primary(method, block, **options)
         
     | 
| 
       105 
115 
     | 
    
         
             
                  return send(method, **options) if method
         
     | 
| 
       106 
116 
     | 
    
         | 
| 
       107 
     | 
    
         
            -
                  instance_exec 
     | 
| 
      
 117 
     | 
    
         
            +
                  instance_exec(**options, &block)
         
     | 
| 
       108 
118 
     | 
    
         
             
                end
         
     | 
| 
       109 
119 
     | 
    
         
             
              end
         
     | 
| 
       110 
120 
     | 
    
         
             
            end
         
     | 
    
        data/snfoil-context.gemspec
    CHANGED
    
    | 
         @@ -5,13 +5,13 @@ require_relative 'lib/snfoil/context/version' 
     | 
|
| 
       5 
5 
     | 
    
         
             
            Gem::Specification.new do |spec|
         
     | 
| 
       6 
6 
     | 
    
         
             
              spec.name          = 'snfoil-context'
         
     | 
| 
       7 
7 
     | 
    
         
             
              spec.version       = SnFoil::Context::VERSION
         
     | 
| 
       8 
     | 
    
         
            -
              spec.authors       = ['Matthew Howes']
         
     | 
| 
       9 
     | 
    
         
            -
              spec.email         = ['howeszy@gmail.com']
         
     | 
| 
      
 8 
     | 
    
         
            +
              spec.authors       = ['Matthew Howes', 'Cliff Campbell']
         
     | 
| 
      
 9 
     | 
    
         
            +
              spec.email         = ['howeszy@gmail.com', 'cliffcampbell@hey.com']
         
     | 
| 
       10 
10 
     | 
    
         | 
| 
       11 
11 
     | 
    
         
             
              spec.summary       = 'Setup simple pipelined workflows'
         
     | 
| 
       12 
12 
     | 
    
         
             
              spec.description   = 'An easy way to make extensible workflows and actions'
         
     | 
| 
       13 
13 
     | 
    
         
             
              spec.homepage      = 'https://github.com/limited-effort/snfoil-context'
         
     | 
| 
       14 
     | 
    
         
            -
              spec.license       = ' 
     | 
| 
      
 14 
     | 
    
         
            +
              spec.license       = 'Apache-2.0'
         
     | 
| 
       15 
15 
     | 
    
         
             
              spec.required_ruby_version = '>= 2.5.0'
         
     | 
| 
       16 
16 
     | 
    
         | 
| 
       17 
17 
     | 
    
         
             
              spec.metadata['homepage_uri'] = spec.homepage
         
     | 
| 
         @@ -30,6 +30,8 @@ Gem::Specification.new do |spec| 
     | 
|
| 
       30 
30 
     | 
    
         | 
| 
       31 
31 
     | 
    
         
             
              spec.add_dependency 'activesupport', '>= 5.2.6'
         
     | 
| 
       32 
32 
     | 
    
         | 
| 
      
 33 
     | 
    
         
            +
              spec.add_development_dependency 'bundle-audit', '~> 0.1.0'
         
     | 
| 
      
 34 
     | 
    
         
            +
              spec.add_development_dependency 'fasterer', '~> 0.9.0'
         
     | 
| 
       33 
35 
     | 
    
         
             
              spec.add_development_dependency 'pry-byebug', '~> 3.9'
         
     | 
| 
       34 
36 
     | 
    
         
             
              spec.add_development_dependency 'rake', '~> 13.0'
         
     | 
| 
       35 
37 
     | 
    
         
             
              spec.add_development_dependency 'rspec', '~> 3.10'
         
     | 
    
        metadata
    CHANGED
    
    | 
         @@ -1,14 +1,15 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            --- !ruby/object:Gem::Specification
         
     | 
| 
       2 
2 
     | 
    
         
             
            name: snfoil-context
         
     | 
| 
       3 
3 
     | 
    
         
             
            version: !ruby/object:Gem::Version
         
     | 
| 
       4 
     | 
    
         
            -
              version: 0.0. 
     | 
| 
      
 4 
     | 
    
         
            +
              version: 0.0.4
         
     | 
| 
       5 
5 
     | 
    
         
             
            platform: ruby
         
     | 
| 
       6 
6 
     | 
    
         
             
            authors:
         
     | 
| 
       7 
7 
     | 
    
         
             
            - Matthew Howes
         
     | 
| 
      
 8 
     | 
    
         
            +
            - Cliff Campbell
         
     | 
| 
       8 
9 
     | 
    
         
             
            autorequire: 
         
     | 
| 
       9 
10 
     | 
    
         
             
            bindir: exe
         
     | 
| 
       10 
11 
     | 
    
         
             
            cert_chain: []
         
     | 
| 
       11 
     | 
    
         
            -
            date: 2021-10- 
     | 
| 
      
 12 
     | 
    
         
            +
            date: 2021-10-28 00:00:00.000000000 Z
         
     | 
| 
       12 
13 
     | 
    
         
             
            dependencies:
         
     | 
| 
       13 
14 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       14 
15 
     | 
    
         
             
              name: activesupport
         
     | 
| 
         @@ -24,6 +25,34 @@ dependencies: 
     | 
|
| 
       24 
25 
     | 
    
         
             
                - - ">="
         
     | 
| 
       25 
26 
     | 
    
         
             
                  - !ruby/object:Gem::Version
         
     | 
| 
       26 
27 
     | 
    
         
             
                    version: 5.2.6
         
     | 
| 
      
 28 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 29 
     | 
    
         
            +
              name: bundle-audit
         
     | 
| 
      
 30 
     | 
    
         
            +
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
      
 31 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 32 
     | 
    
         
            +
                - - "~>"
         
     | 
| 
      
 33 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 34 
     | 
    
         
            +
                    version: 0.1.0
         
     | 
| 
      
 35 
     | 
    
         
            +
              type: :development
         
     | 
| 
      
 36 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 37 
     | 
    
         
            +
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
      
 38 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 39 
     | 
    
         
            +
                - - "~>"
         
     | 
| 
      
 40 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 41 
     | 
    
         
            +
                    version: 0.1.0
         
     | 
| 
      
 42 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 43 
     | 
    
         
            +
              name: fasterer
         
     | 
| 
      
 44 
     | 
    
         
            +
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
      
 45 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 46 
     | 
    
         
            +
                - - "~>"
         
     | 
| 
      
 47 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 48 
     | 
    
         
            +
                    version: 0.9.0
         
     | 
| 
      
 49 
     | 
    
         
            +
              type: :development
         
     | 
| 
      
 50 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 51 
     | 
    
         
            +
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
      
 52 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 53 
     | 
    
         
            +
                - - "~>"
         
     | 
| 
      
 54 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 55 
     | 
    
         
            +
                    version: 0.9.0
         
     | 
| 
       27 
56 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       28 
57 
     | 
    
         
             
              name: pry-byebug
         
     | 
| 
       29 
58 
     | 
    
         
             
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
         @@ -111,10 +140,12 @@ dependencies: 
     | 
|
| 
       111 
140 
     | 
    
         
             
            description: An easy way to make extensible workflows and actions
         
     | 
| 
       112 
141 
     | 
    
         
             
            email:
         
     | 
| 
       113 
142 
     | 
    
         
             
            - howeszy@gmail.com
         
     | 
| 
      
 143 
     | 
    
         
            +
            - cliffcampbell@hey.com
         
     | 
| 
       114 
144 
     | 
    
         
             
            executables: []
         
     | 
| 
       115 
145 
     | 
    
         
             
            extensions: []
         
     | 
| 
       116 
146 
     | 
    
         
             
            extra_rdoc_files: []
         
     | 
| 
       117 
147 
     | 
    
         
             
            files:
         
     | 
| 
      
 148 
     | 
    
         
            +
            - ".fasterer.yml"
         
     | 
| 
       118 
149 
     | 
    
         
             
            - ".github/workflows/main.yml"
         
     | 
| 
       119 
150 
     | 
    
         
             
            - ".gitignore"
         
     | 
| 
       120 
151 
     | 
    
         
             
            - ".rspec"
         
     | 
| 
         @@ -135,7 +166,7 @@ files: 
     | 
|
| 
       135 
166 
     | 
    
         
             
            - snfoil-context.gemspec
         
     | 
| 
       136 
167 
     | 
    
         
             
            homepage: https://github.com/limited-effort/snfoil-context
         
     | 
| 
       137 
168 
     | 
    
         
             
            licenses:
         
     | 
| 
       138 
     | 
    
         
            -
            -  
     | 
| 
      
 169 
     | 
    
         
            +
            - Apache-2.0
         
     | 
| 
       139 
170 
     | 
    
         
             
            metadata:
         
     | 
| 
       140 
171 
     | 
    
         
             
              homepage_uri: https://github.com/limited-effort/snfoil-context
         
     | 
| 
       141 
172 
     | 
    
         
             
              source_code_uri: https://github.com/limited-effort/snfoil-context
         
     |