metacrunch 2.2.3 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +2 -1
  3. data/Gemfile +11 -13
  4. data/License.txt +1 -1
  5. data/Readme.md +139 -2
  6. data/bin/console +9 -6
  7. data/exe/metacrunch +1 -2
  8. data/lib/metacrunch/cli.rb +62 -14
  9. data/lib/metacrunch/db/reader.rb +27 -0
  10. data/lib/metacrunch/db/writer.rb +23 -0
  11. data/lib/metacrunch/db.rb +8 -0
  12. data/lib/metacrunch/fs/entry.rb +17 -0
  13. data/lib/metacrunch/{file_reader.rb → fs/reader.rb} +9 -10
  14. data/lib/metacrunch/fs.rb +6 -0
  15. data/lib/metacrunch/job/buffer.rb +26 -0
  16. data/lib/metacrunch/job/dsl/option_support.rb +102 -0
  17. data/lib/metacrunch/job/dsl.rb +42 -0
  18. data/lib/metacrunch/job.rb +149 -0
  19. data/lib/metacrunch/test_utils/dummy_callable.rb +14 -0
  20. data/lib/metacrunch/test_utils/dummy_destination.rb +21 -0
  21. data/lib/metacrunch/test_utils/dummy_source.rb +22 -0
  22. data/lib/metacrunch/test_utils.rb +7 -0
  23. data/lib/metacrunch/version.rb +1 -1
  24. data/lib/metacrunch.rb +14 -27
  25. data/metacrunch.gemspec +5 -10
  26. metadata +24 -144
  27. data/lib/metacrunch/cli/base.rb +0 -29
  28. data/lib/metacrunch/cli/command_definition.rb +0 -41
  29. data/lib/metacrunch/cli/command_registry.rb +0 -17
  30. data/lib/metacrunch/cli/main.rb +0 -16
  31. data/lib/metacrunch/command.rb +0 -27
  32. data/lib/metacrunch/file/reader/file_system_fetcher.rb +0 -21
  33. data/lib/metacrunch/file/reader/plain_file_reader.rb +0 -33
  34. data/lib/metacrunch/file/reader/scp_fetcher.rb +0 -56
  35. data/lib/metacrunch/file/reader/tar_file_reader.rb +0 -37
  36. data/lib/metacrunch/file/reader/zip_file_reader.rb +0 -30
  37. data/lib/metacrunch/file/reader.rb +0 -72
  38. data/lib/metacrunch/file/writer/plain_file_writer.rb +0 -19
  39. data/lib/metacrunch/file/writer/tar_file_writer.rb +0 -26
  40. data/lib/metacrunch/file/writer/zip_file_writer.rb +0 -29
  41. data/lib/metacrunch/file/writer.rb +0 -26
  42. data/lib/metacrunch/file.rb +0 -24
  43. data/lib/metacrunch/file_reader_entry.rb +0 -21
  44. data/lib/metacrunch/file_writer.rb +0 -40
  45. data/lib/metacrunch/hash.rb +0 -51
  46. data/lib/metacrunch/parallel.rb +0 -69
  47. data/lib/metacrunch/processor.rb +0 -10
  48. data/lib/metacrunch/snr/field.rb +0 -31
  49. data/lib/metacrunch/snr/section.rb +0 -74
  50. data/lib/metacrunch/snr.rb +0 -117
  51. data/lib/metacrunch/tar_writer.rb +0 -26
  52. data/lib/metacrunch/transformator/transformation/step.rb +0 -45
  53. data/lib/metacrunch/transformator/transformation.rb +0 -48
  54. data/lib/metacrunch/transformator.rb +0 -5
  55. data/lib/metacrunch/transformer/helper.rb +0 -29
  56. data/lib/metacrunch/transformer/step.rb +0 -37
  57. data/lib/metacrunch/transformer.rb +0 -38
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 071c720dfc2ad17aa71665f25579961eb1a0beea
4
- data.tar.gz: 622e3192f6021da9e5851485b7fb9181ec75e2c6
3
+ metadata.gz: 657c0cedb16066bee69a76a30a0e02783e5d0209
4
+ data.tar.gz: 7c0290c94a11af5daf8bfb40e0b0abab3f92c8df
5
5
  SHA512:
6
- metadata.gz: 6fe42cf29e183659f667cfac082cebebee345ab199a4fd99dd175a0ea1716ea3a5b38b3a4ce9ab13c790a4dc03d4775d343d55fe0593b43ba10eaac5557654c9
7
- data.tar.gz: f14bee54085db41b4ed15a6f551a9f6a1465541c896037a3674cafff4cbbab375574c0236b2e9c33b9c03e3fbef929d11e0aa473b11f4a8f763ef001c371e879
6
+ metadata.gz: ee0834cbe3f70238f1c5f7fbaf37284c0c7adedbdafe4c01e7b31819cfa8274585a4cd8407fd5cc35ca32c033f0944c86f872d09d8ee5d56ba22d48435898d4d
7
+ data.tar.gz: d9663a2b36247dcd20721e9e2016bc3f1d42dae47aa89acc671fb112437c925779bf5949edfb5409e3e6ff3aa2612216c93468847deb51ebc8b4ae6da064eb97
data/.travis.yml CHANGED
@@ -1,3 +1,4 @@
1
1
  language: ruby
2
2
  rvm:
3
- - "2.2.2"
3
+ - ruby-2.3.0
4
+ - jruby-9.0.5.0
data/Gemfile CHANGED
@@ -1,25 +1,23 @@
1
1
  source "https://rubygems.org"
2
2
 
3
- # Specify your gem's dependencies in your gemspec
4
3
  gemspec
5
4
 
6
5
  group :development do
7
- gem "bundler"
8
- gem "nokogiri"
9
- gem "rake"
10
- gem "rspec", ">= 3.0.0", "< 4.0.0"
11
- gem "simplecov", ">= 0.8.0"
6
+ gem "bundler", ">= 1.7"
7
+ gem "rake", ">= 11.1"
8
+ gem "rspec", ">= 3.0.0", "< 4.0.0"
9
+ gem "simplecov", ">= 0.11.0"
10
+ gem "sqlite3", ">= 1.3.11", platform: :ruby
11
+ gem "jdbc-sqlite3", ">= 3.8", platform: :jruby
12
12
 
13
13
  if !ENV["CI"]
14
- gem "hashdiff"
15
- gem "pry", "~> 0.9.12.6"
16
- gem "pry-byebug", "<= 1.3.2"
17
- gem "pry-rescue", "~> 1.4.2"
18
- gem "pry-stack_explorer", "~> 0.4.9.1"
19
- gem "pry-syntax-hacks", "~> 0.0.6"
14
+ gem "hashdiff", ">= 0.3.0", platform: :ruby
15
+ gem "pry-byebug", ">= 3.3.0", platform: :ruby
16
+ gem "pry-rescue", ">= 1.4.2", platform: :ruby
17
+ gem "pry-state", ">= 0.1.7", platform: :ruby
20
18
  end
21
19
  end
22
20
 
23
21
  group :test do
24
- gem "codeclimate-test-reporter", require: nil
22
+ gem "codeclimate-test-reporter", ">= 0.5.0", require: nil
25
23
  end
data/License.txt CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2013 René Sprotte, Michael Sievers, Marcel Otto
1
+ Copyright (c) 2016 René Sprotte, Michael Sievers, Marcel Otto
2
2
 
3
3
  MIT License
4
4
 
data/Readme.md CHANGED
@@ -1,7 +1,144 @@
1
- # metacrunch
1
+ metacrunch
2
+ ==========
2
3
 
