interactify 0.4.1 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c0ac09f812f0ad0ef3787c8bba0088bcbf24853e77f054a2751778eb581e7ee2
4
- data.tar.gz: e4cbff812c74598c1f6a846b25007ed5058e1ab89b0ad51323e49de847579291
3
+ metadata.gz: d55a6d70e6996f8fb4e2f523f80532b6337e43072110283c9479fb4ee3f10bde
4
+ data.tar.gz: a948d6aed7f5076ebcc2851f1ede6658353c64c4e4947d68b7a70d0975828a92
5
5
  SHA512:
6
- metadata.gz: 8c3c740e8130e66acf52ffb1131f75de98eba440aa5183cc0d8b18390196c0b6ed28e61f0d4df17391c0956fe785bcd3f5d45a41fa65b8b567906b29a11c7fe1
7
- data.tar.gz: 1ad479044c68b77f757c99a8fafd51658f99cc0d86ce947ff4ce385fbb5f32345e7cf8d0979fba2a5ddf70d2feb2158cf0fdcab3d89334641ccc670f7f93fda3
6
+ metadata.gz: 3ad70be9c0770932b1658509e19e58a9251c91fc7117f42a9191e4b4a9ec1e9bb4606ea33b7321561036df3969505b347f61ceb8b387ae8b75381f8db0bc0a41
7
+ data.tar.gz: a6cd09925a0d1bad7d62ec24f06970a4647f20de4d135e671bf2ed1681d0976d76670d1c87bf28d5d7121826a86b8b61891ddac87921f210c69cc3da9c2db559
data/.rubocop.yml CHANGED
@@ -6,6 +6,9 @@ AllCops:
6
6
  - 'tmp/**/*'
7
7
  - '.git/**/*'
8
8
  - 'bin/*'
9
+ Style/OpenStructUse:
10
+ Exclude:
11
+ - 'spec/integration/*'
9
12
  Style/ClassAndModuleChildren:
10
13
  Exclude:
11
14
  - 'spec/**/*'
data/CHANGELOG.md CHANGED
@@ -28,3 +28,10 @@
28
28
 
29
29
  ## [0.4.1] - 2023-12-29
30
30
  - Fix bug triggered when nesting each and if
31
+
32
+ ## [0.5.0] - 2024-01-01
33
+ - Add support for `SetA = Interactify { _1.a = 'a' }`, lambda and block class creation syntax
34
+ - Add support for organizing `organize A.organizing(B, C, D), E, F` contract syntax
35
+ - make definition errors raise optionally
36
+ - raise an error with unexpected keys in Interactify.if clause
37
+ - propagate caller_info through chains
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Interactify
2
2
 
