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/lib/pathway.rb CHANGED
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'ruby2_keywords'
4
3
  require 'forwardable'
5
4
  require 'dry/inflector'
6
5
  require 'contextualizer'
@@ -11,7 +10,7 @@ module Pathway
11
10
  Inflector = Dry::Inflector.new
12
11
  class Operation
13
12
  class << self
14
- ruby2_keywords def plugin(name, *args)
13
+ def plugin(name,...)
15
14
  require "pathway/plugins/#{Inflector.underscore(name)}" if name.is_a?(Symbol)
16
15
 
17
16
  plugin = name.is_a?(Module) ? name : Plugins.const_get(Inflector.camelize(name))
@@ -20,7 +19,7 @@ module Pathway
20
19
  self.include plugin::InstanceMethods if plugin.const_defined? :InstanceMethods
21
20
  self::DSL.include plugin::DSLMethods if plugin.const_defined? :DSLMethods
22
21
 
23
- plugin.apply(self, *args) if plugin.respond_to?(:apply)
22
+ plugin.apply(self,...) if plugin.respond_to?(:apply)
24
23
  end
25
24
 
26
25
  def inherited(subclass)
@@ -45,13 +44,8 @@ module Pathway
45
44
  @details = details || {}
46
45
  end
47
46
 
48
- def deconstruct
49
- [type, message, details]
50
- end
51
-
52
- def deconstruct_keys(_)
53
- { type: type, message: message, details: details }
54
- end
47
+ def deconstruct = [type, message, details]
48
+ def deconstruct_keys(_) = { type:, message:, details: }
55
49
 
56
50
  private
57
51
 
@@ -62,35 +56,29 @@ module Pathway
62
56
 
63
57
  class State
64
58
  extend Forwardable
59
+ delegate %i([] []= fetch store include? values_at deconstruct_keys) => :@hash
65
60
 
66
61
  def initialize(operation, values = {})
67
62
  @hash = operation.context.merge(values)
68
63
  @result_key = operation.result_key
69
64
  end
70
65
 
71
- delegate %i([] []= fetch store include? values_at deconstruct_keys) => :@hash
72
-
73
66
  def update(kargs)
74
67
  @hash.update(kargs)
75
68
  self
76
69
  end
77
70
 
78
- def result
79
- @hash[@result_key]
80
- end
81
-
82
- def to_hash
83
- @hash
84
- end
71
+ def result = @hash[@result_key]
72
+ def to_hash = @hash
85
73
 
86
74
  def use(&bl)
87
75
  raise ArgumentError, 'a block must be provided' if !block_given?
88
- if bl.parameters.any? {|(type,_)| type == :keyrest || type == :rest }
76
+ if bl.parameters in [*, [:rest|:keyrest,], *]
89
77
  raise ArgumentError, 'rest arguments are not supported'
90
78
  end
91
79
 
92
- keys = bl.parameters.select {|(type,_)| type == :key || type == :keyreq }.map(&:last)
93
- names = bl.parameters.select {|(type,_)| type == :req || type == :opt }.map(&:last)
80
+ keys = bl.parameters.select { _1 in :key|:keyreq, }.map(&:last)
81
+ names = bl.parameters.select { _1 in :req|:opt, }.map(&:last)
94
82
 
95
83
  if keys.any? && names.any?
96
84
  raise ArgumentError, 'cannot mix positional and keyword arguments'
@@ -110,20 +98,18 @@ module Pathway
110
98
  module Base
111
99
  module ClassMethods
112
100
  attr_accessor :result_key
113
- alias :result_at :result_key=
114
101
 
115
- def process(&bl)
116
- dsl = self::DSL
102
+ alias_method :result_at, :result_key=
103
+
104
+ def process(&steps)
117
105
  define_method(:call) do |input|
118
- dsl.new(State.new(self, input: input), self)
119
- .run(&bl)
106
+ _dsl_for(input:)
107
+ .run(&steps)
120
108
  .then(&:result)
121
109
  end
122
110
  end
123
111
 
124
- ruby2_keywords def call(ctx, *params)
125
- new(ctx).call(*params)
126
- end
112
+ def call(ctx,...) = new(ctx).call(...)
127
113
 
128
114
  def inherited(subclass)
129
115
  super
@@ -137,19 +123,21 @@ module Pathway
137
123
  delegate :result_key => 'self.class'
