motion 0.1.1 → 0.3.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.
- checksums.yaml +4 -4
 - data/lib/generators/motion/component_generator.rb +34 -0
 - data/lib/generators/motion/install_generator.rb +10 -3
 - data/lib/generators/motion/templates/motion.js +37 -0
 - data/lib/generators/motion/templates/motion.rb +54 -15
 - data/lib/motion.rb +5 -0
 - data/lib/motion/action_cable_extentions.rb +6 -0
 - data/lib/motion/action_cable_extentions/declarative_notifications.rb +101 -0
 - data/lib/motion/action_cable_extentions/declarative_streams.rb +12 -45
 - data/lib/motion/action_cable_extentions/synchronization.rb +34 -0
 - data/lib/motion/channel.rb +12 -4
 - data/lib/motion/component.rb +2 -0
 - data/lib/motion/component/broadcasts.rb +40 -26
 - data/lib/motion/component/lifecycle.rb +91 -9
 - data/lib/motion/component/motions.rb +26 -16
 - data/lib/motion/component/periodic_timers.rb +68 -0
 - data/lib/motion/component/rendering.rb +11 -14
 - data/lib/motion/component_connection.rb +18 -2
 - data/lib/motion/configuration.rb +18 -11
 - data/lib/motion/errors.rb +102 -71
 - data/lib/motion/event.rb +9 -1
 - data/lib/motion/log_helper.rb +2 -0
 - data/lib/motion/markup_transformer.rb +6 -21
 - data/lib/motion/railtie.rb +1 -0
 - data/lib/motion/revision_calculator.rb +48 -0
 - data/lib/motion/serializer.rb +4 -0
 - data/lib/motion/version.rb +1 -1
 - metadata +12 -7
 - data/lib/generators/motion/templates/motion_controller.js +0 -28
 
    
        data/lib/motion/component.rb
    CHANGED
    
    | 
         @@ -7,6 +7,7 @@ require "motion" 
     | 
|
| 
       7 
7 
     | 
    
         
             
            require "motion/component/broadcasts"
         
     | 
| 
       8 
8 
     | 
    
         
             
            require "motion/component/lifecycle"
         
     | 
| 
       9 
9 
     | 
    
         
             
            require "motion/component/motions"
         
     | 
| 
      
 10 
     | 
    
         
            +
            require "motion/component/periodic_timers"
         
     | 
| 
       10 
11 
     | 
    
         
             
            require "motion/component/rendering"
         
     | 
| 
       11 
12 
     | 
    
         | 
| 
       12 
13 
     | 
    
         
             
            module Motion
         
     | 
| 
         @@ -16,6 +17,7 @@ module Motion 
     | 
|
| 
       16 
17 
     | 
    
         
             
                include Broadcasts
         
     | 
| 
       17 
18 
     | 
    
         
             
                include Lifecycle
         
     | 
| 
       18 
19 
     | 
    
         
             
                include Motions
         
     | 
| 
      
 20 
     | 
    
         
            +
                include PeriodicTimers
         
     | 
| 
       19 
21 
     | 
    
         
             
                include Rendering
         
     | 
| 
       20 
22 
     | 
    
         
             
              end
         
     | 
| 
       21 
23 
     | 
    
         
             
            end
         
     | 
| 
         @@ -3,6 +3,7 @@ 
     | 
|
| 
       3 
3 
     | 
    
         
             
            require "active_support/concern"
         
     | 
| 
       4 
4 
     | 
    
         
             
            require "active_support/core_ext/class/attribute"
         
     | 
| 
       5 
5 
     | 
    
         
             
            require "active_support/core_ext/object/to_param"
         
     | 
| 
      
 6 
     | 
    
         
            +
            require "active_support/core_ext/hash/except"
         
     | 
| 
       6 
7 
     | 
    
         | 
| 
       7 
8 
     | 
    
         
             
            require "motion"
         
     | 
| 
       8 
9 
     | 
    
         | 
| 
         @@ -11,6 +12,31 @@ module Motion 
     | 
|
| 
       11 
12 
     | 
    
         
             
                module Broadcasts
         
     | 
| 
       12 
13 
     | 
    
         
             
                  extend ActiveSupport::Concern
         
     | 
| 
       13 
14 
     | 
    
         | 
| 
      
 15 
     | 
    
         
            +
                  # Analogous to `module_function` (available on both class and instance)
         
     | 
| 
      
 16 
     | 
    
         
            +
                  module ModuleFunctions
         
     | 
| 
      
 17 
     | 
    
         
            +
                    def stream_from(broadcast, handler)
         
     | 
| 
      
 18 
     | 
    
         
            +
                      self._broadcast_handlers =
         
     | 
| 
      
 19 
     | 
    
         
            +
                        _broadcast_handlers.merge(broadcast.to_s => handler.to_sym).freeze
         
     | 
