toot 0.1.3 → 0.2.0

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: 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: []