crochet 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (2) hide show
  1. data/lib/crochet.rb +73 -0
  2. metadata +46 -0
@@ -0,0 +1,73 @@
1
+ module Crochet
2
+ VERSION = "0.0.1"
3
+ class Hook
4
+ # Map symbols to their class- or instance-relevant methods
5
+ TYPE_SPECS = {
6
+ :instance => {
7
+ :accessor => :instance_method,
8
+ :definer => :define_method,
9
+ :evaluator => :instance_exec
10
+ },
11
+ :class => {
12
+ :accessor => :method,
13
+ :definer => :define_singleton_method,
14
+ :evaluator => :class_exec
15
+ }
16
+ }
17
+ def initialize(klass, &block)
18
+ @klass = klass
19
+ @methods = []
20
+ self.instance_eval(&block) if block
21
+ end
22
+ def _attach(timing, destructive, method, method_type=:instance, &block)
23
+ specs = TYPE_SPECS[method_type]
24
+
25
+ # Capture the original method
26
+ orig_method = @klass.method(specs[:accessor]).(method)
27
+
28
+ # Redefine the method
29
+ @klass.send(specs[:definer], method) do |*args|
30
+ # Pass the original arguments "before" hook methods
31
+ if timing == :before
32
+ hook_result = self.send(specs[:evaluator], *args, &block)
33
+ args = hook_result if destructive
34
+ end
35
+
36
+ # Call the original method and assign the result
37
+ method_result = (method_type == :instance ? orig_method.bind(self) : orig_method).call(*args)
38
+
39
+ # Pass method result, followed by the args it received, to "after" hook methods
40
+ if timing == :after
41
+ hook_result = self.send(specs[:evaluator], method_result, *args, &block)
42
+ method_result = hook_result if destructive
43
+ end
44
+
45
+ # Finally, return the (optionally overridden) method result
46
+ method_result
47
+ end
48
+ @methods << { :orig => orig_method, :name => method, :type => method_type }
49
+ nil
50
+ end
51
+
52
+ # Define hook methods and their destructive twins
53
+ [ :before, :after, :before!, :after! ].each do |method|
54
+ define_method method do |*args, &block|
55
+ str = method.to_s
56
+ destructive = (str[-1] == "!")
57
+ timing = (destructive ? str[0...-1].to_sym : method)
58
+ _attach(timing, destructive, *args, &block)
59
+ end
60
+ end
61
+
62
+ # When `destroy` is called, it should restore all affected methods
63
+ def destroy
64
+ @methods.each do |method|
65
+ specs = TYPE_SPECS[method[:type]]
66
+ @klass.send(specs[:definer], method[:name]) do |*args|
67
+ (method[:type] == :instance ? method[:orig].bind(self) : method[:orig]).call(*args)
68
+ end
69
+ end
70
+ @methods = []
71
+ end
72
+ end
73
+ end
metadata ADDED
@@ -0,0 +1,46 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: crochet
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Jeremy Singer-Vine
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-05-05 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: Hook into and/or monkeypatch any Ruby class- or instance-method. Provides
15
+ 'before' and 'after' hooks, plus their destructive evil twins.
16
+ email: jsvine@gmail.com
17
+ executables: []
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - lib/crochet.rb
22
+ homepage: https://github.com/jsvine/crochet
23
+ licenses: []
24
+ post_install_message:
25
+ rdoc_options: []
26
+ require_paths:
27
+ - lib
28
+ required_ruby_version: !ruby/object:Gem::Requirement
29
+ none: false
30
+ requirements:
31
+ - - ! '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ required_rubygems_version: !ruby/object:Gem::Requirement
35
+ none: false
36
+ requirements:
37
+ - - ! '>='
38
+ - !ruby/object:Gem::Version
39
+ version: '0'
40
+ requirements: []
41
+ rubyforge_project:
42
+ rubygems_version: 1.8.23
43
+ signing_key:
44
+ specification_version: 3
45
+ summary: Simple Ruby hooks.
46
+ test_files: []