pathway 0.12.3 → 1.1.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.
data/bin/sequel ADDED
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'sequel' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../.ruby-lsp/Gemfile", __dir__)
12
+
13
+ bundle_binstub = File.expand_path("bundle", __dir__)
14
+
15
+ if File.file?(bundle_binstub)
16
+ if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
17
+ load(bundle_binstub)
18
+ else
19
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
20
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
21
+ end
22
+ end
23
+
24
+ require "rubygems"
25
+ require "bundler/setup"
26
+
27
+ load Gem.bin_path("sequel", "sequel")
data/bin/yard ADDED
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'yard' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../.ruby-lsp/Gemfile", __dir__)
12
+
13
+ bundle_binstub = File.expand_path("bundle", __dir__)
14
+
15
+ if File.file?(bundle_binstub)
16
+ if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
17
+ load(bundle_binstub)
18
+ else
19
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
20
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
21
+ end
22
+ end
23
+
24
+ require "rubygems"
25
+ require "bundler/setup"
26
+
27
+ load Gem.bin_path("yard", "yard")
data/bin/yardoc ADDED
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'yardoc' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../.ruby-lsp/Gemfile", __dir__)
12
+
13
+ bundle_binstub = File.expand_path("bundle", __dir__)
14
+
15
+ if File.file?(bundle_binstub)
16
+ if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
17
+ load(bundle_binstub)
18
+ else
19
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
20
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
21
+ end
22
+ end
23
+
24
+ require "rubygems"
25
+ require "bundler/setup"
26
+
27
+ load Gem.bin_path("yard", "yardoc")
data/bin/yri ADDED
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'yri' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../.ruby-lsp/Gemfile", __dir__)
12
+
13
+ bundle_binstub = File.expand_path("bundle", __dir__)
14
+
15
+ if File.file?(bundle_binstub)
16
+ if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
17
+ load(bundle_binstub)
18
+ else
19
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
20
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
21
+ end
22
+ end
23
+
24
+ require "rubygems"
25
+ require "bundler/setup"
26
+
27
+ load Gem.bin_path("yard", "yri")
@@ -1,12 +1,22 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- if RUBY_VERSION =~ /^3\./
4
- require 'pathway/plugins/auto_deconstruct_state/ruby3'
5
- end
6
-
7
3
  module Pathway
8
4
  module Plugins
9
5
  module AutoDeconstructState
6
+ module DSLMethods
7
+ private
8
+
9
+ def _callable(callable)
10
+ if callable.is_a?(Symbol) && @operation.respond_to?(callable, true) &&
11
+ @operation.method(callable).arity != 0 &&
12
+ @operation.method(callable).parameters.all? { _1 in [:key|:keyreq|:keyrest|:block,*] }
13
+
14
+ -> state { @operation.send(callable, **state) }
15
+ else
16
+ super
17
+ end
18
+ end
19
+ end
10
20
  end
11
21
  end
12
22
  end
@@ -5,21 +5,82 @@ require 'dry/validation'
5
5
  module Pathway
6
6
  module Plugins
7
7
  module DryValidation
