bunny 0.1.0 → 0.1.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.markdown CHANGED
@@ -4,30 +4,23 @@ Google Group: [bunny-amqp](http://groups.google.com/group/bunny-amqp)
4
4
 
5
5
  Mailing List: [bunny-amqp-devel](http://rubyforge.org/mailman/listinfo/bunny-amqp-devel)
6
6
 
7
- Rubyforge: [bunny-amqp](http://bunny-amqp.rubyforge.org)
7
+ Rubyforge: [bunny-amqp](http://rubyforge.org/projects/bunny-amqp)
8
8
 
9
9
  ## Announcements
10
10
 
11
- **IMPORTANT**
11
+ Bunny v0.1.1 has been released. It contains the following changes -
12
12
 
13
- The Exchange#initialize method arguments have changed as of version 0.0.7
14
-
15
- You now create an exchange like this -
16
-
17
- b = Bunny.new
18
- exch = b.exchange('my_exchange', :type => :fanout)
19
-
20
- If you do not specify a :type option then a default of :direct is used.
21
-
22
- The old way was -
23
-
24
- b = Bunny.new
25
- exch = b.exchange(:fanout, 'my_exchange')
13
+ * Queue#delete method returns ‘QUEUE DELETED’, Exchange#delete method returns ‘EXCHANGE DELETED’, Queue#bind returns ‘BIND SUCCEEDED’, Queue#unbind returns ‘UNBIND SUCCEEDED’
14
+ * Queue#subscribe method available (see example bunny/examples/simple_consumer.rb)
15
+ * Queue#status now returns a hash {:message_count, :consumer_count}
16
+ * Queue#ack works after a Queue#subscribe or Queue#pop if :ack => true was specified
26
17
 
27
18
  ## About
28
19
 
29
20
  *Bunny* is an [AMQP](http://www.amqp.org) (Advanced Message Queuing Protocol) client, written in Ruby, that is intended to allow you to interact with AMQP-compliant message brokers/servers such as [RabbitMQ](http://www.rabbitmq.com) in a synchronous fashion.
30
21
 
22
+ It is based on a great deal of fabulous code from [amqp](http://github.com/tmm1/amqp) by Aman Gupta and [Carrot](http://github.com/famoseagle/carrot) by Amos Elliston.
23
+
31
24
  You can use *Bunny* to -
32
25
 
33
26
  * Create and delete exchanges
@@ -43,12 +36,7 @@ You can use *Bunny* to -
43
36
  b = Bunny.new(:logging => true)
44
37
 
45
38
  # start a communication session with the amqp server
46
- begin
47
- b.start
48
- rescue Exception => e
49
- puts 'ERROR - Could not start a session: ' + e
50
- exit
51
- end
39
+ b.start
52
40
 
53
41
  # declare a queue
54
42
  q = b.queue('test1')
@@ -110,12 +98,15 @@ Queue#message_count
110
98
  ### Return queue consumer count
111
99
  Queue#consumer_count
112
100
 
113
- ### Return queue status (array of message count and consumer_count)
101
+ ### Return queue status (hash {:message count, :consumer_count})
114
102
  Queue#status
115
103
 
116
104
  ### Delete a queue from the target server
117
105
  Queue#delete({_options_})
118
106
 
107
+ ### Acknowledge receipt of a message
108
+ Queue#ack
109
+
119
110
  ## Acknowledgements
120
111
 
121
112
  This project has borrowed heavily from the following two projects and owes their respective creators and collaborators a whole lot of gratitude:
@@ -0,0 +1,44 @@
1
+ # fanout.rb
2
+
3
+ # Assumes that target message broker/server has a user called 'guest' with a password 'guest'
4
+ # and that it is running on 'localhost'.
5
+
6
+ # If this is not the case, please change the 'Bunny.new' call below to include
7
+ # the relevant arguments e.g. b = Bunny.new(:user => 'john', :pass => 'doe', :host => 'foobar')
8
+
9
+ $:.unshift File.dirname(__FILE__) + '/../lib'
10
+
11
+ require 'bunny'
12
+
13
+ b = Bunny.new(:logging => true)
14
+
15
+ # start a communication session with the amqp server
16
+ begin
17
+ b.start
18
+ rescue Exception => e
19
+ puts 'ERROR - Could not start a session: ' + e
20
+ exit
21
+ end
22
+
23
+ # declare queues
24
+ q1 = b.queue('test_fan1')
25
+ q2 = b.queue('test_fan2')
26
+
27
+ # create a fanout exchange
28
+ exch = b.exchange('test_fan', :type => :fanout)
29
+
30
+ # bind the queues to the exchange
31
+ q1.bind(exch)
32
+ q2.bind(exch)
33
+
34
+ # publish a message to the exchange
35
+ exch.publish('This message will be fanned out')
36
+
37
+ # get message from the queues
38
+ msg = q1.pop
39
+ puts 'This is the message from q1: ' + msg + "\n\n"
40
+ msg = q2.pop
41
+ puts 'This is the message from q2: ' + msg + "\n\n"
42
+
43
+ # close the client connection
44
+ b.stop
data/examples/simple.rb CHANGED
@@ -13,12 +13,7 @@ require 'bunny'
13
13
  b = Bunny.new(:logging => true)
14
14
 
15
15
  # start a communication session with the amqp server
16
- begin
17
- b.start
18
- rescue Exception => e
19
- puts 'ERROR - Could not start a session: ' + e
20
- exit
21
- end
16
+ b.start
22
17
 
23
18
  # declare a queue
24
19
  q = b.queue('test1')
@@ -0,0 +1,33 @@
1
+ # simple_ack.rb
2
+
3
+ # Assumes that target message broker/server has a user called 'guest' with a password 'guest'
4
+ # and that it is running on 'localhost'.
5
+
6
+ # If this is not the case, please change the 'Bunny.new' call below to include
7
+ # the relevant arguments e.g. b = Bunny.new(:user => 'john', :pass => 'doe', :host => 'foobar')
8
+
9
+ $:.unshift File.dirname(__FILE__) + '/../lib'
10
+
11
+ require 'bunny'
12
+
13
+ b = Bunny.new(:logging => true)
14
+
15
+ # start a communication session with the amqp server
16
+ b.start
17
+
18
+ # declare a queue
19
+ q = b.queue('test1')
20
+
21
+ # publish a message to the queue
22
+ q.publish('Testing acknowledgements')
23
+
24
+ # get message from the queue
25
+ msg = q.pop(:ack => true)
26
+
27
+ # acknowledge receipt of message
28
+ q.ack
29
+
30
+ puts 'This is the message: ' + msg + "\n\n"
31
+
32
+ # close the client connection
33
+ b.stop
@@ -0,0 +1,36 @@
1
+ # consumer.rb
2
+
3
+ # N.B. To be used in conjunction with publisher.rb - RUN THIS BEFORE simple_publisher.rb
4
+
5
+ # Assumes that target message broker/server has a user called 'guest' with a password 'guest'
6
+ # and that it is running on 'localhost'.
7
+
8
+ # If this is not the case, please change the 'Bunny.new' call below to include
9
+ # the relevant arguments e.g. b = Bunny.new(:user => 'john', :pass => 'doe', :host => 'foobar')
10
+
11
+ $:.unshift File.dirname(__FILE__) + '/../lib'
12
+
13
+ require 'bunny'
14
+
15
+ b = Bunny.new(:logging => true)
16
+
17
+ # start a communication session with the amqp server
18
+ b.start
19
+
20
+ # create/get queue
21
+ q = b.queue('po_box')
22
+
23
+ # create/get exchange
24
+ exch = b.exchange('sorting_room')
25
+
26
+ # bind queue to exchange
27
+ q.bind(exch, :key => 'fred')
28
+
29
+ # subscribe to queue
30
+ msg = q.subscribe(:consumer_tag => 'testtag1')
31
+
32
+ # output received message
33
+ puts msg
34
+
35
+ # close the connection
36
+ b.stop
@@ -0,0 +1,33 @@
1
+ # simple_publisher.rb
2
+
3
+ # N.B. To be used in conjunction with simple_consumer.rb
4
+
5
+ # Assumes that target message broker/server has a user called 'guest' with a password 'guest'
6
+ # and that it is running on 'localhost'.
7
+
8
+ # If this is not the case, please change the 'Bunny.new' call below to include
9
+ # the relevant arguments e.g. b = Bunny.new(:user => 'john', :pass => 'doe', :host => 'foobar')
10
+
11
+ $:.unshift File.dirname(__FILE__) + '/../lib'
12
+
13
+ require 'bunny'
14
+
15
+ b = Bunny.new(:logging => true)
16
+
17
+ # start a communication session with the amqp server
18
+ b.start
19
+
20
+ # create/get queue
21
+ q = b.queue('po_box')
22
+
23
+ # create/get exchange
24
+ exch = b.exchange('sorting_room')
25
+
26
+ # bind queue to exchange
27
+ q.bind(exch, :key => 'fred')
28
+
29
+ # publish message to exchange
30
+ exch.publish('This is a message from the publisher', :key => 'fred')
31
+
32
+ # message should now be picked up by the consumer so we can stop
33
+ b.stop
data/lib/amqp.rb CHANGED
@@ -3,10 +3,14 @@ module AMQP
3
3
  require "amqp/#{file}"
4
4
  end
5
5
 
6
- # constants
6
+ # return messages
7
7
  CONNECTED = 'CONNECTED'
8
8
  NOT_CONNECTED = 'NOT CONNECTED'
9
9
  QUEUE_EMPTY = 'QUEUE EMPTY'
10
+ QUEUE_DELETED = 'QUEUE DELETED'
11
+ EXCHANGE_DELETED = 'EXCHANGE DELETED'
12
+ BIND_SUCCEEDED = 'BIND SUCCEEDED'
13
+ UNBIND_SUCCEEDED = 'UNBIND SUCCEEDED'
10
14
 
11
15
  # specific error definitions
12
16
  class ProtocolError < StandardError; end
@@ -65,6 +65,9 @@ class Bunny
65
65
  client.next_method.is_a?(Protocol::Exchange::DeleteOk)
66
66
 
67
67
  client.exchanges.delete(name)
68
+
69
+ # return confirmation
70
+ EXCHANGE_DELETED
68
71
  end
69
72
 
70
73
  end
data/lib/bunny/queue.rb CHANGED
@@ -24,15 +24,28 @@ class Bunny
24
24
 
25
25
  raise ProtocolError, "Error declaring queue #{name}" unless client.next_method.is_a?(Protocol::Queue::DeclareOk)
26
26
  end
27
+
28
+ def ack
29
+ client.send_frame(
30
+ Protocol::Basic::Ack.new(:delivery_tag => delivery_tag)
31
+ )
32
+
33
+ # reset delivery tag
34
+ self.delivery_tag = nil
35
+ end
27
36
 
28
37
  def pop(opts = {})
38
+
29
39
  # do we want the message header?
30
40
  hdr = opts.delete(:header)
31
41
 
42
+ # do we want to have to provide an acknowledgement?
43
+ ack = opts.delete(:ack)
44
+
32
45
  client.send_frame(
33
46
  Protocol::Basic::Get.new({ :queue => name,
34
47
  :consumer_tag => name,
35
- :no_ack => !opts.delete(:ack),
48
+ :no_ack => !ack,
36
49
  :nowait => true }.merge(opts))
37
50
  )
38
51
 
@@ -44,6 +57,9 @@ class Bunny
44
57
  raise ProtocolError, "Error getting message from queue #{name}"
45
58
  end
46
59
 
60
+ # get delivery tag to use for acknowledge
61
+ self.delivery_tag = method.delivery_tag if ack
62
+
47
63
  header = client.next_payload
48
64
  msg = client.next_payload
49
65
  raise MessageError, 'unexpected length' if msg.length < header.size
@@ -57,20 +73,58 @@ class Bunny
57
73
  end
58
74
 
59
75
  def message_count
60
- status.first
76
+ s = status
77
+ s[:message_count]
61
78
  end
62
79
 
63
80
  def consumer_count
64
- status.last
81
+ s = status
82
+ s[:consumer_count]
65
83
  end
66
84
 
67
- def status(opts = {}, &blk)
85
+ def status(opts = {})
68
86
  client.send_frame(
69
87
  Protocol::Queue::Declare.new({ :queue => name, :passive => true }.merge(opts))
70
88
  )
71
89
  method = client.next_method
72
- [method.message_count, method.consumer_count]
90
+ {:message_count => method.message_count, :consumer_count => method.consumer_count}
73
91
  end
92
+
93
+ def subscribe(opts = {})
94
+ consumer_tag = opts[:consumer_tag] || name
95
+
96
+ # ignore the :nowait option if passed, otherwise program will not wait for a
97
+ # message to get to the server causing an error
98
+ opts.delete(:nowait)
99
+
100
+ # do we want the message header?
101
+ hdr = opts.delete(:header)
102
+
103
+ # do we want to have to provide an acknowledgement?
104
+ ack = opts.delete(:ack)
105
+
106
+ client.send_frame(
107
+ Protocol::Basic::Consume.new({ :queue => name,
108
+ :consumer_tag => consumer_tag,
109
+ :no_ack => !ack,
110
+ :nowait => false }.merge(opts))
111
+ )
112
+
113
+ raise ProtocolError,
114
+ "Error subscribing to queue #{name}" unless
115
+ client.next_method.is_a?(Protocol::Basic::ConsumeOk)
116
+
117
+ method = client.next_method
118
+
119
+ # get delivery tag to use for acknowledge
120
+ self.delivery_tag = method.delivery_tag if ack
121
+
122
+ header = client.next_payload
123
+ msg = client.next_payload
124
+ raise MessageError, 'unexpected length' if msg.length < header.size
125
+
126
+ hdr ? {:header => header, :payload => msg} : msg
127
+ end
74
128
 
75
129
  def bind(exchange, opts = {})
76
130
  exchange = exchange.respond_to?(:name) ? exchange.name : exchange
@@ -90,6 +144,9 @@ class Bunny
90
144
  raise ProtocolError,
91
145
  "Error binding queue #{name}" unless
92
146
  client.next_method.is_a?(Protocol::Queue::BindOk)
147
+
148
+ # return message
149
+ BIND_SUCCEEDED
93
150
  end
94
151
 
95
152
  def unbind(exchange, opts = {})
@@ -107,6 +164,9 @@ class Bunny
107
164
  raise ProtocolError,
108
165
  "Error unbinding queue #{name}" unless
109
166
  client.next_method.is_a?(Protocol::Queue::UnbindOk)
167
+
168
+ # return message
169
+ UNBIND_SUCCEEDED
110
170
  end
111
171
 
112
172
  def delete(opts = {})
@@ -123,6 +183,9 @@ class Bunny
123
183
  client.next_method.is_a?(Protocol::Queue::DeleteOk)
124
184
 
125
185
  client.queues.delete(name)
186
+
187
+ # return confirmation
188
+ QUEUE_DELETED
126
189
  end
127
190
 
128
191
  private
@@ -62,7 +62,8 @@ describe Bunny::Exchange do
62
62
 
63
63
  it "should be able to be deleted" do
64
64
  exch = @b.exchange('direct_exchange')
65
- exch.delete
65
+ res = exch.delete
66
+ res.should == 'EXCHANGE DELETED'
66
67
  @b.exchanges.has_key?('direct_exchange').should be false
67
68
  end
68
69
 
data/spec/queue_spec.rb CHANGED
@@ -22,25 +22,25 @@ describe Bunny::Queue do
22
22
  it "should ignore the :nowait option when binding to an exchange" do
23
23
  exch = @b.exchange('direct_exch')
24
24
  q = @b.queue('test0')
25
- q.bind(exch, :nowait => true)
25
+ q.bind(exch, :nowait => true).should == 'BIND SUCCEEDED'
26
26
  end
27
27
 
28
28
  it "should be able to bind to an exchange" do
29
29
  exch = @b.exchange('direct_exch')
30
30
  q = @b.queue('test1')
31
- q.bind(exch)
31
+ q.bind(exch).should == 'BIND SUCCEEDED'
32
32
  end
33
33
 
34
34
  it "should ignore the :nowait option when unbinding from an exchange" do
35
35
  exch = @b.exchange('direct_exch')
36
36
  q = @b.queue('test0')
37
- q.unbind(exch, :nowait => true)
37
+ q.unbind(exch, :nowait => true).should == 'UNBIND SUCCEEDED'
38
38
  end
39
39
 
40
40
  it "should be able to unbind from an exchange" do
41
41
  exch = @b.exchange('direct_exch')
42
42
  q = @b.queue('test1')
43
- q.unbind(exch)
43
+ q.unbind(exch).should == 'UNBIND SUCCEEDED'
44
44
  end
45
45
 
46
46
  it "should be able to publish a message" do
@@ -76,7 +76,8 @@ describe Bunny::Queue do
76
76
 
77
77
  it "should be able to be deleted" do
78
78
  q = @b.queue('test1')
79
- q.delete
79
+ res = q.delete
80
+ res.should == 'QUEUE DELETED'
80
81
  @b.queues.has_key?('test1').should be false
81
82
  end
82
83
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bunny
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Duncan
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-04-25 00:00:00 +01:00
12
+ date: 2009-04-27 00:00:00 +01:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -36,6 +36,10 @@ files:
36
36
  - lib/amqp/spec.rb
37
37
  - lib/bunny.rb
38
38
  - examples/simple.rb
39
+ - examples/fanout.rb
40
+ - examples/simple_consumer.rb
41
+ - examples/simple_publisher.rb
42
+ - examples/simple_ack.rb
39
43
  - spec/bunny_spec.rb
40
44
  - spec/exchange_spec.rb
41
45
  - spec/queue_spec.rb