pathway 0.9.1 → 0.11.3

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.
@@ -0,0 +1,86 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pathway
4
+ module Plugins
5
+ module DryValidation
6
+ module V0_11
7
+ module ClassMethods
8
+ attr_reader :form_class, :form_options
9
+ attr_accessor :auto_wire_options
10
+
11
+ def form(base = nil, **opts, &block)
12
+ if block_given?
13
+ base ||= _base_form
14
+ self.form_class = _block_definition(base, opts, &block)
15
+ elsif base
16
+ self.form_class = _form_class(base)
17
+ else
18
+ raise ArgumentError, 'Either a form class or a block must be provided'
19
+ end
20
+ end
21
+
22
+ def form_class= klass
23
+ @builded_form = klass.options.empty? ? klass.new : nil
24
+ @form_class = klass
25
+ @form_options = klass.options.keys
26
+ end
27
+
28
+ def build_form(opts = {})
29
+ @builded_form || form_class.new(opts)
30
+ end
31
+
32
+ def inherited(subclass)
33
+ super
34
+ subclass.form_class = form_class
35
+ subclass.auto_wire_options = auto_wire_options
36
+ end
37
+
38
+ private
39
+
40
+ def _base_form
41
+ superclass.respond_to?(:form_class) ? superclass.form_class : Dry::Validation::Schema::Form
42
+ end
43
+
44
+ def _form_class(form)
45
+ form.is_a?(Class) ? form : form.class
46
+ end
47
+
48
+ def _form_opts(opts = {})
49
+ opts.merge(build: false)
50
+ end
51
+
52
+ def _block_definition(base, opts, &block)
53
+ Dry::Validation.Form(_form_class(base), _form_opts(opts), &block)
54
+ end
55
+ end
56
+
57
+ module InstanceMethods
58
+ extend Forwardable
59
+
60
+ delegate %i[build_form form_options auto_wire_options] => 'self.class'
61
+ alias :form :build_form
62
+
63
+ def validate(state, with: nil)
64
+ if auto_wire_options && form_options.any?
65
+ with ||= form_options.zip(form_options).to_h
66
+ end
67
+ opts = Hash(with).map { |opt, key| [opt, state[key]] }.to_h
68
+ validate_with(state[:input], opts)
69
+ .then { |params| state.update(params: params) }
70
+ end
71
+
72
+ def validate_with(params, opts = {})
73
+ val = form(opts).call(params)
74
+
75
+ val.success? ? wrap(val.output) : error(:validation, details: val.messages)
76
+ end
77
+ end
78
+
79
+ def self.apply(operation, auto_wire_options: false)
80
+ operation.form_class = Dry::Validation::Schema::Form
81
+ operation.auto_wire_options = auto_wire_options
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,86 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pathway
4
+ module Plugins
5
+ module DryValidation
6
+ module V0_12
7
+ module ClassMethods
8
+ attr_reader :form_class, :form_options
9
+ attr_accessor :auto_wire_options
10
+
11
+ def form(base = nil, **opts, &block)
12
+ if block_given?
13
+ base ||= _base_form
14
+ self.form_class = _block_definition(base, opts, &block)
15
+ elsif base
16
+ self.form_class = _form_class(base)
17
+ else
18
+ raise ArgumentError, 'Either a form class or a block must be provided'
19
+ end
20
+ end
21
+
22
+ def form_class= klass
23
+ @builded_form = klass.options.empty? ? klass.new : nil
24
+ @form_class = klass
25
+ @form_options = klass.options.keys
26
+ end
27
+
28
+ def build_form(opts = {})
29
+ @builded_form || form_class.new(opts)
30
+ end
31
+
32
+ def inherited(subclass)
33
+ super
34
+ subclass.form_class = form_class
35
+ subclass.auto_wire_options = auto_wire_options
36
+ end
37
+
38
+ private
39
+
40
+ def _base_form
41
+ superclass.respond_to?(:form_class) ? superclass.form_class : Dry::Validation::Schema::Params
42
+ end
43
+
44
+ def _form_class(form)
45
+ form.is_a?(Class) ? form : form.class
46
+ end
47
+
48
+ def _form_opts(opts = {})
49
+ opts.merge(build: false)
50
+ end
51
+
52
+ def _block_definition(base, opts, &block)
53
+ Dry::Validation.Params(_form_class(base), _form_opts(opts), &block)
54
+ end
55
+ end
56
+
57
+ module InstanceMethods
58
+ extend Forwardable
59
+
60
+ delegate %i[build_form form_options auto_wire_options] => 'self.class'
61
+ alias :form :build_form
62
+
63
+ def validate(state, with: nil)
64
+ if auto_wire_options && form_options.any?
65
+ with ||= form_options.zip(form_options).to_h
66
+ end
67
+ opts = Hash(with).map { |opt, key| [opt, state[key]] }.to_h
68
+ validate_with(state[:input], opts)
69
+ .then { |params| state.update(params: params) }
70
+ end
71
+
72
+ def validate_with(params, opts = {})
73
+ val = form(opts).call(params)
74
+
75
+ val.success? ? wrap(val.output) : error(:validation, details: val.messages)
76
+ end
77
+ end
78
+
79
+ def self.apply(operation, auto_wire_options: false)
80
+ operation.form_class = Dry::Validation::Schema::Params
81
+ operation.auto_wire_options = auto_wire_options
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pathway
4
+ module Plugins
5
+ module DryValidation
6
+ module V1_0
7
+ module ClassMethods
8
+ attr_reader :contract_class, :contract_options
9
+ attr_accessor :auto_wire_options
10
+
11
+ def contract(base = nil, &block)
12
+ if block_given?
13
+ base ||= _base_contract
14
+ self.contract_class = Class.new(base, &block)
15
+ elsif base
16
+ self.contract_class = base
17
+ else
18
+ raise ArgumentError, 'Either a contract class or a block must be provided'
19
+ end
20
+ end
21
+
22
+ def params(*args, &block)
23
+ contract { params(*args, &block) }
24
+ end
25
+
26
+ def contract_class= klass
27
+ @contract_class = klass
28
+ @contract_options = (klass.dry_initializer.options - Dry::Validation::Contract.dry_initializer.options).map(&:target)
29
+ @builded_contract = @contract_options.empty? && klass.schema ? klass.new : nil
30
+ end
31
+
32
+ def build_contract(opts = {})
33
+ @builded_contract || contract_class.new(opts)
34
+ end
35
+
36
+ def inherited(subclass)
37
+ super
38
+ subclass.contract_class = contract_class
39
+ subclass.auto_wire_options = auto_wire_options
40
+ end
41
+
42
+ private
43
+
44
+ def _base_contract
45
+ superclass.respond_to?(:contract_class) ? superclass.contract_class : Dry::Validation::Contract
46
+ end
47
+ end
48
+
49
+ module InstanceMethods
50
+ extend Forwardable
51
+
52
+ delegate %i[build_contract contract_options auto_wire_options] => 'self.class'
53
+ alias :contract :build_contract
54
+
55
+ def validate(state, with: nil)
56
+ if auto_wire_options && contract_options.any?
57
+ with ||= contract_options.zip(contract_options).to_h
58
+ end
59
+ opts = Hash(with).map { |to, from| [to, state[from]] }.to_h
60
+ validate_with(state[:input], opts)
61
+ .then { |params| state.update(params: params) }
62
+ end
63
+
64
+ def validate_with(input, opts = {})
65
+ result = contract(opts).call(input)
66
+
67
+ result.success? ? wrap(result.values.to_h) : error(:validation, details: result.errors.to_h)
68
+ end
69
+ end
70
+
71
+ def self.apply(operation, auto_wire_options: false)
72
+ operation.contract_class = Dry::Validation::Contract
73
+ operation.auto_wire_options = auto_wire_options
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Pathway
2
4
  module Plugins