8
- def self.apply(operation, **kwargs)
8
+ module ClassMethods
9
+ attr_reader :contract_class, :contract_options
10
+ attr_accessor :auto_wire
11
+
12
+ alias_method :auto_wire_options, :auto_wire
13
+ alias_method :auto_wire_options=, :auto_wire=
14
+
15
+ def contract(base = nil, &)
16
+ if block_given?
17
+ base ||= _base_contract
18
+ self.contract_class = Class.new(base, &)
19
+ elsif base
20
+ self.contract_class = base
21
+ else
22
+ raise ArgumentError, 'Either a contract class or a block must be provided'
23
+ end
24
+ end
25
+
26
+ def params(...)
27
+ contract { params(...) }
28
+ end
29
+
30
+ def contract_class= klass
31
+ @contract_class = klass
32
+ @contract_options = (klass.dry_initializer.options - Dry::Validation::Contract.dry_initializer.options).map(&:target)
33
+ @builded_contract = @contract_options.empty? && klass.schema ? klass.new : nil
34
+ end
35
+
36
+ def build_contract(**)
37
+ @builded_contract || contract_class.new(**)
38
+ end
39
+
40
+ def inherited(subclass)
41
+ super
42
+ subclass.auto_wire = auto_wire
43
+ subclass.contract_class = contract_class
44
+ end
45
+
46
+ private
47
+
48
+ def _base_contract
49
+ superclass.respond_to?(:contract_class) ? superclass.contract_class : Dry::Validation::Contract
50
+ end
51
+ end
52
+
53
+ module InstanceMethods
54
+ extend Forwardable
55
+
56
+ delegate %i[build_contract contract_options auto_wire_options auto_wire] => 'self.class'
57
+ alias_method :contract, :build_contract
58
+
59
+ def validate(state, with: nil)
60
+ if auto_wire && contract_options.any?
61
+ with ||= contract_options.zip(contract_options).to_h
62
+ end
63
+ opts = Hash(with).map { |to, from| [to, state[from]] }.to_h
64
+ validate_with(state[:input], **opts)
65
+ .then { |params| state.update(params:) }
66
+ end
67
+
68
+ def validate_with(input, **)
69
+ result = contract(**).call(input)
70
+
71
+ result.success? ? wrap(result.values.to_h) : error(:validation, details: result.errors.to_h)
72
+ end
73
+ end
74
+
75
+ def self.apply(operation, auto_wire_options: (auto_wire_options_was_not_used=true; false), auto_wire: auto_wire_options)
9
76
  #:nocov:
10
- if Gem.loaded_specs['dry-validation'].version < Gem::Version.new('0.11')
11
- fail 'unsupported dry-validation gem version'
12
- elsif Gem.loaded_specs['dry-validation'].version < Gem::Version.new('0.12')
13
- require 'pathway/plugins/dry_validation/v0_11'
14
- operation.plugin(Plugins::DryValidation::V0_11, **kwargs)
15
- elsif Gem.loaded_specs['dry-validation'].version < Gem::Version.new('1.0')
16
- require 'pathway/plugins/dry_validation/v0_12'
17
- operation.plugin(Plugins::DryValidation::V0_12, **kwargs)
18
- else
19
- require 'pathway/plugins/dry_validation/v1_0'
20
- operation.plugin(Plugins::DryValidation::V1_0, **kwargs)
77
+ unless auto_wire_options_was_not_used
78
+ warn "[DEPRECATION] `auto_wire_options` is deprecated. Please use `auto_wire` instead"
21
79
  end
22
80
  #:nocov:
81
+
82
+ operation.auto_wire = auto_wire
83
+ operation.contract_class = Dry::Validation::Contract
23
84
  end
24
85
  end
25
86
  end
@@ -4,15 +4,15 @@ module Pathway
4
4
  module Plugins
5
5
  module Responder
6
6
  module ClassMethods
7
- ruby2_keywords def call(*args, &bl)
8
- result = super(*args)
7
+ def call(*args, **kwargs, &bl)
8
+ result = super(*args, **kwargs)
9
9
  block_given? ? Responder.respond(result, &bl) : result
10
10
  end
11
11
  end
12
12
 
13
13
  class Responder
14
- def self.respond(result, &bl)
15
- r = new(result, &bl)
14
+ def self.respond(...)
15
+ r = new(...)
16
16
  r.respond
17
17
  end
18
18
 
@@ -21,9 +21,7 @@ module Pathway
21
21
  instance_eval(&bl)
22
22
  end
23
23
 
24
- def success(&bl)
25
- @ok = bl
26
- end
24
+ def success(&bl)= @ok = bl
27
25
 
28
26
  def failure(type = nil, &bl)
29
27
  if type.nil?
@@ -6,33 +6,43 @@ module Pathway
6
6
  module Plugins
7
7
  module SequelModels
