Module: Brainguy::Observer::ClassMethods

Defined in:
lib/brainguy/observer.rb

Constant Summary collapse

HANDLER_METHOD_PATTERN =
/\Aon_(.+)\z/

Instance Method Summary collapse

Instance Method Details

#method_added(method_name) ⇒ Object



13
14
15
16
17
18
# File 'lib/brainguy/observer.rb', line 13

def method_added(method_name)
  if method_name.to_s =~ HANDLER_METHOD_PATTERN
    regenerate_dispatch_method
  end
  super
end

#regenerate_dispatch_methodObject

[Re]generate a #call method containing a fast dispatch table from event names to handler method names. The code generation strategy here has been benchmarked as equivalent to hand-written dispatch code on Ruby 2.2. See benchmark_listener_dispatch for the relevant benchmark.



25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# File 'lib/brainguy/observer.rb', line 25

def regenerate_dispatch_method
  dispatch_table = instance_methods
                       .map(&:to_s)
                       .grep(HANDLER_METHOD_PATTERN) { |method_name|
    event_name = $1
    "when :#{event_name} then #{method_name}(event)"
  }.join("\n")
  code = %{
    def call(event)
      case event.name
      #{dispatch_table}
      # Note: following case is mainly here to keep the parser happy
      # when there are no other cases (i.e. no handler methods defined
      # yet).
      when nil then fail ArgumentError, "Event cannot be nil"
      else event_handler_missing(event)
      end
    end
  }
  class_eval code
rescue SyntaxError => error
  # SyntaxErrors suck when you can't look at the syntax
  error.message << "\n\nGenerated code:\n\n#{code}"
  raise error
end