3
5
  module Responder
@@ -1,25 +1,39 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'sequel/model'
2
4
 
3
5
  module Pathway
4
6
  module Plugins
5
7
  module SequelModels
6
8
  module DSLMethods
7
- def transaction(&bl)
8
- around(-> steps, _ {
9
- db.transaction(savepoint: true) do
10
- raise Sequel::Rollback if steps.call.failure?
11
- end
12
- }, &bl)
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?
11
+
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)
20
+ end
13
21
  end
14
22
 
15
- def after_commit(&bl)
16
- around(-> steps, state {
17
- dsl = self.class::DSL.new(State.new(self, state.to_h.dup), self)
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?
18
25
 
19
- db.after_commit do
20
- steps.call(dsl)
21
- end
22
- }, &bl)
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
+
32
+ db.after_commit do
33
+ steps.call(dsl)
34
+ end
35
+ }, &bl)
36
+ end
23
37
  end
24
38
  end
25
39
 
@@ -49,10 +63,11 @@ module Pathway
49
63
  delegate :db => :model_class
50
64
 
51
65
  def fetch_model(state, from: model_class, search_by: search_field, using: search_by, to: result_key, overwrite: false, error_message: nil)
52
- error_message ||= if from != model_class
53
- Inflector.humanize(Inflector.underscore(Inflector.demodulize(from.name))) + ' not found'
54
- else
66
+ error_message ||= if (from == model_class)
55
67
  model_not_found
