pusher-fake 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -16,11 +16,10 @@ end
16
16
  When %{I subscribe to the "$channel" channel with presence events} do |channel|
17
17
  page.execute_script(%{
18
18
  var list = document.querySelector("#presence ul"),
19
+ count = document.querySelector("#presence header h1 span"),
19
20
  channel = Pusher.instance.subscribe(#{channel.to_json});
20
21
 
21
22
  channel.bind("pusher:subscription_succeeded", function(clients) {
22
- var
23
- count = document.querySelector("#presence header h1 span");
24
23
  count.innerHTML = clients.count;
25
24
 
26
25
  clients.each(function(client) {
@@ -30,8 +29,6 @@ When %{I subscribe to the "$channel" channel with presence events} do |channel|
30
29
  });
31
30
  });
32
31
  channel.bind("pusher:member_added", function(client) {
33
- var
34
- count = document.querySelector("#presence header h1 span");
35
32
  count.innerHTML = parseInt(count.innerHTML, 10) + 1;
36
33
 
37
34
  var
@@ -39,8 +36,7 @@ When %{I subscribe to the "$channel" channel with presence events} do |channel|
39
36
  element.setAttribute("id", "client-" + client.id);
40
37
  });
41
38
  channel.bind("pusher:member_removed", function(client) {
42
- var item = list.querySelector("li#client-" + client.id),
43
- count = document.querySelector("#presence header h1 span");
39
+ var item = list.querySelector("li#client-" + client.id);
44
40
 
45
41
  count.innerHTML = parseInt(count.innerHTML, 10) - 1;
46
42
 
@@ -14,28 +14,24 @@ When %{I manually trigger the "$event" event on the "$channel" channel} do |even
14
14
  page.execute_script(%{Pusher.instance.send_event(#{event.to_json}, {}, #{channel.to_json})})
15
15
  end
16
16
 
17
- Then /^I should receive a "([^"]+)" event on the "([^"]+)" channel$/ do |event, channel|
18
- wait do
19
- events = page.evaluate_script("Pusher.instance.events[#{[channel, event].join(":").to_json}]")
20
- events.length.should == 1
21
- end
22
- end
23
-
24
- Then /^I should not receive a "([^"]+)" event on the "([^"]+)" channel$/ do |event, channel|
25
- wait do
26
- events = page.evaluate_script("Pusher.instance.events[#{[channel, event].join(":").to_json}]")
27
- events.should be_nil
28
- end
29
- end
17
+ Then /^([^ ]+) should receive a "([^"]+)" event on the "([^"]+)" channel$/ do |name, event, channel|
18
+ name = nil if name == "I"
30
19
 
31
- Then /^([^I]+) should receive a "([^"]+)" event on the "([^"]+)" channel$/ do |name, event, channel|
32
20
  using_session(name) do
33
- step %{I should receive a "#{event}" event on the "#{channel}" channel}
21
+ wait do
22
+ events = page.evaluate_script("Pusher.instance.events[#{[channel, event].join(":").to_json}]")
23
+ events.length.should == 1
24
+ end
34
25
  end
35
26
  end
36
27
 
37
- Then /^([^I]+) should not receive a "([^"]+)" event on the "([^"]+)" channel$/ do |name, event, channel|
28
+ Then /^([^ ]+) should not receive a "([^"]+)" event on the "([^"]+)" channel$/ do |name, event, channel|
29
+ name = nil if name == "I"
30
+
38
31
  using_session(name) do
39
- step %{I should not receive a "#{event}" event on the "#{channel}" channel}
32
+ wait do
33
+ events = page.evaluate_script("Pusher.instance.events[#{[channel, event].join(":").to_json}]")
34
+ events.should be_nil
35
+ end
40
36
  end
41
37
  end
@@ -15,15 +15,13 @@ class Sinatra::Application
15
15
  end
16
16
 
17
17
  post "/pusher/auth" do
18
+ data = nil
18
19
  channel = Pusher[params[:channel_name]]
19
20
 
20
- if params[:channel_name] =~ /^private-/
21
- channel.authenticate(params[:socket_id]).to_json
22
- elsif params[:channel_name] =~ /^presence-/
23
- channel.authenticate(params[:socket_id], {
24
- user_id: params[:socket_id],
25
- user_info: {}
26
- }).to_json
21
+ if params[:channel_name] =~ /^presence-/
22
+ data = { user_id: params[:socket_id], user_info: {} }
27
23
  end
24
+
25
+ channel.authenticate(params[:socket_id], data).to_json
28
26
  end
29
27
  end
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Pusher JavaScript Library v1.11.0
2
+ * Pusher JavaScript Library v1.11.2
3
3
  * http://pusherapp.com/
4
4
  *
5
5
  * Copyright 2011, Pusher
@@ -181,7 +181,7 @@ Pusher.warn = function() {
181
181
  };
182
182
 
183
183
  // Pusher defaults
184
- Pusher.VERSION = '1.11.0';
184
+ Pusher.VERSION = '1.11.2';
185
185
 
186
186
  Pusher.host = 'ws.pusherapp.com';
187
187
  Pusher.ws_port = 80;
@@ -307,6 +307,11 @@ Example:
307
307
  var stateCallbacks = this.stateActions;
308
308
 
309
309
  if (prevState && (Pusher.Util.arrayIndexOf(this.transitions[prevState], nextState) == -1)) {
310
+ this.emit('invalid_transition_attempt', {
311
+ oldState: prevState,
312
+ newState: nextState
313
+ });
314
+
310
315
  throw new Error('Invalid transition [' + prevState + ' to ' + nextState + ']');
311
316
  }
312
317
 
@@ -350,6 +355,7 @@ Example:
350
355
  A little bauble to interface with window.navigator.onLine,
351
356
  window.ononline and window.onoffline. Easier to mock.
352
357
  */
358
+
353
359
  var NetInfo = function() {
354
360
  var self = this;
355
361
  Pusher.EventsDispatcher.call(this);
@@ -376,7 +382,7 @@ Example:
376
382
  };
377
383
 
378
384
  Pusher.Util.extend(NetInfo.prototype, Pusher.EventsDispatcher.prototype);
379
-
385
+
380
386
  this.Pusher.NetInfo = NetInfo;
381
387
  }).call(this);
382
388
 
@@ -431,7 +437,7 @@ Example:
431
437
  this.netInfo.bind('online', function(){
432
438
  if (self._machine.is('waiting')) {
433
439
  self._machine.transition('connecting');
434
- triggerStateChange('connecting');
440
+ updateState('connecting');
435
441
  }
436
442
  });
437
443
 
@@ -452,8 +458,6 @@ Example:
452
458
 
453
459
  // define the state machine that runs the connection
454
460
  this._machine = new Pusher.Machine('initialized', machineTransitions, {
455
-
456
- // TODO: Use the constructor for this.
457
461
  initializedPre: function() {
458
462
  self.compulsorySecure = self.options.encrypted;
459
463
 
@@ -469,16 +473,18 @@ Example:
469
473
  self.emit('connecting_in', self.connectionWait);
470
474
  }
471
475
 
472
- if (self.netInfo.isOnLine() === false || self.connectionAttempts > 4){
473
- triggerStateChange('unavailable');
476
+ if (self.netInfo.isOnLine() && self.connectionAttempts <= 4) {
477
+ updateState('connecting');
474
478
  } else {
475
- triggerStateChange('connecting');
479
+ updateState('unavailable');
476
480
  }
477
481
 
478
- if (self.netInfo.isOnLine() === true) {
482
+ // When in the unavailable state we attempt to connect, but don't
483
+ // broadcast that fact
484
+ if (self.netInfo.isOnLine()) {
479
485
  self._waitingTimer = setTimeout(function() {
480
486
  self._machine.transition('connecting');
481
- }, self.connectionWait);
487
+ }, connectionDelay());
482
488
  }
483
489
  },
484
490
 
@@ -491,7 +497,7 @@ Example:
491
497
  // state even when offline.
492
498
  if (self.netInfo.isOnLine() === false) {
493
499
  self._machine.transition('waiting');
494
- triggerStateChange('unavailable');
500
+ updateState('unavailable');
495
501
 
496
502
  return;
497
503
  }
@@ -545,6 +551,11 @@ Example:
545
551
  },
546
552
 
547
553
  openToImpermanentlyClosing: function() {
554
+ // Possible to receive connection_established event after transition to impermanentlyClosing
555
+ // but before socket close. Prevent this triggering a transition from impermanentlyClosing to connected
556
+ // by unbinding onmessage callback.
557
+ self.socket.onmessage = undefined;
558
+
548
559
  updateConnectionParameters();
549
560
  },
550
561
 
@@ -556,17 +567,18 @@ Example:
556
567
  self.socket.onclose = transitionToWaiting;
557
568
 
558
569
  resetConnectionParameters(self);
570
+ self.connectedAt = new Date().getTime();
559
571
 
560
572
  resetActivityCheck();
561
573
  },
562
574
 
563
575
  connectedPost: function() {
564
- triggerStateChange('connected');
576
+ updateState('connected');
565
577
  },
566
578
 
567
579
  connectedExit: function() {
568
580
  stopActivityCheck();
569
- triggerStateChange('disconnected');
581
+ updateState('disconnected');
570
582
  },
571
583
 
572
584
  impermanentlyClosingPost: function() {
@@ -591,8 +603,12 @@ Example:
591
603
  },
592
604
 
593
605
  failedPre: function() {
594
- triggerStateChange('failed');
606
+ updateState('failed');
595
607
  Pusher.debug('WebSockets are not available in this browser.');
608
+ },
609
+
610
+ permanentlyClosedPost: function() {
611
+ updateState('disconnected');
596
612
  }
597
613
  });
598
614
 
@@ -633,7 +649,11 @@ Example:
633
649
  protocol = 'wss://';
634
650
  }
635
651
 
636
- return protocol + Pusher.host + ':' + port + '/app/' + key + '?client=js&version=' + Pusher.VERSION;
652
+ var flash = (Pusher.TransportType === "flash") ? "true" : "false";
653
+
654
+ return protocol + Pusher.host + ':' + port + '/app/' + key + '?protocol=5&client=js'
655
+ + '&version=' + Pusher.VERSION
656
+ + '&flash=' + flash;
637
657
  }
638
658
 
639
659
  // callback for close and retry. Used on timeouts.
@@ -657,6 +677,25 @@ Example:
657
677
  if (self._activityTimer) { clearTimeout(self._activityTimer); }
658
678
  }
