activeinteractor 2.0.0.alpha.2.1.0 → 2.0.0.alpha.2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/active_interactor/base.rb +39 -38
- data/lib/active_interactor/context/attribute.rb +47 -0
- data/lib/active_interactor/context/attribute_assignment.rb +58 -0
- data/lib/active_interactor/context/attribute_registration.rb +27 -0
- data/lib/active_interactor/context/attribute_set.rb +35 -0
- data/lib/active_interactor/context/base.rb +30 -0
- data/lib/active_interactor/context/input.rb +19 -0
- data/lib/active_interactor/context/output.rb +27 -0
- data/lib/active_interactor/context/runtime.rb +54 -0
- data/lib/active_interactor/context.rb +16 -0
- data/lib/active_interactor/has_active_model_errors.rb +28 -0
- data/lib/active_interactor/result.rb +13 -10
- data/lib/active_interactor.rb +2 -0
- metadata +14 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e288a5c77ab45d9b0009db2a3d1a2997bd577207bb20f16386c8aa29be50f454
|
4
|
+
data.tar.gz: 6e045fd1af8f93d2f22aeed4d96ddb44ac93f83cce65ea9237da3e2de3d167db
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e22e0efcf6e53c4c70cf1b30e7871b17de7ebf13933779b989b40119ce3628eab3ade0228f1f3bbf96e7976440661cb0d4b8ec8d09f7af64d56074bf15e47ed1
|
7
|
+
data.tar.gz: 7cef976acbe9bfd3ef6a9e7d24237587d4a51220b5c08b8595cdfa4522ae6e84aba8903c6ab5fadb97d1529529fb216a00eab92adc171cc3c997eb0f05c7cdda
|
@@ -3,8 +3,20 @@
|
|
3
3
|
module ActiveInteractor
|
4
4
|
class Base
|
5
5
|
class << self
|
6
|
-
|
7
|
-
|
6
|
+
delegate :argument, :argument_names, :arguments, to: :input_context_class
|
7
|
+
delegate :returns, :field_names, :fields, to: :output_context_class
|
8
|
+
|
9
|
+
def input_context_class
|
10
|
+
@input_context_class ||= const_set(:InputContext, Class.new(Context::Input))
|
11
|
+
end
|
12
|
+
|
13
|
+
def accepts_arguments_matching(set_input_context_class)
|
14
|
+
@input_context_class = set_input_context_class
|
15
|
+
end
|
16
|
+
alias input_context accepts_arguments_matching
|
17
|
+
|
18
|
+
def output_context_class
|
19
|
+
@output_context_class ||= const_set(:OutputContext, Class.new(Context::Output))
|
8
20
|
end
|
9
21
|
|
10
22
|
def perform!(input_context = {})
|
@@ -19,26 +31,31 @@ module ActiveInteractor
|
|
19
31
|
Result.failure(errors: e.message)
|
20
32
|
end
|
21
33
|
|
22
|
-
def
|
23
|
-
|
34
|
+
def returns_data_matching(set_output_context_class)
|
35
|
+
@output_context_class = set_output_context_class
|
24
36
|
end
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
37
|
+
alias output_context returns_data_matching
|
38
|
+
|
39
|
+
def runtime_context_class
|
40
|
+
@runtime_context_class ||= begin
|
41
|
+
context_class = const_set(:RuntimeContext, Class.new(Context::Runtime))
|
42
|
+
context_class.send(:attribute_set).merge(input_context_class.send(:attribute_set).attributes)
|
43
|
+
context_class.send(:attribute_set).merge(output_context_class.send(:attribute_set).attributes)
|
44
|
+
context_class
|
45
|
+
end
|
30
46
|
end
|
31
47
|
end
|
32
48
|
|
33
49
|
def initialize(input = {})
|
34
|
-
@
|
35
|
-
|
50
|
+
@raw_input = input.dup
|
51
|
+
validate_input_and_generate_runtime_context!
|
36
52
|
end
|
37
53
|
|
38
54
|
def perform!
|
39
55
|
with_notification(:perform) do |payload|
|
40
56
|
interact
|
41
|
-
|
57
|
+
generate_and_validate_output_context!
|
58
|
+
payload[:result] = Result.success(data: @output)
|
42
59
|
end
|
43
60
|
end
|
44
61
|
|
@@ -68,36 +85,20 @@ module ActiveInteractor
|
|
68
85
|
raise Error, result
|
69
86
|
end
|
70
87
|
|
71
|
-
def
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
hash[name] = @input[name] || options[:default]
|
76
|
-
end
|
77
|
-
|
78
|
-
raise Error, Result.failure(errors: errors, status: Result::STATUS[:failed_on_input]) unless errors.empty?
|
79
|
-
|
80
|
-
context
|
81
|
-
end
|
82
|
-
|
83
|
-
def parse_output!
|
84
|
-
errors = {}
|
85
|
-
context = self.class.send(:attributes)[:fields].each_with_object({}) do |(name, options), hash|
|
86
|
-
errors = validate_attribute_value(self.context[name], name, options, errors)
|
87
|
-
hash[name] = self.context[name] || options[:default]
|
88
|
-
end
|
89
|
-
|
90
|
-
raise Error, Result.failure(errors: errors, status: Result::STATUS[:failed_on_output]) unless errors.empty?
|
88
|
+
def generate_and_validate_output_context!
|
89
|
+
@output = self.class.output_context_class.new(context.attributes)
|
90
|
+
@output.validate!
|
91
|
+
return @output if @output.errors.empty?
|
91
92
|
|
92
|
-
|
93
|
+
raise Error, Result.failure(errors: @output.errors, status: Result::STATUS[:failed_at_output])
|
93
94
|
end
|
94
95
|
|
95
|
-
def
|
96
|
-
|
96
|
+
def validate_input_and_generate_runtime_context!
|
97
|
+
@input = self.class.input_context_class.new(@raw_input)
|
98
|
+
@input.validate!
|
99
|
+
return (@context = self.class.runtime_context_class.new(@raw_input)) if @input.errors.empty?
|
97
100
|
|
98
|
-
errors
|
99
|
-
errors[attribute_name] << :blank
|
100
|
-
errors
|
101
|
+
raise Error, Result.failure(errors: @input.errors, status: Result::STATUS[:failed_at_input])
|
101
102
|
end
|
102
103
|
|
103
104
|
def with_notification(action)
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveInteractor
|
4
|
+
module Context
|
5
|
+
class Attribute
|
6
|
+
NO_DEFAULT_VALUE = :__no_default_value__
|
7
|
+
attr_reader :description, :error_messages, :name
|
8
|
+
|
9
|
+
def initialize(owner, name, type, description = nil, **options)
|
10
|
+
@owner = owner
|
11
|
+
@name = name.to_sym
|
12
|
+
@type_expression = type
|
13
|
+
@description = description || options[:description]
|
14
|
+
@options = { required: false, default: NO_DEFAULT_VALUE }.merge(options)
|
15
|
+
@error_messages = []
|
16
|
+
end
|
17
|
+
|
18
|
+
def assign_value(value)
|
19
|
+
@user_provided_value = value
|
20
|
+
end
|
21
|
+
|
22
|
+
def default_value
|
23
|
+
return if @options[:default] == NO_DEFAULT_VALUE
|
24
|
+
|
25
|
+
@options[:default]
|
26
|
+
end
|
27
|
+
|
28
|
+
def required?
|
29
|
+
@options[:required]
|
30
|
+
end
|
31
|
+
|
32
|
+
def type
|
33
|
+
@type_expression
|
34
|
+
end
|
35
|
+
|
36
|
+
def validate!
|
37
|
+
return true unless required? && value.nil?
|
38
|
+
|
39
|
+
error_messages << :blank
|
40
|
+
end
|
41
|
+
|
42
|
+
def value
|
43
|
+
@user_provided_value || default_value
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveInteractor
|
4
|
+
module Context
|
5
|
+
module AttributeAssignment
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
def [](attribute_name)
|
9
|
+
read_attribute_value(attribute_name)
|
10
|
+
end
|
11
|
+
|
12
|
+
def []=(attribute_name, value)
|
13
|
+
assign_attribute_value(attribute_name, value)
|
14
|
+
end
|
15
|
+
|
16
|
+
protected
|
17
|
+
|
18
|
+
def assign_attribute_value(attribute_name, value)
|
19
|
+
attribute = attribute_set.find(attribute_name)
|
20
|
+
raise NoMethodError, "unknown attribute '#{attribute_name}' for #{self.class.name}" unless attribute
|
21
|
+
|
22
|
+
attribute.assign_value(value)
|
23
|
+
end
|
24
|
+
|
25
|
+
def assignment_method_missing(method_name, *arguments)
|
26
|
+
if arguments.length != 1
|
27
|
+
raise ArgumentError,
|
28
|
+
"wrong number of arguments (given #{arguments.length}, expected 1)"
|
29
|
+
end
|
30
|
+
|
31
|
+
assign_attribute_value(method_name, arguments.first)
|
32
|
+
end
|
33
|
+
|
34
|
+
def method_missing(method_id, *arguments)
|
35
|
+
return super unless respond_to_missing?(method_id)
|
36
|
+
|
37
|
+
method_name = method_id[/.*(?==\z)/m]
|
38
|
+
return assignment_method_missing(method_name, *arguments) if method_name
|
39
|
+
|
40
|
+
read_attribute_value(method_id)
|
41
|
+
end
|
42
|
+
|
43
|
+
def read_attribute_value(attribute_name)
|
44
|
+
attribute = attribute_set.find(attribute_name)
|
45
|
+
raise NoMethodError, "unknown attribute '#{attribute_name}' for #{self.class.name}" unless attribute
|
46
|
+
|
47
|
+
attribute.value
|
48
|
+
end
|
49
|
+
|
50
|
+
def respond_to_missing?(method_name, _include_private = false)
|
51
|
+
return true if attribute_set.attribute_names.include?(method_name.to_sym)
|
52
|
+
return true if attribute_set.attribute_names.include?(method_name[/.*(?==\z)/m]&.to_sym)
|
53
|
+
|
54
|
+
super
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveInteractor
|
4
|
+
module Context
|
5
|
+
module AttributeRegistration
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
protected
|
10
|
+
|
11
|
+
def attribute_set
|
12
|
+
@attribute_set ||= AttributeSet.new(self)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
included do
|
17
|
+
extend ClassMethods
|
18
|
+
end
|
19
|
+
|
20
|
+
protected
|
21
|
+
|
22
|
+
def attribute_set
|
23
|
+
@attribute_set ||= AttributeSet.new(self, *self.class.send(:attribute_set).attributes.map(&:dup))
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveInteractor
|
4
|
+
module Context
|
5
|
+
class AttributeSet
|
6
|
+
def initialize(owner, *attributes)
|
7
|
+
@owner = owner
|
8
|
+
@set = {}
|
9
|
+
attributes.each { |attribute| @set[attribute.name] = attribute }
|
10
|
+
end
|
11
|
+
|
12
|
+
def add(*attribute_args)
|
13
|
+
attribute_options = attribute_args.extract_options!
|
14
|
+
attribute = Attribute.new(@owner, *attribute_args, **attribute_options)
|
15
|
+
@set[attribute.name] = attribute
|
16
|
+
end
|
17
|
+
|
18
|
+
def attribute_names
|
19
|
+
@set.keys
|
20
|
+
end
|
21
|
+
|
22
|
+
def attributes
|
23
|
+
@set.values
|
24
|
+
end
|
25
|
+
|
26
|
+
def find(attribute_name)
|
27
|
+
@set[attribute_name.to_sym]
|
28
|
+
end
|
29
|
+
|
30
|
+
def merge(attributes)
|
31
|
+
attributes.each { |attribute| @set[attribute.name] = attribute }
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveInteractor
|
4
|
+
module Context
|
5
|
+
class Base
|
6
|
+
include ActiveModel::Validations
|
7
|
+
include HasActiveModelErrors
|
8
|
+
include AttributeRegistration
|
9
|
+
include AttributeAssignment
|
10
|
+
|
11
|
+
attr_reader :errors
|
12
|
+
|
13
|
+
def initialize(attributes = {})
|
14
|
+
@errors = ActiveModel::Errors.new(self)
|
15
|
+
attribute_set.attributes.each do |attribute|
|
16
|
+
next unless attributes.with_indifferent_access.key?(attribute.name)
|
17
|
+
|
18
|
+
assign_attribute_value(attribute.name, attributes.with_indifferent_access[attribute.name])
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def validate!
|
23
|
+
attribute_set.attributes.each do |attribute|
|
24
|
+
attribute.validate!
|
25
|
+
attribute.error_messages.each { |message| errors.add(attribute.name, message) }
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveInteractor
|
4
|
+
module Context
|
5
|
+
class Input < Base
|
6
|
+
def self.argument(*attribute_args)
|
7
|
+
attribute_set.add(*attribute_args)
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.argument_names
|
11
|
+
attribute_set.attribute_names
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.arguments
|
15
|
+
attribute_set.attributes
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveInteractor
|
4
|
+
module Context
|
5
|
+
class Output < Base
|
6
|
+
delegate :to_h, :to_hash, :to_json, to: :fields
|
7
|
+
|
8
|
+
def self.returns(*attribute_args)
|
9
|
+
attribute_set.add(*attribute_args)
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.field_names
|
13
|
+
attribute_set.attribute_names
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.fields
|
17
|
+
attribute_set.attributes
|
18
|
+
end
|
19
|
+
|
20
|
+
def fields
|
21
|
+
attribute_set.attributes.each_with_object({}) do |attribute, result|
|
22
|
+
result[attribute.name] = attribute.value
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveInteractor
|
4
|
+
module Context
|
5
|
+
class Runtime < Base
|
6
|
+
def initialize(attributes = {})
|
7
|
+
super
|
8
|
+
@table = {}
|
9
|
+
end
|
10
|
+
|
11
|
+
def attributes
|
12
|
+
clean = attribute_set.attributes.each_with_object({}) do |attribute, result|
|
13
|
+
result[attribute.name] = attribute.value
|
14
|
+
end
|
15
|
+
@table.merge(clean)
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def assign_attribute_value(attribute_name, value)
|
21
|
+
attribute = attribute_set.find(attribute_name)
|
22
|
+
return super if attribute
|
23
|
+
|
24
|
+
assign_dirty_attribute_value(attribute_name, value)
|
25
|
+
end
|
26
|
+
|
27
|
+
def assign_dirty_attribute_value(attribute_name, value)
|
28
|
+
@table[attribute_name.to_sym] = value
|
29
|
+
end
|
30
|
+
|
31
|
+
def method_missing(method_id, *arguments)
|
32
|
+
method_name = method_id[/.*(?==\z)/m]
|
33
|
+
return assignment_method_missing(method_name, *arguments) if method_name
|
34
|
+
|
35
|
+
read_attribute_value(method_id)
|
36
|
+
end
|
37
|
+
|
38
|
+
def read_attribute_value(attribute_name)
|
39
|
+
attribute = attribute_set.find(attribute_name)
|
40
|
+
return super if attribute
|
41
|
+
|
42
|
+
read_dirty_attribute_value(attribute_name)
|
43
|
+
end
|
44
|
+
|
45
|
+
def read_dirty_attribute_value(attribute_name)
|
46
|
+
@table[attribute_name.to_sym]
|
47
|
+
end
|
48
|
+
|
49
|
+
def respond_to_missing?(_method_name, _include_private = false)
|
50
|
+
true
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveInteractor
|
4
|
+
module Context
|
5
|
+
extend ActiveSupport::Autoload
|
6
|
+
|
7
|
+
autoload :Attribute
|
8
|
+
autoload :AttributeRegistration
|
9
|
+
autoload :AttributeSet
|
10
|
+
autoload :AttributeAssignment
|
11
|
+
autoload :Base
|
12
|
+
autoload :Input
|
13
|
+
autoload :Output
|
14
|
+
autoload :Runtime
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveInteractor
|
4
|
+
module HasActiveModelErrors
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
module ClassMethods
|
8
|
+
def self.human_attribute_name(attribute, _options = {})
|
9
|
+
attribute.respond_to?(:to_s) ? attribute.to_s.humanize : attribute
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.lookup_ancestors
|
13
|
+
[self]
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
included do
|
18
|
+
extend ActiveModel::Naming
|
19
|
+
extend ClassMethods
|
20
|
+
|
21
|
+
attr_reader :errors
|
22
|
+
end
|
23
|
+
|
24
|
+
def read_attribute_for_validation(attribute_name)
|
25
|
+
send(attribute_name.to_sym)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -2,7 +2,9 @@
|
|
2
2
|
|
3
3
|
module ActiveInteractor
|
4
4
|
class Result
|
5
|
-
|
5
|
+
include HasActiveModelErrors
|
6
|
+
|
7
|
+
delegate :to_json, to: :to_hash
|
6
8
|
|
7
9
|
STATUS = {
|
8
10
|
success: 0,
|
@@ -26,14 +28,6 @@ module ActiveInteractor
|
|
26
28
|
result
|
27
29
|
end
|
28
30
|
|
29
|
-
def human_attribute_name(attribute, _options = {})
|
30
|
-
attribute.respond_to?(:to_s) ? attribute.to_s.humanize : attribute
|
31
|
-
end
|
32
|
-
|
33
|
-
def lookup_ancestors
|
34
|
-
[self]
|
35
|
-
end
|
36
|
-
|
37
31
|
private
|
38
32
|
|
39
33
|
def parse_errors(errors)
|
@@ -62,12 +56,21 @@ module ActiveInteractor
|
|
62
56
|
alias failed? failure?
|
63
57
|
|
64
58
|
def read_attribute_for_validation(attribute_name)
|
65
|
-
data
|
59
|
+
data.send(attribute_name.to_sym)
|
66
60
|
end
|
67
61
|
|
68
62
|
def success?
|
69
63
|
@status == STATUS[:success]
|
70
64
|
end
|
71
65
|
alias successful? success?
|
66
|
+
|
67
|
+
def to_hash
|
68
|
+
{
|
69
|
+
success: success?,
|
70
|
+
errors: errors.to_hash,
|
71
|
+
data: data.to_hash
|
72
|
+
}
|
73
|
+
end
|
74
|
+
alias to_h to_hash
|
72
75
|
end
|
73
76
|
end
|
data/lib/active_interactor.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activeinteractor
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.0.alpha.2.
|
4
|
+
version: 2.0.0.alpha.2.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Aaron Allen
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-10-
|
11
|
+
date: 2023-10-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activemodel
|
@@ -64,7 +64,17 @@ files:
|
|
64
64
|
- README.md
|
65
65
|
- lib/active_interactor.rb
|
66
66
|
- lib/active_interactor/base.rb
|
67
|
+
- lib/active_interactor/context.rb
|
68
|
+
- lib/active_interactor/context/attribute.rb
|
69
|
+
- lib/active_interactor/context/attribute_assignment.rb
|
70
|
+
- lib/active_interactor/context/attribute_registration.rb
|
71
|
+
- lib/active_interactor/context/attribute_set.rb
|
72
|
+
- lib/active_interactor/context/base.rb
|
73
|
+
- lib/active_interactor/context/input.rb
|
74
|
+
- lib/active_interactor/context/output.rb
|
75
|
+
- lib/active_interactor/context/runtime.rb
|
67
76
|
- lib/active_interactor/errors.rb
|
77
|
+
- lib/active_interactor/has_active_model_errors.rb
|
68
78
|
- lib/active_interactor/result.rb
|
69
79
|
- sig/active_interactor.rbs
|
70
80
|
homepage: https://github.com/activeinteractor/activeinteractor
|
@@ -72,9 +82,9 @@ licenses:
|
|
72
82
|
- MIT
|
73
83
|
metadata:
|
74
84
|
bug_tracker_uri: https://github.com/activeinteractor/activeinteractor/issues
|
75
|
-
changelog_uri: https://github.com/activeinteractor/activeinteractor/blob/v2.0.0-alpha.2.
|
85
|
+
changelog_uri: https://github.com/activeinteractor/activeinteractor/blob/v2.0.0-alpha.2.2.0/CHANGELOG.md
|
76
86
|
homepage_uri: https://github.com/activeinteractor/activeinteractor
|
77
|
-
source_code_uri: https://github.com/activeinteractor/activeinteractor/tree/v2.0.0-alpha.2.
|
87
|
+
source_code_uri: https://github.com/activeinteractor/activeinteractor/tree/v2.0.0-alpha.2.2.0
|
78
88
|
wiki_uri: https://github.com/activeinteractor/activeinteractor/wiki
|
79
89
|
rubygems_mfa_required: 'true'
|
80
90
|
post_install_message:
|