Class: Jetpants::Callback

Inherits:
Object show all
Defined in:
lib/jetpants/callback.rb

Overview

Generic representation of a before-method or after-method callback. Used internally by CallbackHandler; you won’t need to interact with Callback directly.

Constant Summary collapse

@@all_callbacks =

hash of class obj -> method_name symbol -> type string -> array of callbacks

{}
@@currently_wrapping =

hash of class obj -> method_name symbol -> bool

{}

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(for_class, method_name, type = :after, priority = 100) ⇒ Callback

Returns a new instance of Callback.



67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/jetpants/callback.rb', line 67

def initialize(for_class, method_name, type=:after, priority=100)
  @for_class = for_class
  @method_name = method_name
  @type = type
  @priority = priority
  
  @@all_callbacks[for_class] ||= {}
  @@all_callbacks[for_class][method_name] ||= {}
  already_wrapped = Callback.wrapped?(for_class, method_name)
  @@all_callbacks[for_class][method_name][type] ||= []

  next_method_id = @@all_callbacks[for_class][method_name][type].count + 1
  old_name = "#{type.to_s}_#{method_name.to_s}".to_sym
  @my_alias = new_name = ("real_callback_#{old_name}_" + for_class.to_s.sub('::', '_') + "_#{next_method_id}").to_sym
  for_class.class_eval do
    alias_method new_name, old_name
  end
  Callback.wrap_method(for_class, method_name) unless already_wrapped
  
  @@all_callbacks[for_class][method_name][type] << self
end

Instance Attribute Details

#for_classObject (readonly)

class object



61
62
63
# File 'lib/jetpants/callback.rb', line 61

def for_class
  @for_class
end

#method_nameObject (readonly)

symbol containing method name (the one being callback-wrapped)



62
63
64
# File 'lib/jetpants/callback.rb', line 62

def method_name
  @method_name
end

#my_aliasObject (readonly)

method name alias OF THE CALLBACK



65
66
67
# File 'lib/jetpants/callback.rb', line 65

def my_alias
  @my_alias
end

#priorityObject (readonly)

high numbers get triggered first



64
65
66
# File 'lib/jetpants/callback.rb', line 64

def priority
  @priority
end

#typeObject (readonly)

:before or :after



63
64
65
# File 'lib/jetpants/callback.rb', line 63

def type
  @type
end

Class Method Details

.trigger(for_object, method_name, type, *args) ⇒ Object



115
116
117
118
119
120
121
122
123
124
# File 'lib/jetpants/callback.rb', line 115

def self.trigger(for_object, method_name, type, *args)
  my_callbacks = []
  for_object.class.ancestors.each do |for_class|
    if @@all_callbacks[for_class] && @@all_callbacks[for_class][method_name] && @@all_callbacks[for_class][method_name][type]
      my_callbacks.concat(@@all_callbacks[for_class][method_name][type])
    end
  end
  my_callbacks.sort_by! {|c| -1 * c.priority}
  my_callbacks.each {|c| for_object.send(c.my_alias, *args)}
end

.wrap_method(for_class, method_name) ⇒ Object



89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/jetpants/callback.rb', line 89

def self.wrap_method(for_class, method_name)
  @@currently_wrapping[for_class] ||= {}
  @@currently_wrapping[for_class][method_name] ||= false
  return if @@currently_wrapping[for_class][method_name] # prevent infinite recursion from the alias_method call
  @@currently_wrapping[for_class][method_name] = true
  
  for_class.class_eval do
    alias_method "#{method_name}_without_callbacks".to_sym, method_name
    define_method method_name do |*args|
      begin
        Callback.trigger(self, method_name, :before, *args)
      rescue CallbackAbortError
        return
      end
      result = send "#{method_name}_without_callbacks".to_sym, *args
      begin
        Callback.trigger(self, method_name, :after, *args)
      rescue CallbackAbortError
      end
      result
    end
  end
  
  @@currently_wrapping[for_class][method_name] = false
end

.wrapped?(for_class, method_name) ⇒ Boolean

Returns:

  • (Boolean)


126
127
128
129
# File 'lib/jetpants/callback.rb', line 126

def self.wrapped?(for_class, method_name)
  return false unless @@all_callbacks[for_class] && @@all_callbacks[for_class][method_name]
  @@all_callbacks[for_class][method_name].count > 0
end