arq 0.2.1 → 0.3.1
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 +156 -35
- data/lib/arq/action_module_hash.rb +44 -0
- data/lib/arq/version.rb +1 -1
- data/lib/arq.rb +3 -1
- metadata +4 -4
- data/lib/arq/runnable.rb +0 -109
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a0ee16565eecb2e2866939a75dae3fde195f0c941bddb66f43f98ccc92c0e642
|
4
|
+
data.tar.gz: 2e4ca8c155a462706ca2668b18bac36c38fac84b025f00f4b59f54d0d478a382
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 047d23d860d49a35f90564695578e776b35e3628d9f53681de8db4d2c4eaee407a8bae985983015c2e843e67bc70857e1ad173dfbb93d081cfeb9fdd7cf87dd8
|
7
|
+
data.tar.gz: 34f0ca90c2783f25623c1dfd464e7e4b7dce0677e187647678876aad0a5927b856bc77ed6e3d75bfd460a76f2488f0a5e9f084e6a80f3f76b23bb8ab5b5e7238
|
data/lib/arq/action.rb
CHANGED
@@ -1,55 +1,176 @@
|
|
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 paths with dot accessors.
|
121
|
+
# IE `Foo::Bar::Action` can be called via `foo.bar.action`
|
122
|
+
def method_missing(method, *args, &block)
|
123
|
+
# Format method as module path.
|
124
|
+
formatted = method.to_s.camelize
|
125
|
+
|
126
|
+
# Attempt to find object.
|
127
|
+
obj = if Object.const_defined?(formatted)
|
128
|
+
Object.const_get(formatted)
|
129
|
+
else
|
130
|
+
return super
|
131
|
+
end
|
132
|
+
|
133
|
+
# Defer handling to ActionModuleHash
|
134
|
+
Arq::ActionModuleHash.from(obj, self)
|
135
|
+
end
|
136
|
+
|
137
|
+
def respond_to_missing?(method, include_private: false)
|
138
|
+
Object.const_defined?(method.to_s.camelize) || super
|
139
|
+
end
|
140
|
+
|
141
|
+
private
|
142
|
+
|
143
|
+
# Load parameters of context as instance variables
|
144
|
+
def _import_context
|
145
|
+
@_ctx.each do |key, val|
|
146
|
+
instance_variable_set(:"@#{key}", val)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
# Exports instance variables (excluding those prefixed with _) to the context
|
151
|
+
def _export_variables
|
152
|
+
# Filter out vars starting with _
|
153
|
+
vars = instance_variables.filter do |key|
|
154
|
+
!key.start_with?("@_")
|
155
|
+
end
|
156
|
+
|
157
|
+
vars.each do |var|
|
158
|
+
# Strip @ prefix
|
159
|
+
key = var[1..].to_sym
|
160
|
+
|
161
|
+
@_ctx[key] = instance_variable_get(var)
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
def _validate_required_params
|
166
|
+
missing_params = (self.class.params_list - @_ctx.keys)
|
167
|
+
raise Arq::ParametersNotInContextError, missing_params unless missing_params.empty?
|
168
|
+
end
|
169
|
+
|
170
|
+
def _validate_required_returns
|
171
|
+
missing_returns = (self.class.returns_list - @_ctx.keys)
|
172
|
+
raise Arq::ReturnValuesNotInContextError, missing_returns unless missing_returns.empty?
|
173
|
+
end
|
53
174
|
end
|
54
175
|
end
|
55
176
|
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Arq
|
4
|
+
# Allows for dot-accessing of modules and running of actions.
|
5
|
+
# Child modules are automatically wrapped and actions are called.
|
6
|
+
class ActionModuleHash < Hash
|
7
|
+
# Calls action or wraps in hash class if module.
|
8
|
+
def self.from(obj, action_inst)
|
9
|
+
case obj
|
10
|
+
when Arq::Action
|
11
|
+
action_inst.call_other(obj)
|
12
|
+
when Module
|
13
|
+
new(obj, action_inst)
|
14
|
+
else
|
15
|
+
raise "Object must be an Action or Module"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def initialize(mod, action_inst)
|
20
|
+
super()
|
21
|
+
|
22
|
+
@module = mod
|
23
|
+
@action_inst = action_inst
|
24
|
+
end
|
25
|
+
|
26
|
+
def method_missing(method, *args, &block)
|
27
|
+
# Format method as module path.
|
28
|
+
formatted = method.to_s.camelize
|
29
|
+
|
30
|
+
# Attempt to find object.
|
31
|
+
obj = if Object.const_defined?(formatted)
|
32
|
+
Object.const_get(formatted)
|
33
|
+
else
|
34
|
+
return super
|
35
|
+
end
|
36
|
+
|
37
|
+
self.class.from(obj)
|
38
|
+
end
|
39
|
+
|
40
|
+
def respond_to_missing?(method, include_private = false)
|
41
|
+
@module.const_defined?(method.to_s.camelize.to_sym) || super
|
42
|
+
end
|
43
|
+
end
|
44
|
+
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/action_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.1
|
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.
|
@@ -20,9 +20,9 @@ extra_rdoc_files: []
|
|
20
20
|
files:
|
21
21
|
- lib/arq.rb
|
22
22
|
- lib/arq/action.rb
|
23
|
+
- lib/arq/action_module_hash.rb
|
23
24
|
- lib/arq/context.rb
|
24
25
|
- lib/arq/errors.rb
|
25
|
-
- lib/arq/runnable.rb
|
26
26
|
- lib/arq/version.rb
|
27
27
|
homepage: https://github.com/kphan32/arq
|
28
28
|
licenses:
|
@@ -48,7 +48,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
48
48
|
- !ruby/object:Gem::Version
|
49
49
|
version: '0'
|
50
50
|
requirements: []
|
51
|
-
rubygems_version: 3.
|
51
|
+
rubygems_version: 3.3.7
|
52
52
|
signing_key:
|
53
53
|
specification_version: 4
|
54
54
|
summary: A simple service skeleton framework
|
data/lib/arq/runnable.rb
DELETED
@@ -1,109 +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
|
-
val = run_block
|
20
|
-
|
21
|
-
# If the block returned an array, attempt to run
|
22
|
-
run_sequence(val) if val.is_a?(Array)
|
23
|
-
|
24
|
-
# Only validate returns if context is successful
|
25
|
-
validate_required_returns if @ctx.success?
|
26
|
-
|
27
|
-
val
|
28
|
-
end
|
29
|
-
|
30
|
-
def run(&block)
|
31
|
-
Arq::Runnable.new(@ctx, [], [], &block)
|
32
|
-
end
|
33
|
-
|
34
|
-
def fail!(message = nil)
|
35
|
-
@ctx.fail!(message)
|
36
|
-
end
|
37
|
-
|
38
|
-
def fail_now!(message = nil)
|
39
|
-
@ctx.fail_now!(message)
|
40
|
-
end
|
41
|
-
|
42
|
-
private
|
43
|
-
|
44
|
-
def run_block
|
45
|
-
with_context do
|
46
|
-
instance_eval(&@block)
|
47
|
-
rescue Arq::FailureError
|
48
|
-
nil
|
49
|
-
end
|
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
|
-
# Runs the block with context parameters set as instance variables, then
|
64
|
-
# imports all context parameters and any new instance vars into the context.
|
65
|
-
# Returns the return value of the block.
|
66
|
-
def with_context
|
67
|
-
# Grab all current variables to know what is being returned
|
68
|
-
before_vars = instance_variables
|
69
|
-
|
70
|
-
# Load all context parameters into runnable instance
|
71
|
-
import_context_to_vars
|
72
|
-
|
73
|
-
# Run block
|
74
|
-
val = yield
|
75
|
-
|
76
|
-
# Grab all ctx + new vars
|
77
|
-
ctx_vars = instance_variables - before_vars
|
78
|
-
|
79
|
-
# Import instance vars into ctx
|
80
|
-
import_vars_to_context(ctx_vars)
|
81
|
-
|
82
|
-
# Return block value
|
83
|
-
val
|
84
|
-
end
|
85
|
-
|
86
|
-
def import_context_to_vars
|
87
|
-
@ctx.each do |key, val|
|
88
|
-
instance_variable_set(:"@#{key}", val)
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
def import_vars_to_context(vars)
|
93
|
-
vars.each do |var|
|
94
|
-
key = var[1..].to_sym
|
95
|
-
@ctx[key] = instance_variable_get(var)
|
96
|
-
end
|
97
|
-
end
|
98
|
-
|
99
|
-
def validate_required_params
|
100
|
-
missing_params = (@params - @ctx.keys)
|
101
|
-
raise Arq::ParametersNotInContextError, missing_params unless missing_params.empty?
|
102
|
-
end
|
103
|
-
|
104
|
-
def validate_required_returns
|
105
|
-
missing_returns = (@returns - @ctx.keys)
|
106
|
-
raise Arq::ReturnValuesNotInContextError, missing_returns unless missing_returns.empty?
|
107
|
-
end
|
108
|
-
end
|
109
|
-
end
|