arq 0.2.0 → 0.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.
- checksums.yaml +4 -4
- data/lib/arq/action.rb +153 -35
- data/lib/arq/module_hash.rb +38 -0
- data/lib/arq/version.rb +1 -1
- data/lib/arq.rb +3 -1
- metadata +3 -3
- data/lib/arq/runnable.rb +0 -90
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bf6593b58efb70d3d2ac268f33cb8eae378fe821d13e69975c13216cdfe1ff2f
|
4
|
+
data.tar.gz: fa4401c24cd50c2d8a5b6f7adb69e3224e126d75c166fca994f816ceb27e4523
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a9feae6ec6e4ff17c37a2af7d99b7df6ec22e1d1fce6af04e42444bdff3e250b44e2c8036d64b333620929cd0d75bd5e0f69058e09d190dc49438ca2e2d456d9
|
7
|
+
data.tar.gz: 297f51c062e329349999b9b370c1f1fc91ba17f90e2b57baf141fc44df6aae3ae97086eef293108204417b94143814ba1e8f512deb9f89d31022c7eb37e5287d
|
data/lib/arq/action.rb
CHANGED
@@ -1,55 +1,173 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Arq
|
4
|
-
# Module to extend to create an action.
|
4
|
+
# Module to extend to create an action.
|
5
|
+
# Class methods are used to configure the action itself.
|
6
|
+
# Instance methods are exposed to the block passed into `run`.
|
5
7
|
module Action
|
6
|
-
def
|
7
|
-
|
8
|
-
|
9
|
-
generate_runnable(ctx).call
|
10
|
-
|
11
|
-
ctx
|
8
|
+
def self.extended(base)
|
9
|
+
base.extend(ClassMethods)
|
10
|
+
base.include(InstanceMethods)
|
12
11
|
end
|
13
12
|
|
14
|
-
def
|
15
|
-
|
13
|
+
def self.included(_base)
|
14
|
+
raise "`Arq::Action` should be `extended`"
|
16
15
|
end
|
17
16
|
|
18
|
-
|
19
|
-
|
20
|
-
|
17
|
+
# Methods and fields exposed to configure the action.
|
18
|
+
module ClassMethods
|
19
|
+
# Runs the stored block with variables from the provided context.
|
20
|
+
def call(ctx = Arq::Context.new)
|
21
|
+
ctx = transform_input_context(ctx)
|
21
22
|
|
22
|
-
|
23
|
-
|
24
|
-
end
|
23
|
+
inst = new(ctx)
|
24
|
+
inst.run
|
25
25
|
|
26
|
-
private
|
27
|
-
|
28
|
-
def transform_input_context(ctx)
|
29
|
-
case ctx
|
30
|
-
when Arq::Context
|
31
26
|
ctx
|
32
|
-
when Hash
|
33
|
-
Arq::Context.new(ctx)
|
34
|
-
else
|
35
|
-
raise Arq::InvalidContextParameterError
|
36
27
|
end
|
37
|
-
end
|
38
28
|
|
39
|
-
|
40
|
-
|
41
|
-
|
29
|
+
def params_list
|
30
|
+
@params_list ||= []
|
31
|
+
end
|
42
32
|
|
43
|
-
|
44
|
-
|
45
|
-
|
33
|
+
def returns_list
|
34
|
+
@returns_list ||= []
|
35
|
+
end
|
36
|
+
|
37
|
+
def run_block
|
38
|
+
@run_block ||= nil
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
46
42
|
|
47
|
-
|
48
|
-
|
43
|
+
# Ensures that a valid context is passed and returned.
|
44
|
+
# Acceptable values are Context or Hash objects.
|
45
|
+
def transform_input_context(ctx)
|
46
|
+
case ctx
|
47
|
+
when Arq::Context
|
48
|
+
ctx
|
49
|
+
when Hash
|
50
|
+
Arq::Context.new(ctx)
|
51
|
+
else
|
52
|
+
raise Arq::InvalidContextParameterError
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def params(*keys)
|
57
|
+
params_list.concat(keys).compact
|
58
|
+
end
|
59
|
+
|
60
|
+
def returns(*keys)
|
61
|
+
returns_list.concat(keys).compact
|
62
|
+
end
|
63
|
+
|
64
|
+
def run(&block)
|
65
|
+
return "Block required" unless block_given?
|
66
|
+
|
67
|
+
@run_block = block
|
68
|
+
end
|
49
69
|
end
|
50
70
|
|
51
|
-
|
52
|
-
|
71
|
+
# Methods and fields exposed to the run block.
|
72
|
+
module InstanceMethods
|
73
|
+
def initialize(ctx)
|
74
|
+
@_ctx = ctx
|
75
|
+
end
|
76
|
+
|
77
|
+
# This is the entry-point for the action's execution.
|
78
|
+
# rubocop:disable Metrics/MethodLength
|
79
|
+
def run
|
80
|
+
return if @_ctx.failure?
|
81
|
+
|
82
|
+
_validate_required_params
|
83
|
+
_import_context
|
84
|
+
|
85
|
+
# Suppress `FailureError`s since they're used to just exit the action.
|
86
|
+
begin
|
87
|
+
# Instance eval to expose instance variables.
|
88
|
+
instance_eval(&self.class.run_block)
|
89
|
+
rescue Arq::FailureError
|
90
|
+
nil
|
91
|
+
end
|
92
|
+
|
93
|
+
_export_variables
|
94
|
+
|
95
|
+
# Only validate returns if context is successful
|
96
|
+
_validate_required_returns if @_ctx.success?
|
97
|
+
|
98
|
+
nil
|
99
|
+
end
|
100
|
+
# rubocop:enable Metrics/MethodLength
|
101
|
+
|
102
|
+
# Used to call another action using the current action's context.
|
103
|
+
# Because of this, the context is exported and then imported again.
|
104
|
+
def call_other(action)
|
105
|
+
_export_variables
|
106
|
+
action.call(@_ctx)
|
107
|
+
_import_context
|
108
|
+
end
|
109
|
+
|
110
|
+
# Fails the context without exiting the current action.
|
111
|
+
def fail!(message = nil)
|
112
|
+
@_ctx.fail!(message)
|
113
|
+
end
|
114
|
+
|
115
|
+
# Fails the context and exits the current action.
|
116
|
+
def fail_now!(message = nil)
|
117
|
+
@_ctx.fail_now!(message)
|
118
|
+
end
|
119
|
+
|
120
|
+
# Used to easily call other actions via snake-cased modules and dot accessors.
|
121
|
+
# IE `Foo::Bar::Action` can be called via `foo.bar.action`
|
122
|
+
def method_missing(method, *args, &block)
|
123
|
+
obj = Object.const_get(method.to_s.camelize)
|
124
|
+
case obj
|
125
|
+
when Arq::Action
|
126
|
+
call_other(obj)
|
127
|
+
when Module
|
128
|
+
Arq::ModuleHash.new(obj, self)
|
129
|
+
end
|
130
|
+
rescue NameError => _e
|
131
|
+
super
|
132
|
+
end
|
133
|
+
|
134
|
+
def respond_to_missing?(method, include_private: false)
|
135
|
+
Object.const_defined?(method.to_s.camelize) || super
|
136
|
+
end
|
137
|
+
|
138
|
+
private
|
139
|
+
|
140
|
+
# Load parameters of context as instance variables
|
141
|
+
def _import_context
|
142
|
+
@_ctx.each do |key, val|
|
143
|
+
instance_variable_set(:"@#{key}", val)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
# Exports instance variables (excluding those prefixed with _) to the context
|
148
|
+
def _export_variables
|
149
|
+
# Filter out vars starting with _
|
150
|
+
vars = instance_variables.filter do |key|
|
151
|
+
!key.start_with?("@_")
|
152
|
+
end
|
153
|
+
|
154
|
+
vars.each do |var|
|
155
|
+
# Strip @ prefix
|
156
|
+
key = var[1..].to_sym
|
157
|
+
|
158
|
+
@_ctx[key] = instance_variable_get(var)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
def _validate_required_params
|
163
|
+
missing_params = (self.class.params_list - @_ctx.keys)
|
164
|
+
raise Arq::ParametersNotInContextError, missing_params unless missing_params.empty?
|
165
|
+
end
|
166
|
+
|
167
|
+
def _validate_required_returns
|
168
|
+
missing_returns = (self.class.returns_list - @_ctx.keys)
|
169
|
+
raise Arq::ReturnValuesNotInContextError, missing_returns unless missing_returns.empty?
|
170
|
+
end
|
53
171
|
end
|
54
172
|
end
|
55
173
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Arq
|
4
|
+
# Allows for dot-accessing of modules.
|
5
|
+
# Child modules are automatically wrapped and actions are called.
|
6
|
+
class ModuleHash < Hash
|
7
|
+
def initialize(mod, action_inst)
|
8
|
+
super()
|
9
|
+
|
10
|
+
@module = mod
|
11
|
+
@action_inst = action_inst
|
12
|
+
end
|
13
|
+
|
14
|
+
def method_missing(method, *args, &block)
|
15
|
+
wrap(@module.const_get(method.to_s.camelize))
|
16
|
+
rescue NameError => _e
|
17
|
+
super
|
18
|
+
end
|
19
|
+
|
20
|
+
def respond_to_missing?(method, include_private = false)
|
21
|
+
@module.const_defined?(method.to_s.camelize.to_sym) || super
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
# If the value is a Module, it's returned as a ModuleHash.
|
27
|
+
def wrap(value)
|
28
|
+
case value
|
29
|
+
when Arq::Action
|
30
|
+
@action_inst.call_other(value)
|
31
|
+
when Module
|
32
|
+
self.class.new(value, @action_inst)
|
33
|
+
else
|
34
|
+
value
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/lib/arq/version.rb
CHANGED
data/lib/arq.rb
CHANGED
@@ -1,7 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "active_support/core_ext/string"
|
4
|
+
|
3
5
|
require_relative "arq/version"
|
4
6
|
require_relative "arq/errors"
|
5
7
|
require_relative "arq/context"
|
6
|
-
require_relative "arq/
|
8
|
+
require_relative "arq/module_hash"
|
7
9
|
require_relative "arq/action"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: arq
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kavin Phan
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-09-
|
11
|
+
date: 2022-09-29 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: A service skeleton framework heavily inspired by LightService with the
|
14
14
|
primary goal of being less verbose.
|
@@ -22,7 +22,7 @@ files:
|
|
22
22
|
- lib/arq/action.rb
|
23
23
|
- lib/arq/context.rb
|
24
24
|
- lib/arq/errors.rb
|
25
|
-
- lib/arq/
|
25
|
+
- lib/arq/module_hash.rb
|
26
26
|
- lib/arq/version.rb
|
27
27
|
homepage: https://github.com/kphan32/arq
|
28
28
|
licenses:
|
data/lib/arq/runnable.rb
DELETED
@@ -1,90 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Arq
|
4
|
-
# Represents a process to run with a given context, parameters, and returns.
|
5
|
-
# A Runnable is generated from an Action.
|
6
|
-
class Runnable
|
7
|
-
def initialize(ctx, params = [], returns = [], &block)
|
8
|
-
@ctx = ctx
|
9
|
-
@params = params
|
10
|
-
@returns = returns
|
11
|
-
@block = block
|
12
|
-
end
|
13
|
-
|
14
|
-
def call
|
15
|
-
return if @ctx.failure?
|
16
|
-
|
17
|
-
validate_required_params
|
18
|
-
|
19
|
-
import_context
|
20
|
-
val = run_block
|
21
|
-
export_context
|
22
|
-
|
23
|
-
# If the block returned an array, attempt to run
|
24
|
-
run_sequence(val) if val.is_a?(Array)
|
25
|
-
|
26
|
-
# Only validate returns if context is successful
|
27
|
-
validate_required_returns if @ctx.success?
|
28
|
-
|
29
|
-
val
|
30
|
-
end
|
31
|
-
|
32
|
-
def run(&block)
|
33
|
-
Arq::Runnable.new(@ctx, [], [], &block)
|
34
|
-
end
|
35
|
-
|
36
|
-
def fail!(message)
|
37
|
-
@ctx.fail!(message)
|
38
|
-
end
|
39
|
-
|
40
|
-
def fail_now!(message)
|
41
|
-
@ctx.fail_now!(message)
|
42
|
-
end
|
43
|
-
|
44
|
-
private
|
45
|
-
|
46
|
-
def run_block
|
47
|
-
instance_eval(&@block)
|
48
|
-
rescue Arq::FailureError
|
49
|
-
nil
|
50
|
-
end
|
51
|
-
|
52
|
-
def run_sequence(sequence)
|
53
|
-
sequence.each do |e|
|
54
|
-
case e
|
55
|
-
when Arq::Action
|
56
|
-
e.call(@ctx)
|
57
|
-
when Arq::Runnable
|
58
|
-
e.call
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
def import_context
|
64
|
-
@ctx.each do |key, val|
|
65
|
-
instance_variable_set(:"@#{key}", val)
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
def export_context
|
70
|
-
keys = [*@ctx.keys, *@returns]
|
71
|
-
|
72
|
-
keys.each do |key|
|
73
|
-
instance_key = :"@#{key}"
|
74
|
-
# Must check for existence since getting non-existent
|
75
|
-
# instance variables will return nil.
|
76
|
-
@ctx[key] = instance_variable_get(instance_key) if instance_variables.include?(instance_key)
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
def validate_required_params
|
81
|
-
missing_params = (@params - @ctx.keys)
|
82
|
-
raise Arq::ParametersNotInContextError, missing_params unless missing_params.empty?
|
83
|
-
end
|
84
|
-
|
85
|
-
def validate_required_returns
|
86
|
-
missing_returns = (@returns - @ctx.keys)
|
87
|
-
raise Arq::ReturnValuesNotInContextError, missing_returns unless missing_returns.empty?
|
88
|
-
end
|
89
|
-
end
|
90
|
-
end
|