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.
Files changed (102) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +12 -0
  3. data/CHANGELOG.md +50 -158
  4. data/README.md +13 -856
  5. data/lib/active_interactor.rb +61 -4
  6. data/lib/active_interactor/base.rb +26 -20
  7. data/lib/active_interactor/config.rb +36 -18
  8. data/lib/active_interactor/configurable.rb +17 -9
  9. data/lib/active_interactor/context/attributes.rb +73 -26
  10. data/lib/active_interactor/context/base.rb +236 -65
  11. data/lib/active_interactor/context/loader.rb +20 -15
  12. data/lib/active_interactor/context/status.rb +38 -56
  13. data/lib/active_interactor/error.rb +15 -7
  14. data/lib/active_interactor/interactor/callbacks.rb +174 -160
  15. data/lib/active_interactor/interactor/context.rb +279 -87
  16. data/lib/active_interactor/interactor/perform.rb +256 -0
  17. data/lib/active_interactor/interactor/worker.rb +19 -14
  18. data/lib/active_interactor/models.rb +65 -0
  19. data/lib/active_interactor/organizer/base.rb +18 -0
  20. data/lib/active_interactor/organizer/callbacks.rb +153 -0
  21. data/lib/active_interactor/organizer/interactor_interface.rb +38 -26
  22. data/lib/active_interactor/organizer/interactor_interface_collection.rb +35 -32
  23. data/lib/active_interactor/organizer/organize.rb +67 -0
  24. data/lib/active_interactor/organizer/perform.rb +93 -0
  25. data/lib/active_interactor/rails.rb +0 -10
  26. data/lib/active_interactor/rails/orm/active_record.rb +1 -1
  27. data/lib/active_interactor/rails/railtie.rb +8 -11
  28. data/lib/active_interactor/version.rb +2 -1
  29. data/lib/rails/generators/active_interactor.rb +1 -38
  30. data/lib/rails/generators/active_interactor/application_context_generator.rb +21 -0
  31. data/lib/rails/generators/active_interactor/application_interactor_generator.rb +5 -15
  32. data/lib/rails/generators/active_interactor/application_organizer_generator.rb +21 -0
  33. data/lib/rails/generators/active_interactor/base.rb +29 -0
  34. data/lib/rails/generators/active_interactor/generator.rb +21 -0
  35. data/lib/rails/generators/active_interactor/install_generator.rb +2 -9
  36. data/lib/rails/generators/interactor/context/rspec_generator.rb +3 -10
  37. data/lib/rails/generators/interactor/context/test_unit_generator.rb +4 -11
  38. data/lib/rails/generators/interactor/context_generator.rb +7 -10
  39. data/lib/rails/generators/interactor/generates_context.rb +28 -0
  40. data/lib/rails/generators/interactor/interactor_generator.rb +8 -10
  41. data/lib/rails/generators/interactor/organizer_generator.rb +8 -12
  42. data/lib/rails/generators/interactor/rspec_generator.rb +2 -9
  43. data/lib/rails/generators/interactor/test_unit_generator.rb +3 -10
  44. data/lib/rails/generators/{active_interactor/templates/initializer.erb → templates/active_interactor.erb} +3 -11
  45. data/lib/rails/generators/{active_interactor/templates → templates}/application_context.rb +0 -0
  46. data/lib/rails/generators/{active_interactor/templates → templates}/application_interactor.rb +0 -0
  47. data/lib/rails/generators/templates/application_organizer.rb +4 -0
  48. data/lib/rails/generators/{interactor/templates → templates}/context.erb +0 -0
  49. data/lib/rails/generators/{interactor/context/templates/rspec.erb → templates/context_spec.erb} +0 -0
  50. data/lib/rails/generators/{interactor/context/templates/test_unit.erb → templates/context_test_unit.erb} +0 -0
  51. data/lib/rails/generators/{interactor/templates → templates}/interactor.erb +0 -0
  52. data/lib/rails/generators/{interactor/templates/rspec.erb → templates/interactor_spec.erb} +0 -0
  53. data/lib/rails/generators/{interactor/templates/test_unit.erb → templates/interactor_text_unit.erb} +0 -0
  54. data/lib/rails/generators/{interactor/templates → templates}/organizer.erb +0 -0
  55. data/spec/active_interactor/base_spec.rb +3 -3
  56. data/spec/active_interactor/interactor/{perform_options_spec.rb → perform/options_spec.rb} +1 -1
  57. data/spec/active_interactor/interactor/worker_spec.rb +14 -15
  58. data/spec/active_interactor/{organizer_spec.rb → organizer/base_spec.rb} +27 -17
  59. data/spec/integration/a_basic_interactor_spec.rb +106 -0
  60. data/spec/integration/a_basic_organizer_spec.rb +97 -0
  61. data/spec/integration/a_failing_interactor_spec.rb +42 -0
  62. data/spec/integration/active_record_integration_spec.rb +9 -9
  63. data/spec/integration/an_interactor_with_after_context_validation_callbacks_spec.rb +69 -0
  64. data/spec/integration/an_interactor_with_after_perform_callbacks_spec.rb +30 -0
  65. data/spec/integration/an_interactor_with_after_rollback_callbacks_spec.rb +33 -0
  66. data/spec/integration/an_interactor_with_an_existing_context_class_spec.rb +49 -0
  67. data/spec/integration/an_interactor_with_around_perform_callbacks_spec.rb +35 -0
  68. data/spec/integration/an_interactor_with_around_rollback_callbacks_spec.rb +39 -0
  69. data/spec/integration/an_interactor_with_before_perform_callbacks_spec.rb +30 -0
  70. data/spec/integration/an_interactor_with_before_rollback_callbacks_spec.rb +33 -0
  71. data/spec/integration/an_interactor_with_validations_on_called_spec.rb +40 -0
  72. data/spec/integration/an_interactor_with_validations_on_calling_spec.rb +36 -0
  73. data/spec/integration/an_interactor_with_validations_spec.rb +93 -0
  74. data/spec/integration/an_organizer_performing_in_parallel_spec.rb +48 -0
  75. data/spec/integration/an_organizer_with_after_each_callbacks_spec.rb +34 -0
  76. data/spec/integration/an_organizer_with_around_each_callbacks_spec.rb +39 -0
  77. data/spec/integration/an_organizer_with_before_each_callbacks_spec.rb +34 -0
  78. data/spec/integration/an_organizer_with_conditionally_organized_interactors_spec.rb +314 -0
  79. data/spec/spec_helper.rb +8 -12
  80. data/spec/support/coverage.rb +4 -0
  81. data/spec/support/coverage/reporters.rb +11 -0
  82. data/spec/support/coverage/reporters/codacy.rb +39 -0
  83. data/spec/support/coverage/reporters/simple_cov.rb +54 -0
  84. data/spec/support/coverage/runner.rb +66 -0
  85. data/spec/support/helpers/factories.rb +1 -1
  86. data/spec/support/shared_examples/a_class_with_interactor_callback_methods_example.rb +8 -8
  87. data/spec/support/shared_examples/a_class_with_interactor_context_methods_example.rb +5 -5
  88. data/spec/support/shared_examples/a_class_with_interactor_methods_example.rb +2 -2
  89. data/spec/support/shared_examples/a_class_with_organizer_callback_methods_example.rb +3 -3
  90. metadata +83 -40
  91. data/lib/active_interactor/interactor.rb +0 -84
  92. data/lib/active_interactor/interactor/perform_options.rb +0 -29
  93. data/lib/active_interactor/organizer.rb +0 -269
  94. data/lib/active_interactor/rails/config.rb +0 -45
  95. data/lib/active_interactor/rails/models.rb +0 -58
  96. data/lib/rails/generators/active_interactor/templates/application_organizer.rb +0 -4
  97. data/spec/active_interactor/rails/config_spec.rb +0 -29
  98. data/spec/active_interactor/rails_spec.rb +0 -24
  99. data/spec/integration/basic_callback_integration_spec.rb +0 -355
  100. data/spec/integration/basic_context_integration_spec.rb +0 -73
  101. data/spec/integration/basic_integration_spec.rb +0 -570
  102. data/spec/integration/basic_validations_integration_spec.rb +0 -204
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe 'An interactor with an existing .context_class', type: :integration do
6
+ context 'having .name "AnInteractor"' do
7
+ let(:interactor_class) { build_interactor('AnInteractor') }
8
+
9
+ include_examples 'a class with interactor methods'
10
+ include_examples 'a class with interactor callback methods'
11
+ include_examples 'a class with interactor context methods'
12
+
13
+ context 'having a class named "AnInteractorContext" with validations' do
14
+ let!(:context_class) do
15
+ build_context('AnInteractorContext') do
16
+ validates :test_field, presence: true
17
+ end
18
+ end
19
+
20
+ describe '.context_class' do
21
+ subject { interactor_class.context_class }
22
+
23
+ it { is_expected.to eq AnInteractorContext }
24
+ it { is_expected.to be < ActiveInteractor::Context::Base }
25
+ end
26
+
27
+ describe '.perform' do
28
+ subject { interactor_class.perform(context_attributes) }
29
+
30
+ context 'with valid context attributes' do
31
+ let(:context_attributes) { { test_field: 'test' } }
32
+
33
+ it { is_expected.to be_an AnInteractorContext }
34
+ it { is_expected.to be_successful }
35
+ end
36
+
37
+ context 'with invalid context attributes' do
38
+ let(:context_attributes) { {} }
39
+
40
+ it { is_expected.to be_an AnInteractorContext }
41
+ it { is_expected.to be_failure }
42
+ it 'is expected to have errors on :some_field' do
43
+ expect(subject.errors[:test_field]).not_to be_nil
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe 'An interactor with .around_perform callbacks', type: :integration do
6
+ let(:interactor_class) do
7
+ build_interactor do
8
+ around_perform :test_around_perform
9
+
10
+ def perform
11
+ context.perform_step << 2
12
+ end
13
+
14
+ private
15
+
16
+ def test_around_perform
17
+ context.perform_step = []
18
+ context.perform_step << 1
19
+ yield
20
+ context.perform_step << 3
21
+ end
22
+ end
23
+ end
24
+
25
+ include_examples 'a class with interactor methods'
26
+ include_examples 'a class with interactor callback methods'
27
+ include_examples 'a class with interactor context methods'
28
+
29
+ describe '.perform' do
30
+ subject { interactor_class.perform }
31
+
32
+ it { is_expected.to be_a interactor_class.context_class }
33
+ it { is_expected.to have_attributes(perform_step: [1, 2, 3]) }
34
+ end
35
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe 'An interactor with .around_rollback callbacks', type: :integration do
6
+ let(:interactor_class) do
7
+ build_interactor do
8
+ around_rollback :test_around_rollback
9
+
10
+ def perform
11
+ context.fail!
12
+ end
13
+
14
+ def rollback
15
+ context.rollback_step << 2
16
+ end
17
+
18
+ private
19
+
20
+ def test_around_rollback
21
+ context.rollback_step = []
22
+ context.rollback_step << 1
23
+ yield
24
+ context.rollback_step << 3
25
+ end
26
+ end
27
+ end
28
+
29
+ include_examples 'a class with interactor methods'
30
+ include_examples 'a class with interactor callback methods'
31
+ include_examples 'a class with interactor context methods'
32
+
33
+ describe '.perform' do
34
+ subject { interactor_class.perform }
35
+
36
+ it { is_expected.to be_a interactor_class.context_class }
37
+ it { is_expected.to have_attributes(rollback_step: [1, 2, 3]) }
38
+ end
39
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe 'An interactor with .before_perform callbacks', type: :integration do
6
+ let(:interactor_class) do
7
+ build_interactor do
8
+ before_perform :test_before_perform
9
+
10
+ private
11
+
12
+ def test_before_perform; end
13
+ end
14
+ end
15
+
16
+ include_examples 'a class with interactor methods'
17
+ include_examples 'a class with interactor callback methods'
18
+ include_examples 'a class with interactor context methods'
19
+
20
+ describe '.perform' do
21
+ subject { interactor_class.perform }
22
+
23
+ it { is_expected.to be_a interactor_class.context_class }
24
+ it { is_expected.to be_successful }
25
+ it 'is expected to receive #test_before_perform' do
26
+ expect_any_instance_of(interactor_class).to receive(:test_before_perform)
27
+ subject
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe 'An interactor with .before_rollback callbacks', type: :integration do
6
+ let(:interactor_class) do
7
+ build_interactor do
8
+ before_rollback :test_before_rollback
9
+
10
+ def perform
11
+ context.fail!
12
+ end
13
+
14
+ private
15
+
16
+ def test_before_rollback; end
17
+ end
18
+ end
19
+
20
+ include_examples 'a class with interactor methods'
21
+ include_examples 'a class with interactor callback methods'
22
+ include_examples 'a class with interactor context methods'
23
+
24
+ describe '.perform' do
25
+ subject { interactor_class.perform }
26
+
27
+ it { is_expected.to be_a interactor_class.context_class }
28
+ it 'is expected to receive #test_before_rollback' do
29
+ expect_any_instance_of(interactor_class).to receive(:test_before_rollback)
30
+ subject
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe 'An interactor with validations on :called', type: :integration do
6
+ let(:interactor_class) do
7
+ build_interactor do
8
+ context_validates :test_field, presence: true, on: :called
9
+
10
+ def perform
11
+ context.test_field = 'test' if context.should_have_test_field
12
+ end
13
+ end
14
+ end
15
+
16
+ include_examples 'a class with interactor methods'
17
+ include_examples 'a class with interactor callback methods'
18
+ include_examples 'a class with interactor context methods'
19
+
20
+ describe '.perform' do
21
+ subject { interactor_class.perform(context_attributes) }
22
+
23
+ context 'with :should_have_test_field true' do
24
+ let(:context_attributes) { { should_have_test_field: true } }
25
+
26
+ it { is_expected.to be_an TestInteractor::Context }
27
+ it { is_expected.to be_successful }
28
+ end
29
+
30
+ context 'with :should_have_test_field false' do
31
+ let(:context_attributes) { { should_have_test_field: false } }
32
+
33
+ it { is_expected.to be_an TestInteractor::Context }
34
+ it { is_expected.to be_failure }
35
+ it 'is expected to have errors on :some_field' do
36
+ expect(subject.errors[:test_field]).not_to be_nil
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe 'An interactor with validations on :calling', type: :integration do
6
+ let(:interactor_class) do
7
+ build_interactor do
8
+ context_validates :test_field, presence: true, on: :calling
9
+ end
10
+ end
11
+
12
+ include_examples 'a class with interactor methods'
13
+ include_examples 'a class with interactor callback methods'
14
+ include_examples 'a class with interactor context methods'
15
+
16
+ describe '.perform' do
17
+ subject { interactor_class.perform(context_attributes) }
18
+
19
+ context 'with :test_field "test"' do
20
+ let(:context_attributes) { { test_field: 'test' } }
21
+
22
+ it { is_expected.to be_an TestInteractor::Context }
23
+ it { is_expected.to be_successful }
24
+ end
25
+
26
+ context 'with :test_field nil' do
27
+ let(:context_attributes) { {} }
28
+
29
+ it { is_expected.to be_an TestInteractor::Context }
30
+ it { is_expected.to be_failure }
31
+ it 'is expected to have errors on :some_field' do
32
+ expect(subject.errors[:test_field]).not_to be_nil
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,93 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe 'An interactor with validations', type: :integration do
6
+ let(:interactor_class) do
7
+ build_interactor do
8
+ context_validates :test_field, presence: true
9
+
10
+ def perform
11
+ context.other_field = context.test_field
12
+ end
13
+
14
+ def rollback
15
+ context.other_field = 'failed'
16
+ end
17
+ end
18
+ end
19
+
20
+ include_examples 'a class with interactor methods'
21
+ include_examples 'a class with interactor callback methods'
22
+ include_examples 'a class with interactor context methods'
23
+
24
+ describe '.perform' do
25
+ subject { interactor_class.perform(context_attributes) }
26
+
27
+ context 'with valid context attributes' do
28
+ let(:context_attributes) { { test_field: 'test' } }
29
+
30
+ it { is_expected.to be_a interactor_class.context_class }
31
+ it { is_expected.to be_successful }
32
+ it { is_expected.to have_attributes(test_field: 'test', other_field: 'test') }
33
+ end
34
+
35
+ context 'with invalid context attributes' do
36
+ let(:context_attributes) { {} }
37
+
38
+ it { is_expected.to be_a interactor_class.context_class }
39
+ it { is_expected.to be_failure }
40
+ it { is_expected.to have_attributes(other_field: 'failed') }
41
+ it 'is expected to have errors on :test_field' do
42
+ expect(subject.errors[:test_field]).not_to be_nil
43
+ end
44
+ end
45
+ end
46
+
47
+ context 'having conditional validations' do
48
+ let(:interactor_class) do
49
+ build_interactor do
50
+ context_validates :test_field, presence: true, if: :test_condition
51
+
52
+ def perform
53
+ context.other_field = context.test_field
54
+ end
55
+
56
+ def rollback
57
+ context.other_field = 'failed'
58
+ end
59
+ end
60
+ end
61
+
62
+ describe '.perform' do
63
+ subject { interactor_class.perform(context_attributes) }
64
+
65
+ context 'with :test_field defined and :test_condition false' do
66
+ let(:context_attributes) { { test_field: 'test', test_condition: false } }
67
+
68
+ it { is_expected.to be_a interactor_class.context_class }
69
+ it { is_expected.to be_successful }
70
+ it { is_expected.to have_attributes(test_field: 'test', test_condition: false, other_field: 'test') }
71
+ end
72
+
73
+ context 'with :test_field defined and :test_condition true' do
74
+ let(:context_attributes) { { test_field: 'test', test_condition: true } }
75
+
76
+ it { is_expected.to be_a interactor_class.context_class }
77
+ it { is_expected.to be_successful }
78
+ it { is_expected.to have_attributes(test_field: 'test', test_condition: true, other_field: 'test') }
79
+ end
80
+
81
+ context 'with :test_field undefined and :test_condition true' do
82
+ let(:context_attributes) { { test_condition: true } }
83
+
84
+ it { is_expected.to be_a interactor_class.context_class }
85
+ it { is_expected.to be_failure }
86
+ it { is_expected.to have_attributes(test_condition: true, other_field: 'failed') }
87
+ it 'is expected to have errors on :test_field' do
88
+ expect(subject.errors[:test_field]).not_to be_nil
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe 'An organizer performing in parallel', type: :integration do
6
+ let!(:test_interactor_1) do
7
+ build_interactor('TestInteractor1') do
8
+ def perform
9
+ context.test_field_1 = 'test 1'
10
+ end
11
+ end
12
+ end
13
+
14
+ let!(:test_interactor_2) do
15
+ build_interactor('TestInteractor2') do
16
+ def perform
17
+ context.test_field_2 = 'test 2'
18
+ end
19
+ end
20
+ end
21
+
22
+ let(:interactor_class) do
23
+ build_organizer do
24
+ perform_in_parallel
25
+ organize TestInteractor1, TestInteractor2
26
+ end
27
+ end
28
+
29
+ include_examples 'a class with interactor methods'
30
+ include_examples 'a class with interactor callback methods'
31
+ include_examples 'a class with interactor context methods'
32
+ include_examples 'a class with organizer callback methods'
33
+
34
+ describe '.context_class' do
35
+ subject { interactor_class.context_class }
36
+
37
+ it { is_expected.to eq TestOrganizer::Context }
38
+ it { is_expected.to be < ActiveInteractor::Context::Base }
39
+ end
40
+
41
+ describe '.perform' do
42
+ subject { interactor_class.perform }
43
+
44
+ it { is_expected.to be_a interactor_class.context_class }
45
+ it { is_expected.to be_successful }
46
+ it { is_expected.to have_attributes(test_field_1: 'test 1', test_field_2: 'test 2') }
47
+ end
48
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe 'An organizer with .after_each callbacks', type: :integration do
6
+ let!(:interactor1) { build_interactor('TestInteractor1') }
7
+ let!(:interactor2) { build_interactor('TestInteractor2') }
8
+ let(:interactor_class) do
9
+ build_organizer do
10
+ after_each_perform :test_after_each_perform
11
+ organize TestInteractor1, TestInteractor2
12
+
13
+ private
14
+
15
+ def test_after_each_perform; end
16
+ end
17
+ end
18
+
19
+ include_examples 'a class with interactor methods'
20
+ include_examples 'a class with interactor callback methods'
21
+ include_examples 'a class with interactor context methods'
22
+ include_examples 'a class with organizer callback methods'
23
+
24
+ describe '.perform' do
25
+ subject { interactor_class.perform }
26
+
27
+ it { is_expected.to be_a interactor_class.context_class }
28
+ it 'is expected to receive #test_after_each_perform twice' do
29
+ expect_any_instance_of(interactor_class).to receive(:test_after_each_perform)
30
+ .exactly(:twice)
31
+ subject
32
+ end
33
+ end
34
+ end