You can "wrap" an instance (or singleton) method so that your wrapping method gets to act both before and after the wrapped method is called:
$ cat -n t.rb
1 class Array
2
3 # Save the existing method.
4 alias :old_initialize :initialize
5
6 # Define the wrapper method.
7 def initialize(*args, &block)
8 # Here's where we get to do a prelude.
9 block_s = block ? block.inspect : 'no block'
10 puts "Creating an array from #{args} and #{block_s}."
11 # Make the call, saving the result.
12 a = old_initialize(*args, &block)
13 # Here's where we get to do a postlude.
14 puts "Created #{a}."
15 puts ''
16 # And of course return the new array.
17 a
18 end
19
20 end
21
22 Array.new
23 Array.new([])
24 Array.new(4)
25 Array.new(4, 'nosuch')
26 Array.new(4) {|i| "Element #{i}"}
The output:
Creating an array from [] and no block.
Created [].
Creating an array from [[]] and no block.
Created [].
Creating an array from [4] and no block.
Created [nil, nil, nil, nil].
Creating an array from [4, "nosuch"] and no block.
Created ["nosuch", "nosuch", "nosuch", "nosuch"].
Creating an array from [4] and #<Proc:0x000001e256eb3ab8 t.rb:26>.
Created ["Element 0", "Element 1", "Element 2", "Element 3"].