| 
      
 20 
     | 
    
         
            +
                    end
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                    def stop_streaming_from(broadcast)
         
     | 
| 
      
 23 
     | 
    
         
            +
                      self._broadcast_handlers =
         
     | 
| 
      
 24 
     | 
    
         
            +
                        _broadcast_handlers.except(broadcast.to_s).freeze
         
     | 
| 
      
 25 
     | 
    
         
            +
                    end
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                    def stream_for(model, handler)
         
     | 
| 
      
 28 
     | 
    
         
            +
                      stream_from(broadcasting_for(model), handler)
         
     | 
| 
      
 29 
     | 
    
         
            +
                    end
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                    def stop_streaming_for(model)
         
     | 
| 
      
 32 
     | 
    
         
            +
                      stop_streaming_from(broadcasting_for(model))
         
     | 
| 
      
 33 
     | 
    
         
            +
                    end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                    def broadcasts
         
     | 
| 
      
 36 
     | 
    
         
            +
                      _broadcast_handlers.keys
         
     | 
| 
      
 37 
     | 
    
         
            +
                    end
         
     | 
| 
      
 38 
     | 
    
         
            +
                  end
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
       14 
40 
     | 
    
         
             
                  included do
         
     | 
| 
       15 
41 
     | 
    
         
             
                    class_attribute :_broadcast_handlers,
         
     | 
| 
       16 
42 
     | 
    
         
             
                      instance_reader: false,
         
     | 
| 
         @@ -20,26 +46,19 @@ module Motion 
     | 
|
| 
       20 
46 
     | 
    
         
             
                  end
         
     | 
| 
       21 
47 
     | 
    
         | 
| 
       22 
48 
     | 
    
         
             
                  class_methods do
         
     | 
| 
      
 49 
     | 
    
         
            +
                    include ModuleFunctions
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
       23 
51 
     | 
    
         
             
                    def broadcast_to(model, message)
         
     | 
| 
       24 
52 
     | 
    
         
             
                      ActionCable.server.broadcast(broadcasting_for(model), message)
         
     | 
| 
       25 
53 
     | 
    
         
             
                    end
         
     | 
| 
       26 
54 
     | 
    
         | 
| 
       27 
     | 
    
         
            -
                    def stream_from(broadcast, handler)
         
     | 
| 
       28 
     | 
    
         
            -
                      self._broadcast_handlers =
         
     | 
| 
       29 
     | 
    
         
            -
                        _broadcast_handlers.merge(broadcast.to_s => handler.to_sym).freeze
         
     | 
| 
       30 
     | 
    
         
            -
                    end
         
     | 
| 
       31 
     | 
    
         
            -
             
     | 
| 
       32 
     | 
    
         
            -
                    def stream_for(model, handler)
         
     | 
| 
       33 
     | 
    
         
            -
                      stream_from(broadcasting_for(model), handler)
         
     | 
| 
       34 
     | 
    
         
            -
                    end
         
     | 
| 
       35 
     | 
    
         
            -
             
     | 
| 
       36 
55 
     | 
    
         
             
                    def broadcasting_for(model)
         
     | 
| 
       37 
56 
     | 
    
         
             
                      serialize_broadcasting([name, model])
         
     | 
| 
       38 
57 
     | 
    
         
             
                    end
         
     | 
| 
       39 
58 
     | 
    
         | 
| 
       40 
59 
     | 
    
         
             
                    private
         
     | 
| 
       41 
60 
     | 
    
         | 
| 
       42 
     | 
    
         
            -
                    #  
     | 
| 
      
 61 
     | 
    
         
            +
                    # This definition is copied from ActionCable::Channel::Broadcasting
         
     | 
| 
       43 
62 
     | 
    
         
             
                    def serialize_broadcasting(object)
         
     | 
| 
       44 
63 
     | 
    
         
             
                      if object.is_a?(Array)
         
     | 
| 
       45 
64 
     | 
    
         
             
                        object.map { |m| serialize_broadcasting(m) }.join(":")
         
     | 
| 
         @@ -51,31 +70,26 @@ module Motion 
     | 
|
| 
       51 
70 
     | 
    
         
             
                    end
         
     | 
| 
       52 
71 
     | 
    
         
             
                  end
         
     | 
| 
       53 
72 
     | 
    
         | 
| 
       54 
     | 
    
         
            -
                   
     | 
| 
       55 
     | 
    
         
            -
                    _broadcast_handlers.keys
         
     | 
| 
       56 
     | 
    
         
            -
                  end
         
     | 
| 
      
 73 
     | 
    
         
            +
                  include ModuleFunctions
         
     | 
| 
       57 
74 
     | 
    
         | 
| 
       58 