8
8
  module DSLMethods
9
- def transaction(step_name = nil, &bl)
10
- fail 'must provide a step or a block but not both' if !step_name.nil? == block_given?
9
+ def transaction(step_name = nil, if: nil, unless: nil, &steps)
10
+ _with_db_steps(steps, step_name, *_opts_if_unless(binding)) do |runner|
11
+ db.transaction(savepoint: true) do
12
+ raise Sequel::Rollback if runner.call.failure?
13
+ end
14
+ end
15
+ end
11
16
 
12
- if step_name
13
- transaction { step step_name }
14
- else
15
- around(-> steps, _ {
16
- db.transaction(savepoint: true) do
17
- raise Sequel::Rollback if steps.call.failure?
18
- end
19
- }, &bl)
17
+ def after_commit(step_name = nil, if: nil, unless: nil, &steps)
18
+ _with_db_steps(steps, step_name, *_opts_if_unless(binding)) do |runner, state|
19
+ dsl_copy = _dsl_for(state)
20
+ db.after_commit { runner.call(dsl_copy) }
20
21
  end
21
22
  end
22
23
 
23
- def after_commit(step_name = nil, &bl)
24
- fail 'must provide a step or a block but not both' if !step_name.nil? == block_given?
24
+ def after_rollback(step_name = nil, if: nil, unless: nil, &steps)
25
+ _with_db_steps(steps, step_name, *_opts_if_unless(binding)) do |runner, state|
26
+ dsl_copy = _dsl_for(state)
27
+ db.after_rollback(savepoint: true) { runner.call(dsl_copy) }
28
+ end
29
+ end
25
30
 
26
- if step_name
27
- after_commit { step step_name }
28
- else
29
- around(-> steps, state {
30
- dsl = self.class::DSL.new(State.new(self, state.to_h.dup), self)
31
+ private
32
+
33
+ def _opts_if_unless(bg) = %i[if unless].map { bg.local_variable_get(_1) }
31
34
 
32
- db.after_commit do
33
- steps.call(dsl)
34
- end
35
- }, &bl)
35
+ def _with_db_steps(steps, step_name=nil, if_cond=nil, unless_cond=nil, &db_logic)
36
+ raise ArgumentError, 'options :if and :unless are mutually exclusive' if if_cond && unless_cond
37
+ raise ArgumentError, 'must provide either a step or a block but not both' if !!step_name == !!steps
38
+ steps ||= proc { step step_name }
39
+
40
+ if if_cond
41
+ if_true(if_cond) { _with_db_steps(steps, &db_logic) }
42
+ elsif unless_cond
43
+ if_false(unless_cond) { _with_db_steps(steps, &db_logic) }
44
+ else
45
+ around(db_logic, &steps)
36
46
  end
37
47
  end
38
48
  end
@@ -41,10 +51,10 @@ module Pathway
41
51
  attr_accessor :model_class, :search_field, :model_not_found
42
52
 
43
53
  def model(model_class, search_by: model_class.primary_key, set_result_key: true, set_context_param: true, error_message: nil)
44
- self.model_class = model_class
45
- self.search_field = search_by
46
- self.result_key = Inflector.underscore(Inflector.demodulize(model_class.name)).to_sym if set_result_key
47
- self.model_not_found = error_message || "#{Inflector.humanize(Inflector.underscore(Inflector.demodulize(model_class.name)))} not found".freeze
54
+ self.model_class = model_class
55
+ self.search_field = search_by
56
+ self.result_key = Inflector.underscore(Inflector.demodulize(model_class.name)).to_sym if set_result_key
57
+ self.model_not_found = error_message || "#{Inflector.humanize(Inflector.underscore(Inflector.demodulize(model_class.name)))} not found".freeze
48
58
 
49
59
  self.context(result_key => Contextualizer::OPTIONAL) if set_result_key && set_context_param
50
60
  end
@@ -26,9 +26,7 @@ module Pathway
26
26
  authorized?(*objs) ? wrap(objs) : error(:forbidden)
