retl 0.0.4 → 0.0.5
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 +11 -0
- data/README.md +70 -3
- data/lib/retl.rb +11 -0
- data/lib/retl/configuration.rb +7 -0
- data/lib/retl/errors/step_execution_error.rb +17 -0
- data/lib/retl/handlers/explode_handler.rb +1 -1
- data/lib/retl/handlers/filter_handler.rb +1 -1
- data/lib/retl/handlers/fork_handler.rb +1 -1
- data/lib/retl/handlers/handler.rb +9 -2
- data/lib/retl/handlers/inspect_handler.rb +1 -1
- data/lib/retl/handlers/path_handler.rb +1 -1
- data/lib/retl/handlers/step_handler.rb +1 -1
- data/lib/retl/handlers/transform_handler.rb +4 -3
- data/lib/retl/next_description.rb +22 -0
- data/lib/retl/path.rb +12 -3
- data/lib/retl/path_builder.rb +11 -1
- data/lib/retl/transformation.rb +18 -4
- data/lib/retl/version.rb +1 -1
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5fb3e97322814aed123d196693eacd2eb5560719
|
4
|
+
data.tar.gz: 778407acae9f684ddaa8b746d0c8dd751ed2e9be
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8b0182706dbf3a4350d53cb967b576075a9fbf85dd1dd1efb778bc0bd4d648b15bddea9904ece0a973bf15896d60ed38ae4833f09b1c5ffc986f48650415fa8d
|
7
|
+
data.tar.gz: 29a71295ac8f7025fde450c1f4f079e100fe082c2891d20fe34950f28f588c12affe2a0e1e8bcc50a3bd43ca20e80ad6ea97f9839fccf8535514b6c43a93fe84
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,16 @@
|
|
1
1
|
# Change Log
|
2
2
|
|
3
|
+
### 0.0.5
|
4
|
+
|
5
|
+
- New Feature: Step descriptions allow steps to be described while being
|
6
|
+
built. This will allow the description of the step to appear in the
|
7
|
+
error message if an error occurs.
|
8
|
+
- Bug Fix: transform was mutating source data. Instead we just want it to
|
9
|
+
mutate a duplicate and pass that along.
|
10
|
+
- New Feature: adds a configuration block to alter the behavior of rETL
|
11
|
+
- New Feature: error handling. Errors can simple be raised (for development)
|
12
|
+
or be captured so they can be evaluated later (for production)
|
13
|
+
|
3
14
|
### 0.0.4
|
4
15
|
|
5
16
|
- Bug Fix: fixes memoized fork results
|
data/README.md
CHANGED
@@ -232,8 +232,6 @@ end
|
|
232
232
|
result = my_path.transform([6])
|
233
233
|
result.to_a
|
234
234
|
#=> [3, 9, 15]
|
235
|
-
|
236
|
-
expect(result.to_a).to eq([3, 9, 15])
|
237
235
|
```
|
238
236
|
|
239
237
|
#### Path Reuse
|
@@ -355,6 +353,76 @@ result.to_a
|
|
355
353
|
#=> [{years_since_birth: 7, age_classification: "child"}]
|
356
354
|
```
|
357
355
|
|
356
|
+
### Error Handling
|
357
|
+
|
358
|
+
Sometimes errors happen while a step is being performed. By default, errors are
|
359
|
+
wrapped in a `StepExecutionError` and the transformation will abort (this
|
360
|
+
can be changed with configuration, however). The `StepExecutionError` will
|
361
|
+
provide context to aid in debugging the error.
|
362
|
+
|
363
|
+
Pay attention to the `desc` step in the path below. `desc` simply describes the
|
364
|
+
next step. Not only does this provide good documentation, but the description
|
365
|
+
will also be available in the `StepExecutionError` to make debugging easier.
|
366
|
+
|
367
|
+
```
|
368
|
+
my_path = Retl::Path.new do
|
369
|
+
desc "calculates the number 5"
|
370
|
+
calc(:five) { 5 }
|
371
|
+
|
372
|
+
desc "Check for sane ages"
|
373
|
+
transform do |row|
|
374
|
+
raise StandardError, "bad age" if row[:age] > 100
|
375
|
+
end
|
376
|
+
end
|
377
|
+
|
378
|
+
data = [
|
379
|
+
{age: 33},
|
380
|
+
{age: 3},
|
381
|
+
{age: 1000}
|
382
|
+
]
|
383
|
+
|
384
|
+
begin
|
385
|
+
result = my_path.transform(data).to_a
|
386
|
+
rescue Retl::StepExecutionError => e
|
387
|
+
e.message
|
388
|
+
#=> "bad age (at step: Check for sane ages))"
|
389
|
+
|
390
|
+
e.step_description
|
391
|
+
#=> "Check for sane ages"
|
392
|
+
|
393
|
+
e.input_data
|
394
|
+
#=> { :age => 1000 }
|
395
|
+
|
396
|
+
e.current_data
|
397
|
+
#=> { :age => 1000, :five => 5 }
|
398
|
+
end
|
399
|
+
```
|
400
|
+
|
401
|
+
rETL can be globally configured to continue transforming data despite an error
|
402
|
+
like so:
|
403
|
+
|
404
|
+
```
|
405
|
+
Retl.configure do |config|
|
406
|
+
config.raise_errors = false
|
407
|
+
end
|
408
|
+
```
|
409
|
+
|
410
|
+
With this configuration change, the transformation would continue to process the
|
411
|
+
data and errors would be accessible via the `#errors` method on the
|
412
|
+
transformation.
|
413
|
+
|
414
|
+
```
|
415
|
+
# same path and data as above
|
416
|
+
|
417
|
+
result = my_path.transform(data)
|
418
|
+
|
419
|
+
result.to_a
|
420
|
+
#=> [ { age: 3, five: 5 } ] # the error data isn't in the result
|
421
|
+
|
422
|
+
result.errors.to_a
|
423
|
+
#=> [ StepExecutionError ] # the error information is still available, see
|
424
|
+
# above for use.
|
425
|
+
```
|
358
426
|
|
359
427
|
## Roadmap
|
360
428
|
|
@@ -372,7 +440,6 @@ universal for any type of data transformation requirement in Ruby.
|
|
372
440
|
|
373
441
|
### Next Steps
|
374
442
|
|
375
|
-
- Error handling
|
376
443
|
- Tracing and logging
|
377
444
|
- Extract patterns
|
378
445
|
- Load patterns
|
data/lib/retl.rb
CHANGED
@@ -1,7 +1,18 @@
|
|
1
1
|
require "retl/version"
|
2
2
|
|
3
3
|
require "retl/path"
|
4
|
+
require "retl/configuration"
|
4
5
|
|
5
6
|
module Retl
|
7
|
+
@configuration = Configuration.new
|
8
|
+
|
9
|
+
class << self
|
10
|
+
attr_reader :configuration
|
11
|
+
|
12
|
+
def configure(&block)
|
13
|
+
block.call(@configuration)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
6
17
|
# Your code goes here...
|
7
18
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Retl
|
2
|
+
class StepExecutionError < StandardError
|
3
|
+
attr_reader :input_data, :current_data, :step, :cause
|
4
|
+
|
5
|
+
def initialize(input_data: nil, current_data: nil, step: nil, cause: $!)
|
6
|
+
@input_data, @current_data = input_data, current_data
|
7
|
+
@step, @cause = step, cause
|
8
|
+
|
9
|
+
super("#{cause} (at step: #{step_description}))")
|
10
|
+
set_backtrace(cause.backtrace)
|
11
|
+
end
|
12
|
+
|
13
|
+
def step_description
|
14
|
+
@step.description
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -1,7 +1,10 @@
|
|
1
1
|
module Retl
|
2
2
|
class Handler
|
3
|
+
attr_accessor :description
|
4
|
+
|
3
5
|
def initialize
|
4
|
-
@output
|
6
|
+
@output = []
|
7
|
+
@description = "unknown"
|
5
8
|
end
|
6
9
|
|
7
10
|
def output
|
@@ -9,6 +12,10 @@ module Retl
|
|
9
12
|
end
|
10
13
|
|
11
14
|
def push_in(data, context)
|
15
|
+
call(data, context)
|
16
|
+
end
|
17
|
+
|
18
|
+
def call(data, context)
|
12
19
|
raise NotImplementedError, "Handlers much implement the #push_in(data, context) method"
|
13
20
|
end
|
14
21
|
|
@@ -18,4 +25,4 @@ module Retl
|
|
18
25
|
@output.push data
|
19
26
|
end
|
20
27
|
end
|
21
|
-
end
|
28
|
+
end
|
@@ -2,9 +2,10 @@ require_relative "step_handler"
|
|
2
2
|
|
3
3
|
module Retl
|
4
4
|
class TransformHandler < StepHandler
|
5
|
-
def
|
6
|
-
|
7
|
-
|
5
|
+
def call(data, context)
|
6
|
+
dup = data.dup
|
7
|
+
context.execute_step(step, dup)
|
8
|
+
push_out dup
|
8
9
|
end
|
9
10
|
end
|
10
11
|
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Retl
|
2
|
+
class NextDescription
|
3
|
+
def initialize(default="unknown")
|
4
|
+
@default = default
|
5
|
+
reset
|
6
|
+
end
|
7
|
+
|
8
|
+
def reset
|
9
|
+
@next_description = @default
|
10
|
+
end
|
11
|
+
|
12
|
+
def describe_next(description)
|
13
|
+
@next_description = description
|
14
|
+
end
|
15
|
+
|
16
|
+
def take
|
17
|
+
description = @next_description
|
18
|
+
reset
|
19
|
+
description
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/lib/retl/path.rb
CHANGED
@@ -5,6 +5,7 @@ require "retl/handlers/handler"
|
|
5
5
|
require "retl/handlers/step_handler"
|
6
6
|
require "retl/handlers/explode_handler"
|
7
7
|
require "retl/handlers/fork_handler"
|
8
|
+
require "retl/errors/step_execution_error"
|
8
9
|
|
9
10
|
module Retl
|
10
11
|
# A Path is a blueprint for transforming data
|
@@ -106,10 +107,18 @@ module Retl
|
|
106
107
|
# @param context [Context] the execution context for the transformation
|
107
108
|
#
|
108
109
|
# @return [Array<Hash>] the transformed data
|
109
|
-
def call(
|
110
|
-
@steps.reduce([
|
110
|
+
def call(input, context=Context.new(self))
|
111
|
+
@steps.reduce([input]) do |queue, handler|
|
111
112
|
queue.each do |data|
|
112
|
-
|
113
|
+
begin
|
114
|
+
handler.push_in(data, context)
|
115
|
+
rescue Exception => e
|
116
|
+
raise StepExecutionError.new(
|
117
|
+
input_data: input,
|
118
|
+
current_data: data,
|
119
|
+
step: handler
|
120
|
+
)
|
121
|
+
end
|
113
122
|
end
|
114
123
|
handler.output
|
115
124
|
end
|
data/lib/retl/path_builder.rb
CHANGED
@@ -4,18 +4,24 @@ require "retl/handlers/filter_handler"
|
|
4
4
|
require "retl/handlers/inspect_handler"
|
5
5
|
require "retl/handlers/explode_handler"
|
6
6
|
require "retl/handlers/path_handler"
|
7
|
+
require "retl/next_description"
|
7
8
|
|
8
9
|
|
9
10
|
module Retl
|
10
11
|
class PathBuilder
|
11
12
|
def initialize(path, &block)
|
12
13
|
@path = path
|
14
|
+
@next_descripion = NextDescription.new
|
13
15
|
instance_eval(&block)
|
14
16
|
end
|
15
17
|
|
16
18
|
def step(step=nil, handler: StepHandler, &block)
|
17
19
|
step ||= block
|
18
|
-
|
20
|
+
|
21
|
+
handler = handler.new(step)
|
22
|
+
handler.description = @next_descripion.take
|
23
|
+
|
24
|
+
@path.add_handler handler
|
19
25
|
end
|
20
26
|
alias_method :replace, :step
|
21
27
|
|
@@ -63,5 +69,9 @@ module Retl
|
|
63
69
|
def path(path, dependencies={}, &block)
|
64
70
|
@path.add_handler PathHandler.new(path, dependencies, &block)
|
65
71
|
end
|
72
|
+
|
73
|
+
def desc(step_description)
|
74
|
+
@next_descripion.describe_next(step_description)
|
75
|
+
end
|
66
76
|
end
|
67
77
|
end
|
data/lib/retl/transformation.rb
CHANGED
@@ -1,15 +1,17 @@
|
|
1
1
|
require "retl/context"
|
2
2
|
require "retl/fork_data_collector"
|
3
|
+
require "retl/errors/step_execution_error"
|
3
4
|
|
4
5
|
module Retl
|
5
6
|
class Transformation
|
6
7
|
include Enumerable
|
7
|
-
|
8
|
+
|
8
9
|
def initialize(enumerable, path, options={})
|
9
10
|
@enumerable, @path, @options = enumerable, path, options
|
10
11
|
@context = Context.new(@path, @options)
|
11
12
|
@fork_data = ForkDataCollector.new(@context)
|
12
13
|
@forks = {}
|
14
|
+
@errors = []
|
13
15
|
end
|
14
16
|
|
15
17
|
def each(&block)
|
@@ -52,13 +54,25 @@ module Retl
|
|
52
54
|
end
|
53
55
|
end
|
54
56
|
|
57
|
+
def errors
|
58
|
+
@errors.each
|
59
|
+
end
|
60
|
+
|
55
61
|
private
|
56
62
|
|
57
63
|
def build_each_result(&block)
|
58
64
|
@each ||= @enumerable.reduce([]) do |result, data|
|
59
|
-
|
60
|
-
|
61
|
-
|
65
|
+
begin
|
66
|
+
@path.call(data, @context).each do |data|
|
67
|
+
yield data if block_given?
|
68
|
+
result << data
|
69
|
+
end
|
70
|
+
rescue StepExecutionError => e
|
71
|
+
if Retl.configuration.raise_errors
|
72
|
+
raise e
|
73
|
+
else
|
74
|
+
@errors << e
|
75
|
+
end
|
62
76
|
end
|
63
77
|
result
|
64
78
|
end
|
data/lib/retl/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: retl
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Biehl
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-11-
|
11
|
+
date: 2015-11-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -71,7 +71,9 @@ files:
|
|
71
71
|
- bin/console
|
72
72
|
- bin/setup
|
73
73
|
- lib/retl.rb
|
74
|
+
- lib/retl/configuration.rb
|
74
75
|
- lib/retl/context.rb
|
76
|
+
- lib/retl/errors/step_execution_error.rb
|
75
77
|
- lib/retl/event_router.rb
|
76
78
|
- lib/retl/fork_data_collector.rb
|
77
79
|
- lib/retl/handlers/explode_handler.rb
|
@@ -82,6 +84,7 @@ files:
|
|
82
84
|
- lib/retl/handlers/path_handler.rb
|
83
85
|
- lib/retl/handlers/step_handler.rb
|
84
86
|
- lib/retl/handlers/transform_handler.rb
|
87
|
+
- lib/retl/next_description.rb
|
85
88
|
- lib/retl/path.rb
|
86
89
|
- lib/retl/path_builder.rb
|
87
90
|
- lib/retl/transformation.rb
|