75 
     | 
    
         
             
                  def process_broadcast(broadcast, message)
         
     | 
| 
       59 
76 
     | 
    
         
             
                    return unless (handler = _broadcast_handlers[broadcast])
         
     | 
| 
       60 
77 
     | 
    
         | 
| 
       61 
     | 
    
         
            -
                     
     | 
| 
       62 
     | 
    
         
            -
             
     | 
| 
       63 
     | 
    
         
            -
             
     | 
| 
       64 
     | 
    
         
            -
             
     | 
| 
       65 
     | 
    
         
            -
             
     | 
| 
      
 78 
     | 
    
         
            +
                    _run_action_callbacks(context: handler) do
         
     | 
| 
      
 79 
     | 
    
         
            +
                      if method(handler).arity.zero?
         
     | 
| 
      
 80 
     | 
    
         
            +
                        send(handler)
         
     | 
| 
      
 81 
     | 
    
         
            +
                      else
         
     | 
| 
      
 82 
     | 
    
         
            +
                        send(handler, message)
         
     | 
| 
      
 83 
     | 
    
         
            +
                      end
         
     | 
| 
      
 84 
     | 
    
         
            +
                    end
         
     | 
| 
       66 
85 
     | 
    
         
             
                  end
         
     | 
| 
       67 
86 
     | 
    
         | 
| 
       68 
     | 
    
         
            -
                   
     | 
| 
       69 
     | 
    
         
            -
                    self._broadcast_handlers =
         
     | 
| 
       70 
     | 
    
         
            -
                      _broadcast_handlers.merge(broadcast.to_s => handler.to_sym).freeze
         
     | 
| 
       71 
     | 
    
         
            -
                  end
         
     | 
| 
      
 87 
     | 
    
         
            +
                  private
         
     | 
| 
       72 
88 
     | 
    
         | 
| 
       73 
     | 
    
         
            -
                  def  
     | 
| 
       74 
     | 
    
         
            -
                     
     | 
| 
      
 89 
     | 
    
         
            +
                  def broadcasting_for(model)
         
     | 
| 
      
 90 
     | 
    
         
            +
                    self.class.broadcasting_for(model)
         
     | 
| 
       75 
91 
     | 
    
         
             
                  end
         
     | 
| 
       76 
92 
     | 
    
         | 
| 
       77 
     | 
    
         
            -
                  private
         
     | 
| 
       78 
     | 
    
         
            -
             
     | 
| 
       79 
93 
     | 
    
         
             
                  attr_writer :_broadcast_handlers
         
     | 
| 
       80 
94 
     | 
    
         | 
| 
       81 
95 
     | 
    
         
             
                  def _broadcast_handlers
         
     | 
| 
         @@ -1,6 +1,8 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # frozen_string_literal: true
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
      
 3 
     | 
    
         
            +
            require "active_support/callbacks"
         
     | 
| 
       3 
4 
     | 
    
         
             
            require "active_support/concern"
         
     | 
| 
      
 5 
     | 
    
         
            +
            require "active_support/deprecation"
         
     | 
| 
       4 
6 
     | 
    
         | 
| 
       5 
7 
     | 
    
         
             
            require "motion"
         
     | 
| 
       6 
8 
     | 
    
         | 
| 
         @@ -9,22 +11,102 @@ module Motion 
     | 
|
| 
       9 
11 
     | 
    
         
             
                module Lifecycle
         
     | 
| 
       10 
12 
     | 
    
         
             
                  extend ActiveSupport::Concern
         
     | 
| 
       11 
13 
     | 
    
         | 
| 
      
 14 
     | 
    
         
            +
                  include ActiveSupport::Callbacks
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                  included do
         
     | 
| 
      
 17 
     | 
    
         
            +
                    define_callbacks :action, :connect, :disconnect
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                    # The built-in triggers defined on the target class will override ours.
         
     | 
| 
      
 20 
     | 
    
         
            +
                    remove_method(:_run_action_callbacks)
         
     | 
| 
      
 21 
     | 
    
         
            +
                  end
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
       12 
23 
     | 
    
         
             
                  class_methods do
         
     | 
| 
       13 
     | 
    
         
            -
                     
     | 
| 
       14 
     | 
    
         
            -
             
     | 
| 
       15 
     | 
    
         
            -
             
     | 
| 
       16 
     | 
    
         
            -
             
     | 
| 
       17 
     | 
    
         
            -
             
     | 
| 
       18 
     | 
    
         
            -
                        Motion.config.revision,
         
     | 
| 
       19 
     | 
    
         
            -
                        previous_revision
         
     | 
| 
      
 24 
     | 
    
         
            +
                    def upgrade_from(previous_revision, instance)
         
     | 
