nocode 0.0.4 → 0.0.8
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/CHANGELOG.md +22 -1
- data/README.md +1 -1
- data/exe/nocode +2 -0
- data/lib/nocode/context.rb +16 -3
- data/lib/nocode/job_executor.rb +55 -0
- data/lib/nocode/step_registry.rb +3 -3
- data/lib/nocode/steps/dataset/append.rb +21 -0
- data/lib/nocode/steps/dataset/coalesce.rb +22 -0
- data/lib/nocode/steps/dataset/insert.rb +29 -0
- data/lib/nocode/steps/dataset/prepend.rb +21 -0
- data/lib/nocode/steps/dataset/range.rb +32 -0
- data/lib/nocode/steps/each.rb +47 -0
- data/lib/nocode/steps/io/delete.rb +24 -0
- data/lib/nocode/steps/io/list.rb +25 -0
- data/lib/nocode/steps/map.rb +52 -0
- data/lib/nocode/steps/record/map.rb +25 -0
- data/lib/nocode/steps/serialize/csv.rb +0 -6
- data/lib/nocode/steps/sleep.rb +2 -0
- data/lib/nocode/steps_executor.rb +68 -0
- data/lib/nocode/util/class_registry.rb +2 -2
- data/lib/nocode/util/optionable.rb +8 -0
- data/lib/nocode/version.rb +1 -1
- data/lib/nocode.rb +2 -2
- metadata +14 -3
- data/lib/nocode/executor.rb +0 -84
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f42cd4574b36e4098fbb2c3de7263d8530ee2c935ec1d86da30950c51f45998e
|
4
|
+
data.tar.gz: a1259cd1075a946a056db27b2a3da5c7acebee2002c0f1e01b2f6a5fef203fa9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7be2f97365a7d2494e956362074d47c07cf39a741af34299b2bd30e70c2a74f8bf7566a24de816b4af692deede762c4e03ba9b2e1f8ddd81cf161a263e6e6f1b
|
7
|
+
data.tar.gz: '0099f90f5b0a569f2fe95b93d16aa5e737f957830bcfcb84d598f362c21edec9c759e113f0d01049a5ecfa05bb17d5e70ec49436b5c558a66f0e194d8c32ff28'
|
data/CHANGELOG.md
CHANGED
@@ -1,7 +1,28 @@
|
|
1
|
+
|
2
|
+
#### 0.0.8 - February 14th, 2022
|
3
|
+
|
4
|
+
* Add `map` step to iterate and collect a dataset result.
|
5
|
+
* Add `record/map` step to iterate over a hash.
|
6
|
+
* Add `io/list` to populate a register with the contents of a directory.
|
7
|
+
* Add `io/delete` to delete a file specified in the path option.
|
8
|
+
#### 0.0.7 - February 13th, 2022
|
9
|
+
|
10
|
+
* Move shared logging logic to context (until a first class log writer emerges).
|
11
|
+
* Provide type_prefix option for class_registry
|
12
|
+
|
13
|
+
#### 0.0.6 - February 13th, 2022
|
14
|
+
|
15
|
+
* Expose registers to main YAML configuration.
|
16
|
+
* Add `each` step to serve as an example of an iterator.
|
17
|
+
|
18
|
+
#### 0.0.5 - February 13th, 2022
|
19
|
+
|
20
|
+
* Added initial `dataset` steps.
|
21
|
+
|
1
22
|
#### 0.0.4 - February 13th, 2022
|
2
23
|
|
3
24
|
* Increase class documentation
|
4
|
-
* Add YAML serialization/
|
25
|
+
* Add YAML serialization/deserialization
|
5
26
|
|
6
27
|
#### 0.0.3 - February 12th, 2022
|
7
28
|
|
data/README.md
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
#### Execute Ruby code through YAML
|
4
4
|
|
5
|
-
[](https://badge.fury.io/rb/nocode) [](https://github.com/mattruggio/nocode/actions/workflows/rubygem.yml)
|
5
|
+
[](https://badge.fury.io/rb/nocode) [](https://github.com/mattruggio/nocode/actions/workflows/rubygem.yml) [](https://codeclimate.com/github/mattruggio/nocode/maintainability) [](https://opensource.org/licenses/MIT)
|
6
6
|
|
7
7
|
This is a proof of concept showing how a YAML interface could be draped over arbitrary Ruby code. The YAML contains a series of steps with each step mapping to a specific Ruby class. The Ruby classes just have one responsibility: to implement #perform.
|
8
8
|
|
data/exe/nocode
CHANGED
data/lib/nocode/context.rb
CHANGED
@@ -4,7 +4,12 @@ module Nocode
|
|
4
4
|
# Describes the environment for each running step. An instance is initialized when a job
|
5
5
|
# kicks off and then is passed from step to step.
|
6
6
|
class Context
|
7
|
-
|
7
|
+
PARAMETERS_KEY = 'parameters'
|
8
|
+
REGISTERS_KEY = 'registers'
|
9
|
+
|
10
|
+
attr_reader :io,
|
11
|
+
:parameters,
|
12
|
+
:registers
|
8
13
|
|
9
14
|
def initialize(io: $stdout, parameters: {}, registers: {})
|
10
15
|
@io = io || $stdout
|
@@ -24,9 +29,17 @@ module Nocode
|
|
24
29
|
|
25
30
|
def to_h
|
26
31
|
{
|
27
|
-
|
28
|
-
|
32
|
+
REGISTERS_KEY => registers,
|
33
|
+
PARAMETERS_KEY => parameters
|
29
34
|
}
|
30
35
|
end
|
36
|
+
|
37
|
+
def log_line
|
38
|
+
log('-' * 50)
|
39
|
+
end
|
40
|
+
|
41
|
+
def log(msg)
|
42
|
+
io.puts(msg)
|
43
|
+
end
|
31
44
|
end
|
32
45
|
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'context'
|
4
|
+
require_relative 'steps_executor'
|
5
|
+
|
6
|
+
module Nocode
|
7
|
+
# Manages the lifecycle and executes a job.
|
8
|
+
class JobExecutor
|
9
|
+
PARAMETERS_KEY = 'parameters'
|
10
|
+
REGISTERS_KEY = 'registers'
|
11
|
+
STEPS_KEY = 'steps'
|
12
|
+
|
13
|
+
attr_reader :yaml, :io
|
14
|
+
|
15
|
+
def initialize(yaml, io: $stdout)
|
16
|
+
@yaml = yaml.respond_to?(:read) ? yaml.read : yaml
|
17
|
+
@yaml = YAML.safe_load(@yaml) || {}
|
18
|
+
@io = io
|
19
|
+
|
20
|
+
freeze
|
21
|
+
end
|
22
|
+
|
23
|
+
def execute
|
24
|
+
steps = yaml[STEPS_KEY] || []
|
25
|
+
parameters = yaml[PARAMETERS_KEY] || {}
|
26
|
+
registers = yaml[REGISTERS_KEY] || {}
|
27
|
+
|
28
|
+
context = Context.new(
|
29
|
+
io: io,
|
30
|
+
parameters: parameters,
|
31
|
+
registers: registers
|
32
|
+
)
|
33
|
+
|
34
|
+
log_title(context)
|
35
|
+
|
36
|
+
StepsExecutor.new(context: context, steps: steps).execute
|
37
|
+
|
38
|
+
context.log("Ended: #{DateTime.now}")
|
39
|
+
context.log_line
|
40
|
+
|
41
|
+
context
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def log_title(context)
|
47
|
+
context.log_line
|
48
|
+
|
49
|
+
context.log('Nocode Execution')
|
50
|
+
context.log("Started: #{DateTime.now}")
|
51
|
+
|
52
|
+
context.log_line
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
data/lib/nocode/step_registry.rb
CHANGED
@@ -10,8 +10,8 @@ module Nocode
|
|
10
10
|
class StepRegistry < Util::ClassRegistry
|
11
11
|
include Singleton
|
12
12
|
|
13
|
-
|
14
|
-
DIR
|
13
|
+
CLASS_PREFIX = 'Nocode::Steps::'
|
14
|
+
DIR = File.join(__dir__, 'steps')
|
15
15
|
|
16
16
|
class << self
|
17
17
|
extend Forwardable
|
@@ -27,7 +27,7 @@ module Nocode
|
|
27
27
|
files_loaded = Util::ClassLoader.new(DIR).load!
|
28
28
|
|
29
29
|
# Class the parent to load up the registry with the files we found.
|
30
|
-
load(files_loaded,
|
30
|
+
load(files_loaded, class_prefix: CLASS_PREFIX)
|
31
31
|
end
|
32
32
|
end
|
33
33
|
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Nocode
|
4
|
+
module Steps
|
5
|
+
module Dataset
|
6
|
+
# Add entries specified in the options to the end of the specified register's
|
7
|
+
# existing entries.
|
8
|
+
class Append < Step
|
9
|
+
option :entries, :register
|
10
|
+
|
11
|
+
def perform
|
12
|
+
registers[register_option] = array(registers[register_option])
|
13
|
+
|
14
|
+
array(entries_option).each do |entry|
|
15
|
+
registers[register_option].append(entry)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Nocode
|
4
|
+
module Steps
|
5
|
+
module Dataset
|
6
|
+
# Combine all specified from_registers into one dataset and place in the specified
|
7
|
+
# to_register. If anything currently exists in the to_register then it will be coerced
|
8
|
+
# to an array and prepended to the beginning.
|
9
|
+
class Coalesce < Step
|
10
|
+
option :from_registers, :to_register
|
11
|
+
|
12
|
+
def perform
|
13
|
+
registers[to_register_option] = array(registers[to_register_option])
|
14
|
+
|
15
|
+
array(from_registers_option).each do |from_register|
|
16
|
+
registers[to_register_option] += array(registers[from_register])
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Nocode
|
4
|
+
module Steps
|
5
|
+
module Dataset
|
6
|
+
# Insert the entries to the at_index of the specified register.
|
7
|
+
# If at_index is nil then they will appended to the end.
|
8
|
+
class Insert < Step
|
9
|
+
option :at_index, :entries, :register
|
10
|
+
|
11
|
+
def perform
|
12
|
+
registers[register_option] = array(registers[register_option])
|
13
|
+
|
14
|
+
registers[register_option].insert(at_index, *entries)
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def entries
|
20
|
+
array(entries_option)
|
21
|
+
end
|
22
|
+
|
23
|
+
def at_index
|
24
|
+
at_index_option.nil? ? -1 : at_index_option.to_i
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Nocode
|
4
|
+
module Steps
|
5
|
+
module Dataset
|
6
|
+
# Add entries specified in the options to the beginning of the specified register's
|
7
|
+
# existing entries.
|
8
|
+
class Prepend < Step
|
9
|
+
option :entries, :register
|
10
|
+
|
11
|
+
def perform
|
12
|
+
registers[register_option] = array(registers[register_option])
|
13
|
+
|
14
|
+
array(entries_option).reverse_each do |entry|
|
15
|
+
registers[register_option].prepend(entry)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Nocode
|
4
|
+
module Steps
|
5
|
+
module Dataset
|
6
|
+
# Slice a dataset and keep on the entries between start_index and end_index, inclusively.
|
7
|
+
# If start_index is not provided then it defaults to 0.
|
8
|
+
# If end_index is not provided then it defaults to the end of the dataset.
|
9
|
+
class Range < Step
|
10
|
+
option :end_index,
|
11
|
+
:register,
|
12
|
+
:start_index
|
13
|
+
|
14
|
+
def perform
|
15
|
+
registers[register_option] = array(registers[register_option])
|
16
|
+
|
17
|
+
registers[register_option] = registers[register_option][start_index..end_index]
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def start_index
|
23
|
+
start_index_option.nil? ? 0 : start_index_option.to_i
|
24
|
+
end
|
25
|
+
|
26
|
+
def end_index
|
27
|
+
end_index_option.nil? ? -1 : end_index_option.to_i
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Nocode
|
4
|
+
module Steps
|
5
|
+
# Iterate over a register. Each iteration will store the current element and index in
|
6
|
+
# special registers called: _element and _index. You can prefix these registers by setting
|
7
|
+
# the element_register_prefix option.
|
8
|
+
class Each < Step
|
9
|
+
option :element_register_prefix,
|
10
|
+
:register,
|
11
|
+
:steps
|
12
|
+
|
13
|
+
skip_options_evaluation!
|
14
|
+
|
15
|
+
def perform
|
16
|
+
entries.each_with_index do |entry, index|
|
17
|
+
registers[element_key] = entry
|
18
|
+
registers[index_key] = index
|
19
|
+
|
20
|
+
execute_steps
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def execute_steps
|
27
|
+
StepsExecutor.new(context: context, steps: steps).execute
|
28
|
+
end
|
29
|
+
|
30
|
+
def entries
|
31
|
+
array(registers[register_option])
|
32
|
+
end
|
33
|
+
|
34
|
+
def steps
|
35
|
+
array(steps_option)
|
36
|
+
end
|
37
|
+
|
38
|
+
def element_key
|
39
|
+
"#{element_register_prefix_option}_element"
|
40
|
+
end
|
41
|
+
|
42
|
+
def index_key
|
43
|
+
"#{element_register_prefix_option}_index"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Nocode
|
4
|
+
module Steps
|
5
|
+
module Io
|
6
|
+
# Delete the specified path. Does nothing if the file does not exist.
|
7
|
+
class Delete < Step
|
8
|
+
option :path
|
9
|
+
|
10
|
+
def perform
|
11
|
+
return if path.to_s.empty?
|
12
|
+
|
13
|
+
FileUtils.rm_f(path) if File.exist?(path)
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def path
|
19
|
+
File.join(*array(path_option))
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Nocode
|
4
|
+
module Steps
|
5
|
+
module Io
|
6
|
+
# List all files in the path option. Wildcards can be used.
|
7
|
+
#
|
8
|
+
# Mechanic: https://ruby-doc.org/core-2.5.0/Dir.html#method-c-glob
|
9
|
+
class List < Step
|
10
|
+
option :path,
|
11
|
+
:register
|
12
|
+
|
13
|
+
def perform
|
14
|
+
registers[register_option] = Dir[path].reject { |p| File.directory?(p) }
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def path
|
20
|
+
File.join(*array(path_option))
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Nocode
|
4
|
+
module Steps
|
5
|
+
# Iterate over a register. Each iteration will store the current element and index in
|
6
|
+
# special registers called: _element and _index. You can prefix these registers by setting
|
7
|
+
# the element_register_prefix option.
|
8
|
+
#
|
9
|
+
# The main difference between this and 'each' is that this will collect the iterator
|
10
|
+
# element register and set the register to this new collection.
|
11
|
+
class Map < Step
|
12
|
+
option :element_register_prefix,
|
13
|
+
:register,
|
14
|
+
:steps
|
15
|
+
|
16
|
+
skip_options_evaluation!
|
17
|
+
|
18
|
+
def perform
|
19
|
+
registers[register_option] = entries.map.with_index do |entry, index|
|
20
|
+
registers[element_key] = entry
|
21
|
+
registers[index_key] = index
|
22
|
+
|
23
|
+
execute_steps
|
24
|
+
|
25
|
+
registers[element_key]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def execute_steps
|
32
|
+
StepsExecutor.new(context: context, steps: steps).execute
|
33
|
+
end
|
34
|
+
|
35
|
+
def entries
|
36
|
+
array(registers[register_option])
|
37
|
+
end
|
38
|
+
|
39
|
+
def steps
|
40
|
+
array(steps_option)
|
41
|
+
end
|
42
|
+
|
43
|
+
def element_key
|
44
|
+
"#{element_register_prefix_option}_element"
|
45
|
+
end
|
46
|
+
|
47
|
+
def index_key
|
48
|
+
"#{element_register_prefix_option}_index"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Nocode
|
4
|
+
module Steps
|
5
|
+
module Record
|
6
|
+
# Create a new hash from an existing hash mapping each key as configured by the
|
7
|
+
# key_mappings option. The key_mappings option should be in the form of:
|
8
|
+
# new_key => old_key
|
9
|
+
class Map < Step
|
10
|
+
option :key_mappings, :register
|
11
|
+
|
12
|
+
def perform
|
13
|
+
input = registers[register_option] || {}
|
14
|
+
output = {}
|
15
|
+
|
16
|
+
(key_mappings_option || {}).each do |to, from|
|
17
|
+
output[to.to_s] = input[from.to_s]
|
18
|
+
end
|
19
|
+
|
20
|
+
registers[register_option] = output
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/nocode/steps/sleep.rb
CHANGED
@@ -0,0 +1,68 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'step_registry'
|
4
|
+
|
5
|
+
module Nocode
|
6
|
+
# Class that knows how to execute a series of steps given a context.
|
7
|
+
class StepsExecutor
|
8
|
+
extend Forwardable
|
9
|
+
|
10
|
+
NAME_KEY = 'name'
|
11
|
+
OPTIONS_KEY = 'options'
|
12
|
+
TYPE_KEY = 'type'
|
13
|
+
|
14
|
+
attr_reader :context, :steps
|
15
|
+
|
16
|
+
def_delegators :context, :log_line, :log
|
17
|
+
|
18
|
+
def initialize(context:, steps:)
|
19
|
+
@context = context
|
20
|
+
@steps = steps
|
21
|
+
|
22
|
+
freeze
|
23
|
+
end
|
24
|
+
|
25
|
+
def execute
|
26
|
+
steps.each do |step|
|
27
|
+
step_instance = make_step(step)
|
28
|
+
|
29
|
+
execute_step(step_instance)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def make_step(step)
|
36
|
+
evaluated_step = Util::ObjectTemplate.new(step).evaluate(context.to_h)
|
37
|
+
type = evaluated_step[TYPE_KEY].to_s
|
38
|
+
name = evaluated_step[NAME_KEY].to_s
|
39
|
+
step_class = StepRegistry.constant!(type)
|
40
|
+
|
41
|
+
options =
|
42
|
+
if step_class.skip_options_evaluation?
|
43
|
+
step[OPTIONS_KEY]
|
44
|
+
else
|
45
|
+
evaluated_step[OPTIONS_KEY]
|
46
|
+
end
|
47
|
+
|
48
|
+
step_class.new(
|
49
|
+
options: Util::Dictionary.new(options),
|
50
|
+
context: context,
|
51
|
+
name: name,
|
52
|
+
type: type
|
53
|
+
)
|
54
|
+
end
|
55
|
+
|
56
|
+
def execute_step(step)
|
57
|
+
log(step.name) unless step.name.empty?
|
58
|
+
log("Step: #{step.type}")
|
59
|
+
log("Class: #{step.class}")
|
60
|
+
|
61
|
+
time_in_seconds = Benchmark.measure { step.perform }.real
|
62
|
+
|
63
|
+
log("Completed in #{time_in_seconds.round(3)} second(s)")
|
64
|
+
|
65
|
+
log_line
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -20,13 +20,13 @@ module Nocode
|
|
20
20
|
freeze
|
21
21
|
end
|
22
22
|
|
23
|
-
def load(types,
|
23
|
+
def load(types, class_prefix: '', type_prefix: '')
|
24
24
|
types.each do |type|
|
25
25
|
pascal_cased = type.split(File::SEPARATOR).map do |part|
|
26
26
|
part.split('_').collect(&:capitalize).join
|
27
27
|
end.join('::')
|
28
28
|
|
29
|
-
register(type, "#{
|
29
|
+
register("#{type_prefix}#{type}", "#{class_prefix}#{pascal_cased}")
|
30
30
|
end
|
31
31
|
|
32
32
|
self
|
@@ -23,6 +23,14 @@ module Nocode
|
|
23
23
|
|
24
24
|
# Class-level DSL Methods
|
25
25
|
module ClassMethods
|
26
|
+
def skip_options_evaluation?
|
27
|
+
@skip_options_evaluation || false
|
28
|
+
end
|
29
|
+
|
30
|
+
def skip_options_evaluation!
|
31
|
+
@skip_options_evaluation = true
|
32
|
+
end
|
33
|
+
|
26
34
|
def option(*values)
|
27
35
|
values.each { |v| options << v.to_s }
|
28
36
|
end
|
data/lib/nocode/version.rb
CHANGED
data/lib/nocode.rb
CHANGED
@@ -12,14 +12,14 @@ require 'yaml'
|
|
12
12
|
require 'nocode/util'
|
13
13
|
|
14
14
|
# Core
|
15
|
-
require 'nocode/
|
15
|
+
require 'nocode/job_executor'
|
16
16
|
|
17
17
|
# Establish main top-level namespace
|
18
18
|
module Nocode
|
19
19
|
# Default consumer entrypoint into the library.
|
20
20
|
class << self
|
21
21
|
def execute(yaml, io: $stdout)
|
22
|
-
|
22
|
+
JobExecutor.new(yaml, io: io).execute
|
23
23
|
end
|
24
24
|
end
|
25
25
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: nocode
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Matthew Ruggio
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-02-
|
11
|
+
date: 2022-02-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler-audit
|
@@ -175,22 +175,33 @@ files:
|
|
175
175
|
- exe/nocode
|
176
176
|
- lib/nocode.rb
|
177
177
|
- lib/nocode/context.rb
|
178
|
-
- lib/nocode/
|
178
|
+
- lib/nocode/job_executor.rb
|
179
179
|
- lib/nocode/step.rb
|
180
180
|
- lib/nocode/step_registry.rb
|
181
181
|
- lib/nocode/steps/copy.rb
|
182
|
+
- lib/nocode/steps/dataset/append.rb
|
183
|
+
- lib/nocode/steps/dataset/coalesce.rb
|
184
|
+
- lib/nocode/steps/dataset/insert.rb
|
185
|
+
- lib/nocode/steps/dataset/prepend.rb
|
186
|
+
- lib/nocode/steps/dataset/range.rb
|
182
187
|
- lib/nocode/steps/delete.rb
|
183
188
|
- lib/nocode/steps/deserialize/csv.rb
|
184
189
|
- lib/nocode/steps/deserialize/json.rb
|
185
190
|
- lib/nocode/steps/deserialize/yaml.rb
|
191
|
+
- lib/nocode/steps/each.rb
|
192
|
+
- lib/nocode/steps/io/delete.rb
|
193
|
+
- lib/nocode/steps/io/list.rb
|
186
194
|
- lib/nocode/steps/io/read.rb
|
187
195
|
- lib/nocode/steps/io/write.rb
|
188
196
|
- lib/nocode/steps/log.rb
|
197
|
+
- lib/nocode/steps/map.rb
|
198
|
+
- lib/nocode/steps/record/map.rb
|
189
199
|
- lib/nocode/steps/serialize/csv.rb
|
190
200
|
- lib/nocode/steps/serialize/json.rb
|
191
201
|
- lib/nocode/steps/serialize/yaml.rb
|
192
202
|
- lib/nocode/steps/set.rb
|
193
203
|
- lib/nocode/steps/sleep.rb
|
204
|
+
- lib/nocode/steps_executor.rb
|
194
205
|
- lib/nocode/util.rb
|
195
206
|
- lib/nocode/util/arrayable.rb
|
196
207
|
- lib/nocode/util/class_loader.rb
|
data/lib/nocode/executor.rb
DELETED
@@ -1,84 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative 'context'
|
4
|
-
require_relative 'step_registry'
|
5
|
-
|
6
|
-
module Nocode
|
7
|
-
# Manages the lifecycle and executes a job.
|
8
|
-
class Executor
|
9
|
-
attr_reader :yaml, :io
|
10
|
-
|
11
|
-
def initialize(yaml, io: $stdout)
|
12
|
-
@yaml = yaml.respond_to?(:read) ? yaml.read : yaml
|
13
|
-
@yaml = YAML.safe_load(@yaml) || {}
|
14
|
-
@io = io
|
15
|
-
|
16
|
-
freeze
|
17
|
-
end
|
18
|
-
|
19
|
-
def execute
|
20
|
-
steps = yaml['steps'] || []
|
21
|
-
parameters = yaml['parameters'] || {}
|
22
|
-
context = Context.new(io: io, parameters: parameters)
|
23
|
-
|
24
|
-
log_title
|
25
|
-
|
26
|
-
steps.each do |step|
|
27
|
-
step_instance = make_step(step, context)
|
28
|
-
|
29
|
-
execute_step(step_instance)
|
30
|
-
end
|
31
|
-
|
32
|
-
log("Ended: #{DateTime.now}")
|
33
|
-
log_line
|
34
|
-
|
35
|
-
context
|
36
|
-
end
|
37
|
-
|
38
|
-
private
|
39
|
-
|
40
|
-
def make_step(step, context)
|
41
|
-
step = Util::ObjectTemplate.new(step).evaluate(context.to_h)
|
42
|
-
type = step['type'].to_s
|
43
|
-
name = step['name'].to_s
|
44
|
-
options = step['options'] || {}
|
45
|
-
step_class = StepRegistry.constant!(type)
|
46
|
-
|
47
|
-
step_class.new(
|
48
|
-
options: Util::Dictionary.new(options),
|
49
|
-
context: context,
|
50
|
-
name: name,
|
51
|
-
type: type
|
52
|
-
)
|
53
|
-
end
|
54
|
-
|
55
|
-
def execute_step(step)
|
56
|
-
log(step.name) unless step.name.empty?
|
57
|
-
log("Step: #{step.type}")
|
58
|
-
log("Class: #{step.class}")
|
59
|
-
|
60
|
-
time_in_seconds = Benchmark.measure { step.perform }.real
|
61
|
-
|
62
|
-
log("Completed in #{time_in_seconds.round(3)} second(s)")
|
63
|
-
|
64
|
-
log_line
|
65
|
-
end
|
66
|
-
|
67
|
-
def log_title
|
68
|
-
log_line
|
69
|
-
|
70
|
-
log('Nocode Execution')
|
71
|
-
log("Started: #{DateTime.now}")
|
72
|
-
|
73
|
-
log_line
|
74
|
-
end
|
75
|
-
|
76
|
-
def log_line
|
77
|
-
log('-' * 50)
|
78
|
-
end
|
79
|
-
|
80
|
-
def log(msg)
|
81
|
-
io.puts(msg)
|
82
|
-
end
|
83
|
-
end
|
84
|
-
end
|