fluffle 0.2.0 → 0.2.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2de3913524a4ba8c3270b96d5272f806c1b307e1
4
- data.tar.gz: f2d2d81a77fed5dd7ed95a79e70e986c53c5bca4
3
+ metadata.gz: 255eee82ad3d15d6a7b9623e2abc52327c0b029c
4
+ data.tar.gz: 9d0496f43f6f63e85b8de2d861d516959ec92cb5
5
5
  SHA512:
6
- metadata.gz: b33a3af2b4958527059766387e030d491d56ee05dbfc6e3141f57255f0c664680e575319fd2aa4cd38bbe7ae1466e6e00da17d82c111c81fc29bfa7c33b9a263
7
- data.tar.gz: a92a7984a455c82071dd492b50fa87ad9d81aa86bb7a6059fdc51a707a056e4fc9b505aa62678d2c1689cfad228cbb1a1953459f01143a93fa55ae5fdae32032
6
+ metadata.gz: 5dad9fde293a176c4b3f9cfe1c8dcc3cee2359f683db422d3e8a1f0273be9d84e57b5c24b1bd044a8f7416db58fa9d96551c87d4c1c19ee1e75ad31df9165e8c
7
+ data.tar.gz: 1d5e676a4db1978eda8e987c56d045ae137cd06345917ad10a0678db108d1b18d8240f9c2361ed47b00f4d512690443e3910fa99450e412198bd460b86e8cce7
data/README.md CHANGED
@@ -14,8 +14,10 @@ An implementation of [JSON-RPC][] over RabbitMQ through the [Bunny][] library. P
14
14
 
15
15
  ## Features
16
16
 
17
- - Client: Thread-safe blocking client (via [concurrent-ruby][])
18
- - Server: One-thread-per-queue implementation (multi-threaded coming soon)
17
+ Both the client and server implementations should be thread-safe, as their behavior is implemented on top of the excellent [concurrent-ruby][] gem's data structures.
18
+
19
+ - Client: Thread-safe client that can perform multiple requests concurrently
20
+ - Server: Single or multi-threaded server (one request/response per thread)
19
21
  - Server: Easy-to-use built-in handlers and straightforward API for building custom handlers
20
22
 
21
23
  [concurrent-ruby]: https://github.com/ruby-concurrency/concurrent-ruby
@@ -26,9 +28,41 @@ See the [`examples`](examples/) directory.
26
28
 
27
29
  The server provides a few options for handling RPC requests:
28
30
 
29
- - Dispatcher pattern: `dispatcher.handle('upcase') { |str| str.upcase }`
30
- - Delegator pattern: delegate will receive the `#upcase` message with a single argument (the string)
31
- - Custom: any handler needs to implement the API described in `Fluffle::Handlers::Base`
31
+ - [Dispatcher](lib/fluffle/handlers/dispatcher.rb): `dispatcher.handle('upcase') { |str| str.upcase }`
32
+ - [Delegator](lib/fluffle/handlers/delegator.rb): delegate will receive the `#upcase` message with a single argument (the string)
33
+ - Custom: any handler needs to implement the API described in [`Fluffle::Handlers::Base`](lib/fluffle/handlers/base.rb)
34
+
35
+ ### Basic server and client
36
+
37
+ A server has two basic requirements: the URL of a RabbitMQ server to connect to and one or more queues to drain (with a handler for each queue).
38
+
39
+ Below is a basic server providing an `upcase` method to return the upper cased version of its argument:
40
+
41
+ ```ruby
42
+ require 'fluffle'
43
+
44
+ server = Fluffle::Server.new url: 'amqp://localhost'
45
+
46
+ server.drain do |dispatcher|
47
+ dispatcher.handle('upcase') { |str| str.upcase }
48
+ end
49
+
50
+ server.start
51
+ ```
52
+
53
+ This example relies on a couple features of `Server#drain`:
54
+
55
+ 1. By default it will drain the `default` queue.
56
+ 2. You can provide a block to the method to have it set up a [`Dispatcher`](lib/fluffle/handlers/dispatcher.rb) handler and pass that in to the block.
57
+
58
+ And client to call that `upcase` method looks like:
59
+
60
+ ```ruby
61
+ client = Fluffle::Client.new url: 'amqp://localhost'
62
+
63
+ client.call 'upcase', ['Hello world!']
64
+ # => "HELLO WORLD!"
65
+ ```
32
66
 
33
67
  ## License
34
68
 
data/examples/client.rb CHANGED
@@ -4,6 +4,8 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
  require 'fluffle'
5
5
 
6
6
  client = Fluffle::Client.new url: 'amqp://localhost'
7
+ # You can also pass `connection:` to use an existing Bunny connection:
8
+ # Fluffle::Client.new(connection: Bunny.new('amqp://localhost', heartbeat: 2))
7
9
 
8
10
  timings = 10.times.map do
9
11
  t0 = Time.now
data/examples/server.rb CHANGED
@@ -3,7 +3,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
3
 
4
4
  require 'fluffle'
5
5
 
6
- server = Fluffle::Server.new url: 'amqp://localhost'
6
+ server = Fluffle::Server.new url: 'amqp://localhost', concurrency: 5
7
7
 
8
8
  server.drain do |dispatcher|
9
9
  dispatcher.handle('foo') { 'bar' }
@@ -12,12 +12,12 @@ module Fluffle
12
12
  attr_accessor :default_timeout
