kafka-rb 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/LICENSE +20 -0
- data/README.md +52 -0
- data/Rakefile +61 -0
- data/lib/kafka/io.rb +30 -0
- data/lib/kafka/message.rb +25 -0
- data/lib/kafka/producer.rb +49 -0
- data/lib/kafka.rb +9 -0
- data/lib/test.rb +32 -0
- data/spec/io_spec.rb +64 -0
- data/spec/kafka_spec.rb +7 -0
- data/spec/message_spec.rb +44 -0
- data/spec/producer_spec.rb +95 -0
- data/spec/spec_helper.rb +4 -0
- metadata +92 -0
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2010 Alejandro Crosa
|
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.
|
data/README.md
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
# kafka-rb
|
2
|
+
kafka-rb allows you to produce messages to the Kafka distributed publish/subscribe messaging service.
|
3
|
+
|
4
|
+
## Requirements
|
5
|
+
You need to have access to your Kafka instance and be able to connect through TCP. You can obtain a copy and instructions on how to setup kafka at https://github.com/kafka-dev/kafka
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
sudo gem install kafka-rb
|
9
|
+
|
10
|
+
(the code works fine with JRuby, Ruby 1.8x and Ruby 1.9.x)
|
11
|
+
|
12
|
+
## Usage
|
13
|
+
|
14
|
+
### Sending a simple message
|
15
|
+
|
16
|
+
require 'kafka-rb'
|
17
|
+
|
18
|
+
producer = Kafka::Producer.new
|
19
|
+
|
20
|
+
message = Kafka::Message.new("some random message content")
|
21
|
+
|
22
|
+
producer.send(message)
|
23
|
+
|
24
|
+
### sending a sequence of messages
|
25
|
+
|
26
|
+
require 'kafka-rb'
|
27
|
+
|
28
|
+
producer = Kafka::Producer.new
|
29
|
+
|
30
|
+
message1 = Kafka::Message.new("some random message content")
|
31
|
+
|
32
|
+
message2 = Kafka::Message.new("some more content")
|
33
|
+
|
34
|
+
producer.send([message1, message2])
|
35
|
+
|
36
|
+
### batching a bunch of messages using the block syntax
|
37
|
+
|
38
|
+
require 'kafka-rb'
|
39
|
+
|
40
|
+
producer = Kafka::Producer.new
|
41
|
+
|
42
|
+
producer.batch do |messages|
|
43
|
+
|
44
|
+
puts "Batching a send of multiple messages.."
|
45
|
+
|
46
|
+
messages << Kafka::Message.new("first message to send")
|
47
|
+
|
48
|
+
messages << Kafka::Message.new("second message to send")
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
* they will be sent all at once, after the block execution
|
data/Rakefile
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake/gempackagetask'
|
3
|
+
require 'rubygems/specification'
|
4
|
+
require 'date'
|
5
|
+
require 'spec/rake/spectask'
|
6
|
+
|
7
|
+
GEM = 'kafka-rb'
|
8
|
+
GEM_NAME = 'Kafka Client Producer'
|
9
|
+
GEM_VERSION = '0.0.1'
|
10
|
+
AUTHORS = ['Alejandro Crosa']
|
11
|
+
EMAIL = "alejandrocrosa@gmail.com"
|
12
|
+
HOMEPAGE = "http://github.com/acrosa/kafka-rb"
|
13
|
+
SUMMARY = "A Ruby client for the Kafka distributed publish/subscribe messaging service"
|
14
|
+
DESCRIPTION = "kafka-rb allows you to produce messages to the Kafka distributed publish/subscribe messaging service."
|
15
|
+
|
16
|
+
spec = Gem::Specification.new do |s|
|
17
|
+
s.name = GEM
|
18
|
+
s.version = GEM_VERSION
|
19
|
+
s.platform = Gem::Platform::RUBY
|
20
|
+
s.has_rdoc = true
|
21
|
+
s.extra_rdoc_files = ["LICENSE"]
|
22
|
+
s.summary = SUMMARY
|
23
|
+
s.description = DESCRIPTION
|
24
|
+
s.authors = AUTHORS
|
25
|
+
s.email = EMAIL
|
26
|
+
s.homepage = HOMEPAGE
|
27
|
+
s.add_development_dependency "rspec"
|
28
|
+
s.require_path = 'lib'
|
29
|
+
s.autorequire = GEM
|
30
|
+
s.files = %w(LICENSE README.md Rakefile) + Dir.glob("{lib,tasks,spec}/**/*")
|
31
|
+
end
|
32
|
+
|
33
|
+
task :default => :spec
|
34
|
+
|
35
|
+
desc "Run specs"
|
36
|
+
Spec::Rake::SpecTask.new do |t|
|
37
|
+
t.spec_files = FileList['spec/**/*_spec.rb']
|
38
|
+
t.spec_opts = %w(-fs --color)
|
39
|
+
end
|
40
|
+
|
41
|
+
Rake::GemPackageTask.new(spec) do |pkg|
|
42
|
+
pkg.gem_spec = spec
|
43
|
+
end
|
44
|
+
|
45
|
+
desc "install the gem locally"
|
46
|
+
task :install => [:package] do
|
47
|
+
sh %{sudo gem install pkg/#{GEM_NAME}-#{GEM_VERSION}}
|
48
|
+
end
|
49
|
+
|
50
|
+
desc "create a gemspec file"
|
51
|
+
task :make_spec do
|
52
|
+
File.open("#{GEM}.gemspec", "w") do |file|
|
53
|
+
file.puts spec.to_ruby
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
desc "Run all examples with RCov"
|
58
|
+
Spec::Rake::SpecTask.new(:rcov) do |t|
|
59
|
+
t.spec_files = FileList['spec/**/*_spec.rb']
|
60
|
+
t.rcov = true
|
61
|
+
end
|
data/lib/kafka/io.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
module Kafka
|
2
|
+
module IO
|
3
|
+
attr_accessor :socket, :host, :port
|
4
|
+
|
5
|
+
def connect(host, port)
|
6
|
+
raise ArgumentError, "No host or port specified" unless host && port
|
7
|
+
self.host = host
|
8
|
+
self.port = port
|
9
|
+
self.socket = TCPSocket.new(host, port)
|
10
|
+
end
|
11
|
+
|
12
|
+
def reconnect
|
13
|
+
self.disconnect
|
14
|
+
self.socket = self.connect(self.host, self.port)
|
15
|
+
end
|
16
|
+
|
17
|
+
def disconnect
|
18
|
+
self.socket.close rescue nil
|
19
|
+
self.socket = nil
|
20
|
+
end
|
21
|
+
|
22
|
+
def write(data)
|
23
|
+
self.reconnect unless self.socket
|
24
|
+
self.socket.write(data)
|
25
|
+
rescue Errno::ECONNRESET, Errno::EPIPE, Errno::ECONNABORTED
|
26
|
+
self.reconnect
|
27
|
+
self.socket.write(data) # retry
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Kafka
|
2
|
+
|
3
|
+
# A message. The format of an N byte message is the following:
|
4
|
+
# 1 byte "magic" identifier to allow format changes
|
5
|
+
# 4 byte CRC32 of the payload
|
6
|
+
# N - 5 byte payload
|
7
|
+
class Message
|
8
|
+
MAGIC_IDENTIFIER_DEFAULT = 0
|
9
|
+
attr_accessor :magic, :checksum, :payload
|
10
|
+
|
11
|
+
def initialize(payload = nil, magic = MAGIC_IDENTIFIER_DEFAULT)
|
12
|
+
self.magic = magic
|
13
|
+
self.payload = payload
|
14
|
+
self.checksum = self.calculate_checksum
|
15
|
+
end
|
16
|
+
|
17
|
+
def calculate_checksum
|
18
|
+
Zlib.crc32(self.payload)
|
19
|
+
end
|
20
|
+
|
21
|
+
def valid?
|
22
|
+
self.checksum == Zlib.crc32(self.payload)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Kafka
|
2
|
+
class Producer
|
3
|
+
|
4
|
+
include Kafka::IO
|
5
|
+
|
6
|
+
PRODUCE_REQUEST_ID = 0
|
7
|
+
|
8
|
+
attr_accessor :topic, :partition
|
9
|
+
|
10
|
+
def initialize(options = {})
|
11
|
+
self.topic = options[:topic] || "test"
|
12
|
+
self.partition = options[:partition] || 0
|
13
|
+
self.host = options[:host] || "localhost"
|
14
|
+
self.port = options[:port] || 9092
|
15
|
+
self.connect(self.host, self.port)
|
16
|
+
end
|
17
|
+
|
18
|
+
def encode(message)
|
19
|
+
[message.magic].pack("C") + [message.calculate_checksum].pack("N") + message.payload.to_s
|
20
|
+
end
|
21
|
+
|
22
|
+
def encode_request(topic, partition, messages)
|
23
|
+
message_set = Array(messages).collect { |message|
|
24
|
+
encoded_message = self.encode(message)
|
25
|
+
[encoded_message.length].pack("N") + encoded_message
|
26
|
+
}.join("")
|
27
|
+
|
28
|
+
request = [PRODUCE_REQUEST_ID].pack("n")
|
29
|
+
topic = [topic.length].pack("n") + topic
|
30
|
+
partition = [partition].pack("N")
|
31
|
+
messages = [message_set.length].pack("N") + message_set
|
32
|
+
|
33
|
+
data = request + topic + partition + messages
|
34
|
+
|
35
|
+
return [data.length].pack("N") + data
|
36
|
+
end
|
37
|
+
|
38
|
+
def send(messages)
|
39
|
+
self.write(self.encode_request(self.topic, self.partition, messages))
|
40
|
+
end
|
41
|
+
|
42
|
+
def batch(&block)
|
43
|
+
batch = Kafka::Batch.new
|
44
|
+
block.call( batch )
|
45
|
+
self.send(batch.messages)
|
46
|
+
batch.messages.clear
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
data/lib/kafka.rb
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
require 'socket'
|
2
|
+
require 'zlib'
|
3
|
+
require File.join(File.dirname(__FILE__), "kafka", "io")
|
4
|
+
require File.join(File.dirname(__FILE__), "kafka", "batch")
|
5
|
+
require File.join(File.dirname(__FILE__), "kafka", "message")
|
6
|
+
require File.join(File.dirname(__FILE__), "kafka", "producer")
|
7
|
+
|
8
|
+
module Kafka
|
9
|
+
end
|
data/lib/test.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
$KCODE = 'UTF-8'
|
2
|
+
|
3
|
+
require 'zlib'
|
4
|
+
|
5
|
+
PRODUCE_REQUEST_ID = 0
|
6
|
+
|
7
|
+
def encode_message(message)
|
8
|
+
# <MAGIC_BYTE: char> <CRC32: int> <PAYLOAD: bytes>
|
9
|
+
data = [0].pack("C").to_s + [Zlib.crc32(message)].pack('N').to_s + message
|
10
|
+
# print ("CHECKSUM " + Zlib.crc32(message).to_s)
|
11
|
+
# print ("MES " + data.length.to_s)
|
12
|
+
return data
|
13
|
+
end
|
14
|
+
# encode_message("ale")
|
15
|
+
|
16
|
+
def encode_produce_request(topic, partition, messages)
|
17
|
+
encoded = messages.collect { |m| encode_message(m) }
|
18
|
+
message_set = encoded.collect { |e| puts "Message size #{e.length}"; [e.length].pack("N") + e }.join("")
|
19
|
+
|
20
|
+
puts "MESSAGE"
|
21
|
+
puts message_set.inspect
|
22
|
+
|
23
|
+
data = [PRODUCE_REQUEST_ID].pack("n") + \
|
24
|
+
[topic.length].pack("n") + topic.to_s + \
|
25
|
+
[partition].pack("N") + \
|
26
|
+
[message_set.length].pack("N") + message_set
|
27
|
+
puts "DATA " + message_set.length.to_s
|
28
|
+
return [data.length].pack("N") + data
|
29
|
+
end
|
30
|
+
|
31
|
+
socket = TCPSocket.open("localhost", 9092)
|
32
|
+
socket.write encode_produce_request("test", 0, ["ale"])
|
data/spec/io_spec.rb
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
class IOTest
|
4
|
+
include Kafka::IO
|
5
|
+
end
|
6
|
+
|
7
|
+
describe IO do
|
8
|
+
|
9
|
+
before(:each) do
|
10
|
+
@mocked_socket = mock(TCPSocket)
|
11
|
+
TCPSocket.stub!(:new).and_return(@mocked_socket) # don't use a real socket
|
12
|
+
@io = IOTest.new
|
13
|
+
@io.connect("somehost", 9093)
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "default methods" do
|
17
|
+
it "has a socket, a host and a port" do
|
18
|
+
[:socket, :host, :port].each do |m|
|
19
|
+
@io.should respond_to(m.to_sym)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
it "raises an exception if no host and port is specified" do
|
24
|
+
lambda {
|
25
|
+
io = IOTest.new
|
26
|
+
io.connect
|
27
|
+
}.should raise_error(ArgumentError)
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should remember the port and host on connect" do
|
31
|
+
@io.connect("somehost", 9093)
|
32
|
+
@io.host.should eql("somehost")
|
33
|
+
@io.port.should eql(9093)
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should write to a socket" do
|
37
|
+
data = "some data"
|
38
|
+
@mocked_socket.should_receive(:write).with(data).and_return(9)
|
39
|
+
@io.write(data).should eql(9)
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should disconnect" do
|
43
|
+
@io.should respond_to(:disconnect)
|
44
|
+
@mocked_socket.should_receive(:close).and_return(nil)
|
45
|
+
@io.disconnect
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should reconnect" do
|
49
|
+
@mocked_socket.should_receive(:close)
|
50
|
+
@io.should_receive(:connect)
|
51
|
+
@io.reconnect
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should reconnect on a broken pipe error" do
|
55
|
+
[Errno::ECONNABORTED, Errno::EPIPE, Errno::ECONNRESET].each do |error|
|
56
|
+
@mocked_socket.should_receive(:write).exactly(:twice).and_raise(error)
|
57
|
+
@mocked_socket.should_receive(:close).exactly(:once).and_return(nil)
|
58
|
+
lambda {
|
59
|
+
@io.write("some data to send")
|
60
|
+
}.should raise_error(error)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
data/spec/kafka_spec.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
describe Message do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
@message = Message.new
|
7
|
+
end
|
8
|
+
|
9
|
+
describe "Kafka Message" do
|
10
|
+
it "should have a default magic number" do
|
11
|
+
Message::MAGIC_IDENTIFIER_DEFAULT.should eql(0)
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should have a magic field, a checksum and a payload" do
|
15
|
+
[:magic, :checksum, :payload].each do |field|
|
16
|
+
@message.should respond_to(field.to_sym)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should set a default value of zero" do
|
21
|
+
@message.magic.should eql(Kafka::Message::MAGIC_IDENTIFIER_DEFAULT)
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should allow to set a custom magic number" do
|
25
|
+
@message = Message.new("ale", 1)
|
26
|
+
@message.magic.should eql(1)
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should calculate the checksum (crc32 of a given message)" do
|
30
|
+
@message.payload = "ale"
|
31
|
+
@message.calculate_checksum.should eql(1120192889)
|
32
|
+
@message.payload = "alejandro"
|
33
|
+
@message.calculate_checksum.should eql(2865078607)
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should say if the message is valid using the crc32 signature" do
|
37
|
+
@message.payload = "alejandro"
|
38
|
+
@message.checksum = 2865078607
|
39
|
+
@message.valid?.should eql(true)
|
40
|
+
@message.checksum = 0
|
41
|
+
@message.valid?.should eql(false)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
describe Producer do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
@mocked_socket = mock(TCPSocket)
|
7
|
+
TCPSocket.stub!(:new).and_return(@mocked_socket) # don't use a real socket
|
8
|
+
@producer = Producer.new
|
9
|
+
end
|
10
|
+
|
11
|
+
describe "Kafka Producer" do
|
12
|
+
it "should have a PRODUCE_REQUEST_ID" do
|
13
|
+
Producer::PRODUCE_REQUEST_ID.should eql(0)
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should have a topic and a partition" do
|
17
|
+
@producer.should respond_to(:topic)
|
18
|
+
@producer.should respond_to(:partition)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should set a topic and partition on initialize" do
|
22
|
+
@producer = Producer.new({ :host => "localhost", :port => 9092, :topic => "testing" })
|
23
|
+
@producer.topic.should eql("testing")
|
24
|
+
@producer.partition.should eql(0)
|
25
|
+
@producer = Producer.new({ :topic => "testing", :partition => 3 })
|
26
|
+
@producer.partition.should eql(3)
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should set default host and port if none is specified" do
|
30
|
+
@producer = Producer.new
|
31
|
+
@producer.host.should eql("localhost")
|
32
|
+
@producer.port.should eql(9092)
|
33
|
+
end
|
34
|
+
|
35
|
+
describe "Message Encoding" do
|
36
|
+
it "should encode a message" do
|
37
|
+
message = Kafka::Message.new("alejandro")
|
38
|
+
full_message = [message.magic].pack("C") + [message.calculate_checksum].pack("N") + message.payload
|
39
|
+
@producer.encode(message).should eql(full_message)
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should encode an empty message" do
|
43
|
+
message = Kafka::Message.new()
|
44
|
+
full_message = [message.magic].pack("C") + [message.calculate_checksum].pack("N") + message.payload.to_s
|
45
|
+
@producer.encode(message).should eql(full_message)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe "Request Encoding" do
|
50
|
+
it "should binary encode an empty request" do
|
51
|
+
bytes = @producer.encode_request("test", 0, [])
|
52
|
+
bytes.length.should eql(20)
|
53
|
+
bytes.should eql("\000\000\000\020\000\000\000\004test\000\000\000\000\000\000\000\000")
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should binary encode a request with a message, using a specific wire format" do
|
57
|
+
message = Kafka::Message.new("ale")
|
58
|
+
bytes = @producer.encode_request("test", 3, message)
|
59
|
+
data_size = bytes[0, 4].unpack("N").shift
|
60
|
+
request_id = bytes[4, 2].unpack("n").shift
|
61
|
+
topic_length = bytes[6, 2].unpack("n").shift
|
62
|
+
topic = bytes[8, 4]
|
63
|
+
partition = bytes[12, 4].unpack("N").shift
|
64
|
+
messages_length = bytes[16, 4].unpack("N").shift
|
65
|
+
messages = bytes[20, messages_length]
|
66
|
+
|
67
|
+
bytes.length.should eql(32)
|
68
|
+
data_size.should eql(28)
|
69
|
+
request_id.should eql(0)
|
70
|
+
topic_length.should eql(4)
|
71
|
+
topic.should eql("test")
|
72
|
+
partition.should eql(3)
|
73
|
+
messages_length.should eql(12)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
it "should send messages" do
|
79
|
+
@producer.should_receive(:write).and_return(32)
|
80
|
+
message = Kafka::Message.new("ale")
|
81
|
+
@producer.send(message).should eql(32)
|
82
|
+
end
|
83
|
+
|
84
|
+
describe "Message Batching" do
|
85
|
+
it "should batch messages and send them at once" do
|
86
|
+
message1 = Kafka::Message.new("one")
|
87
|
+
message2 = Kafka::Message.new("two")
|
88
|
+
@producer.should_receive(:send).with([message1, message2]).exactly(:once).and_return(nil)
|
89
|
+
@producer.batch do |messages|
|
90
|
+
messages << message1
|
91
|
+
messages << message2
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: kafka-rb
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 29
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 1
|
10
|
+
version: 0.0.1
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Alejandro Crosa
|
14
|
+
autorequire: kafka-rb
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-01-07 00:00:00 -08:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: rspec
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 3
|
30
|
+
segments:
|
31
|
+
- 0
|
32
|
+
version: "0"
|
33
|
+
type: :development
|
34
|
+
version_requirements: *id001
|
35
|
+
description: kafka-rb allows you to produce messages to the Kafka distributed publish/subscribe messaging service.
|
36
|
+
email: alejandrocrosa@gmail.com
|
37
|
+
executables: []
|
38
|
+
|
39
|
+
extensions: []
|
40
|
+
|
41
|
+
extra_rdoc_files:
|
42
|
+
- LICENSE
|
43
|
+
files:
|
44
|
+
- LICENSE
|
45
|
+
- README.md
|
46
|
+
- Rakefile
|
47
|
+
- lib/kafka/io.rb
|
48
|
+
- lib/kafka/message.rb
|
49
|
+
- lib/kafka/producer.rb
|
50
|
+
- lib/kafka.rb
|
51
|
+
- lib/test.rb
|
52
|
+
- spec/io_spec.rb
|
53
|
+
- spec/kafka_spec.rb
|
54
|
+
- spec/message_spec.rb
|
55
|
+
- spec/producer_spec.rb
|
56
|
+
- spec/spec_helper.rb
|
57
|
+
has_rdoc: true
|
58
|
+
homepage: http://github.com/acrosa/kafka-rb
|
59
|
+
licenses: []
|
60
|
+
|
61
|
+
post_install_message:
|
62
|
+
rdoc_options: []
|
63
|
+
|
64
|
+
require_paths:
|
65
|
+
- lib
|
66
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
67
|
+
none: false
|
68
|
+
requirements:
|
69
|
+
- - ">="
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
hash: 3
|
72
|
+
segments:
|
73
|
+
- 0
|
74
|
+
version: "0"
|
75
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
76
|
+
none: false
|
77
|
+
requirements:
|
78
|
+
- - ">="
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
hash: 3
|
81
|
+
segments:
|
82
|
+
- 0
|
83
|
+
version: "0"
|
84
|
+
requirements: []
|
85
|
+
|
86
|
+
rubyforge_project:
|
87
|
+
rubygems_version: 1.3.7
|
88
|
+
signing_key:
|
89
|
+
specification_version: 3
|
90
|
+
summary: A Ruby client for the Kafka distributed publish/subscribe messaging service
|
91
|
+
test_files: []
|
92
|
+
|