interactor-strict 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.github/workflows/tests.yml +35 -0
- data/.gitignore +17 -0
- data/.rspec +3 -0
- data/.standard.yml +4 -0
- data/CHANGELOG.md +53 -0
- data/CONTRIBUTING.md +39 -0
- data/Gemfile +10 -0
- data/LICENSE.txt +48 -0
- data/README.md +64 -0
- data/Rakefile +7 -0
- data/interactor-strict.gemspec +20 -0
- data/lib/interactor/strict.rb +40 -0
- data/spec/integration_spec.rb +1777 -0
- data/spec/interactor/context_spec.rb +201 -0
- data/spec/interactor/hooks_spec.rb +358 -0
- data/spec/interactor/organizer_spec.rb +57 -0
- data/spec/interactor/strict_spec.rb +95 -0
- data/spec/interactor_spec.rb +3 -0
- data/spec/spec_helper.rb +8 -0
- data/spec/support/lint.rb +144 -0
- metadata +112 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 1a672dc50d21ef4b2abc5fb2b15dce9a76215db114b90e6e875f245257022e09
|
4
|
+
data.tar.gz: af00d3e146d703307f507db32c7fc285b62b7e5c52cbf9011e33fd4c8b5b016d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 0f5d50fc187bfa3a146df6f6aed6c1171bd6d98f8cd0c5e5ff1cb1bb6f9730849ec35a87ee09853b8d3e6b50d03d86472395ccee04af3f8161a0f4201fedca4a
|
7
|
+
data.tar.gz: fdf36277e93030d0da8be725b5d9ec4b1de057ba34c302816f830afac108f02cbd51e30883f7e7caa28ff3f884331db03cb181e2acfb2d5a76057536875d4c88
|
@@ -0,0 +1,35 @@
|
|
1
|
+
name: Run Tests
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
branches:
|
6
|
+
- "master"
|
7
|
+
- "v3"
|
8
|
+
pull_request:
|
9
|
+
branches:
|
10
|
+
- '*'
|
11
|
+
|
12
|
+
jobs:
|
13
|
+
spec:
|
14
|
+
runs-on: ubuntu-latest
|
15
|
+
|
16
|
+
strategy:
|
17
|
+
matrix:
|
18
|
+
ruby_version:
|
19
|
+
- "2.7"
|
20
|
+
- "3.0"
|
21
|
+
- "3.1"
|
22
|
+
- "3.2"
|
23
|
+
- "head"
|
24
|
+
|
25
|
+
steps:
|
26
|
+
- uses: actions/checkout@v2
|
27
|
+
|
28
|
+
- name: Set up Ruby
|
29
|
+
uses: ruby/setup-ruby@v1
|
30
|
+
with:
|
31
|
+
ruby-version: ${{ matrix.ruby_version }}
|
32
|
+
bundler-cache: true
|
33
|
+
|
34
|
+
- name: Run Tests
|
35
|
+
run: bundle exec rspec
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.standard.yml
ADDED
data/CHANGELOG.md
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
## 3.2.0 / Unreleased
|
2
|
+
* [BUGFIX] Raise failures from nested contexts [#170]
|
3
|
+
|
4
|
+
## 3.1.2 / 2019-12-29
|
5
|
+
* [BUGFIX] Fix Context#fail! on Ruby 2.7
|
6
|
+
|
7
|
+
## 3.1.1 / 2018-05-30
|
8
|
+
|
9
|
+
* [BUGFIX] Allow Context#fail! to accept a hash with string keys
|
10
|
+
* [ENHANCEMENT] Many documentation updates
|
11
|
+
|
12
|
+
## 3.1.0 / 2014-10-13
|
13
|
+
|
14
|
+
* [FEATURE] Add around hooks
|
15
|
+
|
16
|
+
## 3.0.1 / 2014-09-09
|
17
|
+
|
18
|
+
* [ENHANCEMENT] Add TomDoc code documentation
|
19
|
+
|
20
|
+
## 3.0.0 / 2014-09-07
|
21
|
+
|
22
|
+
* [FEATURE] Remove "magical" access to the context through the interactor
|
23
|
+
* [FEATURE] Manage context values via setters/getters rather than hash access
|
24
|
+
* [FEATURE] Change the primary interactor API method from "perform" to "call"
|
25
|
+
* [FEATURE] Return the mutated context rather than the interactor instance
|
26
|
+
* [FEATURE] Replace interactor setup with before and after hooks
|
27
|
+
* [FEATURE] Abort execution immediately upon interactor failure
|
28
|
+
* [ENHANCEMENT] Build a suite of realistic integration tests
|
29
|
+
* [ENHANCEMENT] Move rollback responsibility into the context
|
30
|
+
|
31
|
+
## 2.1.1 / 2014-09-30
|
32
|
+
|
33
|
+
* [FEATURE] Halt performance if the interactor fails prior
|
34
|
+
* [ENHANCEMENT] Add support for Ruby 2.1
|
35
|
+
|
36
|
+
## 2.1.0 / 2013-09-05
|
37
|
+
|
38
|
+
* [FEATURE] Roll back when an interactor within an organizer raises an error
|
39
|
+
* [BUGFIX] Ensure that context-deferred methods respect string keys
|
40
|
+
* [FEATURE] Respect context initialization from an indifferent access hash
|
41
|
+
|
42
|
+
## 2.0.1 / 2013-08-28
|
43
|
+
|
44
|
+
* [BUGFIX] Allow YAML (de)serialization by fixing interactor allocation
|
45
|
+
|
46
|
+
## 2.0.0 / 2013-08-19
|
47
|
+
|
48
|
+
* [BUGFIX] Fix rollback behavior within nested organizers
|
49
|
+
* [BUGFIX] Skip rollback for the failed interactor
|
50
|
+
|
51
|
+
## 1.0.0 / 2013-08-17
|
52
|
+
|
53
|
+
* Initial release!
|
data/CONTRIBUTING.md
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
# Contributing to Interactor
|
2
|
+
|
3
|
+
Interactor is open source and contributions from the community are encouraged!
|
4
|
+
No contribution is too small.
|
5
|
+
|
6
|
+
Please consider:
|
7
|
+
|
8
|
+
* adding a feature
|
9
|
+
* squashing a bug
|
10
|
+
* writing [documentation](http://tomdoc.org)
|
11
|
+
* reporting an issue
|
12
|
+
* fixing a typo
|
13
|
+
* correcting [style](https://github.com/styleguide/ruby)
|
14
|
+
|
15
|
+
## How do I contribute?
|
16
|
+
|
17
|
+
For the best chance of having your changes merged, please:
|
18
|
+
|
19
|
+
1. [Fork](https://github.com/collectiveidea/interactor/fork) the project.
|
20
|
+
2. [Write](http://en.wikipedia.org/wiki/Test-driven_development) a failing test.
|
21
|
+
3. [Commit](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html) changes that fix the tests.
|
22
|
+
4. [Submit](https://github.com/collectiveidea/interactor/pulls) a pull request with *at least* one animated GIF.
|
23
|
+
5. Be patient.
|
24
|
+
|
25
|
+
## Bug Reports
|
26
|
+
|
27
|
+
If you are experiencing unexpected behavior and, after having read Interactor's
|
28
|
+
documentation, are convinced this behavior is a bug, please:
|
29
|
+
|
30
|
+
1. [Search](https://github.com/collectiveidea/interactor/issues) existing issues.
|
31
|
+
2. Collect enough information to reproduce the issue:
|
32
|
+
* Interactor version
|
33
|
+
* Ruby version
|
34
|
+
* Rails version (if applicable)
|
35
|
+
* Specific setup conditions
|
36
|
+
* Description of expected behavior
|
37
|
+
* Description of actual behavior
|
38
|
+
3. [Submit](https://github.com/collectiveidea/interactor/issues/new) an issue.
|
39
|
+
4. Be patient.
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
Copyright (c) 2023 Marcelo Jacobus
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
23
|
+
Copyright (c) 2023 Marcelo Jacobus
|
24
|
+
|
25
|
+
----------------------------------------------------------------------
|
26
|
+
Original License:
|
27
|
+
----------------------------------------------------------------------
|
28
|
+
|
29
|
+
MIT License
|
30
|
+
|
31
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
32
|
+
a copy of this software and associated documentation files (the
|
33
|
+
"Software"), to deal in the Software without restriction, including
|
34
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
35
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
36
|
+
permit persons to whom the Software is furnished to do so, subject to
|
37
|
+
the following conditions:
|
38
|
+
|
39
|
+
The above copyright notice and this permission notice shall be
|
40
|
+
included in all copies or substantial portions of the Software.
|
41
|
+
|
42
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
43
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
44
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
45
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
46
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
47
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
48
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
# Interactor::Strict
|
2
|
+
|
3
|
+
A stricter version of [`Interactor`](https://github.com/collectiveidea/interactor).
|
4
|
+
|
5
|
+
[![Gem Version](https://img.shields.io/gem/v/interactor-strict.svg)](http://rubygems.org/gems/interactor-strict)
|
6
|
+
[![Build Status](https://github.com/mjacobus/interactor-strict/actions/workflows/tests.yml/badge.svg)](https://github.com/mjacobus/interactor-strict/actions/workflows/tests.yml)
|
7
|
+
[![Maintainability](https://img.shields.io/codeclimate/maintainability/mjacobus/interactor-strict.svg)](https://codeclimate.com/github/mjacobus/interactor-strict)
|
8
|
+
[![Test Coverage](https://img.shields.io/codeclimate/coverage-letter/mjacobus/interactor-strict.svg)](https://codeclimate.com/github/mjacobus/interactor-strict)
|
9
|
+
[![Ruby Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://github.com/testdouble/standard)
|
10
|
+
|
11
|
+
## Getting Started
|
12
|
+
|
13
|
+
Add interactor-strict to your Gemfile and `bundle install`.
|
14
|
+
|
15
|
+
```ruby
|
16
|
+
gem "interactor-strict"
|
17
|
+
```
|
18
|
+
|
19
|
+
## How to use
|
20
|
+
|
21
|
+
Include the `Interactor` module as well as the `Intractor::Strict`. That will allow you to use keyword arguments. The of keyword arguments is that you may not miss them, as they will be required by the interpreter. Also, you'll not need to document your params in comments, because the method signature will do that for you.
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
class SomeService
|
25
|
+
include Interactor
|
26
|
+
include Interactor::Strict # that will allow you to use keywords
|
27
|
+
|
28
|
+
def call(foo:, bar:, with_default: 'default')
|
29
|
+
context.result = [foo, bar, with_default]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
SomeService.call(foo: "the-foo", bar: "the-bar")
|
34
|
+
```
|
35
|
+
|
36
|
+
Without the strict interactor module, you would have implemented that service more or less like:
|
37
|
+
|
38
|
+
```ruby
|
39
|
+
class SomeService
|
40
|
+
include Interactor
|
41
|
+
|
42
|
+
def call
|
43
|
+
raise "missing foo" if context.foo.nil?
|
44
|
+
raise "missing bar" if context.bar.nil?
|
45
|
+
context.result = [context.foo, context.bar, context.with_default || "default"]
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
SomeService.call(foo: "the-foo", bar: "the-bar")
|
50
|
+
```
|
51
|
+
|
52
|
+
## Credits
|
53
|
+
|
54
|
+
This code started as a fork of [mjacobus/interactor](https://github.com/mjacobus/interactor).
|
55
|
+
|
56
|
+
## Disclaimer/Opinion
|
57
|
+
|
58
|
+
The Interactor gem provides a DSL for a very common design of service classes in ruby.
|
59
|
+
|
60
|
+
I don't particularly support this type of service. I don't like its design because this is not really OOP. `Service.call` is a function attached to a namespace.
|
61
|
+
|
62
|
+
Also, it imposes on your API/Interface, providing a DSL that brings no real value. You should decide how your services should be designed.
|
63
|
+
|
64
|
+
However, if you do think Interactor provides a good pattern - or you happen to work in a project that uses this heavily - you are better off with this stricter extension.
|
data/Rakefile
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require "English"
|
2
|
+
|
3
|
+
Gem::Specification.new do |spec|
|
4
|
+
spec.name = "interactor-strict"
|
5
|
+
spec.version = "1.0.0"
|
6
|
+
|
7
|
+
spec.author = "Marcelo Jacobus"
|
8
|
+
spec.email = "marcelo.jacobus@gmail.com"
|
9
|
+
spec.description = "Extends the interactor gem"
|
10
|
+
spec.summary = "Extends the interactor gem"
|
11
|
+
spec.homepage = "https://github.com/mjacobus/interactor-strict"
|
12
|
+
spec.license = "MIT"
|
13
|
+
|
14
|
+
spec.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
|
15
|
+
spec.test_files = spec.files.grep(/^spec/)
|
16
|
+
|
17
|
+
spec.add_dependency "interactor"
|
18
|
+
spec.add_development_dependency "bundler"
|
19
|
+
spec.add_development_dependency "rake"
|
20
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require "interactor"
|
2
|
+
|
3
|
+
module Interactor
|
4
|
+
module Strict
|
5
|
+
def self.included(base)
|
6
|
+
base.class_eval do
|
7
|
+
extend ClassMethods
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize(*args, **kargs)
|
12
|
+
unless args.empty?
|
13
|
+
raise ArgumentError, "wrong number of arguments (given #{args.size}, expected 0)"
|
14
|
+
end
|
15
|
+
|
16
|
+
@kargs = kargs
|
17
|
+
@context = Context.build(*args)
|
18
|
+
end
|
19
|
+
|
20
|
+
def run!
|
21
|
+
with_hooks do
|
22
|
+
call(**@kargs)
|
23
|
+
context.called!(self)
|
24
|
+
end
|
25
|
+
rescue
|
26
|
+
context.rollback!
|
27
|
+
raise
|
28
|
+
end
|
29
|
+
|
30
|
+
module ClassMethods
|
31
|
+
def call(*args, **kargs)
|
32
|
+
new(*args, **kargs).tap(&:run).context
|
33
|
+
end
|
34
|
+
|
35
|
+
def call!(*args, **kargs)
|
36
|
+
new(*args, **kargs).tap(&:run!).context
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|