activeinteractor 1.0.0.beta.7 → 1.0.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/.yardopts +12 -0
- data/CHANGELOG.md +50 -158
- data/README.md +13 -856
- data/lib/active_interactor.rb +61 -4
- data/lib/active_interactor/base.rb +26 -20
- data/lib/active_interactor/config.rb +36 -18
- data/lib/active_interactor/configurable.rb +17 -9
- data/lib/active_interactor/context/attributes.rb +73 -26
- data/lib/active_interactor/context/base.rb +236 -65
- data/lib/active_interactor/context/loader.rb +20 -15
- data/lib/active_interactor/context/status.rb +38 -56
- data/lib/active_interactor/error.rb +15 -7
- data/lib/active_interactor/interactor/callbacks.rb +174 -160
- data/lib/active_interactor/interactor/context.rb +279 -87
- data/lib/active_interactor/interactor/perform.rb +256 -0
- data/lib/active_interactor/interactor/worker.rb +19 -14
- data/lib/active_interactor/models.rb +65 -0
- data/lib/active_interactor/organizer/base.rb +18 -0
- data/lib/active_interactor/organizer/callbacks.rb +153 -0
- data/lib/active_interactor/organizer/interactor_interface.rb +38 -26
- data/lib/active_interactor/organizer/interactor_interface_collection.rb +35 -32
- data/lib/active_interactor/organizer/organize.rb +67 -0
- data/lib/active_interactor/organizer/perform.rb +93 -0
- data/lib/active_interactor/rails.rb +0 -10
- data/lib/active_interactor/rails/orm/active_record.rb +1 -1
- data/lib/active_interactor/rails/railtie.rb +8 -11
- data/lib/active_interactor/version.rb +2 -1
- data/lib/rails/generators/active_interactor.rb +1 -38
- data/lib/rails/generators/active_interactor/application_context_generator.rb +21 -0
- data/lib/rails/generators/active_interactor/application_interactor_generator.rb +5 -15
- data/lib/rails/generators/active_interactor/application_organizer_generator.rb +21 -0
- data/lib/rails/generators/active_interactor/base.rb +29 -0
- data/lib/rails/generators/active_interactor/generator.rb +21 -0
- data/lib/rails/generators/active_interactor/install_generator.rb +2 -9
- data/lib/rails/generators/interactor/context/rspec_generator.rb +3 -10
- data/lib/rails/generators/interactor/context/test_unit_generator.rb +4 -11
- data/lib/rails/generators/interactor/context_generator.rb +7 -10
- data/lib/rails/generators/interactor/generates_context.rb +28 -0
- data/lib/rails/generators/interactor/interactor_generator.rb +8 -10
- data/lib/rails/generators/interactor/organizer_generator.rb +8 -12
- data/lib/rails/generators/interactor/rspec_generator.rb +2 -9
- data/lib/rails/generators/interactor/test_unit_generator.rb +3 -10
- data/lib/rails/generators/{active_interactor/templates/initializer.erb → templates/active_interactor.erb} +3 -11
- data/lib/rails/generators/{active_interactor/templates → templates}/application_context.rb +0 -0
- data/lib/rails/generators/{active_interactor/templates → templates}/application_interactor.rb +0 -0
- data/lib/rails/generators/templates/application_organizer.rb +4 -0
- data/lib/rails/generators/{interactor/templates → templates}/context.erb +0 -0
- data/lib/rails/generators/{interactor/context/templates/rspec.erb → templates/context_spec.erb} +0 -0
- data/lib/rails/generators/{interactor/context/templates/test_unit.erb → templates/context_test_unit.erb} +0 -0
- data/lib/rails/generators/{interactor/templates → templates}/interactor.erb +0 -0
- data/lib/rails/generators/{interactor/templates/rspec.erb → templates/interactor_spec.erb} +0 -0
- data/lib/rails/generators/{interactor/templates/test_unit.erb → templates/interactor_text_unit.erb} +0 -0
- data/lib/rails/generators/{interactor/templates → templates}/organizer.erb +0 -0
- data/spec/active_interactor/base_spec.rb +3 -3
- data/spec/active_interactor/interactor/{perform_options_spec.rb → perform/options_spec.rb} +1 -1
- data/spec/active_interactor/interactor/worker_spec.rb +14 -15
- data/spec/active_interactor/{organizer_spec.rb → organizer/base_spec.rb} +27 -17
- data/spec/integration/a_basic_interactor_spec.rb +106 -0
- data/spec/integration/a_basic_organizer_spec.rb +97 -0
- data/spec/integration/a_failing_interactor_spec.rb +42 -0
- data/spec/integration/active_record_integration_spec.rb +9 -9
- data/spec/integration/an_interactor_with_after_context_validation_callbacks_spec.rb +69 -0
- data/spec/integration/an_interactor_with_after_perform_callbacks_spec.rb +30 -0
- data/spec/integration/an_interactor_with_after_rollback_callbacks_spec.rb +33 -0
- data/spec/integration/an_interactor_with_an_existing_context_class_spec.rb +49 -0
- data/spec/integration/an_interactor_with_around_perform_callbacks_spec.rb +35 -0
- data/spec/integration/an_interactor_with_around_rollback_callbacks_spec.rb +39 -0
- data/spec/integration/an_interactor_with_before_perform_callbacks_spec.rb +30 -0
- data/spec/integration/an_interactor_with_before_rollback_callbacks_spec.rb +33 -0
- data/spec/integration/an_interactor_with_validations_on_called_spec.rb +40 -0
- data/spec/integration/an_interactor_with_validations_on_calling_spec.rb +36 -0
- data/spec/integration/an_interactor_with_validations_spec.rb +93 -0
- data/spec/integration/an_organizer_performing_in_parallel_spec.rb +48 -0
- data/spec/integration/an_organizer_with_after_each_callbacks_spec.rb +34 -0
- data/spec/integration/an_organizer_with_around_each_callbacks_spec.rb +39 -0
- data/spec/integration/an_organizer_with_before_each_callbacks_spec.rb +34 -0
- data/spec/integration/an_organizer_with_conditionally_organized_interactors_spec.rb +314 -0
- data/spec/spec_helper.rb +8 -12
- data/spec/support/coverage.rb +4 -0
- data/spec/support/coverage/reporters.rb +11 -0
- data/spec/support/coverage/reporters/codacy.rb +39 -0
- data/spec/support/coverage/reporters/simple_cov.rb +54 -0
- data/spec/support/coverage/runner.rb +66 -0
- data/spec/support/helpers/factories.rb +1 -1
- data/spec/support/shared_examples/a_class_with_interactor_callback_methods_example.rb +8 -8
- data/spec/support/shared_examples/a_class_with_interactor_context_methods_example.rb +5 -5
- data/spec/support/shared_examples/a_class_with_interactor_methods_example.rb +2 -2
- data/spec/support/shared_examples/a_class_with_organizer_callback_methods_example.rb +3 -3
- metadata +83 -40
- data/lib/active_interactor/interactor.rb +0 -84
- data/lib/active_interactor/interactor/perform_options.rb +0 -29
- data/lib/active_interactor/organizer.rb +0 -269
- data/lib/active_interactor/rails/config.rb +0 -45
- data/lib/active_interactor/rails/models.rb +0 -58
- data/lib/rails/generators/active_interactor/templates/application_organizer.rb +0 -4
- data/spec/active_interactor/rails/config_spec.rb +0 -29
- data/spec/active_interactor/rails_spec.rb +0 -24
- data/spec/integration/basic_callback_integration_spec.rb +0 -355
- data/spec/integration/basic_context_integration_spec.rb +0 -73
- data/spec/integration/basic_integration_spec.rb +0 -570
- data/spec/integration/basic_validations_integration_spec.rb +0 -204
data/lib/active_interactor.rb
CHANGED
@@ -1,10 +1,31 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'active_model'
|
4
|
+
require 'active_support/callbacks'
|
5
|
+
require 'active_support/core_ext/array/extract_options'
|
6
|
+
require 'active_support/core_ext/class/attribute'
|
7
|
+
require 'active_support/core_ext/string/inflections'
|
3
8
|
require 'active_support/dependencies/autoload'
|
9
|
+
require 'logger'
|
10
|
+
require 'ostruct'
|
4
11
|
|
5
|
-
require 'active_interactor/
|
12
|
+
require 'active_interactor/configurable'
|
6
13
|
require 'active_interactor/config'
|
14
|
+
require 'active_interactor/version'
|
7
15
|
|
16
|
+
# An {Base interactor} is a simple, single-purpose service object. {Base Interactors} can be used to reduce the
|
17
|
+
# responsibility of your controllers, workers, and models and encapsulate your application's
|
18
|
+
# {https://en.wikipedia.org/wiki/Business_logic business logic}. Each {Base interactor} represents one thing that your
|
19
|
+
# application does.
|
20
|
+
#
|
21
|
+
# Each {Base interactor} has it's own immutable {Context::Base context} which contains everything the
|
22
|
+
# {Base interactor} needs to do its work. When an {Base interactor} does its single purpose, it affects its given
|
23
|
+
# {Context::Base context}.
|
24
|
+
#
|
25
|
+
# @see https://github.com/aaronmallen/activeinteractor/wiki Usage
|
26
|
+
#
|
27
|
+
# ## License
|
28
|
+
#
|
8
29
|
# Copyright (c) 2019 Aaron Allen
|
9
30
|
#
|
10
31
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
@@ -29,18 +50,54 @@ module ActiveInteractor
|
|
29
50
|
|
30
51
|
autoload :Base
|
31
52
|
|
32
|
-
#
|
53
|
+
# {Context::Base Context} classes and modules
|
54
|
+
#
|
55
|
+
# @see https://github.com/aaronmallen/activeinteractor/wiki/Context Context
|
56
|
+
#
|
33
57
|
# @author Aaron Allen <hello@aaronmallen.me>
|
34
|
-
# @since 0.0
|
58
|
+
# @since 0.1.0
|
35
59
|
module Context
|
36
60
|
extend ActiveSupport::Autoload
|
37
61
|
|
62
|
+
autoload :Attributes
|
38
63
|
autoload :Base
|
39
64
|
autoload :Loader
|
40
65
|
autoload :Status
|
41
66
|
end
|
42
67
|
|
43
|
-
|
68
|
+
# {Base Interactor} classes and modules
|
69
|
+
#
|
70
|
+
# @see https://github.com/aaronmallen/activeinteractor/wiki/Interactors Interactors
|
71
|
+
#
|
72
|
+
# @author Aaron Allen <hello@aaronmallen.me>
|
73
|
+
# @since 0.1.0
|
74
|
+
module Interactor
|
75
|
+
extend ActiveSupport::Autoload
|
76
|
+
|
77
|
+
autoload :Callbacks
|
78
|
+
autoload :Context
|
79
|
+
autoload :Perform
|
80
|
+
autoload :Worker
|
81
|
+
end
|
82
|
+
|
83
|
+
autoload :Models
|
84
|
+
|
85
|
+
# {Organizer::Base Organizer} classes and modules
|
86
|
+
#
|
87
|
+
# @see https://github.com/aaronmallen/activeinteractor/wiki/Interactors#organizers Organizers
|
88
|
+
#
|
89
|
+
# @author Aaron Allen <hello@aaronmallen.me>
|
90
|
+
# @since 0.1.0
|
91
|
+
module Organizer
|
92
|
+
extend ActiveSupport::Autoload
|
93
|
+
|
94
|
+
autoload :Base
|
95
|
+
autoload :Callbacks
|
96
|
+
autoload :InteractorInterface
|
97
|
+
autoload :InteractorInterfaceCollection
|
98
|
+
autoload :Organize
|
99
|
+
autoload :Perform
|
100
|
+
end
|
44
101
|
|
45
102
|
eager_autoload do
|
46
103
|
autoload :Error
|
@@ -1,29 +1,35 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'active_interactor/interactor'
|
4
|
-
|
5
3
|
module ActiveInteractor
|
6
|
-
# The base
|
7
|
-
#
|
4
|
+
# The base class all {Base interactors} should inherit from.
|
5
|
+
#
|
6
|
+
# When {Base} is loaded by your application an
|
7
|
+
# {https://api.rubyonrails.org/classes/ActiveSupport/LazyLoadHooks.html ActiveSupport load hook} is called
|
8
|
+
# with `:active_interactor` and {Base}.
|
9
|
+
#
|
8
10
|
# @author Aaron Allen <hello@aaronmallen.me>
|
9
|
-
# @since 0.0
|
10
|
-
# @example a basic interactor
|
11
|
-
# class MyInteractor < ActiveInteractor::Base
|
12
|
-
# def perform
|
13
|
-
# context.called = true
|
14
|
-
# end
|
15
|
-
# end
|
11
|
+
# @since 0.1.0
|
16
12
|
#
|
17
|
-
#
|
18
|
-
#
|
13
|
+
# @example a basic {Base interactor}
|
14
|
+
# class MyInteractor < ActiveInteractor::Base
|
15
|
+
# def perform
|
16
|
+
# # TODO: implement the perform method
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
# def rollback
|
20
|
+
# # TODO: implement the rollback method
|
21
|
+
# end
|
22
|
+
# end
|
19
23
|
class Base
|
20
|
-
|
24
|
+
extend ActiveInteractor::Interactor::Callbacks::ClassMethods
|
25
|
+
extend ActiveInteractor::Interactor::Context::ClassMethods
|
26
|
+
extend ActiveInteractor::Interactor::Perform::ClassMethods
|
21
27
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
self.class.new(context.dup)
|
27
|
-
end
|
28
|
+
include ActiveSupport::Callbacks
|
29
|
+
include ActiveInteractor::Interactor::Callbacks
|
30
|
+
include ActiveInteractor::Interactor::Context
|
31
|
+
include ActiveInteractor::Interactor::Perform
|
28
32
|
end
|
33
|
+
|
34
|
+
ActiveSupport.run_load_hooks(:active_interactor, Base)
|
29
35
|
end
|
@@ -1,41 +1,59 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'logger'
|
4
|
-
|
5
|
-
require 'active_interactor/configurable'
|
6
|
-
|
7
3
|
module ActiveInteractor
|
8
4
|
# The ActiveInteractor configuration object
|
5
|
+
#
|
9
6
|
# @author Aaron Allen <hello@aaronmallen.me>
|
10
7
|
# @since 1.0.0
|
8
|
+
#
|
11
9
|
# @!attribute [rw] logger
|
12
|
-
#
|
10
|
+
# The logger instance to use for logging.
|
11
|
+
#
|
12
|
+
# @since 1.0.0
|
13
|
+
#
|
14
|
+
# @return [Class] an instance of Logger.
|
15
|
+
#
|
16
|
+
# @!method initialize(options = {})
|
17
|
+
# Initialize a new instance of {Config}
|
18
|
+
#
|
19
|
+
# @since 1.0.0
|
20
|
+
#
|
21
|
+
# @param options [Hash{Symbol=>*}] the attributes to assign to {Config}
|
22
|
+
# @option options [Class] :logger (Logger.new(STDOUT)) the {Config#logger} attribute
|
23
|
+
# @return [Config] a new instance of {Config}
|
13
24
|
class Config
|
14
|
-
include Configurable
|
25
|
+
include ActiveInteractor::Configurable
|
15
26
|
defaults logger: Logger.new(STDOUT)
|
16
27
|
end
|
17
28
|
|
18
29
|
# The ActiveInteractor configuration
|
19
|
-
#
|
20
|
-
# @
|
30
|
+
#
|
31
|
+
# @since 0.1.0
|
32
|
+
#
|
33
|
+
# @return [Config] a {Config} instance
|
21
34
|
def self.config
|
22
|
-
@config ||= Config.new
|
35
|
+
@config ||= ActiveInteractor::Config.new
|
23
36
|
end
|
24
37
|
|
25
|
-
#
|
26
|
-
#
|
38
|
+
# Configure the ActiveInteractor gem
|
39
|
+
#
|
40
|
+
# @since 0.1.0
|
41
|
+
#
|
27
42
|
# @example Configure ActiveInteractor
|
28
|
-
#
|
29
|
-
#
|
30
|
-
#
|
31
|
-
#
|
43
|
+
# require 'active_interactor'
|
44
|
+
# ActiveInteractor.configure do |config|
|
45
|
+
# config.logger = ::Rails.logger
|
46
|
+
# end
|
47
|
+
# @yield [#config]
|
32
48
|
def self.configure
|
33
49
|
yield config
|
34
50
|
end
|
35
51
|
|
36
|
-
# The
|
37
|
-
#
|
38
|
-
# @
|
52
|
+
# The logger instance to use for logging
|
53
|
+
#
|
54
|
+
# @since 0.1.0
|
55
|
+
#
|
56
|
+
# @return [Class] the {Config#logger #config#logger} instance
|
39
57
|
def self.logger
|
40
58
|
config.logger
|
41
59
|
end
|
@@ -1,9 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'active_support/core_ext/class/attribute'
|
4
|
-
|
5
3
|
module ActiveInteractor
|
6
|
-
#
|
4
|
+
# Configurable object methods. Because {Configurable} is a module classes should include {Configurable} rather than
|
5
|
+
# inherit from it.
|
6
|
+
#
|
7
|
+
# @api private
|
7
8
|
# @author Aaron Allen <hello@aaronmallen.me>
|
8
9
|
# @since 1.0.0
|
9
10
|
module Configurable
|
@@ -13,11 +14,18 @@ module ActiveInteractor
|
|
13
14
|
end
|
14
15
|
end
|
15
16
|
|
16
|
-
#
|
17
|
+
# Configurable object class methods. Because {ClassMethods} is a module classes should extend {ClassMethods} rather
|
18
|
+
# than inherit from it.
|
19
|
+
#
|
20
|
+
# @api private
|
21
|
+
# @author Aaron Allen <hello@aaronmallen.me>
|
22
|
+
# @since 1.0.0
|
17
23
|
module ClassMethods
|
18
|
-
#
|
19
|
-
#
|
20
|
-
#
|
24
|
+
# Get or Set the default attributes for a {Configurable} class. This method will create an `attr_accessor` on
|
25
|
+
# the configurable class as well as set a default value for the attribute.
|
26
|
+
#
|
27
|
+
# @param options [Hash{Symbol=>*}, nil] the default options to set on the {Configurable} class
|
28
|
+
# @return [Hash{Symbol=>*}] the passed options or the set defaults if no options are passed.
|
21
29
|
def defaults(options = {})
|
22
30
|
return __defaults if options.empty?
|
23
31
|
|
@@ -34,8 +42,8 @@ module ActiveInteractor
|
|
34
42
|
end
|
35
43
|
end
|
36
44
|
|
37
|
-
#
|
38
|
-
# @
|
45
|
+
# nodoc #
|
46
|
+
# @private
|
39
47
|
def initialize(options = {})
|
40
48
|
self.class.defaults.merge(options).each do |key, value|
|
41
49
|
instance_variable_set("@#{key}", value)
|
@@ -2,31 +2,34 @@
|
|
2
2
|
|
3
3
|
module ActiveInteractor
|
4
4
|
module Context
|
5
|
-
# Context attribute methods
|
5
|
+
# Context attribute methods. Because {Attributes} is a module classes should include {Attributes} rather than
|
6
|
+
# inherit from it.
|
7
|
+
#
|
6
8
|
# @author Aaron Allen <hello@aaronmallen.me>
|
7
9
|
# @since 0.1.4
|
8
10
|
module Attributes
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
# Context attribute class methods extended by all {Context::Base}
|
11
|
+
# Context attribute class methods. Because {ClassMethods} is a module classes should extend {ClassMethods} rather
|
12
|
+
# than inherit from it.
|
13
|
+
#
|
14
|
+
# @author Aaron Allen <hello@aaronmallen.me>
|
15
|
+
# @since 0.1.4
|
16
16
|
module ClassMethods
|
17
|
-
#
|
18
|
-
#
|
19
|
-
#
|
17
|
+
# Get or set attributes on a {Base context} class
|
18
|
+
#
|
19
|
+
# @example Set attributes on a {Base context} class
|
20
|
+
# class MyContext < ActiveInteractor::Context::Base
|
20
21
|
# attributes :first_name, :last_name
|
21
22
|
# end
|
22
|
-
#
|
23
|
-
#
|
24
|
-
#
|
23
|
+
#
|
24
|
+
# @example Get attributes defined on a {Base context} class
|
25
|
+
# MyContext.attributes
|
26
|
+
# #=> [:first_name, :last_name]
|
27
|
+
#
|
25
28
|
# @return [Array<Symbol>] the defined attributes
|
26
29
|
def attributes(*attributes)
|
27
30
|
return __attributes if attributes.empty?
|
28
31
|
|
29
|
-
@__attributes = __attributes.concat(attributes).compact.uniq.sort
|
32
|
+
@__attributes = __attributes.concat(attributes.map(&:to_sym)).compact.uniq.sort
|
30
33
|
end
|
31
34
|
|
32
35
|
private
|
@@ -36,27 +39,71 @@ module ActiveInteractor
|
|
36
39
|
end
|
37
40
|
end
|
38
41
|
|
39
|
-
#
|
40
|
-
# @example Get attributes defined on an instance
|
41
|
-
# class MyInteractor::Context < ActiveInteractor::Context::Base
|
42
|
-
# attributes :first_name, :last_name
|
43
|
-
# end
|
42
|
+
# Initialize a new instance of {Base}
|
44
43
|
#
|
45
|
-
#
|
46
|
-
#
|
44
|
+
# @param context [Hash, Base, Class] attributes to assign to the {Base context}
|
45
|
+
# @return [Base] a new instance of {Base}
|
46
|
+
def initialize(context = {})
|
47
|
+
merge_errors!(context.errors) if context.respond_to?(:errors)
|
48
|
+
copy_flags!(context)
|
49
|
+
copy_called!(context)
|
50
|
+
super
|
51
|
+
end
|
52
|
+
|
53
|
+
# Get values defined on the instance of {Base context} whose keys are defined on the {Base context} class'
|
54
|
+
# {ClassMethods#attributes .attributes}
|
55
|
+
#
|
56
|
+
# @example Get attributes defined on an instance of {Base context}
|
57
|
+
# class MyContext < ActiveInteractor::Context::Base
|
58
|
+
# attributes :first_name, :last_name
|
47
59
|
# end
|
48
60
|
#
|
49
|
-
#
|
50
|
-
# #=> <#
|
61
|
+
# context = MyContext.new(first_name: 'Aaron', last_name: 'Allen', occupation: 'Ruby Nerd')
|
62
|
+
# #=> <#MyContext first_name='Aaron' last_name='Allen' occupation='Ruby Nerd')
|
51
63
|
#
|
52
|
-
#
|
64
|
+
# context.attributes
|
53
65
|
# #=> { first_name: 'Aaron', last_name: 'Allen' }
|
54
|
-
#
|
66
|
+
#
|
67
|
+
# context.occupation
|
68
|
+
# #=> 'Ruby Nerd'
|
69
|
+
#
|
70
|
+
# @return [Hash{Symbol => *}] the defined attributes and values
|
55
71
|
def attributes
|
56
72
|
self.class.attributes.each_with_object({}) do |attribute, hash|
|
57
73
|
hash[attribute] = self[attribute] if self[attribute]
|
58
74
|
end
|
59
75
|
end
|
76
|
+
|
77
|
+
# Merge an instance of {Base context} into the calling {Base context} instance
|
78
|
+
#
|
79
|
+
# @since 1.0.0
|
80
|
+
#
|
81
|
+
# @example
|
82
|
+
# context = MyContext.new(first_name: 'Aaron', last_name: 'Allen')
|
83
|
+
# other_context = MyContext.new(last_name: 'Awesome')
|
84
|
+
# context.merge!(other_context)
|
85
|
+
# #=> <#MyContext first_name='Aaron' last_name='Awesome'>
|
86
|
+
#
|
87
|
+
# @param context [Class] a {Base context} instance to be merged
|
88
|
+
# @return [self] the {Base context} instance
|
89
|
+
def merge!(context)
|
90
|
+
merge_errors!(context.errors) if context.respond_to?(:errors)
|
91
|
+
copy_flags!(context)
|
92
|
+
context.each_pair do |key, value|
|
93
|
+
self[key] = value unless value.nil?
|
94
|
+
end
|
95
|
+
self
|
96
|
+
end
|
97
|
+
|
98
|
+
private
|
99
|
+
|
100
|
+
def merge_errors!(errors)
|
101
|
+
if errors.is_a? String
|
102
|
+
self.errors.add(:context, errors)
|
103
|
+
else
|
104
|
+
self.errors.merge!(errors)
|
105
|
+
end
|
106
|
+
end
|
60
107
|
end
|
61
108
|
end
|
62
109
|
end
|
@@ -1,75 +1,246 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'active_model'
|
4
|
-
require 'ostruct'
|
5
|
-
|
6
|
-
require 'active_interactor/context/attributes'
|
7
|
-
|
8
3
|
module ActiveInteractor
|
9
4
|
module Context
|
10
|
-
# The base context class
|
11
|
-
#
|
5
|
+
# The base {Base context} class all {Base context} objects should inherit from.
|
6
|
+
#
|
12
7
|
# @author Aaron Allen <hello@aaronmallen.me>
|
13
|
-
# @since 0.0
|
8
|
+
# @since 0.1.0
|
9
|
+
#
|
10
|
+
# @!method attribute_method?(attribute)
|
11
|
+
# @!scope class
|
12
|
+
# @since 0.1.0
|
13
|
+
# @see
|
14
|
+
# https://api.rubyonrails.org/classes/ActiveModel/Validations/ClassMethods.html#method-i-attribute_method-3F
|
15
|
+
# ActiveModel::Validations::ClassMethods#attribute_method?
|
16
|
+
#
|
17
|
+
# @!method clear_validators!(attribute)
|
18
|
+
# @!scope class
|
19
|
+
# @since 0.1.0
|
20
|
+
# @see
|
21
|
+
# https://api.rubyonrails.org/classes/ActiveModel/Validations/ClassMethods.html#method-i-clear_validators-21
|
22
|
+
# ActiveModel::Validations::ClassMethods#clear_validators!
|
23
|
+
#
|
24
|
+
# @!method validate(*args, &block)
|
25
|
+
# @!scope class
|
26
|
+
# @since 0.1.0
|
27
|
+
# @see
|
28
|
+
# https://api.rubyonrails.org/classes/ActiveModel/Validations/ClassMethods.html#method-i-validate
|
29
|
+
# ActiveModel::Validations::ClassMethods#validate
|
30
|
+
#
|
31
|
+
# @!method validates(*attributes)
|
32
|
+
# @!scope class
|
33
|
+
# @since 0.1.0
|
34
|
+
# @see
|
35
|
+
# https://api.rubyonrails.org/classes/ActiveModel/Validations/ClassMethods.html#method-i-validates
|
36
|
+
# ActiveModel::Validations::ClassMethods#validates
|
37
|
+
#
|
38
|
+
# @!method validates!(*attributes)
|
39
|
+
# @!scope class
|
40
|
+
# @since 0.1.0
|
41
|
+
# @see
|
42
|
+
# https://api.rubyonrails.org/classes/ActiveModel/Validations/ClassMethods.html#method-i-validates-21
|
43
|
+
# ActiveModel::Validations::ClassMethods#validates!
|
44
|
+
#
|
45
|
+
# @!method validates_absence_of(*attr_names)
|
46
|
+
# @!scope class
|
47
|
+
# @since 0.1.0
|
48
|
+
# @see
|
49
|
+
# https://api.rubyonrails.org/classes/ActiveModel/Validations/HelperMethods.html#method-i-validates_absence_of
|
50
|
+
# ActiveModel::Validations::HelperMethods#validates_absence_of
|
51
|
+
#
|
52
|
+
# @!method validates_acceptance_of(*attr_names)
|
53
|
+
# @!scope class
|
54
|
+
# @since 0.1.0
|
55
|
+
# @see
|
56
|
+
# https://api.rubyonrails.org/classes/ActiveModel/Validations/HelperMethods.html#method-i-validates_acceptance_of
|
57
|
+
# ActiveModel::Validations::HelperMethods#validates_acceptance_of
|
58
|
+
#
|
59
|
+
# @!method validates_confirmation_of(*attr_names)
|
60
|
+
# @!scope class
|
61
|
+
# @since 0.1.0
|
62
|
+
# @see
|
63
|
+
# https://api.rubyonrails.org/classes/ActiveModel/Validations/HelperMethods.html#method-i-validates_confirmation_of
|
64
|
+
# ActiveModel::Validations::HelperMethods#validates_confirmation_of
|
65
|
+
#
|
66
|
+
# @!method validates_each(*attr_names, &block)
|
67
|
+
# @!scope class
|
68
|
+
# @since 0.1.0
|
69
|
+
# @see
|
70
|
+
# https://api.rubyonrails.org/classes/ActiveModel/Validations/ClassMethods.html#method-i-validates_each
|
71
|
+
# ActiveModel::Validations::ClassMethods#validates_each
|
72
|
+
#
|
73
|
+
# @!method validates_exclusion_of(*attr_names)
|
74
|
+
# @!scope class
|
75
|
+
# @since 0.1.0
|
76
|
+
# @see
|
77
|
+
# https://api.rubyonrails.org/classes/ActiveModel/Validations/HelperMethods.html#method-i-validates_exclusion_of
|
78
|
+
# ActiveModel::Validations::HelperMethods#validates_exclusion_of
|
79
|
+
#
|
80
|
+
# @!method validates_format_of(*attr_names)
|
81
|
+
# @!scope class
|
82
|
+
# @since 0.1.0
|
83
|
+
# @see
|
84
|
+
# https://api.rubyonrails.org/classes/ActiveModel/Validations/HelperMethods.html#method-i-validates_format_of
|
85
|
+
# ActiveModel::Validations::HelperMethods#validates_format_of
|
86
|
+
#
|
87
|
+
# @!method validates_inclusion_of(*attr_names)
|
88
|
+
# @!scope class
|
89
|
+
# @since 0.1.0
|
90
|
+
# @see
|
91
|
+
# https://api.rubyonrails.org/classes/ActiveModel/Validations/HelperMethods.html#method-i-validates_inclusion_of
|
92
|
+
# ActiveModel::Validations::HelperMethods#validates_inclusion_of
|
93
|
+
#
|
94
|
+
# @!method validates_length_of(*attr_names)
|
95
|
+
# @!scope class
|
96
|
+
# @since 0.1.0
|
97
|
+
# @see
|
98
|
+
# https://api.rubyonrails.org/classes/ActiveModel/Validations/HelperMethods.html#method-i-validates_length_of
|
99
|
+
# ActiveModel::Validations::HelperMethods#validates_length_of
|
100
|
+
#
|
101
|
+
# @!method validates_numericality_of(*attr_names)
|
102
|
+
# @!scope class
|
103
|
+
# @since 0.1.0
|
104
|
+
# @see
|
105
|
+
# https://api.rubyonrails.org/classes/ActiveModel/Validations/HelperMethods.html#method-i-validates_numericality_of
|
106
|
+
# ActiveModel::Validations::HelperMethods#validates_numericality_of
|
107
|
+
#
|
108
|
+
# @!method validates_presence_of(*attr_names)
|
109
|
+
# @!scope class
|
110
|
+
# @since 0.1.0
|
111
|
+
# @see
|
112
|
+
# https://api.rubyonrails.org/classes/ActiveModel/Validations/HelperMethods.html#method-i-validates_presence_of
|
113
|
+
# ActiveModel::Validations::HelperMethods#validates_presence_of
|
114
|
+
#
|
115
|
+
# @!method validates_size_of(*attr_names)
|
116
|
+
# @!scope class
|
117
|
+
# @since 0.1.0
|
118
|
+
# @see
|
119
|
+
# https://api.rubyonrails.org/classes/ActiveModel/Validations/HelperMethods.html#method-i-validates_size_of
|
120
|
+
# ActiveModel::Validations::HelperMethods#validates_size_of
|
121
|
+
#
|
122
|
+
# @!method validates_with(*args, &block)
|
123
|
+
# @!scope class
|
124
|
+
# @since 0.1.0
|
125
|
+
# @see
|
126
|
+
# https://api.rubyonrails.org/classes/ActiveModel/Validations/ClassMethods.html#method-i-validates_with
|
127
|
+
# ActiveModel::Validations::ClassMethods#validates_with
|
128
|
+
#
|
129
|
+
# @!method validators
|
130
|
+
# @!scope class
|
131
|
+
# @since 0.1.0
|
132
|
+
# @see
|
133
|
+
# https://api.rubyonrails.org/classes/ActiveModel/Validations/ClassMethods.html#method-i-validators
|
134
|
+
# ActiveModel::Validations::ClassMethods#validators
|
135
|
+
#
|
136
|
+
# @!method validators_on(*attributes)
|
137
|
+
# @!scope class
|
138
|
+
# @since 0.1.0
|
139
|
+
# @see
|
140
|
+
# https://api.rubyonrails.org/classes/ActiveModel/Validations/ClassMethods.html#method-i-validators_on
|
141
|
+
# ActiveModel::Validations::ClassMethods#validators_on
|
142
|
+
#
|
143
|
+
# @!method errors
|
144
|
+
# @since 0.1.0
|
145
|
+
# @see
|
146
|
+
# https://api.rubyonrails.org/classes/ActiveModel/Validations.html#method-i-errors
|
147
|
+
# ActiveModel::Validations#errors
|
148
|
+
#
|
149
|
+
# @!method invalid?(context = nil)
|
150
|
+
# @since 0.1.0
|
151
|
+
# @see
|
152
|
+
# https://api.rubyonrails.org/classes/ActiveModel/Validations.html#method-i-invalid-3F
|
153
|
+
# ActiveModel::Validations#invalid?
|
154
|
+
#
|
155
|
+
# @!method valid?(context = nil)
|
156
|
+
# @since 0.1.0
|
157
|
+
# @see
|
158
|
+
# https://api.rubyonrails.org/classes/ActiveModel/Validations.html#method-i-valid-3F
|
159
|
+
# ActiveModel::Validations#valid?
|
160
|
+
#
|
161
|
+
# @!method validate(context = nil)
|
162
|
+
# @since 0.1.0
|
163
|
+
# @see
|
164
|
+
# https://api.rubyonrails.org/classes/ActiveModel/Validations.html#method-i-validate
|
165
|
+
# ActiveModel::Validations#validate
|
166
|
+
#
|
167
|
+
# @!method validate!(context = nil)
|
168
|
+
# @since 0.1.0
|
169
|
+
# @see
|
170
|
+
# https://api.rubyonrails.org/classes/ActiveModel/Validations.html#method-i-validate-21
|
171
|
+
# ActiveModel::Validations#validate!
|
172
|
+
#
|
173
|
+
# @!method validates_absence_of(*attr_names)
|
174
|
+
# @since 0.1.0
|
175
|
+
# @see
|
176
|
+
# https://api.rubyonrails.org/classes/ActiveModel/Validations/HelperMethods.html#method-i-validates_absence_of
|
177
|
+
# ActiveModel::Validations::HelperMethods#validates_absence_of
|
178
|
+
#
|
179
|
+
# @!method validates_acceptance_of(*attr_names)
|
180
|
+
# @since 0.1.0
|
181
|
+
# @see
|
182
|
+
# https://api.rubyonrails.org/classes/ActiveModel/Validations/HelperMethods.html#method-i-validates_acceptance_of
|
183
|
+
# ActiveModel::Validations::HelperMethods#validates_acceptance_of
|
184
|
+
#
|
185
|
+
# @!method validates_confirmation_of(*attr_names)
|
186
|
+
# @since 0.1.0
|
187
|
+
# @see
|
188
|
+
# https://api.rubyonrails.org/classes/ActiveModel/Validations/HelperMethods.html#method-i-validates_confirmation_of
|
189
|
+
# ActiveModel::Validations::HelperMethods#validates_confirmation_of
|
190
|
+
#
|
191
|
+
# @!method validates_exclusion_of(*attr_names)
|
192
|
+
# @since 0.1.0
|
193
|
+
# @see
|
194
|
+
# https://api.rubyonrails.org/classes/ActiveModel/Validations/HelperMethods.html#method-i-validates_exclusion_of
|
195
|
+
# ActiveModel::Validations::HelperMethods#validates_exclusion_of
|
196
|
+
#
|
197
|
+
# @!method validates_format_of(*attr_names)
|
198
|
+
# @since 0.1.0
|
199
|
+
# @see
|
200
|
+
# https://api.rubyonrails.org/classes/ActiveModel/Validations/HelperMethods.html#method-i-validates_format_of
|
201
|
+
# ActiveModel::Validations::HelperMethods#validates_format_of
|
202
|
+
#
|
203
|
+
# @!method validates_inclusion_of(*attr_names)
|
204
|
+
# @since 0.1.0
|
205
|
+
# @see
|
206
|
+
# https://api.rubyonrails.org/classes/ActiveModel/Validations/HelperMethods.html#method-i-validates_inclusion_of
|
207
|
+
# ActiveModel::Validations::HelperMethods#validates_inclusion_of
|
208
|
+
#
|
209
|
+
# @!method validates_length_of(*attr_names)
|
210
|
+
# @since 0.1.0
|
211
|
+
# @see
|
212
|
+
# https://api.rubyonrails.org/classes/ActiveModel/Validations/HelperMethods.html#method-i-validates_length_of
|
213
|
+
# ActiveModel::Validations::HelperMethods#validates_length_of
|
214
|
+
#
|
215
|
+
# @!method validates_numericality_of(*attr_names)
|
216
|
+
# @since 0.1.0
|
217
|
+
# @see
|
218
|
+
# https://api.rubyonrails.org/classes/ActiveModel/Validations/HelperMethods.html#method-i-validates_numericality_of
|
219
|
+
# ActiveModel::Validations::HelperMethods#validates_numericality_of
|
220
|
+
#
|
221
|
+
# @!method validates_presence_of(*attr_names)
|
222
|
+
# @since 0.1.0
|
223
|
+
# @see
|
224
|
+
# https://api.rubyonrails.org/classes/ActiveModel/Validations/HelperMethods.html#method-i-validates_presence_of
|
225
|
+
# ActiveModel::Validations::HelperMethods#validates_presence_of
|
226
|
+
#
|
227
|
+
# @!method validates_size_of(*attr_names)
|
228
|
+
# @since 0.1.0
|
229
|
+
# @see
|
230
|
+
# https://api.rubyonrails.org/classes/ActiveModel/Validations/HelperMethods.html#method-i-validates_size_of
|
231
|
+
# ActiveModel::Validations::HelperMethods#validates_size_of
|
232
|
+
#
|
233
|
+
# @!method validates_with(*args, &block)
|
234
|
+
# @since 0.1.0
|
235
|
+
# @see
|
236
|
+
# https://api.rubyonrails.org/classes/ActiveModel/Validations.html#method-i-validates_with
|
237
|
+
# ActiveModel::Validations#validates_with
|
14
238
|
class Base < OpenStruct
|
15
|
-
|
16
|
-
include Attributes
|
17
|
-
include Status
|
18
|
-
|
19
|
-
# @param context [Hash|Context::Base] attributes to assign to the context
|
20
|
-
# @return [Context::Base] a new instance of {Context::Base}
|
21
|
-
def initialize(context = {})
|
22
|
-
merge_errors!(context.errors) if context.respond_to?(:errors)
|
23
|
-
copy_flags!(context)
|
24
|
-
copy_called!(context)
|
25
|
-
super
|
26
|
-
end
|
239
|
+
extend ActiveInteractor::Context::Attributes::ClassMethods
|
27
240
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
# ActiveModel::Validations#valid?
|
32
|
-
|
33
|
-
# Merge an instance of context or a hash into an existing context
|
34
|
-
# @since 1.0.0
|
35
|
-
# @example
|
36
|
-
# class MyInteractor1 < ActiveInteractor::Base
|
37
|
-
# def perform
|
38
|
-
# context.first_name = 'Aaron'
|
39
|
-
# end
|
40
|
-
# end
|
41
|
-
#
|
42
|
-
# class MyInteractor2 < ActiveInteractor::Base
|
43
|
-
# def perform
|
44
|
-
# context.last_name = 'Allen'
|
45
|
-
# end
|
46
|
-
# end
|
47
|
-
#
|
48
|
-
# result = MyInteractor1.perform
|
49
|
-
# #=> <#MyInteractor1::Context first_name='Aaron'>
|
50
|
-
#
|
51
|
-
# result.merge!(MyInteractor2.perform)
|
52
|
-
# #=> <#MyInteractor1::Context first_name='Aaron' last_name='Allen'>
|
53
|
-
# @param context [Base|Hash] attributes to merge into the context
|
54
|
-
# @return [Base] an instance of {Base}
|
55
|
-
def merge!(context)
|
56
|
-
merge_errors!(context.errors) if context.respond_to?(:errors)
|
57
|
-
copy_flags!(context)
|
58
|
-
context.each_pair do |key, value|
|
59
|
-
self[key] = value
|
60
|
-
end
|
61
|
-
self
|
62
|
-
end
|
63
|
-
|
64
|
-
private
|
65
|
-
|
66
|
-
def merge_errors!(errors)
|
67
|
-
if errors.is_a? String
|
68
|
-
self.errors.add(:context, errors)
|
69
|
-
else
|
70
|
-
self.errors.merge!(errors)
|
71
|
-
end
|
72
|
-
end
|
241
|
+
include ActiveModel::Validations
|
242
|
+
include ActiveInteractor::Context::Attributes
|
243
|
+
include ActiveInteractor::Context::Status
|
73
244
|
end
|
74
245
|
end
|
75
246
|
end
|