pipely 0.0.1
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.
- data/README.md +4 -0
- data/Rakefile +21 -0
- data/bin/pipely +24 -0
- data/lib/pipely.rb +20 -0
- data/lib/pipely/component.rb +111 -0
- data/lib/pipely/definition.rb +72 -0
- data/lib/pipely/dependency.rb +14 -0
- data/lib/pipely/graph_builder.rb +51 -0
- data/lib/pipely/reference_list.rb +32 -0
- data/lib/pipely/version.rb +3 -0
- data/spec/lib/pipely/component_spec.rb +44 -0
- data/spec/lib/pipely/definition_spec.rb +56 -0
- data/spec/lib/pipely/dependency_spec.rb +11 -0
- data/spec/lib/pipely/graph_builder_spec.rb +42 -0
- data/spec/lib/pipely/reference_list_spec.rb +45 -0
- data/spec/lib/pipely_spec.rb +38 -0
- metadata +125 -0
data/README.md
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
begin
|
3
|
+
require 'bundler/setup'
|
4
|
+
rescue LoadError
|
5
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
6
|
+
end
|
7
|
+
|
8
|
+
Bundler::GemHelper.install_tasks
|
9
|
+
|
10
|
+
require 'rspec/core/rake_task'
|
11
|
+
require 'cane/rake_task'
|
12
|
+
|
13
|
+
RSpec::Core::RakeTask.new do |t|
|
14
|
+
t.pattern = 'spec/**/*_spec.rb'
|
15
|
+
end
|
16
|
+
|
17
|
+
Cane::RakeTask.new(:quality) do |cane|
|
18
|
+
cane.canefile = '.cane'
|
19
|
+
end
|
20
|
+
|
21
|
+
task :default => [:spec, :quality]
|
data/bin/pipely
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'pipely'
|
4
|
+
require 'optparse'
|
5
|
+
|
6
|
+
output_path = nil
|
7
|
+
|
8
|
+
OptionParser.new do |opts|
|
9
|
+
opts.banner = "Usage: pipely [options] definition.json"
|
10
|
+
|
11
|
+
opts.on("-o", "--output PATH",
|
12
|
+
"Path to write PNG file(s) of graph visualization(s)") do |output|
|
13
|
+
output_path = output
|
14
|
+
end
|
15
|
+
end.parse!
|
16
|
+
|
17
|
+
definition_file = ARGV.last
|
18
|
+
definition_json = File.open(definition_file).read
|
19
|
+
|
20
|
+
output_base = File.basename(definition_file,".*") + '.png'
|
21
|
+
output_file = output_path ? File.join(output_path, output_base) : output_base
|
22
|
+
|
23
|
+
puts "Generating #{output_file}"
|
24
|
+
Pipely.draw(definition_json, output_file)
|
data/lib/pipely.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'pipely/definition'
|
2
|
+
require 'pipely/graph_builder'
|
3
|
+
|
4
|
+
# The top-level module for this gem. It provides the recommended public
|
5
|
+
# interface for using Pipely to visualize and manipulate your Data Pipeline
|
6
|
+
# definitions.
|
7
|
+
#
|
8
|
+
module Pipely
|
9
|
+
|
10
|
+
def self.draw(definition_json, filename, node_attributes=nil)
|
11
|
+
definition = Definition.parse(definition_json)
|
12
|
+
definition.apply_node_attributes(node_attributes) if node_attributes
|
13
|
+
|
14
|
+
graph_builder = GraphBuilder.new
|
15
|
+
|
16
|
+
graph = graph_builder.build(definition.components_for_graph)
|
17
|
+
graph.output( :png => filename )
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
require 'virtus'
|
2
|
+
require 'pipely/reference_list'
|
3
|
+
|
4
|
+
module Pipely
|
5
|
+
|
6
|
+
# Represents a Component within a Data Pipeline Definition
|
7
|
+
# http://amzn.to/16lbBKx
|
8
|
+
#
|
9
|
+
class Component
|
10
|
+
|
11
|
+
REFERENCE_KEYS = [
|
12
|
+
'dependsOn',
|
13
|
+
'input',
|
14
|
+
'output',
|
15
|
+
'runsOn',
|
16
|
+
'schedule',
|
17
|
+
'onFail',
|
18
|
+
'onSuccess',
|
19
|
+
'dataFormat',
|
20
|
+
]
|
21
|
+
|
22
|
+
STATE_COLORS = {
|
23
|
+
'FINISHED' => 'deepskyblue1',
|
24
|
+
'RUNNING' => 'chartreuse',
|
25
|
+
'WAITING_ON_DEPENDENCIES' => 'gray',
|
26
|
+
'WAITING_FOR_RUNNER' => 'bisque4',
|
27
|
+
'FAILED' => 'orangered',
|
28
|
+
}
|
29
|
+
|
30
|
+
include Virtus
|
31
|
+
|
32
|
+
attribute :id, String
|
33
|
+
attribute :type, String
|
34
|
+
attribute :color, String
|
35
|
+
attribute :execution_state, String
|
36
|
+
|
37
|
+
attribute :dependsOn, ReferenceList
|
38
|
+
attribute :input, ReferenceList
|
39
|
+
attribute :output, ReferenceList
|
40
|
+
attribute :runsOn, ReferenceList
|
41
|
+
attribute :schedule, ReferenceList
|
42
|
+
attribute :onFail, ReferenceList
|
43
|
+
attribute :onSuccess, ReferenceList
|
44
|
+
attribute :dataFormat, ReferenceList
|
45
|
+
|
46
|
+
def initialize(args)
|
47
|
+
@original_args = args.clone
|
48
|
+
super
|
49
|
+
coerce_references
|
50
|
+
end
|
51
|
+
|
52
|
+
def coerce_references
|
53
|
+
REFERENCE_KEYS.each do |key|
|
54
|
+
value = send(key)
|
55
|
+
unless value.is_a?(ReferenceList)
|
56
|
+
send("#{key}=", ReferenceList.new(value))
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def graphviz_options
|
62
|
+
{
|
63
|
+
:shape => 'record',
|
64
|
+
:label => "{#{label}}",
|
65
|
+
:color => color || 'black',
|
66
|
+
:fillcolor => STATE_COLORS[execution_state] || 'white',
|
67
|
+
:style => 'filled',
|
68
|
+
}
|
69
|
+
end
|
70
|
+
|
71
|
+
def dependencies(scope=nil)
|
72
|
+
deps = dependsOn.build_dependencies('dependsOn') +
|
73
|
+
input.build_dependencies('input') +
|
74
|
+
output.build_dependencies('output')
|
75
|
+
|
76
|
+
if :all == scope
|
77
|
+
deps += runsOn.build_dependencies(:runsOn)
|
78
|
+
deps += schedule.build_dependencies(:schedule)
|
79
|
+
deps += onFail.build_dependencies(:onFail)
|
80
|
+
deps += onSuccess.build_dependencies(:onSuccess)
|
81
|
+
deps += dataFormat.build_dependencies(:dataFormat)
|
82
|
+
end
|
83
|
+
|
84
|
+
deps
|
85
|
+
end
|
86
|
+
|
87
|
+
def to_json(options={})
|
88
|
+
h = @original_args
|
89
|
+
|
90
|
+
REFERENCE_KEYS.each do |key|
|
91
|
+
value = send(key)
|
92
|
+
|
93
|
+
if value.present?
|
94
|
+
h[key] = value
|
95
|
+
else
|
96
|
+
h.delete(key)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
h.to_json(options)
|
101
|
+
end
|
102
|
+
|
103
|
+
private
|
104
|
+
|
105
|
+
def label
|
106
|
+
[id, type, execution_state].compact.join('|')
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'pipely/component'
|
3
|
+
|
4
|
+
module Pipely
|
5
|
+
|
6
|
+
# Pipely's representation of a Pipeline Definition for AWS Data Pipeline
|
7
|
+
# http://amzn.to/1bpW8Ru
|
8
|
+
#
|
9
|
+
class Definition
|
10
|
+
|
11
|
+
# Showing all component types leads to an unwieldy graph.
|
12
|
+
# TODO: make this list configurable.
|
13
|
+
NON_GRAPH_COMPONENT_TYPES = [
|
14
|
+
'Schedule',
|
15
|
+
'SnsAlarm',
|
16
|
+
'Ec2Resource',
|
17
|
+
'EmrCluster',
|
18
|
+
'CSV',
|
19
|
+
nil,
|
20
|
+
]
|
21
|
+
|
22
|
+
def self.parse(content)
|
23
|
+
objects = JSON.parse(content)['objects']
|
24
|
+
components = objects.map{|obj| Component.new(obj)}
|
25
|
+
|
26
|
+
new(components)
|
27
|
+
end
|
28
|
+
|
29
|
+
def initialize(components)
|
30
|
+
@components = components
|
31
|
+
end
|
32
|
+
|
33
|
+
attr_reader :components
|
34
|
+
|
35
|
+
def components_for_graph
|
36
|
+
components.reject { |component|
|
37
|
+
NON_GRAPH_COMPONENT_TYPES.include?(component['type'])
|
38
|
+
}
|
39
|
+
end
|
40
|
+
|
41
|
+
def to_json
|
42
|
+
{ :objects => components }.to_json
|
43
|
+
end
|
44
|
+
|
45
|
+
def apply_component_attributes(component_attributes)
|
46
|
+
self.components.each do |component|
|
47
|
+
if attributes = component_attributes[component.id]
|
48
|
+
component.attributes = attributes
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
def get_components(target_component_ids)
|
56
|
+
components.select { |component|
|
57
|
+
target_component_ids.include?(component.id)
|
58
|
+
}
|
59
|
+
end
|
60
|
+
|
61
|
+
def dependencies_of(selected_components)
|
62
|
+
all_dependencies = selected_components.map { |component|
|
63
|
+
component.dependencies(:all)
|
64
|
+
}.flatten.uniq
|
65
|
+
|
66
|
+
Set.new(get_components(all_dependencies.map(&:target_id)))
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'graphviz'
|
3
|
+
|
4
|
+
module Pipely
|
5
|
+
|
6
|
+
# Builds a GraphViz graph from a set of Components and their Dependencies
|
7
|
+
class GraphBuilder
|
8
|
+
|
9
|
+
def initialize(graph=nil)
|
10
|
+
@graph = graph || GraphViz.new(:G, :type => :digraph)
|
11
|
+
end
|
12
|
+
|
13
|
+
def build(components)
|
14
|
+
add_nodes(components)
|
15
|
+
add_edges(components)
|
16
|
+
@graph
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
# Represent Components as nodes on the graph
|
22
|
+
def add_nodes(components)
|
23
|
+
components.each do |component|
|
24
|
+
@graph.add_nodes(component.id, component.graphviz_options)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# Represent Dependencies as edges on the graph
|
29
|
+
def add_edges(components)
|
30
|
+
components.each do |component|
|
31
|
+
component.dependencies.each do |dependency|
|
32
|
+
options = {
|
33
|
+
:label => dependency.label,
|
34
|
+
:color => dependency.color,
|
35
|
+
}
|
36
|
+
|
37
|
+
options[:dir] = 'back' if ('input' == dependency.label)
|
38
|
+
|
39
|
+
@graph.add_edges(
|
40
|
+
component.id,
|
41
|
+
dependency.target_id,
|
42
|
+
options
|
43
|
+
)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'pipely/dependency'
|
2
|
+
|
3
|
+
module Pipely
|
4
|
+
|
5
|
+
# A list of references to Components for managing dependencies
|
6
|
+
#
|
7
|
+
class ReferenceList
|
8
|
+
|
9
|
+
def initialize(input)
|
10
|
+
@raw_references = [input].flatten.compact
|
11
|
+
end
|
12
|
+
|
13
|
+
def build_dependencies(label)
|
14
|
+
@raw_references.map{|h| Dependency.new(label, h['ref'])}
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_json(options={})
|
18
|
+
if 1 == @raw_references.count
|
19
|
+
@raw_references.first.to_json(options)
|
20
|
+
else
|
21
|
+
@raw_references.to_json(options)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def present?
|
26
|
+
!@raw_references.empty?
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'pipely/component'
|
2
|
+
require 'pipely/dependency'
|
3
|
+
|
4
|
+
describe Pipely::Component do
|
5
|
+
|
6
|
+
subject {
|
7
|
+
described_class.new(
|
8
|
+
id: 'my-component',
|
9
|
+
type: 'OreoSalad',
|
10
|
+
dependsOn: {'ref' => 'asdf'},
|
11
|
+
input: {'ref' => 'infile'},
|
12
|
+
output: {'ref' => 'outfile'},
|
13
|
+
color: 'yellow',
|
14
|
+
execution_state: 'WAITING_FOR_RUNNER',
|
15
|
+
)
|
16
|
+
}
|
17
|
+
|
18
|
+
it 'coerces dependsOn into a ReferenceList' do
|
19
|
+
expect(subject.dependsOn).to be_a(Pipely::ReferenceList)
|
20
|
+
end
|
21
|
+
|
22
|
+
describe '#graphviz_options' do
|
23
|
+
it 'builds properties for graphviz node representing this component' do
|
24
|
+
expect(subject.graphviz_options).to eq({
|
25
|
+
:shape => 'record',
|
26
|
+
:label => '{my-component|OreoSalad|WAITING_FOR_RUNNER}',
|
27
|
+
:color => 'yellow',
|
28
|
+
:fillcolor => 'bisque4',
|
29
|
+
:style => 'filled',
|
30
|
+
})
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe '#dependencies' do
|
35
|
+
it 'includes dependsOn edges' do
|
36
|
+
expect(subject.dependencies).to eq([
|
37
|
+
Pipely::Dependency.new('dependsOn', 'asdf'),
|
38
|
+
Pipely::Dependency.new('input', 'infile'),
|
39
|
+
Pipely::Dependency.new('output', 'outfile'),
|
40
|
+
])
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'pipely/definition'
|
2
|
+
|
3
|
+
describe Pipely::Definition do
|
4
|
+
|
5
|
+
subject { described_class.parse(definition_json) }
|
6
|
+
|
7
|
+
let(:definition_json) {
|
8
|
+
<<EOF
|
9
|
+
{
|
10
|
+
"objects": [
|
11
|
+
{
|
12
|
+
"id": "DoStuff",
|
13
|
+
"type": "ShellCommandActivity",
|
14
|
+
"onFail": { "ref": "FailureNotify" }
|
15
|
+
},
|
16
|
+
{
|
17
|
+
"id": "FailureNotify",
|
18
|
+
"type": "SnsAlarm"
|
19
|
+
}
|
20
|
+
]
|
21
|
+
}
|
22
|
+
EOF
|
23
|
+
}
|
24
|
+
|
25
|
+
describe '#components' do
|
26
|
+
it 'builds a Component for each object in the definition JSON' do
|
27
|
+
expect(subject.components.count).to eq(2)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe '#components_for_graph' do
|
32
|
+
it 'filters out node types we do not want on the graph' do
|
33
|
+
expect(subject.components_for_graph.count).to eq(1)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe '#to_json' do
|
38
|
+
it 'renders the components as JSON' do
|
39
|
+
original = JSON.parse(definition_json)
|
40
|
+
expect(JSON.parse(subject.to_json)).to eq(original)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe '#apply_component_attributes' do
|
45
|
+
it 'applies attributes to nodes with matching ids' do
|
46
|
+
subject.apply_component_attributes({
|
47
|
+
'DoStuff' => { color: 'pink' },
|
48
|
+
})
|
49
|
+
|
50
|
+
pink_node = subject.components.detect{|n| n.id == 'DoStuff'}
|
51
|
+
|
52
|
+
expect(pink_node.color).to eq('pink')
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'pipely/graph_builder'
|
2
|
+
|
3
|
+
describe Pipely::GraphBuilder do
|
4
|
+
|
5
|
+
let(:graph) { stub(:graph) }
|
6
|
+
|
7
|
+
let(:node1) {
|
8
|
+
Pipely::Component.new(
|
9
|
+
:id => '1',
|
10
|
+
:dependsOn => { 'ref' => '2' },
|
11
|
+
)
|
12
|
+
}
|
13
|
+
|
14
|
+
let(:node2) {
|
15
|
+
Pipely::Component.new(
|
16
|
+
:id => '2',
|
17
|
+
)
|
18
|
+
}
|
19
|
+
|
20
|
+
subject { described_class.new(graph) }
|
21
|
+
|
22
|
+
describe '#build' do
|
23
|
+
it 'builds a graph from a list of Components' do
|
24
|
+
graph.should_receive(:add_nodes).
|
25
|
+
with(node1.id, node1.graphviz_options).ordered
|
26
|
+
|
27
|
+
graph.should_receive(:add_nodes).
|
28
|
+
with(node2.id, node2.graphviz_options).ordered
|
29
|
+
|
30
|
+
graph.should_receive(:add_edges).
|
31
|
+
with(
|
32
|
+
node1.id,
|
33
|
+
node2.id,
|
34
|
+
:label => 'dependsOn',
|
35
|
+
:color => 'black',
|
36
|
+
).ordered
|
37
|
+
|
38
|
+
subject.build([node1, node2])
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'pipely/reference_list'
|
2
|
+
|
3
|
+
describe Pipely::ReferenceList do
|
4
|
+
|
5
|
+
context 'given nil input' do
|
6
|
+
subject { described_class.new(nil) }
|
7
|
+
|
8
|
+
describe '#build_dependencies' do
|
9
|
+
it 'returns an empty array' do
|
10
|
+
expect(subject.build_dependencies('dependsOn')).to eq([])
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
context 'given a single input' do
|
16
|
+
subject { described_class.new({ 'ref' => 'foo' }) }
|
17
|
+
|
18
|
+
describe '#build_dependencies' do
|
19
|
+
it 'returns an array of the single reference' do
|
20
|
+
expect(subject.build_dependencies('dependsOn')).to eq([
|
21
|
+
Pipely::Dependency.new('dependsOn', 'foo'),
|
22
|
+
])
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context 'given an array of references as input' do
|
28
|
+
subject {
|
29
|
+
described_class.new([
|
30
|
+
{ 'ref' => 'foo' },
|
31
|
+
{ 'ref' => 'bar' },
|
32
|
+
])
|
33
|
+
}
|
34
|
+
|
35
|
+
describe '#build_dependencies' do
|
36
|
+
it 'returns an array of the single reference' do
|
37
|
+
expect(subject.build_dependencies('dependsOn')).to eq([
|
38
|
+
Pipely::Dependency.new('dependsOn', 'foo'),
|
39
|
+
Pipely::Dependency.new('dependsOn', 'bar'),
|
40
|
+
])
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'pipely'
|
2
|
+
|
3
|
+
describe Pipely do
|
4
|
+
let(:definition_json) { stub }
|
5
|
+
let(:filename) { stub }
|
6
|
+
let(:definition) { stub }
|
7
|
+
|
8
|
+
before do
|
9
|
+
Pipely::Definition.stub(:parse).with(definition_json) { definition }
|
10
|
+
end
|
11
|
+
|
12
|
+
describe '.draw' do
|
13
|
+
let(:components) { stub }
|
14
|
+
let(:definition) { stub(:definition, :components_for_graph => components) }
|
15
|
+
let(:graph) { stub(:graph, :output => nil) }
|
16
|
+
|
17
|
+
before do
|
18
|
+
Pipely::GraphBuilder.any_instance.stub(:build).with(components) { graph }
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'parses a JSON definition and builds a graph' do
|
22
|
+
graph.should_receive(:output).with(:png => filename)
|
23
|
+
|
24
|
+
described_class.draw(definition_json, filename)
|
25
|
+
end
|
26
|
+
|
27
|
+
context 'with node_attributes' do
|
28
|
+
let(:node_attributes) { stub }
|
29
|
+
|
30
|
+
it 'applies the node_attributes to the definition' do
|
31
|
+
definition.should_receive(:apply_node_attributes).with(node_attributes)
|
32
|
+
|
33
|
+
described_class.draw(definition_json, filename, node_attributes)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
metadata
ADDED
@@ -0,0 +1,125 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: pipely
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Matt Gillooly
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-10-02 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: ruby-graphviz
|
16
|
+
requirement: &70104078435520 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70104078435520
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: rake
|
27
|
+
requirement: &70104078435100 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *70104078435100
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: virtus
|
38
|
+
requirement: &70104078434680 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
44
|
+
type: :runtime
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *70104078434680
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: rspec
|
49
|
+
requirement: &70104078434260 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *70104078434260
|
58
|
+
- !ruby/object:Gem::Dependency
|
59
|
+
name: cane
|
60
|
+
requirement: &70104078433840 !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ! '>='
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0'
|
66
|
+
type: :development
|
67
|
+
prerelease: false
|
68
|
+
version_requirements: *70104078433840
|
69
|
+
description:
|
70
|
+
email:
|
71
|
+
- matt@swipely.com
|
72
|
+
executables:
|
73
|
+
- pipely
|
74
|
+
extensions: []
|
75
|
+
extra_rdoc_files: []
|
76
|
+
files:
|
77
|
+
- lib/pipely/component.rb
|
78
|
+
- lib/pipely/definition.rb
|
79
|
+
- lib/pipely/dependency.rb
|
80
|
+
- lib/pipely/graph_builder.rb
|
81
|
+
- lib/pipely/reference_list.rb
|
82
|
+
- lib/pipely/version.rb
|
83
|
+
- lib/pipely.rb
|
84
|
+
- Rakefile
|
85
|
+
- README.md
|
86
|
+
- spec/lib/pipely/component_spec.rb
|
87
|
+
- spec/lib/pipely/definition_spec.rb
|
88
|
+
- spec/lib/pipely/dependency_spec.rb
|
89
|
+
- spec/lib/pipely/graph_builder_spec.rb
|
90
|
+
- spec/lib/pipely/reference_list_spec.rb
|
91
|
+
- spec/lib/pipely_spec.rb
|
92
|
+
- !binary |-
|
93
|
+
YmluL3BpcGVseQ==
|
94
|
+
homepage: http://github.com/swipely/pipely
|
95
|
+
licenses: []
|
96
|
+
post_install_message:
|
97
|
+
rdoc_options: []
|
98
|
+
require_paths:
|
99
|
+
- lib
|
100
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
101
|
+
none: false
|
102
|
+
requirements:
|
103
|
+
- - ! '>='
|
104
|
+
- !ruby/object:Gem::Version
|
105
|
+
version: '0'
|
106
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
107
|
+
none: false
|
108
|
+
requirements:
|
109
|
+
- - ! '>='
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: '0'
|
112
|
+
requirements: []
|
113
|
+
rubyforge_project:
|
114
|
+
rubygems_version: 1.8.11
|
115
|
+
signing_key:
|
116
|
+
specification_version: 3
|
117
|
+
summary: Generate dependency graphs from pipeline definitions.
|
118
|
+
test_files:
|
119
|
+
- spec/lib/pipely/component_spec.rb
|
120
|
+
- spec/lib/pipely/definition_spec.rb
|
121
|
+
- spec/lib/pipely/dependency_spec.rb
|
122
|
+
- spec/lib/pipely/graph_builder_spec.rb
|
123
|
+
- spec/lib/pipely/reference_list_spec.rb
|
124
|
+
- spec/lib/pipely_spec.rb
|
125
|
+
has_rdoc:
|