nocode 0.0.6 → 0.0.10
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +19 -2
- data/lib/nocode/context.rb +8 -0
- data/lib/nocode/job_executor.rb +8 -16
- data/lib/nocode/step_registry.rb +3 -3
- data/lib/nocode/steps/each.rb +25 -9
- 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_executor.rb +2 -13
- data/lib/nocode/util/class_registry.rb +2 -2
- data/lib/nocode/util.rb +0 -1
- data/lib/nocode/version.rb +1 -1
- data/lib/nocode.rb +1 -0
- data/nocode.gemspec +2 -0
- metadata +26 -4
- data/lib/nocode/util/object_template.rb +0 -44
- data/lib/nocode/util/string_template.rb +0 -49
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e8132a6f8dd5bde1975030689aaed4f3858243075116febf95c34fa182df67f5
|
4
|
+
data.tar.gz: 950d30f0d5c5d9ff9c670119f3f03e90628a4ef54b578ca925be9c5f23a0995f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 72a179c3862851d65cf38679d2f147da64bb5f3bcceca8c2f7849c3687500f8637fb4c1f3ae78a90f670e356ef19d37ff2b3e35559d11e32467c4ac0b3c1e43b
|
7
|
+
data.tar.gz: 0dafc012dbcd75fe1ac4af1cda75e3084a8c9c85b9e21e51b69451b70b968aba7d03fdb5d485eb44b9f4ecca997a932c1dba750f5e7e8e8bbfcec074b777bde0
|
data/CHANGELOG.md
CHANGED
@@ -1,11 +1,28 @@
|
|
1
|
+
#### 0.0.10 - February 18th, 2022
|
2
|
+
|
3
|
+
* Replace ObjectTemplate with Nay library.
|
4
|
+
#### 0.0.9 - February 18th, 2022
|
5
|
+
|
6
|
+
* Replace StringTemplate with Nay library.
|
7
|
+
#### 0.0.8 - February 14th, 2022
|
8
|
+
|
9
|
+
* Add `map` step to iterate and collect a dataset result.
|
10
|
+
* Add `record/map` step to iterate over a hash.
|
11
|
+
* Add `io/list` to populate a register with the contents of a directory.
|
12
|
+
* Add `io/delete` to delete a file specified in the path option.
|
13
|
+
#### 0.0.7 - February 13th, 2022
|
14
|
+
|
15
|
+
* Move shared logging logic to context (until a first class log writer emerges).
|
16
|
+
* Provide type_prefix option for class_registry
|
17
|
+
|
1
18
|
#### 0.0.6 - February 13th, 2022
|
2
19
|
|
3
20
|
* Expose registers to main YAML configuration.
|
4
|
-
* Add
|
21
|
+
* Add `each` step to serve as an example of an iterator.
|
5
22
|
|
6
23
|
#### 0.0.5 - February 13th, 2022
|
7
24
|
|
8
|
-
* Added initial
|
25
|
+
* Added initial `dataset` steps.
|
9
26
|
|
10
27
|
#### 0.0.4 - February 13th, 2022
|
11
28
|
|
data/lib/nocode/context.rb
CHANGED
data/lib/nocode/job_executor.rb
CHANGED
@@ -31,33 +31,25 @@ module Nocode
|
|
31
31
|
registers: registers
|
32
32
|
)
|
33
33
|
|
34
|
-
log_title
|
34
|
+
log_title(context)
|
35
35
|
|
36
36
|
StepsExecutor.new(context: context, steps: steps).execute
|
37
37
|
|
38
|
-
log("Ended: #{DateTime.now}")
|
39
|
-
log_line
|
38
|
+
context.log("Ended: #{DateTime.now}")
|
39
|
+
context.log_line
|
40
40
|
|
41
41
|
context
|
42
42
|
end
|
43
43
|
|
44
44
|
private
|
45
45
|
|
46
|
-
def log_title
|
47
|
-
log_line
|
46
|
+
def log_title(context)
|
47
|
+
context.log_line
|
48
48
|
|
49
|
-
log('Nocode Execution')
|
50
|
-
log("Started: #{DateTime.now}")
|
49
|
+
context.log('Nocode Execution')
|
50
|
+
context.log("Started: #{DateTime.now}")
|
51
51
|
|
52
|
-
log_line
|
53
|
-
end
|
54
|
-
|
55
|
-
def log_line
|
56
|
-
log('-' * 50)
|
57
|
-
end
|
58
|
-
|
59
|
-
def log(msg)
|
60
|
-
io.puts(msg)
|
52
|
+
context.log_line
|
61
53
|
end
|
62
54
|
end
|
63
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
|
|
data/lib/nocode/steps/each.rb
CHANGED
@@ -12,20 +12,36 @@ module Nocode
|
|
12
12
|
|
13
13
|
skip_options_evaluation!
|
14
14
|
|
15
|
-
# rubocop:disable Metrics/AbcSize
|
16
15
|
def perform
|
17
|
-
entries = array(registers[register_option])
|
18
|
-
|
19
16
|
entries.each_with_index do |entry, index|
|
20
|
-
|
21
|
-
|
22
|
-
registers["#{element_register_prefix_option}_element"] = entry
|
23
|
-
registers["#{element_register_prefix_option}_index"] = index
|
17
|
+
registers[element_key] = entry
|
18
|
+
registers[index_key] = index
|
24
19
|
|
25
|
-
|
20
|
+
execute_steps
|
26
21
|
end
|
27
22
|
end
|
28
|
-
|
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
|
29
45
|
end
|
30
46
|
end
|
31
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
|
@@ -13,7 +13,7 @@ module Nocode
|
|
13
13
|
|
14
14
|
attr_reader :context, :steps
|
15
15
|
|
16
|
-
def_delegators :context, :
|
16
|
+
def_delegators :context, :log_line, :log
|
17
17
|
|
18
18
|
def initialize(context:, steps:)
|
19
19
|
@context = context
|
@@ -32,11 +32,8 @@ module Nocode
|
|
32
32
|
|
33
33
|
private
|
34
34
|
|
35
|
-
# TODO: It could be better encapsulated to move the evaluation logic into the step itself
|
36
|
-
# and let it deal with compilation. This may call for re-working the lifecycle of the Step
|
37
|
-
# class so I will temporarily defer this refactoring.
|
38
35
|
def make_step(step)
|
39
|
-
evaluated_step =
|
36
|
+
evaluated_step = Nay.evaluate(step, context.to_h)
|
40
37
|
type = evaluated_step[TYPE_KEY].to_s
|
41
38
|
name = evaluated_step[NAME_KEY].to_s
|
42
39
|
step_class = StepRegistry.constant!(type)
|
@@ -67,13 +64,5 @@ module Nocode
|
|
67
64
|
|
68
65
|
log_line
|
69
66
|
end
|
70
|
-
|
71
|
-
def log_line
|
72
|
-
log('-' * 50)
|
73
|
-
end
|
74
|
-
|
75
|
-
def log(msg)
|
76
|
-
io.puts(msg)
|
77
|
-
end
|
78
67
|
end
|
79
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
|
data/lib/nocode/util.rb
CHANGED
data/lib/nocode/version.rb
CHANGED
data/lib/nocode.rb
CHANGED
data/nocode.gemspec
CHANGED
metadata
CHANGED
@@ -1,15 +1,35 @@
|
|
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.10
|
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-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: nay
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.0'
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 0.0.3
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - "~>"
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0.0'
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 0.0.3
|
13
33
|
- !ruby/object:Gem::Dependency
|
14
34
|
name: bundler-audit
|
15
35
|
requirement: !ruby/object:Gem::Requirement
|
@@ -189,9 +209,13 @@ files:
|
|
189
209
|
- lib/nocode/steps/deserialize/json.rb
|
190
210
|
- lib/nocode/steps/deserialize/yaml.rb
|
191
211
|
- lib/nocode/steps/each.rb
|
212
|
+
- lib/nocode/steps/io/delete.rb
|
213
|
+
- lib/nocode/steps/io/list.rb
|
192
214
|
- lib/nocode/steps/io/read.rb
|
193
215
|
- lib/nocode/steps/io/write.rb
|
194
216
|
- lib/nocode/steps/log.rb
|
217
|
+
- lib/nocode/steps/map.rb
|
218
|
+
- lib/nocode/steps/record/map.rb
|
195
219
|
- lib/nocode/steps/serialize/csv.rb
|
196
220
|
- lib/nocode/steps/serialize/json.rb
|
197
221
|
- lib/nocode/steps/serialize/yaml.rb
|
@@ -203,9 +227,7 @@ files:
|
|
203
227
|
- lib/nocode/util/class_loader.rb
|
204
228
|
- lib/nocode/util/class_registry.rb
|
205
229
|
- lib/nocode/util/dictionary.rb
|
206
|
-
- lib/nocode/util/object_template.rb
|
207
230
|
- lib/nocode/util/optionable.rb
|
208
|
-
- lib/nocode/util/string_template.rb
|
209
231
|
- lib/nocode/version.rb
|
210
232
|
- nocode.gemspec
|
211
233
|
homepage: https://github.com/mattruggio/nocode
|
@@ -1,44 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative 'string_template'
|
4
|
-
|
5
|
-
module Nocode
|
6
|
-
module Util
|
7
|
-
# Built on top of StringTemplate but instead of only working for a string, this will
|
8
|
-
# recursively evaluate all strings within an object. Heuristics:
|
9
|
-
# - Strings evaluate using StringTemplate
|
10
|
-
# - Hashes will have their keys and values traversed
|
11
|
-
# - Arrays will have their entries traversed
|
12
|
-
# - All other types will simply return themselves
|
13
|
-
class ObjectTemplate
|
14
|
-
attr_reader :object
|
15
|
-
|
16
|
-
def initialize(object)
|
17
|
-
@object = object
|
18
|
-
|
19
|
-
freeze
|
20
|
-
end
|
21
|
-
|
22
|
-
def evaluate(values = {})
|
23
|
-
recursive_evaluate(object, values)
|
24
|
-
end
|
25
|
-
|
26
|
-
private
|
27
|
-
|
28
|
-
def recursive_evaluate(expression, values)
|
29
|
-
case expression
|
30
|
-
when Array
|
31
|
-
expression.map { |o| recursive_evaluate(o, values) }
|
32
|
-
when Hash
|
33
|
-
expression.to_h do |k, v|
|
34
|
-
[recursive_evaluate(k, values), recursive_evaluate(v, values)]
|
35
|
-
end
|
36
|
-
when String
|
37
|
-
Util::StringTemplate.new(expression).evaluate(values)
|
38
|
-
else
|
39
|
-
expression
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
@@ -1,49 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Nocode
|
4
|
-
module Util
|
5
|
-
# Takes in an expression and interpolates in any parameters using << >> notation.
|
6
|
-
# For example:
|
7
|
-
# input = { 'person' => 'hops' }
|
8
|
-
# Nocode::Util::StringTemplate.new("Hello, << person.name >>!").evaluate(input)
|
9
|
-
# Should produce: "Hello, hops!"
|
10
|
-
class StringTemplate
|
11
|
-
LEFT_TOKEN = '<<'
|
12
|
-
RIGHT_TOKEN = '>>'
|
13
|
-
SEPARATOR = '.'
|
14
|
-
REG_EXPR = /#{Regexp.quote(LEFT_TOKEN)}(.*?)#{Regexp.quote(RIGHT_TOKEN)}/.freeze
|
15
|
-
|
16
|
-
attr_reader :expression
|
17
|
-
|
18
|
-
def initialize(expression)
|
19
|
-
@expression = expression.to_s
|
20
|
-
|
21
|
-
freeze
|
22
|
-
end
|
23
|
-
|
24
|
-
def evaluate(values = {})
|
25
|
-
resolved = tokens_to_values(tokens, values)
|
26
|
-
|
27
|
-
tokens.inject(expression) do |memo, token|
|
28
|
-
memo.gsub("#{LEFT_TOKEN}#{token}#{RIGHT_TOKEN}", resolved[token].to_s)
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
private
|
33
|
-
|
34
|
-
def tokens
|
35
|
-
expression.to_s.scan(REG_EXPR).flatten
|
36
|
-
end
|
37
|
-
|
38
|
-
def tokens_to_values(tokens, values)
|
39
|
-
tokens.each_with_object({}) do |token, memo|
|
40
|
-
cleansed = token.strip
|
41
|
-
parts = cleansed.split(SEPARATOR)
|
42
|
-
value = values.dig(*parts)
|
43
|
-
|
44
|
-
memo[token] = value
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|