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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bb204abe5d0c62fce45c1c9afd052fe90e21c9f422020b7acb497dd3e226c22b
4
- data.tar.gz: dedd69881e903e5a1778303ea5adcd114fdcba10fbadbe2605c7e72b867beb83
3
+ metadata.gz: e8132a6f8dd5bde1975030689aaed4f3858243075116febf95c34fa182df67f5
4
+ data.tar.gz: 950d30f0d5c5d9ff9c670119f3f03e90628a4ef54b578ca925be9c5f23a0995f
5
5
  SHA512:
6
- metadata.gz: 1e36a07d157d207d70606a067561cbfd049fab0842c124ebb252ef7e15d2bf1e397f5e683b17cead76f92e75112596038d627189ad9e37372bf7236341d500ef
7
- data.tar.gz: dfb6f8759f55c3234fc04bae3e1701679b59d6e2678ae12d81190d9775f22a1f87beb6de63e0e58da5e7454d47ba72e3ec3791df66ce43a4e015a6ab8892878a
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 Each step to serve as an example of an iterator.
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 Dataset steps.
25
+ * Added initial `dataset` steps.
9
26
 
10
27
  #### 0.0.4 - February 13th, 2022
11
28
 
@@ -33,5 +33,13 @@ module Nocode
33
33
  PARAMETERS_KEY => parameters
34
34
  }
35
35
  end
36
+
37
+ def log_line
38
+ log('-' * 50)
39
+ end
40
+
41
+ def log(msg)
42
+ io.puts(msg)
43
+ end
36
44
  end
37
45
  end
@@ -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
@@ -10,8 +10,8 @@ module Nocode
10
10
  class StepRegistry < Util::ClassRegistry
11
11
  include Singleton
12
12
 
13
- PREFIX = 'Nocode::Steps::'
14
- DIR = File.join(__dir__, 'steps')
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, PREFIX)
30
+ load(files_loaded, class_prefix: CLASS_PREFIX)
31
31
  end
32
32
  end
33
33
 
@@ -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
- steps = array(steps_option)
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
- StepsExecutor.new(context: context, steps: steps).execute
20
+ execute_steps
26
21
  end
27
22
  end
28
- # rubocop:enable Metrics/AbcSize
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, :io
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 = Util::ObjectTemplate.new(step).evaluate(context.to_h)
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, prefix = '')
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, "#{prefix}#{pascal_cased}")
29
+ register("#{type_prefix}#{type}", "#{class_prefix}#{pascal_cased}")
30
30
  end
31
31
 
32
32
  self
data/lib/nocode/util.rb CHANGED
@@ -4,5 +4,4 @@ require_relative 'util/arrayable'
4
4
  require_relative 'util/class_loader'
5
5
  require_relative 'util/class_registry'
6
6
  require_relative 'util/dictionary'
7
- require_relative 'util/object_template'
8
7
  require_relative 'util/optionable'
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Nocode
4
- VERSION = '0.0.6'
4
+ VERSION = '0.0.10'
5
5
  end
data/lib/nocode.rb CHANGED
@@ -4,6 +4,7 @@ require 'benchmark'
4
4
  require 'csv'
5
5
  require 'fileutils'
6
6
  require 'json'
7
+ require 'nay'
7
8
  require 'singleton'
8
9
  require 'time'
9
10
  require 'yaml'
data/nocode.gemspec CHANGED
@@ -29,6 +29,8 @@ Gem::Specification.new do |s|
29
29
 
30
30
  s.required_ruby_version = '>= 2.6'
31
31
 
32
+ s.add_dependency('nay', '~>0.0', '>=0.0.3')
33
+
32
34
  s.add_development_dependency('bundler-audit')
33
35
  s.add_development_dependency('guard-rspec')
34
36
  s.add_development_dependency('pry')
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.6
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-14 00:00:00.000000000 Z
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