138
124
  delegate %i[result success failure] => Result
139
125
 
140
- alias :wrap :result
126
+ alias_method :wrap, :result
141
127
 
142
- def call(*)
143
- fail 'must implement at subclass'
144
- end
128
+ def call(*) = raise 'must implement at subclass'
145
129
 
146
130
  def error(type, message: nil, details: nil)
147
- failure(Error.new(type: type, message: message, details: details))
131
+ failure(Error.new(type:, message:, details:))
148
132
  end
149
133
 
150
134
  def wrap_if_present(value, type: :not_found, message: nil, details: {})
151
- value.nil? ? error(type, message: message, details: details) : success(value)
135
+ value.nil? ? error(type, message:, details:) : success(value)
152
136
  end
137
+
138
+ private
139
+
140
+ def _dsl_for(vals) = self.class::DSL.new(State.new(self, vals), self)
153
141
  end
154
142
 
155
143
  def self.apply(klass)
@@ -162,51 +150,48 @@ module Pathway
162
150
  @result, @operation = wrap(state), operation
163
151
  end
164
152
 
165
- def run(&bl)
166
- instance_eval(&bl)
153
+ def run(&steps)
154
+ instance_eval(&steps)
167
155
  @result
168
156
  end
169
157
 
170
158
  # Execute step and preserve the former state
171
- ruby2_keywords def step(callable, *args)
159
+ def step(callable,...)
172
160
  bl = _callable(callable)
173
-
174
- @result = @result.tee { |state| bl.call(state, *args) }
161
+ @result = @result.tee { |state| bl.call(state,...) }
175
162
  end
176
163
 
177
164
  # Execute step and modify the former state setting the key
178
- def set(callable, *args, to: @operation.result_key)
165
+ def set(callable, *args, to: @operation.result_key, **kwargs, &bl)
179
166
  bl = _callable(callable)
180
167
 
181
168
  @result = @result.then do |state|
182
- wrap(bl.call(state, *args))
169
+ wrap(bl.call(state, *args, **kwargs, &bl))
183
170
  .then { |value| state.update(to => value) }
184
171
  end
185
172
  end
186
173
 
187
174
  # Execute step and replace the current state completely
188
- def map(callable)
175
+ def map(callable,...)
189
176
  bl = _callable(callable)
190
- @result = @result.then(bl)
177
+ @result = @result.then { |state| bl.call(state,...) }
191
178
  end
192
179
 
193
- def around(wrapper, &steps)
180
+ def around(execution_strategy, &steps)
194
181
  @result.then do |state|
195
- seq = -> (dsl = self) { @result = dsl.run(&steps) }
196
- _callable(wrapper).call(seq, state)
182
+ steps_runner = ->(dsl = self) { dsl.run(&steps) }
183
+
184
+ _callable(execution_strategy).call(steps_runner, state)
197
185
  end
198
186
  end
199
187
 
200
188
  def if_true(cond, &steps)
201
189
  cond = _callable(cond)
202
- around(-> seq, state {
203
- seq.call if cond.call(state)
204
- }, &steps)
190
+ around(->(runner, state) { runner.call if cond.call(state) }, &steps)
205
191
  end
206
192
 
207
193
  def if_false(cond, &steps)
208
- cond = _callable(cond)
209
- if_true(-> state { !cond.call(state) }, &steps)
194
+ if_true(_callable(cond) >> :!.to_proc, &steps)
210
195
  end
211
196
 
212
197
  alias_method :sequence, :around
@@ -214,16 +199,14 @@ module Pathway
214
199
 
215
200
  private
216
201
 
217
- def wrap(obj)
218
- Result.result(obj)
219
- end
202
+ def wrap(obj) = Result.result(obj)
220
203
 
221
204
  def _callable(callable)
222
205
  case callable
223
- when Proc
224
- -> *args { @operation.instance_exec(*args, &callable) }.ruby2_keywords
206
+ when Proc # unless (callable.binding rescue nil)&.receiver == @operation
207
+ ->(*args, **kwargs) { @operation.instance_exec(*args, **kwargs, &callable) }
225
208
  when Symbol
226
- -> *args { @operation.send(callable, *args) }.ruby2_keywords
209
+ ->(*args, **kwargs) { @operation.send(callable, *args, **kwargs) }
227
210
  else
228
211
  callable
229
212
  end