68
+ elsif from.respond_to?(:name) || from.respond_to?(:model)
69
+ from_name = (from.respond_to?(:name) ? from : from.model).name
70
+ Inflector.humanize(Inflector.underscore(Inflector.demodulize(from_name))) + ' not found'
56
71
  end
57
72
 
58
73
  if state[to].nil? || overwrite
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Pathway
2
4
  module Plugins
3
5
  module SimpleAuth
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Pathway
2
4
  class Result
3
5
  extend Forwardable
@@ -1 +1,3 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'pathway/rspec/matchers'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'pathway/rspec/matchers/succeed_on'
2
4
  require 'pathway/rspec/matchers/fail_on'
3
5
  require 'pathway/rspec/matchers/accept_optional_fields'
@@ -1,30 +1,43 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'pathway/rspec/matchers/form_schema_helpers'
2
4
 
3
5
  RSpec::Matchers.define :accept_optional_fields do |*fields|
4
6
  match do |form|
5
7
  @form, @fields = form, fields
6
8
 
7
- not_defined.empty? && not_optional.empty?
9
+ not_defined.empty? &&
10
+ not_optional.empty? &&
11
+ allowing_null_values_matches? &&
12
+ not_allowing_null_values_matches?
8
13
  end
9
14
 
10
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
17
+
11
18
  @form, @fields = form, fields
12
19
 
13
20
  not_defined.empty? && optional.empty?
14
21
  end
15
22
 
16
23
  description do
17
- "accept #{field_list} as optional #{pluralize_fields}"
24
+ null_value_allowed = @allowing_null_values ? ' allowing null values' : ''
25
+ null_value_disallowed = @not_allowing_null_values ? ' not allowing null values' : ''
26
+ "accept #{field_list} as optional #{pluralize_fields}#{null_value_allowed}#{null_value_disallowed}"
18
27
  end
19
28
 
20
29
  failure_message do
21
- "Expected to accept #{field_list} as optional #{pluralize_fields} but " +
22
- [not_optional_list, not_defined_list].compact.join("; and ")
30
+ null_value_allowed = @allowing_null_values ? ' allowing null values' : ''
31
+ null_value_disallowed = @not_allowing_null_values ? ' not allowing null values' : ''
32
+
33
+ "Expected to accept #{field_list} as optional #{pluralize_fields}#{null_value_allowed}#{null_value_disallowed} but " +
34
+ as_sentence([not_optional_list, not_defined_list, accepting_null_list, not_accepting_null_list].compact,
35
+ connector: '; ', last_connector: '; and ')
23
36
  end
24
37
 
25
38
  failure_message_when_negated do
26
39
  "Did not expect to accept #{field_list} as optional #{pluralize_fields} but " +
27
- [optional_list, not_defined_list].compact.join("; and ")
40
+ [optional_list, not_defined_list].compact.join('; and ')
28
41
  end
29
42
 
30
43
  include Pathway::Rspec::FormSchemaHelpers
@@ -34,7 +47,19 @@ RSpec::Matchers.define :accept_optional_fields do |*fields|
34
47
  end
35
48
 
36
49
  def not_optional_list
37
- "#{as_list(not_required)} #{were_was(not_required)} not optional" if not_optional.any?
50
+ "#{as_list(not_optional)} #{were_was(not_optional)} not optional" if not_optional.any?
51
+ end
52
+
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
55
+
56
+ @allowing_null_values = true
57
+ end
58
+
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
61
+
62
+ @not_allowing_null_values = true
38
63
  end
39
64
  end
40
65
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'pathway/rspec/matchers/list_helpers'
2
4
 
3
5
  RSpec::Matchers.define :fail_on do |input|
@@ -38,20 +40,20 @@ RSpec::Matchers.define :fail_on do |input|
38
40
  alias :and_details :details
39
41
 
40
42
  description do
41
- "fail" + (@type ? " with :#@type error" : '')
43
+ 'fail' + (@type ? " with :#@type error" : '')
42
44
  end
43
45
 
44
46
  failure_message do
45
47
  if !failure?
46
48
  "Expected operation to fail but it didn't"
47
49
  else
48
- "Expected failed operation to " +
50
+ 'Expected failed operation to ' +
49
51
  as_sentence(failure_descriptions, connector: '; ', last_connector: '; and ')
50
52
  end
51
53
  end
52
54
 
53
55
  failure_message_when_negated do
54
- "Did not to expected operation to fail but it did"
56
+ 'Did not expected operation to fail but it did'
55
57
  end
56
58
 
57
59
  def failure?