pathway 1.1.0 → 1.3.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.
@@ -3,14 +3,15 @@
3
3
  module Pathway
4
4
  class Result
5
5
  extend Forwardable
6
+
6
7
  attr_reader :value, :error
7
8
 
8
9
  class Success < Result
9
10
  def initialize(value) = @value = value
10
11
  def success? = true
11
12
 
12
- def then(bl=nil)
13
- result(block_given? ? yield(value): bl.call(value))
13
+ def then(bl = nil)
14
+ result(block_given? ? yield(value) : bl.call(value))
14
15
  end
15
16
 
16
17
  def tee(...)
@@ -18,20 +19,16 @@ module Pathway
18
19
  follow.failure? ? follow : self
19
20
  end
20
21
 
21
- private
22
-
23
- alias_method :value_for_deconstruct, :value
22
+ private alias_method :value_for_deconstruct, :value
24
23
  end
25
24
 
26
25
  class Failure < Result
27
26
  def initialize(error) = @error = error
28
27
  def success? = false
29
- def then(_=nil) = self
30
- def tee(_=nil) = self
31
-
32
- private
28
+ def then(_ = nil) = self
29
+ def tee(_ = nil) = self
33
30
 
34
- alias_method :value_for_deconstruct, :error
31
+ private alias_method :value_for_deconstruct, :error
35
32
  end
36
33
 
37
34
  module Mixin
@@ -57,6 +54,6 @@ module Pathway
57
54
  end
58
55
  end
59
56
 
60
- delegate :result => 'self.class'
57
+ delegate result: "self.class"
61
58
  end
62
59
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'pathway/rspec/matchers/form_schema_helpers'
3
+ require "pathway/rspec/matchers/form_schema_helpers"
4
4
 
5
5
  RSpec::Matchers.define :accept_optional_fields do |*fields|
6
6
  match do |form|
@@ -13,7 +13,7 @@ RSpec::Matchers.define :accept_optional_fields do |*fields|
13
13
  end
14
14
 
15
15
  match_when_negated do |form|
16
- raise NotImplementedError, 'expect().not_to accept_optional_fields.not_allowing_null_values is not supported.' if @allowing_null_values || @not_allowing_null_values
16
+ raise NotImplementedError, "expect().not_to accept_optional_fields.not_allowing_null_values is not supported." if @allowing_null_values || @not_allowing_null_values
17
17
 
18
18
  @form, @fields = form, fields
19
19
 
@@ -21,23 +21,23 @@ RSpec::Matchers.define :accept_optional_fields do |*fields|
21
21
  end
22
22
 
23
23
  description do
24
- null_value_allowed = @allowing_null_values ? ' allowing null values' : ''
25
- null_value_disallowed = @not_allowing_null_values ? ' not allowing null values' : ''
24
+ null_value_allowed = @allowing_null_values ? " allowing null values" : ""
25
+ null_value_disallowed = @not_allowing_null_values ? " not allowing null values" : ""
26
26
  "accept #{field_list} as optional #{pluralize_fields}#{null_value_allowed}#{null_value_disallowed}"
27
27
  end
28
28
 
29
29
  failure_message do
30
- null_value_allowed = @allowing_null_values ? ' allowing null values' : ''
31
- null_value_disallowed = @not_allowing_null_values ? ' not allowing null values' : ''
30
+ null_value_allowed = @allowing_null_values ? " allowing null values" : ""
31
+ null_value_disallowed = @not_allowing_null_values ? " not allowing null values" : ""
32
32
 
33
33
  "Expected to accept #{field_list} as optional #{pluralize_fields}#{null_value_allowed}#{null_value_disallowed} but " +
34
34
  as_sentence([not_optional_list, not_defined_list, accepting_null_list, not_accepting_null_list].compact,
35
- connector: '; ', last_connector: '; and ')
35
+ connector: "; ", last_connector: "; and ")
36
36
  end
37
37
 
38
38
  failure_message_when_negated do
39
39
  "Did not expect to accept #{field_list} as optional #{pluralize_fields} but " +