data/pathway.gemspec CHANGED
@@ -27,13 +27,12 @@ Gem::Specification.new do |spec|
27
27
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
28
28
  spec.require_paths = ["lib"]
29
29
 
30
- spec.required_ruby_version = ">= 2.4.0"
30
+ spec.required_ruby_version = ">= 3.2.0"
31
31
 
32
32
  spec.add_dependency "dry-inflector", ">= 0.1.0"
33
- spec.add_dependency "contextualizer", "~> 0.0.4"
34
- spec.add_dependency "ruby2_keywords"
33
+ spec.add_dependency "contextualizer", "~> 0.1.0"
35
34
 
36
- spec.add_development_dependency "dry-validation", ">= 0.11"
35
+ spec.add_development_dependency "dry-validation", ">= 1.0"
37
36
  spec.add_development_dependency "bundler", ">= 2.4.10"
38
37
  spec.add_development_dependency "sequel", "~> 5.0"
39
38
  spec.add_development_dependency "rake", "~> 13.0"
@@ -41,6 +40,8 @@ Gem::Specification.new do |spec|
41
40
  spec.add_development_dependency "simplecov-lcov", '~> 0.8.0'
42
41
  spec.add_development_dependency "simplecov"
43
42
  spec.add_development_dependency "pry"
43
+ spec.add_development_dependency "reline"
44
+ spec.add_development_dependency "byebug"
44
45
  spec.add_development_dependency "pry-byebug"
45
46
  spec.add_development_dependency "pry-doc"
46
47
  spec.add_development_dependency "pry-stack"
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pathway
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.12.3
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pablo Herrero
8
- autorequire:
9
8
  bindir: exe
10
9
  cert_chain: []
11
- date: 2024-08-13 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: dry-inflector
@@ -30,42 +29,28 @@ dependencies:
30
29
  requirements:
31
30
  - - "~>"
32
31
  - !ruby/object:Gem::Version
33
- version: 0.0.4
32
+ version: 0.1.0
34
33
  type: :runtime
35
34
  prerelease: false
36
35
  version_requirements: !ruby/object:Gem::Requirement
37
36
  requirements:
38
37
  - - "~>"
39
38
  - !ruby/object:Gem::Version
40
- version: 0.0.4
41
- - !ruby/object:Gem::Dependency
42
- name: ruby2_keywords
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - ">="
46
- - !ruby/object:Gem::Version
47
- version: '0'
48
- type: :runtime
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - ">="
53
- - !ruby/object:Gem::Version
54
- version: '0'
39
+ version: 0.1.0
55
40
  - !ruby/object:Gem::Dependency
56
41
  name: dry-validation
57
42
  requirement: !ruby/object:Gem::Requirement
58
43
  requirements:
59
44
  - - ">="
60
45
  - !ruby/object:Gem::Version
61
- version: '0.11'
46
+ version: '1.0'
62
47
  type: :development
63
48
  prerelease: false
64
49
  version_requirements: !ruby/object:Gem::Requirement
65
50
  requirements:
66
51
  - - ">="
67
52
  - !ruby/object:Gem::Version
68
- version: '0.11'
53
+ version: '1.0'
69
54
  - !ruby/object:Gem::Dependency
70
55
  name: bundler
71
56
  requirement: !ruby/object:Gem::Requirement
@@ -164,6 +149,34 @@ dependencies:
164
149
  - - ">="
165
150
  - !ruby/object:Gem::Version
166
151
  version: '0'
152
+ - !ruby/object:Gem::Dependency
153
+ name: reline
154
+ requirement: !ruby/object:Gem::Requirement
155
+ requirements:
156
+ - - ">="
157
+ - !ruby/object:Gem::Version
158
+ version: '0'
159
+ type: :development
160
+ prerelease: false
161
+ version_requirements: !ruby/object:Gem::Requirement
162
+ requirements:
163
+ - - ">="
164
+ - !ruby/object:Gem::Version
165
+ version: '0'
166
+ - !ruby/object:Gem::Dependency
167
+ name: byebug
168
+ requirement: !ruby/object:Gem::Requirement
169
+ requirements:
170
+ - - ">="
171
+ - !ruby/object:Gem::Version
172
+ version: '0'
173
+ type: :development
174
+ prerelease: false
175
+ version_requirements: !ruby/object:Gem::Requirement
176
+ requirements:
177
+ - - ">="
178
+ - !ruby/object:Gem::Version
179
+ version: '0'
167
180
  - !ruby/object:Gem::Dependency
