Module: RmagickTidy::Hook

Defined in:
lib/rmagick_tidy/hook.rb

Constant Summary collapse

SKIP_INSTANCE_METHODS =

Methods we never want to wrap. Most of them either return self, return primitives, or are introspection / lifecycle helpers where wrapping would be wasteful or risk recursion.

%i[
  destroy! destroyed? inspect to_s == eql? hash freeze frozen?
  tainted? untrusted? object_id class itself
].freeze
CLASS_METHODS =

Class-level methods on Magick::Image that produce new images.

%i[new read ping from_blob read_inline capture constitute combine].freeze

Class Method Summary collapse

Class Method Details

.define_wrapper(mod, name) ⇒ Object



56
57
58
59
60
61
62
63
64
65
66
# File 'lib/rmagick_tidy/hook.rb', line 56

def define_wrapper(mod, name)
  mod.send(:define_method, name) do |*args, **kwargs, &block|
    result = if kwargs.empty?
               super(*args, &block)
             else
               super(*args, **kwargs, &block)
             end
    ::RmagickTidy::Tracker.track(result, self)
    result
  end
end

.install!Object



16
17
18
19
20
21
22
23
24
25
26
27
28
29
# File 'lib/rmagick_tidy/hook.rb', line 16

def install!
  return if @installed
  return unless defined?(::Magick::Image)

  install_instance_hook(::Magick::Image)
  install_class_hook(::Magick::Image)

  if defined?(::Magick::ImageList)
    install_instance_hook(::Magick::ImageList)
    install_class_hook(::Magick::ImageList)
  end

  @installed = true
end

.install_class_hook(klass) ⇒ Object



44
45
46
47
48
49
50
51
52
53
54
# File 'lib/rmagick_tidy/hook.rb', line 44

def install_class_hook(klass)
  mod = Module.new do
    def self.inspect = "#<RmagickTidy::ClassHook>"
  end
  CLASS_METHODS.each do |name|
    next unless klass.respond_to?(name)

    define_wrapper(mod, name)
  end
  klass.singleton_class.prepend(mod)
end

.install_instance_hook(klass) ⇒ Object



31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/rmagick_tidy/hook.rb', line 31

def install_instance_hook(klass)
  mod = Module.new do
    def self.inspect = "#<RmagickTidy::InstanceHook>"
  end
  method_names = klass.public_instance_methods(false) - SKIP_INSTANCE_METHODS
  method_names.each do |name|
    next if name.to_s.end_with?("=")

    define_wrapper(mod, name)
  end
  klass.prepend(mod)
end