40
- [optional_list, not_defined_list].compact.join('; and ')
40
+ [optional_list, not_defined_list].compact.join("; and ")
41
41
  end
42
42
 
43
43
  include Pathway::Rspec::FormSchemaHelpers
@@ -51,13 +51,13 @@ RSpec::Matchers.define :accept_optional_fields do |*fields|
51
51
  end
52
52
 
53
53
  chain :allowing_null_values do
54
- fail 'cannot use allowing_null_values and not_allowing_null_values at the same time' if @not_allowing_null_values
54
+ raise "cannot use allowing_null_values and not_allowing_null_values at the same time" if @not_allowing_null_values
55
55
 
56
56
  @allowing_null_values = true
57
57
  end
58
58
 
59
59
  chain :not_allowing_null_values do
60
- fail 'cannot use allowing_null_values and not_allowing_null_values at the same time' if @allowing_null_values
60
+ raise "cannot use allowing_null_values and not_allowing_null_values at the same time" if @allowing_null_values
61
61
 
62
62
  @not_allowing_null_values = true
63
63
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'pathway/rspec/matchers/list_helpers'
3
+ require "pathway/rspec/matchers/list_helpers"
4
4
 
5
5
  RSpec::Matchers.define :fail_on do |input|
6
6
  match do |operation|
@@ -10,9 +10,10 @@ RSpec::Matchers.define :fail_on do |input|
10
10
  end
11
11
 
12
12
  match_when_negated do |operation|
13
- raise NotImplementedError, '`expect().not_to fail_on(input).with_type()` is not supported.' if @type
14
- raise NotImplementedError, '`expect().not_to fail_on(input).with_message()` is not supported.' if @message
15
- raise NotImplementedError, '`expect().not_to fail_on(input).with_details()` is not supported.' if @details
13
+ raise NotImplementedError, "`expect().not_to fail_on(input).with_type()` is not supported." if @type
14
+ raise NotImplementedError, "`expect().not_to fail_on(input).with_message()` is not supported." if @message
15
+ raise NotImplementedError, "`expect().not_to fail_on(input).with_details()` is not supported." if @details
16
+
16
17
  @operation, @input = operation, input
17
18
 
18
19
  !failure?
@@ -40,20 +41,20 @@ RSpec::Matchers.define :fail_on do |input|
40
41
  alias_method :and_details, :details
41
42
 
42
43
  description do
43
- 'fail' + (@type ? " with :#@type error" : '')
44
+ "fail" + (@type ? " with :#{@type} error" : "")
44
45
  end
45
46
 
46
47
  failure_message do
47
- if !failure?
48
- "Expected operation to fail but it didn't"
48
+ if failure?
49
+ "Expected failed operation to " +
50
+ as_sentence(failure_descriptions, connector: "; ", last_connector: "; and ")
49
51
  else
50
- 'Expected failed operation to ' +
51
- as_sentence(failure_descriptions, connector: '; ', last_connector: '; and ')
52
+ "Expected operation to fail but it didn't"
52
53
  end
53
54
  end
54
55
 
55
56
  failure_message_when_negated do
56
- 'Did not expected operation to fail but it did'
57
+ "Did not expected operation to fail but it did"
57
58
  end
58
59
 
59
60
  def failure?
@@ -85,7 +86,7 @@ RSpec::Matchers.define :fail_on do |input|
85
86
  end
86
87
 
87
88
  def type_failure_description
88
- type_matches? ? nil : "have type :#@type but instead was :#{error.type}"
89
+ type_matches? ? nil : "have type :#{@type} but instead was :#{error.type}"
89
90
  end
90
91
 
91
92
  def message_failure_description
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'pathway/rspec/matchers/list_helpers'
3
+ require "pathway/rspec/matchers/list_helpers"
4
4
 
5
5
  module Pathway
6
6
  module Rspec
@@ -12,11 +12,11 @@ module Pathway
12
12
  end
13
13
 
14
14
  def were_was(list)
15
- list.size > 1 ? 'were' : 'was'
15
+ list.size > 1 ? "were" : "was"
16
16
  end
