thalamus 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +12 -0
- data/.travis.yml +5 -0
- data/Gemfile +2 -0
- data/Guardfile +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +123 -0
- data/Rakefile +11 -0
- data/bin/console +7 -0
- data/bin/setup +8 -0
- data/lib/thalamus/interactor/result.rb +64 -0
- data/lib/thalamus/interactor.rb +101 -0
- data/lib/thalamus/policy.rb +17 -0
- data/lib/thalamus/version.rb +3 -0
- data/lib/thalamus.rb +6 -0
- data/thalamus.gemspec +33 -0
- metadata +185 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 822ad009daebff4c13eac447e6724b0f2206641e
|
4
|
+
data.tar.gz: bd1d9d475aff1910b645372f2c88d9e900ec9d06
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: f1bcd0fc04e006f5116ed0348ed3fc5789e57d432562725eafb479b94325140edc250f5f460472c58fe4f2a422285478550614681f51770da511bab8d334b3c3
|
7
|
+
data.tar.gz: 3bbd55cca05ce32b5112dc5bd573c5c54bd50a38d497b8c00da3133310f7dc33f83250412c1bd00cf394e4c2e7db79cf9981e8769cbad03f8dacedb2d0e0a84a
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Guardfile
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
guard :minitest do
|
2
|
+
watch(%r{^test/(.*)\/?(.*)_test\.rb$})
|
3
|
+
watch(%r{^lib/(.*/)?([^/]+)\.rb$}) { |m| "test/#{m[1]}#{m[2]}_test.rb" }
|
4
|
+
watch(%r{^lib((/\w+)+)/\w+.rb$}) { |m| "test#{m[1]}_test.rb" }
|
5
|
+
watch(%r{^lib/\w+\.rb$}) { 'test' }
|
6
|
+
watch(%r{^test/test_helper\.rb$}) { 'test' }
|
7
|
+
end
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2017 Josh Greenberg
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,123 @@
|
|
1
|
+
# Thalamus
|
2
|
+
|
3
|
+
**Thalamus** is a simple implementation of the interactor pattern. It encourages SOLID(ish) design, in particular the separation of business logic from implementation logic. Thin files, fat directories!
|
4
|
+
|
5
|
+
Thalamus is heavily inspired by [Hanami::Interactor](https://github.com/hanami/utils) and, in many ways, is just a more opinionated version.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Come on now.
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
gem 'thalamus'#, github: 'joshgreenberg/thalamus'
|
13
|
+
```
|
14
|
+
```bash
|
15
|
+
bundle install
|
16
|
+
```
|
17
|
+
|
18
|
+
## Usage
|
19
|
+
|
20
|
+
```ruby
|
21
|
+
class DoSomething < Thalamus::Interactor
|
22
|
+
def call
|
23
|
+
perform_side_effects
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
def perform_side_effects
|
28
|
+
# ...
|
29
|
+
end
|
30
|
+
end
|
31
|
+
```
|
32
|
+
|
33
|
+
Call `DoSomething.call(payload)` from anywhere - a controller, an API endpoint, a task or job, the command line, another interactor, etc. This is the _only_ entry point from your app's implementation details to the business logic.
|
34
|
+
|
35
|
+
Note that you invoke with `Interactor.call` but define behaviour with `Interactor#call`.
|
36
|
+
|
37
|
+
### Input
|
38
|
+
|
39
|
+
The input payload must be a hash and is immutable. Symbolized keys are preferred. The hash content may take two forms:
|
40
|
+
|
41
|
+
- `{params: {foo: 'bar'}, current_user: User.new}` is recommended. `:params` must be structured like a JSON object. Often, implementation in the controller will look like `Interactor.call(params: http_request_body, current_user: authenticated_user)`.
|
42
|
+
- `{foo: 'bar', current_user: User.new}` is also accepted. Special fields will be extracted and will _not_ be passed to `:params`. Special fields include:
|
43
|
+
+ `:current_user` (see Authorization)
|
44
|
+
|
45
|
+
### Authorization
|
46
|
+
|
47
|
+
```ruby
|
48
|
+
class EatCheese < Thalamus::Interactor
|
49
|
+
policy PunditStylePolicy, :eat?
|
50
|
+
def call
|
51
|
+
# ...
|
52
|
+
end
|
53
|
+
end
|
54
|
+
```
|
55
|
+
|
56
|
+
If a policy is defined, `.call` will extract `payload[:current_user]` (which should be an entity) and run it through the policy. If the policy fails, the interactor will fail immediately.
|
57
|
+
|
58
|
+
### Validation
|
59
|
+
|
60
|
+
Thalamus depends on [dry-rb](http://dry-rb.org/gems/dry-validation) and [Hanami::Validations](https://github.com/hanami/validations):
|
61
|
+
|
62
|
+
```ruby
|
63
|
+
class Blah < Thalamus::Interactor
|
64
|
+
validations do
|
65
|
+
# ...
|
66
|
+
end
|
67
|
+
def call
|
68
|
+
# ...
|
69
|
+
end
|
70
|
+
end
|
71
|
+
```
|
72
|
+
|
73
|
+
Validations will be run on `payload[:params]` after authorization and before execution. Running validations first ensures that your business logic will never be working with invalid input.
|
74
|
+
|
75
|
+
You can override the default validation logic. Overriding `#valid?` will ignore the `validations` block.
|
76
|
+
|
77
|
+
```ruby
|
78
|
+
class Foo < Thalamus::Interactor
|
79
|
+
def call
|
80
|
+
# ...
|
81
|
+
end
|
82
|
+
private
|
83
|
+
def valid?
|
84
|
+
# boolean expression
|
85
|
+
end
|
86
|
+
end
|
87
|
+
```
|
88
|
+
|
89
|
+
### Execution
|
90
|
+
|
91
|
+
This is where you work with domain entities - and as a best practice, this should be the outermost layer _in your entire application_ where you work with them. (User authentication in the router or controller is the only exception, and even then you should only be exposing credentials outside of the business domain.) `#call` will only be run if the interactor is both authorized and valid, enforcing permitted access and changes.
|
92
|
+
|
93
|
+
`#error!(message)` triggers a failure and aborts the interactor.
|
94
|
+
|
95
|
+
`#params` provides a copy of the sanitized input after it has been processed by the validator. It cannot be modified - see below to mutate return data.
|
96
|
+
|
97
|
+
### Output
|
98
|
+
|
99
|
+
An interactor returns an instance of Thalamus::Result. It responds to the following instance methods:
|
100
|
+
|
101
|
+
- `status` => Symbol in `[:success, :unauthorized, :invalid, :failure]`
|
102
|
+
+ `success?` => Boolean, results are successful if no errors are raised
|
103
|
+
+ `unauthorized?` => Boolean
|
104
|
+
+ `invalid?` => Boolean
|
105
|
+
+ `failure?` => Boolean, equivalent of `!success?`
|
106
|
+
- `errors` => Array of `Interactor#error!(message)`
|
107
|
+
- `validation_errors` => Hash of error messages from dry-validation, organized by key
|
108
|
+
|
109
|
+
Any other name starting with a lowercase letter can be exposed to the result object:
|
110
|
+
|
111
|
+
```ruby
|
112
|
+
class CreateBook < Thalamus::Interactor
|
113
|
+
expose :book
|
114
|
+
|
115
|
+
def call
|
116
|
+
@book = Book.create({})
|
117
|
+
end
|
118
|
+
end
|
119
|
+
```
|
120
|
+
|
121
|
+
Whatever is at `@book` is now available at `Result#book`.
|
122
|
+
|
123
|
+
It is up to the developer to enforce boundaries appropriately. You must decide which data to expose outside of the interactor, and which layer is responsible for converting it. For example, you may wish to convert an entity to JSON for an API response, but when calling an interactor from somewhere else you may find it more useful to return a richer object. You may decide to handle JSON conversions in the controller - the interactor is the layer that modifies data, but there is no conversion mechanism because it is agnostic to how it is stored.
|
data/Rakefile
ADDED
data/bin/console
ADDED
data/bin/setup
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
module Thalamus
|
2
|
+
class Interactor
|
3
|
+
class Result
|
4
|
+
|
5
|
+
def expose!(exposures)
|
6
|
+
@exposures = exposures
|
7
|
+
self
|
8
|
+
end
|
9
|
+
|
10
|
+
def finish!(status, errors = [], validation_errors = {})
|
11
|
+
@status = status
|
12
|
+
@errors = errors
|
13
|
+
@validation_errors = validation_errors
|
14
|
+
self
|
15
|
+
end
|
16
|
+
attr_reader :status, :errors, :validation_errors
|
17
|
+
|
18
|
+
def success? # 200 or 201
|
19
|
+
@status == :success && errors.empty?
|
20
|
+
end
|
21
|
+
|
22
|
+
def unauthorized? # 403
|
23
|
+
@status == :unauthorized
|
24
|
+
end
|
25
|
+
|
26
|
+
def invalid? # 422
|
27
|
+
@status == :invalid
|
28
|
+
end
|
29
|
+
|
30
|
+
def failure? # catch-all
|
31
|
+
!success?
|
32
|
+
end
|
33
|
+
|
34
|
+
def response
|
35
|
+
if success?
|
36
|
+
@exposures
|
37
|
+
elsif unauthorized?
|
38
|
+
{errors: ["UNAUTHORIZED"]}
|
39
|
+
elsif invalid?
|
40
|
+
validation_errors
|
41
|
+
elsif failure?
|
42
|
+
{errors: errors}
|
43
|
+
else
|
44
|
+
raise "[Thalamus] Invalid result status: #{status}"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
protected
|
49
|
+
|
50
|
+
def method_missing(m, *args, &block)
|
51
|
+
if m.to_s =~ /^[a-z]/
|
52
|
+
(@exposures || {}).fetch(m) { super }
|
53
|
+
else
|
54
|
+
super
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def respond_to_missing?(m, include_private = false)
|
59
|
+
m.to_s =~ /^[a-z]/ && @exposures.key?(m)
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
require 'hanami/validations/form'
|
2
|
+
require 'thalamus/interactor/result'
|
3
|
+
|
4
|
+
module Thalamus
|
5
|
+
class Interactor
|
6
|
+
include Hanami::Validations::Form
|
7
|
+
|
8
|
+
def initialize(payload = {})
|
9
|
+
@current_user = payload.delete(:current_user)
|
10
|
+
@_params = payload.delete(:params) || payload
|
11
|
+
@_errors = []
|
12
|
+
end
|
13
|
+
attr_reader :current_user, :model
|
14
|
+
|
15
|
+
def params
|
16
|
+
@_params.dup
|
17
|
+
end
|
18
|
+
|
19
|
+
def _call
|
20
|
+
status = catch :status do
|
21
|
+
# Authorization
|
22
|
+
if tuple = self.class._policy
|
23
|
+
klass, policy = tuple
|
24
|
+
fail!(:unauthorized) unless klass.new(current_user, model).send(policy)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Validation
|
28
|
+
fail!(:invalid) unless valid?
|
29
|
+
|
30
|
+
# Execution
|
31
|
+
call
|
32
|
+
:success
|
33
|
+
end
|
34
|
+
result = Result.new.expose!(_exposures)
|
35
|
+
.finish!(status, @_errors, @_validation_errors)
|
36
|
+
yield result if block_given? && result.success?
|
37
|
+
result
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def error!(msg = '')
|
43
|
+
@_errors << msg
|
44
|
+
fail!
|
45
|
+
end
|
46
|
+
|
47
|
+
def fail!(status = :failure)
|
48
|
+
throw :status, status
|
49
|
+
end
|
50
|
+
|
51
|
+
def valid?
|
52
|
+
if schema = self.class.schema
|
53
|
+
r = schema.call(@_params)
|
54
|
+
@_params = r.output
|
55
|
+
@_validation_errors = r.errors
|
56
|
+
r.success?
|
57
|
+
else
|
58
|
+
true
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def _exposures
|
63
|
+
exposures = self.class.exposures || {}
|
64
|
+
exposures.map do |ivar|
|
65
|
+
[ivar, instance_variable_get("@#{ivar}")]
|
66
|
+
end.to_h
|
67
|
+
end
|
68
|
+
|
69
|
+
class << self
|
70
|
+
private :new
|
71
|
+
|
72
|
+
def call(payload = {}, &block) # Public entry point
|
73
|
+
new(payload)._call(&block)
|
74
|
+
end
|
75
|
+
|
76
|
+
attr_reader :_policy, :exposures
|
77
|
+
|
78
|
+
private # Class-level DSL
|
79
|
+
|
80
|
+
def policy(klass, policy)
|
81
|
+
@_policy = [klass, policy]
|
82
|
+
end
|
83
|
+
|
84
|
+
def schema_type(type)
|
85
|
+
@_schema_type = type
|
86
|
+
end
|
87
|
+
|
88
|
+
def _schema_type
|
89
|
+
@_schema_type || super
|
90
|
+
end
|
91
|
+
|
92
|
+
def expose(*ivars)
|
93
|
+
ivars.each do |ivar|
|
94
|
+
@exposures ||= []
|
95
|
+
@exposures << ivar.to_sym
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Thalamus
|
2
|
+
class Policy
|
3
|
+
attr_reader :user, :model
|
4
|
+
|
5
|
+
def initialize(user, model)
|
6
|
+
@user, @model = user, model
|
7
|
+
end
|
8
|
+
|
9
|
+
def method_missing(m, *args, &block)
|
10
|
+
m.to_s[-1] == '?' ? false : super
|
11
|
+
end
|
12
|
+
|
13
|
+
def respond_to_missing?(m, include_private = false)
|
14
|
+
m.to_s[-1] == '?' || super
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/lib/thalamus.rb
ADDED
data/thalamus.gemspec
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require "thalamus/version"
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "thalamus"
|
8
|
+
spec.version = Thalamus::VERSION
|
9
|
+
spec.authors = ["Josh Greenberg"]
|
10
|
+
spec.email = ["joshgreenberg91@gmail.com"]
|
11
|
+
|
12
|
+
spec.summary = "Interactors"
|
13
|
+
spec.description = "Interactors"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
17
|
+
f.match(%r{^(test|spec|features)/})
|
18
|
+
end
|
19
|
+
spec.bindir = "exe"
|
20
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
21
|
+
spec.require_paths = ["lib"]
|
22
|
+
|
23
|
+
spec.add_development_dependency "bundler", "~> 1.15"
|
24
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
25
|
+
spec.add_development_dependency "minitest", "~> 5.0"
|
26
|
+
spec.add_development_dependency "minitest-reporters"
|
27
|
+
spec.add_development_dependency "pry"
|
28
|
+
spec.add_development_dependency "guard"
|
29
|
+
spec.add_development_dependency "guard-minitest"
|
30
|
+
spec.add_development_dependency "rake-notes"
|
31
|
+
|
32
|
+
spec.add_dependency "hanami-validations", "~> 1.0"
|
33
|
+
end
|
metadata
ADDED
@@ -0,0 +1,185 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: thalamus
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Josh Greenberg
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-07-05 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.15'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.15'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: minitest
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '5.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '5.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: minitest-reporters
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: pry
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: guard
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: guard-minitest
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: rake-notes
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: hanami-validations
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - "~>"
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '1.0'
|
132
|
+
type: :runtime
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - "~>"
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '1.0'
|
139
|
+
description: Interactors
|
140
|
+
email:
|
141
|
+
- joshgreenberg91@gmail.com
|
142
|
+
executables: []
|
143
|
+
extensions: []
|
144
|
+
extra_rdoc_files: []
|
145
|
+
files:
|
146
|
+
- ".gitignore"
|
147
|
+
- ".travis.yml"
|
148
|
+
- Gemfile
|
149
|
+
- Guardfile
|
150
|
+
- LICENSE.txt
|
151
|
+
- README.md
|
152
|
+
- Rakefile
|
153
|
+
- bin/console
|
154
|
+
- bin/setup
|
155
|
+
- lib/thalamus.rb
|
156
|
+
- lib/thalamus/interactor.rb
|
157
|
+
- lib/thalamus/interactor/result.rb
|
158
|
+
- lib/thalamus/policy.rb
|
159
|
+
- lib/thalamus/version.rb
|
160
|
+
- thalamus.gemspec
|
161
|
+
homepage:
|
162
|
+
licenses:
|
163
|
+
- MIT
|
164
|
+
metadata: {}
|
165
|
+
post_install_message:
|
166
|
+
rdoc_options: []
|
167
|
+
require_paths:
|
168
|
+
- lib
|
169
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
170
|
+
requirements:
|
171
|
+
- - ">="
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: '0'
|
174
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
175
|
+
requirements:
|
176
|
+
- - ">="
|
177
|
+
- !ruby/object:Gem::Version
|
178
|
+
version: '0'
|
179
|
+
requirements: []
|
180
|
+
rubyforge_project:
|
181
|
+
rubygems_version: 2.6.8
|
182
|
+
signing_key:
|
183
|
+
specification_version: 4
|
184
|
+
summary: Interactors
|
185
|
+
test_files: []
|