27
27
  end
28
28
 
29
- def authorized?(*)
30
- true
31
- end
29
+ def authorized?(*) = true
32
30
  end
33
31
  end
34
32
  end
@@ -6,48 +6,32 @@ module Pathway
6
6
  attr_reader :value, :error
7
7
 
8
8
  class Success < Result
9
- def initialize(value)
10
- @value = value
11
- end
12
-
13
- def success?
14
- true
15
- end
9
+ def initialize(value) = @value = value
10
+ def success? = true
16
11
 
17
12
  def then(bl=nil)
18
13
  result(block_given? ? yield(value): bl.call(value))
19
14
  end
20
15
 
21
- def tee(bl=nil, &block)
22
- follow = self.then(bl, &block)
16
+ def tee(...)
17
+ follow = self.then(...)
23
18
  follow.failure? ? follow : self
24
19
  end
25
20
 
26
21
  private
27
22
 
28
- alias :value_for_deconstruct :value
23
+ alias_method :value_for_deconstruct, :value
29
24
  end
30
25
 
31
26
  class Failure < Result
32
- def initialize(error)
33
- @error = error
34
- end
35
-
36
- def success?
37
- false
38
- end
39
-
40
- def then(_=nil)
41
- self
42
- end
43
-
44
- def tee(_=nil)
45
- self
46
- end
27
+ def initialize(error) = @error = error
28
+ def success? = false
29
+ def then(_=nil) = self
30
+ def tee(_=nil) = self
47
31
 
48
32
  private
49
33
 
50
- alias :value_for_deconstruct :error
34
+ alias_method :value_for_deconstruct, :error
51
35
  end
52
36
 
53
37
  module Mixin
@@ -55,10 +39,16 @@ module Pathway
55
39
  Failure = Result::Failure
56
40
  end
57
41
 
58
- def deconstruct
59
- [value_for_deconstruct]
42
+ def self.success(value) = Success.new(value)
43
+ def self.failure(error) = Failure.new(error)
44
+
45
+ def self.result(object)
46
+ object.is_a?(Result) ? object : success(object)
60
47
  end
61
48
 
49
+ def failure? = !success?
50
+ def deconstruct = [value_for_deconstruct]
51
+
62
52
  def deconstruct_keys(keys)
63
53
  if value_for_deconstruct.respond_to?(:deconstruct_keys)
64
54
  value_for_deconstruct.deconstruct_keys(keys)
@@ -67,22 +57,6 @@ module Pathway
67
57
  end
68
58
  end
69
59
 
70
- def failure?
71
- !success?
72
- end
73
-
74
- def self.success(value)
75
- Success.new(value)
76
- end
77
-
78
- def self.failure(error)
79
- Failure.new(error)
80
- end
81
-
82
- def self.result(object)
83
- object.is_a?(Result) ? object : success(object)
84
- end
85
-
86
60
  delegate :result => 'self.class'
87
61
  end
88
62
  end
@@ -22,22 +22,22 @@ RSpec::Matchers.define :fail_on do |input|
22
22
  @type = type
23
23
  end
24
24
 
25
- alias :with_type :type
26
- alias :and_type :type
25
+ alias_method :with_type, :type
26
+ alias_method :and_type, :type
27
27
 
28
28
  chain :message do |message|
29
29
  @message = message
30
30
  end
31
31
 
32
- alias :with_message :message
33
- alias :and_message :message
32
+ alias_method :with_message, :message
33
+ alias_method :and_message, :message
34
34
 
35
35
  chain :details do |details|
36
36
  @details = details
37
37
  end
38
38
 
39
- alias :with_details :details
40
- alias :and_details :details
39
+ alias_method :with_details, :details
40
+ alias_method :and_details, :details
41
41
 
42
42
  description do
43
43
  'fail' + (@type ? " with :#@type error" : '')
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Pathway
4
- VERSION = '0.12.3'
4
+ VERSION = '1.1.0'
5
5
  end