pusher 0.9.4 → 0.10.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.
data/.gitignore CHANGED
@@ -18,7 +18,6 @@ coverage
18
18
  rdoc
19
19
  pkg
20
20
  .yardoc
21
- Gemfile.lock
22
21
 
23
22
  ## PROJECT::SPECIFIC
24
23
  .bundle
data/.travis.yml CHANGED
@@ -1 +1,12 @@
1
+ language: ruby
2
+
3
+ rvm:
4
+ - 1.8.7
5
+ - 1.9.2
6
+ - 1.9.3
7
+ - jruby-18mode
8
+ - jruby-19mode
9
+ - rbx-18mode
10
+ - rbx-19mode
11
+
1
12
  script: "rspec spec/*_spec.rb"
data/Gemfile.lock ADDED
@@ -0,0 +1,50 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ pusher (0.10.0)
5
+ multi_json (~> 1.0)
6
+ signature (~> 0.1.4)
7
+
8
+ GEM
9
+ remote: http://rubygems.org/
10
+ specs:
11
+ addressable (2.3.2)
12
+ cookiejar (0.3.0)
13
+ crack (0.3.1)
14
+ diff-lcs (1.1.3)
15
+ em-http-request (1.0.3)
16
+ addressable (>= 2.2.3)
17
+ cookiejar
18
+ em-socksify
19
+ eventmachine (>= 1.0.0.beta.4)
20
+ http_parser.rb (>= 0.5.3)
21
+ em-socksify (0.2.1)
22
+ eventmachine (>= 1.0.0.beta.4)
23
+ eventmachine (1.0.0)
24
+ http_parser.rb (0.5.3)
25
+ multi_json (1.3.6)
26
+ rack (1.4.1)
27
+ rake (0.9.2.2)
28
+ rspec (2.11.0)
29
+ rspec-core (~> 2.11.0)
30
+ rspec-expectations (~> 2.11.0)
31
+ rspec-mocks (~> 2.11.0)
32
+ rspec-core (2.11.1)
33
+ rspec-expectations (2.11.3)
34
+ diff-lcs (~> 1.1.3)
35
+ rspec-mocks (2.11.3)
36
+ signature (0.1.4)
37
+ webmock (1.8.10)
38
+ addressable (>= 2.2.7)
39
+ crack (>= 0.1.7)
40
+
41
+ PLATFORMS
42
+ ruby
43
+
44
+ DEPENDENCIES
45
+ em-http-request (~> 1.0.0)
46
+ pusher!
47
+ rack
48
+ rake
49
+ rspec (~> 2.0)
50
+ webmock
data/README.md CHANGED
@@ -1,6 +1,8 @@
1
1
  Pusher gem
2
2
  ==========
3
3
 
