Method: AppMap::Hook#hook_builtins

Defined in:
lib/appmap/hook.rb

#hook_builtinsObject

hook_builtins builds hooks for code that is built in to the Ruby standard library. No TracePoint events are emitted for builtins, so a separate hooking mechanism is needed.



104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
# File 'lib/appmap/hook.rb', line 104

def hook_builtins
  return unless self.class.hook_builtins?

  hook_loaded_code = lambda do |hooks_by_class, builtin|
    hooks_by_class.each do |class_name, hooks|
      Array(hooks).each do |hook|
        HookLog.builtin class_name do
          if builtin && hook.package.require_name && hook.package.require_name != "ruby"
            begin
              require hook.package.require_name
            rescue
              HookLog.load_error hook.package.require_name, "Unable to require #{hook.package.require_name}: #{$!}" if HookLog.enabled?
              next
            end
          end

          begin
            base_cls = Object.const_get class_name
          rescue NameError
            HookLog.load_error class_name, "Class #{class_name} not found in global scope" if HookLog.enabled?
            next
          end

          Array(hook.method_names).each do |method_name|
            method_name = method_name.to_sym

            hook_method = lambda do |entry|
              cls, method = entry
              next if config.never_hook?(cls, method)

              hook.package.handler_class.new(hook.package, cls, method).activate
            end

            methods = []
            # irb(main):001:0> Kernel.public_instance_method(:system)
            # (irb):1:in `public_instance_method': method `system' for module `Kernel' is  private (NameError)
            if base_cls == Kernel
              begin
                methods << [base_cls, base_cls.instance_method(method_name)]
              rescue
                nil
              end
            end
            begin
              methods << [base_cls, base_cls.public_instance_method(method_name)]
            rescue
              nil
            end
            begin
              methods << [base_cls, base_cls.protected_instance_method(method_name)]
            rescue
              nil
            end
            if base_cls.respond_to?(:singleton_class)
              begin
                methods << [base_cls.singleton_class, base_cls.singleton_class.public_instance_method(method_name)]
              rescue
                nil
              end
              begin
                methods << [base_cls.singleton_class, base_cls.singleton_class.protected_instance_method(method_name)]
              rescue
                nil
              end
            end
            methods.compact!
            if methods.empty?
              HookLog.load_error [base_cls.name, method_name].join("[#.]"), "Method #{method_name} not found on #{base_cls.name}" if HookLog.enabled?
            else
              methods.each(&hook_method)
            end
          end
        end
      end
    end
  end

  hook_loaded_code.call(config.builtin_hooks, true)
end