pathway 0.9.1 → 0.11.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -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?