17
17
 
18
18
  def pluralize_fields
19
- @fields.size > 1 ? 'fields' : 'field'
19
+ @fields.size > 1 ? "fields" : "field"
20
20
  end
21
21
  end
22
22
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'pathway/rspec/matchers/field_list_helpers'
3
+ require "pathway/rspec/matchers/field_list_helpers"
4
4
 
5
5
  module Pathway
6
6
  module Rspec
@@ -3,14 +3,14 @@
3
3
  module Pathway
4
4
  module Rspec
5
5
  module ListHelpers
6
- def as_list(items, **kwargs)
7
- as_sentence(items.map(&:inspect), **kwargs)
6
+ def as_list(items, **)
7
+ as_sentence(items.map(&:inspect), **)
8
8
  end
9
9
 
10
- def as_sentence(items, connector: ', ', last_connector: ' and ')
10
+ def as_sentence(items, connector: ", ", last_connector: " and ")
11
11
  *rest, last = items
12
12
 
13
- result = String.new
13
+ result = +""
14
14
  result << rest.join(connector) << last_connector if rest.any?
15
15
  result << last
16
16
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'pathway/rspec/matchers/form_schema_helpers'
3
+ require "pathway/rspec/matchers/form_schema_helpers"
4
4
 
5
5
  RSpec::Matchers.define :require_fields do |*fields|
6
6
  match do |form|
@@ -13,7 +13,7 @@ RSpec::Matchers.define :require_fields do |*fields|
13
13
  end
14
14
 
15
15
  match_when_negated do |form|
16
- raise NotImplementedError, 'expect().not_to require_fields.not_allowing_null_values is not supported.' if @allowing_null_values || @not_allowing_null_values
16
+ raise NotImplementedError, "expect().not_to require_fields.not_allowing_null_values is not supported." if @allowing_null_values || @not_allowing_null_values
17
17
 
18
18
  @form, @fields = form, fields
19
19
 
@@ -21,23 +21,23 @@ RSpec::Matchers.define :require_fields do |*fields|
21
21
  end
22
22
 
23
23
  description do
24
- null_value_allowed = @allowing_null_values ? ' allowing null values' : ''
25
- null_value_disallowed = @not_allowing_null_values ? ' not allowing null values' : ''
24
+ null_value_allowed = @allowing_null_values ? " allowing null values" : ""
25
+ null_value_disallowed = @not_allowing_null_values ? " not allowing null values" : ""
26
26
  "require #{field_list} as #{pluralize_fields}#{null_value_allowed}#{null_value_disallowed}"
27
27
  end
28
28
 
29
29
  failure_message do
30
- null_value_allowed = @allowing_null_values ? ' allowing null values' : ''
31
- null_value_disallowed = @not_allowing_null_values ? ' not allowing null values' : ''
30
+ null_value_allowed = @allowing_null_values ? " allowing null values" : ""
31
+ null_value_disallowed = @not_allowing_null_values ? " not allowing null values" : ""
32
32
 
33
33
  "Expected to require #{field_list} as #{pluralize_fields}#{null_value_allowed}#{null_value_disallowed} but " +
34
34
  as_sentence([not_required_list, not_defined_list, accepting_null_list, not_accepting_null_list].compact,
35
- connector: '; ', last_connector: '; and ')
35
+ connector: "; ", last_connector: "; and ")
36
36
  end
37
37
 
38
38
  failure_message_when_negated do
39
39
  "Did not expect to require #{field_list} as #{pluralize_fields} but " +
40
- [required_list, not_defined_list].compact.join('; and ')
40
+ [required_list, not_defined_list].compact.join("; and ")
41
41
  end
42
42
 
43
43
  include Pathway::Rspec::FormSchemaHelpers
@@ -51,13 +51,13 @@ RSpec::Matchers.define :require_fields do |*fields|
51
51
  end
52
52
 
53
53
  chain :allowing_null_values do
54
- fail 'cannot use allowing_null_values and not_allowing_null_values at the same time' if @not_allowing_null_values
54
+ raise "cannot use allowing_null_values and not_allowing_null_values at the same time" if @not_allowing_null_values
55
55
 
