nocode 0.0.6 → 0.0.10
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 +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
|