168
181
  name: pry-byebug
169
182
  requirement: !ruby/object:Gem::Requirement
@@ -221,18 +234,33 @@ files:
221
234
  - LICENSE.txt
222
235
  - README.md
223
236
  - Rakefile
237
+ - bin/bundle
224
238
  - bin/byebug
239
+ - bin/coderay
225
240
  - bin/console
241
+ - bin/erb
242
+ - bin/htmldiff
243
+ - bin/irb
244
+ - bin/ldiff
245
+ - bin/pry
226
246
  - bin/rake
247
+ - bin/rbs
248
+ - bin/rdbg
249
+ - bin/rdoc
250
+ - bin/ri
227
251
  - bin/rspec
252
+ - bin/ruby-lsp
253
+ - bin/ruby-lsp-check
254
+ - bin/ruby-lsp-launcher
255
+ - bin/ruby-lsp-test-exec
256
+ - bin/sequel
228
257
  - bin/setup
258
+ - bin/yard
259
+ - bin/yardoc
260
+ - bin/yri
229
261
  - lib/pathway.rb
230
262
  - lib/pathway/plugins/auto_deconstruct_state.rb
231
- - lib/pathway/plugins/auto_deconstruct_state/ruby3.rb
232
263
  - lib/pathway/plugins/dry_validation.rb
233
- - lib/pathway/plugins/dry_validation/v0_11.rb
234
- - lib/pathway/plugins/dry_validation/v0_12.rb
235
- - lib/pathway/plugins/dry_validation/v1_0.rb
236
264
  - lib/pathway/plugins/responder.rb
237
265
  - lib/pathway/plugins/sequel_models.rb
238
266
  - lib/pathway/plugins/simple_auth.rb
@@ -254,7 +282,6 @@ licenses:
254
282
  metadata:
255
283
  bug_tracker_uri: https://github.com/pabloh/pathway/issues
256
284
  source_code_uri: https://github.com/pabloh/pathway
257
- post_install_message:
258
285
  rdoc_options: []
259
286
  require_paths:
260
287
  - lib
@@ -262,15 +289,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
262
289
  requirements:
263
290
  - - ">="
264
291
  - !ruby/object:Gem::Version
265
- version: 2.4.0
292
+ version: 3.2.0
266
293
  required_rubygems_version: !ruby/object:Gem::Requirement
267
294
  requirements:
268
295
  - - ">="
269
296
  - !ruby/object:Gem::Version
270
297
  version: '0'
271
298
  requirements: []
272
- rubygems_version: 3.5.10
273
- signing_key:
299
+ rubygems_version: 3.6.9
274
300
  specification_version: 4
275
301
  summary: Define your business logic in simple steps.
276
302
  test_files: []
