Class: Retl::Path

Inherits:
Object
  • Object
show all
Defined in:
lib/retl/path.rb

Overview

A Path is a blueprint for transforming data

A Path is a sequence of steps that are executed on data in order to transform it.

Paths can be built with a block using the API defined in the #PathBuilder.

Steps are added to the Path with the #add_step method.

A Path can act on a single piece of data with the #call method.

A Path can transform a list of data with the #transform method.

Examples:

path = Retl::Path.new do 
  step do |data|
    data[:something] = "some value"
    data
  end

  calculate(:something_else) do 
    "some other value"
  end

  transform do |data|
    data[:something_together] = data[:something] + data[:something_else]
  end
end

path.transform(data)

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(parent = nil, &block) ⇒ Path

Initializes a new Path

Parameters:

  • parent (Path) (defaults to: nil)
    • a Path to inherit from



48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/retl/path.rb', line 48

def initialize(parent=nil, &block)
  @steps         = []
  @dependencies  = {}
  @forks         = {}
  @fork_builders = {}

  if parent
    @dependencies = parent.dependencies.dup
    add_step parent.dup, handler: ExplodeHandler
  end

  build(&block) if block
end

Instance Attribute Details

#dependenciesObject (readonly)

Returns the value of attribute dependencies.



43
44
45
# File 'lib/retl/path.rb', line 43

def dependencies
  @dependencies
end

#sourceObject (readonly)

Returns the value of attribute source.



43
44
45
# File 'lib/retl/path.rb', line 43

def source
  @source
end

#stepsObject (readonly)

Returns the value of attribute steps.



43
44
45
# File 'lib/retl/path.rb', line 43

def steps
  @steps
end

Instance Method Details

#add_dependency(name, source) ⇒ void

This method returns an undefined value.

Adds a depdency to the Path

Parameters:

  • name (Symbol)

    the name of the dependency (should be a valid Ruby method)

  • source (#call)

    a callable object that will return the depdency



173
174
175
# File 'lib/retl/path.rb', line 173

def add_dependency(name, source)
  @dependencies[name] = source
end

#add_fork(name, &block) ⇒ void

This method returns an undefined value.

Adds an fork to the Path

Forks can be accessed via #forks

Examples:

path.add_fork(:river) do 
  filter { |data| data[:is_wet] }
end
path.forks(:river)

Parameters:

  • name (Symbol)

    the name of the fork



140
141
142
143
144
# File 'lib/retl/path.rb', line 140

def add_fork(name, &block)
  fork = Path.new(&block)
  add_handler ForkHandler.new(name)
  @forks[name] = fork 
end

#add_fork_builder(name, &block) ⇒ Fork

Adds a fork builder block

Parameters:

  • name (Symbol)

    the name of the fork to build

  • &block (Block)

    the block that builds the fork

Returns:

  • (Fork)

    the built fork



161
162
163
164
# File 'lib/retl/path.rb', line 161

def add_fork_builder(name, &block)
  @fork_builders[name] = block
  add_fork(name, &block)
end

#add_handler(handler) ⇒ Object



94
95
96
# File 'lib/retl/path.rb', line 94

def add_handler(handler)
  @steps << handler
end

#add_step(step, handler: StepHandler) ⇒ void

This method returns an undefined value.

Adds a step to the Path

A step is called with data and is expected to return complete, modified data.

Steps are executed in the sequence they are added.

Parameters:

  • step (#call(data))

    the step to take



90
91
92
# File 'lib/retl/path.rb', line 90

def add_step(step, handler: StepHandler)
  add_handler handler.new(step)
end

#build(&block) ⇒ void

This method returns an undefined value.

Builds a Path with the PathBuilder DSL



65
66
67
# File 'lib/retl/path.rb', line 65

def build(&block)
  PathBuilder.new(self, &block)
end

#call(input, context = Context.new(self)) ⇒ Array<Hash>

Execuutes the Path with the given data

Currently the DSL mostly supports Hash based data, so this expects a Hash.

Since a piece of data can now be exploded, this method will always return an Array.

Parameters:

  • data (Hash)

    the data that will be transformed by the Path

  • context (Context) (defaults to: Context.new(self))

    the execution context for the transformation

Returns:

  • (Array<Hash>)

    the transformed data



110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/retl/path.rb', line 110

def call(input, context=Context.new(self))
  @steps.reduce([input]) do |queue, handler|
    queue.each do |data|
      begin
        handler.push_in(data, context)
      rescue Exception => e
        raise StepExecutionError.new(
          input_data: input, 
          current_data: data, 
          step: handler
        )
      end
    end
    handler.output
  end
end

#forks(name) ⇒ Path

Gets a fork by name

Parameters:

  • name (Symbol)

    the name of the fork to get

Returns:

  • (Path)

    the forked path



151
152
153
# File 'lib/retl/path.rb', line 151

def forks(name)
  @forks[name]
end

#initialize_copy(source) ⇒ Object

Initializer when copying a Path

When a Path is copied, a copy of the Path’s steps need to be copied as well. That was if additional steps are added to the original Path they won’t be part of the copied Path.



74
75
76
77
78
# File 'lib/retl/path.rb', line 74

def initialize_copy(source)
  @steps         = source.steps.dup
  @forks         = {}
  @fork_builders = {}
end

#transform(enumerable, options = {}) ⇒ Transformation

Executes the Path with data

Parameters:

  • the (Enumerable)

    data that will be processed by the Path

  • options (Hash) (defaults to: {})

    a customizable set of options

Options Hash (options):

  • that (Object)

    will be passed to #depends_on for the context

Returns:



183
184
185
# File 'lib/retl/path.rb', line 183

def transform(enumerable, options={})
  Transformation.new(enumerable, self, options)
end