659
679
 
680
+ // Returns the delay before the next connection attempt should be made
681
+ //
682
+ // This function guards against attempting to connect more frequently than
683
+ // once every second
684
+ //
685
+ function connectionDelay() {
686
+ var delay = self.connectionWait;
687
+ if (delay === 0) {
688
+ if (self.connectedAt) {
689
+ var t = 1000;
690
+ var connectedFor = new Date().getTime() - self.connectedAt;
691
+ if (connectedFor < t) {
692
+ delay = t - connectedFor;
693
+ }
694
+ }
695
+ }
696
+ return delay;
697
+ }
698
+
660
699
  /*-----------------------------------------------
661
700
  WebSocket Callbacks
662
701
  -----------------------------------------------*/
@@ -666,28 +705,40 @@ Example:
666
705
  self._machine.transition('open');
667
706
  };
668
707
 
708
+ function handleCloseCode(code, message) {
709
+ // first inform the end-developer of this error
710
+ self.emit('error', {type: 'PusherError', data: {code: code, message: message}});
711
+
712
+ if (code === 4000) {
713
+ // SSL only app
714
+ self.compulsorySecure = true;
715
+ self.connectionSecure = true;
716
+ self.options.encrypted = true;
717
+
718
+ self._machine.transition('impermanentlyClosing')
719
+ } else if (code < 4100) {
720
+ // Permentently close connection
721
+ self._machine.transition('permanentlyClosing')
722
+ } else if (code < 4200) {
723
+ // Backoff before reconnecting
724
+ self.connectionWait = 1000;
725
+ self._machine.transition('waiting')
726
+ } else if (code < 4300) {
727
+ // Reconnect immediately
728
+ self._machine.transition('impermanentlyClosing')
729
+ } else {
730
+ // Unknown error
731
+ self._machine.transition('permanentlyClosing')
732
+ }
733
+ }
734
+
669
735
  function ws_onMessageOpen(event) {
670
736
  var params = parseWebSocketEvent(event);
671
737
  if (params !== undefined) {
672
738
  if (params.event === 'pusher:connection_established') {
673
739
  self._machine.transition('connected', params.data.socket_id);
674
740
  } else if (params.event === 'pusher:error') {
675
- // first inform the end-developer of this error
676
- self.emit('error', {type: 'PusherError', data: params.data});
677
-
678
- switch (params.data.code) {
679
- case 4000:
680
- Pusher.warn(params.data.message);
681
-
682
- self.compulsorySecure = true;
683
- self.connectionSecure = true;
684
- self.options.encrypted = true;
685
- break;
686
- case 4001:
687
- // App not found by key - close connection
688
- self._machine.transition('permanentlyClosing');
689
- break;
690
- }
741
+ handleCloseCode(params.data.code, params.data.message)
691
742
  }
692
743
  }
693
744
  }