56
56
  @allowing_null_values = true
57
57
  end
58
58
 
59
59
  chain :not_allowing_null_values do
60
- fail 'cannot use allowing_null_values and not_allowing_null_values at the same time' if @allowing_null_values
60
+ raise "cannot use allowing_null_values and not_allowing_null_values at the same time" if @allowing_null_values
61
61
 
62
62
  @not_allowing_null_values = true
63
63
  end
@@ -8,7 +8,8 @@ RSpec::Matchers.define :succeed_on do |input|
8
8
  end
9
9
 
10
10
  match_when_negated do |operation|
11
- raise NotImplementedError, '`expect().not_to succeed_on(input).returning()` is not supported.' if @value
11
+ raise NotImplementedError, "`expect().not_to succeed_on(input).returning()` is not supported." if @value
12
+
12
13
  @operation, @input = operation, input
13
14
 
14
15
  !success?
@@ -23,15 +24,15 @@ RSpec::Matchers.define :succeed_on do |input|
23
24
  end
24
25
 
25
26
  failure_message do
26
- if !success?
27
- "Expected operation to be successful but failed with :#{result.error.type} error"
28
- else
27
+ if success?
29
28
  "Expected successful operation to return #{description_of(@value)} but instead got #{description_of(result.value)}"
29
+ else
30
+ "Expected operation to be successful but failed with :#{result.error.type} error"
30
31
  end
31
32
  end
32
33
 
33
34
  failure_message_when_negated do
34
- 'Did not to expected operation to be successful but it was'
35
+ "Did not to expected operation to be successful but it was"
35
36
  end
36
37
 
37
38
  def success?
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'pathway/rspec/matchers/succeed_on'
4
- require 'pathway/rspec/matchers/fail_on'
5
- require 'pathway/rspec/matchers/accept_optional_fields'
6
- require 'pathway/rspec/matchers/require_fields'
3
+ require "pathway/rspec/matchers/succeed_on"
4
+ require "pathway/rspec/matchers/fail_on"
5
+ require "pathway/rspec/matchers/accept_optional_fields"
6
+ require "pathway/rspec/matchers/require_fields"
data/lib/pathway/rspec.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'pathway/rspec/matchers'
3
+ require "pathway/rspec/matchers"
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Pathway
4
- VERSION = '1.1.0'
4
+ VERSION = "1.3.0"
5
5
  end
data/lib/pathway.rb CHANGED
@@ -1,16 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'forwardable'
4
- require 'dry/inflector'
5
- require 'contextualizer'
6
- require 'pathway/version'
7
- require 'pathway/result'
3
+ require "forwardable"
4
+ require "dry/inflector"
5
+ require "contextualizer"
6
+ require "pathway/version"
7
+ require "pathway/result"
8
8
 
9
9
  module Pathway
10
10
  Inflector = Dry::Inflector.new
11
11
  class Operation
12
12
  class << self
13
- def plugin(name,...)
13
+ def plugin(name, ...)
14
14
  require "pathway/plugins/#{Inflector.underscore(name)}" if name.is_a?(Symbol)
15
15
 
16
16
  plugin = name.is_a?(Module) ? name : Plugins.const_get(Inflector.camelize(name))
@@ -19,7 +19,7 @@ module Pathway
19
19
  self.include plugin::InstanceMethods if plugin.const_defined? :InstanceMethods
20
20
  self::DSL.include plugin::DSLMethods if plugin.const_defined? :DSLMethods
21
21
 
22
- plugin.apply(self,...) if plugin.respond_to?(:apply)
22
+ plugin.apply(self, ...) if plugin.respond_to?(:apply)
23
23
  end
24
24
 
25
25
  def inherited(subclass)
@@ -34,6 +34,7 @@ module Pathway
34
34
 
35
35
  class Error
36
36
  attr_reader :type, :message, :details
37
+
37
38
  singleton_class.send :attr_accessor, :default_messages
38
39
 