| 
      
 25 
     | 
    
         
            +
                      raise UpgradeNotImplementedError.new(
         
     | 
| 
      
 26 
     | 
    
         
            +
                        instance,
         
     | 
| 
      
 27 
     | 
    
         
            +
                        previous_revision,
         
     | 
| 
      
 28 
     | 
    
         
            +
                        Motion.config.revision
         
     | 
| 
       20 
29 
     | 
    
         
             
                      )
         
     | 
| 
       21 
30 
     | 
    
         
             
                    end
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                    def before_action(*methods, **options, &block)
         
     | 
| 
      
 33 
     | 
    
         
            +
                      set_action_callback(:before, *methods, **options, &block)
         
     | 
| 
      
 34 
     | 
    
         
            +
                    end
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
                    def around_action(*methods, **options, &block)
         
     | 
| 
      
 37 
     | 
    
         
            +
                      set_action_callback(:around, *methods, **options, &block)
         
     | 
| 
      
 38 
     | 
    
         
            +
                    end
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
                    def after_action(*methods, **options, &block)
         
     | 
| 
      
 41 
     | 
    
         
            +
                      set_action_callback(:after, *methods, **options, &block)
         
     | 
| 
      
 42 
     | 
    
         
            +
                    end
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
                    def after_connect(*methods, **options, &block)
         
     | 
| 
      
 45 
     | 
    
         
            +
                      set_callback(:connect, :after, *methods, **options, &block)
         
     | 
| 
      
 46 
     | 
    
         
            +
                    end
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
                    def after_disconnect(*methods, **options, &block)
         
     | 
| 
      
 49 
     | 
    
         
            +
                      set_callback(:disconnect, :after, *methods, **options, &block)
         
     | 
| 
      
 50 
     | 
    
         
            +
                    end
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
                    private
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
                    def set_action_callback(kind, *methods, **options, &block)
         
     | 
| 
      
 55 
     | 
    
         
            +
                      filters = Array(options.delete(:if))
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                      if (only = Array(options.delete(:only))).any?
         
     | 
| 
      
 58 
     | 
    
         
            +
                        filters << action_callback_context_filter(only)
         
     | 
| 
      
 59 
     | 
    
         
            +
                      end
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
                      if (except = Array(options.delete(:except))).any?
         
     | 
| 
      
 62 
     | 
    
         
            +
                        filters << action_callback_context_filter(except, invert: true)
         
     | 
| 
      
 63 
     | 
    
         
            +
                      end
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
                      set_callback(:action, kind, *methods, if: filters, **options, &block)
         
     | 
| 
      
 66 
     | 
    
         
            +
                    end
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
                    def action_callback_context_filter(contexts, invert: false)
         
     | 
| 
      
 69 
     | 
    
         
            +
                      proc { contexts.include?(@_action_callback_context) ^ invert }
         
     | 
| 
      
 70 
     | 
    
         
            +
                    end
         
     | 
| 
      
 71 
     | 
    
         
            +
                  end
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
                  def process_connect
         
     | 
| 
      
 74 
     | 
    
         
            +
                    _run_connect_callbacks
         
     | 
| 
      
 75 
     | 
    
         
            +
             
     | 
| 
      
 76 
     | 
    
         
            +
                    # TODO: Remove at next minor release
         
     | 
| 
      
 77 
     | 
    
         
            +
                    if respond_to?(:connected)
         
     | 
| 
      
 78 
     | 
    
         
            +
                      ActiveSupport::Deprecation.warn(
         
     | 
| 
      
 79 
     | 
    
         
            +
                        "The `connected` lifecycle method is being replaced by the " \
         
     | 
| 
      
 80 
     | 
    
         
            +
                        "`after_connect` callback and will no longer be automatically " \
         
     | 
| 
      
 81 
     | 
    
         
            +
                        "invoked in the next **minor release** of Motion."
         
     | 
| 
      
 82 
     | 
    
         
            +
                      )
         
     | 
| 
      
 83 
     | 
    
         
            +
             
     | 
| 
      
 84 
     | 
    
         
            +
                      send(:connected)
         
     | 
| 
      
 85 
     | 
    
         
            +
                    end
         
     | 
| 
       22 
86 
     | 
    
         
             
                  end
         
     | 
| 
       23 
87 
     | 
    
         | 
| 
       24 
     | 
    
         
            -
                  def  
     | 
| 
      
 88 
     | 
    
         
            +
                  def process_disconnect
         
     | 
| 
      
 89 
     | 
    
         
            +
                    _run_disconnect_callbacks
         
     | 
| 
      
 90 
     | 
    
         
            +
             
     | 
| 
      
 91 
     | 
    
         
            +
                    # TODO: Remove at next minor release
         
     | 
| 
      
 92 
     | 
    
         
            +
                    if respond_to?(:disconnected)
         
     | 