4
+ [![Build Status](https://secure.travis-ci.org/pusher/pusher-gem.png?branch=master)](http://travis-ci.org/pusher/pusher-gem)
5
+
4
6
  Getting started
5
7
  ---------------
6
8
 
data/lib/pusher.rb CHANGED
@@ -30,6 +30,8 @@ module Pusher
30
30
  def_delegators :default_client, :authentication_token, :url
31
31
  def_delegators :default_client, :encrypted=, :url=
32
32
 
33
+ def_delegators :default_client, :channels, :channel_info, :trigger
34
+
33
35
  attr_writer :logger
34
36
 
35
37
  # Return a channel by name
@@ -62,21 +62,21 @@ module Pusher
62
62
  Pusher.logger.error("#{e.message} (#{e.class})")
63
63
  Pusher.logger.debug(e.backtrace.join("\n"))
64
64
  end
65
-
66
- # Request channel stats
65
+
66
+ # Request info for a channel
67
67
  #
68
- # @return [Hash] See Pusher api docs for reported stats
68
+ # @param info [Array] Array of attributes required (as lowercase strings)
69
+ # @return [Hash] Hash of requested attributes for this channel
69
70
  # @raise [Pusher::Error] on invalid Pusher response - see the error message for more details
70
71
  # @raise [Pusher::HTTPError] on any error raised inside Net::HTTP - the original error is available in the original_error attribute
71
72
  #
72
- def stats
73
- request = Pusher::Request.new(:get, @uri + 'stats', {}, nil, nil, @client)
74
- return request.send_sync
73
+ def info(attributes = [])
74
+ @client.channel_info(name, :info => attributes.join(','))
75
75
  end
76
76
 
77
- # Compute authentication string required to subscribe to this channel.
78
- #
79
- # See http://pusher.com/docs/auth_signatures for more details.
77
+ # Compute authentication string required as part of the authentication
78
+ # endpoint response. Generally the authenticate method should be used in
79
+ # preference to this one
80
80
  #
81
81
  # @param socket_id [String] Each Pusher socket connection receives a
82
82
  # unique socket_id. This is sent from pusher.js to your server when
@@ -85,10 +85,16 @@ module Pusher
85
85
  # @return [String]
86
86
  #
87
87
  def authentication_string(socket_id, custom_string = nil)
88
- raise "Invalid socket_id" if socket_id.nil? || socket_id.empty?
89
- raise 'Custom argument must be a string' unless custom_string.nil? || custom_string.kind_of?(String)
88
+ if socket_id.nil? || socket_id.empty?
89
+ raise Error, "Invalid socket_id #{socket_id}"
90
+ end
91
+
92
+ unless custom_string.nil? || custom_string.kind_of?(String)
93
+ raise Error, 'Custom argument must be a string'
94
+ end
90
95
 
91
- string_to_sign = [socket_id, name, custom_string].compact.map{|e|e.to_s}.join(':')
96
+ string_to_sign = [socket_id, name, custom_string].
97
+ compact.map(&:to_s).join(':')
92
98
  Pusher.logger.debug "Signing #{string_to_sign}"
93
99
  token = @client.authentication_token
94
100
  digest = OpenSSL::Digest::SHA256.new
@@ -96,11 +102,9 @@ module Pusher
96
102
 
97
103
  return "#{token.key}:#{signature}"
98
104
  end
99
-
100
- # Deprecated - for backward compatibility
101
- alias :socket_auth :authentication_string
102
105
 
103
- # Generate an authentication endpoint response
106
+ # Generate the expected response for an authentication endpoint.
107
+ # See http://pusher.com/docs/authenticating_users for details.
104
108
  #
105
109
  # @example Private channels
106
110
  # render :json => Pusher['private-my_channel'].authenticate(params[:socket_id])
@@ -123,7 +127,7 @@ module Pusher
123
127
  #
124
128
  def authenticate(socket_id, custom_data = nil)
125
129
  custom_data = MultiJson.encode(custom_data) if custom_data
126
- auth = socket_auth(socket_id, custom_data)
130
+ auth = authentication_string(socket_id, custom_data)
127
131
  r = {:auth => auth}
128
132
  r[:channel_data] = custom_data if custom_data
129
133
  r
data/lib/pusher/client.rb CHANGED
@@ -21,13 +21,13 @@ module Pusher
21
21
  Signature::Token.new(@key, @secret)
22
22
  end
23
23
 
24
- # @private Builds a connection url for Pusherapp
25
- def url
24
+ # @private Builds a url for this app, optionally appending a path
25
+ def url(path = nil)
26
26
  URI::Generic.build({
27
27
  :scheme => @scheme,
28
28
  :host => @host,
29
29
  :port => @port,
30
- :path => "/apps/#{@app_id}"
30
+ :path => "/apps/#{@app_id}#{path}"
31
31
  })
32
32
  end
33
33
 
@@ -59,7 +59,7 @@ module Pusher
59
59
  @port = boolean ? 443 : 80
60
60
  end
61
61
 
62
- # Return a channel by name
62
+ # Return a convenience channel object by name. No API request is made.
63
63
  #
64
64
  # @example
65
65
  # Pusher['my-channel']
@@ -72,6 +72,74 @@ module Pusher
72
72
  @channels[channel_name.to_s] ||= Channel.new(url, channel_name, self)
73
73
  end
74
74
 
75
+ # Request a list of occupied channels from the API
76
+ #
77
+ # GET /apps/[id]/channels
78
+ #
79
+ # @param options [Hash] Hash of options for the API - see Pusher API docs
80
+ # @return [Hash] See Pusher API docs
81
+ # @raise [Pusher::Error] on invalid Pusher response - see the error message for more details
82
+ # @raise [Pusher::HTTPError] on any error raised inside Net::HTTP - the original error is available in the original_error attribute
83
+ #
84
+ def channels(options = {})
85
+ @_channels_url ||= url('/channels')
86
+ request = Request.new(:get, @_channels_url, options, nil, nil, self)
87
+ return request.send_sync
88
+ end
89
+
90
+ # Request info for a specific channel
91
+ #
92
+ # GET /apps/[id]/channels/[channel_name]
93
+ #
94
+ # @param channel_name [String] Channel name
95
+ # @param options [Hash] Hash of options for the API - see Pusher API docs
96
+ # @return [Hash] See Pusher API docs
97
+ # @raise [Pusher::Error] on invalid Pusher response - see the error message for more details
98
+ # @raise [Pusher::HTTPError] on any error raised inside Net::HTTP - the original error is available in the original_error attribute
99
+ #
100
+ def channel_info(channel_name, options = {})
101
+ request = Request.new(:get, url("/channels/#{channel_name}"), options, nil, nil, self)
102
+ return request.send_sync
103
+ end
104
+
105
+ # Trigger an event on one or more channels
106
+ #
107
+ # POST /apps/[app_id]/events
108
+ #
109
+ # @param channels [Array] One of more channel names
110
+ # @param event_name [String]
111
+ # @param data [Object] Event data to be triggered in javascript.
112
+ # Objects other than strings will be converted to JSON
113
+ # @param options [Hash] Additional options to send to api, e.g socket_id
114
+ # @return [Hash] See Pusher API docs
115
+ # @raise [Pusher::Error] on invalid Pusher response - see the error message for more details
116
+ # @raise [Pusher::HTTPError] on any error raised inside Net::HTTP - the original error is available in the original_error attribute
117
+ #
118
+ def trigger(channels, event_name, data, options = {})
119
+ @_trigger_url ||= url('/events')
120
+
121
+ encoded_data = case data
122
+ when String
123
+ data
124
+ else
125
+ begin
126
+ MultiJson.encode(data)
127
+ rescue MultiJson::DecodeError => e
128
+ Pusher.logger.error("Could not convert #{data.inspect} into JSON")
129
+ raise e
130
+ end
131
+ end
132
+
133
+ options.merge!({
134
+ :name => event_name,
135
+ :channels => channels,
136
+ :data => encoded_data,
137
+ })
138
+
139
+ request = Request.new(:post, @_trigger_url, {}, MultiJson.encode(options), nil, self)
140
+ return request.send_sync
141
+ end
142
+
75
143
  private
76
144
 
77
145
  def configured?
@@ -57,7 +57,6 @@ module Pusher
57
57
  def initialize(verb, uri, params, body = nil, token = nil, client = Pusher)
58
58
  @verb = verb
59
59
  @uri = uri
60
- @client = client
61
60
 
62
61
  if body
63
62
  @body = body
@@ -65,13 +64,16 @@ module Pusher
65
64
  end
66
65
 
67
66
  request = Signature::Request.new(verb.to_s.upcase, uri.path, params)
68
- auth_hash = request.sign(token || @client.authentication_token)
69
- @params = params.merge(auth_hash)
67
+ request.sign(token || client.authentication_token)
68
+ @params = request.signed_params
70
69
  end
71
70
 
72
71
  def send_sync
73
- require 'net/http' unless defined?(Net::HTTP)
74
- require 'net/https' if (ssl? && !defined?(Net::HTTPS))
72
+ if ssl?
73
+ require 'net/https' unless defined?(Net::HTTPS)
74
+ else
75
+ require 'net/http' unless defined?(Net::HTTP)
76
+ end
75
77
 
76
78
  @http_sync ||= begin
77
79
  http = Net::HTTP.new(@uri.host, @uri.port)
@@ -94,7 +96,7 @@ module Pusher
94
96
  raise "Unknown verb"
95
97
  end
96
98
  rescue Errno::EINVAL, Errno::ECONNRESET, Errno::ECONNREFUSED,
97
- Errno::ETIMEDOUT, Errno::EHOSTUNREACH, Errno::ECONNRESET,
99
+ Errno::ETIMEDOUT, Errno::EHOSTUNREACH,
98
100
  Timeout::Error, EOFError,
99
101
  Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError,
100
102
  Net::ProtocolError => e
@@ -103,7 +105,9 @@ module Pusher
103
105
  raise error
104
106
  end
105
107
 
106
- return handle_response(response.code.to_i, response.body.chomp)
108
+ body = response.body ? response.body.chomp : nil
109
+
110
+ return handle_response(response.code.to_i, body)
107
111
  end
108
112
 
109
113
  def send_async
@@ -139,7 +143,7 @@ module Pusher
139
143
  def handle_response(status_code, body)
140
144
  case status_code
141
145
  when 200
142
- return MultiJson.decode(body, :symbolize_keys => true)
146
+ return symbolize_first_level(MultiJson.decode(body))
143
147
  when 202
144
148
  return true
145
149
  when 400
@@ -156,5 +160,12 @@ module Pusher
156
160
  def ssl?
157
161
  @uri.scheme == 'https'
158
162
  end
163
+
164
+ def symbolize_first_level(hash)
165
+ hash.inject({}) do |result, (key, value)|
166
+ result[key.to_sym] = value
167
+ result
168
+ end
169
+ end
159
170
  end
160
171
  end
data/pusher.gemspec CHANGED
@@ -3,7 +3,7 @@ $:.push File.expand_path("../lib", __FILE__)
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = "pusher"
6
- s.version = "0.9.4"
6
+ s.version = "0.10.0"
7
7
  s.platform = Gem::Platform::RUBY
8
8
  s.authors = ["Pusher"]
9
9
  s.email = ["support@pusher.com"]
@@ -12,7 +12,8 @@ Gem::Specification.new do |s|
12
12
  s.description = %q{Wrapper for pusher.com REST api}
13
13
 
14
14
  s.add_dependency "multi_json", "~> 1.0"
15
- s.add_dependency 'signature', "~> 0.1.2"
15
+ s.add_dependency 'signature', "~> 0.1.4"
16
+ s.add_dependency "jruby-openssl" if defined?(JRUBY_VERSION)
16
17
 
17
18
  s.add_development_dependency "rspec", "~> 2.0"
18
19
  s.add_development_dependency "webmock"
data/spec/channel_spec.rb CHANGED
@@ -10,18 +10,28 @@ describe Pusher::Channel do
10
10
  :port => 80,
11
11
  })