@@ -753,19 +804,21 @@ Example:
753
804
  self._machine.transition('impermanentlyClosing');
754
805
  }
755
806
 
756
- function triggerStateChange(newState, data) {
757
- // avoid emitting and changing the state
758
- // multiple times when it's the same.
759
- if (self.state === newState) return;
760
-
807
+ // Updates the public state information exposed by connection
808
+ //
809
+ // This is distinct from the internal state information used by _machine
810
+ // to manage the connection
811
+ //
812
+ function updateState(newState, data) {
761
813
  var prevState = self.state;
762
-
763
814
  self.state = newState;
764
815
 
765
- Pusher.debug('State changed', prevState + ' -> ' + newState);
766
-
767
- self.emit('state_change', {previous: prevState, current: newState});
768
- self.emit(newState, data);
816
+ // Only emit when the state changes
817
+ if (prevState !== newState) {
818
+ Pusher.debug('State changed', prevState + ' -> ' + newState);
819
+ self.emit('state_change', {previous: prevState, current: newState});
820
+ self.emit(newState, data);
821
+ }
769
822
  }
770
823
  };
771
824
 
@@ -785,14 +838,24 @@ Example:
785
838
  }
786
839
  // user re-opening connection after closing it
787
840
  else if(this._machine.is("permanentlyClosed")) {
841
+ resetConnectionParameters(this);
788
842
  this._machine.transition('waiting');
789
843
  }
