rubymaniac/saxxy

View on GitHub
lib/saxxy/callbacks/sax.rb

Summary

Maintainability
A
0 mins
Test Coverage
require "forwardable"
require "saxxy/utils/callback_array"
require "saxxy/event_registry"


module Saxxy
  module Callbacks

    module SAX
      def self.included(base)
        base.extend Forwardable
        base.def_delegators :@event_registry, :activate_events_on, :deactivate_events_on,
          :push_text, :register_event_from_action, :remove_actions!
      end

      def initialize(context)
        initialize_state
        @active_pool << context
      end

      def on_start_element(name, attrs = {})
        register_and_activate_events_on(name, attrs)
        activate_contexts_on(name, attrs)
      end

      def on_characters(string)
        push_text(string || "")
      end

      def on_end_element(name)
        deactivate_events_on(name)
        deactivate_contexts_on(name)
      end

      def on_end_document
        @active_pool.clear
        @inactive_pool.clear
        @event_registry.clear
      end

      private
      def initialize_state
        @event_registry = EventRegistry.new
        @inactive_pool = CallbackArray.new.on_add(&method(:on_add_to_inactive_pool))
        @active_pool = CallbackArray.new.on_add(&method(:on_add_to_active_pool)).on_remove(&method(:on_remove_from_active_pool))
      end

      def register_and_activate_events_on(name, attrs)
        actions.select { |a| a.matches(name, attrs) }.each do |action|
          register_event_from_action(action, name, attrs)
        end
        activate_events_on(name, attrs)
      end

      def activate_contexts_on(name, attrs)
        @inactive_pool.each { |context| context.activate_on(name, attrs) }
      end

      def deactivate_contexts_on(name)
        @active_pool.each { |context| context.deactivate_on(name) }
      end

      def on_add_to_inactive_pool(context)
        context.on_activation do |context|
          @inactive_pool >> context
          @active_pool << context
        end
      end

      def on_add_to_active_pool(context)
        context.on_deactivation { |context| @active_pool >> context }
        context.child_contexts.each { |context| @inactive_pool << context }
      end

      def on_remove_from_active_pool(context)
        @inactive_pool << context if @active_pool.member?(context.parent_context)
        remove_actions!(*context.actions)
      end

      def actions
        @active_pool.flat_map(&:actions)
      end
    end

  end
end