| 
      
 93 
     | 
    
         
            +
                      ActiveSupport::Deprecation.warn(
         
     | 
| 
      
 94 
     | 
    
         
            +
                        "The `disconnected` lifecycle method is being replaced by the " \
         
     | 
| 
      
 95 
     | 
    
         
            +
                        "`after_disconnect` callback and will no longer be automatically " \
         
     | 
| 
      
 96 
     | 
    
         
            +
                        "invoked in the next **minor release** of Motion."
         
     | 
| 
      
 97 
     | 
    
         
            +
                      )
         
     | 
| 
      
 98 
     | 
    
         
            +
             
     | 
| 
      
 99 
     | 
    
         
            +
                      send(:disconnected)
         
     | 
| 
      
 100 
     | 
    
         
            +
                    end
         
     | 
| 
       25 
101 
     | 
    
         
             
                  end
         
     | 
| 
       26 
102 
     | 
    
         | 
| 
       27 
     | 
    
         
            -
                  def  
     | 
| 
      
 103 
     | 
    
         
            +
                  def _run_action_callbacks(context:, &block)
         
     | 
| 
      
 104 
     | 
    
         
            +
                    @_action_callback_context = context
         
     | 
| 
      
 105 
     | 
    
         
            +
             
     | 
| 
      
 106 
     | 
    
         
            +
                    run_callbacks(:action, &block)
         
     | 
| 
      
 107 
     | 
    
         
            +
                  ensure
         
     | 
| 
      
 108 
     | 
    
         
            +
                    # `@_action_callback_context = nil` would still appear in the state
         
     | 
| 
      
 109 
     | 
    
         
            +
                    remove_instance_variable(:@_action_callback_context)
         
     | 
| 
       28 
110 
     | 
    
         
             
                  end
         
     | 
| 
       29 
111 
     | 
    
         
             
                end
         
     | 
| 
       30 
112 
     | 
    
         
             
              end
         
     | 
| 
         @@ -2,6 +2,7 @@ 
     | 
|
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            require "active_support/concern"
         
     | 
| 
       4 
4 
     | 
    
         
             
            require "active_support/core_ext/class/attribute"
         
     | 
| 
      
 5 
     | 
    
         
            +
            require "active_support/core_ext/hash/except"
         
     | 
| 
       5 
6 
     | 
    
         | 
| 
       6 
7 
     | 
    
         
             
            require "motion"
         
     | 
| 
       7 
8 
     | 
    
         | 
| 
         @@ -10,6 +11,23 @@ module Motion 
     | 
|
| 
       10 
11 
     | 
    
         
             
                module Motions
         
     | 
| 
       11 
12 
     | 
    
         
             
                  extend ActiveSupport::Concern
         
     | 
| 
       12 
13 
     | 
    
         | 
| 
      
 14 
     | 
    
         
            +
                  # Analogous to `module_function` (available on both class and instance)
         
     | 
| 
      
 15 
     | 
    
         
            +
                  module ModuleFunctions
         
     | 
| 
      
 16 
     | 
    
         
            +
                    def map_motion(motion, handler = motion)
         
     | 
| 
      
 17 
     | 
    
         
            +
                      self._motion_handlers =
         
     | 
| 
      
 18 
     | 
    
         
            +
                        _motion_handlers.merge(motion.to_s => handler.to_sym).freeze
         
     | 
| 
      
 19 
     | 
    
         
            +
                    end
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                    def unmap_motion(motion)
         
     | 
| 
      
 22 
     | 
    
         
            +
                      self._motion_handlers =
         
     | 
| 
      
 23 
     | 
    
         
            +
                        _motion_handlers.except(motion.to_s).freeze
         
     | 
| 
      
 24 
     | 
    
         
            +
                    end
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                    def motions
         
     | 
| 
      
 27 
     | 
    
         
            +
                      _motion_handlers.keys
         
     | 
| 
      
 28 
     | 
    
         
            +
                    end
         
     | 
| 
      
 29 
     | 
    
         
            +
                  end
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
       13 
31 
     | 
    
         
             
                  included do
         
     | 
| 
       14 
32 
     | 
    
         
             
                    class_attribute :_motion_handlers,
         
     | 
| 
       15 
33 
     | 
    
         
             
                      instance_reader: false,
         
     | 
| 
         @@ -19,33 +37,25 @@ module Motion 
     | 
|
| 
       19 
37 
     | 
    
         
             
                  end
         
     | 
| 
       20 
38 
     | 
    
         | 
| 
       21 
39 
     | 
    
         
             
                  class_methods do
         
     | 
| 
       22 
     | 
    
         
            -
                     
     | 
| 
       23 
     | 
    
         
            -
                      self._motion_handlers =
         
     | 
| 
       24 
     | 
    
         
            -
                        _motion_handlers.merge(motion.to_s => handler.to_sym).freeze
         
     | 
