hookly 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 8fa80ff4c39928e6d5e8a0a6f789c7346d0da23f
4
+ data.tar.gz: e751e4408f4e131e8a9856d2315b10ff21ba359f
5
+ SHA512:
6
+ metadata.gz: 7bb848c28200fbfe0fc742091f34b8196dcfd2100189fa16c609e6dede135ae7295c15883c073861993b8e713e4b93680303d2c4f4671d6243ae53395e68aef5
7
+ data.tar.gz: cc8ae03b69889979098c526bce2da03b5f8c9164ef2f1646df0ad218085ae7ab235e8b4b69d11df3d88b007a2712e0179c07408fe689c895f3dfe153afbabfec
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ .DS_Store
2
+
3
+ *.gem
4
+ .bundle
5
+ Gemfile.lock
6
+
7
+ tmp
8
+ .ruby-version
9
+ .ruby-gemset
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/LICENSE.md ADDED
@@ -0,0 +1,22 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 Brian Norton
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
data/README.md ADDED
@@ -0,0 +1,75 @@
1
+ #hookly-rails
2
+
3
+ 1. Ruby wrapper for the Hookly API
4
+ 2. hookly.js asset pipeline provider/wrapper
5
+
6
+ Rails 3.1+ asset-pipeline gem to provide hookly.js
7
+
8
+ #Setup
9
+
10
+ Add to your Gemfile:
11
+
12
+ ```ruby
13
+ gem 'hookly-rails'
14
+ ```
15
+
16
+ ###JS Setup
17
+ Then add this to you application.js manifest:
18
+
19
+ ```javascript
20
+ //= require hookly
21
+ ```
22
+
23
+ Then check out the [hookly.js docs](https://github.com/bnorton/hookly.js) for usage and working examples
24
+
25
+ ###API Setup
26
+
27
+ ```ruby
28
+ # config/initializers/hookly.rb
29
+ Hookly.token = '{{token}}'
30
+ Hookly.secret = '{{secret}}'
31
+ ```
32
+
33
+ ###Post a message to the #updates channel
34
+
35
+ In the client javascript subscribe to '#updates'
36
+ ```javascript
37
+ hookly.setup('{{token}}')
38
+ hookly.on('#updates', function(options) {
39
+ // options == { model: 'Message', id: 5, text: 'Thanks for the info.' }
40
+ });
41
+ ```
42
+
43
+ The push a new message the updates channel
44
+ ```ruby
45
+ Hookly::Channel.new('#updates').push(model: 'Message', id: 5, text: 'Thanks for the info.')
46
+ #=> #<Hookly::Message id: '44fjwq-djas' slug: '#updates', data: { model: 'Message', id: 5, text: 'Thanks for the info.' }>
47
+ ```
48
+
49
+ ###Post a **private** message
50
+
51
+ Have information that only a certain user should see??
52
+
53
+ Include a unique user id on the client and server
54
+
55
+ ```javascript
56
+ hookly.setup('{{token}}', '{{uid}}')
57
+ hookly.on('#updates', function(options) {
58
+ // options == { model: 'Message', id: 6, text: 'Thanks for the PRIVATE info.' }
59
+ });
60
+ ```
61
+
62
+ ```ruby
63
+ Hookly::Channel.new('#updates', uid: '{{uid}}').push(model: 'Message', id: 6, text: 'Thanks for the PRIVATE info.')
64
+ #=> #<Hookly::Message id: '44fjwq-djas' slug: '#updates', uid: '{{uid}}' data: { model: 'Message', id: 6, text: 'Thanks for the PRIVATE info.' }>
65
+ ```
66
+
67
+
68
+ <!--- Not yet implemented
69
+ ###Message buffering / caching
70
+ A channel can be setup to buffer messages and deliver them when a user comes online.
71
+ Simply create a buffered channel, messages will be cached for 60 minutes following their receipt
72
+ ```ruby
73
+ Hookly::Channel.create(buffer: 3600)
74
+ ```
75
+ -->
data/hookly.gemspec ADDED
@@ -0,0 +1,23 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path('../lib', __FILE__)
3
+ require 'hookly/version'
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = 'hookly'
7
+ s.version = Hookly::VERSION
8
+ s.authors = ['Brian Norton']
9
+ s.email = ['brian.nort@gmail.com']
10
+ s.homepage = 'https://github.com/bnorton/hookly-rails'
11
+ s.summary = %q{hookly.js asset pipeline provider/wrapper. Ruby wrapper for the Hookly API}
12
+ s.license = 'MIT'
13
+
14
+ s.files = `git ls-files`.split("\n")
15
+ s.test_files = `git ls-files -- spec/*`.split("\n")
16
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
17
+ s.require_paths = ['lib']
18
+
19
+ s.add_development_dependency 'rspec', '~> 3.2'
20
+ s.add_development_dependency 'webmock', '~> 1.21'
21
+
22
+ s.add_dependency 'typhoeus', '~> 0.7'
23
+ end
data/lib/error.rb ADDED
@@ -0,0 +1 @@
1
+ require 'errors/response_error'
@@ -0,0 +1,7 @@
1
+ module Hookly
2
+ class ResponseError < StandardError
3
+ def initialize(response)
4
+ super "The request failed with code: `#{response.response_code}`"
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,8 @@
1
+ module Hookly
2
+ MAJOR = 0
3
+ MINOR = 9
4
+ PATCH = 0
5
+ PRE = nil
6
+
7
+ VERSION = [MAJOR, MINOR, PATCH, PRE].map(&:freeze).compact.join('.').freeze
8
+ end
data/lib/hookly.rb ADDED
@@ -0,0 +1,31 @@
1
+ ##
2
+ # Dependencies
3
+ #
4
+ require 'json'
5
+ require 'typhoeus'
6
+
7
+ ##
8
+ # Project files
9
+ #
10
+ require 'request'
11
+ require 'message'
12
+ require 'error'
13
+
14
+ module Hookly
15
+ %i(token secret url).each do |name|
16
+ define_singleton_method(name, &-> { instance_variable_get(:"@#{name}") })
17
+ define_singleton_method("#{name}=", &->(v) { instance_variable_set(:"@#{name}", v) })
18
+ end
19
+
20
+ module Rails
21
+ if defined?(::Rails)
22
+ class Rails::Engine < ::Rails::Engine
23
+ # this will enable the asset pipeline
24
+ end
25
+ end
26
+ end
27
+ end
28
+
29
+ require 'hookly/version'
30
+
31
+ Hookly.url = 'https://hookly.herokuapp.com'
data/lib/message.rb ADDED
@@ -0,0 +1,18 @@
1
+ module Hookly
2
+ class Message
3
+ attr_reader :id, :slug, :uid, :body
4
+
5
+ def self.create(slug, *args)
6
+ body = args.pop
7
+
8
+ new(Request.run(:post, :messages, { slug: slug, :uid => args.last }, body))
9
+ end
10
+
11
+ def initialize(options)
12
+ @id = options['id']
13
+ @slug = options['slug']
14
+ @uid = options['uid']
15
+ @body = options['body']
16
+ end
17
+ end
18
+ end
data/lib/request.rb ADDED
@@ -0,0 +1,35 @@
1
+ module Hookly
2
+ class Request
3
+ def self.run(name, path, options, body={})
4
+ request_options = {
5
+ method: name,
6
+ accept_encoding: :gzip,
7
+ headers: { 'Content-Type' => 'application/json', 'User-Agent' => user_agent }
8
+ }
9
+
10
+ request_options[body_param(name)] = processed_body(name, options.merge( secret: Hookly.secret, :body => body ))
11
+
12
+ response = Typhoeus::Request.new("#{Hookly.url}/#{path}", request_options).run
13
+
14
+ if response.success?
15
+ JSON.parse(response.response_body)['message']
16
+ else
17
+ raise ResponseError.new(response)
18
+ end
19
+ end
20
+
21
+ private
22
+
23
+ def self.user_agent
24
+ "hookly-rails [language(ruby), lib-version(#{Hookly::VERSION}), platform(#{RUBY_PLATFORM}), platform-version(#{RUBY_VERSION})]"
25
+ end
26
+
27
+ def self.body_param(name)
28
+ %w(get delete).include?(name.to_s) ? :params : :body
29
+ end
30
+
31
+ def self.processed_body(name, options)
32
+ %w(get delete).include?(name.to_s) ? options : JSON.dump(options)
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,3 @@
1
+ def run_response(options)
2
+ JSON.parse(options.to_json)
3
+ end
@@ -0,0 +1,3 @@
1
+ Hookly.token = 'test-config-token'
2
+ Hookly.secret = 'test-config-secret'
3
+ Hookly.url = 'http://test.host:1234'
File without changes
@@ -0,0 +1,50 @@
1
+ require 'spec_helper'
2
+
3
+ describe Hookly::Message do
4
+ describe '.create' do
5
+ let(:options) { { id: 5, text: 'Thanks for the information!' } }
6
+ let(:create) { described_class.create('#updates', options) }
7
+
8
+ let!(:response) { run_response(id: 1440, slug: '#updates', body: options) }
9
+
10
+ before do
11
+ allow(Hookly::Request).to receive(:run).and_return(response)
12
+ end
13
+
14
+ it 'should post to messages' do
15
+ expect(Hookly::Request).to receive(:run).with(:post, :messages, anything, anything).and_return(response)
16
+
17
+ create
18
+ end
19
+
20
+ it 'should specify the slug' do
21
+ expect(Hookly::Request).to receive(:run).with(anything, anything, hash_including(slug: '#updates'), anything).and_return(response)
22
+
23
+ create
24
+ end
25
+
26
+ it 'should send the body' do
27
+ expect(Hookly::Request).to receive(:run).with(anything, anything, anything, id: 5, text: 'Thanks for the information!').and_return(response)
28
+
29
+ create
30
+ end
31
+
32
+ it 'should return the message' do
33
+ expect(create).to be_a(Hookly::Message)
34
+ expect(create.id).to eq(1440)
35
+ expect(create.slug).to eq('#updates')
36
+ expect(create.uid).to eq(nil)
37
+ expect(create.body).to eq('id' => 5, 'text' => 'Thanks for the information!')
38
+ end
39
+
40
+ describe 'when given a user identifier' do
41
+ let(:create) { described_class.create('#updates', '5a17b-124f5', id: 5, text: 'Thanks for the information!' ) }
42
+
43
+ it 'should specify the uid' do
44
+ expect(Hookly::Request).to receive(:run).with(anything, anything, hash_including(uid: '5a17b-124f5'), anything).and_return(response)
45
+
46
+ create
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,90 @@
1
+ require 'spec_helper'
2
+
3
+ describe Hookly::Request do
4
+ describe '.run' do
5
+ let(:method) { %w(get post patch delete).sample }
6
+ let(:options) { { option1: 1, option2: 2 } }
7
+ let(:body) { double('Hash[body]') }
8
+ let(:run) { described_class.run(method, 'pathname', options, body) }
9
+
10
+ let!(:request) { double(:request, :run => response) }
11
+ let!(:response) { double(:response, :success? => true, :response_body => { response: 'body' }.to_json, :response_code => 900) }
12
+
13
+ before do
14
+ allow(Typhoeus::Request).to receive(:new).and_return(request)
15
+ end
16
+
17
+ it 'should send the url + path' do
18
+ expect(Typhoeus::Request).to receive(:new).with('http://test.host:1234/pathname', anything).and_return(request)
19
+
20
+ run
21
+ end
22
+
23
+ it 'should send the method' do
24
+ expect(Typhoeus::Request).to receive(:new).with(anything, hash_including(method: method)).and_return(request)
25
+
26
+ run
27
+ end
28
+
29
+ it 'should be json' do
30
+ expect(Typhoeus::Request).to receive(:new).with(anything, hash_including(headers: { 'Content-Type' => 'application/json', 'User-Agent' => "hookly-rails [language(ruby), lib-version(#{Hookly::VERSION}), platform(#{RUBY_PLATFORM}), platform-version(#{RUBY_VERSION})]" })).and_return(request)
31
+
32
+ run
33
+ end
34
+
35
+ it 'should run the request' do
36
+ expect(request).to receive(:run)
37
+
38
+ run
39
+ end
40
+
41
+ it 'should return the response body' do
42
+ expect(run).to eq({ 'response' => 'body' })
43
+ end
44
+
45
+ describe 'with a body' do
46
+ let(:method) { %w(post patch).sample }
47
+
48
+ it 'should send the auth + options + body' do
49
+ expected_body = { option1: 1, option2: 2, secret: 'test-config-secret', body: body }.to_json
50
+ expect(Typhoeus::Request).to receive(:new).with(anything, hash_including(body: expected_body)).and_return(request)
51
+
52
+ run
53
+ end
54
+ end
55
+
56
+ describe 'with url parameters' do
57
+ let(:method) { %w(get delete).sample }
58
+
59
+ it 'should send the auth + options + body' do
60
+ expected_params = { secret: 'test-config-secret', option1: 1, option2: 2, body: body }
61
+ expect(Typhoeus::Request).to receive(:new).with(anything, hash_including(params: expected_params)).and_return(request)
62
+
63
+ run
64
+ end
65
+
66
+ describe 'without a body' do
67
+ let(:run) { described_class.run(method, 'pathname', options) }
68
+
69
+ it 'should send the auth + options' do
70
+ expected_params = { secret: 'test-config-secret', option1: 1, option2: 2, body: {} }
71
+ expect(Typhoeus::Request).to receive(:new).with(anything, hash_including(params: expected_params)).and_return(request)
72
+
73
+ run
74
+ end
75
+ end
76
+ end
77
+
78
+ describe 'on error' do
79
+ before do
80
+ allow(response).to receive(:success?).and_return(false)
81
+ end
82
+
83
+ it 'should error' do
84
+ expect {
85
+ run
86
+ }.to raise_error(Hookly::ResponseError, /failed with code: `900`/)
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,28 @@
1
+ require 'rspec'
2
+ require 'webmock/rspec'
3
+
4
+ require 'hookly'
5
+
6
+ RSpec.configure do |config|
7
+ config.expect_with :rspec do |expectations|
8
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
9
+ end
10
+
11
+ config.mock_with :rspec do |mocks|
12
+ mocks.syntax = :expect
13
+ mocks.verify_partial_doubles = true
14
+ end
15
+
16
+ config.run_all_when_everything_filtered = true
17
+ config.profile_examples = 10
18
+ config.order = :defined
19
+ config.warnings = true
20
+
21
+ config.default_formatter = 'doc' if config.files_to_run.one? # More verbose when focused on one file
22
+ end
23
+
24
+ WebMock.disable_net_connect!
25
+
26
+ Dir[File.dirname(__FILE__) + '/helpers/*.rb'].each do |file|
27
+ require file
28
+ end