rflow 1.0.1 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.ruby-version +1 -1
- data/.travis.yml +3 -0
- data/Gemfile +2 -1
- data/Guardfile +1 -1
- data/README.md +9 -9
- data/Vagrantfile +9 -9
- data/bin/rflow +9 -9
- data/example/http_extensions.rb +7 -7
- data/lib/rflow.rb +24 -3
- data/lib/rflow/child_process.rb +2 -0
- data/lib/rflow/component.rb +2 -2
- data/lib/rflow/component/port.rb +51 -26
- data/lib/rflow/configuration.rb +4 -4
- data/lib/rflow/configuration/ruby_dsl.rb +4 -4
- data/lib/rflow/connection.rb +4 -4
- data/lib/rflow/connections/zmq_connection.rb +5 -7
- data/lib/rflow/daemon_process.rb +12 -2
- data/lib/rflow/logger.rb +1 -1
- data/lib/rflow/master.rb +2 -20
- data/lib/rflow/message.rb +28 -18
- data/lib/rflow/pid_file.rb +17 -5
- data/lib/rflow/shard.rb +6 -6
- data/lib/rflow/version.rb +1 -1
- data/rflow.gemspec +20 -20
- data/schema/message.avsc +6 -1
- data/spec/rflow/component/port_spec.rb +17 -17
- data/spec/rflow/components/clock_spec.rb +1 -1
- data/spec/rflow/configuration/ruby_dsl_spec.rb +47 -47
- data/spec/rflow/configuration_spec.rb +8 -8
- data/spec/rflow/forward_to_input_port_spec.rb +38 -9
- data/spec/rflow/forward_to_output_port_spec.rb +5 -4
- data/spec/rflow/logger_spec.rb +5 -5
- data/spec/rflow/message/data/raw_spec.rb +2 -2
- data/spec/rflow/message/data_spec.rb +8 -8
- data/spec/rflow/message_spec.rb +63 -29
- data/spec/rflow_spec.rb +18 -18
- metadata +14 -13
- data/NOTES +0 -187
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 325fd6dd2c2d5409dc692a641c36da3b2139f7e8
|
4
|
+
data.tar.gz: d71bb8ce7e17c7e86fc1e2de7f299e73efdaeb5a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e5a602dc11534aa9a48b81bfc5d2035103b048b67d96684587f84c03152f90b415a43f6e19050616cbdccd37cfbad3ddf67e5c45ecfb4690c2dd40cfaa1b5883
|
7
|
+
data.tar.gz: e7d78c206614c6df0824b4d87f50a1c48edb54468defc498f5fa2319b05c707a4a4ee440514a8a11058998202b76ab93885859a8a50b1dbe85bc33bc82a5c041
|
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
ruby-2.
|
1
|
+
ruby-2.3.0
|
data/.travis.yml
CHANGED
@@ -4,6 +4,8 @@ rvm:
|
|
4
4
|
- 1.9.3
|
5
5
|
- 2.0.0
|
6
6
|
- 2.1.0
|
7
|
+
- 2.2.0
|
8
|
+
- 2.3.0
|
7
9
|
|
8
10
|
before_install:
|
9
11
|
- sudo apt-get install libtool autoconf automake uuid-dev build-essential
|
@@ -12,6 +14,7 @@ before_install:
|
|
12
14
|
# - sudo add-apt-repository -y ppa:chris-lea/zeromq
|
13
15
|
# - sudo apt-get update
|
14
16
|
# - sudo apt-get install libzmq3 libzmq3-dev
|
17
|
+
- gem update bundler
|
15
18
|
|
16
19
|
script: bundle exec rspec spec
|
17
20
|
|
data/Gemfile
CHANGED
data/Guardfile
CHANGED
data/README.md
CHANGED
@@ -13,7 +13,7 @@ RFlow is a Ruby framework inspired by
|
|
13
13
|
|
14
14
|
In short, components communicate with each other by sending/receiving
|
15
15
|
messages via their output/input ports over connections. Ports are
|
16
|
-
|
16
|
+
'wired' together output->input with connections, and messages are
|
17
17
|
explicitly serialized before being sent over the connection. RFlow
|
18
18
|
supports generalized connection types and message serialization,
|
19
19
|
however only two are in current use, namely ZeroMQ connections and
|
@@ -58,7 +58,7 @@ work. (You will probably get errors saying arcane things like
|
|
58
58
|
|
59
59
|
* __Port__ - a named entity on each component that is responsible for
|
60
60
|
receiving data (and input port) or sending data (and output port).
|
61
|
-
Ports can be
|
61
|
+
Ports can be 'keyed' or 'indexed' to allow better multiplexing of
|
62
62
|
messages out/in a single port, as well as allow a single port to be
|
63
63
|
accessed by an array.
|
64
64
|
|
@@ -70,7 +70,7 @@ work. (You will probably get errors saying arcane things like
|
|
70
70
|
* __Message__ - a bit of serialized data that is sent out an output
|
71
71
|
port and received on an input port. Due to the serialization,
|
72
72
|
message types and schemas are explicitly defined. In a departure
|
73
|
-
from
|
73
|
+
from 'pure' FBP, RFlow supports sending multiple message types via a
|
74
74
|
single connection.
|
75
75
|
|
76
76
|
* __Workflow__ - the common name for the digraph created when the
|
@@ -126,7 +126,7 @@ end
|
|
126
126
|
component to clean up any external resources that it might have
|
127
127
|
outstanding, such as file handles or network sockets.
|
128
128
|
|
129
|
-
|
129
|
+
'Source' components will often do all of their work within the `run!`
|
130
130
|
method, and often gather message data from an external source, such as
|
131
131
|
file, database, or network socket. The following component generates a
|
132
132
|
set of integers between a configured start/finish, incrementing by a
|
@@ -158,7 +158,7 @@ class RFlow::Components::GenerateIntegerSequence < RFlow::Component
|
|
158
158
|
end
|
159
159
|
```
|
160
160
|
|
161
|
-
|
161
|
+
'Middle' components receive messages on input port(s), perform a bit
|
162
162
|
of computation, and then send a message out the output port(s). The
|
163
163
|
following component accepts a Ruby expression string via its config,
|
164
164
|
and then uses that as an expression to determine what port to send an
|
@@ -189,7 +189,7 @@ class RFlow::Components::RubyProcFilter < RFlow::Component
|
|
189
189
|
end
|
190
190
|
```
|
191
191
|
|
192
|
-
|
192
|
+
'Sink' components accept messages on an input port and do not have an
|
193
193
|
output port. They often operate on external sinks, such as writing
|
194
194
|
messages to a file, database, or network socket. The following
|
195
195
|
component writes the inspected message to a file (defined via the
|
@@ -220,10 +220,10 @@ end
|
|
220
220
|
|
221
221
|
RFlow messages are instances of
|
222
222
|
[`RFlow::Message`](lib/rflow/message.rb), which are ultimately
|
223
|
-
serialized via an Avro [schema](schema/message.
|
223
|
+
serialized via an Avro [schema](schema/message.avsc).
|
224
224
|
|
225
|
-
There are two parts of the message
|
226
|
-
embedded data object
|
225
|
+
There are two parts of the message 'envelope': a provenance and the
|
226
|
+
embedded data object 'payload'.
|
227
227
|
|
228
228
|
The `provenance` is a way for a component to annotate a message with a
|
229
229
|
bit of data that should (by convention) be carried through the
|
data/Vagrantfile
CHANGED
@@ -1,16 +1,16 @@
|
|
1
1
|
# -*- mode: ruby -*-
|
2
2
|
# vi: set ft=ruby :
|
3
|
-
VAGRANTFILE_API_VERSION =
|
3
|
+
VAGRANTFILE_API_VERSION = '2'
|
4
4
|
|
5
5
|
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
|
6
6
|
config.vm.define 'centos62' do |c|
|
7
|
-
c.vm.box =
|
7
|
+
c.vm.box = 'jstoneham/rflow-centos62'
|
8
8
|
end
|
9
9
|
config.vm.define 'centos64' do |c|
|
10
|
-
c.vm.box =
|
10
|
+
c.vm.box = 'box-cutter/centos64'
|
11
11
|
end
|
12
12
|
config.vm.define 'centos65' do |c|
|
13
|
-
c.vm.box =
|
13
|
+
c.vm.box = 'chef/centos-6.5'
|
14
14
|
end
|
15
15
|
|
16
16
|
config.vm.synced_folder '.', '/rflow'
|
@@ -21,28 +21,28 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
|
|
21
21
|
config.vm.synced_folder '../rflow-components-http', '/rflow-components-http'
|
22
22
|
|
23
23
|
# forward http for rflow testing
|
24
|
-
config.vm.network
|
24
|
+
config.vm.network 'forwarded_port', guest: 8000, host: 8000
|
25
25
|
|
26
26
|
# install RPM dependencies for rflow and zeromq
|
27
|
-
config.vm.provision
|
27
|
+
config.vm.provision 'shell', privileged: true, inline: <<-EOS
|
28
28
|
curl -O https://dl.fedoraproject.org/pub/epel/6/i386/epel-release-6-8.noarch.rpm
|
29
29
|
rpm -ivh epel-release-6-8.noarch.rpm
|
30
30
|
yum -y install libyaml-devel patch libffi-devel glibc-headers autoconf gcc-c++ glibc-devel readline-devel zlib-devel openssl-devel automake libtool bison git sqlite-devel rpm-build libuuid-devel vim
|
31
31
|
EOS
|
32
32
|
|
33
33
|
# build zeromq as vagrant user
|
34
|
-
config.vm.provision
|
34
|
+
config.vm.provision 'shell', privileged: false, inline: <<-EOS
|
35
35
|
curl -O http://download.zeromq.org/zeromq-3.2.4.tar.gz
|
36
36
|
rpmbuild -tb zeromq-3.2.4.tar.gz
|
37
37
|
EOS
|
38
38
|
|
39
39
|
# install zeromq
|
40
|
-
config.vm.provision
|
40
|
+
config.vm.provision 'shell', privileged: true, inline: <<-EOS
|
41
41
|
rpm -ivh ~vagrant/rpmbuild/RPMS/x86_64/zeromq-*
|
42
42
|
EOS
|
43
43
|
|
44
44
|
# set up RVM and bundler
|
45
|
-
config.vm.provision
|
45
|
+
config.vm.provision 'shell', privileged: false, inline: <<-EOS
|
46
46
|
rm -f .profile
|
47
47
|
curl -sSL https://get.rvm.io | bash -s stable
|
48
48
|
source .rvm/scripts/rvm
|
data/bin/rflow
CHANGED
@@ -16,41 +16,41 @@ option_parser = OptionParser.new do |opts|
|
|
16
16
|
Usage: #{File.basename $0} [options] (start|stop|status|load)
|
17
17
|
EOB
|
18
18
|
|
19
|
-
opts.on(
|
19
|
+
opts.on('-d', '--database DB', 'Config database (sqlite) path (GENERALLY REQUIRED)') do |db|
|
20
20
|
options[:config_database_path] = File.expand_path(db)
|
21
21
|
end
|
22
22
|
|
23
|
-
opts.on(
|
23
|
+
opts.on('-c', '--config CONFIG', 'Config file path (only valid for load)') do |config|
|
24
24
|
options[:config_file_path] = File.expand_path(config)
|
25
25
|
end
|
26
26
|
|
27
|
-
opts.on(
|
27
|
+
opts.on('-e', '--extensions FILE1[,FILE_N]', Array, 'Extension file paths (will load)') do |extensions|
|
28
28
|
options[:extensions_file_paths] += extensions.map {|extension| File.expand_path(extension)}
|
29
29
|
end
|
30
30
|
|
31
|
-
opts.on(
|
31
|
+
opts.on('-g', '--gems GEM1[,GEM_N]', Array, 'Extension gems (will require)') do |gems|
|
32
32
|
options[:gems] += gems
|
33
33
|
end
|
34
34
|
|
35
|
-
opts.on(
|
35
|
+
opts.on('-l', '--log LOGFILE', 'Initial startup log file (in addition to stdout)') do |log|
|
36
36
|
options[:startup_log_file_path] = File.expand_path(log)
|
37
37
|
end
|
38
38
|
|
39
|
-
opts.on(
|
39
|
+
opts.on('-v', '--verbose [LEVEL]', [:DEBUG, :INFO, :WARN], 'Control the startup log (and stdout) verbosity (DEBUG, INFO, WARN) defaults to INFO') do |level|
|
40
40
|
options[:startup_log_level] = level || :DEBUG
|
41
41
|
end
|
42
42
|
|
43
|
-
opts.on(
|
43
|
+
opts.on('-f', 'Run in the foreground') do |f|
|
44
44
|
options[:daemonize] = false
|
45
45
|
end
|
46
46
|
|
47
|
-
opts.on_tail(
|
47
|
+
opts.on_tail('--version', 'Show RFlow version and exit') do
|
48
48
|
require 'rflow/version'
|
49
49
|
puts RFlow::VERSION
|
50
50
|
exit 0
|
51
51
|
end
|
52
52
|
|
53
|
-
opts.on_tail(
|
53
|
+
opts.on_tail('-h', '--help', 'Show this message and exit') do
|
54
54
|
puts opts
|
55
55
|
exit 0
|
56
56
|
end
|
data/example/http_extensions.rb
CHANGED
@@ -98,10 +98,10 @@ class HTTPServer < RFlow::Component
|
|
98
98
|
# This is done by inspecting the provenance, specifically the
|
99
99
|
# context attribute that we stored originally
|
100
100
|
def process_message(input_port, input_port_key, connection, message)
|
101
|
-
RFlow.logger.debug
|
101
|
+
RFlow.logger.debug 'Received a message'
|
102
102
|
return unless message.data_type_name == 'HTTPResponse'
|
103
103
|
|
104
|
-
RFlow.logger.debug
|
104
|
+
RFlow.logger.debug 'Received a HTTPResponse message, determining if its mine'
|
105
105
|
my_events = message.provenance.find_all {|processing_event| processing_event.component_instance_uuid == instance_uuid}
|
106
106
|
RFlow.logger.debug "Found #{my_events.size} processing events from me"
|
107
107
|
|
@@ -122,7 +122,7 @@ class HTTPServer < RFlow::Component
|
|
122
122
|
attr_accessor :server, :client_ip, :client_port
|
123
123
|
|
124
124
|
def post_init
|
125
|
-
@client_port, @client_ip = Socket.unpack_sockaddr_in(get_peername) rescue [
|
125
|
+
@client_port, @client_ip = Socket.unpack_sockaddr_in(get_peername) rescue ['?', '?.?.?.?']
|
126
126
|
RFlow.logger.debug "Connection from #{@client_ip}:#{@client_port}"
|
127
127
|
super
|
128
128
|
no_environment_strings
|
@@ -154,9 +154,9 @@ class HTTPServer < RFlow::Component
|
|
154
154
|
|
155
155
|
# Default values
|
156
156
|
resp.status = 200
|
157
|
-
resp.content =
|
158
|
-
resp.headers[
|
159
|
-
resp.headers[
|
157
|
+
resp.content = ''
|
158
|
+
resp.headers['Content-Type'] = 'text/html; charset=UTF-8'
|
159
|
+
resp.headers['Server'] = 'Apache/2.2.3 (CentOS)'
|
160
160
|
|
161
161
|
if response_message
|
162
162
|
resp.status = response_message.data.status
|
@@ -170,7 +170,7 @@ class HTTPServer < RFlow::Component
|
|
170
170
|
# Called when a connection is torn down for whatever reason.
|
171
171
|
# Remove this connection from the server's list
|
172
172
|
def unbind
|
173
|
-
RFlow.logger.debug
|
173
|
+
RFlow.logger.debug 'Connection lost'
|
174
174
|
server.connections.delete(self.signature)
|
175
175
|
end
|
176
176
|
end
|
data/lib/rflow.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler/setup'
|
3
3
|
require 'time'
|
4
4
|
require 'active_record'
|
5
5
|
require 'eventmachine'
|
@@ -38,7 +38,7 @@ class RFlow
|
|
38
38
|
def self.establish_configuration
|
39
39
|
@configuration = Configuration.new(@config_database_path)
|
40
40
|
unless configuration['rflow.application_directory_path']
|
41
|
-
raise ArgumentError,
|
41
|
+
raise ArgumentError, 'Empty configuration database! Use a view/controller (such as the RubyDSL) to create a configuration'
|
42
42
|
end
|
43
43
|
end
|
44
44
|
|
@@ -60,4 +60,25 @@ class RFlow
|
|
60
60
|
master.daemonize! if @daemonize
|
61
61
|
master.run! # blocks until EventMachine stops
|
62
62
|
end
|
63
|
+
|
64
|
+
# This ought to be in EM, but we'll put it here instead of monkey-patching
|
65
|
+
def self.next_tick_and_wait
|
66
|
+
mutex = Mutex.new
|
67
|
+
condition = ConditionVariable.new
|
68
|
+
|
69
|
+
mutex.synchronize do # while locked...
|
70
|
+
EM.next_tick do # schedule a job that will...
|
71
|
+
mutex.synchronize do # grab the lock
|
72
|
+
begin
|
73
|
+
yield # do its thing...
|
74
|
+
condition.signal # then wake us up when it's done...
|
75
|
+
rescue
|
76
|
+
condition.signal # even if the thing fails
|
77
|
+
raise
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
condition.wait(mutex) # drop the mutex to allow the job to run
|
82
|
+
end
|
83
|
+
end
|
63
84
|
end
|
data/lib/rflow/child_process.rb
CHANGED
data/lib/rflow/component.rb
CHANGED
@@ -91,11 +91,11 @@ class RFlow
|
|
91
91
|
|
92
92
|
# Returns a list of connected input ports. Each port will have
|
93
93
|
# one or more keys associated with a particular connection.
|
94
|
-
def input_ports; ports.by_type[
|
94
|
+
def input_ports; ports.by_type['RFlow::Component::InputPort']; end
|
95
95
|
|
96
96
|
# Returns a list of connected output ports. Each port will have
|
97
97
|
# one or more keys associated with the particular connection.
|
98
|
-
def output_ports; ports.by_type[
|
98
|
+
def output_ports; ports.by_type['RFlow::Component::OutputPort']; end
|
99
99
|
|
100
100
|
def configure_input_port!(port_name, options = {})
|
101
101
|
RFlow.logger.debug "Configuring component '#{name}' (#{uuid}) input port '#{port_name}' (#{options[:uuid]})"
|
data/lib/rflow/component/port.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
class RFlow
|
2
2
|
class Component
|
3
3
|
# TODO: make this into a class to limit the amount of extensions
|
4
|
-
# that we have to do when operating on these
|
4
|
+
# that we have to do when operating on these 'Arrays', i.e. when
|
5
5
|
# adding two together
|
6
6
|
module ConnectionCollection
|
7
7
|
def send_message(message)
|
@@ -44,6 +44,30 @@ class RFlow
|
|
44
44
|
def connected?; connected; end
|
45
45
|
end
|
46
46
|
|
47
|
+
# Stateless class to help with a nicer API
|
48
|
+
class HashSubPort
|
49
|
+
def initialize(hash_port, key)
|
50
|
+
@hash_port = hash_port
|
51
|
+
@key = key
|
52
|
+
end
|
53
|
+
|
54
|
+
def send_message(message)
|
55
|
+
connections.each {|connection| connection.send_message(message) }
|
56
|
+
end
|
57
|
+
|
58
|
+
def connections
|
59
|
+
@hash_port.connections_for(@key)
|
60
|
+
end
|
61
|
+
|
62
|
+
def direct_connect(other_port)
|
63
|
+
@hash_port.direct_connect(@key, other_port)
|
64
|
+
end
|
65
|
+
|
66
|
+
def each
|
67
|
+
connections.each {|connection| yield connection }
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
47
71
|
# Allows for a list of connections to be assigned to each port/key
|
48
72
|
# combination. Note that binding an input port to an un-indexed
|
49
73
|
# output port will result in messages from all indexed connections
|
@@ -53,41 +77,44 @@ class RFlow
|
|
53
77
|
class HashPort < Port
|
54
78
|
attr_accessor :name, :uuid
|
55
79
|
|
56
|
-
protected
|
57
|
-
attr_reader :connections_for
|
58
|
-
|
59
80
|
public
|
60
81
|
def initialize(component, args = {})
|
61
82
|
super(component)
|
62
83
|
self.uuid = args[:uuid]
|
63
84
|
self.name = args[:name]
|
64
|
-
@connections_for = Hash.new {|hash, key| hash[key] = []
|
85
|
+
@connections_for = Hash.new {|hash, key| hash[key] = []}
|
65
86
|
end
|
66
87
|
|
67
|
-
#
|
68
|
-
#
|
88
|
+
# Get the subport for a given key, which can be used to send messages
|
89
|
+
# or direct connection
|
90
|
+
def [](key)
|
91
|
+
HashSubPort.new(self, key)
|
92
|
+
end
|
93
|
+
|
94
|
+
# Returns an Array of all the connections that should
|
95
|
+
# be sent/received on this subport. Merges the nil-keyed port
|
69
96
|
# (i.e. any connections for a port without a key) to those
|
70
97
|
# specific for the key, so should only be used to read a list of
|
71
98
|
# connections, not to add new ones. Use add_connection to add a
|
72
99
|
# new connection for a given key.
|
73
|
-
def
|
100
|
+
def connections_for(key)
|
74
101
|
case key
|
75
|
-
when nil; connections_for[nil]
|
76
|
-
else connections_for[key] + connections_for[nil]
|
77
|
-
end
|
102
|
+
when nil; @connections_for[nil]
|
103
|
+
else @connections_for[key] + @connections_for[nil]
|
104
|
+
end
|
78
105
|
end
|
79
106
|
|
80
107
|
# Adds a connection for a given key
|
81
108
|
def add_connection(key, connection)
|
82
109
|
RFlow.logger.debug "Attaching #{connection.class.name} connection '#{connection.name}' (#{connection.uuid}) to port '#{name}' (#{uuid}), key '#{connection.input_port_key}'"
|
83
|
-
connections_for[key] << connection
|
110
|
+
@connections_for[key] << connection
|
84
111
|
@all_connections = nil
|
85
112
|
end
|
86
113
|
|
87
114
|
# Removes a connection from a given key
|
88
115
|
def remove_connection(key, connection)
|
89
116
|
RFlow.logger.debug "Removing #{connection.class.name} connection '#{connection.name}' (#{connection.uuid}) from port '#{name}' (#{uuid}), key '#{connection.input_port_key}'"
|
90
|
-
connections_for[key].delete(connection)
|
117
|
+
@connections_for[key].delete(connection)
|
91
118
|
@all_connections = nil
|
92
119
|
end
|
93
120
|
|
@@ -105,41 +132,39 @@ class RFlow
|
|
105
132
|
end
|
106
133
|
end
|
107
134
|
|
108
|
-
def direct_connect(other_port)
|
135
|
+
def direct_connect(key = nil, other_port)
|
109
136
|
case other_port
|
110
|
-
when InputPort; add_connection
|
111
|
-
when OutputPort; add_connection
|
137
|
+
when InputPort; add_connection key, ForwardToInputPort.new(other_port)
|
138
|
+
when OutputPort; add_connection key, ForwardToOutputPort.new(other_port)
|
112
139
|
else raise ArgumentError, "Unknown port type #{other_port.class.name}"
|
113
140
|
end
|
114
141
|
end
|
115
142
|
|
116
143
|
# Return a list of connected keys
|
117
144
|
def keys
|
118
|
-
connections_for.keys
|
145
|
+
@connections_for.keys
|
119
146
|
end
|
120
147
|
|
121
|
-
# Enumerate through all the ConnectionCollections
|
122
|
-
# TODO: simplify with enumerators and procs
|
123
148
|
def each
|
124
|
-
connections_for.values.each {|connections| yield connections }
|
149
|
+
@connections_for.values.each {|connections| yield connections }
|
125
150
|
end
|
126
151
|
|
127
152
|
def send_message(message)
|
128
|
-
|
153
|
+
raise NotImplementedError, 'Raw ports do not know how to send messages'
|
129
154
|
end
|
130
155
|
|
131
156
|
# Should be overridden. Called when it is time to actually
|
132
157
|
# establish the connection
|
133
|
-
def connect!; raise NotImplementedError,
|
158
|
+
def connect!; raise NotImplementedError, 'Raw ports do not know which direction to connect'; end
|
134
159
|
|
135
160
|
def all_connections
|
136
|
-
@all_connections ||= connections_for.values.flatten.uniq.extend(ConnectionCollection)
|
161
|
+
@all_connections ||= @connections_for.values.flatten.uniq.extend(ConnectionCollection)
|
137
162
|
end
|
138
163
|
end
|
139
164
|
|
140
165
|
class InputPort < HashPort
|
141
166
|
def connect!
|
142
|
-
connections_for.each {|key, conns| conns.each {|c| c.connect_input! } }
|
167
|
+
@connections_for.each {|key, conns| conns.each {|c| c.connect_input! } }
|
143
168
|
@connected = true
|
144
169
|
end
|
145
170
|
|
@@ -149,7 +174,7 @@ class RFlow
|
|
149
174
|
end
|
150
175
|
|
151
176
|
def recv_callback=(callback)
|
152
|
-
connections_for.each do |key, connections|
|
177
|
+
@connections_for.each do |key, connections|
|
153
178
|
connections.each do |connection|
|
154
179
|
connection.recv_callback = Proc.new do |message|
|
155
180
|
callback.call self, key, connection, message
|
@@ -161,7 +186,7 @@ class RFlow
|
|
161
186
|
|
162
187
|
class OutputPort < HashPort
|
163
188
|
def connect!
|
164
|
-
connections_for.each {|key, conns| conns.each {|c| c.connect_output! } }
|
189
|
+
@connections_for.each {|key, conns| conns.each {|c| c.connect_output! } }
|
165
190
|
@connected = true
|
166
191
|
end
|
167
192
|
|