| 
       25 
     | 
    
         
            -
                    end
         
     | 
| 
      
 40 
     | 
    
         
            +
                    include ModuleFunctions
         
     | 
| 
       26 
41 
     | 
    
         
             
                  end
         
     | 
| 
       27 
42 
     | 
    
         | 
| 
       28 
     | 
    
         
            -
                   
     | 
| 
       29 
     | 
    
         
            -
                    _motion_handlers.keys
         
     | 
| 
       30 
     | 
    
         
            -
                  end
         
     | 
| 
      
 43 
     | 
    
         
            +
                  include ModuleFunctions
         
     | 
| 
       31 
44 
     | 
    
         | 
| 
       32 
45 
     | 
    
         
             
                  def process_motion(motion, event = nil)
         
     | 
| 
       33 
46 
     | 
    
         
             
                    unless (handler = _motion_handlers[motion])
         
     | 
| 
       34 
47 
     | 
    
         
             
                      raise MotionNotMapped.new(self, motion)
         
     | 
| 
       35 
48 
     | 
    
         
             
                    end
         
     | 
| 
       36 
49 
     | 
    
         | 
| 
       37 
     | 
    
         
            -
                     
     | 
| 
       38 
     | 
    
         
            -
                       
     | 
| 
       39 
     | 
    
         
            -
             
     | 
| 
       40 
     | 
    
         
            -
                       
     | 
| 
      
 50 
     | 
    
         
            +
                    _run_action_callbacks(context: handler) do
         
     | 
| 
      
 51 
     | 
    
         
            +
                      if method(handler).arity.zero?
         
     | 
| 
      
 52 
     | 
    
         
            +
                        send(handler)
         
     | 
| 
      
 53 
     | 
    
         
            +
                      else
         
     | 
| 
      
 54 
     | 
    
         
            +
                        send(handler, event)
         
     | 
| 
      
 55 
     | 
    
         
            +
                      end
         
     | 
| 
       41 
56 
     | 
    
         
             
                    end
         
     | 
| 
       42 
57 
     | 
    
         
             
                  end
         
     | 
| 
       43 
58 
     | 
    
         | 
| 
       44 
     | 
    
         
            -
                  def map_motion(motion, handler = motion)
         
     | 
| 
       45 
     | 
    
         
            -
                    self._motion_handlers =
         
     | 
| 
       46 
     | 
    
         
            -
                      _motion_handlers.merge(motion.to_s => handler.to_sym).freeze
         
     | 
| 
       47 
     | 
    
         
            -
                  end
         
     | 
| 
       48 
     | 
    
         
            -
             
     | 
| 
       49 
59 
     | 
    
         
             
                  private
         
     | 
| 
       50 
60 
     | 
    
         | 
| 
       51 
61 
     | 
    
         
             
                  attr_writer :_motion_handlers
         
     | 
| 
         @@ -0,0 +1,68 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require "active_support/concern"
         
     | 
| 
      
 4 
     | 
    
         
            +
            require "active_support/core_ext/class/attribute"
         
     | 
| 
      
 5 
     | 
    
         
            +
            require "active_support/core_ext/hash/except"
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            require "motion"
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            module Motion
         
     | 
| 
      
 10 
     | 
    
         
            +
              module Component
         
     | 
| 
      
 11 
     | 
    
         
            +
                module PeriodicTimers
         
     | 
| 
      
 12 
     | 
    
         
            +
                  extend ActiveSupport::Concern
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                  # Analogous to `module_function` (available on both class and instance)
         
     | 
| 
      
 15 
     | 
    
         
            +
                  module ModuleFunctions
         
     | 
| 
      
 16 
     | 
    
         
            +
                    def every(interval, handler, name: handler)
         
     | 
| 
      
 17 
     | 
    
         
            +
                      periodic_timer(name, handler, every: interval)
         
     | 
| 
      
 18 
     | 
    
         
            +
                    end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                    def periodic_timer(name, handler = name, every:)
         
     | 
| 
      
 21 
     | 
    
         
            +
                      self._periodic_timers =
         
     | 
| 
      
 22 
     | 
    
         
            +
                        _periodic_timers.merge(name.to_s => [handler.to_sym, every]).freeze
         
     | 
| 
      
 23 
     | 
    
         
            +
                    end
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                    def stop_periodic_timer(name)
         
     | 
| 
      
 26 
     | 
    
         
            +
                      self._periodic_timers =
         
     | 
| 
      
 27 
     | 
    
         
            +
                        _periodic_timers.except(name.to_s).freeze
         
     | 
| 
      
 28 
     | 
    
         
            +
                    end
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                    def periodic_timers
         
     | 
| 
      
 31 
     | 
    
         
            +
                      _periodic_timers.transform_values { |_handler, interval| interval }
         
     | 
