wrapr 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.
- data/.gitignore +7 -0
- data/.rspec +2 -0
- data/Gemfile +4 -0
- data/README.md +34 -0
- data/Rakefile +1 -0
- data/informal_tests.rb +34 -0
- data/lib/wrapr.rb +86 -0
- data/lib/wrapr/version.rb +3 -0
- data/spec/wrapr_spec.rb +81 -0
- data/wrapr.gemspec +24 -0
- metadata +67 -0
data/.gitignore
ADDED
data/.rspec
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
Wrapr
|
2
|
+
====
|
3
|
+
|
4
|
+
Modify class behavior at runtime. Similar to before/after/around filters in Rails ActionController::Base
|
5
|
+
|
6
|
+
Example
|
7
|
+
------
|
8
|
+
|
9
|
+
require 'wrapr'
|
10
|
+
require 'logger'
|
11
|
+
log = Logger.new(STDOUT)
|
12
|
+
|
13
|
+
Wrapr::Wrapr.new(Exception).before(:initialize) do |this,*args|
|
14
|
+
log.debug("New exception is being created "+args.inspect)
|
15
|
+
args
|
16
|
+
end
|
17
|
+
|
18
|
+
5/0 # we can hijack any class's instance methods and inject our own functionality
|
19
|
+
|
20
|
+
|
21
|
+
Potential Uses
|
22
|
+
--------------
|
23
|
+
|
24
|
+
Use with ruby-debug to set conditional break points
|
25
|
+
|
26
|
+
require 'ruby-debug'
|
27
|
+
Wrapr::Wrapr.new(Post).before(:find) do |this,*args|
|
28
|
+
# Open debug when a post is instantiated
|
29
|
+
debugger if args[:conditions][:
|
30
|
+
args
|
31
|
+
end
|
32
|
+
|
33
|
+
Use with analytics packages to track application events from a single location
|
34
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/informal_tests.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# These examples written for samples of code in the documentation
|
2
|
+
|
3
|
+
$: << File.dirname(__FILE__)+"/lib"
|
4
|
+
require 'wrapr'
|
5
|
+
require 'logger'
|
6
|
+
log = Logger.new(STDOUT)
|
7
|
+
|
8
|
+
|
9
|
+
|
10
|
+
|
11
|
+
w = Wrapr::Wrapr.new(Exception)
|
12
|
+
# #before can mutate the instance and args as well
|
13
|
+
w.before(:initialize) do |this,*args|
|
14
|
+
args[0].upcase!
|
15
|
+
args
|
16
|
+
end
|
17
|
+
puts Exception.new("foo").to_s # FOO
|
18
|
+
w.around(:to_s) do |this,method,*args|
|
19
|
+
puts "Before to_s"
|
20
|
+
result = method.call()
|
21
|
+
result+=" "
|
22
|
+
end
|
23
|
+
puts Exception.new("foo").to_s # FOO, "Before to_s OOF "
|
24
|
+
w.after(:to_s) do |this,result|
|
25
|
+
result.downcase
|
26
|
+
end
|
27
|
+
puts Exception.new("foo").to_s # FOO, "Before to_s foo"
|
28
|
+
|
29
|
+
Wrapr::Wrapr.new(Exception).before(:initialize) do |this,*args|
|
30
|
+
log.debug("New exception is being created "+args.inspect)
|
31
|
+
args
|
32
|
+
end
|
33
|
+
|
34
|
+
5/0
|
data/lib/wrapr.rb
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
require "wrapr/version"
|
2
|
+
|
3
|
+
module Wrapr
|
4
|
+
|
5
|
+
|
6
|
+
|
7
|
+
|
8
|
+
# Allows method wrapping
|
9
|
+
#
|
10
|
+
# Usage
|
11
|
+
# w = Wrapr::Wrapr.new(Exception)
|
12
|
+
# # #before can mutate the instance and args as well
|
13
|
+
# w.before(:initialize) do |this,*args|
|
14
|
+
# args[0].upcase!
|
15
|
+
# args
|
16
|
+
# end
|
17
|
+
# puts Exception.new("foo").to_s # FOO
|
18
|
+
# w.around(:to_s) do |this,method,*args|
|
19
|
+
# puts "Before to_s"
|
20
|
+
# result = method.call()
|
21
|
+
# result+=" "
|
22
|
+
# end
|
23
|
+
# puts Exception.new("foo").to_s # FOO, "Before to_s OOF "
|
24
|
+
# w.after(:to_s) do |this,result|
|
25
|
+
# result.downcase
|
26
|
+
# end
|
27
|
+
# puts Exception.new("foo").to_s # FOO, "Before to_s foo"
|
28
|
+
|
29
|
+
class Wrapr
|
30
|
+
def initialize(klass)
|
31
|
+
@klass=klass
|
32
|
+
end
|
33
|
+
# Executes block around
|
34
|
+
# Call of wrapped method is responsibility of the passed block
|
35
|
+
#
|
36
|
+
# Transparently
|
37
|
+
#
|
38
|
+
# Wrapr.new(Exception).around(:to_s) { |self,method,*outer_args|
|
39
|
+
# method.call(*outer_args)
|
40
|
+
# }
|
41
|
+
def around(method,&block)
|
42
|
+
# fetch the unbound instance method
|
43
|
+
unbound = @klass.instance_method(method)
|
44
|
+
@klass.class_eval do
|
45
|
+
# create a new method with the same name
|
46
|
+
define_method(method) do |*outer_args|
|
47
|
+
# we pass the current instance and overridden method
|
48
|
+
block.call(self,unbound.bind(self),*outer_args)
|
49
|
+
# We cannot do self.send(method,...) because we are redefining @method, causes recursion
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
# Executes block before method is called
|
54
|
+
# Passes the return of the block to method
|
55
|
+
#
|
56
|
+
# Transparent before
|
57
|
+
#
|
58
|
+
# Wrapr.new(Exception).before(:to_s) { |self,*outer_args|
|
59
|
+
# return outer_args
|
60
|
+
# }
|
61
|
+
def before(method,&block)
|
62
|
+
unbound = @klass.instance_method(method)
|
63
|
+
@klass.class_eval do
|
64
|
+
define_method(method) do |*outer_args|
|
65
|
+
unbound.bind(self).call(*block.call(self,*outer_args))
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
# Executes block after method is called
|
70
|
+
# Passes the response of method into block
|
71
|
+
#
|
72
|
+
# Transparent after
|
73
|
+
#
|
74
|
+
# Wrapr.new(Exception).after(:to_s) do |self,*result|
|
75
|
+
# return result
|
76
|
+
# end
|
77
|
+
def after(method,&block)
|
78
|
+
unbound = @klass.instance_method(method)
|
79
|
+
@klass.class_eval do
|
80
|
+
define_method(method) do |*outer_args|
|
81
|
+
block.call(self, *unbound.bind(self).call(*outer_args))
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
data/spec/wrapr_spec.rb
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'wrapr'
|
2
|
+
describe Wrapr::Wrapr do
|
3
|
+
before do
|
4
|
+
class Foo
|
5
|
+
attr_accessor :stack
|
6
|
+
def initialize
|
7
|
+
@stack = [:initialize]
|
8
|
+
end
|
9
|
+
def instance_m
|
10
|
+
@stack.push([:instance_m])
|
11
|
+
end
|
12
|
+
def instance_m_arg(x)
|
13
|
+
@stack.push x
|
14
|
+
end
|
15
|
+
def self.static_m(stack,item)
|
16
|
+
stack << item
|
17
|
+
end
|
18
|
+
end
|
19
|
+
@wrapper = Wrapr::Wrapr.new(Foo)
|
20
|
+
end
|
21
|
+
context "around" do
|
22
|
+
it "wraps something around a method" do
|
23
|
+
@wrapper.around(:instance_m) do |this,method,*args|
|
24
|
+
this.stack << :around_before
|
25
|
+
method.call(*args)
|
26
|
+
this.stack << :around_after
|
27
|
+
end
|
28
|
+
instance = Foo.new
|
29
|
+
instance.instance_m
|
30
|
+
instance.stack.should include(:around_before,:around_after)
|
31
|
+
end
|
32
|
+
it "even works with arguments" do
|
33
|
+
@wrapper.around(:instance_m) do |this,method,a,b|
|
34
|
+
this.stack << a << b
|
35
|
+
method.call()
|
36
|
+
end
|
37
|
+
instance = Foo.new
|
38
|
+
instance.instance_m(:argument_one,:argument_two)
|
39
|
+
instance.stack.should include(:argument_one,:argument_two)
|
40
|
+
end
|
41
|
+
it "even works with layers of arguments" do
|
42
|
+
@wrapper.around(:instance_m_arg) do |this,method,a,b|
|
43
|
+
this.stack.push(b)
|
44
|
+
method.call( (a.to_s+b.to_s).to_sym )
|
45
|
+
end
|
46
|
+
instance = Foo.new
|
47
|
+
instance.instance_m_arg(:argument_one, :argument_two)
|
48
|
+
instance.stack.should_not include(:argument_one)
|
49
|
+
instance.stack.should include(:argument_oneargument_two)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
context "before" do
|
53
|
+
it "passes through arguments to a method" do
|
54
|
+
@wrapper.before(:instance_m_arg) do |this,x|
|
55
|
+
x.to_s
|
56
|
+
end
|
57
|
+
instance = Foo.new
|
58
|
+
instance.instance_m_arg(:argument)
|
59
|
+
instance.stack.should include("argument")
|
60
|
+
end
|
61
|
+
it "works transparently" do
|
62
|
+
@wrapper.before(:instance_m) do |this,*args|
|
63
|
+
this.stack.shift
|
64
|
+
args
|
65
|
+
end
|
66
|
+
instance = Foo.new
|
67
|
+
instance.instance_m
|
68
|
+
instance.stack.should_not include(:initialize)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
context "after" do
|
72
|
+
it "passes return values into block" do
|
73
|
+
@wrapper.after(:instance_m) do |this,result|
|
74
|
+
result.to_s.upcase
|
75
|
+
end
|
76
|
+
instance = Foo.new
|
77
|
+
instance.instance_m.should == "INITIALIZE"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
it "works with static methods"
|
81
|
+
end
|
data/wrapr.gemspec
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "wrapr/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "wrapr"
|
7
|
+
s.version = Wrapr::VERSION
|
8
|
+
s.authors = ["Thomas W. Devol"]
|
9
|
+
s.email = ["thomas.devol@gmail.com"]
|
10
|
+
s.homepage = ""
|
11
|
+
s.summary = %q{Allows before/around/after instance method wrapping}
|
12
|
+
s.description = s.summary+" etc..."
|
13
|
+
|
14
|
+
s.rubyforge_project = "wrapr"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
# specify any dependencies here; for example:
|
22
|
+
s.add_development_dependency "rspec"
|
23
|
+
# s.add_runtime_dependency "rest-client"
|
24
|
+
end
|
metadata
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: wrapr
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Thomas W. Devol
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-10-07 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rspec
|
16
|
+
requirement: &70194634911940 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70194634911940
|
25
|
+
description: Allows before/around/after instance method wrapping etc...
|
26
|
+
email:
|
27
|
+
- thomas.devol@gmail.com
|
28
|
+
executables: []
|
29
|
+
extensions: []
|
30
|
+
extra_rdoc_files: []
|
31
|
+
files:
|
32
|
+
- .gitignore
|
33
|
+
- .rspec
|
34
|
+
- Gemfile
|
35
|
+
- README.md
|
36
|
+
- Rakefile
|
37
|
+
- informal_tests.rb
|
38
|
+
- lib/wrapr.rb
|
39
|
+
- lib/wrapr/version.rb
|
40
|
+
- spec/wrapr_spec.rb
|
41
|
+
- wrapr.gemspec
|
42
|
+
homepage: ''
|
43
|
+
licenses: []
|
44
|
+
post_install_message:
|
45
|
+
rdoc_options: []
|
46
|
+
require_paths:
|
47
|
+
- lib
|
48
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
55
|
+
none: false
|
56
|
+
requirements:
|
57
|
+
- - ! '>='
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: '0'
|
60
|
+
requirements: []
|
61
|
+
rubyforge_project: wrapr
|
62
|
+
rubygems_version: 1.8.10
|
63
|
+
signing_key:
|
64
|
+
specification_version: 3
|
65
|
+
summary: Allows before/around/after instance method wrapping
|
66
|
+
test_files:
|
67
|
+
- spec/wrapr_spec.rb
|