deadly_serious 0.10.0 → 0.11.0
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/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/deadly_serious.gemspec +1 -1
- data/lib/deadly_serious/engine/commands.rb +113 -0
- data/lib/deadly_serious/engine/spawner.rb +30 -32
- data/lib/deadly_serious/version.rb +1 -1
- data/lib/deadly_serious.rb +1 -0
- metadata +16 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 05f3250fb16090279dad66ecabbab4990e170873
|
4
|
+
data.tar.gz: 5bb83f5cb6f050f7f2e008242434e4f556964e09
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 03bda6d7a58b0c890dbe1b98ace3b8b338ff788725cbd02289797912bb7cc5507ea5331bf447cce4614b9ff058b046b228ad8cd2ce28e3a76b68adb8fad22ca8
|
7
|
+
data.tar.gz: 170776a0f3d4f8fc593b24513027e0341d950590e67ceb945502f7467fa0be6e16f3174c29193225eca82436d5df3f148824f05214c3e60eec3bbbd9f4adc615
|
data/.ruby-gemset
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
deadly_serious
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
ruby-2.1
|
data/deadly_serious.gemspec
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
# coding: utf-8
|
2
1
|
lib = File.expand_path('../lib', __FILE__)
|
3
2
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
3
|
require 'deadly_serious/version'
|
@@ -18,6 +17,7 @@ Gem::Specification.new do |spec|
|
|
18
17
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
18
|
spec.require_paths = ['lib']
|
20
19
|
|
20
|
+
spec.required_ruby_version = '~> 2.1'
|
21
21
|
spec.add_development_dependency 'bundler', '~> 1.3'
|
22
22
|
spec.add_development_dependency 'rake'
|
23
23
|
|
@@ -0,0 +1,113 @@
|
|
1
|
+
module DeadlySerious
|
2
|
+
module Engine
|
3
|
+
# Commands make work with Pipelines easier.
|
4
|
+
module Commands
|
5
|
+
|
6
|
+
private def auto_pipe
|
7
|
+
@auto_pipe ||= AutoPipe.new
|
8
|
+
end
|
9
|
+
|
10
|
+
def on_subnet(&block)
|
11
|
+
auto_pipe.on_subnet &block
|
12
|
+
end
|
13
|
+
|
14
|
+
def next_pipe
|
15
|
+
auto_pipe.next
|
16
|
+
end
|
17
|
+
|
18
|
+
def last_pipe
|
19
|
+
auto_pipe.last
|
20
|
+
end
|
21
|
+
|
22
|
+
# Read a file from "data" dir and pipe it to
|
23
|
+
# the next component.
|
24
|
+
def from_file(file_name, writer: next_pipe)
|
25
|
+
file = file_name.sub(/^>?(.*)$/, '>\1')
|
26
|
+
spawn_command(%{cat ((#{file})) > ((#{writer}))})
|
27
|
+
end
|
28
|
+
|
29
|
+
# Write a file to "data" dir from the pipe
|
30
|
+
# of the last component
|
31
|
+
def to_file(file_name, reader: last_pipe)
|
32
|
+
file = file_name.sub(/^>?(.*)$/, '>\1')
|
33
|
+
spawn_command(%{cat ((#{reader})) > ((#{file}))})
|
34
|
+
end
|
35
|
+
|
36
|
+
# Read from a specific named pipe.
|
37
|
+
#
|
38
|
+
# This is useful after a {#spawn_tee}, sometimes.
|
39
|
+
def from_pipe(pipe_name, writer: next_pipe)
|
40
|
+
pipe = pipe_name.sub(/^>?/, '')
|
41
|
+
spawn_command(%{cat ((#{pipe})) > ((#{writer}))})
|
42
|
+
end
|
43
|
+
|
44
|
+
# Write the output of the last component to
|
45
|
+
# a specific named pipe.
|
46
|
+
#
|
47
|
+
# Unless you are connecting different pipelines,
|
48
|
+
# avoid using this or check if you don't need
|
49
|
+
# {#spawn_tee} instead.
|
50
|
+
def to_pipe(pipe_name, reader: last_pipe)
|
51
|
+
pipe = pipe_name.sub(/^>?/, '')
|
52
|
+
spawn_command(%{cat ((#{reader})) > ((#{pipe}))})
|
53
|
+
end
|
54
|
+
|
55
|
+
# Spawn a class connected to the last and next components
|
56
|
+
def spawn_class(a_class, *args, reader: last_pipe, writer: next_pipe)
|
57
|
+
spawn_process(a_class, *args, readers: [reader], writers: [writer])
|
58
|
+
end
|
59
|
+
|
60
|
+
# Spawn {number_of_processes} classes, one process for each of them.
|
61
|
+
# Also, it divides the previous pipe in {number_of_processes} pipes,
|
62
|
+
# an routes data through them.
|
63
|
+
def spawn_class_parallel(number_of_processes, class_name, *args, reader: last_pipe, writer: next_pipe)
|
64
|
+
connect_a = (1..number_of_processes).map { |i| sprintf('%s.%da.splitter', class_name.to_s.downcase.gsub(/\W+/, '_'), i) }
|
65
|
+
connect_b = (1..number_of_processes).map { |i| sprintf('%s.%db.splitter', class_name.to_s.downcase.gsub(/\W+/, '_'), i) }
|
66
|
+
spawn_process(DeadlySerious::Processes::Splitter, readers: [reader], writers: connect_a)
|
67
|
+
connect_a.zip(connect_b).each do |a, b|
|
68
|
+
spawn_class(class_name, *args, reader: a, writer: b)
|
69
|
+
end
|
70
|
+
spawn_process(DeadlySerious::Processes::Joiner, readers: connect_b, writers: [writer])
|
71
|
+
end
|
72
|
+
|
73
|
+
# Pipe from the last component to a intermediate
|
74
|
+
# file (or pipe) while continue the process.
|
75
|
+
#
|
76
|
+
# If a block is provided, it pipes from the last
|
77
|
+
# component INTO the block, while it pipes to the
|
78
|
+
# next component OUT of the block.
|
79
|
+
def spawn_tee(escape = nil, reader: nil, writer: nil, &block)
|
80
|
+
# Lots of contours to make #last_pipe and and #next_pipe
|
81
|
+
# to work correctly.
|
82
|
+
reader ||= last_pipe
|
83
|
+
escape ||= next_pipe
|
84
|
+
writer ||= next_pipe
|
85
|
+
|
86
|
+
# TODO Validates if an "escape" or a block was provided
|
87
|
+
spawn_command(%{cat ((#{reader})) | tee ((#{escape})) > ((#{writer}))})
|
88
|
+
|
89
|
+
return unless block_given?
|
90
|
+
on_subnet do
|
91
|
+
spawn_command(%{cat ((#{escape})) > ((#{next_pipe}))})
|
92
|
+
block.call
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
# Sometimes we need all previous process to end before
|
97
|
+
# starting new processes. The capacitor command does
|
98
|
+
# exactly that.
|
99
|
+
def spawn_capacitor(charger_file = nil, reader: last_pipe, writer: next_pipe)
|
100
|
+
if charger_file.nil?
|
101
|
+
charger_file = ">#{last_pipe}"
|
102
|
+
temp_charger = true
|
103
|
+
end
|
104
|
+
fail "#{charger_file} must be a file" unless charger_file.start_with?('>')
|
105
|
+
if temp_charger
|
106
|
+
spawn_command("cat ((#{reader})) > ((#{charger_file})); cat ((#{charger_file})) > ((#{writer})); rm ((#{charger_file}))")
|
107
|
+
else
|
108
|
+
spawn_command("cat ((#{reader})) > ((#{charger_file})); cat ((#{charger_file})) > ((#{writer}))")
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -6,6 +6,8 @@ require 'deadly_serious/processes/splitter'
|
|
6
6
|
module DeadlySerious
|
7
7
|
module Engine
|
8
8
|
class Spawner
|
9
|
+
include DeadlySerious::Engine::Commands
|
10
|
+
|
9
11
|
attr_reader :data_dir, :pipe_dir
|
10
12
|
|
11
13
|
def initialize(data_dir: './data',
|
@@ -14,22 +16,9 @@ module DeadlySerious
|
|
14
16
|
@data_dir = data_dir
|
15
17
|
@pipe_dir = pipe_dir
|
16
18
|
@ids = []
|
17
|
-
@auto_pipe = AutoPipe.new
|
18
19
|
Channel.config(data_dir, pipe_dir, preserve_pipe_dir)
|
19
20
|
end
|
20
21
|
|
21
|
-
def on_subnet(&block)
|
22
|
-
@auto_pipe.on_subnet &block
|
23
|
-
end
|
24
|
-
|
25
|
-
def next_pipe
|
26
|
-
@auto_pipe.next
|
27
|
-
end
|
28
|
-
|
29
|
-
def last_pipe
|
30
|
-
@auto_pipe.last
|
31
|
-
end
|
32
|
-
|
33
22
|
def run
|
34
23
|
Channel.setup
|
35
24
|
run_pipeline
|
@@ -41,10 +30,21 @@ module DeadlySerious
|
|
41
30
|
Channel.teardown
|
42
31
|
end
|
43
32
|
|
33
|
+
# Wait all sub processes to finish before
|
34
|
+
# continue the pipeline.
|
35
|
+
#
|
36
|
+
# Always prefer to use {DeadlySerious::Engine::Commands#spawn_capacitor}
|
37
|
+
# if possible.
|
44
38
|
def wait_processes!
|
45
39
|
wait_children
|
46
40
|
end
|
47
41
|
|
42
|
+
# Spawn a class in a separated process.
|
43
|
+
#
|
44
|
+
# This is a basic command, use it only if you have
|
45
|
+
# more than one input or output pipe. Otherwise
|
46
|
+
# prefer the simplier {DeadlySerious::Engine::Commands#spawn_class}
|
47
|
+
# method.
|
48
48
|
def spawn_process(a_class, *args, process_name: a_class.name, readers: [], writers: [])
|
49
49
|
writers.each { |writer| create_pipe(writer) }
|
50
50
|
fork_it do
|
@@ -61,6 +61,16 @@ module DeadlySerious
|
|
61
61
|
end
|
62
62
|
end
|
63
63
|
|
64
|
+
def spawn_command(a_shell_command)
|
65
|
+
command = a_shell_command.dup
|
66
|
+
a_shell_command.scan(/\(\((.*?)\)\)/) do |(pipe_name)|
|
67
|
+
pipe_path = create_pipe(pipe_name)
|
68
|
+
command.gsub!("((#{pipe_name}))", "'#{pipe_path.gsub("'", "\\'")}'")
|
69
|
+
end
|
70
|
+
@ids << spawn(command)
|
71
|
+
end
|
72
|
+
|
73
|
+
# @deprecated (Use [Spawner#spawn_process] with [Splitter] instead)
|
64
74
|
def spawn_processes(a_class, *args, process_name: a_class.name, reader_pattern: nil, writers: [])
|
65
75
|
number = last_number(reader_pattern)
|
66
76
|
|
@@ -76,10 +86,12 @@ module DeadlySerious
|
|
76
86
|
end
|
77
87
|
end
|
78
88
|
|
89
|
+
# @deprecated (Use [Spawner#spawn_process] instead)
|
79
90
|
def spawn_source(a_class, *args, writer: a_class.dasherize(a_class.name))
|
80
91
|
spawn_process(a_class, *args, process_name: process_name, readers: [], writers: [writer])
|
81
92
|
end
|
82
93
|
|
94
|
+
# @deprecated (Use [Spawner#spawn_process] instead)
|
83
95
|
def spawn_splitter(process_name: 'Splitter', reader: nil, writer: '>output01.txt', number: 2)
|
84
96
|
start = last_number(writer)
|
85
97
|
finish = start + number - 1
|
@@ -92,6 +104,7 @@ module DeadlySerious
|
|
92
104
|
writers: writers)
|
93
105
|
end
|
94
106
|
|
107
|
+
# @deprecated (Use [Spawner#spawn_process] with [Splitter] instead)
|
95
108
|
def spawn_socket_splitter(process_name: 'SocketSplitter', reader: nil, port: 11000, number: 2)
|
96
109
|
spawn_splitter(process_name: process_name,
|
97
110
|
reader: reader,
|
@@ -99,15 +112,6 @@ module DeadlySerious
|
|
99
112
|
number: number)
|
100
113
|
end
|
101
114
|
|
102
|
-
def spawn_command(a_shell_command)
|
103
|
-
command = a_shell_command.dup
|
104
|
-
a_shell_command.scan(/\(\((.*?)\)\)/) do |(pipe_name)|
|
105
|
-
pipe_path = create_pipe(pipe_name)
|
106
|
-
command.gsub!("((#{pipe_name}))", "'#{pipe_path.gsub("'", "\\'")}'")
|
107
|
-
end
|
108
|
-
@ids << spawn(command)
|
109
|
-
end
|
110
|
-
|
111
115
|
private
|
112
116
|
|
113
117
|
def append_open_io_if_needed(a_class)
|
@@ -118,8 +122,6 @@ module DeadlySerious
|
|
118
122
|
Channel.create_pipe(pipe_name)
|
119
123
|
end
|
120
124
|
|
121
|
-
# @!group Process Control
|
122
|
-
|
123
125
|
def fork_it
|
124
126
|
@ids << fork { yield }
|
125
127
|
end
|
@@ -138,13 +140,11 @@ module DeadlySerious
|
|
138
140
|
$0 = "ruby #{self.class.dasherize(name)} <(#{readers.join(' ')}) >(#{writers.join(' ')})"
|
139
141
|
end
|
140
142
|
|
141
|
-
# @!endgroup
|
142
|
-
# @!group Minor Helpers
|
143
|
-
|
144
143
|
def self.dasherize(a_string)
|
145
144
|
a_string.gsub(/(.)([A-Z])/, '\1-\2').downcase.gsub(/\W+/, '-')
|
146
145
|
end
|
147
146
|
|
147
|
+
# @deprecated
|
148
148
|
def last_number_pattern(a_string)
|
149
149
|
last_number_pattern = /(\d+)[^\d]*$/.match(a_string)
|
150
150
|
raise %(Writer name "#{writer}" should have a number) if last_number_pattern.nil?
|
@@ -152,10 +152,12 @@ module DeadlySerious
|
|
152
152
|
last_number_pattern[1]
|
153
153
|
end
|
154
154
|
|
155
|
+
# @deprecated
|
155
156
|
def last_number(a_string)
|
156
157
|
last_number_pattern(a_string).to_i
|
157
158
|
end
|
158
159
|
|
160
|
+
# @deprecated
|
159
161
|
def pattern_replace(a_string, number)
|
160
162
|
pattern = last_number_pattern(a_string)
|
161
163
|
pattern_length = pattern.size
|
@@ -166,8 +168,4 @@ module DeadlySerious
|
|
166
168
|
end
|
167
169
|
end
|
168
170
|
end
|
169
|
-
end
|
170
|
-
|
171
|
-
if __FILE__ == $0
|
172
|
-
DeadlySerious::Engine::Spawner.new.run
|
173
|
-
end
|
171
|
+
end
|
data/lib/deadly_serious.rb
CHANGED
metadata
CHANGED
@@ -1,55 +1,55 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: deadly_serious
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.11.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ronie Uliana
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-07-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - ~>
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '1.3'
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - ~>
|
24
|
+
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '1.3'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rake
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- -
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '0'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- -
|
38
|
+
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: json
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- -
|
45
|
+
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: '0'
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- -
|
52
|
+
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
55
|
description: Flow Based Programming Engine mechanically sympathetic to *nix.
|
@@ -59,7 +59,9 @@ executables: []
|
|
59
59
|
extensions: []
|
60
60
|
extra_rdoc_files: []
|
61
61
|
files:
|
62
|
-
- .gitignore
|
62
|
+
- ".gitignore"
|
63
|
+
- ".ruby-gemset"
|
64
|
+
- ".ruby-version"
|
63
65
|
- Gemfile
|
64
66
|
- LICENSE.txt
|
65
67
|
- README.md
|
@@ -69,6 +71,7 @@ files:
|
|
69
71
|
- lib/deadly_serious/engine/auto_pipe.rb
|
70
72
|
- lib/deadly_serious/engine/base_process.rb
|
71
73
|
- lib/deadly_serious/engine/channel.rb
|
74
|
+
- lib/deadly_serious/engine/commands.rb
|
72
75
|
- lib/deadly_serious/engine/json_io.rb
|
73
76
|
- lib/deadly_serious/engine/json_process.rb
|
74
77
|
- lib/deadly_serious/engine/lazy_io.rb
|
@@ -93,17 +96,17 @@ require_paths:
|
|
93
96
|
- lib
|
94
97
|
required_ruby_version: !ruby/object:Gem::Requirement
|
95
98
|
requirements:
|
96
|
-
- -
|
99
|
+
- - "~>"
|
97
100
|
- !ruby/object:Gem::Version
|
98
|
-
version: '
|
101
|
+
version: '2.1'
|
99
102
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
100
103
|
requirements:
|
101
|
-
- -
|
104
|
+
- - ">="
|
102
105
|
- !ruby/object:Gem::Version
|
103
106
|
version: '0'
|
104
107
|
requirements: []
|
105
108
|
rubyforge_project:
|
106
|
-
rubygems_version: 2.
|
109
|
+
rubygems_version: 2.2.2
|
107
110
|
signing_key:
|
108
111
|
specification_version: 4
|
109
112
|
summary: Flow Based Programming engine that relies on named pipes and Linux processes
|