3
4
  [![Gem Version](https://badge.fury.io/rb/metacrunch.svg)](http://badge.fury.io/rb/metacrunch)
4
5
  [![Code Climate](https://codeclimate.com/github/ubpb/metacrunch/badges/gpa.svg)](https://codeclimate.com/github/ubpb/metacrunch)
5
6
  [![Build Status](https://travis-ci.org/ubpb/metacrunch.svg)](https://travis-ci.org/ubpb/metacrunch)
6
7
 
7
- Dokumentation folgt in Kürze...
8
+ metacrunch is a simple and lightweight data processing and ETL ([Extract-Transform-Load](http://en.wikipedia.org/wiki/Extract,_transform,_load))
9
+ toolkit for Ruby.
10
+
11
+
12
+ Installation
13
+ ------------
14
+
15
+ ```
16
+ $ gem install metacrunch
17
+ ```
18
+
19
+
20
+ Create ETL jobs
21
+ ---------------
22
+
23
+ The basic idea behind an ETL job in metacrunch is the concept of a data processing pipeline. Each ETL job reads data from one or more **sources** (extract step), runs one or more **transformations** (transform step) on the data and finally writes the transformed data back to one or more **destinations** (load step).
24
+
25
+ metacrunch provides you with a simple DSL to define such ETL jobs. Just create a text file with the extension `.metacrunch`. Note: The extension doesn't really matter but you should avoid `.rb` to not loading them by mistake from another Ruby component.
26
+
27
+ Let's take a look at an example. For a collection of working examples check out our [metacrunch-demo](https://github.com/ubpb/metacrunch-demo) repo.
28
+
29
+ ```ruby
30
+ # File: my_etl_job.metacrunch
31
+
32
+ # Every metacrunch job file is a regular Ruby file. So you can always use regular Ruby
33
+ # stuff like declaring methods
34
+ def my_helper
35
+ # ...
36
+ end
37
+
38
+ # ... declaring classes
39
+ class MyHelper
40
+ # ...
41
+ end
42
+
43
+ # ... declaring variables
44
+ foo = "bar"
45
+
46
+ # ... or loading other ruby files
47
+ require_relative "./some/other/ruby/file"
48
+
49
+ # Declare a source (use a build-in or 3rd party source or implement it – see notes below).
50
+ # At least one source is required to allow the job to run.
51
+ source MySource.new
52
+ # ... maybe another one. Sources are processed in the order they are defined.
53
+ source MyOtherSource.new
54
+
55
+ # Declare a destination (use a build-in or 3rd party destination or implement it – see notes below).
56
+ # Technically a destination is optional, but a job that doesn't store it's
57
+ # output doesn't really makes sense.
58
+ destination MyDestination.new
59
+ # ... you can have more destinations if you like
60
+ destination MyOtherDestination.new
61
+
62
+ # To process data use the #transformation hook.
63
+ transformation do |data|
64
+ # Called for each data object that has been put in the pipeline by a source.
65
+
66
+ # Do your data transformation process here.
67
+
68
+ # You must return the data to keep it in the pipeline. Dismiss the
69
+ # data conditionally by returning nil.
70
+ data
71
+ end
72
+
73
+ # Instead of passing a block to #transformation you can pass a
74
+ # `callable` object (an object responding to #call).
75
+ transformation Proc.new {
76
+ # Procs and Lambdas responds to #call
77
+ }
78
+
79
+ # MyTransformation defines #call
80
+ transformation MyTransformation.new
81
+
82
+ # To run arbitrary code before the first transformation use the #pre_process hook.
83
+ pre_process do
84
+ # Called before the first transformation
85
+ end
86
+
87
+ # To run arbitrary code after the last transformation use the #post_process hook.
88
+ post_process do
89
+ # Called after the last transformation
90
+ end
91
+
92
+ # Instead of passing a block to #pre_process or #post_process you can pass a
93
+ # `callable` object (an object responding to #call).
94
+ pre_process Proc.new {
95
+ # Procs and Lambdas responds to #call
96
+ }
97
+
98
+ # MyCallable class defines #call
99
+ post_process MyCallable.new
100
+
101
+ ```
102
+
103
+
104
+ Run ETL jobs
105
+ ------------
106
+
107
+ metacrunch comes with a handy command line tool. In your terminal just call
108
+
109
+
110
+ ```
111
+ $ metacrunch run my_etl_job.metacrunch
112
+ ```
113
+
114
+ to run the job.
115
+
116
+ Implementing sources
117
+ --------------------
118
+
119
+ TBD.
120
+
121
+ Implementing transformations
122
+ ----------------------------
123
+
124
+ TBD.
125
+
126
+ Implementing writers
127
+ ---------------------
128
+
129
+ TBD.
130
+
131
+ Defining job dependencies
132
+ -------------------------
133
+
134
+ TBD.
135
+
136
+ Defining job options
137
+ --------------------
138
+
139
+ TBD.
140
+
141
+ License
142
+ -------
143
+
144
+ metacrunch is available at [github](https://github.com/ubpb/metacrunch) under [MIT license](https://github.com/ubpb/metacrunch/blob/master/License.txt).
data/bin/console CHANGED
@@ -1,11 +1,14 @@
1
1
  #!/usr/bin/env ruby
2
-
3
2
  require "bundler/setup"
4
3
  require "metacrunch"
5
4
 
6
- # You can add fixtures and/or initialization code here to make experimenting
7
- # with your gem easier. You can also use a different console, if you like.
5
+ begin
6
+ require "pry"
7
+ rescue LoadError ; end
8
8
 
9
- # (If you use this, don't forget to add pry to your Gemfile!)
10
- require "pry"
11
- Pry.start
9
+ if defined?(Pry)
10
+ Pry.start
11
+ else
12
+ require "irb"
13
+ IRB.start
14
+ end
data/exe/metacrunch CHANGED
@@ -1,4 +1,3 @@
1
1
  #!/usr/bin/env ruby
2
2
  require "metacrunch"
3
- Metacrunch.load_plugins
4
- Metacrunch::Cli.start(ARGV)
3
+ Metacrunch::Cli.new.run
@@ -1,26 +1,74 @@
1
1
  module Metacrunch
2
2
  class Cli
3
- require_relative "./cli/main"
4
- require_relative "./cli/base"
5
- require_relative "./cli/command_registry"
6
- require_relative "./cli/command_definition"
3
+ ARGS_SEPERATOR = "@@"
7
4
 
8
- def self.start(argv)
9
- Main.start(argv)
5
+ def run
6
+ init_commander!
7
+ init_run_command!
8
+ run_commander!
10
9
  end
11
10
 
12
- def self.setup(namespace, description, &block)
13
- klass = Class.new(Base)
14
- klass.namespace(namespace)
11
+ private
12
+ def commander
13
+ @commander ||= Commander::Runner.new(metacrunch_args)
14
+ end
15
+
16
+ def init_commander!
17
+ commander.program :name, "metacrunch"
18
+ commander.program :version, Metacrunch::VERSION
19
+ commander.program :description, "Data processing and ETL toolkit for Ruby."
20
+ commander.default_command :help
21
+ end
22
+
23
+ def run_commander!
24
+ commander.run!
25
+ end
26
+
27
+ def init_run_command!
28
+ commander.command :run do |c|
29
+ c.syntax = "metacrunch run [options] FILE [@@ job_options]"
30
+ c.description = "Runs a metacrunch job description."
31
+
32
+ c.action do |filenames, program_options|
33
+ if filenames.empty?
34
+ say "You need to provide a job description file."
35
+ exit(1)
36
+ elsif filenames.count > 1
37
+ say "You must provide exactly one job description file."
38
+ else
39
+ filename = File.expand_path(filenames.first)
40
+ dir = File.dirname(filename)
15
41
 
16
- registry = CommandRegistry.new
17
- yield(registry)
42
+ setup_bundler(dir)
18
43
 
19
- registry.commands.each do |c|
20
- klass.register_thor_command(c)
44
+ Dir.chdir(dir) do
45
+ contents = File.read(filename)
46
+ context = Metacrunch::Job.define(contents, filename: filename, args: job_args)
47
+ context.run
48
+ end
49
+ end
50
+ end
21
51
  end
52
+ end
53
+
54
+ def metacrunch_args
55
+ index = ARGV.index(ARGS_SEPERATOR)
56
+ @metacrunch_args ||= index ? ARGV[0..index-1] : ARGV
57
+ end
22
58
 
23
- Main.register(klass, namespace, "#{namespace} [COMMAND]", description)
59
+ def job_args
60
+ index = ARGV.index(ARGS_SEPERATOR)
61
+ @job_args ||= index ? ARGV[index+1..-1] : nil
24
62
  end
63
+
64
+ def setup_bundler(dir)
65
+ ENV['BUNDLE_GEMFILE'] ||= File.join(dir, "Gemfile")
66
+ if File.exists?(ENV['BUNDLE_GEMFILE'])
67
+ puts "Using Gemfile `#{ENV['BUNDLE_GEMFILE']}`."
68
+ Bundler.setup
69
+ Bundler.require
70
+ end
71
+ end
72
+
25
73
  end
26
74
  end
@@ -0,0 +1,27 @@
1
+ module Metacrunch
2
+ class Db::Reader
3
+
4
+ def initialize(database_connection_or_url, dataset_proc, options = {})
5
+ @rows_per_fetch = options.delete(:rows_per_fetch) || 1000
6
+
7
+ @db = if database_connection_or_url.is_a?(String)
8
+ Sequel.connect(database_connection_or_url, options)
9
+ else
10
+ database_connection_or_url
11
+ end
12
+
13
+ @dataset = dataset_proc.call(@db)
14
+ end
15
+
16
+ def each(&block)
17
+ return enum_for(__method__) unless block_given?
18
+
19
+ @dataset.paged_each(rows_per_fetch: @rows_per_fetch) do |row|
20
+ yield(row)
21
+ end
22
+
23
+ self
24
+ end
25
+
26
+ end
27
+ end
@@ -0,0 +1,23 @@
1
+ module Metacrunch
2
+ class Db::Writer
3
+
4
+ def initialize(database_connection_or_url, dataset_proc, options = {})
5
+ @db = if database_connection_or_url.is_a?(String)
6
+ Sequel.connect(database_connection_or_url, options)
7
+ else
8
+ database_connection_or_url
9
+ end
10
+
11
+ @dataset = dataset_proc.call(@db)
12
+ end
13
+
14
+ def write(data)
15
+ @dataset.insert(data)
16
+ end
17
+
18
+ def close
19
+ @db.disconnect
20
+ end
21
+
22
+ end
23
+ end
@@ -0,0 +1,8 @@
1
+ require "sequel"
2
+
3
+ module Metacrunch
4
+ class Db
5
+ require_relative "db/reader"
6
+ require_relative "db/writer"
7
+ end
8
+ end
@@ -0,0 +1,17 @@
1
+ module Metacrunch
2
+ class Fs::Entry
3
+
4
+ attr_reader :filename, :archive_filename, :contents
5
+
6
+ def initialize(filename:, archive_filename: nil, contents: nil)
7
+ @filename = filename
8
+ @archive_filename = archive_filename.presence
9
+ @contents = contents
10
+ end
11
+
12
+ def from_archive?
13
+ @archive_filename != nil
14
+ end
15
+
16
+ end
17
+ end
@@ -1,10 +1,9 @@
1
1
  require "rubygems/package"
2
- require_relative "./file_reader_entry"
3
2
 
4
3
  module Metacrunch
5
- class FileReader
4
+ class Fs::Reader
6
5
 
7
- def initialize(filenames)
6
+ def initialize(filenames = nil)
8
7
  @filenames = [*filenames].map{|f| f.presence}.compact
9
8
  end
10
9
 
@@ -23,27 +22,27 @@ module Metacrunch
23
22
  private
24
23
 
25
24
  def is_archive?(filename)
26
- filename.ends_with?(".tar") || filename.ends_with?(".tar.gz")
25
+ filename.ends_with?(".tar") || filename.ends_with?(".tar.gz") || filename.ends_with?(".tgz")
27
26
  end
28
27
 
29
28
  def is_gzip_file?(filename)
30
- filename.ends_with?(".gz")
29
+ filename.ends_with?(".gz") || filename.ends_with?(".tgz")
31
30
  end
32
31
 
33
32
  def read_regular_file(filename, &block)
34
- if ::File.file?(filename)
35
- io = is_gzip_file?(filename) ? Zlib::GzipReader.open(filename) : ::File.open(filename, "r")
36
- yield Entry.new(filename: filename, archive_filename: nil, contents: io.read)
33
+ if File.file?(filename)
34
+ io = is_gzip_file?(filename) ? Zlib::GzipReader.open(filename) : File.open(filename, "r")
35
+ yield Fs::Entry.new(filename: filename, archive_filename: nil, contents: io.read)
37
36
  end
38
37
  end
39
38
 
40
39
  def read_archive(filename, &block)
41
- io = is_gzip_file?(filename) ? Zlib::GzipReader.open(filename) : ::File.open(filename, "r")
40
+ io = is_gzip_file?(filename) ? Zlib::GzipReader.open(filename) : File.open(filename, "r")
42
41
  tarReader = Gem::Package::TarReader.new(io)
43
42
 
44
43
  tarReader.each do |_tar_entry|
45
44
  if _tar_entry.file?
46
- yield Entry.new(
45
+ yield Fs::Entry.new(
47
46
  filename: filename,
48
47
  archive_filename: _tar_entry.full_name,
49
48
  contents: _tar_entry.read
@@ -0,0 +1,6 @@
1
+ module Metacrunch
2
+ module Fs
3
+ require_relative "fs/reader"
4
+ require_relative "fs/entry"
5
+ end
6
+ end
@@ -0,0 +1,26 @@
1
+ module Metacrunch
2
+ class Job::Buffer
3
+
4
+ def initialize(size)
5
+ @size = size
6
+ end
7
+
8
+ def buffer(data)
9
+ storage << data
10
+ flush if storage.count >= @size
11
+ end
12
+
13
+ def flush
14
+ storage
15
+ ensure
16
+ @buffer = nil
17
+ end
18
+
19
+ private
20
+
21
+ def storage
22
+ @buffer ||= []
23
+ end
24
+
25
+ end
26
+ end
@@ -0,0 +1,102 @@
1
+ module Metacrunch
2
+ class Job::Dsl::OptionSupport
3
+
4
+ def register_options(args, require_args: false, &block)
5
+ options = {}
6
+ registry.instance_eval(&block)
7
+
8
+ registry.each do |key, opt_def|
9
+ # Set default value
10
+ options[key] = opt_def[:default]
11
+
12
+ # Register with OptionParser
13
+ if opt_def[:args].present?
14
+ option = parser.define(*opt_def[:args]) { |value| options[key] = value }
15
+
16
+ option.desc << "REQUIRED" if opt_def[:required]
17
+ option.desc << "DEFAULT: #{opt_def[:default]}" if opt_def[:default].present?
18
+
19
+ parser_options[key] = option
20
+ end
21
+ end
22
+
23
+ # Finally parse CLI options with OptionParser
24
+ args = parser.parse(args || [])
25
+
26
+ # Make sure required options are present
27
+ ensure_required_options!(options)
28
+
29
+ # Make sure args are present if required
30
+ ensure_required_args!(args) if require_args
31
+
32
+ options
33
+ end
34
+
35
+ private
36
+
37
+ def parser
38
+ @parser ||= OptionParser.new do |parser|
39
+ parser.banner = "Usage: metacrunch run [options] JOB_FILE @@ [job-options] [ARGS]\nJob options:"
40
+ end
41
+ end
42
+
43
+ def parser_options
44
+ @parser_options ||= {}
45
+ end
46
+
47
+ def registry
48
+ @registry ||= OptionRegistry.new
49
+ end
50
+
51
+ def ensure_required_options!(options)
52
+ registry.each do |key, opt_def|
53
+ if opt_def[:required] && options[key].blank?
54
+ long_option = parser_options[key].long.try(:[], 0)
55
+ short_option = parser_options[key].short.try(:[], 0)
56
+
57
+ puts "Error: Required job option `#{long_option || short_option}` missing."
58
+ puts parser.help
59
+
60
+ exit(1)
61
+ end
62
+ end
63
+ end
64
+
65
+ def ensure_required_args!(args)
66
+ if args.blank?
67
+ puts "Error: Required ARGS are missing."
68
+ puts parser.help
69
+
70
+ exit(1)
71
+ end
72
+ end
73
+
74
+ private
75
+
76
+ class OptionRegistry
77
+
78
+ def add(name, *args, default: nil, required: false)
79
+ if default && required
80
+ raise ArgumentError, "You can't use `default` and `required` option at the same time."
81
+ end
82
+
83
+ options[name.to_sym] = {
84
+ args: args,
85
+ default: default,
86
+ required: required
87
+ }
88
+ end
89
+
90
+ def each(&block)
91
+ options.each(&block)
92
+ end
93
+
94
+ private
95
+
96
+ def options
97
+ @options ||= {}
98
+ end
99
+ end
100
+
101
+ end
102
+ end
@@ -0,0 +1,42 @@
1
+ module Metacrunch
2
+ class Job::Dsl
3
+ require_relative "dsl/option_support"
4
+
5
+ def initialize(job)
6
+ @_job = job
7
+ end
8
+
9
+ def source(source)
10
+ @_job.add_source(source)
11
+ end
12
+
13
+ def destination(destination)
14
+ @_job.add_destination(destination)
15
+ end
16
+
17
+ def pre_process(callable = nil, &block)
18
+ @_job.add_pre_process(callable, &block)
19
+ end
20
+
21
+ def post_process(callable = nil, &block)
22
+ @_job.add_post_process(callable, &block)
23
+ end
24
+
25
+ def transformation_buffer(size)
26
+ @_job.add_transformation_buffer(size)
27
+ end
28
+
29
+ def transformation(callable = nil, &block)
30
+ @_job.add_transformation(callable, &block)
31
+ end
32
+
33
+ def options(require_args: false, &block)
34
+ if block_given?
35
+ @_options = OptionSupport.new.register_options(@_job.args, require_args: require_args, &block)
36
+ else
37
+ @_options ||= {}
38
+ end
39
+ end
40
+
41
+ end
42
+ end