horobi 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile ADDED
@@ -0,0 +1,13 @@
1
+ source "http://rubygems.org"
2
+ # Add dependencies required to use your gem here.
3
+ # Example:
4
+ # gem "activesupport", ">= 2.3.5"
5
+
6
+ # Add dependencies to develop your gem here.
7
+ # Include everything needed to run rake, tests, features, etc.
8
+ group :development do
9
+ gem "rspec", "~> 2.3.0"
10
+ gem "bundler", "~> 1.0.0"
11
+ gem "jeweler", "~> 1.5.2"
12
+ gem "rcov", ">= 0"
13
+ end
@@ -0,0 +1,28 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ diff-lcs (1.1.2)
5
+ git (1.2.5)
6
+ jeweler (1.5.2)
7
+ bundler (~> 1.0.0)
8
+ git (>= 1.2.5)
9
+ rake
10
+ rake (0.8.7)
11
+ rcov (0.9.9)
12
+ rspec (2.3.0)
13
+ rspec-core (~> 2.3.0)
14
+ rspec-expectations (~> 2.3.0)
15
+ rspec-mocks (~> 2.3.0)
16
+ rspec-core (2.3.1)
17
+ rspec-expectations (2.3.0)
18
+ diff-lcs (~> 1.1.2)
19
+ rspec-mocks (2.3.0)
20
+
21
+ PLATFORMS
22
+ ruby
23
+
24
+ DEPENDENCIES
25
+ bundler (~> 1.0.0)
26
+ jeweler (~> 1.5.2)
27
+ rcov
28
+ rspec (~> 2.3.0)
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 uu59
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,108 @@
1
+ # horobi
2
+
3
+ Horobi is very flexible mesh network builder with ZeroMQ.
4
+
5
+ ![zmq model](http://uu59.github.com/horobi/horobi-zmq.png)
6
+
7
+ Virtual realtime web.
8
+
9
+ ![sample1](http://uu59.github.com/horobi/horobi-sample.png)
10
+
11
+ Scalable logging architecture.
12
+
13
+ ![sample2](http://uu59.github.com/horobi/horobi-sample2.png)
14
+
15
+ Or, you can do all on one machine.
16
+
17
+ ![sample3](http://uu59.github.com/horobi/horobi-sample3.png)
18
+
19
+ # Node Type
20
+
21
+
22
+ ## Pub
23
+
24
+ Pub-node push some interesting data to Hub-node.
25
+
26
+ #!/usr/bin/env ruby
27
+ require "rubygems"
28
+ require "horobi"
29
+
30
+ loop do
31
+ Horobi::Pub.send(Time.now.to_s)
32
+ sleep 1
33
+ end
34
+
35
+ Real world sample as below:
36
+
37
+ #!/usr/bin/env ruby
38
+ require "rubygems"
39
+ require "twitter/json_stream" # https://github.com/voloko/twitter-stream
40
+ require "horobi"
41
+
42
+ EM.run do
43
+ stream = Twitter::JSONStream.connect(
44
+ :path => '/1/statuses/filter.json?track=ruby',
45
+ :auth => 'LOGIN:PASSWORD'
46
+ )
47
+
48
+ stream.each_item do |json|
49
+ Horobi::Pub.send("twitter " + json)
50
+ end
51
+ end
52
+
53
+ ## Hub
54
+
55
+ Hub-node get data from Pub-node, and push to Sub-node.
56
+
57
+ #!/usr/bin/env ruby
58
+ require "rubygems"
59
+ require "horobi"
60
+
61
+ Horobi::Hub.start
62
+
63
+ ## Sub
64
+
65
+ Sub-node get data from Hub-node and do some stuff.
66
+
67
+ #!/usr/bin/env ruby
68
+ require "rubygems"
69
+ require "notify" # https://github.com/jugyo/notify
70
+ require "json"
71
+ require "horobi"
72
+
73
+ Horobi::Sub.listen("twitter") do |data|
74
+ tweet = JSON.parse(data)
75
+ Notify.notify(tweet["user"]["screen_name"], tweet["text"])
76
+ end
77
+
78
+ # Example
79
+
80
+ Please see example/ directory.
81
+
82
+ # launch pub node with background job, stream push to tcp://127.0.0.1:5551. if you don't want to log messages, use -l /dev/null option
83
+ $ SCREEN_NAME=uu59 PASSWORD=xxxx ruby example/twitter/pub1.rb -o tcp://127.0.0.1:5551 ruby & # tracking twitter stream with "ruby"
84
+ $ ruby example/twitter/pub2.rb -o tcp://127.0.0.1:5551 & # fake stream
85
+
86
+ # launch hub node as daemon(-d), ZeroMQ PULL socket listen to tcp://127.0.0.1:5551 (-i 5551) and PUB socket is tcp://127.0.0.1:5552 (-o 5552)
87
+ $ ruby example/twitter/hub.rb -d -i 5551 -o 5552
88
+
89
+ # get data from tcp://127.0.0.1:5552. you'll get mixed stream of twitter and fake.
90
+ $ ruby example/twitter/sub1.rb -i tcp://127.0.0.1:5552
91
+
92
+ You can ignore launch sequence to Pub/Sub/Hub nodes.
93
+
94
+ # Contributing to horobi
95
+
96
+ * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
97
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
98
+ * Fork the project
99
+ * Start a feature/bugfix branch
100
+ * Commit and push until you are happy with your contribution
101
+ * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
102
+ * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
103
+
104
+ # Copyright
105
+
106
+ Copyright (c) 2011 uu59. See LICENSE.txt for
107
+ further details.
108
+
@@ -0,0 +1,50 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+ require 'rake'
11
+
12
+ require 'jeweler'
13
+ Jeweler::Tasks.new do |gem|
14
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
15
+ gem.name = "horobi"
16
+ gem.homepage = "http://github.com/tt25/horobi"
17
+ gem.license = "MIT"
18
+ gem.summary = %Q{TODO: one-line summary of your gem}
19
+ gem.description = %Q{TODO: longer description of your gem}
20
+ gem.email = "a@tt25.org"
21
+ gem.authors = ["uu59"]
22
+ # Include your dependencies below. Runtime dependencies are required when using your gem,
23
+ # and development dependencies are only needed for development (ie running rake tasks, tests, etc)
24
+ # gem.add_runtime_dependency 'jabber4r', '> 0.1'
25
+ # gem.add_development_dependency 'rspec', '> 1.2.3'
26
+ end
27
+ Jeweler::RubygemsDotOrgTasks.new
28
+
29
+ require 'rspec/core'
30
+ require 'rspec/core/rake_task'
31
+ RSpec::Core::RakeTask.new(:spec) do |spec|
32
+ spec.pattern = FileList['spec/**/*_spec.rb']
33
+ end
34
+
35
+ RSpec::Core::RakeTask.new(:rcov) do |spec|
36
+ spec.pattern = 'spec/**/*_spec.rb'
37
+ spec.rcov = true
38
+ end
39
+
40
+ task :default => :spec
41
+
42
+ require 'rake/rdoctask'
43
+ Rake::RDocTask.new do |rdoc|
44
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
45
+
46
+ rdoc.rdoc_dir = 'rdoc'
47
+ rdoc.title = "horobi #{version}"
48
+ rdoc.rdoc_files.include('README*')
49
+ rdoc.rdoc_files.include('lib/**/*.rb')
50
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+ # -- coding: utf-8
3
+
4
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', '..', 'lib'))
5
+ require "rubygems"
6
+ require "horobi"
7
+
8
+ Horobi::Hub.start
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env ruby
2
+ # -- coding: utf-8
3
+
4
+ require "rubygems"
5
+ require "eventmachine"
6
+ require "twitter/json_stream"
7
+
8
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', '..', 'lib'))
9
+ require "horobi"
10
+
11
+ EM.run do
12
+ stream = Twitter::JSONStream.connect(
13
+ :path => "/1/statuses/filter.json?track=#{ARGV.first}",
14
+ :auth => "#{ENV["SCREEN_NAME"]}:#{ENV["PASSWORD"]}"
15
+ )
16
+ stream.each_item do |json|
17
+ Horobi::Pub.send(json)
18
+ end
19
+
20
+ stream.on_error do |message|
21
+ p message
22
+ EM.stop
23
+ end
24
+ end
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env ruby
2
+ # -- coding: utf-8
3
+
4
+ require "rubygems"
5
+ require "json"
6
+
7
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', '..', 'lib'))
8
+ require "horobi"
9
+
10
+ loop do
11
+ Horobi::Pub.send({
12
+ "user" => {
13
+ "screen_name" => "fake",
14
+ },
15
+ "text" => "this is fake tweet!"
16
+ }.to_json)
17
+ sleep 1
18
+ end
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ # -- coding: utf-8
3
+
4
+
5
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', '..', 'lib'))
6
+ require "horobi"
7
+ require "json"
8
+
9
+ Horobi::Sub.listen do |msg|
10
+ begin
11
+ tw = JSON.parse(msg)
12
+ puts tw["user"]["screen_name"] + ": " + tw["text"]
13
+ rescue
14
+ next
15
+ end
16
+ end
@@ -0,0 +1,47 @@
1
+ # coding: utf-8
2
+
3
+ require "logger"
4
+ require "optparse"
5
+ require "rubygems"
6
+ require "yaml"
7
+ require "zmq"
8
+
9
+ module Horobi
10
+ attr_accessor :logger
11
+ attr_reader :config
12
+ @logger = Logger.new(nil)
13
+ @closes = []
14
+
15
+ def daemonize
16
+ exit! if fork
17
+ Process.setsid
18
+ exit! if fork
19
+
20
+ STDIN.reopen('/dev/null', 'r+')
21
+ STDOUT.reopen('/dev/null', 'a')
22
+ STDERR.reopen('/dev/null', 'a')
23
+ end
24
+
25
+ def close_hooks(&block)
26
+ @closes << block
27
+ end
28
+
29
+ %w!INT TERM!.each{|sig|
30
+ Signal.trap(sig) do
31
+ @closes.each{|destruct|
32
+ begin
33
+ destruct.call
34
+ ensure
35
+ next
36
+ end
37
+ }
38
+ exit!
39
+ end
40
+ }
41
+
42
+ extend self
43
+ end
44
+
45
+ require "#{File.dirname(__FILE__)}/horobi/hub.rb"
46
+ require "#{File.dirname(__FILE__)}/horobi/sub.rb"
47
+ require "#{File.dirname(__FILE__)}/horobi/pub.rb"
@@ -0,0 +1,79 @@
1
+ # -- coding: utf-8
2
+
3
+ require "rubygems"
4
+
5
+ module Horobi
6
+ module Hub
7
+ def start
8
+
9
+ @options = {
10
+ "logfile" => STDERR,
11
+ "input" => "5551",
12
+ "output" => "5552",
13
+ }
14
+ OptionParser.new do |op|
15
+ op.on('-p VAL','--pidfile=VAL','pidfile path'){|v| @options["pidfile"] = v}
16
+ op.on('-l VAL','--logfile=VAL','logfile path'){|v| @options["logfile"] = (v == "-" ? STDOUT : v)}
17
+ op.on('-i VAL','--input-port=VAL','input(pull) point such as 5551'){|v| @options["input"] = v}
18
+ op.on('-o VAL','--output-port=VAL','output(pub) point such as 5552'){|v| @options["output"] = v}
19
+ op.on('-d','--daemonize','daemonize this script'){ @options["daemonize"] = true }
20
+ op.parse!(ARGV)
21
+ end
22
+
23
+ @logger = Logger.new(@options["logfile"])
24
+
25
+ if @options["daemonize"]
26
+ Horobi.daemonize
27
+ @logger.debug("mainloop running ##{Process.pid}")
28
+ end
29
+
30
+ if @options["pidfile"]
31
+ File.open(@options["pidfile"],"w"){|fp| fp.write Process.pid}
32
+ end
33
+
34
+ begin
35
+ @context = ZMQ::Context.new
36
+ @input = @context.socket(ZMQ::PULL)
37
+ @input.bind("tcp://127.0.0.1:#{@options["input"]}")
38
+ @logger.info("input socket listen at #{@options["input"]}")
39
+ @output = @context.socket(ZMQ::PUB)
40
+ @output.bind("tcp://127.0.0.1:#{@options["output"]}")
41
+ @logger.info("output socket listen at #{@options["output"]}")
42
+ rescue TypeError => ex
43
+ puts "invalid port. input:#{@options["input"]}, output:#{@options["output"]}"
44
+ exit!
45
+ end
46
+
47
+ Horobi.close_hooks do
48
+ @logger.info("hub stopping")
49
+ stop
50
+ end
51
+
52
+ loop do
53
+ sleep 0.1
54
+ next unless inp = @input.recv(ZMQ::NOBLOCK)
55
+ @output.send(inp)
56
+ @logger.debug(inp)
57
+ end
58
+
59
+ exit!
60
+ end
61
+
62
+ def stop
63
+ begin
64
+ @logger.info("stopping..")
65
+ @input.close if @input
66
+ @output.close if @output
67
+ rescue IOError
68
+ # in `recv': closed socket (IOError)
69
+ ensure
70
+ if @options["pidfile"]
71
+ File.delete(@options["pidfile"])
72
+ end
73
+ @context.close
74
+ end
75
+ end
76
+
77
+ extend self
78
+ end
79
+ end
@@ -0,0 +1,51 @@
1
+ # -- coding: utf-8
2
+
3
+ module Horobi
4
+ module Pub
5
+ attr_reader :sock
6
+
7
+ def self.init
8
+ @context ||= ZMQ::Context.new
9
+ options = {
10
+ "logfile" => STDERR,
11
+ "outputs" => [],
12
+ }
13
+ OptionParser.new do |op|
14
+ op.on('-p VAL','--pidfile=VAL','pidfile path'){|v| options["pidfile"] = v}
15
+ op.on('-l VAL','--logfile=VAL','logfile path'){|v| options["logfile"] = (v == "-" ? STDOUT : v)}
16
+ op.on('-o VAL','--ouput-points=VAL',
17
+ "output(hub's input) point(s) such as 'tcp://127.0.0.1:5551,tcp://127.0.11.1:5551'"){|v| options["outputs"] = v.split(",")}
18
+ op.on('-d','--daemonize','daemonize this script'){ options["daemon"] = true }
19
+ op.parse!(ARGV)
20
+ end
21
+ @options = options
22
+ if @options["outputs"].compact.length < 1
23
+ raise "pub output points are undefined"
24
+ end
25
+ @logger = Logger.new(options["logfile"])
26
+ @sock ||= begin
27
+ sock = @context.socket(ZMQ::PUSH)
28
+ @options["outputs"].each do |point|
29
+ @logger.info("connecting to #{point}")
30
+ sock.connect(point)
31
+ end
32
+ sock.setsockopt(ZMQ::LINGER, 100)
33
+ sock
34
+ end
35
+ end
36
+
37
+ def self.send(msg, flags=nil) # flags = ZMQ::NOBLOCK | ZMQ::SNDMORE
38
+ if @options.nil?
39
+ init
40
+ end
41
+
42
+ @logger.debug("message send to #{@options["inputs"]}: " + msg)
43
+ @sock.send(msg, flags)
44
+ end
45
+
46
+ Horobi.close_hooks do
47
+ @sock.close if @sock
48
+ @context.close if @context
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,52 @@
1
+ # -- coding: utf-8
2
+
3
+ module Horobi
4
+ module Sub
5
+ @context = ZMQ::Context.new
6
+
7
+ def self.init
8
+ options = {
9
+ "logfile" => STDERR,
10
+ "inputs" => [],
11
+ }
12
+ OptionParser.new do |op|
13
+ op.on('-p VAL','--pidfile=VAL','pidfile path'){|v| options["pidfile"] = v}
14
+ op.on('-l VAL','--logfile=VAL','logfile path'){|v| options["logfile"] = (v == "-" ? STDOUT : v)}
15
+ op.on('-i VAL','--input-points=VAL',
16
+ "input(hub's output) point(s) such as 'tcp://127.0.0.1:5551,tcp://127.0.11.1:5551'"){|v| options["inputs"] = v.split(",")}
17
+ #op.on('-d','--daemonize','daemonize this script'){ options["daemon"] = true }
18
+ op.parse!(ARGV)
19
+ end
20
+ @options = options
21
+ if @options["inputs"].compact.length < 1
22
+ raise "subscribe input points are undefined"
23
+ end
24
+ @logger = Logger.new(options["logfile"])
25
+ @sock ||= begin
26
+ sock = @context.socket(ZMQ::SUB)
27
+ @options["inputs"].each do |point|
28
+ @logger.info("connecting to #{point}")
29
+ sock.connect(point)
30
+ end
31
+ sock.setsockopt(ZMQ::LINGER, 100)
32
+ sock
33
+ end
34
+ end
35
+
36
+ def self.listen(filter=nil, &block)
37
+ init unless @sock
38
+ @sock.setsockopt(ZMQ::SUBSCRIBE, filter.to_s)
39
+
40
+ Horobi.close_hooks do
41
+ @input.close
42
+ @context.close
43
+ end
44
+
45
+ loop do
46
+ buf = @sock.recv(ZMQ::NOBLOCK)
47
+ block.call(buf) if buf
48
+ sleep 0.1
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,7 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe "Horobi" do
4
+ it "fails" do
5
+ fail "hey buddy, you should probably rename this file and start specing for real"
6
+ end
7
+ end
@@ -0,0 +1,12 @@
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
3
+ require 'rspec'
4
+ require 'horobi'
5
+
6
+ # Requires supporting files with custom matchers and macros, etc,
7
+ # in ./support/ and its subdirectories.
8
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
9
+
10
+ RSpec.configure do |config|
11
+
12
+ end
metadata ADDED
@@ -0,0 +1,122 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: horobi
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.0.1
6
+ platform: ruby
7
+ authors:
8
+ - uu59
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2011-04-08 00:00:00 +09:00
14
+ default_executable:
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: rspec
18
+ prerelease: false
19
+ requirement: &id001 !ruby/object:Gem::Requirement
20
+ none: false
21
+ requirements:
22
+ - - ~>
23
+ - !ruby/object:Gem::Version
24
+ version: 2.3.0
25
+ type: :development
26
+ version_requirements: *id001
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ prerelease: false
30
+ requirement: &id002 !ruby/object:Gem::Requirement
31
+ none: false
32
+ requirements:
33
+ - - ~>
34
+ - !ruby/object:Gem::Version
35
+ version: 1.0.0
36
+ type: :development
37
+ version_requirements: *id002
38
+ - !ruby/object:Gem::Dependency
39
+ name: jeweler
40
+ prerelease: false
41
+ requirement: &id003 !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ~>
45
+ - !ruby/object:Gem::Version
46
+ version: 1.5.2
47
+ type: :development
48
+ version_requirements: *id003
49
+ - !ruby/object:Gem::Dependency
50
+ name: rcov
51
+ prerelease: false
52
+ requirement: &id004 !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: "0"
58
+ type: :development
59
+ version_requirements: *id004
60
+ description: mesh network builder with ZeroMQ
61
+ email: a@tt25.org
62
+ executables: []
63
+
64
+ extensions: []
65
+
66
+ extra_rdoc_files:
67
+ - LICENSE.txt
68
+ - README.mkd
69
+ files:
70
+ - .document
71
+ - .rspec
72
+ - Gemfile
73
+ - Gemfile.lock
74
+ - LICENSE.txt
75
+ - README.mkd
76
+ - Rakefile
77
+ - VERSION
78
+ - examples/twitter/hub.rb
79
+ - examples/twitter/pub1.rb
80
+ - examples/twitter/pub2.rb
81
+ - examples/twitter/sub1.rb
82
+ - lib/horobi.rb
83
+ - lib/horobi/hub.rb
84
+ - lib/horobi/pub.rb
85
+ - lib/horobi/sub.rb
86
+ - spec/horobi_spec.rb
87
+ - spec/spec_helper.rb
88
+ has_rdoc: true
89
+ homepage: http://github.com/uu59/horobi
90
+ licenses:
91
+ - MIT
92
+ post_install_message:
93
+ rdoc_options: []
94
+
95
+ require_paths:
96
+ - lib
97
+ required_ruby_version: !ruby/object:Gem::Requirement
98
+ none: false
99
+ requirements:
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: "0"
103
+ required_rubygems_version: !ruby/object:Gem::Requirement
104
+ none: false
105
+ requirements:
106
+ - - ">="
107
+ - !ruby/object:Gem::Version
108
+ version: "0"
109
+ requirements: []
110
+
111
+ rubyforge_project:
112
+ rubygems_version: 1.6.2
113
+ signing_key:
114
+ specification_version: 3
115
+ summary: mesh network builder with ZeroMQ
116
+ test_files:
117
+ - examples/twitter/hub.rb
118
+ - examples/twitter/pub1.rb
119
+ - examples/twitter/pub2.rb
120
+ - examples/twitter/sub1.rb
121
+ - spec/horobi_spec.rb
122
+ - spec/spec_helper.rb