| 
      
 32 
     | 
    
         
            +
                    end
         
     | 
| 
      
 33 
     | 
    
         
            +
                  end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                  included do
         
     | 
| 
      
 36 
     | 
    
         
            +
                    class_attribute :_periodic_timers,
         
     | 
| 
      
 37 
     | 
    
         
            +
                      instance_reader: false,
         
     | 
| 
      
 38 
     | 
    
         
            +
                      instance_writer: false,
         
     | 
| 
      
 39 
     | 
    
         
            +
                      instance_predicate: false,
         
     | 
| 
      
 40 
     | 
    
         
            +
                      default: {}.freeze
         
     | 
| 
      
 41 
     | 
    
         
            +
                  end
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                  class_methods do
         
     | 
| 
      
 44 
     | 
    
         
            +
                    include ModuleFunctions
         
     | 
| 
      
 45 
     | 
    
         
            +
                  end
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                  include ModuleFunctions
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
                  def process_periodic_timer(name)
         
     | 
| 
      
 50 
     | 
    
         
            +
                    return unless (handler, _interval = _periodic_timers[name])
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
                    _run_action_callbacks(context: handler) do
         
     | 
| 
      
 53 
     | 
    
         
            +
                      send(handler)
         
     | 
| 
      
 54 
     | 
    
         
            +
                    end
         
     | 
| 
      
 55 
     | 
    
         
            +
                  end
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                  private
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
                  attr_writer :_periodic_timers
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
                  def _periodic_timers
         
     | 
| 
      
 62 
     | 
    
         
            +
                    return @_periodic_timers if defined?(@_periodic_timers)
         
     | 
| 
      
 63 
     | 
    
         
            +
             
     | 
| 
      
 64 
     | 
    
         
            +
                    self.class._periodic_timers
         
     | 
| 
      
 65 
     | 
    
         
            +
                  end
         
     | 
| 
      
 66 
     | 
    
         
            +
                end
         
     | 
| 
      
 67 
     | 
    
         
            +
              end
         
     | 
| 
      
 68 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -24,36 +24,33 @@ module Motion 
     | 
|
| 
       24 
24 
     | 
    
         
             
                  # * If it doesn't change every time the component's state changes,
         
     | 
| 
       25 
25 
     | 
    
         
             
                  #   things may fall out of sync unless you also call `#rerender!`
         
     | 
| 
       26 
26 
     | 
    
         
             
                  def render_hash
         
     | 
| 
       27 
     | 
    
         
            -
                     
     | 
| 
       28 
     | 
    
         
            -
                    #
         
     | 
| 
       29 
     | 
    
         
            -
                    # Is something with Ruby's built-in `hash` Good Enough(TM)?
         
     | 
| 
       30 
     | 
    
         
            -
                    #
         
     | 
| 
       31 
     | 
    
         
            -
                    #  instance_variables
         
     | 
| 
       32 
     | 
    
         
            -
                    #    .map { |ivar| instance_variable_get(ivar).hash }
         
     | 
| 
       33 
     | 
    
         
            -
                    #    .reduce(0, &:^)
         
     | 
| 
       34 
     | 
    
         
            -
             
     | 
| 
       35 
     | 
    
         
            -
                    key, _state = Motion.serializer.serialize(self)
         
     | 
| 
       36 
     | 
    
         
            -
                    key
         
     | 
| 
      
 27 
     | 
    
         
            +
                    Motion.serializer.weak_digest(self)
         
     | 
| 
       37 
28 
     | 
    
         
             
                  end
         
     | 
| 
       38 
29 
     | 
    
         | 
| 
       39 
30 
     | 
    
         
             
                  def render_in(view_context)
         
     | 
| 
       40 
31 
     | 
    
         
             
                    raise BlockNotAllowedError, self if block_given?
         
     | 
| 
       41 
     | 
    
         
            -
                    clear_awaiting_forced_rerender!
         
     | 
| 
       42 
32 
     | 
    
         | 
| 
       43 
     | 
    
         
            -
                    html = 
     | 
| 
      
 33 
     | 
    
         
            +
                    html =
         
     | 
| 
      
 34 
     | 
    
         
            +
                      _run_action_callbacks(context: :render) {
         
     | 
| 
      
 35 
     | 
    
         
            +
                        _clear_awaiting_forced_rerender!
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                        view_context.capture { _without_new_instance_variables { super } }
         
     | 
| 
      
 38 
     | 
    
         
            +
                      }
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
                    raise RenderAborted, self if html == false
         
     | 
| 
       44 
41 
     | 
    
         | 
| 
       45 
42 
     | 
    
         
             
                    Motion.markup_transformer.add_state_to_html(self, html)
         
     | 
| 
       46 
