burner 0.0.0 → 1.0.0.pre.alpha

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c01fa95eaea68e4f0e84d616dcd22ecc3ffe4b415605ba70dc3484a6ed72868f
4
- data.tar.gz: 3e73452a5757d1cdb7c4a95aee1c4aebbb987f5f97bc1060d45eb18b29d77e5c
3
+ metadata.gz: 920f3b0f0027e21b30da75f86335d75d2d351f49c8b68662de7226ade43474c6
4
+ data.tar.gz: b7f4189e37023f1d627ea5222df0f397a24a69c7ce3721b13ce714d2e274ee94
5
5
  SHA512:
6
- metadata.gz: f6b9e1d10e4415d5cce06f0a0ccd0797df5e95a1ff53c5beb522e704cec8c11af2f8f48d57a2fb2194a0624f870885d39b4d5777099fcf1c1a9ee2edda8843ab
7
- data.tar.gz: e714ddeb82888412ab78167dcfa4f63f0ef4e391f7d9b3dee88b06a920a3cd6916186e2e4639dd4e85d977a7816a9025bcd6f4dcd56f6ff1ce19c2a5961d44a7
6
+ metadata.gz: d488edf32a95e5da64190c512f365d76e2414d16712cee9b56a400bd62e11ed7824a316a95923af15f0ecac3390e4be359d2e31ffc33fb13129309c4efce9403
7
+ data.tar.gz: 8640cfdb2fa4241fb2a493c2ac2aed62e08e1826446907f4b16d043276fffee656c787d2079545fe03d52b8f45756240a523ad878fc89063884868c3f94bfecd
data/.gitignore CHANGED
@@ -4,6 +4,3 @@
4
4
  /coverage
5
5
  Gemfile.lock
6
6
  /pkg
7
-
8
- /spec/config/database.yaml
9
- /spec/db
data/README.md CHANGED
@@ -1,5 +1,76 @@
1
1
  # Burner
2
2
 
