toot 0.1.3 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 61eb3541be9eb9395b6186880b157f86a11ad5a6
4
- data.tar.gz: c1ae6a89295589372da37e5c0c96e67d4b8074b6
3
+ metadata.gz: 083d9404092e22b97c3cc28414d2a7544f00e4af
4
+ data.tar.gz: a384f7ab9ebc684a9374b2d6b24f4f1844717322
5
5
  SHA512:
6
- metadata.gz: 2f7a6502c9ab7f892ac5870e766800b35c5c678e7018c070d1141c15824bfeaf07ebae97e8e902e7c96e4ce21a44c6990bff634d28ee58753055ce857b1734b6
7
- data.tar.gz: f3da1d5b7acf29f6f3cca1fe3740da34014a7e5791e5691d9fef3270d2abd6da91748b2066189cb49f53efdf0a84747d4d1eab5f44dc3842b20e60a3d04de240
6
+ metadata.gz: fc56a2166877aad3957fa83a7a24342bac4191ab05df5b3d73fb409bb6e92740ff0592606cfa66a23741cba03bcc2f8163bddd5c4ec43bb1158a3fd454606201
7
+ data.tar.gz: 945bc0a83d6b9e0fc831346b835a2157fc21fbff6c0413a1df648853009bfff7cfb46fcb3245eddf9f68814759aae51fd63b16663ced58fd999064b81008ef45
data/README.md CHANGED
@@ -1,8 +1,170 @@
1
- # Toot
1
+ # Toot :postal_horn: :dash:
2
2
 
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/toot`. To experiment with that code, run `bin/console` for an interactive prompt.
3
+ Toot is a library for basic PubSub over HTTP. Toot fires off event
4
+ payloads, and provides lightweight Rack apps for handling event callbacks and
5
+ subscription management that you can mount up in any Rack compatible
6
+ app. All of these actions happen through Sidekiq providing asynchronous,
7
+ persistent, and fault-tolerant events.
4
8
 
5
- TODO: Delete this and the text above, and describe your gem
9
+ ## Usage
10
+
11
+ Toot is composed of several standalone components. An app can play the
12
+ rolls of an event publisher, subscriber, or both. It just depends on how
13
+ you configure it. Let's take a look at an example using two apps:
14
+ "publisher" and "subscriber".
15
+
16
+ ### Overview
17
+
18
+ Here is how you could publish an event on the channel "users.updated.v1"
19
+ from the "publisher" app and then subscribe to that channel on the
20
+ "subscriber" app.
21
+
22
+ ```ruby
23
+ # Publish an event
24
+ Toot.publish "users.updated.v1", id: 123
25
+
26
+ # Subscribe to an event
27
+ Toot.subscribe :publisher, "users.updated.v1", -> (event) {
28
+ puts "User with id #{event["id"]} was updated."
29
+ }
30
+ ```
31
+
32
+ The "subscriber" app has a named `source` called "publisher" that is
33
+ configured in the config block. Let's take a look at what configuration
34
+ looks like on both apps. First let's take a look at the publisher:
35
+
36
+ ```ruby
37
+ # Configuration on the publisher
38
+ Toot.config do |c|
39
+ c.channel_prefix = "org.example.publisher."
40
+ end
41
+
42
+ # Mount up the subscriptions service (e.g. For Rails in routes.rb)
43
+ match "/subscriptions", to: Toot::SubscriptionsService, via: :post
44
+ ```
45
+
46
+ We set the `channel_prefix` which will prepend all events we publish
47
+ with this string. This ensures that we don't have name collisions with
48
+ other publishers we may introduce.
49
+
50
+ The `Toot::SubscriptionsService` is a lightweight Rack app that can be
51
+ mounted up in any Rack compatible application. You can mount it at
52
+ whatever path you like. We'll need the full URL when we configure our
53
+ subscriber.
54
+
55
+ Let's take a look at the subscriber configuration now:
56
+
57
+ ```ruby
58
+ # Configuration on the subscriber
59
+ Toot.config do |c|
60
+ c.callback_url = "https://subscriber.example.org/callbacks"
61
+ c.source :publisher,
62
+ subscription_url: "https://publisher.example.org/subscriptions",
63
+ channel_prefix: "org.example.publisher."
64
+ end
65
+
66
+ # Mount up the handler service (e.g. For Rails in routes.rb)
67
+ match "/callbacks", to: Toot::HandlerService, via: :post
68
+ ```
69
+
70
+ The `source` option defines a new event source called "publisher". We
71
+ reference this name in any calls to `Toot.subscribe`. We define the
72
+ `subscription_url` to match the URL that we mounted up the
73
+ `Toot::SubscriptionsService` Rack app on the publisher, and the
74
+ `channel_prefix` should match the publisher's.
75
+
76
+ The `Toot::HandlerService` is the Rack app that handles the event
77
+ callback from the publisher. The `callback_url` configuration option
78
+ should match whatever URL you mount this Rack app to on your
79
+ application. This is used in the subscibe process to let the publisher
80
+ know how to notify us about a new event.
81
+
82
+ ### Event Lifecycle
83
+
84
+ If you're having trouble picturing how this is actually working let's
85
+ trace the journey of a newly published event from the "publisher" to the
86
+ "subscriber".
87
+
88
+ 1. Event is published using the `Event.publish` method.
89
+ 2. This enqueues a background job which checks the Database (Redis) for
90
+ subscribers to this channel and enqueues another job for each
91
+ subscriber it finds.
92
+ 3. The subscriber's callback URL is called with the event's data payload
93
+ 4. The subscriber enqueues a background job if it has a handler for this
94
+ event.
95
+ 5. This background job runs the actual event handler code.
96
+
97
+ ### Subscribing
98
+
99
+ Subscribing is handled by a callable class called
100
+ `Toot::RegistersSusbcriptions`. There is also a rake task available that
101
+ does the same thing called `toot:register_subscriptions`. If you are
102
+ using Rails this rake task will be available to you automatically.
103
+
104
+ ### Configuration
105
+
106
+ We've looked at an example, but let's look at the conifguration options
107
+ in greater detail.
108
+
109
+ * `channel_prefix`: This option sets a string that will be prepended to
110
+ all events published from this app. In all of our examples we've been
111
+ using the [reverse DNS notation][1], but you can use whatever
112
+ convention you'd like.
113
+ * `callback_url`: The event handler URL that this application will
114
+ register to remote publishers. It should match the full URL to
115
+ wherever you have mounted the `Toot::HandlerService` for this app.
116
+ * `http_connection`: An instance of Faraday::Connection which is used
117
+ for any external HTTP calls. You can use this to add custom middleware
118
+ for authorization, logging, or debugging.
119
+ * `redis_connection`: If you'd like to use a custom Redis connection you
120
+ can configure a callable here that yields a redis connection. By
121
+ default the Sidekiq Redis connection pool is used.
122
+ * `source`: This is a method call that defines a named source. It should
123
+ include a `subscription_url` option and a `channel_prefix` option.
124
+ * The first argument is the name of this source
125
+ * The `subscription_url` option is the URL to this source's
126
+ `Toot::SubscriptionsService` app.
127
+ * The `channel_prefix` should match this app's configured
128
+ channel_prefix. This ensures that event channel names will be built
129
+ correctly on the publisher side and on the subscriber side.
130
+ * `subscribe`: This is a method call that adds a subscription to a given
131
+ source's channel. It takes three arguments:
132
+ * The source name. This must match a previously defined source
133
+ * The channel suffix. This will be joined with the `channel_prefix`
134
+ configured on the source to form the full channel name.
135
+ * A callable event handler. The event object will be passed in as the
136
+ only argument.
137
+
138
+ ### The Event Object
139
+
140
+ The schema of the publisher's payload is a contract between publisher
141
+ and subscriber and is outside of the scope of this library. However,
142
+ Toot does provide some extra information to aid in debugging and general
143
+ happiness:
144
+
145
+ ```ruby
146
+ Toot.subscribe :publisher, "awesome.channel", -> (event) {
147
+ event.id # => "c6c4af6b-a227-4b0e-a7b5-5259d31cf98b"
148
+ event.timestamp # => 2015-10-23 11:50:09 -0500
149
+ event.channel # => "org.example.publisher.awesome.channel"
150
+ event.payload # => { "publisher_data" => 123 }
151
+ event["publisher_data"] # => 123
152
+ }
153
+ ```
154
+
155
+ ### Authentication
156
+
157
+ It is important to note that there is no authentication baked into
158
+ Toot's services. If you aren't running in a trusted environment (almost
159
+ everybody) you will need to wrap these Rack apps in some kind of
160
+ authentication middleware. In Rails, you can use the [constraints
161
+ routing config][2], or more generically, you can just decorate the
162
+ service with another callable object that does the authentication
163
+ checks.
164
+
165
+ **TODO:** Currently we don't have the ability to add credentials to
166
+ outgoing requests. This will need to be added before this problem is
167
+ 100% solved.
6
168
 
7
169
  ## Installation
8
170
 
@@ -20,17 +182,26 @@ Or install it yourself as:
20
182
 
21
183
  $ gem install toot
22
184
 
23
- ## Usage
185
+ ### Requirements
24
186
 
25
- TODO: Write usage instructions here
187
+ * Sidekiq (and therefore Redis)
188
+ * Ruby 2.1+ (or at least that's what's tested)
26
189
 
27
190
  ## Development
28
191
 
29
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake rspec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
192
+ After checking out the repo, run `bin/setup` to install dependencies.
193
+ Then, run `rake rspec` to run the tests. You can also run `bin/console`
194
+ for an interactive prompt that will allow you to experiment.
30
195
 
31
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
196
+ To install this gem onto your local machine, run `bundle exec rake
197
+ install`. To release a new version, update the version number in
198
+ `version.rb`, and then run `bundle exec rake release`, which will create
199
+ a git tag for the version, push git commits and tags, and push the
200
+ `.gem` file to [rubygems.org](https://rubygems.org).
32
201
 
33
202
  ## Contributing
34
203
 
35
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/toot.
204
+ Bug reports and pull requests are welcome on GitHub at https://github.com/watermarkchurch/toot.
36
205
 
206
+ [1]: https://en.wikipedia.org/wiki/Reverse_domain_name_notation
207
+ [2]: http://guides.rubyonrails.org/routing.html#advanced-constraints
data/Rakefile CHANGED
@@ -4,3 +4,10 @@ require "rspec/core/rake_task"
4
4
  RSpec::Core::RakeTask.new(:spec)
5
5
 
6
6
  task :default => :spec
7
+
8
+ task :environment do
9
+ $LOAD_PATH.unshift File.expand_path('../lib', __FILE__)
10
+ require 'toot'
11
+ end
12
+
13
+ load './lib/tasks/toot.rake'
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'rspec' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'pathname'
10
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require 'rubygems'
14
+ require 'bundler/setup'
15
+
16
+ load Gem.bin_path('rspec-core', 'rspec')
@@ -0,0 +1,6 @@
1
+ machine:
2
+ ruby:
3
+ version: 2.2.0
4
+ dependencies:
5
+ pre:
6
+ - gem install bundler --version='~>1.10'
@@ -0,0 +1,9 @@
1
+ task :environment
2
+
3
+ namespace :toot do
4
+ desc 'Register subscriptions with remote sources'
5
+ task :register_subscriptions => :environment do
6
+ Toot::RegistersSubscriptions.call
7
+ end
8
+ end
9
+
@@ -1,5 +1,54 @@
1
- require "toot/version"
1
+ require 'toot/version'
2
+
3
+ require 'faraday'
4
+ require 'sidekiq'
5
+
6
+ require 'toot/config'
7
+ require 'toot/event'
8
+ require 'toot/source'
9
+ require 'toot/subscription'
10
+
11
+ require 'toot/calls_event_callback'
12
+ require 'toot/calls_handlers'
13
+ require 'toot/handler_service'
14
+ require 'toot/publishes_event'
15
+ require 'toot/registers_subscriptions'
16
+ require 'toot/subscriptions_service'
2
17
 
3
18
  module Toot
4
- # Your code goes here...
19
+
20
+ class Error < StandardError; end
21
+ class ConfigError < Error; end
22
+ class CallbackFailure < Error; end
23
+ class RegisterSubscriptionFailure < Error; end
24
+
25
+ def self.config
26
+ if block_given?
27
+ yield config
28
+ else
29
+ @config ||= Config.new
30
+ end
31
+ end
32
+
33
+ def self.reset_config
34
+ @config = Config.new
35
+ end
36
+
37
+ def self.publish(channel, payload, prefix: config.channel_prefix)
38
+ Event.new(
39
+ channel: [prefix, channel].join,
40
+ payload: payload
41
+ ).publish
42
+ end
43
+
44
+ def self.subscribe(*args)
45
+ config.subscribe(*args)
46
+ end
47
+
48
+ def self.redis(connection=config.redis_connection, &block)
49
+ connection.call(&block)
50
+ end
51
+
5
52
  end
53
+
54
+ require 'toot/rails' if defined?(Rails)
@@ -0,0 +1,27 @@
1
+ require 'net/http'
2
+
3
+ module Toot
4
+ class CallsEventCallback
5
+ include Sidekiq::Worker
6
+
7
+ def perform(callback_url, event_data)
8
+ uri = URI(callback_url)
9
+
10
+ response = Toot.config.http_connection.post do |request|
11
+ request.url uri
12
+ request.body = event_data.to_json
13
+ request.headers["Content-Type"] = "application/json"
14
+ end
15
+
16
+ if response.success?
17
+ if response.headers["X-Toot-Unsubscribe"]
18
+ Toot.redis do |r|
19
+ r.srem event_data["channel"], callback_url
20
+ end
21
+ end
22
+ else
23
+ raise CallbackFailure, "Response code: #{response.status}"
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,13 @@
1
+ module Toot
2
+ class CallsHandlers
3
+ include Sidekiq::Worker
4
+
5
+ def perform(event_data)
6
+ event = Event.new(event_data)
7
+ Toot.config
8
+ .subscriptions_for_channel(event.channel)
9
+ .each { |s| s.handler.call(event) }
10
+ end
11
+
12
+ end
13
+ end
@@ -0,0 +1,58 @@
1
+ module Toot
2
+ CONFIG_ATTRS = %i[
3
+ channel_prefix
4
+ http_connection
5
+ redis_connection
6
+ callback_url
7
+ ]
8
+
9
+ class Config < Struct.new(*CONFIG_ATTRS)
10
+
11
+ def source(name, subscription_url:, channel_prefix:)
12
+ Source.new(
13
+ name: name,
14
+ subscription_url: subscription_url,
15
+ channel_prefix: channel_prefix
16
+ ).tap do |source|
17
+ sources << source
18
+ end
19
+ end
20
+
21
+ def subscribe(source_name, channel_suffix, handler)
22
+ source = find_source_by_name(source_name) or
23
+ fail(ConfigError, "You cannot subscribe to an undefined source: #{source_name}")
24
+ Subscription.new(
25
+ source: source,
26
+ channel: [source.channel_prefix, channel_suffix].join,
27
+ handler: handler
28
+ ).tap do |subscription|
29
+ subscriptions << subscription
30
+ end
31
+ end
32
+
33
+ def sources
34
+ @sources ||= []
35
+ end
36
+
37
+ def subscriptions
38
+ @subscriptions ||= []
39
+ end
40
+
41
+ def find_source_by_name(name)
42
+ sources.find { |source| source.name == name }
43
+ end
44
+
45
+ def subscriptions_for_channel(channel)
46
+ subscriptions.select { |s| s.channel == channel }
47
+ end
48
+
49
+ def http_connection
50
+ self[:http_connection] ||= Faraday::Connection.new
51
+ end
52
+
53
+ def redis_connection
54
+ self[:redis_connection] ||= Sidekiq.method(:redis)
55
+ end
56
+
57
+ end
58
+ end
@@ -0,0 +1,46 @@
1
+ require 'securerandom'
2
+
3
+ module Toot
4
+ class Event
5
+
6
+ attr_accessor :id, :timestamp, :payload, :channel
7
+
8
+ DEFAULTS = -> {
9
+ {
10
+ id: SecureRandom.uuid,
11
+ timestamp: Time.now,
12
+ payload: {},
13
+ }
14
+ }
15
+
16
+ def initialize(args={})
17
+ args = DEFAULTS.().merge(args.symbolize_keys)
18
+ @id = args[:id]
19
+ @timestamp = args[:timestamp]
20
+ @payload = args[:payload]
21
+ @channel = args[:channel]
22
+ end
23
+
24
+ def publish
25
+ PublishesEvent.perform_async(to_h)
26
+ self
27
+ end
28
+
29
+ def to_h
30
+ {
31
+ id: id,
32
+ timestamp: timestamp,
33
+ payload: payload,
34
+ channel: channel,
35
+ }
36
+ end
37
+
38
+ def ==(other)
39
+ self.id == other.id
40
+ end
41
+
42
+ def [](key)
43
+ payload[key]
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,25 @@
1
+ require 'rack'
2
+
3
+ module Toot
4
+ class HandlerService
5
+
6
+ def call(env)
7
+ request = Rack::Request.new(env)
8
+ response = Rack::Response.new
9
+ event_data = JSON.parse(request.body.read)
10
+
11
+ if Toot.config.subscriptions_for_channel(event_data["channel"]).any?
12
+ CallsHandlers.perform_async(event_data)
13
+ else
14
+ response["X-Toot-Unsubscribe"] = "True"
15
+ end
16
+
17
+ response.finish
18
+ end
19
+
20
+ def self.call(env)
21
+ new.call(env)
22
+ end
23
+
24
+ end
25
+ end
@@ -0,0 +1,19 @@
1
+ module Toot
2
+ class PublishesEvent
3
+ include Sidekiq::Worker
4
+
5
+ def perform(event_data)
6
+ event = Event.new(event_data)
7
+ channel_callback_urls(event.channel)
8
+ .map { |callback| CallsEventCallback.perform_async(callback, event_data) }
9
+ end
10
+
11
+ private
12
+
13
+ def channel_callback_urls(channel)
14
+ Toot.redis do |r|
15
+ r.smembers channel
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,9 @@
1
+ module Toot
2
+ class Rails < Rails::Railtie
3
+ rake_tasks do
4
+ Dir.glob(File.expand_path("../../tasks/*.rake", __FILE__)).each do |rake_file|
5
+ load rake_file
6
+ end
7
+ end
8
+ end if defined?(Rails::Railtie)
9
+ end
@@ -0,0 +1,36 @@
1
+ module Toot
2
+ class RegistersSubscriptions
3
+
4
+ def call
5
+ subscriptions = Toot.config
6
+ .subscriptions
7
+ .each_with_object({}) { |s, hash| hash[[s.source, s.channel]] = s }
8
+ .values
9
+
10
+ subscriptions.each do |subscription|
11
+ register(subscription)
12
+ end
13
+ end
14
+
15
+ def self.call(*args)
16
+ new.call(*args)
17
+ end
18
+
19
+ private def register(subscription)
20
+ uri = URI(subscription.source.subscription_url)
21
+
22
+ response = Toot.config.http_connection.post uri do |request|
23
+ request.body = {
24
+ callback_url: Toot.config.callback_url,
25
+ channel: subscription.channel,
26
+ }.to_json
27
+ request.headers["Content-Type"] = "application/json"
28
+ end
29
+
30
+ unless response.success?
31
+ raise RegisterSubscriptionFailure, "Response code: #{response.status}"
32
+ end
33
+ end
34
+
35
+ end
36
+ end
@@ -0,0 +1,13 @@
1
+ module Toot
2
+ class Source
3
+
4
+ attr_accessor :name, :subscription_url, :channel_prefix
5
+
6
+ def initialize(name:, subscription_url:, channel_prefix:)
7
+ @name = name
8
+ @subscription_url = subscription_url
9
+ @channel_prefix = channel_prefix
10
+ end
11
+
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ module Toot
2
+ class Subscription
3
+
4
+ attr_accessor :source, :channel, :handler
5
+
6
+ def initialize(source:, channel:, handler:)
7
+ @source = source
8
+ @channel = channel
9
+ @handler = handler
10
+ end
11
+
12
+ end
13
+ end
@@ -0,0 +1,31 @@
1
+ module Toot
2
+ class SubscriptionsService
3
+
4
+ def call(env)
5
+ request = Rack::Request.new(env)
6
+ response = Rack::Response.new
7
+ json = parse_body_json(request)
8
+
9
+ if json["channel"] && json["callback_url"]
10
+ Toot.redis do |r|
11
+ r.sadd json["channel"], json["callback_url"]
12
+ end
13
+ else
14
+ response.status = 422
15
+ end
16
+
17
+ response.finish
18
+ end
19
+
20
+ def self.call(env)
21
+ new.call(env)
22
+ end
23
+
24
+ private def parse_body_json(request)
25
+ JSON.parse(request.body.read)
26
+ rescue JSON::ParserError
27
+ {}
28
+ end
29
+
30
+ end
31
+ end
@@ -1,3 +1,3 @@
1
1
  module Toot
2
- VERSION = "0.1.3"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -9,8 +9,8 @@ Gem::Specification.new do |spec|
9
9
  spec.authors = ["Travis Petticrew"]
10
10
  spec.email = ["travis@petticrew.net"]
11
11
 
12
- spec.summary = %q{WIP: A tool for sounding off events to remote services}
13
- spec.description = %q{WIP: A tool for sounding off events to remote services}
12
+ spec.summary = %q{Send and receive events from remote services over HTTP.}
13
+ spec.description = %q{Send and receive events from remote services over HTTP.}
14
14
  spec.homepage = "https://github.com/watermarkchurch/toot"
15
15
 
16
16
  spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
@@ -18,7 +18,12 @@ Gem::Specification.new do |spec|
18
18
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
19
19
  spec.require_paths = ["lib"]
20
20
 
21
+ spec.add_dependency "sidekiq", ">=2"
22
+ spec.add_dependency "rack", ">=1"
23
+ spec.add_dependency "faraday", "<1"
24
+
21
25
  spec.add_development_dependency "bundler", "~> 1.10"
22
26
  spec.add_development_dependency "rake", "~> 10.0"
23
27
  spec.add_development_dependency "rspec"
28
+ spec.add_development_dependency "webmock"
24
29
  end
metadata CHANGED
@@ -1,15 +1,57 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: toot
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Travis Petticrew
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2015-10-16 00:00:00.000000000 Z
11
+ date: 2015-11-09 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: sidekiq
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '2'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '2'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rack
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '1'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '1'
41
+ - !ruby/object:Gem::Dependency
42
+ name: faraday
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "<"
46
+ - !ruby/object:Gem::Version
47
+ version: '1'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "<"
53
+ - !ruby/object:Gem::Version
54
+ version: '1'
13
55
  - !ruby/object:Gem::Dependency
14
56
  name: bundler
15
57
  requirement: !ruby/object:Gem::Requirement
@@ -52,7 +94,21 @@ dependencies:
52
94
  - - ">="
53
95
  - !ruby/object:Gem::Version
54
96
  version: '0'
55
- description: 'WIP: A tool for sounding off events to remote services'
97
+ - !ruby/object:Gem::Dependency
98
+ name: webmock
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ description: Send and receive events from remote services over HTTP.
56
112
  email:
57
113
  - travis@petticrew.net
58
114
  executables: []
@@ -66,8 +122,22 @@ files:
66
122
  - README.md
67
123
  - Rakefile
68
124
  - bin/console
125
+ - bin/rspec
69
126
  - bin/setup
127
+ - circle.yml
128
+ - lib/tasks/toot.rake
70
129
  - lib/toot.rb
130
+ - lib/toot/calls_event_callback.rb
131
+ - lib/toot/calls_handlers.rb
132
+ - lib/toot/config.rb
133
+ - lib/toot/event.rb
134
+ - lib/toot/handler_service.rb
135
+ - lib/toot/publishes_event.rb
136
+ - lib/toot/rails.rb
137
+ - lib/toot/registers_subscriptions.rb
138
+ - lib/toot/source.rb
139
+ - lib/toot/subscription.rb
140
+ - lib/toot/subscriptions_service.rb
71
141
  - lib/toot/version.rb
72
142
  - toot.gemspec
73
143
  homepage: https://github.com/watermarkchurch/toot
@@ -92,5 +162,5 @@ rubyforge_project:
92
162
  rubygems_version: 2.4.2
93
163
  signing_key:
94
164
  specification_version: 4
95
- summary: 'WIP: A tool for sounding off events to remote services'
165
+ summary: Send and receive events from remote services over HTTP.
96
166
  test_files: []