13
13
  attr_accessor :logger
14
14
 
15
- def initialize(url:)
15
+ def initialize(url: nil, connection: nil)
16
+ self.connect(url || connection)
17
+
16
18
  @default_timeout = 5
17
19
  @logger = Fluffle.logger
18
20
 
19
- self.connect url
20
-
21
21
  @uuid = UUIDTools::UUID.timestamp_create.to_s
22
22
  @channel = @connection.create_channel
23
23
  @exchange = @channel.default_exchange
@@ -9,7 +9,13 @@ module Fluffle
9
9
  def connect(*args)
10
10
  self.stop if self.connected?
11
11
 
12
- @connection = Bunny.new *args
12
+ @connection =
13
+ if args.first.is_a? Bunny::Session
14
+ args.first
15
+ else
16
+ Bunny.new *args
17
+ end
18
+
13
19
  @connection.start
14
20
  end
15
21
 
@@ -6,8 +6,9 @@ module Fluffle
6
6
 
7
7
  # url: - Optional URL to pass to `Bunny.new` to immediately connect
8
8
  # concurrency: - Number of threads to handle messages on (default: 1)
9
- def initialize(url: nil, concurrency: 1)
10
- self.connect(url) if url
9
+ def initialize(url: nil, connection: nil, concurrency: 1)
10
+ url_or_connection = url || connection
11
+ self.connect(url_or_connection) if url_or_connection
11
12
 
12
13
  @handlers = {}
13
14
  @handler_pool = Concurrent::FixedThreadPool.new concurrency
@@ -1,3 +1,3 @@
1
1
  module Fluffle
2
- VERSION = '0.2.0'
2
+ VERSION = '0.2.1'
3
3
  end
data/spec/client_spec.rb CHANGED
@@ -13,6 +13,33 @@ describe Fluffle::Client do
13
13
  end
14
14
  end
15
15
 
16
+ describe '#initialize' do
17
+ it 'allows user to pass an `amqp://` URL via `url:`' do
18
+ client = Fluffle::Client.new url: 'amqp://localhost'
19
+
20
+ expect(client.connection).to be_a Bunny::Session
21
+ expect(client.connected?).to eq true
22
+ end
23
+
24
+ it 'allows user to provide existing Bunny connection via `connection:`' do
25
+ bunny_channel = double 'Bunny::Channel',
26
+ default_exchange: double('Bunny::Exchange'),
27
+ queue: double('Bunny::Queue', subscribe: nil)
28
+
29
+ bunny_session = double 'Bunny::Session',
30
+ create_channel: bunny_channel,
31
+ start: nil,
32
+ connected?: true
33
+
34
+ allow(bunny_session).to receive(:is_a?).with(Bunny::Session).and_return(true)
35
+
36
+ client = Fluffle::Client.new connection: bunny_session
37
+
38
+ expect(client.connection).to eq bunny_session
39
+ expect(client.connected?).to eq true
40
+ end
41
+ end
42
+
16
43
  describe '#call' do
17
44
  def prepare_response(payload)
18
45
  ->(id) do
@@ -0,0 +1,26 @@
1
+ require 'spec_helper'
2
+
3
+ describe Fluffle::Handlers::Delegator do
4
+ before do
5
+ @delegated_object = double 'Delegated Object'
6
+
7
+ @handler = Fluffle::Handlers::Delegator.new @delegated_object
8
+ end
9
+
10
+ it 'calls the method with the params on the delegated object' do
11
+ param1 = 'One'
12
+ param2 = 'Two'
13
+ result = 'Three'
14
+
15
+ expect(@delegated_object).to receive(:some_method)
16
+ .with(param1, param2)
17
+ .and_return(result)
18
+
19
+ actual_result = @handler.call id: 'abc123',
20
+ method: 'some_method',
21
+ params: [param1, param2],
22
+ meta: {}
23
+
24
+ expect(actual_result).to eq(result)
25
+ end
26
+ end
@@ -0,0 +1,27 @@
1
+ require 'spec_helper'
2
+
3
+ describe Fluffle::Handlers::Dispatcher do
4
+ before do
5
+ @handler = Fluffle::Handlers::Dispatcher.new
6
+
7
+ @handler.handle('double_it') { |arg| arg * 2 }
8
+ end
9
+
10
+ it 'calls the method with the params on the delegated object' do
11
+ result = @handler.call id: 'abc123',
12
+ method: 'double_it',
13
+ params: [2],
14
+ meta: {}
15
+
16
+ expect(result).to eq(4)
17
+ end
18
+
19
+ it 'raises error if method not configured' do
20
+ expect {
21
+ @handler.call id: 'def456',
22
+ method: 'doesnt_exist',
23
+ params: ['whatever'],
24
+ meta: {}
25
+ }.to raise_error(NoMethodError, /doesnt_exist/)
26
+ end
27
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fluffle
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dirk Gadsden
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-08-14 00:00:00.000000000 Z
11
+ date: 2016-08-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bunny
@@ -139,6 +139,8 @@ files:
139
139
  - lib/fluffle/testing.rb
140
140
  - lib/fluffle/version.rb
141
141
  - spec/client_spec.rb
142
+ - spec/handlers/delegator_spec.rb
143
+ - spec/handlers/dispatcher_spec.rb
142
144
  - spec/server_spec.rb
143
145
  - spec/spec_helper.rb
144
146
  homepage: https://github.com/Everlane/fluffle