realize 1.0.0.pre.alpha.1 → 1.0.0.pre.alpha.2

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: b982efd1c16b8416b6a1f230d6de7ca3923ddaf2d6986f4b16fa84628f6075ab
4
- data.tar.gz: d3f20dc7adb39811a3ab1c065cabff494dded6ff13c7e5bbc5e6398b657f80cc
3
+ metadata.gz: 289c0fa13f4421249a59e82ce767881f04bd47bea5d0b3a4eb4db503b37add28
4
+ data.tar.gz: f8575e76151f98fc0e34d8fcf4c50231294ffad0f037eb6f276fd1393f8e6cd4
5
5
  SHA512:
6
- metadata.gz: 8a2d81b01a096e15ae87e05ec5e303ad68136c758f48df06ead805f0feb5f40e943f42cce4c929ad53ede412a330f94b71091d025de5997c64fe972784b41104
7
- data.tar.gz: b94ecac10ff8727cc69b8b67113703e7a623dc640b914fe8f9ad3a6c25050c1fc5310d18e846333b0d1041a712367263f2309999460d9e4cbe7c08f900571386
6
+ metadata.gz: cf1f9808bdb3870860155d3eecf6187b4bb9a5b3b4ea755552a125e9a96fb34173d3174d2ba98c5da9aeef00dea520e3d2cf2b2f7821daa4b2d3c6558f8cec21
7
+ data.tar.gz: ec3bc0d03c004d8481b4d1d9b690076f9dd48988e9e957cd61c82aac40e77d60401666057dc9484b4ea8d6d116ed781305af49b0dcdf0d2bdfe77583393fc931
data/README.md CHANGED
@@ -2,7 +2,11 @@
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/realize.svg)](https://badge.fury.io/rb/realize) [![Build Status](https://travis-ci.org/bluemarblepayroll/realize.svg?branch=master)](https://travis-ci.org/bluemarblepayroll/realize) [![Maintainability](https://api.codeclimate.com/v1/badges/115f0c5a1d0a4cce7230/maintainability)](https://codeclimate.com/github/bluemarblepayroll/realize/maintainability) [![Test Coverage](https://api.codeclimate.com/v1/badges/115f0c5a1d0a4cce7230/test_coverage)](https://codeclimate.com/github/bluemarblepayroll/realize/test_coverage) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
4
4
 
5
- TODO
5
+ This library provides a pluggable and configurable data transformation framework. The general use-case is:
6
+
7
+ > We need to be able to configure the data transformation pipeline, within an application, for a system-to-system integration.
8
+
9
+ It is currently used in production at Blue Marble to power the transformation pipeline within a larger ETL framework.
6
10
 
7
11
  ## Installation
8
12
 
@@ -20,7 +24,87 @@ bundle add realize
20
24
 
21
25
  ## Examples
22
26
 
23
- TODO
27
+ ### Basic Transformer Example
28
+
29
+ Here is a simple record we will use for data derivation and transformation:
30
+
31
+ ````ruby
32
+ record = {
33
+ id: 1,
34
+ created_at: '2020-03-04T12:34:56Z',
35
+ first: 'Frank',
36
+ last: 'Rizzo'
37
+ }
38
+ ````
39
+
40
+ Let's say we wanted to retrieve the created_at formatted as: 'MM/DD/YY', we could write:
41
+
42
+ ````ruby
43
+ transformers = [
44
+ {
45
+ type: 'r/value/resolve',
46
+ key: :created_at
47
+ },
48
+ {
49
+ type: 'r/format/date',
50
+ output_format: '%D'
51
+ }
52
+ ]
53
+
54
+ value = Realize.pipeline(transformers).transform(record) # 03/04/20
55
+ ````
56
+
57
+ Notice how all built-in transformers are prefixed with 'r'. This should help isolate the built-in transformers from potential externally registered transformers.
58
+
59
+ ### Transformer Gallery
60
+
61
+ Here is a list of each built-in transformer, their options, and what their function is:
62
+
63
+ #### Collection-oriented Transformers
64
+
65
+ * **r/collection/sort** [key, direction]: Takes an array (or coerces value to an array) and sort it either ascending or descending by some defined key's value.
66
+
67
+ #### Filtering Transformers
68
+
69
+ * **r/filter/by_key_record_value** [key, value]: Takes an array (or coerces value to an array) and selects only the records that match the key's value. In this case the value is derived off of the main record.
70
+ * **r/filter/by_key_value_presence** [key]: Takes an array (or coerces value to an array) and selects only the records where the key's value is present (not nil and not empty).
71
+ * **r/filter/by_key_record_value** [key, value]: Takes an array (or coerces value to an array) and selects only the records that match the key's value. In this case, the value is statically defined.
72
+ * **r/filter/inactive** [key, value]: Takes an array (or coerces value to an array) and selects only the records where the current time is between the start and end times as derived from the record. Note that *current time* can be passed in but defaults to current UTC time.
73
+
74
+ #### Format-oriented Transformers
75
+
76
+ * **r/format/date** [input_format, output_format]: Parses the incoming value into a Time object using the configured input_format and outputs it as formatted by the configured output_format.
77
+ * **r/format/remove_whitespace** []: Removes all whitespace from the incoming value.
78
+ * **r/format/string_replace** [original, replacement]: Replaces all occurrences of the configured original value with the replacement value.
79
+
80
+ #### Logical Transformers
81
+
82
+ * **r/logical/switch** [cases, default_transformers, key]: Provides a value-based logic branching. If a value matches a specific case, the specific cases transformers will be executed. If it does not match any case then the default_transformers will be executed.
83
+
84
+ #### Value-oriented Transformers
85
+
86
+ * **r/logical/blank** []: Always return a blank string.
87
+ * **r/logical/map** [values]: Do a lookup on the value using the `values` hash. If a value is found, then its corresponding value is returned. If it isn't then the input is returned.
88
+ * **r/logical/null** []: Always returns null.
89
+ * **r/logical/resolve** [key]: Dynamically resolves a value based on the record's key. It uses the [Objectable](https://github.com/bluemarblepayroll/objectable) library by default, which provides some goodies like dot-notation for nested objects and type-insensitivity (works for Ruby objects, hashes, structs, etc.)
90
+ * **r/logical/static** [value]: Always returns a hard-coded value.
91
+ * **r/logical/verbatim** []: Default transformer, simply echos back the input.
92
+
93
+ ### Plugging in Transformers
94
+
95
+ Custom transformers can be externally created and registered as long as it complies with the general transformer interface:
96
+
97
+ * constructor accepts keyword arguments from which the configuration provides
98
+ * responds to a method called transform with the signature: transform(resolver, value, time, record)
99
+
100
+ After you have implemented the custom transformer, you can externally register is by:
101
+
102
+ ````ruby
103
+ Realize::Transformers.register('some_custom_transformer', SomeCustomTransformer)
104
+ ````
105
+
106
+ You should now be able to use the type: 'some_custom_transformer' within your transformation configuration.
107
+
24
108
 
25
109
  ## Contributing
26
110
 
@@ -18,11 +18,8 @@ require_relative 'realize/pipeline'
18
18
  # Top-level syntactic sugar.
19
19
  module Realize
20
20
  class << self
21
- def pipeline(resolver: Objectable.resolver, transformers: [])
22
- Pipeline.new(
23
- resolver: resolver,
24
- transformers: transformers
25
- )
21
+ def pipeline(transformers = [], resolver: Objectable.resolver)
22
+ Pipeline.new(transformers, resolver: resolver)
26
23
  end
27
24
  end
28
25
  end
@@ -28,10 +28,10 @@ module Realize
28
28
  freeze
29
29
  end
30
30
 
31
- def transform(_resolver, value, _time, _record)
31
+ def transform(resolver, value, _time, _record)
32
32
  records = array(value)
33
33
 
34
- sorted = records.sort_by { |hsh| hsh[key.to_sym] }
34
+ sorted = records.sort_by { |hsh| resolver.get(hsh, key) }
35
35
 
36
36
  order == DESCENDING ? sorted.reverse : sorted
37
37
  end
@@ -7,8 +7,6 @@ module Realize
7
7
  class RemoveWhitespace
8
8
  acts_as_hashable
9
9
 
10
- def initialize(_opts = {}); end
11
-
12
10
  def transform(_resolver, value, _time, _record)
13
11
  value.to_s.gsub(/\s+/, ' ')
14
12
  end
@@ -6,7 +6,7 @@ module Realize
6
6
  class Pipeline
7
7
  attr_reader :resolver, :transformers
8
8
 
9
- def initialize(resolver: Objectable.resolver, transformers: [])
9
+ def initialize(transformers = [], resolver: Objectable.resolver)
10
10
  raise ArgumentError, 'resolver is required' unless resolver
11
11
 
12
12
  @resolver = resolver
@@ -15,11 +15,8 @@ module Realize
15
15
  freeze
16
16
  end
17
17
 
18
- def transform(record, opts = {})
19
- time = opts.fetch(:time, Time.now.utc)
20
- value = opts.fetch(:value, record)
21
-
22
- transformers.inject(value) do |memo, transformer|
18
+ def transform(record, time = Time.now.utc)
19
+ transformers.inject(record) do |memo, transformer|
23
20
  transformer.transform(resolver, memo, time, record)
24
21
  end
25
22
  end
@@ -6,8 +6,6 @@ module Realize
6
6
  class Blank
7
7
  acts_as_hashable
8
8
 
9
- def initialize(_opts = {}); end
10
-
11
9
  def transform(_resolver, _value, _time, _record)
12
10
  ''
13
11
  end
@@ -6,8 +6,6 @@ module Realize
6
6
  class Null
7
7
  acts_as_hashable
8
8
 
9
- def initialize(_opts = {}); end
10
-
11
9
  def transform(_resolver, _value, _time, _record)
12
10
  nil
13
11
  end
@@ -6,11 +6,6 @@ module Realize
6
6
  class Verbatim
7
7
  acts_as_hashable
8
8
 
9
- # This is here to satisfy an underlying issue in acts_as_hashable.
10
- # The #make calls in the factory and hashable module should be calling #new with no
11
- # args if no keys are detected.
12
- def initialize(_opts = {}); end
13
-
14
9
  def transform(_resolver, value, _time, _record)
15
10
  value
16
11
  end
@@ -8,5 +8,5 @@
8
8
  #
9
9
 
10
10
  module Realize
11
- VERSION = '1.0.0-alpha.1'
11
+ VERSION = '1.0.0-alpha.2'
12
12
  end
@@ -28,7 +28,7 @@ Gem::Specification.new do |s|
28
28
 
29
29
  s.required_ruby_version = '>= 2.5'
30
30
 
31
- s.add_dependency('acts_as_hashable', '~>1')
31
+ s.add_dependency('acts_as_hashable', '=1.2.0.pre.alpha')
32
32
  s.add_dependency('objectable', '~>1')
33
33
 
34
34
  s.add_development_dependency('guard-rspec', '~>4.7')
metadata CHANGED
@@ -1,29 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: realize
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0.pre.alpha.1
4
+ version: 1.0.0.pre.alpha.2
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-06-08 00:00:00.000000000 Z
11
+ date: 2020-06-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: acts_as_hashable
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - '='
18
18
  - !ruby/object:Gem::Version
19
- version: '1'
19
+ version: 1.2.0.pre.alpha
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "~>"
24
+ - - '='
25
25
  - !ruby/object:Gem::Version
26
- version: '1'
26
+ version: 1.2.0.pre.alpha
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: objectable
29
29
  requirement: !ruby/object:Gem::Requirement