12
12
  @client.encrypted = false
13
+ @channel = @client['test_channel']
13
14
 
14
15
  WebMock.reset!
15
16
  WebMock.disable_net_connect!
17
+ end
18
+
19
+ let(:pusher_url_regexp) { %r{/apps/20/channels/test_channel/events} }
16
20
 
17
- @pusher_url_regexp = %r{/apps/20/channels/test_channel/events}
21
+ def stub_post(status, body = nil)
22
+ options = {:status => status}
23
+ options.merge!({:body => body}) if body
24
+
25
+ WebMock.stub_request(:post, pusher_url_regexp).to_return(options)
26
+ end
27
+
28
+ def stub_post_to_raise(e)
29
+ WebMock.stub_request(:post, pusher_url_regexp).to_raise(e)
18
30
  end
19
31
 
20
32
  describe 'trigger!' do
21
33
  before :each do
22
- WebMock.stub_request(:post, @pusher_url_regexp).
23
- to_return(:status => 202)
24
- @channel = @client['test_channel']
34
+ stub_post 202
25
35
  end
26
36
 
27
37
  it 'should configure HTTP library to talk to pusher API' do
@@ -41,7 +51,7 @@ describe Pusher::Channel do
41
51
  :name => 'Pusher',
42
52
  :last_name => 'App'