39
40
  @default_messages = {}
@@ -56,7 +57,8 @@ module Pathway
56
57
 
57
58
  class State
58
59
  extend Forwardable
59
- delegate %i([] []= fetch store include? values_at deconstruct_keys) => :@hash
60
+
61
+ delegate %i[[] []= fetch store include? values_at deconstruct_keys] => :@hash
60
62
 
61
63
  def initialize(operation, values = {})
62
64
  @hash = operation.context.merge(values)
@@ -72,16 +74,16 @@ module Pathway
72
74
  def to_hash = @hash
73
75
 
74
76
  def use(&bl)
75
- raise ArgumentError, 'a block must be provided' if !block_given?
76
- if bl.parameters in [*, [:rest|:keyrest,], *]
77
- raise ArgumentError, 'rest arguments are not supported'
77
+ raise ArgumentError, "a block must be provided" unless block_given?
78
+ if bl.parameters in [*, [:rest | :keyrest,], *]
79
+ raise ArgumentError, "rest arguments are not supported"
78
80
  end
79
81
 
80
- keys = bl.parameters.select { _1 in :key|:keyreq, }.map(&:last)
81
- names = bl.parameters.select { _1 in :req|:opt, }.map(&:last)
82
+ keys = bl.parameters.select { _1 in :key | :keyreq, }.map(&:last)
83
+ names = bl.parameters.select { _1 in :req | :opt, }.map(&:last)
82
84
 
83
85
  if keys.any? && names.any?
84
- raise ArgumentError, 'cannot mix positional and keyword arguments'
86
+ raise ArgumentError, "cannot mix positional and keyword arguments"
85
87
  elsif keys.any?
86
88
  bl.call(**to_hash.slice(*keys))
87
89
  else
@@ -104,12 +106,12 @@ module Pathway
104
106
  def process(&steps)
105
107
  define_method(:call) do |input|
106
108
  _dsl_for(input:)
107
- .run(&steps)
108
- .then(&:result)
109
+ .run(&steps)
110
+ .then(&:result)
109
111
  end
110
112
  end
111
113
 
112
- def call(ctx,...) = new(ctx).call(...)
114
+ def call(ctx, ...) = new(ctx).call(...)
113
115
 
114
116
  def inherited(subclass)
115
117
  super
@@ -120,12 +122,12 @@ module Pathway
120
122
  module InstanceMethods
121
123
  extend Forwardable
122
124
 
123
- delegate :result_key => 'self.class'
125
+ delegate result_key: "self.class"
124
126
  delegate %i[result success failure] => Result
125
127
 
126
128
  alias_method :wrap, :result
127
129
 
128
- def call(*) = raise 'must implement at subclass'
130
+ def call(*) = raise "must implement at subclass"
129
131
 
130
132
  def error(type, message: nil, details: nil)
131
133
  failure(Error.new(type:, message:, details:))
@@ -150,33 +152,27 @@ module Pathway
150
152
  @result, @operation = wrap(state), operation
151
153
  end
152
154
 
153
- def run(&steps)
154
- instance_eval(&steps)
155
+ def run(&)
156
+ instance_eval(&)
155
157
  @result
156
158
  end
157
159
 
158
160
  # Execute step and preserve the former state
159
- def step(callable,...)
161
+ def step(callable, *, **)
160
162
  bl = _callable(callable)
161
- @result = @result.tee { |state| bl.call(state,...) }
163
+ @result = @result.tee { |state| bl.call(state, *, **) }
162
164
  end
163
165
 
164
166
  # Execute step and modify the former state setting the key
165
- def set(callable, *args, to: @operation.result_key, **kwargs, &bl)
167
+ def set(callable, *args, to: @operation.result_key, **kwargs)
166
168
  bl = _callable(callable)
167
169
 
168
170
  @result = @result.then do |state|
169
- wrap(bl.call(state, *args, **kwargs, &bl))
171
+ wrap(bl.call(state, *args, **kwargs))
170
172
  .then { |value| state.update(to => value) }
171
173
  end
172
174
  end
173
175
 