43 
     | 
    
         
             
                  end
         
     | 
| 
       47 
44 
     | 
    
         | 
| 
       48 
45 
     | 
    
         
             
                  private
         
     | 
| 
       49 
46 
     | 
    
         | 
| 
       50 
     | 
    
         
            -
                  def  
     | 
| 
      
 47 
     | 
    
         
            +
                  def _clear_awaiting_forced_rerender!
         
     | 
| 
       51 
48 
     | 
    
         
             
                    return unless awaiting_forced_rerender?
         
     | 
| 
       52 
49 
     | 
    
         | 
| 
       53 
50 
     | 
    
         
             
                    remove_instance_variable(RERENDER_MARKER_IVAR)
         
     | 
| 
       54 
51 
     | 
    
         
             
                  end
         
     | 
| 
       55 
52 
     | 
    
         | 
| 
       56 
     | 
    
         
            -
                  def  
     | 
| 
      
 53 
     | 
    
         
            +
                  def _without_new_instance_variables
         
     | 
| 
       57 
54 
     | 
    
         
             
                    existing_instance_variables = instance_variables
         
     | 
| 
       58 
55 
     | 
    
         | 
| 
       59 
56 
     | 
    
         
             
                    yield
         
     | 
| 
         @@ -24,13 +24,13 @@ module Motion 
     | 
|
| 
       24 
24 
     | 
    
         
             
                  timing("Connected") do
         
     | 
| 
       25 
25 
     | 
    
         
             
                    @render_hash = component.render_hash
         
     | 
| 
       26 
26 
     | 
    
         | 
| 
       27 
     | 
    
         
            -
                    component. 
     | 
| 
      
 27 
     | 
    
         
            +
                    component.process_connect
         
     | 
| 
       28 
28 
     | 
    
         
             
                  end
         
     | 
| 
       29 
29 
     | 
    
         
             
                end
         
     | 
| 
       30 
30 
     | 
    
         | 
| 
       31 
31 
     | 
    
         
             
                def close
         
     | 
| 
       32 
32 
     | 
    
         
             
                  timing("Disconnected") do
         
     | 
| 
       33 
     | 
    
         
            -
                    component. 
     | 
| 
      
 33 
     | 
    
         
            +
                    component.process_disconnect
         
     | 
| 
       34 
34 
     | 
    
         
             
                  end
         
     | 
| 
       35 
35 
     | 
    
         | 
| 
       36 
36 
     | 
    
         
             
                  true
         
     | 
| 
         @@ -64,6 +64,18 @@ module Motion 
     | 
|
| 
       64 
64 
     | 
    
         
             
                  false
         
     | 
| 
       65 
65 
     | 
    
         
             
                end
         
     | 
| 
       66 
66 
     | 
    
         | 
| 
      
 67 
     | 
    
         
            +
                def process_periodic_timer(timer)
         
     | 
| 
      
 68 
     | 
    
         
            +
                  timing("Proccessed periodic timer #{timer}") do
         
     | 
| 
      
 69 
     | 
    
         
            +
                    component.process_periodic_timer timer
         
     | 
| 
      
 70 
     | 
    
         
            +
                  end
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
                  true
         
     | 
| 
      
 73 
     | 
    
         
            +
                rescue => error
         
     | 
| 
      
 74 
     | 
    
         
            +
                  handle_error(error, "processing periodic timer #{timer}")
         
     | 
| 
      
 75 
     | 
    
         
            +
             
     | 
| 
      
 76 
     | 
    
         
            +
                  false
         
     | 
| 
      
 77 
     | 
    
         
            +
                end
         
     | 
| 
      
 78 
     | 
    
         
            +
             
     | 
| 
       67 
79 
     | 
    
         
             
                def if_render_required(&block)
         
     | 
| 
       68 
80 
     | 
    
         
             
                  timing("Rendered") do
         
     | 
| 
       69 
81 
     | 
    
         
             
                    next_render_hash = component.render_hash
         
     | 
| 
         @@ -83,6 +95,10 @@ module Motion 
     | 
|
| 
       83 
95 
     | 
    
         
             
                  component.broadcasts
         
     | 
| 
       84 
96 
     | 
    
         
             
                end
         
     | 
| 
       85 
97 
     | 
    
         | 
| 
      
 98 
     | 
    
         
            +
                def periodic_timers
         
     | 
| 
      
 99 
     | 
    
         
            +
                  component.periodic_timers
         
     | 
| 
      
 100 
     | 
    
         
            +
                end
         
     | 
| 
      
 101 
     | 
    
         
            +
             
     | 
| 
       86 
102 
     | 
    
         
             
                private
         
     | 
| 
       87 
103 
     | 
    
         | 
| 
       88 
104 
     | 
    
         
             
                attr_reader :log_helper
         
     |