43
53
  })
44
- WebMock.should have_requested(:post, %r{/apps/20/channels/test_channel/events}).with { |req|
54
+ WebMock.should have_requested(:post, pusher_url_regexp).with { |req|
45
55
  query_hash = req.uri.query_values
46
56
  query_hash["name"].should == 'new_event'
47
57
  query_hash["auth_key"].should == @client.key
@@ -60,57 +70,54 @@ describe Pusher::Channel do
60
70
  it "should POST string data unmodified in request body" do
61
71
  string = "foo\nbar\""
62
72
  @channel.trigger!('new_event', string)
63
- WebMock.should have_requested(:post, %r{/apps/20/channels/test_channel/events}).with { |req| req.body.should == "foo\nbar\"" }
73
+ WebMock.should have_requested(:post, pusher_url_regexp).with { |req| req.body.should == "foo\nbar\"" }
64
74
  end
65
75
 
66
- it "should catch all Net::HTTP exceptions and raise a Pusher::HTTPError, exposing the original error if required" do
67
- WebMock.stub_request(
68
- :post, %r{/apps/20/channels/test_channel/events}
69
- ).to_raise(Timeout::Error)
76
+ def trigger
77
+ lambda { @channel.trigger!('new_event', 'Some data') }
78
+ end
70
79
 
80
+ it "should catch all Net::HTTP exceptions and raise a Pusher::HTTPError, exposing the original error if required" do
81
+ stub_post_to_raise Timeout::Error
71
82
  error_raised = nil
83
+
72
84
  begin
73
- @client['test_channel'].trigger!('new_event', 'Some data')
85
+ trigger.call
74
86
  rescue => e
75
87
  error_raised = e
76
88
  end
89
+
77
90
  error_raised.class.should == Pusher::HTTPError
78
91
  error_raised.message.should == 'Exception from WebMock (Timeout::Error)'
79
92
  error_raised.original_error.class.should == Timeout::Error
80
93
  end
81
94
 
95
+
96
+ it "should raise Pusher::Error if pusher returns 400" do
97
+ stub_post 400
98
+ trigger.should raise_error(Pusher::Error)
99
+ end
100
+
82
101
  it "should raise AuthenticationError if pusher returns 401" do
83
- WebMock.stub_request(
84
- :post,
85
- %r{/apps/20/channels/test_channel/events}
86
- ).to_return(:status => 401)
87
- lambda {
88
- @client['test_channel'].trigger!('new_event', 'Some data')
89
- }.should raise_error(Pusher::AuthenticationError)
102
+ stub_post 401
103
+ trigger.should raise_error(Pusher::AuthenticationError)
90
104
  end
91
105
 
92
106
  it "should raise Pusher::Error if pusher returns 404" do
93
- WebMock.stub_request(
94
- :post, %r{/apps/20/channels/test_channel/events}
95
- ).to_return(:status => 404)
96
- lambda {
97
- @client['test_channel'].trigger!('new_event', 'Some data')
98
- }.should raise_error(Pusher::Error, 'Resource not found: app_id is probably invalid')
107
+ stub_post 404
108
+ trigger.should raise_error(Pusher::Error, 'Resource not found: app_id is probably invalid')
99
109
  end
100
110
 
101
111
  it "should raise Pusher::Error if pusher returns 500" do
102
- WebMock.stub_request(
103
- :post, %r{/apps/20/channels/test_channel/events}
104
- ).to_return(:status => 500, :body => "some error")
105
- lambda {
106
- @client['test_channel'].trigger!('new_event', 'Some data')
107
- }.should raise_error(Pusher::Error, 'Unknown error (status code 500): some error')
112
+ stub_post 500, "some error"
113
+ trigger.should raise_error(Pusher::Error, 'Unknown error (status code 500): some error')
108
114
  end
109
115
  end
110
116
 
111
- describe 'trigger' do
117
+ describe '#trigger' do
112
118
  it "should log failure if error raised in Net::HTTP call" do
113
- stub_request(:post, @pusher_url_regexp).to_raise(Net::HTTPBadResponse)
119
+ stub_post_to_raise(Net::HTTPBadResponse)
120
+
114
121
  Pusher.logger.should_receive(:error).with("Exception from WebMock (Net::HTTPBadResponse) (Pusher::HTTPError)")
115
122
  Pusher.logger.should_receive(:debug) #backtrace
116
123
  channel = Pusher::Channel.new(@client.url, 'test_channel', @client)
@@ -118,21 +125,19 @@ describe Pusher::Channel do
118
125
  end
119
126
 
120
127
  it "should log failure if Pusher returns an error response" do
121
- stub_request(:post, @pusher_url_regexp).to_return(:status => 401)
122
- # @http.should_receive(:post).and_raise(Net::HTTPBadResponse)
123
- Pusher.logger.should_receive(:error).with(" (Pusher::AuthenticationError)")
128
+ stub_post 401
129
+ Pusher.logger.should_receive(:error).with("Pusher::AuthenticationError (Pusher::AuthenticationError)")
124
130
  Pusher.logger.should_receive(:debug) #backtrace
125
131
  channel = Pusher::Channel.new(@client.url, 'test_channel', @client)
126
132
  channel.trigger('new_event', 'Some data')
127
133
  end
128
134
  end
129
135
 
130
- describe "trigger_async" do
136
+ describe "#trigger_async" do
131
137
  it "should by default POST to http api" do
132
138
  EM.run {
133
- stub_request(:post, @pusher_url_regexp).to_return(:status => 202)
134
- channel = Pusher::Channel.new(@client.url, 'test_channel', @client)
135
- channel.trigger_async('new_event', 'Some data').callback {
139
+ stub_post 202
140
+ @channel.trigger_async('new_event', 'Some data').callback {
136
141
  WebMock.should have_requested(:post, %r{http://api.pusherapp.com})
137
142
  EM.stop
138
143
  }
@@ -142,7 +147,7 @@ describe Pusher::Channel do
142
147
  it "should POST to https api if ssl enabled" do
143
148
  @client.encrypted = true
144
149
  EM.run {
145
- stub_request(:post, @pusher_url_regexp).to_return(:status => 202)
150
+ stub_post 202
146
151
  channel = Pusher::Channel.new(@client.url, 'test_channel', @client)
147
152
  channel.trigger_async('new_event', 'Some data').callback {
148
153
  WebMock.should have_requested(:post, %r{https://api.pusherapp.com})
@@ -152,12 +157,12 @@ describe Pusher::Channel do
152
157
  end
153
158
 
154
159
  it "should return a deferrable which succeeds in success case" do
155
- stub_request(:post, @pusher_url_regexp).to_return(:status => 202)
160
+ stub_post 202
156
161
 
157
162
  EM.run {
158
- d = @client['test_channel'].trigger_async('new_event', 'Some data')
163
+ d = @channel.trigger_async('new_event', 'Some data')
159
164
  d.callback {
160
- WebMock.should have_requested(:post, @pusher_url_regexp)
165
+ WebMock.should have_requested(:post, pusher_url_regexp)
161
166
  EM.stop
162
167
  }
163
168
  d.errback {
@@ -168,15 +173,15 @@ describe Pusher::Channel do
168
173
  end
169
174
 
170
175
  it "should return a deferrable which fails (with exception) in fail case" do
171
- stub_request(:post, @pusher_url_regexp).to_return(:status => 401)
176
+ stub_post 401
172
177
 
173
178
  EM.run {
174
- d = @client['test_channel'].trigger_async('new_event', 'Some data')
179
+ d = @channel.trigger_async('new_event', 'Some data')
175
180
  d.callback {
176
181
  fail
177
182
  }
178
183
  d.errback { |error|
179
- WebMock.should have_requested(:post, @pusher_url_regexp)
184
+ WebMock.should have_requested(:post, pusher_url_regexp)
180
185
  error.should be_kind_of(Pusher::AuthenticationError)
181
186
  EM.stop
182
187
  }
@@ -184,76 +189,58 @@ describe Pusher::Channel do
184
189
  end
185
190
  end
186
191
 
187
- describe "stats" do
188
- before :each do
189
- @api_path = %r{/apps/20/channels/presence-test_channel/stats}
192
+ describe '#info' do
193
+ it "should call the Client#channel_info" do
194
+ @client.should_receive(:channel_info).with('mychannel', anything)
195
+ @channel = @client['mychannel']
196
+ @channel.info
190
197
  end
191
198
 
192
- it "should call the user_count api" do
193
- WebMock.stub_request(:get, @api_path).to_return({
194
- :status => 200,
195
- :body => MultiJson.encode(:user_count => 1)
199
+ it "should assemble the requested attribes into the info option" do
200
+ @client.should_receive(:channel_info).with(anything, {
201
+ :info => "user_count,connection_count"
196
202
  })
197
- @channel = @client['presence-test_channel']
198
-
199
- @channel.stats.should == {
200
- :user_count => 1
201
- }
203
+ @channel = @client['presence-foo']
204
+ @channel.info(%w{user_count connection_count})
202
205
  end
203
206
  end
204
207
 
205
- describe "socket_auth" do
206
- before :each do
207
- @channel = @client['test_channel']
208
+ describe "#authentication_string" do
209
+ def authentication_string(*data)
210
+ lambda { @channel.authentication_string(*data) }
208
211
  end
209
212
 
210
213
  it "should return an authentication string given a socket id" do
211
- auth = @channel.socket_auth('socketid')
214
+ auth = @channel.authentication_string('socketid')
212
215
 
213
216
  auth.should == '12345678900000001:827076f551e22451357939e4c7bb1200de29f921d5bf80b40d71668f9cd61c40'
214
217
  end
215
218
 
216
219
  it "should raise error if authentication is invalid" do
217
220
  [nil, ''].each do |invalid|
218
- lambda {
219
- @channel.socket_auth(invalid)
220
- }.should raise_error
221
+ authentication_string(invalid).should raise_error Pusher::Error
221
222
  end
222
223
  end
223
224
 
224
225
  describe 'with extra string argument' do
225
-
226
226
  it 'should be a string or nil' do
227
- lambda {
228
- @channel.socket_auth('socketid', 'boom')
229
- }.should_not raise_error
230
-
231
- lambda {
232
- @channel.socket_auth('socketid', 123)
233
- }.should raise_error
227
+ authentication_string('socketid', 123).should raise_error Pusher::Error
228
+ authentication_string('socketid', {}).should raise_error Pusher::Error
234
229
 
235
- lambda {
236
- @channel.socket_auth('socketid', nil)
237
- }.should_not raise_error
238
-
239
- lambda {
240
- @channel.socket_auth('socketid', {})
241
- }.should raise_error
230
+ authentication_string('socketid', 'boom').should_not raise_error
231
+ authentication_string('socketid', nil).should_not raise_error
242
232
  end
243
233
 
244
234
  it "should return an authentication string given a socket id and custom args" do
245
- auth = @channel.socket_auth('socketid', 'foobar')
235
+ auth = @channel.authentication_string('socketid', 'foobar')
246
236
 
247
237
  auth.should == "12345678900000001:#{hmac(@client.secret, "socketid:test_channel:foobar")}"
248
238
  end
249
-
250
239
  end
251
240
  end
252
241
 
253
242
  describe '#authenticate' do
254
-
255
243
  before :each do
256
- @channel = @client['test_channel']
257
244
  @custom_data = {:uid => 123, :info => {:name => 'Foo'}}
258
245
  end
259
246
 
data/spec/client_spec.rb CHANGED
@@ -3,7 +3,7 @@ require 'spec_helper'
3
3
  require 'em-http'
4
4
 
5
5
  describe Pusher do
6
- describe 'different clients' do
6
+ describe 'using multiple Client objects' do
7
7
  before :each do
8
8
  @client1 = Pusher::Client.new
9
9
  @client2 = Pusher::Client.new
@@ -72,6 +72,8 @@ describe Pusher do
72
72
  end
73
73
  end
74
74
 
75
+ # The behaviour should be the same when using the Client object, or the
76
+ # 'global' client delegated through the Pusher class
75
77
  [lambda { Pusher }, lambda { Pusher::Client.new }].each do |client_gen|
76
78
  before :each do
77
79
  @client = client_gen.call
@@ -130,7 +132,7 @@ describe Pusher do
130
132
  @client.secret = '12345678900000001'
131
133
  end
132
134
 
133
- describe '.[]' do
135
+ describe '#[]' do
134
136
  before do
135
137
  @channel = @client['test_channel']
136
138
  end
@@ -154,6 +156,71 @@ describe Pusher do
154
156
  end
155
157
  end
156
158
  end
159
+
160
+ describe '#channels' do
161
+ it "should call the correct URL and symbolise response correctly" do
162
+ api_path = %r{/apps/20/channels}
163
+ WebMock.stub_request(:get, api_path).to_return({
164
+ :status => 200,
165
+ :body => MultiJson.encode('channels' => {
166
+ "channel1" => {},
167
+ "channel2" => {}
168
+ })
169
+ })
170
+ @client.channels.should == {
171
+ :channels => {
172
+ "channel1" => {},
173
+ "channel2" => {}
174
+ }
175
+ }
176
+ end
177
+ end
178
+
179
+ describe '#channel_info' do
180
+ it "should call correct URL and symbolise response" do
181
+ api_path = %r{/apps/20/channels/mychannel}
182
+ WebMock.stub_request(:get, api_path).to_return({
183
+ :status => 200,
184
+ :body => MultiJson.encode({
185
+ 'occupied' => false,
186
+ })
187
+ })
188
+ @client.channel_info('mychannel').should == {
189
+ :occupied => false,
190
+ }
191
+ end
192
+ end
193
+
194
+ describe '#trigger' do
195
+ before :each do
196
+ @api_path = %r{/apps/20/events}
197
+ WebMock.stub_request(:post, @api_path).to_return({
198
+ :status => 200,
199
+ :body => MultiJson.encode({})
200
+ })
201
+ end
202
+
203
+ it "should call correct URL" do
204
+ @client.trigger('mychannel', 'event', {'some' => 'data'}).
205
+ should == {}
206
+ end
207
+
208
+ it "should pass any options in the body of the request" do
209
+ @client.trigger('mychannel', 'event', {'some' => 'data'}, {
210
+ :socket_id => "1234"
211
+ })
212
+ WebMock.should have_requested(:post, @api_path).with { |req|
213
+ MultiJson.decode(req.body)["socket_id"].should == '1234'
214
+ }
215
+ end
216
+
217
+ it "should convert non string data to JSON before posting" do
218
+ @client.trigger('mychannel', 'event', {'some' => 'data'})
219
+ WebMock.should have_requested(:post, @api_path).with { |req|
220
+ MultiJson.decode(req.body)["data"].should == '{"some":"data"}'
221
+ }
222
+ end
223
+ end
157
224
  end
158
225
  end
159
226
  end
metadata CHANGED
@@ -1,105 +1,142 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: pusher
3
- version: !ruby/object:Gem::Version
4
- version: 0.9.4
3
+ version: !ruby/object:Gem::Version
4
+ hash: 55
5
5
  prerelease:
6
+ segments:
7
+ - 0
8
+ - 10
9
+ - 0
10
+ version: 0.10.0
6
11
  platform: ruby
7
- authors:
12
+ authors:
8
13
  - Pusher
9
14
  autorequire:
10
15
  bindir: bin
11
16
  cert_chain: []
12
- date: 2012-05-28 00:00:00.000000000 Z
13
- dependencies:
14
- - !ruby/object:Gem::Dependency
17
+
18
+ date: 2012-09-28 00:00:00 Z
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
15
21
  name: multi_json
16
- requirement: &70359107850640 !ruby/object:Gem::Requirement
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
17
24
  none: false
18
- requirements:
25
+ requirements:
19
26
  - - ~>
20
- - !ruby/object:Gem::Version
21
- version: '1.0'
27
+ - !ruby/object:Gem::Version
28
+ hash: 15
29
+ segments:
30
+ - 1
31
+ - 0
32
+ version: "1.0"
22
33
  type: :runtime
23
- prerelease: false
24
- version_requirements: *70359107850640
25
- - !ruby/object:Gem::Dependency
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
26
36
  name: signature
27
- requirement: &70359107850160 !ruby/object:Gem::Requirement
37
+ prerelease: false
38
+ requirement: &id002 !ruby/object:Gem::Requirement
28
39
  none: false
29
- requirements:
40
+ requirements:
30
41
  - - ~>
31
- - !ruby/object:Gem::Version
32
- version: 0.1.2
42
+ - !ruby/object:Gem::Version
43
+ hash: 19
44
+ segments:
45
+ - 0
46
+ - 1
47
+ - 4
48
+ version: 0.1.4
33
49
  type: :runtime
34
- prerelease: false
35
- version_requirements: *70359107850160
36
- - !ruby/object:Gem::Dependency
50
+ version_requirements: *id002
51
+ - !ruby/object:Gem::Dependency
37
52
  name: rspec
38
- requirement: &70359107849700 !ruby/object:Gem::Requirement
53
+ prerelease: false
54
+ requirement: &id003 !ruby/object:Gem::Requirement
39
55
  none: false
40
- requirements:
56
+ requirements:
41
57
  - - ~>
42
- - !ruby/object:Gem::Version
43
- version: '2.0'
58
+ - !ruby/object:Gem::Version
59
+ hash: 3
60
+ segments:
61
+ - 2
62
+ - 0
63
+ version: "2.0"
44
64
  type: :development
45
- prerelease: false
46
- version_requirements: *70359107849700
47
- - !ruby/object:Gem::Dependency
65
+ version_requirements: *id003
66
+ - !ruby/object:Gem::Dependency
48
67
  name: webmock
49
- requirement: &70359107849320 !ruby/object:Gem::Requirement
68
+ prerelease: false
69
+ requirement: &id004 !ruby/object:Gem::Requirement
50
70
  none: false
51
- requirements:
52
- - - ! '>='
53
- - !ruby/object:Gem::Version
54
- version: '0'
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ hash: 3
75
+ segments:
76
+ - 0
77
+ version: "0"
55
78
  type: :development
56
- prerelease: false
57
- version_requirements: *70359107849320
58
- - !ruby/object:Gem::Dependency
79
+ version_requirements: *id004
80
+ - !ruby/object:Gem::Dependency
59
81
  name: em-http-request
60
- requirement: &70359107848780 !ruby/object:Gem::Requirement
82
+ prerelease: false
83
+ requirement: &id005 !ruby/object:Gem::Requirement
61
84
  none: false
62
- requirements:
85
+ requirements:
63
86
  - - ~>
64
- - !ruby/object:Gem::Version
87
+ - !ruby/object:Gem::Version
88
+ hash: 23
89
+ segments:
90
+ - 1
91
+ - 0
92
+ - 0
65
93
  version: 1.0.0
66
94
  type: :development
67
- prerelease: false
68
- version_requirements: *70359107848780
69
- - !ruby/object:Gem::Dependency
95
+ version_requirements: *id005
96
+ - !ruby/object:Gem::Dependency
70
97
  name: rake
71
- requirement: &70359107848360 !ruby/object:Gem::Requirement
98
+ prerelease: false
99
+ requirement: &id006 !ruby/object:Gem::Requirement
72
100
  none: false
73
- requirements:
74
- - - ! '>='
75
- - !ruby/object:Gem::Version
76
- version: '0'
101
+ requirements:
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ hash: 3
105
+ segments:
106
+ - 0
107
+ version: "0"
77
108
  type: :development
78
- prerelease: false
79
- version_requirements: *70359107848360
80
- - !ruby/object:Gem::Dependency
109
+ version_requirements: *id006
110
+ - !ruby/object:Gem::Dependency
81
111
  name: rack
82
- requirement: &70359107847900 !ruby/object:Gem::Requirement
112
+ prerelease: false
113
+ requirement: &id007 !ruby/object:Gem::Requirement
83
114
  none: false
84
- requirements:
85
- - - ! '>='
86
- - !ruby/object:Gem::Version
87
- version: '0'
115
+ requirements:
116
+ - - ">="
117
+ - !ruby/object:Gem::Version
118
+ hash: 3
119
+ segments:
120
+ - 0
121
+ version: "0"
88
122
  type: :development
89
- prerelease: false
90
- version_requirements: *70359107847900
123
+ version_requirements: *id007
91
124
  description: Wrapper for pusher.com REST api
92
- email:
125
+ email:
93
126
  - support@pusher.com
94
127
  executables: []
128
+
95
129
  extensions: []
130
+
96
131
  extra_rdoc_files: []
97
- files:
132
+
133
+ files:
98
134
  - .document
99
135
  - .gemtest
100
136
  - .gitignore
101
137
  - .travis.yml
102
138
  - Gemfile
139
+ - Gemfile.lock
103
140
  - LICENSE
104
141
  - README.md
105
142
  - Rakefile
@@ -116,31 +153,39 @@ files:
116
153
  - spec/web_hook_spec.rb
117
154
  homepage: http://github.com/pusher/pusher-gem
118
155
  licenses: []
156
+
119
157
  post_install_message:
120
158
  rdoc_options: []
121
- require_paths:
159
+
160
+ require_paths:
122
161
  - lib
123
- required_ruby_version: !ruby/object:Gem::Requirement
162
+ required_ruby_version: !ruby/object:Gem::Requirement
124
163
  none: false
125
- requirements:
126
- - - ! '>='
127
- - !ruby/object:Gem::Version
128
- version: '0'
129
- required_rubygems_version: !ruby/object:Gem::Requirement
164
+ requirements:
165
+ - - ">="
166
+ - !ruby/object:Gem::Version
167
+ hash: 3
168
+ segments:
169
+ - 0
170
+ version: "0"
171
+ required_rubygems_version: !ruby/object:Gem::Requirement
130
172
  none: false
131
- requirements:
132
- - - ! '>='
133
- - !ruby/object:Gem::Version
134
- version: '0'
173
+ requirements:
174
+ - - ">="
175
+ - !ruby/object:Gem::Version
176
+ hash: 3
177
+ segments:
178
+ - 0
179
+ version: "0"
135
180
  requirements: []
181
+
136
182
  rubyforge_project:
137
- rubygems_version: 1.8.10
183
+ rubygems_version: 1.8.6
138
184
  signing_key:
139
185
  specification_version: 3
140
186
  summary: Pusher API client
141
- test_files:
187
+ test_files:
142
188
  - spec/channel_spec.rb
143
189
  - spec/client_spec.rb
144
190
  - spec/spec_helper.rb
145
191
  - spec/web_hook_spec.rb
146
- has_rdoc: