Skip to content

Commit 0adca91

Browse files
authored
Extract modules (#32)
* add specs * extract modules to make code structure more apparent * fix coverage recording
1 parent a906e09 commit 0adca91

File tree

16 files changed

+307
-113
lines changed

16 files changed

+307
-113
lines changed

.github/workflows/main.yml

+9
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,18 @@ jobs:
3535
- name: Install Appraisal Gems
3636
run: bundle exec appraisal install
3737
- name: Run the specs for Appraisal
38+
env:
39+
APPRAISAL: ${{ matrix.appraisal }}
40+
RUBY_VERSION: ${{ matrix.ruby }}
3841
run: bundle exec appraisal ${{ matrix.appraisal }} rake spec
3942
- name: Upload coverage reports to Codecov
4043
uses: codecov/codecov-action@v3
44+
env:
45+
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
4146
with:
4247
files: ./coverage/${{ matrix.ruby }}-${{ matrix.appraisal }}/coverage.json
4348
token: ${{ secrets.CODECOV_TOKEN }}
49+
50+
- name: List coverage directory
51+
run: ls -R ./coverage
52+

Gemfile

+1
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,5 @@ group :test do
1616
gem "debug"
1717
gem "rspec", "~> 3.0"
1818
gem "simplecov", require: false
19+
gem "simplecov-json", require: false
1920
end

Gemfile.lock

+5
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ GEM
7676
irb (1.10.1)
7777
rdoc
7878
reline (>= 0.3.8)
79+
json (2.7.1)
7980
minitest (5.20.0)
8081
mutex_m (0.2.0)
8182
psych (5.1.1.1)
@@ -104,6 +105,9 @@ GEM
104105
simplecov-html (~> 0.11)
105106
simplecov_json_formatter (~> 0.1)
106107
simplecov-html (0.12.3)
108+
simplecov-json (0.2.3)
109+
json
110+
simplecov
107111
simplecov_json_formatter (0.1.3)
108112
stringio (3.1.0)
109113
thor (1.2.2)
@@ -122,6 +126,7 @@ DEPENDENCIES
122126
rake (~> 13.0)
123127
rspec (~> 3.0)
124128
simplecov
129+
simplecov-json
125130

126131
BUNDLED WITH
127132
2.4.22

lib/interactify.rb

+5-89
Original file line numberDiff line numberDiff line change
@@ -11,100 +11,16 @@
1111
require "interactify/wiring"
1212
require "interactify/configuration"
1313
require "interactify/interactify_callable"
14-
15-
module Interactify
16-
class << self
17-
delegate :on_definition_error, :trigger_definition_error, to: :configuration
18-
19-
def railties_missing?
20-
@railties_missing
21-
end
22-
23-
def railties_missing!
24-
@railties_missing = true
25-
end
26-
27-
def railties
28-
railties?
29-
end
30-
31-
def railties?
32-
!railties_missing?
33-
end
34-
35-
def sidekiq_missing?
36-
@sidekiq_missing
37-
end
38-
39-
def sidekiq_missing!
40-
@sidekiq_missing = true
41-
end
42-
43-
def sidekiq
44-
sidekiq?
45-
end
46-
47-
def sidekiq?
48-
!sidekiq_missing?
49-
end
50-
end
51-
end
52-
53-
Interactify.instance_eval do
54-
@sidekiq_missing = nil
55-
@railties_missing = nil
56-
end
57-
58-
begin
59-
require "sidekiq"
60-
rescue LoadError
61-
Interactify.sidekiq_missing!
62-
end
63-
64-
begin
65-
require "rails/railtie"
66-
rescue LoadError
67-
Interactify.railties_missing!
68-
end
14+
require "interactify/dependency_inference"
15+
require "interactify/hooks"
16+
require "interactify/configure"
6917

7018
module Interactify
7119
extend ActiveSupport::Concern
20+
extend Hooks
21+
extend Configure
7222

7323
class << self
74-
def validate_app(ignore: [])
75-
Interactify::Wiring.new(root: Interactify.configuration.root, ignore:).validate_app
76-
end
77-
78-
def reset
79-
@on_contract_breach = nil
80-
@before_raise_hook = nil
81-
@configuration = nil
82-
end
83-
84-
def trigger_contract_breach_hook(...)
85-
@on_contract_breach&.call(...)
86-
end
87-
88-
def on_contract_breach(&block)
89-
@on_contract_breach = block
90-
end
91-
92-
def trigger_before_raise_hook(...)
93-
@before_raise_hook&.call(...)
94-
end
95-
96-
def before_raise(&block)
97-
@before_raise_hook = block
98-
end
99-
100-
def configure
101-
yield configuration
102-
end
103-
104-
def configuration
105-
@configuration ||= Configuration.new
106-
end
107-
10824
delegate :root, to: :configuration
10925
end
11026

lib/interactify/configure.rb

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
module Interactify
2+
module Configure
3+
def validate_app(ignore: [])
4+
Interactify::Wiring.new(root: Interactify.configuration.root, ignore:).validate_app
5+
end
6+
7+
def configure
8+
yield configuration
9+
end
10+
11+
def configuration
12+
@configuration ||= Configuration.new
13+
end
14+
end
15+
end

lib/interactify/contracts/breaches.rb

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
module Interactify
2+
module Breaches
3+
def self.handle_with_failure(context, breaches)
4+
breaches = preamble(context, breaches)
5+
context.fail! contract_failures: breaches
6+
end
7+
8+
def self.handle_with_exception(context, failure_klass, breaches)
9+
breaches = preamble(context, breaches)
10+
11+
# e.g. raises
12+
# SomeNamespace::SomeClass::ContractFailure, {whatever: 'is missing'}
13+
# but also sending the context into Sentry
14+
exception = failure_klass.new(breaches.to_json)
15+
Interactify.trigger_before_raise_hook(exception)
16+
raise exception
17+
end
18+
19+
def self.preamble(context, breaches)
20+
breaches = breaches.map { |b| { b.property => b.messages } }.inject(&:merge)
21+
22+
Interactify.trigger_contract_breach_hook(context, breaches)
23+
breaches
24+
end
25+
end
26+
end

lib/interactify/contracts/helpers.rb

+5-13
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
require "interactify/contracts/setup"
77
require "interactify/contracts/promising"
88
require "interactify/contracts/organizing"
9+
require "interactify/contracts/breaches"
910
require "interactify/dsl/organizer"
1011

1112
module Interactify
@@ -60,27 +61,18 @@ def _interactify_extract_keys(clauses)
6061
# rubocop: enable Metrics/BlockLength
6162

6263
included do
63-
c = Class.new(Contracts::Failure)
64+
failure_klass = Class.new(Contracts::Failure)
6465
# example self is Whatever::SomeInteractor
6566
# failure class: Whatever::SomeInteractor::InteractorContractFailure
66-
const_set "InteractorContractFailure", c
67+
const_set "InteractorContractFailure", failure_klass
6768
prepend Contracts::CallWrapper
6869
include Dsl::Organizer
6970

7071
on_breach do |breaches|
71-
breaches = breaches.map { |b| { b.property => b.messages } }.inject(&:merge)
72-
73-
Interactify.trigger_contract_breach_hook(context, breaches)
74-
7572
if @_interactor_called_by_non_bang_method == true
76-
context.fail! contract_failures: breaches
73+
Breaches.handle_with_failure(context, breaches)
7774
else
78-
# e.g. raises
79-
# SomeNamespace::SomeClass::ContractFailure, {whatever: 'is missing'}
80-
# but also sending the context into Sentry
81-
exception = c.new(breaches.to_json)
82-
Interactify.trigger_before_raise_hook(exception)
83-
raise exception
75+
Breaches.handle_with_exception(context, failure_klass, breaches)
8476
end
8577
end
8678
end
+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
module Interactify
2+
class << self
3+
delegate :on_definition_error, :trigger_definition_error, to: :configuration
4+
5+
def railties_missing?
6+
@railties_missing
7+
end
8+
9+
def railties_missing!
10+
@railties_missing = true
11+
end
12+
13+
def railties
14+
railties?
15+
end
16+
17+
def railties?
18+
!railties_missing?
19+
end
20+
21+
def sidekiq_missing?
22+
@sidekiq_missing
23+
end
24+
25+
def sidekiq_missing!
26+
@sidekiq_missing = true
27+
end
28+
29+
def sidekiq
30+
sidekiq?
31+
end
32+
33+
def sidekiq?
34+
!sidekiq_missing?
35+
end
36+
end
37+
end
38+
39+
Interactify.instance_eval do
40+
@sidekiq_missing = nil
41+
@railties_missing = nil
42+
end
43+
44+
begin
45+
require "sidekiq"
46+
rescue LoadError
47+
Interactify.sidekiq_missing!
48+
end
49+
50+
begin
51+
require "rails/railtie"
52+
rescue LoadError
53+
Interactify.railties_missing!
54+
end
55+
56+

lib/interactify/hooks.rb

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
module Interactify
2+
module Hooks
3+
def reset
4+
@on_contract_breach = nil
5+
@before_raise_hook = nil
6+
@configuration = nil
7+
end
8+
9+
def trigger_contract_breach_hook(...)
10+
@on_contract_breach&.call(...)
11+
end
12+
13+
def on_contract_breach(&block)
14+
@on_contract_breach = block
15+
end
16+
17+
def trigger_before_raise_hook(...)
18+
@before_raise_hook&.call(...)
19+
end
20+
21+
def before_raise(&block)
22+
@before_raise_hook = block
23+
end
24+
end
25+
end

spec/fixtures/asdf

Whitespace-only changes.

spec/fixtures/integration_app/app/interactors/all_the_things.rb

+19-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,10 @@
3131
# Note: The conditional structures (`if`, `each`) here are not executed at runtime in the usual
3232
# sense. They are evaluated when defining the organizer, leading to the creation of discrete
3333
# classes that handle the respective logic.
34-
#
34+
35+
require_relative './organizing/organized1'
36+
require_relative './organizing/organized2'
37+
3538
class AllTheThings
3639
include Interactify
3740

@@ -46,6 +49,21 @@ class AllTheThings
4649
else: [If::C, If::D]
4750
),
4851

