amqp 1.1.0.pre1 → 1.1.0.pre2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/ChangeLog.md +5 -0
- data/Gemfile +0 -2
- data/README.md +30 -24
- data/amqp.gemspec +0 -1
- data/lib/amq/protocol/get_response.rb +55 -0
- data/lib/amqp.rb +237 -3
- data/lib/amqp/auth_mechanism_adapter.rb +69 -0
- data/lib/amqp/auth_mechanism_adapter/external.rb +27 -0
- data/lib/amqp/auth_mechanism_adapter/plain.rb +24 -0
- data/lib/amqp/callbacks.rb +67 -0
- data/lib/amqp/channel.rb +517 -76
- data/lib/amqp/consumer.rb +200 -32
- data/lib/amqp/consumer_tag_generator.rb +20 -0
- data/lib/amqp/deferrable.rb +5 -0
- data/lib/amqp/entity.rb +71 -0
- data/lib/amqp/exchange.rb +266 -17
- data/lib/amqp/framing/string/frame.rb +36 -0
- data/lib/amqp/handlers_registry.rb +28 -0
- data/lib/amqp/openable.rb +58 -0
- data/lib/amqp/queue.rb +526 -19
- data/lib/amqp/session.rb +943 -70
- data/lib/amqp/settings.rb +157 -0
- data/lib/amqp/version.rb +1 -1
- data/spec/integration/authentication_spec.rb +1 -1
- data/spec/integration/extensions/rabbitmq/publisher_confirmations_spec.rb +0 -15
- data/spec/integration/store_and_forward_spec.rb +1 -1
- data/spec/spec_helper.rb +1 -1
- data/spec/unit/amqp/client_spec.rb +3 -1
- data/spec/unit/amqp/connection_spec.rb +10 -41
- metadata +15 -19
- data/lib/amqp/client.rb +0 -100
- data/lib/amqp/connection.rb +0 -223
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bf6a9a0cb453a3921f7de2457b275a75be95f468
|
4
|
+
data.tar.gz: d8dc60d937d51493248f5813734cef62472504fd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3cb18aa1e1f532f2c82c32bc9ce6b0075fd43bf37952b2a8ada8f7f0bdfd043df13a5cf156b1c78d7b2d5cbbb6302987c6eeb9275af91d1ff1ba59a2a69b88bb
|
7
|
+
data.tar.gz: d18e7ff42f621a27ea2363adb1ac733fbc53bb6880cee7b0b7b0b88fcbbb8392aec9236499b61a9f4475a20172211a861184eb337843431e1f7ebfb02e932fb2
|
data/ChangeLog.md
CHANGED
@@ -1,5 +1,10 @@
|
|
1
1
|
## Changes Between 1.0.0 and 1.1.0
|
2
2
|
|
3
|
+
### AMQ::Client is Removed
|
4
|
+
|
5
|
+
`amq-client` has been incorporated into amqp gem. `AMQ::Client` and related
|
6
|
+
modules are no longer available.
|
7
|
+
|
3
8
|
### AMQP::Channel#confirm_select is Now Delayed
|
4
9
|
|
5
10
|
`AMQP::Channel#confirm_select` is now delayed until after the channel
|
data/Gemfile
CHANGED
@@ -15,8 +15,6 @@ def custom_gem(name, options = Hash.new)
|
|
15
15
|
end
|
16
16
|
|
17
17
|
custom_gem "eventmachine", ">= 1.0.0"
|
18
|
-
# gem "json", :platform => :ruby_18
|
19
|
-
custom_gem "amq-client", :git => "git://github.com/ruby-amqp/amq-client.git", :branch => "master"
|
20
18
|
custom_gem "amq-protocol", :git => "git://github.com/ruby-amqp/amq-protocol.git", :branch => "master"
|
21
19
|
|
22
20
|
group :development do
|
data/README.md
CHANGED
@@ -1,25 +1,39 @@
|
|
1
1
|
# Ruby amqp gem: the asynchronous Ruby RabbitMQ client
|
2
2
|
|
3
|
-
[Ruby amqp gem](http://rubyamqp.info) is a widely used, feature-rich, well-maintained asynchronous
|
4
|
-
This library works with
|
3
|
+
[Ruby amqp gem](http://rubyamqp.info) is a widely used, feature-rich, well-maintained asynchronous RabbitMQ client with batteries included.
|
4
|
+
This library works with
|
5
|
+
|
6
|
+
* Ruby 2.0
|
7
|
+
* Ruby 1.9.3
|
8
|
+
* [JRuby](http://jruby.org)
|
9
|
+
* [Rubinius](http://rubini.us)
|
10
|
+
* Ruby 1.9.2
|
11
|
+
* Ruby 1.8.7 (*except for p249*, see the FAQ)
|
12
|
+
* [REE](http://www.rubyenterpriseedition.com),
|
13
|
+
|
14
|
+
and is licensed under the [Ruby License](http://www.ruby-lang.org/en/LICENSE.txt)
|
5
15
|
|
6
16
|
0.8.0 and later versions of amqp gem implement [AMQP 0.9.1](http://www.rabbitmq.com/tutorials/amqp-concepts.html) (see also [AMQP 0.9.1 spec document](http://bit.ly/amqp091spec)) and support [RabbitMQ extensions to AMQP 0.9.1](http://www.rabbitmq.com/extensions.html).
|
7
17
|
|
8
18
|
|
9
|
-
## I know what
|
19
|
+
## I know what RabbitMQ is, how do I get started?
|
10
20
|
|
11
21
|
See [Getting started with amqp gem](http://rubyamqp.info/articles/getting_started/) and other [amqp gem documentation guides](http://rubyamqp.info/).
|
12
22
|
We recommend that you read [AMQP 0.9.1 Model Explained](http://www.rabbitmq.com/tutorials/amqp-concepts.html), too.
|
13
23
|
|
14
24
|
|
15
25
|
|
16
|
-
## What is
|
26
|
+
## What is RabbitMQ?
|
17
27
|
|
18
|
-
|
19
|
-
|
28
|
+
RabbitMQ is an open source messaging middleware that emphasizes
|
29
|
+
interoperability between different technologies (for example, Java,
|
30
|
+
.NET, Ruby, Python, Node.js, Erlang, Go, C and so on).
|
20
31
|
|
21
|
-
Key features of
|
22
|
-
|
32
|
+
Key features of RabbitMQ are very flexible yet simple routing and
|
33
|
+
binary protocol efficiency. RabbitMQ supports many sophisticated
|
34
|
+
features, for example, message acknowledgements, queue length limit,
|
35
|
+
message TTL, redelivery of messages that couldn't be processed, load
|
36
|
+
balancing between message consumers and so on.
|
23
37
|
|
24
38
|
|
25
39
|
## What is amqp gem good for?
|
@@ -83,25 +97,17 @@ On other OSes or [JRuby](http://jruby.org):
|
|
83
97
|
#!/usr/bin/env ruby
|
84
98
|
# encoding: utf-8
|
85
99
|
|
86
|
-
require "rubygems"
|
87
|
-
# or
|
88
|
-
#
|
89
|
-
# require "bundler"
|
90
|
-
# Bundler.setup
|
91
|
-
#
|
92
|
-
# if you use Bundler
|
93
|
-
|
94
100
|
require 'amqp'
|
95
101
|
|
96
102
|
EventMachine.run do
|
97
103
|
connection = AMQP.connect(:host => '127.0.0.1')
|
98
|
-
puts "Connecting to
|
104
|
+
puts "Connecting to RabbitMQ. Running #{AMQP::VERSION} version of the gem..."
|
99
105
|
|
100
|
-
|
101
|
-
|
102
|
-
|
106
|
+
ch = AMQP::Channel.new(connection)
|
107
|
+
q = ch.queue("amqpgem.examples.hello_world", :auto_delete => true)
|
108
|
+
x = ch.default_exchange
|
103
109
|
|
104
|
-
|
110
|
+
q.subscribe do |metadata, payload|
|
105
111
|
puts "Received a message: #{payload}. Disconnecting..."
|
106
112
|
|
107
113
|
connection.close {
|
@@ -109,14 +115,14 @@ EventMachine.run do
|
|
109
115
|
}
|
110
116
|
end
|
111
117
|
|
112
|
-
|
118
|
+
x.publish "Hello, world!", :routing_key => q.name
|
113
119
|
end
|
114
120
|
```
|
115
121
|
|
116
122
|
|
117
123
|
[Getting started guide](http://rubyamqp.info/articles/getting_started/) explains this and two more examples in detail,
|
118
|
-
and is written in a form of a tutorial. See [AMQP Model Explained](http://www.rabbitmq.com/tutorials/amqp-concepts.html) if you want
|
119
|
-
to learn more about
|
124
|
+
and is written in a form of a tutorial. See [AMQP 0.9.1 Model Explained](http://www.rabbitmq.com/tutorials/amqp-concepts.html) if you want
|
125
|
+
to learn more about RabbitMQ protocol principles & concepts.
|
120
126
|
|
121
127
|
|
122
128
|
|
data/amqp.gemspec
CHANGED
@@ -0,0 +1,55 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
# Purpose of this class is to simplify work with GetOk and GetEmpty.
|
4
|
+
module AMQ
|
5
|
+
module Protocol
|
6
|
+
class GetResponse
|
7
|
+
attr_reader :method
|
8
|
+
def initialize(method)
|
9
|
+
@method = method
|
10
|
+
end
|
11
|
+
|
12
|
+
def empty?
|
13
|
+
@method.is_a?(::AMQ::Protocol::Basic::GetEmpty)
|
14
|
+
end
|
15
|
+
|
16
|
+
# GetOk attributes
|
17
|
+
def delivery_tag
|
18
|
+
if @method.respond_to?(:delivery_tag)
|
19
|
+
@method.delivery_tag
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def redelivered
|
24
|
+
if @method.respond_to?(:redelivered)
|
25
|
+
@method.redelivered
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def exchange
|
30
|
+
if @method.respond_to?(:exchange)
|
31
|
+
@method.exchange
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def routing_key
|
36
|
+
if @method.respond_to?(:routing_key)
|
37
|
+
@method.routing_key
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def message_count
|
42
|
+
if @method.respond_to?(:message_count)
|
43
|
+
@method.message_count
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# GetEmpty attributes
|
48
|
+
def cluster_id
|
49
|
+
if @method.respond_to?(:cluster_id)
|
50
|
+
@method.cluster_id
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
data/lib/amqp.rb
CHANGED
@@ -1,16 +1,250 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
3
|
require "amq/protocol"
|
4
|
-
require "amq/client"
|
5
|
-
require "amq/client/adapters/event_machine"
|
6
4
|
|
7
5
|
require "amqp/version"
|
8
6
|
if RUBY_VERSION =~ /^1.8.7/
|
9
7
|
require "amqp/compatibility/ruby187_patchlevel_check"
|
10
8
|
end
|
9
|
+
|
10
|
+
require "amqp/handlers_registry"
|
11
|
+
require "amqp/callbacks"
|
12
|
+
require "amqp/entity"
|
13
|
+
|
11
14
|
require "amqp/exceptions"
|
12
|
-
require "amqp/
|
15
|
+
require "amqp/settings"
|
16
|
+
require "amqp/deferrable"
|
17
|
+
require "amqp/session"
|
13
18
|
require "amqp/exchange"
|
14
19
|
require "amqp/queue"
|
15
20
|
require "amqp/channel"
|
16
21
|
require "amqp/header"
|
22
|
+
|
23
|
+
# Top-level namespace of amqp gem. Please refer to "See also" section below.
|
24
|
+
#
|
25
|
+
# @see AMQP.connect
|
26
|
+
# @see AMQP.start
|
27
|
+
# @see AMQP::Channel
|
28
|
+
# @see AMQP::Exchange
|
29
|
+
# @see AMQP::Queue
|
30
|
+
module AMQP
|
31
|
+
|
32
|
+
# Starts EventMachine event loop unless it is already running and connects
|
33
|
+
# to AMQP broker using {AMQP.connect}. It is generally a good idea to
|
34
|
+
# start EventMachine event loop in a separate thread and use {AMQP.connect}
|
35
|
+
# (for Web applications that do not use Thin or Goliath, it is the only option).
|
36
|
+
#
|
37
|
+
# See {AMQP.connect} for information about arguments this method takes and
|
38
|
+
# information about relevant topics such as authentication failure handling.
|
39
|
+
#
|
40
|
+
# @example Using AMQP.start to connect to AMQP broker, EventMachine loop isn't yet running
|
41
|
+
# AMQP.start do |connection|
|
42
|
+
# # default is to connect to localhost:5672, to root ("/") vhost as guest/guest
|
43
|
+
#
|
44
|
+
# # this block never exits unless either AMQP.stop or EM.stop
|
45
|
+
# # is called.
|
46
|
+
#
|
47
|
+
# AMQP::Channel(connection) do |channel|
|
48
|
+
# channel.queue("", :auto_delete => true).bind(channel.fanout("amq.fanout")).subscribe do |headers, payload|
|
49
|
+
# # handle deliveries here
|
50
|
+
# end
|
51
|
+
# end
|
52
|
+
# end
|
53
|
+
#
|
54
|
+
# @api public
|
55
|
+
def self.start(connection_options_or_string = {}, other_options = {}, &block)
|
56
|
+
EM.run do
|
57
|
+
if !@connection || @connection.closed? || @connection.closing?
|
58
|
+
@connection = connect(connection_options_or_string, other_options, &block)
|
59
|
+
end
|
60
|
+
@channel = Channel.new(@connection)
|
61
|
+
@connection
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# Alias for {AMQP.start}
|
66
|
+
# @api public
|
67
|
+
def self.run(*args, &block)
|
68
|
+
self.start(*args, &block)
|
69
|
+
end
|
70
|
+
|
71
|
+
# Properly closes default AMQP connection and then underlying TCP connection.
|
72
|
+
# Pass it a block if you want a piece of code to be run once default connection
|
73
|
+
# is successfully closed.
|
74
|
+
#
|
75
|
+
# @note If default connection was never established or is in the closing state already,
|
76
|
+
# this method has no effect.
|
77
|
+
# @api public
|
78
|
+
def self.stop(reply_code = 200, reply_text = "Goodbye", &block)
|
79
|
+
return if @connection.nil? || self.closing?
|
80
|
+
|
81
|
+
EM.next_tick do
|
82
|
+
if AMQP.channel and AMQP.channel.open? and AMQP.channel.connection.open?
|
83
|
+
AMQP.channel.close
|
84
|
+
end
|
85
|
+
AMQP.channel = nil
|
86
|
+
|
87
|
+
|
88
|
+
shim = Proc.new {
|
89
|
+
block.call
|
90
|
+
|
91
|
+
AMQP.connection = nil
|
92
|
+
}
|
93
|
+
@connection.disconnect(reply_code, reply_text, &shim)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
# Indicates that default connection is closing.
|
98
|
+
#
|
99
|
+
# @return [Boolean]
|
100
|
+
# @api public
|
101
|
+
def self.closing?
|
102
|
+
@connection.closing?
|
103
|
+
end
|
104
|
+
|
105
|
+
# @return [Boolean] Current global logging value
|
106
|
+
# @api public
|
107
|
+
def self.logging
|
108
|
+
self.settings[:logging]
|
109
|
+
end
|
110
|
+
|
111
|
+
# @return [Boolean] Sets current global logging value
|
112
|
+
# @api public
|
113
|
+
def self.logging=(value)
|
114
|
+
self.settings[:logging] = !!value
|
115
|
+
end
|
116
|
+
|
117
|
+
# Default connection. When you do not pass connection instance to methods like
|
118
|
+
# {Channel#initialize}, AMQP gem will use this default connection.
|
119
|
+
#
|
120
|
+
# @api public
|
121
|
+
def self.connection
|
122
|
+
@connection
|
123
|
+
end
|
124
|
+
|
125
|
+
# "Default channel". A placeholder for apps that only want to use one channel. This channel is not global, *not* used
|
126
|
+
# under the hood by methods like {AMQP::Exchange#initialize} and only shared by exchanges/queues you decide on.
|
127
|
+
# To reiterate: this is only a conventience accessor, since many apps (especially Web apps) can get by with just one
|
128
|
+
# connection and one channel.
|
129
|
+
#
|
130
|
+
# @api public
|
131
|
+
def self.channel
|
132
|
+
@channel
|
133
|
+
end
|
134
|
+
|
135
|
+
# A placeholder for applications that only need one channel. If you use {AMQP.start} to set up default connection,
|
136
|
+
# {AMQP.channel} is open on that connection, but can be replaced by your application.
|
137
|
+
#
|
138
|
+
#
|
139
|
+
# @see AMQP.channel
|
140
|
+
# @api public
|
141
|
+
def self.channel=(value)
|
142
|
+
@channel = value
|
143
|
+
end
|
144
|
+
|
145
|
+
# Sets global connection object.
|
146
|
+
# @api public
|
147
|
+
def self.connection=(value)
|
148
|
+
@connection = value
|
149
|
+
end
|
150
|
+
|
151
|
+
# Alias for {AMQP.connection}
|
152
|
+
# @deprecated
|
153
|
+
# @api public
|
154
|
+
def self.conn
|
155
|
+
warn "AMQP.conn will be removed in 1.0. Please use AMQP.connection."
|
156
|
+
@connection
|
157
|
+
end
|
158
|
+
|
159
|
+
# Alias for {AMQP.connection=}
|
160
|
+
# @deprecated
|
161
|
+
# @api public
|
162
|
+
def self.conn=(value)
|
163
|
+
warn "AMQP.conn= will be removed in 1.0. Please use AMQP.connection=(connection)."
|
164
|
+
self.connection = value
|
165
|
+
end
|
166
|
+
|
167
|
+
# Connects to AMQP broker and yields connection object to the block as soon
|
168
|
+
# as connection is considered open.
|
169
|
+
#
|
170
|
+
#
|
171
|
+
# @example Using AMQP.connect with default connection settings
|
172
|
+
#
|
173
|
+
# AMQP.connect do |connection|
|
174
|
+
# AMQP::Channel.new(connection) do |channel|
|
175
|
+
# # channel is ready: set up your messaging flow by creating exchanges,
|
176
|
+
# # queues, binding them together and so on.
|
177
|
+
# end
|
178
|
+
# end
|
179
|
+
#
|
180
|
+
# @example Using AMQP.connect to connect to a public RabbitMQ instance with connection settings given as a hash
|
181
|
+
#
|
182
|
+
# AMQP.connect(:host => "dev.rabbitmq.com", :username => "guest", :password => "guest") do |connection|
|
183
|
+
# AMQP::Channel.new(connection) do |channel|
|
184
|
+
# # ...
|
185
|
+
# end
|
186
|
+
# end
|
187
|
+
#
|
188
|
+
#
|
189
|
+
# @example Using AMQP.connect to connect to a public RabbitMQ instance with connection settings given as a URI
|
190
|
+
#
|
191
|
+
# AMQP.connect "amqp://guest:guest@dev.rabbitmq.com:5672", :on_possible_authentication_failure => Proc.new { puts("Looks like authentication has failed") } do |connection|
|
192
|
+
# AMQP::Channel.new(connection) do |channel|
|
193
|
+
# # ...
|
194
|
+
# end
|
195
|
+
# end
|
196
|
+
#
|
197
|
+
#
|
198
|
+
# @overload connect(connection_string, options = {})
|
199
|
+
# Used to pass connection parameters as a connection string
|
200
|
+
# @param [String] :connection_string AMQP connection URI, à la JDBC connection string. For example: amqp://bus.megacorp.internal:5877/qa
|
201
|
+
#
|
202
|
+
#
|
203
|
+
# @overload connect(connection_options)
|
204
|
+
# Used to pass connection options as a Hash.
|
205
|
+
# @param [Hash] :connection_options AMQP connection options (:host, :port, :username, :vhost, :password)
|
206
|
+
#
|
207
|
+
# @option connection_options_or_string [String] :host ("localhost") Host to connect to.
|
208
|
+
# @option connection_options_or_string [Integer] :port (5672) Port to connect to.
|
209
|
+
# @option connection_options_or_string [String] :vhost ("/") Virtual host to connect to.
|
210
|
+
# @option connection_options_or_string [String] :username ("guest") Username to use. Also can be specified as :user.
|
211
|
+
# @option connection_options_or_string [String] :password ("guest") Password to use. Also can be specified as :pass.
|
212
|
+
# @option connection_options_or_string [Hash] :ssl TLS (SSL) parameters to use.
|
213
|
+
# @option connection_options_or_string [Fixnum] :heartbeat (0) Connection heartbeat, in seconds. 0 means no heartbeat. Can also be configured server-side starting with RabbitMQ 3.0.
|
214
|
+
# @option connection_options_or_string [#call] :on_tcp_connection_failure A callable object that will be run if connection to server fails
|
215
|
+
# @option connection_options_or_string [#call] :on_possible_authentication_failure A callable object that will be run if authentication fails (see Authentication failure section)
|
216
|
+
#
|
217
|
+
#
|
218
|
+
# h2. Handling authentication failures
|
219
|
+
#
|
220
|
+
# AMQP 0.9.1 specification dictates that broker closes TCP connection when it detects that authentication
|
221
|
+
# has failed. However, broker does exactly the same thing when other connection-level exception occurs
|
222
|
+
# so there is no way to guarantee that connection was closed because of authentication failure.
|
223
|
+
#
|
224
|
+
# Because of that, AMQP gem follows Java client example and hints at _possibility_ of authentication failure.
|
225
|
+
# To handle it, pass a callable object (a proc, a lambda, an instance of a class that responds to #call)
|
226
|
+
# with :on_possible_authentication_failure option.
|
227
|
+
#
|
228
|
+
# @note This method assumes that EventMachine even loop is already running. If it is not the case or you are not sure, we recommend you use {AMQP.start} instead.
|
229
|
+
# It takes exactly the same parameters.
|
230
|
+
# @return [AMQP::Session]
|
231
|
+
# @api public
|
232
|
+
def self.connect(connection_options_or_string = {}, other_options = {}, &block)
|
233
|
+
opts = case connection_options_or_string
|
234
|
+
when String then
|
235
|
+
AMQP::Settings.parse_connection_uri(connection_options_or_string)
|
236
|
+
when Hash then
|
237
|
+
connection_options_or_string
|
238
|
+
else
|
239
|
+
Hash.new
|
240
|
+
end
|
241
|
+
|
242
|
+
AMQP::Session.connect(opts.merge(other_options), &block)
|
243
|
+
end
|
244
|
+
|
245
|
+
# @return [Hash] Default AMQP connection settings. This hash may be modified.
|
246
|
+
# @api public
|
247
|
+
def self.settings
|
248
|
+
@settings ||= AMQP::Settings.default
|
249
|
+
end
|
250
|
+
end # AMQP
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module AMQP
|
4
|
+
# Provides a flexible method for encoding AMQP credentials. PLAIN and
|
5
|
+
# EXTERNAL are provided by this gem. In order to implement a new
|
6
|
+
# authentication mechanism, create a subclass like so:
|
7
|
+
#
|
8
|
+
# class MyAuthMechanism < AMQP::Async::AuthMechanismAdapter
|
9
|
+
# auth_mechanism "X-MYAUTH"
|
10
|
+
#
|
11
|
+
# def encode_credentials(username, password)
|
12
|
+
# # ...
|
13
|
+
# end
|
14
|
+
# end
|
15
|
+
class AuthMechanismAdapter
|
16
|
+
|
17
|
+
# Find and instantiate an AuthMechanismAdapter.
|
18
|
+
#
|
19
|
+
# @param [Adapter] adapter The Adapter for which to encode credentials.
|
20
|
+
# @return [AuthMechanismAdapter] An AuthMechanismAdapter that can encode
|
21
|
+
# credentials for the Adapter.
|
22
|
+
# @raise [NotImplementedError] The Adapter's mechanism does not
|
23
|
+
# correspond to any known AuthMechanismAdapter.
|
24
|
+
def self.for_adapter(adapter)
|
25
|
+
registry[adapter.mechanism].new adapter
|
26
|
+
end
|
27
|
+
|
28
|
+
protected
|
29
|
+
|
30
|
+
# Used by subclasses to declare the mechanisms that an
|
31
|
+
# AuthMechanismAdapter understands.
|
32
|
+
#
|
33
|
+
# @param [Array<String>] mechanisms One or more mechanisms that can be
|
34
|
+
# handled by the subclass.
|
35
|
+
def self.auth_mechanism(*mechanisms)
|
36
|
+
mechanisms.each {|mechanism| registry[mechanism] = self}
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
# Accesses the registry of AuthMechanismAdapter subclasses. Keys in
|
42
|
+
# this hash are the names of the authentication mechanisms; values are
|
43
|
+
# the classes that handle them. Referencing an unknown mechanism from
|
44
|
+
# this Hash will raise NotImplementedError.
|
45
|
+
def self.registry
|
46
|
+
@@registry ||= Hash.new {raise NotImplementedError}
|
47
|
+
end
|
48
|
+
|
49
|
+
public
|
50
|
+
|
51
|
+
# The Adapter that this AuthMechanismAdapter operates on behalf of.
|
52
|
+
attr_reader :adapter
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
# Create a new AuthMechanismAdapter. Users of this class should instead
|
57
|
+
# retrieve an instance through for_adapter.
|
58
|
+
def initialize(adapter)
|
59
|
+
@adapter = adapter
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# pre-require builtin auth mechanisms
|
65
|
+
Dir[File.join(File.dirname(__FILE__),
|
66
|
+
File.basename(__FILE__, '.rb'),
|
67
|
+
'*')].each do |f|
|
68
|
+
require f
|
69
|
+
end
|