@@ -1,22 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Pathway
4
- module Plugins
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
20
- end
21
- end
22
- end
@@ -1,96 +0,0 @@
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
10
-
11
- alias_method :auto_wire_options, :auto_wire
12
- alias_method :auto_wire_options=, :auto_wire=
13
-
14
- def form(base = nil, **opts, &block)
15
- if block_given?
16
- base ||= _base_form
17
- self.form_class = _block_definition(base, opts, &block)
18
- elsif base
19
- self.form_class = _form_class(base)
20
- else
21
- raise ArgumentError, 'Either a form class or a block must be provided'
22
- end
23
- end
24
-
25
- def form_class= klass
26
- @builded_form = klass.options.empty? ? klass.new : nil
27
- @form_class = klass
28
- @form_options = klass.options.keys
29
- end
30
-
31
- def build_form(opts = {})
32
- @builded_form || form_class.new(opts)
33
- end
34
-
35
- def inherited(subclass)
36
- super
37
- subclass.form_class = form_class
38
- subclass.auto_wire = auto_wire
39
- end
40
-
41
- private
42
-
43
- def _base_form
44
- superclass.respond_to?(:form_class) ? superclass.form_class : Dry::Validation::Schema::Form
45
- end
46
-
47
- def _form_class(form)
48
- form.is_a?(Class) ? form : form.class
49
- end
50
-
51
- def _form_opts(opts = {})
52
- opts.merge(build: false)
53
- end
54
-
55
- def _block_definition(base, opts, &block)
56
- Dry::Validation.Form(_form_class(base), _form_opts(opts), &block)
57
- end
58
- end
59
-
60
- module InstanceMethods
61
- extend Forwardable
62
-
63
- delegate %i[build_form form_options auto_wire_options] => 'self.class'
64
- delegate %i[build_form form_options auto_wire_options auto_wire] => 'self.class'
65
- alias_method :form, :build_form
66
-
67
- def validate(state, with: nil)
68
- if auto_wire && form_options.any?
69
- with ||= form_options.zip(form_options).to_h
70
- end
71
- opts = Hash(with).map { |opt, key| [opt, state[key]] }.to_h
72
- validate_with(state[:input], opts)
73
- .then { |params| state.update(params: params) }
74
- end
75
-
76
- def validate_with(params, opts = {})
77
- val = form(opts).call(params)
78
-
79
- val.success? ? wrap(val.output) : error(:validation, details: val.messages)
80
- end
81
- end
82
-
83
- def self.apply(operation, auto_wire_options: (auto_wire_options_was_not_used=true; false), auto_wire: auto_wire_options)
84
- #:nocov:
85
- unless auto_wire_options_was_not_used
86
- warn "[DEPRECATION] `auto_wire_options` is deprecated. Please use `auto_wire` instead"
87
- end
88
- #:nocov:
89
-
90
- operation.auto_wire = auto_wire
91
- operation.form_class = Dry::Validation::Schema::Form
92
- end
93
- end
94
- end
95
- end
96
- end
@@ -1,95 +0,0 @@
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
10
-
11
- alias_method :auto_wire_options, :auto_wire
12
- alias_method :auto_wire_options=, :auto_wire=
13
-
14
- def form(base = nil, **opts, &block)
15
- if block_given?
16
- base ||= _base_form
17
- self.form_class = _block_definition(base, opts, &block)
18
- elsif base
19
- self.form_class = _form_class(base)
20
- else
21
- raise ArgumentError, 'Either a form class or a block must be provided'
22
- end
23
- end
24
-
25
- def form_class= klass
26
- @builded_form = klass.options.empty? ? klass.new : nil
27
- @form_class = klass
28
- @form_options = klass.options.keys
29
- end
30
-
31
- def build_form(opts = {})
32
- @builded_form || form_class.new(opts)
33
- end
34
-
35
- def inherited(subclass)
36
- super
37
- subclass.form_class = form_class
38
- subclass.auto_wire = auto_wire
39
- end
40
-
41
- private
42
-
43
- def _base_form
44
- superclass.respond_to?(:form_class) ? superclass.form_class : Dry::Validation::Schema::Params
45
- end
46
-
47
- def _form_class(form)
48
- form.is_a?(Class) ? form : form.class
49
- end
50
-
51
- def _form_opts(opts = {})
52
- opts.merge(build: false)
53
- end
54
-
55
- def _block_definition(base, opts, &block)
56
- Dry::Validation.Params(_form_class(base), _form_opts(opts), &block)
57
- end
58
- end
59
-
60
- module InstanceMethods
61
- extend Forwardable
62
-
63
- delegate %i[build_form form_options auto_wire_options auto_wire] => 'self.class'
64
- alias_method :form, :build_form
65
-
66
- def validate(state, with: nil)
67
- if auto_wire && form_options.any?
68
- with ||= form_options.zip(form_options).to_h
69
- end
70
- opts = Hash(with).map { |opt, key| [opt, state[key]] }.to_h
71
- validate_with(state[:input], opts)
72
- .then { |params| state.update(params: params) }
73
- end
74
-
75
- def validate_with(params, opts = {})
76
- val = form(opts).call(params)
77
-
78
- val.success? ? wrap(val.output) : error(:validation, details: val.messages)
79
- end
80
- end
81
-
82
- def self.apply(operation, auto_wire_options: (auto_wire_options_was_not_used=true; false), auto_wire: auto_wire_options)
83
- #:nocov:
84
- unless auto_wire_options_was_not_used
85
- warn "[DEPRECATION] `auto_wire_options` is deprecated. Please use `auto_wire` instead"
86
- end
87
- #:nocov:
88
-
89
- operation.auto_wire = auto_wire
90
- operation.form_class = Dry::Validation::Schema::Params
91
- end
92
- end
93
- end
94
- end
95
- end