aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Gemfile.lock13
-rw-r--r--actioncable.gemspec10
-rw-r--r--lib/action_cable.rb3
-rw-r--r--lib/action_cable/channel/base.rb39
-rw-r--r--lib/action_cable/version.rb3
-rw-r--r--lib/assets/javascripts/cable/subscriptions.js.coffee8
-rw-r--r--test/channel/base_test.rb40
-rw-r--r--test/test_helper.rb2
8 files changed, 100 insertions, 18 deletions
diff --git a/Gemfile.lock b/Gemfile.lock
index 822f27d5b1..0299c50f9f 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -7,9 +7,9 @@ PATH
celluloid (~> 0.16.0)
coffee-rails
em-hiredis (~> 0.3.0)
- faye-websocket (~> 0.9.2)
+ faye-websocket (~> 0.10.0)
redis (~> 3.0)
- websocket-driver (= 0.5.4)
+ websocket-driver (~> 0.6.1)
GEM
remote: https://rubygems.org/
@@ -49,7 +49,7 @@ GEM
erubis (2.7.0)
eventmachine (1.0.7)
execjs (2.5.2)
- faye-websocket (0.9.2)
+ faye-websocket (0.10.0)
eventmachine (>= 0.12.0)
websocket-driver (>= 0.5.1)
hiredis (0.5.2)
@@ -65,9 +65,8 @@ GEM
metaclass (~> 0.0.1)
nokogiri (1.6.6.2)
mini_portile (~> 0.6.0)
- puma (2.10.2)
- rack (>= 1.1, < 2.0)
- rack (1.6.0)
+ puma (2.12.2)
+ rack (1.6.4)
rack-test (0.6.3)
rack (>= 1.0)
rails-deprecated_sanitizer (1.0.3)
@@ -91,7 +90,7 @@ GEM
hitimes
tzinfo (1.2.2)
thread_safe (~> 0.1)
- websocket-driver (0.5.4)
+ websocket-driver (0.6.2)
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.2)
diff --git a/actioncable.gemspec b/actioncable.gemspec
index 509c5ca75a..02350186db 100644
--- a/actioncable.gemspec
+++ b/actioncable.gemspec
@@ -1,6 +1,9 @@
+$:.push File.expand_path("../lib", __FILE__)
+require 'action_cable/version'
+
Gem::Specification.new do |s|
s.name = 'actioncable'
- s.version = '0.1.0'
+ s.version = ActionCable::VERSION
s.summary = 'Websockets framework for Rails.'
s.description = 'Structure many real-time application concerns into channels over a single websockets connection.'
s.license = 'MIT'
@@ -13,8 +16,9 @@ Gem::Specification.new do |s|
s.add_dependency 'activesupport', '>= 4.2.0'
s.add_dependency 'actionpack', '>= 4.2.0'
- s.add_dependency 'faye-websocket', '~> 0.9.2'
- s.add_dependency 'websocket-driver', '= 0.5.4'
+ s.add_dependency 'faye-websocket', '~> 0.10.0'
+ s.add_dependency 'websocket-driver', '~> 0.6.1'
+ # Use 0.16.0 until https://github.com/celluloid/celluloid/issues/637 is resolved
s.add_dependency 'celluloid', '~> 0.16.0'
s.add_dependency 'em-hiredis', '~> 0.3.0'
s.add_dependency 'redis', '~> 3.0'
diff --git a/lib/action_cable.rb b/lib/action_cable.rb
index 968adafc25..13c5c77578 100644
--- a/lib/action_cable.rb
+++ b/lib/action_cable.rb
@@ -16,10 +16,9 @@ require 'em-hiredis'
require 'redis'
require 'action_cable/engine' if defined?(Rails)
+require 'action_cable/version'
module ActionCable
- VERSION = '0.0.3'
-
autoload :Server, 'action_cable/server'
autoload :Connection, 'action_cable/connection'
autoload :Channel, 'action_cable/channel'
diff --git a/lib/action_cable/channel/base.rb b/lib/action_cable/channel/base.rb
index c83c3b74fd..2f1b4a187d 100644
--- a/lib/action_cable/channel/base.rb
+++ b/lib/action_cable/channel/base.rb
@@ -77,6 +77,42 @@ module ActionCable
attr_reader :params, :connection
delegate :logger, to: :connection
+ class << self
+ # A list of method names that should be considered actions. This
+ # includes all public instance methods on a channel, less
+ # any internal methods (defined on Base), adding back in
+ # any methods that are internal, but still exist on the class
+ # itself.
+ #
+ # ==== Returns
+ # * <tt>Set</tt> - A set of all methods that should be considered actions.
+ def action_methods
+ @action_methods ||= begin
+ # All public instance methods of this class, including ancestors
+ methods = (public_instance_methods(true) -
+ # Except for public instance methods of Base and its ancestors
+ ActionCable::Channel::Base.public_instance_methods(true) +
+ # Be sure to include shadowed public instance methods of this class
+ public_instance_methods(false)).uniq.map(&:to_s)
+ methods.to_set
+ end
+ end
+
+ protected
+ # action_methods are cached and there is sometimes need to refresh
+ # them. ::clear_action_methods! allows you to do that, so next time
+ # you run action_methods, they will be recalculated
+ def clear_action_methods!
+ @action_methods = nil
+ end
+
+ # Refresh the cached action_methods when a new action_method is added.
+ def method_added(name)
+ super
+ clear_action_methods!
+ end
+ end
+
def initialize(connection, identifier, params = {})
@connection = connection
@identifier = identifier
@@ -149,7 +185,7 @@ module ActionCable
end
def processable_action?(action)
- self.class.instance_methods(false).include?(action)
+ self.class.action_methods.include?(action.to_s)
end
def dispatch_action(action, data)
@@ -170,7 +206,6 @@ module ActionCable
end
end
-
def run_subscribe_callbacks
self.class.on_subscribe_callbacks.each { |callback| send(callback) }
end
diff --git a/lib/action_cable/version.rb b/lib/action_cable/version.rb
new file mode 100644
index 0000000000..4947029dcc
--- /dev/null
+++ b/lib/action_cable/version.rb
@@ -0,0 +1,3 @@
+module ActionCable
+ VERSION = '0.0.3'
+end \ No newline at end of file
diff --git a/lib/assets/javascripts/cable/subscriptions.js.coffee b/lib/assets/javascripts/cable/subscriptions.js.coffee
index 3bc53f2d6a..fe6975c870 100644
--- a/lib/assets/javascripts/cable/subscriptions.js.coffee
+++ b/lib/assets/javascripts/cable/subscriptions.js.coffee
@@ -29,8 +29,12 @@ class Cable.Subscriptions
@notify(subscription, "connected")
remove: (subscription) ->
- @sendCommand(subscription, "unsubscribe")
@subscriptions = (s for s in @subscriptions when s isnt subscription)
+ unless @findAll(subscription.identifier).length
+ @sendCommand(subscription, "unsubscribe")
+
+ findAll: (identifier) ->
+ s for s in @subscriptions when s.identifier is identifier
notifyAll: (callbackName, args...) ->
for subscription in @subscriptions
@@ -38,7 +42,7 @@ class Cable.Subscriptions
notify: (subscription, callbackName, args...) ->
if typeof subscription is "string"
- subscriptions = (s for s in @subscriptions when s.identifier is subscription)
+ subscriptions = @findAll(subscription)
else
subscriptions = [subscription]
diff --git a/test/channel/base_test.rb b/test/channel/base_test.rb
index aa31d23297..e7944ff06b 100644
--- a/test/channel/base_test.rb
+++ b/test/channel/base_test.rb
@@ -3,7 +3,22 @@ require 'stubs/test_connection'
require 'stubs/room'
class ActionCable::Channel::BaseTest < ActiveSupport::TestCase
- class ChatChannel < ActionCable::Channel::Base
+ class ActionCable::Channel::Base
+ def kick
+ @last_action = [ :kick ]
+ end
+
+ def topic
+ end
+ end
+
+ class BasicChannel < ActionCable::Channel::Base
+ def chatters
+ @last_action = [ :chatters ]
+ end
+ end
+
+ class ChatChannel < BasicChannel
attr_reader :room, :last_action
on_subscribe :toggle_subscribed
on_unsubscribe :toggle_subscribed
@@ -29,6 +44,10 @@ class ActionCable::Channel::BaseTest < ActiveSupport::TestCase
@last_action = [ :speak, data ]
end
+ def topic(data)
+ @last_action = [ :topic, data ]
+ end
+
def subscribed?
@subscribed
end
@@ -87,11 +106,28 @@ class ActionCable::Channel::BaseTest < ActiveSupport::TestCase
assert_equal [ :speak, data ], @channel.last_action
end
- test "try calling a private method" do
+ test "should not dispatch a private method" do
@channel.perform_action 'action' => :rm_rf
assert_nil @channel.last_action
end
+ test "should not dispatch a public method defined on Base" do
+ @channel.perform_action 'action' => :kick
+ assert_nil @channel.last_action
+ end
+
+ test "should dispatch a public method defined on Base and redefined on channel" do
+ data = { 'action' => :topic, 'content' => "This is Sparta!" }
+
+ @channel.perform_action data
+ assert_equal [ :topic, data ], @channel.last_action
+ end
+
+ test "should dispatch calling a public method defined in an ancestor" do
+ @channel.perform_action 'action' => :chatters
+ assert_equal [ :chatters ], @channel.last_action
+ end
+
test "transmitting data" do
@channel.perform_action 'action' => :get_latest
diff --git a/test/test_helper.rb b/test/test_helper.rb
index 759ea18524..5640178f34 100644
--- a/test/test_helper.rb
+++ b/test/test_helper.rb
@@ -10,6 +10,8 @@ Bundler.require :default, :test
require 'puma'
require 'mocha/mini_test'
+require 'rack/mock'
+
require 'action_cable'
ActiveSupport.test_order = :sorted