790
844
  };
791
845
 
792
846
  Connection.prototype.send = function(data) {
793
847
  if (this._machine.is('connected')) {
794
- this.socket.send(data);
795
- return true;
848
+ // Bug in iOS (reproduced in 5.0.1) Mobile Safari:
849
+ // 1. Open page/tab, connect WS, get some data.
850
+ // 2. Switch tab or close Mobile Safari and wait for WS connection to get closed (probably by server).
851
+ // 3. Switch back to tab or open Mobile Safari and Mobile Safari crashes.
852
+ // The problem is that WS tries to send data on closed WS connection before it realises it is closed.
853
+ // The timeout means that by the time the send happens, the WS readyState correctly reflects closed state.
854
+ var self = this;
855
+ setTimeout(function() {
856
+ self.socket.send(data);
857
+ }, 0);
858
+ return true; // only a reflection of fact that WS thinks it is open - could get returned before some lower-level failure.
796
859
  } else {
797
860
  return false;
798
861
  }
@@ -4,9 +4,5 @@ require "capybara/cucumber"
4
4
 
5
5
  Bundler.require(:default, :development)
6
6
 
7
- Dir[File.expand_path("../support/**/*.rb", __FILE__)].each do |file|
8
- require file
9
- end
10
-
11
7
  Capybara.app = Sinatra::Application
12
8
  Capybara.javascript_driver = :webkit
data/lib/pusher-fake.rb CHANGED
@@ -14,7 +14,7 @@ require "pusher-fake/server/application"
14
14
 
15
15
  module PusherFake
16
16
  # The current version string.
17
- VERSION = "0.1.0"
17
+ VERSION = "0.1.1"
18
18
 
19
19
  # Call this method to modify the defaults.
20
20
  #
@@ -6,7 +6,7 @@ module PusherFake
6
6
 
7
7
  attr_accessor :channels
8
8
 
9
- # Create a channel, determing the type by the name.
9
+ # Create a channel, determining the type by the name.
10
10
  #
11
11
  # @param [String] name The channel name.
12
12
  # @return [Public|Private] The channel object.
@@ -1,5 +1,8 @@
1
1
  module PusherFake
2
2
  class Configuration
3
+ # @return [String] The Pusher Applicaiton ID. (Defaults to +PUSHER_APP_ID+.)
4
+ attr_accessor :app_id
5
+
3
6
  # @return [String] The Pusher API key. (Defaults to +PUSHER_API_KEY+.)
4
7
  attr_accessor :key
5
8
 
@@ -20,6 +23,7 @@ module PusherFake
20
23
 
21
24
  # Instantiated from {PusherFake.configuration}. Sets the defaults.
22
25
  def initialize
26
+ self.app_id = "PUSHER_APP_ID"
23
27
  self.key = "PUSHER_API_KEY"
24
28
  self.secret = "PUSHER_API_SECRET"
25
29
  self.socket_host = "127.0.0.1"
@@ -18,7 +18,7 @@ module PusherFake
18
18
  #
19
19
  # @return [String] The channel name.
20
20
  def self.channel
21
- path.match(%r{/apps/PUSHER_APP_ID/channels/(.+)/events}i)[1]
21
+ path.match(%r{/apps/#{PusherFake.configuration.app_id}/channels/(.+)/events}i)[1]
22
22
  end
23
23
 
24
24
  # Parse and return the event data from the request JSON.
@@ -1,6 +1,7 @@
1
1
  require "spec_helper"
2
2
 
3
3
  describe PusherFake::Configuration do
4
+ it { should have_configuration_option(:app_id).with_default("PUSHER_APP_ID") }
4
5
  it { should have_configuration_option(:key).with_default("PUSHER_API_KEY") }
5
6
  it { should have_configuration_option(:secret).with_default("PUSHER_API_SECRET") }
6
7
  it { should have_configuration_option(:socket_host).with_default("127.0.0.1") }
@@ -60,6 +60,19 @@ describe PusherFake::Server::Application, ".channel" do
60
60
  it "returns the channel name from the path" do
61
61
  subject.channel.should == channel
62
62
  end
63
+
64
+ context "with a custom application ID" do
65
+ let(:path) { "/apps/#{app_id}/channels/#{channel}/events" }
66
+ let(:app_id) { "test-id" }
67
+
68
+ before do
69
+ PusherFake.configuration.app_id = app_id
70
+ end
71
+
72
+ it "returns the channel name from the path" do
73
+ subject.channel.should == channel
74
+ end
75
+ end
63
76
  end
64
77
 
65
78
  describe PusherFake::Server::Application, ".data" do
data/spec/spec_helper.rb CHANGED
@@ -9,4 +9,5 @@ end
9
9
 
10
10
  RSpec.configure do |config|
11
11
  config.mock_with :mocha
12
+ config.include(BartenderHelper)
12
13
  end
@@ -1,19 +1,35 @@
1
- RSpec::Matchers.define :have_configuration_option do |option|
2
- match do |configuration|
3
- configuration.should respond_to(option)
4
- configuration.__send__(option).should == @default if defined?(@default)
5
- configuration.__send__(:"#{option}=", "value")
6
- configuration.__send__(option).should == "value"
7
- end
1
+ module BartenderHelper
2
+ class ConfigurationOption
3
+ def initialize(option)
4
+ @option = option
5
+ end
6
+
7
+ def matches?(configuration)
8
+ @configuration = configuration
9
+
10
+ @configuration.respond_to?(@option).should == true
11
+
12
+ @configuration.__send__(@option).should == @default if instance_variables.include?("@default")
13
+
14
+ @configuration.__send__(:"#{@option}=", "value")
15
+ @configuration.__send__(@option).should == "value"
16
+ end
17
+
18
+ def with_default(default)
19
+ @default = default
20
+
21
+ self
22
+ end
8
23
 
9
- chain :with_default do |default|
10
- @default = default
24
+ def failure_message
25
+ description = "expected #{@configuration} to have"
26
+ description << " configuration option #{@option.inspect}"
27
+ description << " with a default of #{@default.inspect}" if instance_variables.include?("@default")
28
+ description
29
+ end
11
30
  end
12
31
 
13
- failure_message do
14
- description = "expected #{subject} to have"
15
- description << " configuration option #{option.inspect}"
16
- description << " with a default of #{@default.inspect}" if defined?(@default)
17
- description
32
+ def have_configuration_option(option)
33
+ ConfigurationOption.new(option)
18
34
  end
19
35
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pusher-fake
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-03-15 00:00:00.000000000 Z
12
+ date: 2012-03-29 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: em-websocket
16
- requirement: &70110876177100 !ruby/object:Gem::Requirement
16
+ requirement: &70195226755160 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - =
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: 0.3.6
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70110876177100
24
+ version_requirements: *70195226755160
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: ruby-hmac
27
- requirement: &70110876176520 !ruby/object:Gem::Requirement
27
+ requirement: &70195226768900 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - =
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: 0.4.0
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *70110876176520
35
+ version_requirements: *70195226768900
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: thin
38
- requirement: &70110876176040 !ruby/object:Gem::Requirement
38
+ requirement: &70195226779500 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - =
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: 1.3.1
44
44
  type: :runtime
45
45
  prerelease: false
46
- version_requirements: *70110876176040
46
+ version_requirements: *70195226779500
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: yajl-ruby
49
- requirement: &70110876175560 !ruby/object:Gem::Requirement
49
+ requirement: &70195226774260 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - =
@@ -54,32 +54,32 @@ dependencies:
54
54
  version: 1.1.0
55
55
  type: :runtime
56
56
  prerelease: false
57
- version_requirements: *70110876175560
57
+ version_requirements: *70195226774260
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: bourne
60
- requirement: &70110876175000 !ruby/object:Gem::Requirement
60
+ requirement: &70195226798680 !ruby/object:Gem::Requirement
61
61
  none: false
62
62
  requirements:
63
63
  - - =
64
64
  - !ruby/object:Gem::Version
65
- version: 1.1.1
65
+ version: 1.1.2
66
66
  type: :development
67
67
  prerelease: false
68
- version_requirements: *70110876175000
68
+ version_requirements: *70195226798680
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: bundler
71
- requirement: &70110876174540 !ruby/object:Gem::Requirement
71
+ requirement: &70195226812420 !ruby/object:Gem::Requirement
72
72
  none: false
73
73
  requirements:
74
- - - =
74
+ - - ! '>='
75
75
  - !ruby/object:Gem::Version
76
76
  version: 1.1.0
77
77
  type: :development
78
78
  prerelease: false
79
- version_requirements: *70110876174540
79
+ version_requirements: *70195226812420
80
80
  - !ruby/object:Gem::Dependency
81
81
  name: capybara
82
- requirement: &70110876173940 !ruby/object:Gem::Requirement
82
+ requirement: &70195226808740 !ruby/object:Gem::Requirement
83
83
  none: false
84
84
  requirements:
85
85
  - - =
@@ -87,21 +87,21 @@ dependencies:
87
87
  version: 1.1.2
88
88
  type: :development
89
89
  prerelease: false
90
- version_requirements: *70110876173940
90
+ version_requirements: *70195226808740
91
91
  - !ruby/object:Gem::Dependency
92
92
  name: capybara-webkit
93
- requirement: &70110876173440 !ruby/object:Gem::Requirement
93
+ requirement: &70195226819740 !ruby/object:Gem::Requirement
94
94
  none: false
95
95
  requirements:
96
96
  - - =
97
97
  - !ruby/object:Gem::Version
98
- version: 0.10.1
98
+ version: 0.11.0
99
99
  type: :development
100
100
  prerelease: false
101
- version_requirements: *70110876173440
101
+ version_requirements: *70195226819740
102
102
  - !ruby/object:Gem::Dependency
103
103
  name: cucumber
104
- requirement: &70110876172820 !ruby/object:Gem::Requirement
104
+ requirement: &70195226816180 !ruby/object:Gem::Requirement
105
105
  none: false
106
106
  requirements:
107
107
  - - =
@@ -109,10 +109,10 @@ dependencies:
109
109
  version: 1.1.9
110
110
  type: :development
111
111
  prerelease: false
112
- version_requirements: *70110876172820
112
+ version_requirements: *70195226816180
113
113
  - !ruby/object:Gem::Dependency
114
114
  name: pusher
115
- requirement: &70110876172220 !ruby/object:Gem::Requirement
115
+ requirement: &70195226828020 !ruby/object:Gem::Requirement
116
116
  none: false
117
117
  requirements:
118
118
  - - =
@@ -120,32 +120,43 @@ dependencies:
120
120
  version: 0.9.2
121
121
  type: :development
122
122
  prerelease: false
123
- version_requirements: *70110876172220
123
+ version_requirements: *70195226828020
124
+ - !ruby/object:Gem::Dependency
125
+ name: rake
126
+ requirement: &70195226824580 !ruby/object:Gem::Requirement
127
+ none: false
128
+ requirements:
129
+ - - =
130
+ - !ruby/object:Gem::Version
131
+ version: 0.9.2.2
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: *70195226824580
124
135
  - !ruby/object:Gem::Dependency
125
136
  name: redcarpet
126
- requirement: &70110876171320 !ruby/object:Gem::Requirement
137
+ requirement: &70195226822700 !ruby/object:Gem::Requirement
127
138
  none: false
128
139
  requirements:
129
140
  - - =
130
141
  - !ruby/object:Gem::Version
131
- version: 2.1.0
142
+ version: 2.1.1
132
143
  type: :development
133
144
  prerelease: false
134
- version_requirements: *70110876171320
145
+ version_requirements: *70195226822700
135
146
  - !ruby/object:Gem::Dependency
136
147
  name: rspec
137
- requirement: &70110876170800 !ruby/object:Gem::Requirement
148
+ requirement: &70195230220940 !ruby/object:Gem::Requirement
138
149
  none: false
139
150
  requirements:
140
151
  - - =
141
152
  - !ruby/object:Gem::Version
142
- version: 2.8.0
153
+ version: 2.9.0
143
154
  type: :development
144
155
  prerelease: false
145
- version_requirements: *70110876170800
156
+ version_requirements: *70195230220940
146
157
  - !ruby/object:Gem::Dependency
147
158
  name: sinatra
148
- requirement: &70110876170320 !ruby/object:Gem::Requirement
159
+ requirement: &70195230219480 !ruby/object:Gem::Requirement
149
160
  none: false
150
161
  requirements:
151
162
  - - =
@@ -153,10 +164,10 @@ dependencies:
153
164
  version: 1.3.2
154
165
  type: :development
155
166
  prerelease: false
156
- version_requirements: *70110876170320
167
+ version_requirements: *70195230219480
157
168
  - !ruby/object:Gem::Dependency
158
169
  name: yard
159
- requirement: &70110876169640 !ruby/object:Gem::Requirement
170
+ requirement: &70195230217620 !ruby/object:Gem::Requirement
160
171
  none: false
161
172
  requirements:
162
173
  - - =
@@ -164,7 +175,7 @@ dependencies:
164
175
  version: 0.7.5
165
176
  type: :development
166
177
  prerelease: false
167
- version_requirements: *70110876169640
178
+ version_requirements: *70195230217620
168
179
  description: A fake Pusher server for development and testing.
169
180
  email: hello@tristandunn.com
170
181
  executables: []
@@ -220,7 +231,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
220
231
  version: '0'
221
232
  segments:
222
233
  - 0
223
- hash: -4069294578046260452
234
+ hash: 1138384851111270143
224
235
  required_rubygems_version: !ruby/object:Gem::Requirement
225
236
  none: false
226
237
  requirements:
@@ -229,7 +240,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
229
240
  version: '0'
230
241
  segments:
231
242
  - 0
232
- hash: -4069294578046260452
243
+ hash: 1138384851111270143
233
244
  requirements: []
234
245
  rubyforge_project:
235
246
  rubygems_version: 1.8.11