Skip to content

Commit c34cfa1

Browse files
authored
v0.4.0 support if(:condition, then: [A, B, C], else: [B, C, D]) (#16)
* bump version * add support for `if(:condition, then: [A, B, C], else: [D, E, F])` * add missing specs * add examples to README * replace Interactify::RSpec with Interactify::RSpecMatchers avoids a clash when doing module A RSpec.describe Subclass
1 parent ada0d7d commit c34cfa1

24 files changed

+298
-56
lines changed

CHANGELOG.md

+5
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,8 @@
2020

2121
- Fixed to work with and make optional dependencies for sidekiq and railties. Confirmed as working with ruby >= 3.1.4
2222

23+
## [0.4.0] - 2023-12-29
24+
25+
- All internal restructuring/refactoring into domains.
26+
- Add support for organize `self.if(:condition, then: A, else: B)` syntax
27+
- change location of matchers to `require 'interactify/rspec_matchers/matchers'`

Gemfile.lock

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
PATH
22
remote: .
33
specs:
4-
interactify (0.3.0.pre.RC1)
4+
interactify (0.4.0)
55
activesupport (>= 6.0.0)
66
interactor
77
interactor-contracts

README.md

+9-2
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,10 @@ end
4040

4141
### Using the RSpec matchers
4242
```ruby
43-
# e.g. in spec/supoort/interactify.rb
44-
require 'interactify/rspec/matchers'
43+
# e.g. in spec/support/interactify.rb
44+
require 'interactify/rspec_matchers/matchers'
4545

46+
# in specs
4647
expect(described_class).to expect_inputs(:foo, :bar, :baz)
4748
expect(described_class).to promise_outputs(:fee, :fi, :fo, :fum)
4849
```
@@ -232,6 +233,12 @@ class OuterThing
232233

233234
# alternative hash syntax
234235
{if: :key_set_on_context, then: DoThingA, else: DoThingB},
236+
237+
# method call with hash syntax, plus implicit chaining
238+
self.if(:key_set_on_context, then: [A, B, C], else: [B, C, D]),
239+
240+
# method call with lambda, hash syntax, and implicit chaining
241+
self.if(->(ctx) { ctx.this }, then: [A, B, C], else: [B, C, D]),
235242
AfterDoThis
236243
end
237244
```

gemfiles/no_railties_no_sidekiq.gemfile

+3-1
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,14 @@ source "https://rubygems.org"
55
gem "rake", "~> 13.0"
66

77
group :development do
8+
gem "appraisal"
89
gem "bundler", "~> 2.0"
910
end
1011

1112
group :test do
12-
gem "simplecov", require: false
13+
gem "debug"
1314
gem "rspec", "~> 3.0"
15+
gem "simplecov", require: false
1416
end
1517

1618
gemspec path: "../"

gemfiles/no_railties_no_sidekiq.gemfile.lock

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
PATH
22
remote: ..
33
specs:
4-
interactify (0.3.0.pre.alpha.2)
4+
interactify (0.4.0)
55
activesupport (>= 6.0.0)
66
interactor
77
interactor-contracts

gemfiles/railties_6_no_sidekiq.gemfile

+3-1
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,14 @@ gem "rake", "~> 13.0"
66
gem "railties", "6"
77

88
group :development do
9+
gem "appraisal"
910
gem "bundler", "~> 2.0"
1011
end
1112

1213
group :test do
13-
gem "simplecov", require: false
14+
gem "debug"
1415
gem "rspec", "~> 3.0"
16+
gem "simplecov", require: false
1517
end
1618

1719
gemspec path: "../"

gemfiles/railties_6_no_sidekiq.gemfile.lock

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
PATH
22
remote: ..
33
specs:
4-
interactify (0.3.0.pre.alpha.2)
4+
interactify (0.4.0)
5+
activesupport (>= 6.0.0)
56
interactor
67
interactor-contracts
78

gemfiles/railties_6_sidekiq.gemfile

+3-1
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,14 @@ gem "railties", "6"
77
gem "sidekiq", "7"
88

99
group :development do
10+
gem "appraisal"
1011
gem "bundler", "~> 2.0"
1112
end
1213

1314
group :test do
14-
gem "simplecov", require: false
15+
gem "debug"
1516
gem "rspec", "~> 3.0"
17+
gem "simplecov", require: false
1618
end
1719

1820
gemspec path: "../"

gemfiles/railties_6_sidekiq.gemfile.lock

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
PATH
22
remote: ..
33
specs:
4-
interactify (0.3.0.pre.alpha.2)
4+
interactify (0.4.0)
5+
activesupport (>= 6.0.0)
56
interactor
67
interactor-contracts
78

gemfiles/railties_7_no_sidekiq.gemfile

+3-1
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,14 @@ gem "rake", "~> 13.0"
66
gem "railties", "7"
77

88
group :development do
9+
gem "appraisal"
910
gem "bundler", "~> 2.0"
1011
end
1112

1213
group :test do
13-
gem "simplecov", require: false
14+
gem "debug"
1415
gem "rspec", "~> 3.0"
16+
gem "simplecov", require: false
1517
end
1618

1719
gemspec path: "../"

gemfiles/railties_7_no_sidekiq.gemfile.lock

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
PATH
22
remote: ..
33
specs:
4-
interactify (0.3.0.pre.alpha.2)
4+
interactify (0.4.0)
5+
activesupport (>= 6.0.0)
56
interactor
67
interactor-contracts
78

gemfiles/railties_7_sidekiq.gemfile

+3-1
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,14 @@ gem "railties", "7"
77
gem "sidekiq", "7"
88

99
group :development do
10+
gem "appraisal"
1011
gem "bundler", "~> 2.0"
1112
end
1213

1314
group :test do
14-
gem "simplecov", require: false
15+
gem "debug"
1516
gem "rspec", "~> 3.0"
17+
gem "simplecov", require: false
1618
end
1719

1820
gemspec path: "../"

gemfiles/railties_7_sidekiq.gemfile.lock

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
PATH
22
remote: ..
33
specs:
4-
interactify (0.3.0.pre.alpha.2)
4+
interactify (0.4.0)
5+
activesupport (>= 6.0.0)
56
interactor
67
interactor-contracts
78

lib/interactify.rb

+6-1
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,11 @@ def self.sidekiq?
4545
end
4646
end
4747

48+
Interactify.instance_eval do
49+
@sidekiq_missing = nil
50+
@railties_missing = nil
51+
end
52+
4853
begin
4954
require "sidekiq"
5055
rescue LoadError
@@ -62,7 +67,7 @@ module Interactify
6267

6368
class << self
6469
def validate_app(ignore: [])
65-
Interactify::InteractorWiring.new(root: Interactify.configuration.root, ignore:).validate_app
70+
Interactify::Wiring.new(root: Interactify.configuration.root, ignore:).validate_app
6671
end
6772

6873
def reset

lib/interactify/dsl.rb

+9-3
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,18 @@ def each(plural_resource_name, *each_loop_klasses)
2222
)
2323
end
2424

25-
def if(condition, succcess_interactor, failure_interactor = nil)
25+
def if(condition, success_arg, failure_arg = nil)
26+
then_else = if success_arg.is_a?(Hash) && failure_arg.nil?
27+
success_arg.slice(:then, :else)
28+
else
29+
{ then: success_arg, else: failure_arg }
30+
end
31+
2632
IfInteractor.attach_klass(
2733
self,
2834
condition,
29-
succcess_interactor,
30-
failure_interactor
35+
then_else[:then],
36+
then_else[:else]
3137
)
3238
end
3339

lib/interactify/dsl/each_chain.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ def klass
2626
this = self
2727

2828
Class.new do # class SomeNamespace::EachPackage
29-
include Interactify # include Interactify
29+
include Interactify # include Interactify
3030

3131
expects do # expects do
3232
required(this.plural_resource_name) # required(:packages)

lib/interactify/dsl/if_interactor.rb

+40-31
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,47 @@
11
# frozen_string_literal: true
22

33
require "interactify/dsl/unique_klass_name"
4+
require "interactify/dsl/if_klass"
45

56
module Interactify
67
module Dsl
78
class IfInteractor
8-
attr_reader :condition, :success_interactor, :failure_interactor, :evaluating_receiver
9+
attr_reader :condition, :evaluating_receiver
910

1011
def self.attach_klass(evaluating_receiver, condition, succcess_interactor, failure_interactor)
1112
ifable = new(evaluating_receiver, condition, succcess_interactor, failure_interactor)
1213
ifable.attach_klass
1314
end
1415

15-
def initialize(evaluating_receiver, condition, succcess_interactor, failure_interactor)
16+
def initialize(evaluating_receiver, condition, succcess_arg, failure_arg)
1617
@evaluating_receiver = evaluating_receiver
1718
@condition = condition
18-
@success_interactor = succcess_interactor
19-
@failure_interactor = failure_interactor
19+
@success_arg = succcess_arg
20+
@failure_arg = failure_arg
21+
end
22+
23+
def success_interactor
24+
@success_interactor ||= build_chain(@success_arg, true)
25+
end
26+
27+
def failure_interactor
28+
@failure_interactor ||= build_chain(@failure_arg, false)
2029
end
2130

2231
# allows us to dynamically create an interactor chain
2332
# that iterates over the packages and
2433
# uses the passed in each_loop_klasses
25-
# rubocop:disable all
2634
def klass
27-
this = self
28-
29-
Class.new do
30-
include Interactor
31-
include Interactor::Contracts
32-
33-
expects do
34-
required(this.condition) unless this.condition.is_a?(Proc)
35-
end
36-
37-
define_singleton_method(:source_location) do
38-
const_source_location this.evaluating_receiver.to_s # [file, line]
39-
end
40-
41-
define_method(:run!) do
42-
result = this.condition.is_a?(Proc) ? this.condition.call(context) : context.send(this.condition)
43-
interactor = result ? this.success_interactor : this.failure_interactor
44-
interactor&.respond_to?(:call!) ? interactor.call!(context) : interactor&.call(context)
45-
end
35+
IfKlass.new(self).klass
36+
end
4637

47-
define_method(:inspect) do
48-
"<#{this.namespace}::#{this.if_klass_name} #{this.condition} ? #{this.success_interactor} : #{this.failure_interactor}>"
49-
end
38+
# so we have something to attach subclasses to during building
39+
# of the outer class, before we finalize the outer If class
40+
def klass_basis
41+
@klass_basis ||= Class.new do
42+
include Interactify
5043
end
5144
end
52-
# rubocop:enable all
5345

5446
def attach_klass
5547
name = if_klass_name
@@ -62,10 +54,27 @@ def namespace
6254
end
6355

6456
def if_klass_name
65-
prefix = condition.is_a?(Proc) ? "Proc" : condition
66-
prefix = "If#{prefix.to_s.camelize}"
57+
@if_klass_name ||=
58+
begin
59+
prefix = condition.is_a?(Proc) ? "Proc" : condition
60+
prefix = "If#{prefix.to_s.camelize}"
61+
62+
UniqueKlassName.for(namespace, prefix)
63+
end
64+
end
65+
66+
private
6767

68-
UniqueKlassName.for(namespace, prefix)
68+
def build_chain(arg, truthiness)
69+
return if arg.nil?
70+
71+
case arg
72+
when Array
73+
name = "If#{condition.to_s.camelize}#{truthiness ? 'IsTruthy' : 'IsFalsey'}"
74+
klass_basis.chain(name, *arg)
75+
else
76+
arg
77+
end
6978
end
7079
end
7180
end

0 commit comments

Comments
 (0)