setl 0.0.3 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/setl/delegates.rb +43 -0
- data/lib/setl/errors.rb +25 -0
- data/lib/setl/etl.rb +12 -15
- data/lib/setl/version.rb +1 -1
- data/spec/error_handling_spec.rb +57 -7
- data/spec/etl_spec.rb +2 -2
- metadata +6 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3a89bb7b59c0609b79d8cf15d6028ec1f737beae
|
4
|
+
data.tar.gz: cc162c0522666a70fbf9180592e4b0d3e5d128aa
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 15e2d85fef8add097abbda5890201332de3fc251f73e4e61b7c15cb74dcc5f09c64352e039db1411cab8506fe91142157079bebcc96233aed039270a73e70244
|
7
|
+
data.tar.gz: 4c57e706725c5f33b6b5d820bb444590c0508b0b78a2bf47cf8ad9b6d1d6715fdd763e06f42da3a5f040a042d2b4511e4ad6a20c4dab0fd38c49da246e037a1a
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require_relative 'errors'
|
2
|
+
|
3
|
+
module Setl
|
4
|
+
class Delegator
|
5
|
+
def initialize(item, error_handler)
|
6
|
+
@item = item
|
7
|
+
@error_handler = error_handler
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
attr_reader :item, :error_handler
|
13
|
+
end
|
14
|
+
|
15
|
+
class Source < Delegator
|
16
|
+
def each(&block)
|
17
|
+
item.each(&block)
|
18
|
+
rescue StandardError => e
|
19
|
+
# Allow our errors to go through
|
20
|
+
if e.is_a? ETLError
|
21
|
+
raise e
|
22
|
+
else
|
23
|
+
error_handler.(SourceError.new("Failed to read from source"))
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class Transform < Delegator
|
29
|
+
def call(row, &block)
|
30
|
+
item.call(row, &block)
|
31
|
+
rescue StandardError => e
|
32
|
+
error_handler.(ProcessingError.new(row, "Failed to process #{row}"))
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
class Destination < Delegator
|
37
|
+
def call(row, &block)
|
38
|
+
item.call(row, &block)
|
39
|
+
rescue StandardError => e
|
40
|
+
error_handler.(DestinationError.new(row, "Failed to send #{row}"))
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
data/lib/setl/errors.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
module Setl
|
2
|
+
class ETLError < StandardError
|
3
|
+
end
|
4
|
+
|
5
|
+
class ProcessingError < ETLError
|
6
|
+
def initialize(row, message=nil)
|
7
|
+
super message
|
8
|
+
@row = row
|
9
|
+
end
|
10
|
+
|
11
|
+
attr_reader :row
|
12
|
+
end
|
13
|
+
|
14
|
+
class SourceError < ETLError
|
15
|
+
end
|
16
|
+
|
17
|
+
class DestinationError < ETLError
|
18
|
+
def initialize(row, message=nil)
|
19
|
+
super message
|
20
|
+
@row = row
|
21
|
+
end
|
22
|
+
|
23
|
+
attr_reader :row
|
24
|
+
end
|
25
|
+
end
|
data/lib/setl/etl.rb
CHANGED
@@ -1,21 +1,21 @@
|
|
1
|
+
require_relative 'delegates'
|
2
|
+
|
1
3
|
module Setl
|
2
4
|
class ETL
|
3
|
-
def initialize(source, destination, stop_on_errors: false, error_handler: nil)
|
4
|
-
@source = source
|
5
|
-
@destination = destination
|
5
|
+
def initialize(source, destination, transform, stop_on_errors: false, error_handler: nil)
|
6
6
|
@stop_on_errors = stop_on_errors
|
7
7
|
@error_handler = error_handler || DefaultHandler.new(stop_on_errors)
|
8
|
+
|
9
|
+
@source = Source.new(source, @error_handler)
|
10
|
+
@destination = Destination.new(destination, @error_handler)
|
11
|
+
@transform = Transform.new(transform, @error_handler)
|
8
12
|
end
|
9
13
|
|
10
|
-
def process
|
14
|
+
def process
|
11
15
|
source.each do |row|
|
12
16
|
@last_row = row
|
13
17
|
|
14
|
-
|
15
|
-
destination.(transform.(row))
|
16
|
-
rescue StandardError => e
|
17
|
-
error_handler.(row, e)
|
18
|
-
end
|
18
|
+
destination.(transform.(row))
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
@@ -23,10 +23,7 @@ module Setl
|
|
23
23
|
|
24
24
|
private
|
25
25
|
|
26
|
-
attr_reader :source, :destination, :stop_on_errors, :error_handler
|
27
|
-
end
|
28
|
-
|
29
|
-
class ProcessingError < StandardError
|
26
|
+
attr_reader :source, :destination, :transform, :stop_on_errors, :error_handler
|
30
27
|
end
|
31
28
|
|
32
29
|
class DefaultHandler
|
@@ -34,8 +31,8 @@ module Setl
|
|
34
31
|
@reraise = reraise
|
35
32
|
end
|
36
33
|
|
37
|
-
def call(
|
38
|
-
raise
|
34
|
+
def call(exception)
|
35
|
+
raise exception if reraise?
|
39
36
|
end
|
40
37
|
|
41
38
|
private
|
data/lib/setl/version.rb
CHANGED
data/spec/error_handling_spec.rb
CHANGED
@@ -3,7 +3,7 @@ require 'setl/etl'
|
|
3
3
|
|
4
4
|
module Setl
|
5
5
|
RSpec.describe 'error handling' do
|
6
|
-
let(:etl) { ETL.new(source, destination) }
|
6
|
+
let(:etl) { ETL.new(source, destination, transform) }
|
7
7
|
let(:source) { [1, 2] }
|
8
8
|
let(:destination) { double('Destination', call: true) }
|
9
9
|
let(:transform) do
|
@@ -14,7 +14,7 @@ module Setl
|
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
17
|
-
let(:process) { etl.process
|
17
|
+
let(:process) { etl.process }
|
18
18
|
|
19
19
|
context 'by default' do
|
20
20
|
it 'rescues the error' do
|
@@ -29,7 +29,7 @@ module Setl
|
|
29
29
|
end
|
30
30
|
|
31
31
|
context 'when configured to stop on errors' do
|
32
|
-
let(:etl) { ETL.new(source, destination, stop_on_errors: true) }
|
32
|
+
let(:etl) { ETL.new(source, destination, transform, stop_on_errors: true) }
|
33
33
|
|
34
34
|
it 'stops processing when a processing error occurs' do
|
35
35
|
expect { process }.to raise_error(ProcessingError, 'Failed to process 1')
|
@@ -45,14 +45,64 @@ module Setl
|
|
45
45
|
end
|
46
46
|
|
47
47
|
context 'when provided an error handler' do
|
48
|
-
let(:handler)
|
49
|
-
|
48
|
+
let(:handler) do
|
49
|
+
Class.new do
|
50
|
+
def self.call(exception)
|
51
|
+
raise exception
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
50
55
|
|
51
|
-
|
52
|
-
|
56
|
+
let(:etl) { ETL.new(source, destination, transform, error_handler: handler) }
|
57
|
+
|
58
|
+
it 'sends a processing error to the handler' do
|
59
|
+
expect(handler).to receive(:call).with(an_instance_of(ProcessingError))
|
53
60
|
|
54
61
|
process
|
55
62
|
end
|
63
|
+
|
64
|
+
specify 'the error contains the original cause' do
|
65
|
+
begin
|
66
|
+
process
|
67
|
+
rescue ProcessingError => e
|
68
|
+
expect(e.cause).to be_a RuntimeError
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
context 'when the source raises an exception' do
|
73
|
+
let(:handler) { double('ErrorHandler', call: true) }
|
74
|
+
|
75
|
+
let(:source) do
|
76
|
+
Class.new do
|
77
|
+
def self.each
|
78
|
+
raise "nope"
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'sends a SourceError to the handler' do
|
84
|
+
expect(handler).to receive(:call).with(an_instance_of(SourceError))
|
85
|
+
|
86
|
+
process
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
context 'when the destination raises an exception' do
|
91
|
+
let(:handler) { double('ErrorHandler', call: true) }
|
92
|
+
let(:destination) do
|
93
|
+
Class.new do
|
94
|
+
def self.call(row)
|
95
|
+
raise "lol"
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
it 'sends a destination error to the handler' do
|
101
|
+
expect(handler).to receive(:call).with(an_instance_of(DestinationError))
|
102
|
+
|
103
|
+
process
|
104
|
+
end
|
105
|
+
end
|
56
106
|
end
|
57
107
|
end
|
58
108
|
end
|
data/spec/etl_spec.rb
CHANGED
@@ -3,7 +3,7 @@ require 'setl/etl'
|
|
3
3
|
|
4
4
|
module Setl
|
5
5
|
RSpec.describe 'etl' do
|
6
|
-
let(:etl) { ETL.new(source, destination) }
|
6
|
+
let(:etl) { ETL.new(source, destination, transform) }
|
7
7
|
|
8
8
|
describe 'processing a row' do
|
9
9
|
let(:row) { 'hello' }
|
@@ -13,7 +13,7 @@ module Setl
|
|
13
13
|
let(:transform) { double('Transform', call: processed_data) }
|
14
14
|
|
15
15
|
before do
|
16
|
-
etl.process
|
16
|
+
etl.process
|
17
17
|
end
|
18
18
|
|
19
19
|
it 'delegates the processing to the transform' do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: setl
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Leonard Garvey
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-09-
|
11
|
+
date: 2015-09-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -70,6 +70,8 @@ files:
|
|
70
70
|
- bin/rspec
|
71
71
|
- lib/setl.rb
|
72
72
|
- lib/setl/controller.rb
|
73
|
+
- lib/setl/delegates.rb
|
74
|
+
- lib/setl/errors.rb
|
73
75
|
- lib/setl/etl.rb
|
74
76
|
- lib/setl/version.rb
|
75
77
|
- setl.gemspec
|
@@ -97,7 +99,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
97
99
|
version: '0'
|
98
100
|
requirements: []
|
99
101
|
rubyforge_project:
|
100
|
-
rubygems_version: 2.
|
102
|
+
rubygems_version: 2.2.2
|
101
103
|
signing_key:
|
102
104
|
specification_version: 4
|
103
105
|
summary: Simple Extract Transform & Load - setl
|
@@ -106,3 +108,4 @@ test_files:
|
|
106
108
|
- spec/error_handling_spec.rb
|
107
109
|
- spec/etl_spec.rb
|
108
110
|
- spec/spec_helper.rb
|
111
|
+
has_rdoc:
|