174
- # Execute step and replace the current state completely
175
- def map(callable,...)
176
- bl = _callable(callable)
177
- @result = @result.then { |state| bl.call(state,...) }
178
- end
179
-
180
176
  def around(execution_strategy, &steps)
181
177
  @result.then do |state|
182
178
  steps_runner = ->(dsl = self) { dsl.run(&steps) }
@@ -185,13 +181,13 @@ module Pathway
185
181
  end
186
182
  end
187
183
 
188
- def if_true(cond, &steps)
184
+ def if_true(cond, &)
189
185
  cond = _callable(cond)
190
- around(->(runner, state) { runner.call if cond.call(state) }, &steps)
186
+ around(->(runner, state) { runner.call if cond.call(state) }, &)
191
187
  end
192
188
 
193
- def if_false(cond, &steps)
194
- if_true(_callable(cond) >> :!.to_proc, &steps)
189
+ def if_false(cond, &)
190
+ if_true(_callable(cond) >> :!.to_proc, &)
195
191
  end
196
192
 
197
193
  alias_method :sequence, :around
data/pathway.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- lib = File.expand_path("../lib", __FILE__)
3
+ lib = File.expand_path("lib", __dir__)
4
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
5
  require "pathway/version"
6
6
 
@@ -10,24 +10,23 @@ Gem::Specification.new do |spec|
10
10
  spec.authors = ["Pablo Herrero"]
11
11
  spec.email = ["pablodherrero@gmail.com"]
12
12
 
13
- spec.summary = %q{Define your business logic in simple steps.}
14
- spec.description = %q{Define your business logic in simple steps.}
13
+ spec.summary = "Define your business logic in simple steps."
14
+ spec.description = "Define your business logic in simple steps."
15
15
  spec.homepage = "https://github.com/pabloh/pathway"
16
16
  spec.license = "MIT"
17
17
 
18
18
  spec.metadata = {
19
- "bug_tracker_uri" => "https://github.com/pabloh/pathway/issues",
20
- "source_code_uri" => "https://github.com/pabloh/pathway",
19
+ "rubygems_mfa_required" => "true",
20
+ "bug_tracker_uri" => "https://github.com/pabloh/pathway/issues",
21
+ "source_code_uri" => "https://github.com/pabloh/pathway",
21
22
  }
22
23
 
23
- spec.files = `git ls-files -z`.split("\x0").reject do |f|
24
- f.match(%r{^(test|spec|features)/})
25
- end
24
+ spec.files = `git ls-files -z`.split("\x0").grep_v(%r{^(test|spec|features)/})
26
25
  spec.bindir = "exe"
27
26
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
28
27
  spec.require_paths = ["lib"]
29
28
 
30
- spec.required_ruby_version = ">= 3.2.0"
29
+ spec.required_ruby_version = ">= 3.3.0"
31
30
 
32
31
  spec.add_dependency "dry-inflector", ">= 0.1.0"
33
32
  spec.add_dependency "contextualizer", "~> 0.1.0"
@@ -37,12 +36,14 @@ Gem::Specification.new do |spec|
37
36
  spec.add_development_dependency "sequel", "~> 5.0"
38
37
  spec.add_development_dependency "rake", "~> 13.0"
39
38
  spec.add_development_dependency "rspec", "~> 3.11"
40
- spec.add_development_dependency "simplecov-lcov", '~> 0.8.0'
39
+ spec.add_development_dependency "simplecov-lcov", "~> 0.8.0"
40
+ spec.add_development_dependency "rubocop", "~> 1.81.0"
41
+ spec.add_development_dependency "rubocop-performance"
42
+ spec.add_development_dependency "rubocop-rake"
41
43
  spec.add_development_dependency "simplecov"
42
44
  spec.add_development_dependency "pry"
43
45
  spec.add_development_dependency "reline"
44
46
  spec.add_development_dependency "byebug"
45
47
  spec.add_development_dependency "pry-byebug"
46
48
  spec.add_development_dependency "pry-doc"
47
- spec.add_development_dependency "pry-stack"
48
49
  end