3
- [![Gem Version](https://badge.fury.io/rb/interactify.svg)](https://badge.fury.io/rb/interactify)
3
+ [![Gem Version](https://badge.fury.io/rb/interactify.svg?1704002847)](https://badge.fury.io/rb/interactify)
4
4
  [![License](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
5
5
  ![Ruby 3.3.0](https://img.shields.io/badge/ruby-3.3.0-green.svg)
6
6
  ![Ruby 3.2.2](https://img.shields.io/badge/ruby-3.2.2-green.svg)
@@ -25,20 +25,30 @@ gem 'interactify'
25
25
  ```ruby
26
26
  # in config/initializers/interactify.rb
27
27
  Interactify.configure do |config|
28
- # default
29
- # config.root = Rails.root / 'app'
30
- end
28
+ # defaults
29
+ config.root = Rails.root / 'app'
31
30
 
32
- Interactify.on_contract_breach do |context, attrs|
33
- # maybe add context to Sentry or Honeybadger etc here
34
- end
31
+ config.on_contract_breach do |context, contract_failures|
32
+ # maybe add context to Sentry or Honeybadger etc here
33
+ end
34
+
35
+ # called when an Interactify.organizing or Interactify.promising fails to match the actual interactor
36
+ # definitions
37
+ config.on_definition_error = Kernel.method(:raise)
35
38
 
36
- Interactify.before_raise do |exception|
37
- # maybe add context to Sentry or Honeybadger etc here
39
+ # config.on_definition_error do |error|
40
+ # # you may want to raise an error in test but not in production
41
+ # # or you may want to log the error
42
+ # end
43
+
44
+ config.before_raise do |exception|
45
+ # maybe add context to Sentry or Honeybadger etc here
46
+ end
38
47
  end
39
48
  ```
40
49
 
41
50
  ### Using the RSpec matchers
51
+
42
52
  ```ruby
43
53
  # e.g. in spec/support/interactify.rb
44
54
  require 'interactify/rspec_matchers/matchers'
@@ -109,6 +119,24 @@ organize \
109
119
  Thing2
110
120
  ```
111
121
 
122
+ Sometimes you also want a one liner but testability too.
123
+ the `Interactify` method will take a block or a lambda and return an Interactify class.
124
+
125
+ ```ruby
126
+ # passing a block
127
+ DecorateOrder = Interactify do |context|
128
+ context.order = context.order.decorate
129
+ end
130
+
131
+ # passing a lambda
132
+ DecorateOrder = Interactify(some_lambda)
133
+
134
+ # passing anything that responds to call
135
+ # please note if you pass a class it will be instantiated first
136
+ # so you can't pass a class with a constructor that takes arguments
137
+ DecorateOrder = Interactify(callable_object)
138
+ ```
139
+
112
140
  ### Each/Iteration
113
141
 
114
142
  Sometimes we want an interactor for each item in a collection.
@@ -308,6 +336,54 @@ Actual promises are:
308
336
  step1
309
337
  ```
310
338
 
339
+ ### Organizing
340
+ You can now annotate your interactors in the organize arguments with their sub-organizers' interactors.
341
+ This also serves as executable documentation, validated at load time, and is enforced to stay in sync.
342
+
343
+
344
+ ```ruby
345
+ organize \
346
+ LoadOrder,
347
+ MarkAsPaid,
348
+ SendOutNotifications.organizing(
349
+ EmailUser,
350
+ SendPush,
351
+ NotifySomeThirdParty,
352
+ SendOutNotifications::DoAnotherThing
353
+ )
354
+
355
+ class SendOutNotifications
356
+ organize \
357
+ EmailUser,
358
+ SendPush,
359
+ NotifySomeThirdParty,
360
+ SetData = Interactify do |context|
361
+ context.data = {this: true}
362
+ end
363
+ end
364
+ ```
365
+
366
+ In this example, it might seem reasonable for an editor of SendOutNotifications to append SetData to the end of the chain.
367
+ However, the naming here is not ideal.
368
+ If it's generically named and not easily searchable, then the discoverability of the code is reduced.
369
+
370
+ By invoking `.organizing` when the original author first uses `SendOutNotifications`, it encourages the subsequent editor to think about and document its own callers.
371
+ They may still choose to add `SetData` to the end of the chain, but this increases the chances of more easily finding where the data is changed.
372
+
373
+
374
+ Example load time failure:
375
+ ```
376
+ SendOutNotifications does not organize:
377
+ [EmailUser, SendPush, NotifySomeThirdParty]
378
+
379
+ Actual organized classes are:
380
+ [EmailUser, SendPush, NotifySomeThirdParty, SendOutNotifications::SetData]
381
+
382
+ Expected organized classes are:
383
+ [SendOutNotifications::SetData]
384
+ ```
385
+
386
+
311
387
  ### Interactor wiring specs
312
388
  Sometimes you have an interactor chain that fails because something is expected deeper down the chain and not provided further up the chain.
313
389
  The existing way to solve this is with enough integration specs to catch them, hunting and sticking a `byebug`, `debugger` or `binding.pry` in at suspected locations and inferring where in the chain the wiring went awry.
@@ -11,5 +11,13 @@ module Interactify
11
11
  def fallback
12
12
  Rails.root / "app" if Interactify.railties?
13
13
  end
14
+
15
+ def trigger_definition_error(error)
16
+ @on_definition_error&.call(error)
17
+ end
18
+
19
+ def on_definition_error(handler = nil, &block)
20
+ @on_definition_error = block_given? ? block : handler
21
+ end
14
22
  end
15
23
  end
@@ -4,6 +4,8 @@ require "interactify/async/jobable"
4
4
  require "interactify/contracts/call_wrapper"
5
5
  require "interactify/contracts/failure"
6
6
  require "interactify/contracts/setup"
7
+ require "interactify/contracts/promising"
8
+ require "interactify/contracts/organizing"
7
9
  require "interactify/dsl/organizer"
8
10
 
9
11
  module Interactify
@@ -11,6 +13,7 @@ module Interactify
11
13
  module Helpers
12
14
  extend ActiveSupport::Concern
13
15
 
16
+ # rubocop: disable Metrics/BlockLength
14
17
  class_methods do
15
18
  def expect(*attrs, filled: true)
16
19
  Setup.expects(context: self, attrs:, filled:)
@@ -24,6 +27,10 @@ module Interactify
24
27
  Promising.validate(self, *args)
25
28
  end
26
29
 
30
+ def organizing(*args)
31
+ Organizing.validate(self, *args)
32
+ end
33
+
27
34
  def promised_keys
28
35
  _interactify_extract_keys(contract.promises)
29
36
  end
@@ -50,6 +57,7 @@ module Interactify
50
57
  clauses.instance_eval { @terms }.json&.rules&.keys
51
58
  end
52
59
  end
60
+ # rubocop: enable Metrics/BlockLength
53
61
 
54
62
  included do
55
63
  c = Class.new(Contracts::Failure)
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "interactify/contracts/failure"
4
+
5
+ module Interactify
6
+ module Contracts
7
+ class MismatchingOrganizerError < Contracts::Failure
8
+ def initialize(interactor, organizing, organized_klasses)
9
+ @interactor = interactor
10
+ @organizing = organizing
11
+ @organized_klasses = organized_klasses
12
+
13
+ super formatted_message
14
+ end
15
+
16
+ private
17
+
18
+ attr_reader :interactor, :organizing, :organized_klasses
19
+
20
+ def formatted_message
21
+ <<~MESSAGE.chomp.strip
22
+ #{interactor} does not organize:
23
+ #{organizing.inspect}
24
+
25
+ Actual organized classes are:
26
+ #{organized_klasses.inspect}
27
+
28
+ #{missing_and_extra_message}
29
+ MESSAGE
30
+ end
31
+
32
+ def extra = organizing - organized_klasses
33
+ def missing = organized_klasses - organizing
34
+ def missing_message = missing.none? ? nil : "Missing classes are:\n#{missing.inspect}"
35
+ def extra_message = extra.none? ? nil : "Extra classes are:\n#{extra.inspect}"
36
+
37
+ def missing_and_extra_message = [missing_message, extra_message].compact.join("\n\n")
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "interactify/contracts/mismatching_organizer_error"
4
+
5
+ module Interactify
6
+ module Contracts
7
+ class Organizing
8
+ attr_reader :interactor, :organizing
9
+
10
+ def self.validate(interactor, *organizing)
11
+ new(interactor, *organizing).validate
12
+
13
+ interactor
14
+ end
15
+
16
+ def initialize(interactor, *organizing)
17
+ @interactor = interactor
18
+ @organizing = organizing
19
+ end
20
+
21
+ def validate
22
+ return if organizing == organized
23
+
24
+ Interactify.trigger_definition_error(
25
+ MismatchingOrganizerError.new(interactor, organizing, organized)
26
+ )
27
+ end
28
+
29
+ delegate :organized, to: :interactor
30
+ end
31
+ end
32
+ end
@@ -5,17 +5,23 @@ require "interactify/dsl/unique_klass_name"
5
5
  module Interactify
6
6
  module Dsl
7
7
  class EachChain
8
- attr_reader :each_loop_klasses, :plural_resource_name, :evaluating_receiver
8
+ MissingIteratableValueInContext = Class.new(ArgumentError)
9
9
 
10
- def self.attach_klass(evaluating_receiver, plural_resource_name, *each_loop_klasses)
11
- iteratable = new(each_loop_klasses, plural_resource_name, evaluating_receiver)
10
+ attr_reader :each_loop_klasses, :plural_resource_name, :evaluating_receiver, :caller_info
11
+
12
+ def self.attach_klass(evaluating_receiver,
13
+ *each_loop_klasses,
14
+ plural_resource_name:,
15
+ caller_info:)
16
+ iteratable = new(each_loop_klasses, plural_resource_name, evaluating_receiver, caller_info:)
12
17
  iteratable.attach_klass
13
18
  end
14
19
 
15
- def initialize(each_loop_klasses, plural_resource_name, evaluating_receiver)
20
+ def initialize(each_loop_klasses, plural_resource_name, evaluating_receiver, caller_info:)
16
21
  @each_loop_klasses = each_loop_klasses
17
22
  @plural_resource_name = plural_resource_name
18
23
  @evaluating_receiver = evaluating_receiver
24
+ @caller_info = caller_info
19
25
  end
20
26
 
21
27
  # allows us to dynamically create an interactor chain
@@ -33,10 +39,17 @@ module Interactify
33
39
  end # end
34
40
 
35
41
  define_singleton_method(:source_location) do # def self.source_location
36
- const_source_location this.evaluating_receiver.to_s # [file, line]
42
+ file, line = this.caller_info&.split(':')
43
+ return const_source_location(this.evaluating_receiver.to_s) if file.nil?
44
+
45
+ [file, line&.to_i]
37
46
  end # end
38
47
 
39
48
  define_method(:run!) do # def run!
49
+ resources = context.send(this.plural_resource_name) # packages = context.packages
50
+
51
+ bail_with_error(resources) unless resources.respond_to?(:each_with_index) # raise MissingIteratableValueInContext unless packages.respond_to?(:each_with_index)
52
+
40
53
  context.send(this.plural_resource_name).each_with_index do |resource, index|# context.packages.each_with_index do |package, index|
41
54
  context[this.singular_resource_name] = resource # context.package = package
42
55
  context[this.singular_resource_index_name] = index # context.package_index = index
@@ -52,6 +65,11 @@ module Interactify
52
65
  context # context
53
66
  end # end
54
67
 
68
+ define_method(:bail_with_error) do |resources|
69
+ message = "Expected `context.#{this.plural_resource_name}`: #{resources.inspect}\nto respond to :each_with_index"
70
+ raise MissingIteratableValueInContext, message
71
+ end
72
+
55
73
  define_singleton_method(:klasses) do # def self.klasses
56
74
  klasses = instance_variable_get(:@klasses) # @klasses ||= Wrapper.wrap_many(self, [A, B, C])
57
75
  return klasses if klasses
@@ -6,18 +6,19 @@ require "interactify/dsl/if_klass"
6
6
  module Interactify
7
7
  module Dsl
8
8
  class IfInteractor
9
- attr_reader :condition, :evaluating_receiver
9
+ attr_reader :condition, :evaluating_receiver, :caller_info
10
10
 
11
- def self.attach_klass(evaluating_receiver, condition, succcess_interactor, failure_interactor)
12
- ifable = new(evaluating_receiver, condition, succcess_interactor, failure_interactor)
11
+ def self.attach_klass(evaluating_receiver, condition, succcess_interactor, failure_interactor, caller_info:)
12
+ ifable = new(evaluating_receiver, condition, succcess_interactor, failure_interactor, caller_info:)
13
13
  ifable.attach_klass
14
14
  end
15
15
 
16
- def initialize(evaluating_receiver, condition, succcess_arg, failure_arg)
16
+ def initialize(evaluating_receiver, condition, succcess_arg, failure_arg, caller_info:)
17
17
  @evaluating_receiver = evaluating_receiver
18
18
  @condition = condition
19
19
  @success_arg = succcess_arg
20
20
  @failure_arg = failure_arg
21
+ @caller_info = caller_info
21
22
  end
22
23
 
23
24
  def success_interactor
@@ -71,7 +72,7 @@ module Interactify
71
72
  case arg
72
73
  when Array
73
74
  name = "If#{condition.to_s.camelize}#{truthiness ? 'IsTruthy' : 'IsFalsey'}"
74
- klass_basis.chain(name, *arg)
75
+ klass_basis.chain(name, *arg, caller_info:)
75
76
  else
76
77
  arg
77
78
  end
@@ -19,7 +19,7 @@ module Interactify
19
19
  end
20
20
 
21
21
  def run!(context)
22
- result = condition.is_a?(Proc) ? condition.call(context) : context.send(condition)
22
+ result = invoke_callable(context)
23
23
 
24
24
  interactor = result ? success_interactor : failure_interactor
25
25
  interactor.respond_to?(:call!) ? interactor.call!(context) : interactor&.call(context)
@@ -27,6 +27,42 @@ module Interactify
27
27
 
28
28
  private
29
29
 
30
+ def invoke_callable(context)
31
+ return handle_string_or_symbol(context) if string_or_symbol_condition?
32
+ return handle_interactor_subclass(context) if interactor_subclass_condition?
33
+ return handle_proc_or_class(context) if proc_or_class_condition?
34
+
35
+ raise_unknown_condition_error
36
+ end
37
+
38
+ def string_or_symbol_condition?
39
+ condition.class.in?([String, Symbol])
40
+ end
41
+
42
+ def handle_string_or_symbol(context)
43
+ context.send(condition)
44
+ end
45
+
46
+ def interactor_subclass_condition?
47
+ condition.is_a?(Class) && condition < Interactor
48
+ end
49
+
50
+ def handle_interactor_subclass(context)
51
+ condition.new(context).call
52
+ end
53
+
54
+ def proc_or_class_condition?
55
+ condition.is_a?(Proc) || condition.is_a?(Class)
56
+ end
57
+
58
+ def handle_proc_or_class(context)
59
+ condition.call(context)
60
+ end
61
+
62
+ def raise_unknown_condition_error
63
+ raise "Unknown condition: #{condition.inspect}"
64
+ end
65
+
30
66
  def attach_source_location
31
67
  attach do |_klass, this|
32
68
  define_singleton_method(:source_location) do # def self.source_location
@@ -38,7 +74,7 @@ module Interactify
38
74
  def attach_expectations
39
75
  attach do |klass, this|
40
76
  klass.expects do
41
- required(this.condition) unless this.condition.is_a?(Proc)
77
+ required(this.condition.to_sym) if this.condition.class.in?([String, Symbol])
42
78
  end
43
79
  end
44
80
  end
@@ -5,7 +5,7 @@ module Interactify
5
5
  module UniqueKlassName
6
6
  def self.for(namespace, prefix)
7
7
  id = generate_unique_id
8
- klass_name = :"#{prefix}#{id}"
8
+ klass_name = :"#{prefix.to_s.camelize.gsub("::", "__")}#{id}"
9
9
 
10
10
  while namespace.const_defined?(klass_name)
11
11
  id = generate_unique_id
@@ -29,6 +29,12 @@ module Interactify
29
29
  when Array
30
30
  wrap_chain
31
31
  when Proc
32
+ wrap_proc
33
+ when Class
34
+ return interactor if interactor < Interactor
35
+
36
+ raise ArgumentError, "#{interactor} must respond_to .call" unless interactor.respond_to?(:call)
37
+
32
38
  wrap_proc
33
39
  else
34
40
  interactor
@@ -6,6 +6,9 @@ require "interactify/dsl/unique_klass_name"
6
6
 
7
7
  module Interactify
8
8
  module Dsl
9
+ Error = Class.new(::ArgumentError)
10
+ IfDefinitionUnexpectedKey = Class.new(Error)
11
+
9
12
  # creates a class in the attach_klass_to's namespace
10
13
  # e.g.
11
14
  #
@@ -15,25 +18,27 @@ module Interactify
15
18
  # will create a class called Orders::EachPackage, that
16
19
  # will call the interactor chain A, B, C for each package in the context
17
20
  def each(plural_resource_name, *each_loop_klasses)
21
+ caller_info = caller(1..1).first
22
+
18
23
  EachChain.attach_klass(
19
24
  self,
20
- plural_resource_name,
21
- *each_loop_klasses
25
+ *each_loop_klasses,
26
+ caller_info:,
27
+ plural_resource_name:
22
28
  )
23
29
  end
24
30
 
25
31
  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
32
+ then_else = parse_if_args(condition, success_arg, failure_arg)
33
+
34
+ caller_info = caller(1..1).first
31
35
 
32
36
  IfInteractor.attach_klass(
33
37
  self,
34
38
  condition,
35
39
  then_else[:then],
36
- then_else[:else]
40
+ then_else[:else],
41
+ caller_info:
37
42
  )
38
43
  end
39
44
 
@@ -54,7 +59,8 @@ module Interactify
54
59
  # it will attach the generate class to the currenct class and
55
60
  # use the class name passed in
56
61
  # rubocop:disable all
57
- def chain(klass_name, *chained_klasses, expect: [])
62
+ def chain(klass_name, *chained_klasses, expect: [], caller_info: nil)
63
+ caller_info ||= caller(1..1).first
58
64
  expectations = expect
59
65
 
60
66
  klass = Class.new do # class EvaluatingNamespace::SomeClass
@@ -62,7 +68,7 @@ module Interactify
62
68
  expect(*expectations) if expectations.any? # expect :foo, :bar
63
69
 
64
70
  define_singleton_method(:source_location) do # def self.source_location
65
- source_location # [file, line]
71
+ caller_info # [file, line]
66
72
  end # end
67
73
 
68
74
  organize(*chained_klasses) # organize(A, B, C)
@@ -73,5 +79,21 @@ module Interactify
73
79
  klass_name = UniqueKlassName.for(where_to_attach, klass_name)
74
80
  where_to_attach.const_set(klass_name, klass)
75
81
  end
82
+
83
+ private
84
+
85
+ def parse_if_args(condition, success_arg, failure_arg)
86
+ then_else = if success_arg.is_a?(Hash) && failure_arg.nil?
87
+ extra_keys = success_arg.except(:then, :else)
88
+
89
+ if extra_keys.any?
90
+ raise IfDefinitionUnexpectedKey, "Unexpected keys: #{extra_keys.keys.join(", ")}"
91
+ end
92
+
93
+ success_arg.slice(:then, :else)
94
+ else
95
+ { then: success_arg, else: failure_arg }
96
+ end
97
+ end
76
98
  end
77
99
  end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "interactify/dsl/wrapper"
4
+
5
+ # rubocop: disable Naming/MethodName
6
+ def Interactify(method_callable = nil, &block)
7
+ to_wrap = method_callable || block
8
+
9
+ Interactify::Dsl::Wrapper.wrap(self, to_wrap)
10
+ end
11
+ # rubocop: enable Naming/MethodName
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Interactify
4
- VERSION = "0.4.1"
4
+ VERSION = "0.5.0"
5
5
  end
data/lib/interactify.rb CHANGED
@@ -10,38 +10,43 @@ require "interactify/contracts/promising"
10
10
  require "interactify/dsl"
11
11
  require "interactify/wiring"
12
12
  require "interactify/configuration"
13
+ require "interactify/interactify_callable"
13
14
 
14
15
  module Interactify
15
- def self.railties_missing?
16
- @railties_missing
17
- end
16
+ class << self
17
+ delegate :on_definition_error, :trigger_definition_error, to: :configuration
18
18
 
19
- def self.railties_missing!
20
- @railties_missing = true
21
- end
19
+ def railties_missing?
20
+ @railties_missing
21
+ end
22
22
 
23
- def self.railties
24
- railties?
25
- end
23
+ def railties_missing!
24
+ @railties_missing = true
25
+ end
26
26
 
27
- def self.railties?
28
- !railties_missing?
29
- end
27
+ def railties
28
+ railties?
29
+ end
30
30
 
31
- def self.sidekiq_missing?
32
- @sidekiq_missing
33
- end
31
+ def railties?
32
+ !railties_missing?
33
+ end
34
34
 
35
- def self.sidekiq_missing!
36
- @sidekiq_missing = true
37
- end
35
+ def sidekiq_missing?
36
+ @sidekiq_missing
37
+ end
38
38
 
39
- def self.sidekiq
40
- sidekiq?
41
- end
39
+ def sidekiq_missing!
40
+ @sidekiq_missing = true
41
+ end
42
+
43
+ def sidekiq
44
+ sidekiq?
45
+ end
42
46
 
43
- def self.sidekiq?
44
- !sidekiq_missing?
47
+ def sidekiq?
48
+ !sidekiq_missing?
49
+ end
45
50
  end
46
51
  end
47
52
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: interactify
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.1
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mark Burns
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-12-31 00:00:00.000000000 Z
11
+ date: 2024-01-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -96,7 +96,9 @@ files:
96
96
  - lib/interactify/contracts/call_wrapper.rb
97
97
  - lib/interactify/contracts/failure.rb
98
98
  - lib/interactify/contracts/helpers.rb
99
+ - lib/interactify/contracts/mismatching_organizer_error.rb
99
100
  - lib/interactify/contracts/mismatching_promise_error.rb
101
+ - lib/interactify/contracts/organizing.rb
100
102
  - lib/interactify/contracts/promising.rb
101
103
  - lib/interactify/contracts/setup.rb
102
104
  - lib/interactify/dsl.rb
@@ -106,6 +108,7 @@ files:
106
108
  - lib/interactify/dsl/organizer.rb
107
109
  - lib/interactify/dsl/unique_klass_name.rb
108
110
  - lib/interactify/dsl/wrapper.rb
111
+ - lib/interactify/interactify_callable.rb
109
112
  - lib/interactify/rspec_matchers/matchers.rb
110
113
  - lib/interactify/version.rb
111
114
  - lib/interactify/wiring.rb