diff options
-rw-r--r-- | Gemfile.lock | 13 | ||||
-rw-r--r-- | actioncable.gemspec | 10 | ||||
-rw-r--r-- | lib/action_cable.rb | 3 | ||||
-rw-r--r-- | lib/action_cable/channel/base.rb | 39 | ||||
-rw-r--r-- | lib/action_cable/version.rb | 3 | ||||
-rw-r--r-- | lib/assets/javascripts/cable/subscriptions.js.coffee | 8 | ||||
-rw-r--r-- | test/channel/base_test.rb | 40 | ||||
-rw-r--r-- | test/test_helper.rb | 2 |
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 |