3
- ---
3
+ [![Gem Version](https://badge.fury.io/rb/burner.svg)](https://badge.fury.io/rb/burner) [![Build Status](https://travis-ci.org/bluemarblepayroll/burner.svg?branch=master)](https://travis-ci.org/bluemarblepayroll/burner) [![Maintainability](https://api.codeclimate.com/v1/badges/dbc3757929b67504f6ca/maintainability)](https://codeclimate.com/github/bluemarblepayroll/burner/maintainability) [![Test Coverage](https://api.codeclimate.com/v1/badges/dbc3757929b67504f6ca/test_coverage)](https://codeclimate.com/github/bluemarblepayroll/burner/test_coverage) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
4
4
 
5
- Under construction.
5
+ TODO
6
+
7
+ ## Installation
8
+
9
+ To install through Rubygems:
10
+
11
+ ````bash
12
+ gem install burner
13
+ ````
14
+
15
+ You can also add this to your Gemfile:
16
+
17
+ ````bash
18
+ bundle add burner
19
+ ````
20
+
21
+ ## Examples
22
+
23
+ TODO
24
+
25
+ ## Contributing
26
+
27
+ ### Development Environment Configuration
28
+
29
+ Basic steps to take to get this repository compiling:
30
+
31
+ 1. Install [Ruby](https://www.ruby-lang.org/en/documentation/installation/) (check burner.gemspec for versions supported)
32
+ 2. Install bundler (gem install bundler)
33
+ 3. Clone the repository (git clone git@github.com:bluemarblepayroll/burner.git)
34
+ 4. Navigate to the root folder (cd burner)
35
+ 5. Install dependencies (bundle)
36
+
37
+ ### Running Tests
38
+
39
+ To execute the test suite run:
40
+
41
+ ````bash
42
+ bundle exec rspec spec --format documentation
43
+ ````
44
+
45
+ Alternatively, you can have Guard watch for changes:
46
+
47
+ ````bash
48
+ bundle exec guard
49
+ ````
50
+
51
+ Also, do not forget to run Rubocop:
52
+
53
+ ````bash
54
+ bundle exec rubocop
55
+ ````
56
+
57
+ ### Publishing
58
+
59
+ Note: ensure you have proper authorization before trying to publish new versions.
60
+
61
+ After code changes have successfully gone through the Pull Request review process then the following steps should be followed for publishing new versions:
62
+
63
+ 1. Merge Pull Request into master
64
+ 2. Update `lib/burner/version.rb` using [semantic versioning](https://semver.org/)
65
+ 3. Install dependencies: `bundle`
66
+ 4. Update `CHANGELOG.md` with release notes
67
+ 5. Commit & push master to remote and ensure CI builds master successfully
68
+ 6. Run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
69
+
70
+ ## Code of Conduct
71
+
72
+ Everyone interacting in this codebase, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/bluemarblepayroll/burner/blob/master/CODE_OF_CONDUCT.md).
73
+
74
+ ## License
75
+
76
+ This project is MIT Licensed.
@@ -15,7 +15,7 @@ Gem::Specification.new do |s|
15
15
  s.email = ['mruggio@bluemarblepayroll.com']
16
16
  s.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
17
17
  s.bindir = 'exe'
18
- s.executables = %w[]
18
+ s.executables = %w[burner]
19
19
  s.homepage = 'https://github.com/bluemarblepayroll/burner'
20
20
  s.license = 'MIT'
21
21
  s.metadata = {
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # Copyright (c) 2020-present, Blue Marble Payroll, LLC
6
+ #
7
+ # This source code is licensed under the MIT license found in the
8
+ # LICENSE file in the root directory of this source tree.
9
+ #
10
+
11
+ require 'bundler/setup'
12
+ require 'burner'
13
+ require 'pry'
14
+
15
+ if ARGV.empty?
16
+ puts 'Usage: ./exe/burner package.yaml key=value key=value ...'
17
+ exit
18
+ end
19
+
20
+ # This should return exit code of 1 if it raises any hard errors.
21
+ Burner::Cli.new(ARGV).execute
@@ -7,8 +7,13 @@
7
7
  # LICENSE file in the root directory of this source tree.
8
8
  #
9
9
 
10
- require_relative 'burner/cli'
10
+ require 'acts_as_hashable'
11
+ require 'benchmark'
12
+ require 'json'
13
+ require 'objectable'
14
+ require 'securerandom'
15
+ require 'singleton'
16
+ require 'stringento'
17
+ require 'yaml'
11
18
 
12
- # Placeholder
13
- module Burner
14
- end
19
+ require_relative 'burner/cli'
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Copyright (c) 2020-present, Blue Marble Payroll, LLC
5
+ #
6
+ # This source code is licensed under the MIT license found in the
7
+ # LICENSE file in the root directory of this source tree.
8
+ #
9
+
10
+ require_relative 'pipeline'
11
+
12
+ module Burner
13
+ # Process a single string as a Pipeline. This is mainly to back the command-line interface.
14
+ class Cli
15
+ attr_reader :params, :pipeline
16
+
17
+ def initialize(args)
18
+ path = args.first
19
+ cli_params = extract_cli_params(args)
20
+ config = read_yaml(path)
21
+ @pipeline = Burner::Pipeline.make(jobs: config['jobs'], steps: config['steps'])
22
+ @params = (config['params'] || {}).merge(cli_params)
23
+ end
24
+
25
+ def execute
26
+ pipeline.execute(params: params)
27
+ end
28
+
29
+ private
30
+
31
+ def read_yaml(path)
32
+ yaml = IO.read(path)
33
+
34
+ YAML.safe_load(yaml)
35
+ end
36
+
37
+ def extract_cli_params(args)
38
+ args[1..-1].each_with_object({}) do |arg, memo|
39
+ parts = arg.to_s.split('=')
40
+
41
+ memo[parts.first] = parts.last
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Copyright (c) 2020-present, Blue Marble Payroll, LLC
5
+ #
6
+ # This source code is licensed under the MIT license found in the
7
+ # LICENSE file in the root directory of this source tree.
8
+ #
9
+
10
+ require_relative 'string_template'
11
+
12
+ module Burner
13
+ # Abstract base class for all job subclasses. The only public method a subclass needs to
14
+ # implement #perform(params, payload, reporter) and then you can register it for use using
15
+ # the Burner::Jobs factory class method #register. An example of a registration:
16
+ # Burner::Jobs.register('your_class', YourClass)
17
+ class Job
18
+ acts_as_hashable
19
+
20
+ attr_reader :name, :string_template
21
+
22
+ def initialize(name:)
23
+ raise ArgumentError, 'name is required' if name.to_s.empty?
24
+
25
+ @name = name.to_s
26
+ @string_template = StringTemplate.instance
27
+ end
28
+
29
+ private
30
+
31
+ def eval_string_template(expression, input)
32
+ string_template.evaluate(expression, input)
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Copyright (c) 2020-present, Blue Marble Payroll, LLC
5
+ #
6
+ # This source code is licensed under the MIT license found in the
7
+ # LICENSE file in the root directory of this source tree.
8
+ #
9
+
10
+ require_relative 'job'
11
+ require_relative 'jobs/deserialize/json'
12
+ require_relative 'jobs/deserialize/yaml'
13
+ require_relative 'jobs/dummy'
14
+ require_relative 'jobs/echo'
15
+ require_relative 'jobs/io/read'
16
+ require_relative 'jobs/io/write'
17
+ require_relative 'jobs/serialize/json'
18
+ require_relative 'jobs/serialize/yaml'
19
+ require_relative 'jobs/set'
20
+ require_relative 'jobs/sleep'
21
+
22
+ module Burner
23
+ # Main library of jobs. This file contains all the basic/default jobs. All other consumer
24
+ # libraries/applications can register their own, for example:
25
+ # Burner::Jobs.register('your_class', YourClass)
26
+ class Jobs
27
+ acts_as_hashable_factory
28
+
29
+ register 'deserialize/json', Deserialize::Json
30
+ register 'deserialize/yaml', Deserialize::Yaml
31
+ register 'dummy', '', Dummy
32
+ register 'echo', Echo
33
+ register 'io/read', IO::Read
34
+ register 'io/write', IO::Write
35
+ register 'serialize/json', Serialize::Json
36
+ register 'serialize/yaml', Serialize::Yaml
37
+ register 'set', Set
38
+ register 'sleep', Sleep
39
+ end
40
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Copyright (c) 2020-present, Blue Marble Payroll, LLC
5
+ #
6
+ # This source code is licensed under the MIT license found in the
7
+ # LICENSE file in the root directory of this source tree.
8
+ #
9
+
10
+ module Burner
11
+ class Jobs
12
+ module Deserialize
13
+ # Take a JSON string and deserialize into object(s).
14
+ class Json < Job
15
+ def perform(_output, payload, _params)
16
+ payload.value = JSON.parse(payload.value)
17
+
18
+ nil
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Copyright (c) 2020-present, Blue Marble Payroll, LLC
5
+ #
6
+ # This source code is licensed under the MIT license found in the
7
+ # LICENSE file in the root directory of this source tree.
8
+ #
9
+
10
+ module Burner
11
+ class Jobs
12
+ module Deserialize
13
+ # Take a YAML string and deserialize into object(s).
14
+ class Yaml < Job
15
+ attr_reader :safe
16
+
17
+ def initialize(name:, safe: true)
18
+ super(name: name)
19
+
20
+ @safe = safe
21
+
22
+ freeze
23
+ end
24
+
25
+ # The YAML cop was disabled because the consumer may want to actually load unsafe
26
+ # YAML, which can load pretty much any type of class instead of putting the loader
27
+ # in a sandbox. By default, though, we will try and drive them towards using it
28
+ # in the safer alternative.
29
+ # rubocop:disable Security/YAMLLoad
30
+ def perform(output, payload, _params)
31
+ output.detail('Warning: loading YAML not using safe_load.') unless safe
32
+
33
+ payload.value = safe ? YAML.safe_load(payload.value) : YAML.load(payload.value)
34
+
35
+ nil
36
+ end
37
+ # rubocop:enable Security/YAMLLoad
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Copyright (c) 2020-present, Blue Marble Payroll, LLC
5
+ #
6
+ # This source code is licensed under the MIT license found in the
7
+ # LICENSE file in the root directory of this source tree.
8
+ #
9
+
10
+ module Burner
11
+ class Jobs
12
+ # Do nothing.
13
+ class Dummy < Job
14
+ def perform(_output, _payload, _params)
15
+ nil
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Copyright (c) 2020-present, Blue Marble Payroll, LLC
5
+ #
6
+ # This source code is licensed under the MIT license found in the
7
+ # LICENSE file in the root directory of this source tree.
8
+ #
9
+
10
+ module Burner
11
+ class Jobs
12
+ # Output a simple message to the output.
13
+ class Echo < Job
14
+ attr_reader :message
15
+
16
+ def initialize(name:, message: '')
17
+ super(name: name)
18
+
19
+ @message = message.to_s
20
+
21
+ freeze
22
+ end
23
+
24
+ def perform(output, _payload, params)
25
+ compiled_message = eval_string_template(message, params)
26
+
27
+ output.detail(compiled_message)
28
+
29
+ nil
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Copyright (c) 2020-present, Blue Marble Payroll, LLC
5
+ #
6
+ # This source code is licensed under the MIT license found in the
7
+ # LICENSE file in the root directory of this source tree.
8
+ #
9
+
10
+ module Burner
11
+ class Jobs
12
+ module IO
13
+ # Common configuration/code for all IO Job subclasses.
14
+ class Base < Job
15
+ attr_reader :binary, :path
16
+
17
+ def initialize(name:, path:, binary: false)
18
+ super(name: name)
19
+
20
+ raise ArgumentError, 'path is required' if path.to_s.empty?
21
+
22
+ @path = path.to_s
23
+ @binary = binary || false
24
+
25
+ freeze
26
+ end
27
+
28
+ private
29
+
30
+ def compile_path(params)
31
+ eval_string_template(path, params)
32
+ end
33
+
34
+ def mode
35
+ binary ? 'wb' : 'w'
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Copyright (c) 2020-present, Blue Marble Payroll, LLC
5
+ #
6
+ # This source code is licensed under the MIT license found in the
7
+ # LICENSE file in the root directory of this source tree.
8
+ #
9
+
10
+ require_relative 'base'
11
+
12
+ module Burner
13
+ class Jobs
14
+ module IO
15
+ # Read value from disk.
16
+ class Read < Base
17
+ def perform(output, payload, params)
18
+ compiled_path = compile_path(params)
19
+
20
+ output.detail("Reading: #{compiled_path}")
21
+
22
+ payload.value = File.open(compiled_path, mode, &:read)
23
+
24
+ nil
25
+ end
26
+
27
+ private
28
+
29
+ def mode
30
+ binary ? 'rb' : 'r'
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Copyright (c) 2020-present, Blue Marble Payroll, LLC
5
+ #
6
+ # This source code is licensed under the MIT license found in the
7
+ # LICENSE file in the root directory of this source tree.
8
+ #
9
+
10
+ require_relative 'base'
11
+
12
+ module Burner
13
+ class Jobs
14
+ module IO
15
+ # Write value to disk.
16
+ class Write < Base
17
+ def perform(output, payload, params)
18
+ compiled_path = compile_path(params)
19
+
20
+ ensure_directory_exists(output, compiled_path)
21
+
22
+ output.detail("Writing: #{compiled_path}")
23
+
24
+ File.open(compiled_path, mode) { |io| io.write(payload.value) }
25
+
26
+ nil
27
+ end
28
+
29
+ private
30
+
31
+ def ensure_directory_exists(output, compiled_path)
32
+ dirname = File.dirname(compiled_path)
33
+
34
+ return if File.exist?(dirname)
35
+
36
+ output.detail("Outer directory does not exist, creating: #{dirname}")
37
+
38
+ FileUtils.mkdir_p(dirname)
39
+
40
+ nil
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Copyright (c) 2020-present, Blue Marble Payroll, LLC
5
+ #
6
+ # This source code is licensed under the MIT license found in the
7
+ # LICENSE file in the root directory of this source tree.
8
+ #
9
+
10
+ module Burner
11
+ class Jobs
12
+ module Serialize
13
+ # Treat value like a Ruby object and serialize it using JSON.
14
+ class Json < Job
15
+ def perform(_output, payload, _params)
16
+ payload.value = payload.value.to_json
17
+
18
+ nil
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Copyright (c) 2020-present, Blue Marble Payroll, LLC
5
+ #
6
+ # This source code is licensed under the MIT license found in the
7
+ # LICENSE file in the root directory of this source tree.
8
+ #
9
+
10
+ module Burner
11
+ class Jobs
12
+ module Serialize
13
+ # Treat value like a Ruby object and serialize it using YAML.
14
+ class Yaml < Job
15
+ def perform(_output, payload, _params)
16
+ payload.value = payload.value.to_yaml
17
+
18
+ nil
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Copyright (c) 2020-present, Blue Marble Payroll, LLC
5
+ #
6
+ # This source code is licensed under the MIT license found in the
7
+ # LICENSE file in the root directory of this source tree.
8
+ #
9
+
10
+ module Burner
11
+ class Jobs
12
+ # Arbitrarily set value
13
+ class Set < Job
14
+ attr_reader :value
15
+
16
+ def initialize(name:, value: nil)
17
+ super(name: name)
18
+
19
+ @value = value
20
+
21
+ freeze
22
+ end
23
+
24
+ def perform(_output, payload, _params)
25
+ payload.value = value
26
+
27
+ nil
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Copyright (c) 2020-present, Blue Marble Payroll, LLC
5
+ #
6
+ # This source code is licensed under the MIT license found in the
7
+ # LICENSE file in the root directory of this source tree.
8
+ #
9
+
10
+ module Burner
11
+ class Jobs
12
+ # Arbitrarily put thread to sleep for X number of seconds
13
+ class Sleep < Job
14
+ attr_reader :seconds
15
+
16
+ def initialize(name:, seconds: 0)
17
+ super(name: name)
18
+
19
+ @seconds = seconds.to_f
20
+
21
+ freeze
22
+ end
23
+
24
+ def perform(output, _payload, _params)
25
+ output.detail("Going to sleep for #{seconds} second(s)")
26
+
27
+ Kernel.sleep(seconds)
28
+
29
+ nil
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Copyright (c) 2020-present, Blue Marble Payroll, LLC
5
+ #
6
+ # This source code is licensed under the MIT license found in the
7
+ # LICENSE file in the root directory of this source tree.
8
+ #
9
+
10
+ module Burner
11
+ # A Pipeline execution can write main output, which is really an outline to whats happening,
12
+ # step-by-step. This is not meant to replace or be true logging, but serve more as a summary
13
+ # for each of the jobs. Each job can decide what it would like to include in this summary
14
+ # and leverage an instance of this class for inclusion of that information.
15
+ class Output
16
+ RULER_LENGTH = 80
17
+
18
+ attr_reader :id, :job_count, :outs
19
+
20
+ def initialize(id: SecureRandom.uuid, outs: [$stdout])
21
+ @id = id
22
+ @outs = Array(outs)
23
+ @job_count = 1
24
+ end
25
+
26
+ def ruler
27
+ write('-' * RULER_LENGTH)
28
+
29
+ self
30
+ end
31
+
32
+ def title(message)
33
+ write("[#{job_count}] #{message}")
34
+
35
+ @job_count += 1
36
+
37
+ self
38
+ end
39
+
40
+ def detail(message)
41
+ write(" - #{message}")
42
+
43
+ self
44
+ end
45
+
46
+ def write(message)
47
+ raw("[#{id} | #{Time.now.utc}] #{message}")
48
+
49
+ self
50
+ end
51
+
52
+ def complete(time_in_seconds)
53
+ detail("Completed in: #{time_in_seconds.round(3)} second(s)")
54
+
55
+ self
56
+ end
57
+
58
+ private
59
+
60
+ def raw(message)
61
+ outs.each { |out| out.puts(message) }
62
+
63
+ self
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Copyright (c) 2020-present, Blue Marble Payroll, LLC
5
+ #
6
+ # This source code is licensed under the MIT license found in the
7
+ # LICENSE file in the root directory of this source tree.
8
+ #
9
+
10
+ module Burner
11
+ # The input for all Job#perform methods. The main notion of this object is its "value"
12
+ # attribute. This is dynamic and weak on purpose and is subject to whatever the Job#perform
13
+ # methods decides it is. This definitely adds an order-of-magnitude complexity to this whole
14
+ # library and lifecycle, but I am not sure there is any other way around it: trying to build
15
+ # a generic, open-ended object pipeline to serve almost any use case.
16
+ class Payload
17
+ attr_accessor :value
18
+
19
+ attr_reader :context
20
+
21
+ def initialize(context: {}, value: nil)
22
+ @context = context || {}
23
+ @value = value
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Copyright (c) 2020-present, Blue Marble Payroll, LLC
5
+ #
6
+ # This source code is licensed under the MIT license found in the
7
+ # LICENSE file in the root directory of this source tree.
8
+ #
9
+
10
+ require_relative 'jobs'
11
+ require_relative 'output'
12
+ require_relative 'payload'
13
+ require_relative 'step'
14
+
15
+ module Burner
16
+ # The root package. A Pipeline contains the job configurations along with the steps. The steps
17
+ # referens jobs and tell you the order of the jobs to run.
18
+ class Pipeline
19
+ acts_as_hashable
20
+
21
+ class JobNotFoundError < StandardError; end
22
+
23
+ attr_reader :steps
24
+
25
+ def initialize(jobs: [], steps: [])
26
+ jobs_by_name = Jobs.array(jobs).map { |job| [job.name, job] }.to_h
27
+
28
+ @steps = Array(steps).map do |step_name|
29
+ job = jobs_by_name[step_name.to_s]
30
+
31
+ raise JobNotFoundError, "#{step_name} was not declared as a job" unless job
32
+
33
+ Step.new(job)
34
+ end
35
+ end
36
+
37
+ # The main entry-point for kicking off a pipeline.
38
+ def execute(params: {}, output: Output.new, payload: Payload.new)
39
+ output.write("Pipeline started with #{steps.length} step(s)")
40
+
41
+ output_params(params, output)
42
+ output.ruler
43
+
44
+ time_in_seconds = Benchmark.measure do
45
+ steps.each { |step| step.perform(output, payload, params) }
46
+ end.real.round(3)
47
+
48
+ output.ruler
49
+ output.write("Pipeline ended, took #{time_in_seconds} second(s) to complete")
50
+
51
+ payload
52
+ end
53
+
54
+ private
55
+
56
+ def output_params(params, output)
57
+ if params.keys.any?
58
+ output.write('Parameters:')
59
+ else
60
+ output.write('No parameters passed in.')
61
+ end
62
+
63
+ params.each { |key, value| output.detail("#{key}: #{value}") }
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Copyright (c) 2020-present, Blue Marble Payroll, LLC
5
+ #
6
+ # This source code is licensed under the MIT license found in the
7
+ # LICENSE file in the root directory of this source tree.
8
+ #
9
+
10
+ module Burner
11
+ # A wrapper to execute a job (in the context of a Pipeline.)
12
+ class Step
13
+ extend Forwardable
14
+
15
+ SEPARATOR = '::'
16
+
17
+ private_constant :SEPARATOR
18
+
19
+ attr_reader :job
20
+
21
+ def_delegators :job, :name
22
+
23
+ def initialize(job)
24
+ raise ArgumentError, 'job is required' unless job
25
+
26
+ @job = job
27
+
28
+ freeze
29
+ end
30
+
31
+ def perform(output, payload, params)
32
+ output.title("#{job.class.name}#{SEPARATOR}#{job.name}")
33
+
34
+ time_in_seconds = Benchmark.measure do
35
+ job.perform(output, payload, params)
36
+ end.real.round(3)
37
+
38
+ output.complete(time_in_seconds)
39
+
40
+ nil
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Copyright (c) 2020-present, Blue Marble Payroll, LLC
5
+ #
6
+ # This source code is licensed under the MIT license found in the
7
+ # LICENSE file in the root directory of this source tree.
8
+ #
9
+
10
+ module Burner
11
+ # Can take in a string and an object and use the object for formatting string interpolations
12
+ # using tokens of form: {attribute_name}. It can also understand dot-notation for nested
13
+ # objects using the Objectable library. Another benefit of using Objectable for resolution
14
+ # is that it can understand almost any type of object: Hash, Struct, OpenStruct, custom
15
+ # objects, etc. For more information see underlying libraries:
16
+ # * Stringento: https://github.com/bluemarblepayroll/stringento
17
+ # * Objectable: https://github.com/bluemarblepayroll/objectable
18
+ class StringTemplate
19
+ include Singleton
20
+
21
+ attr_reader :resolver
22
+
23
+ def initialize
24
+ @resolver = Objectable.resolver
25
+
26
+ freeze
27
+ end
28
+
29
+ # For general consumption
30
+ def evaluate(expression, input)
31
+ Stringento.evaluate(expression, input, resolver: self)
32
+ end
33
+
34
+ # For Stringento consumption
35
+ def resolve(value, input)
36
+ resolver.get(input, value)
37
+ end
38
+ end
39
+ end
@@ -8,5 +8,5 @@
8
8
  #
9
9
 
10
10
  module Burner
11
- VERSION = '0.0.0'
11
+ VERSION = '1.0.0-alpha'
12
12
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: burner
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.0
4
+ version: 1.0.0.pre.alpha
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matthew Ruggio
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-10-13 00:00:00.000000000 Z
11
+ date: 2020-10-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: acts_as_hashable
@@ -154,7 +154,8 @@ description: " This library serves as the skeleton for a processing engine.
154
154
  allows you to organize your code into Jobs, then stitch those jobs together as steps.\n"
155
155
  email:
156
156
  - mruggio@bluemarblepayroll.com
157
- executables: []
157
+ executables:
158
+ - burner
158
159
  extensions: []
159
160
  extra_rdoc_files: []
160
161
  files:
@@ -173,7 +174,27 @@ files:
173
174
  - bin/console
174
175
  - burner.gemspec
175
176
  - exe/.gitkeep
177
+ - exe/burner
176
178
  - lib/burner.rb
179
+ - lib/burner/cli.rb
180
+ - lib/burner/job.rb
181
+ - lib/burner/jobs.rb
182
+ - lib/burner/jobs/deserialize/json.rb
183
+ - lib/burner/jobs/deserialize/yaml.rb
184
+ - lib/burner/jobs/dummy.rb
185
+ - lib/burner/jobs/echo.rb
186
+ - lib/burner/jobs/io/base.rb
187
+ - lib/burner/jobs/io/read.rb
188
+ - lib/burner/jobs/io/write.rb
189
+ - lib/burner/jobs/serialize/json.rb
190
+ - lib/burner/jobs/serialize/yaml.rb
191
+ - lib/burner/jobs/set.rb
192
+ - lib/burner/jobs/sleep.rb
193
+ - lib/burner/output.rb
194
+ - lib/burner/payload.rb
195
+ - lib/burner/pipeline.rb
196
+ - lib/burner/step.rb
197
+ - lib/burner/string_template.rb
177
198
  - lib/burner/version.rb
178
199
  homepage: https://github.com/bluemarblepayroll/burner
179
200
  licenses:
@@ -195,9 +216,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
195
216
  version: '2.5'
196
217
  required_rubygems_version: !ruby/object:Gem::Requirement
197
218
  requirements:
198
- - - ">="
219
+ - - ">"
199
220
  - !ruby/object:Gem::Version
200
- version: '0'
221
+ version: 1.3.1
201
222
  requirements: []
202
223
  rubygems_version: 3.0.3
203
224
  signing_key: