crochet 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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: []