em-instagram 0.1 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +3 -0
- data/Gemfile +6 -0
- data/LICENSE.md +7 -0
- data/README.md +120 -0
- data/lib/em-instagram/api/media.rb +4 -4
- data/lib/em-instagram/api/subscriptions.rb +7 -9
- data/lib/em-instagram/proxy_logger.rb +5 -0
- data/lib/em-instagram/server.rb +3 -0
- data/lib/em-instagram/version.rb +1 -1
- data/lib/em-instagram.rb +18 -5
- data/spec/api/media_spec.rb +63 -0
- data/spec/api/subscriptions_spec.rb +54 -0
- data/spec/em-instagram_spec.rb +55 -0
- data/spec/server_spec.rb +68 -0
- data/spec/spec_helper.rb +23 -0
- metadata +16 -2
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.md
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
Copyright (c) 2013 Mosaic Sales Solutions
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
4
|
+
|
5
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
6
|
+
|
7
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
CHANGED
@@ -0,0 +1,120 @@
|
|
1
|
+
# Eventmachine Instagram
|
2
|
+
|
3
|
+
This gem provides an interface to the Instagram API which uses EventMachine to interface with it. It is designed for use inside a larger EventMachine based application, and to make the API requests without blocking your reactor.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
If using Bundler, add it to your Gemfile
|
8
|
+
|
9
|
+
gem 'em-instagram'
|
10
|
+
|
11
|
+
If not, just install the gem and require it in your source.
|
12
|
+
|
13
|
+
## Usage
|
14
|
+
|
15
|
+
### Setup
|
16
|
+
|
17
|
+
By default, em-instagram ships with a basic EventMachine web server with it. This allows you to process the callbacks from the API when you subscribe. We recommend that you replace the 'default' server with one of your own as soon as possible, as this is only provided to make initial development easier.
|
18
|
+
|
19
|
+
To set it up, instantiate an EventMachine::Instagram instance
|
20
|
+
|
21
|
+
instagram_args = {
|
22
|
+
:client_id => 'xxxxx',
|
23
|
+
:client_secret => "xxxxx",
|
24
|
+
:callback_url => "www.example.com"
|
25
|
+
}
|
26
|
+
instagram_connection = EventMachine::Instagram.new(instagram_args)
|
27
|
+
instagram_connection.on_update{|media| puts media.inspect}
|
28
|
+
|
29
|
+
EventMachine.run do
|
30
|
+
instagram_connection.start_server
|
31
|
+
end
|
32
|
+
|
33
|
+
The basic arguments that the connection requires is the :client_id, :client_secret and :callback_url. The callback_url is the url of the server that this client is running on. By default, the provided server will just intercept any request aimed at the route, but if you define your own server (more on that later), you can alter how it behaves to different url's.
|
34
|
+
|
35
|
+
You also need to define an update block. This block is called whenever new media is returned by Instagram, with the serialized JSON from the Instagram API.
|
36
|
+
|
37
|
+
Finally, we wrap the server in an EventMachine run block, and boot it up. If your app is already running inside a reactor, there's no need to wrap this code in EM.run.
|
38
|
+
|
39
|
+
### Adding Subscriptions
|
40
|
+
|
41
|
+
To add a subscription, you call subscribe, and pass it a hash of subscription terms. The gem currently allows subscriptions to tags and geographies.
|
42
|
+
|
43
|
+
subscriptions = [{:object => "tag", :object_id => "apple"},
|
44
|
+
{:object => "geography", :lat => latitude, :lng => longitude, :radius => radius}]
|
45
|
+
|
46
|
+
instagram_args = {
|
47
|
+
:client_id => 'xxxxx',
|
48
|
+
:client_secret => "xxxxx",
|
49
|
+
:callback_url => "www.example.com"
|
50
|
+
}
|
51
|
+
instagram_connection = EventMachine::Instagram.new(instagram_args)
|
52
|
+
instagram_connection.on_update{|media| puts media.inspect}
|
53
|
+
instagram_connection.subscribe(*subscriptions)
|
54
|
+
EventMachine.run do
|
55
|
+
instagram_connection.start_server
|
56
|
+
end
|
57
|
+
|
58
|
+
## Configuration
|
59
|
+
|
60
|
+
### Logging
|
61
|
+
|
62
|
+
You can pass a logger into the instagram args. This logger must expect a method called "debug", and will be passed debugging information. For an example of how to add a logger to the basic handler, using the Ruby default logger
|
63
|
+
|
64
|
+
require 'logger'
|
65
|
+
logger = Logger.new('log/instagram.log')
|
66
|
+
instagram_args = {
|
67
|
+
:logger => logger,
|
68
|
+
:client_id => 'xxxxx',
|
69
|
+
:client_secret => "xxxxx",
|
70
|
+
:callback_url => "www.example.com"
|
71
|
+
}
|
72
|
+
instagram_connection = EventMachine::Instagram.new(instagram_args)
|
73
|
+
|
74
|
+
### Custom notification behaviour
|
75
|
+
|
76
|
+
The way the Instagram streaming API works is that it will post you notifications of new content. The default behaviour of em-instagram is to immediately 'fetch' that content and pass it into the update block provided by you. You can change this by calling stream on the connection object, and passing a block. This can be called multiple times, and each time, it will push a new block onto the stack. Whenever a notification comes in, every block in the stack will be called with that notification as an argument.
|
77
|
+
|
78
|
+
instagram_connection = EventMachine::Instagram.new(instagram_args)
|
79
|
+
instagram_connection.stream {|notification| instagram_connection.fetch notification } #preserve original functionality
|
80
|
+
instagram_connection.stream {|notification| my_outside_instance.notify(notification)}
|
81
|
+
instagram_connection.on_update{|media| puts media.inspect}
|
82
|
+
|
83
|
+
### Altering the default server listening addresses
|
84
|
+
|
85
|
+
By default, the provided server listens to 0.0.0.0 at port 8080. To change this, you can pass :port and :host to the initializer.
|
86
|
+
|
87
|
+
instagram_args = {
|
88
|
+
:port => 80,
|
89
|
+
:host => "myserver.vm",
|
90
|
+
:client_id => 'xxxxx',
|
91
|
+
:client_secret => "xxxxx",
|
92
|
+
:callback_url => "www.example.com"
|
93
|
+
}
|
94
|
+
instagram_connection = EventMachine::Instagram.new(instagram_args)
|
95
|
+
|
96
|
+
### Altering the default server
|
97
|
+
|
98
|
+
The server provided is deliberately very sparse. It assumes that all requests incoming are instagram requests and treats them accordingly. It is not designed to be used in a production environment, only to allow you to start developing until you know enough about your architecture to develop your own server. For my use of this gem, I wrote a server based off [evma_httpserver](https://github.com/eventmachine/evma_httpserver). Pass it in with the :server argument to the initializer.
|
99
|
+
|
100
|
+
class MyHttpServer < EM::Connection
|
101
|
+
include EM::HttpServer
|
102
|
+
|
103
|
+
def process_http_request
|
104
|
+
puts "Got a request to #{@http_request_uri}
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
instagram_args = {
|
109
|
+
:server => MyHttpServer,
|
110
|
+
:port => 80,
|
111
|
+
:host => "myserver.vm",
|
112
|
+
:client_id => 'xxxxx',
|
113
|
+
:client_secret => "xxxxx",
|
114
|
+
:callback_url => "www.example.com"
|
115
|
+
}
|
116
|
+
instagram_connection = EventMachine::Instagram.new(instagram_args)
|
117
|
+
|
118
|
+
## Final notes
|
119
|
+
|
120
|
+
This gem is in the early stages of development and is targetted at my own need to use the streaming API's in an event driven fashion. Pull requests to add functionality to the gem are more than welcome!
|
@@ -15,18 +15,18 @@ module EventMachine
|
|
15
15
|
|
16
16
|
|
17
17
|
def fetch_geography(object_id)
|
18
|
-
|
18
|
+
self.logger.debug "fetching #{object_id} updates..."
|
19
19
|
# TODO: figure out if min_id parameter would be appropriate for reading recent tagged media
|
20
20
|
request = media_by_geography(object_id)
|
21
|
-
request.errback { |error|
|
21
|
+
request.errback { |error| self.logger.debug "fetch error: #{error}"; EventMachine::add_timer(15) { fetch_geography object_id } }
|
22
22
|
request.callback { |media| @update_queue.push(*media) }
|
23
23
|
end
|
24
24
|
|
25
25
|
def fetch_tag(object_id)
|
26
|
-
|
26
|
+
self.logger.debug "fetching #{object_id} updates..."
|
27
27
|
# TODO: figure out if max_id or min_id parameter would be appropriate for reading recent tagged media
|
28
28
|
request = media_by_tag(object_id)
|
29
|
-
request.errback { |error|
|
29
|
+
request.errback { |error| self.logger.debug "fetch error: #{error}"; EventMachine::add_timer(15) { fetch_tag object_id } }
|
30
30
|
request.callback { |media| @update_queue.push(*media) }
|
31
31
|
end
|
32
32
|
end
|
@@ -1,15 +1,13 @@
|
|
1
1
|
module EventMachine
|
2
2
|
class Instagram
|
3
3
|
module Subscriptions
|
4
|
-
def send_subscription(params = {})
|
5
|
-
request :post, "/v1/subscriptions", :body => default_params.merge(params)
|
6
|
-
end
|
7
4
|
|
8
5
|
def subscribe_to(options)
|
9
|
-
options = options.merge(:aspect => 'media', :callback_url =>
|
10
|
-
|
11
|
-
request
|
12
|
-
request.
|
6
|
+
options = options.merge(:aspect => 'media', :callback_url => self.callback_url)
|
7
|
+
request_body = default_params.merge(:aspect => 'media', :callback_url => self.callback_url).merge(options)
|
8
|
+
request = request(:post, "/v1/subscriptions", :body => request_body)
|
9
|
+
request.errback { |error| self.logger.debug "subscription error: #{error}"; EventMachine::add_timer(15) { subscribe_to options } }
|
10
|
+
request.callback { |response| self.logger.debug "next subscription..."; EventMachine::next_tick { subscribe_next } }
|
13
11
|
end
|
14
12
|
|
15
13
|
def subscriptions(params = {})
|
@@ -27,9 +25,9 @@ module EventMachine
|
|
27
25
|
|
28
26
|
def subscribe_next
|
29
27
|
if @subscription_queue.empty?
|
30
|
-
|
28
|
+
self.logger.debug "subscribed."
|
31
29
|
else
|
32
|
-
|
30
|
+
self.subscription_queue.pop { |hash| subscribe_to(hash); subscribe_next }
|
33
31
|
end
|
34
32
|
end
|
35
33
|
end
|
data/lib/em-instagram/server.rb
CHANGED
data/lib/em-instagram/version.rb
CHANGED
data/lib/em-instagram.rb
CHANGED
@@ -2,6 +2,7 @@ require File.expand_path('../em-instagram/request', __FILE__)
|
|
2
2
|
require File.expand_path('../em-instagram/server', __FILE__)
|
3
3
|
require File.expand_path('../em-instagram/api/subscriptions', __FILE__)
|
4
4
|
require File.expand_path('../em-instagram/api/media', __FILE__)
|
5
|
+
require File.expand_path('../em-instagram/proxy_logger', __FILE__)
|
5
6
|
|
6
7
|
module EventMachine
|
7
8
|
class Instagram
|
@@ -11,19 +12,21 @@ module EventMachine
|
|
11
12
|
BASE_URI = 'https://api.instagram.com'
|
12
13
|
PORT = 443
|
13
14
|
|
14
|
-
attr_reader :default_params, :host, :port, :server, :logger, :subscription_queue, :update_callback
|
15
|
+
attr_reader :default_params, :host, :port, :server, :logger, :subscription_queue, :update_callback, :callback_url
|
15
16
|
|
16
17
|
def initialize(options = nil)
|
17
18
|
@host, @port, @server = [options[:host], options[:port], options[:server]]
|
18
19
|
@subscription_queue = EventMachine::Queue.new
|
19
20
|
@update_queue = EventMachine::Queue.new
|
20
|
-
@
|
21
|
+
@callback_url = options[:callback_url]
|
22
|
+
@default_stream = Proc.new{|update| self.fetch update}
|
23
|
+
self.logger = options[:logger]
|
21
24
|
@default_params = {:client_id => options[:client_id], :client_secret => options[:client_secret]}
|
22
25
|
update
|
23
26
|
|
24
27
|
end
|
25
28
|
|
26
|
-
|
29
|
+
def fetch(update)
|
27
30
|
case update['object']
|
28
31
|
when 'geography'
|
29
32
|
fetch_geography update['object_id']
|
@@ -32,6 +35,15 @@ module EventMachine
|
|
32
35
|
end
|
33
36
|
end
|
34
37
|
|
38
|
+
def logger
|
39
|
+
return @logger if @logger
|
40
|
+
ProxyLogger.new
|
41
|
+
end
|
42
|
+
|
43
|
+
def logger=(logger)
|
44
|
+
@logger = logger
|
45
|
+
end
|
46
|
+
|
35
47
|
def stream(&block)
|
36
48
|
@streams ||= []
|
37
49
|
@streams << block
|
@@ -47,14 +59,15 @@ module EventMachine
|
|
47
59
|
if @update_callback
|
48
60
|
@update_callback.call(item)
|
49
61
|
else
|
50
|
-
|
62
|
+
self.logger.debug(item)
|
51
63
|
end
|
52
64
|
EventMachine::next_tick { update }
|
53
65
|
end
|
54
66
|
end
|
55
67
|
|
56
68
|
def receive_notification(data)
|
57
|
-
@streams.
|
69
|
+
stream_set = @streams.nil? ? [@default_stream] : @streams
|
70
|
+
stream_set.each { |stream| stream.call(data) }
|
58
71
|
end
|
59
72
|
|
60
73
|
def request(method, path, options = {})
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require File.expand_path('../../spec_helper', __FILE__)
|
2
|
+
|
3
|
+
describe EventMachine::Instagram::Media do
|
4
|
+
before :each do
|
5
|
+
@instagram_url = "https://api.instagram.com/v1/"
|
6
|
+
logger = Logger.new("/dev/null") # OS dependent here!
|
7
|
+
client_id = "11111111"
|
8
|
+
client_secret = "22222222"
|
9
|
+
@callback_url = "myserver.vm/instagram_handler"
|
10
|
+
@instagram = EventMachine::Instagram.new(:logger => logger, :client_id => client_id, :client_secret => client_secret, :callback_url => @callback_url)
|
11
|
+
@expected_body = {:client_id=>client_id, :client_secret=>client_secret}
|
12
|
+
@http_stub = double("http_stub")
|
13
|
+
@request = double("request")
|
14
|
+
@request.stub(:errback => double("errback"))
|
15
|
+
@request.stub(:callback => double("callback"))
|
16
|
+
EventMachine::HttpRequest.stub(:new => @http_stub)
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should post basic media" do
|
20
|
+
media_object = 2
|
21
|
+
EventMachine::HttpRequest.should_receive(:new).with(@instagram_url + "media/#{media_object}").and_return(@http_stub)
|
22
|
+
@http_stub.should_receive(:get).and_return(@request)
|
23
|
+
@instagram.media(media_object)
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should be able to search on tags" do
|
27
|
+
tag = "banana"
|
28
|
+
EventMachine::HttpRequest.should_receive(:new).with(@instagram_url + "tags/#{tag}/media/recent").and_return(@http_stub)
|
29
|
+
@http_stub.should_receive(:get).and_return(@request)
|
30
|
+
@instagram.media_by_tag(tag)
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should be able to search on geographies" do
|
34
|
+
geo = "banana_tree"
|
35
|
+
EventMachine::HttpRequest.should_receive(:new).with(@instagram_url + "geographies/#{geo}/media/recent").and_return(@http_stub)
|
36
|
+
@http_stub.should_receive(:get).and_return(@request)
|
37
|
+
@instagram.media_by_geography(geo)
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should use the correct callbacks with the fetch geography method" do
|
41
|
+
geo = "banana_tree"
|
42
|
+
@instagram.should_receive(:media_by_geography).and_return(@request)
|
43
|
+
@request.should_receive(:callback) do |&callback_args|
|
44
|
+
queue = double("queue")
|
45
|
+
@instagram.send(:instance_variable_set, :@update_queue, queue)
|
46
|
+
queue.should_receive(:push).with({:data => "geo"})
|
47
|
+
callback_args.call([{:data => "geo"}])
|
48
|
+
end
|
49
|
+
@instagram.fetch_geography("banana_tree")
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should use the correct callbacks with the fetch tags method" do
|
53
|
+
geo = "banana_tree"
|
54
|
+
@instagram.should_receive(:media_by_tag).and_return(@request)
|
55
|
+
@request.should_receive(:callback) do |&callback_args|
|
56
|
+
queue = double("queue")
|
57
|
+
@instagram.send(:instance_variable_set, :@update_queue, queue)
|
58
|
+
queue.should_receive(:push).with({:data => "geo"})
|
59
|
+
callback_args.call([{:data => "geo"}])
|
60
|
+
end
|
61
|
+
@instagram.fetch_tag("banana_tree")
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require File.expand_path('../../spec_helper', __FILE__)
|
2
|
+
|
3
|
+
describe EventMachine::Instagram::Subscriptions do
|
4
|
+
before :each do
|
5
|
+
@instagram_url = "https://api.instagram.com/v1/subscriptions"
|
6
|
+
logger = Logger.new("/dev/null") # OS dependent here!
|
7
|
+
client_id = "11111111"
|
8
|
+
client_secret = "22222222"
|
9
|
+
@callback_url = "myserver.vm/instagram_handler"
|
10
|
+
@instagram = EventMachine::Instagram.new(:logger => logger, :client_id => client_id, :client_secret => client_secret, :callback_url => @callback_url)
|
11
|
+
@expected_body = {:client_id=>client_id, :client_secret=>client_secret}
|
12
|
+
@http_stub = double("http_stub")
|
13
|
+
@request = double("request")
|
14
|
+
@request.stub(:errback => double("errback"))
|
15
|
+
@request.stub(:callback => double("callback"))
|
16
|
+
EventMachine::HttpRequest.stub(:new => @http_stub)
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should send a media subscription when asked to subscribe to a topic" do
|
20
|
+
args = {:banana => "fun"}
|
21
|
+
media_args = {:aspect => 'media', :callback_url => @callback_url}
|
22
|
+
EventMachine::HttpRequest.should_receive(:new).with(@instagram_url).and_return(@http_stub)
|
23
|
+
@http_stub.should_receive(:post).with(:body=> @expected_body.merge(args).merge(media_args)).and_return(@request)
|
24
|
+
@instagram.subscribe_to(args)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should be able to get a list of subscriptions" do
|
28
|
+
args = {:banana => "fun"}
|
29
|
+
EventMachine::HttpRequest.should_receive(:new).with(@instagram_url).and_return(@http_stub)
|
30
|
+
@http_stub.should_receive(:get).with(:query=> @expected_body.merge(args)).and_return(@request)
|
31
|
+
@instagram.subscriptions(args)
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should be able to unsubscribe from a subscription" do
|
35
|
+
args = {:banana => "fun"}
|
36
|
+
EventMachine::HttpRequest.should_receive(:new).with(@instagram_url).and_return(@http_stub)
|
37
|
+
@http_stub.should_receive(:delete).with(:query=> @expected_body.merge(args)).and_return(@request)
|
38
|
+
@instagram.unsubscribe(args)
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should push subscriptions onto a queue and then trigger the queue" do
|
42
|
+
queue = []
|
43
|
+
@instagram.send(:instance_variable_set, :@subscription_queue, queue)
|
44
|
+
@instagram.should_receive(:subscribe_next)
|
45
|
+
@instagram.subscribe(:random => "json")
|
46
|
+
queue.should include(:random => "json")
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should pop items off the queue until there are none left" do
|
50
|
+
queue = [{:first_json => "1"}, {:second => 2}, {3 => :four}]
|
51
|
+
@instagram.should_receive(:subscribe_to).with(*queue).ordered
|
52
|
+
@instagram.subscribe_to(*queue)
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require File.expand_path('../spec_helper', __FILE__)
|
2
|
+
|
3
|
+
describe EventMachine::Instagram do
|
4
|
+
|
5
|
+
before :each do
|
6
|
+
logger = Logger.new("/dev/null") # OS dependent here!
|
7
|
+
client_id = "11111111"
|
8
|
+
client_secret = "22222222"
|
9
|
+
@callback_url = "myserver.vm/instagram_handler"
|
10
|
+
@instagram = EventMachine::Instagram.new(:logger => logger, :client_id => client_id, :client_secret => client_secret, :callback_url => @callback_url)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should dispatch a fetch request to the geography API when asked for a geo" do
|
14
|
+
object = {'object' => "geography", "object_id" => 'banana'}
|
15
|
+
@instagram.should_receive(:fetch_geography).with("banana")
|
16
|
+
@instagram.fetch(object)
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should dispatch a fetch request to the tags API when asked for a tag" do
|
20
|
+
object = {'object' => "tag", "object_id" => 'banana'}
|
21
|
+
@instagram.should_receive(:fetch_tag).with("banana")
|
22
|
+
@instagram.fetch(object)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should execute the provided stream block to all streams when it recieves a new notification of content" do
|
26
|
+
call_check = double("checker")
|
27
|
+
call_check_two = double("checker")
|
28
|
+
call_check.should_receive(:called).with("banana")
|
29
|
+
call_check_two.should_receive(:called).with("banana")
|
30
|
+
@instagram.stream{|note| call_check.called(note)}
|
31
|
+
@instagram.stream{|note| call_check_two.called(note)}
|
32
|
+
@instagram.receive_notification("banana")
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should execute anything put onto the update queue and keep the pop waiting for more data" do
|
36
|
+
call_check = double("checker")
|
37
|
+
call_check.should_receive(:called).with("banana").twice
|
38
|
+
@instagram.on_update{|u| call_check.called(u)}
|
39
|
+
EventMachine.run do
|
40
|
+
@instagram.update("banana")
|
41
|
+
@instagram.update("banana")
|
42
|
+
EventMachine.next_tick{EventMachine.stop_event_loop}
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should not throw exceptions if the logger is not present" do
|
47
|
+
@instagram = EventMachine::Instagram.new(:client_id => '1', :client_secret => '2', :callback_url => @callback_url)
|
48
|
+
expect{ @instagram.subscribe_next}.to_not raise_error
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should use the default stream if no stream is defined" do
|
52
|
+
@instagram.should_receive(:fetch)
|
53
|
+
@instagram.receive_notification("banana")
|
54
|
+
end
|
55
|
+
end
|
data/spec/server_spec.rb
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
require File.expand_path('../spec_helper', __FILE__)
|
2
|
+
|
3
|
+
describe EventMachine::Instagram::Server do
|
4
|
+
|
5
|
+
before :all do
|
6
|
+
module EventMachine
|
7
|
+
class ServerStub
|
8
|
+
include Instagram::Server
|
9
|
+
attr_accessor :http_request_method, :http_query_string, :updates, :http_post_content
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
before :each do
|
15
|
+
@response = double("response")
|
16
|
+
EventMachine::DelegatedHttpResponse.stub(:new => @response)
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should create a delayed response to be able to keep processing" do
|
20
|
+
@response.should_receive :send_response
|
21
|
+
@response.should_receive :status=
|
22
|
+
@response.should_receive :content=
|
23
|
+
EventMachine::ServerStub.new.process_http_request
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should respond with a 200 okay to a get request and set the hub challenge parameter as the contents" do
|
27
|
+
@response.should_receive :send_response
|
28
|
+
@response.should_receive(:status=).with(200)
|
29
|
+
@response.should_receive(:content=).with(["banana"])
|
30
|
+
server = EventMachine::ServerStub.new
|
31
|
+
server.http_request_method = "GET"
|
32
|
+
server.http_query_string = "hub.challenge=banana"
|
33
|
+
server.process_http_request
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should respond with a 200 okay to a get request and set the content as blank if no challenge is provided" do
|
37
|
+
@response.should_receive :send_response
|
38
|
+
@response.should_receive(:status=).with(200)
|
39
|
+
@response.should_receive(:content=).with([])
|
40
|
+
server = EventMachine::ServerStub.new
|
41
|
+
server.http_request_method = "GET"
|
42
|
+
server.http_query_string = ''
|
43
|
+
server.process_http_request
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should respond with a 202 and push the json to the update queue when receiving a post" do
|
47
|
+
json = [{'banana' => "fun"}, {'apple' => "also fun"} ]
|
48
|
+
@response.should_receive :send_response
|
49
|
+
@response.should_receive(:status=).with(202)
|
50
|
+
@response.should_receive(:content=).with("Accepted")
|
51
|
+
server = EventMachine::ServerStub.new
|
52
|
+
server.http_request_method = "POST"
|
53
|
+
server.http_post_content = json.to_json
|
54
|
+
server.updates = []
|
55
|
+
server.process_http_request
|
56
|
+
server.updates.should eql(json)
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should respond with a 405 to a request type it doesn't recognise" do
|
60
|
+
@response.should_receive :send_response
|
61
|
+
@response.should_receive(:status=).with(405)
|
62
|
+
@response.should_receive(:content=).with('Method Not Allowed')
|
63
|
+
server = EventMachine::ServerStub.new
|
64
|
+
server.http_request_method = "DELETE"
|
65
|
+
server.process_http_request
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# This file was generated by the `rspec --init` command. Conventionally, all
|
2
|
+
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
|
3
|
+
# Require this file using `require "spec_helper"` to ensure that it is only
|
4
|
+
# loaded once.
|
5
|
+
#
|
6
|
+
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
7
|
+
require 'rubygems'
|
8
|
+
require 'bundler'
|
9
|
+
Bundler.require(:default)
|
10
|
+
require 'logger'
|
11
|
+
require File.expand_path('../../lib/em-instagram.rb', __FILE__)
|
12
|
+
|
13
|
+
RSpec.configure do |config|
|
14
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
15
|
+
config.run_all_when_everything_filtered = true
|
16
|
+
config.filter_run :focus
|
17
|
+
|
18
|
+
# Run specs in random order to surface order dependencies. If you find an
|
19
|
+
# order dependency and want to debug it, you can fix the order by providing
|
20
|
+
# the seed, which is printed after each run.
|
21
|
+
# --seed 1234
|
22
|
+
config.order = 'random'
|
23
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: em-instagram
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 0.1.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -82,14 +82,23 @@ executables: []
|
|
82
82
|
extensions: []
|
83
83
|
extra_rdoc_files: []
|
84
84
|
files:
|
85
|
+
- .gitignore
|
86
|
+
- Gemfile
|
87
|
+
- LICENSE.md
|
85
88
|
- README.md
|
86
89
|
- em-instagram.gemspec
|
87
90
|
- lib/em-instagram.rb
|
88
91
|
- lib/em-instagram/api/media.rb
|
89
92
|
- lib/em-instagram/api/subscriptions.rb
|
93
|
+
- lib/em-instagram/proxy_logger.rb
|
90
94
|
- lib/em-instagram/request.rb
|
91
95
|
- lib/em-instagram/server.rb
|
92
96
|
- lib/em-instagram/version.rb
|
97
|
+
- spec/api/media_spec.rb
|
98
|
+
- spec/api/subscriptions_spec.rb
|
99
|
+
- spec/em-instagram_spec.rb
|
100
|
+
- spec/server_spec.rb
|
101
|
+
- spec/spec_helper.rb
|
93
102
|
homepage: ''
|
94
103
|
licenses: []
|
95
104
|
post_install_message:
|
@@ -114,5 +123,10 @@ rubygems_version: 1.8.23
|
|
114
123
|
signing_key:
|
115
124
|
specification_version: 3
|
116
125
|
summary: ''
|
117
|
-
test_files:
|
126
|
+
test_files:
|
127
|
+
- spec/api/media_spec.rb
|
128
|
+
- spec/api/subscriptions_spec.rb
|
129
|
+
- spec/em-instagram_spec.rb
|
130
|
+
- spec/server_spec.rb
|
131
|
+
- spec/spec_helper.rb
|
118
132
|
has_rdoc:
|