52+
# test nested promises
53+
chain(
54+
:nested_promises,
55+
Organizing::Organized1.promising(
56+
:organized1_called
57+
),
58+
Organizing::Organized2.organizing(
59+
Organizing::DeeplyNestedInteractor,
60+
Organizing::DeeplyNestedPromisingInteractor.promising(
61+
:deeply_nested_promising_interactor_called
62+
),
63+
Organizing::Organized2::Organized2Called
64+
)
65+
),
66+
4967
# test each with lambda
5068
self.if(
5169
-> (c) { c.things },

spec/fixtures/integration_app/app/interactors/organizing/organized2.rb

+8-8
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@ class Organized2
66
include Interactify
77

88
organize(
9-
DeeplyNestedInteractor,
10-
DeeplyNestedPromisingInteractor.promising(
11-
:deeply_nested_promising_interactor_called
12-
),
13-
Organized2Called = Interactify do |context|
14-
context.organized2_called = true
15-
end
16-
)
9+
DeeplyNestedInteractor,
10+
DeeplyNestedPromisingInteractor.promising(
11+
:deeply_nested_promising_interactor_called
12+
),
13+
Organized2Called = Interactify do |context|
14+
context.organized2_called = true
15+
end
16+
)
1717
end
1818
end

0 commit comments

Comments
 (0)