auser-backcall 0.0.2
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/CHANGELOG +2 -0
- data/Manifest +8 -0
- data/README +77 -0
- data/Rakefile +14 -0
- data/backcall.gemspec +47 -0
- data/lib/backcall.rb +134 -0
- data/lib/core/proc.rb +12 -0
- data/spec/callback_spec.rb +200 -0
- data/spec/spec_helper.rb +9 -0
- metadata +79 -0
data/CHANGELOG
ADDED
data/Manifest
ADDED
data/README
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
= Backcall
|
2
|
+
Ari Lerner
|
3
|
+
CitrusByte
|
4
|
+
http://blog.citrusbyte.com
|
5
|
+
|
6
|
+
== DESCRIPTION:
|
7
|
+
|
8
|
+
* Backcall, Ari Lerner, Citrusbyte (http://blog.citrusbyte.com) - Simply add super lightweight, memory-efficient before and after callbacks.
|
9
|
+
|
10
|
+
== Basics
|
11
|
+
|
12
|
+
Simply require backcall
|
13
|
+
require 'backcall'
|
14
|
+
|
15
|
+
And include callbacks in your classes
|
16
|
+
include Backcall::Callbacks in your class
|
17
|
+
|
18
|
+
Then you can call before or after on any method, for instance:
|
19
|
+
|
20
|
+
class TestCallbacks
|
21
|
+
before :world, :hello
|
22
|
+
after :world, :thanks
|
23
|
+
def hello(caller)
|
24
|
+
string << "hello "
|
25
|
+
end
|
26
|
+
def world
|
27
|
+
string << "world"
|
28
|
+
end
|
29
|
+
def thanks(caller)
|
30
|
+
string << ", thank you"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
TestCallbacks.new.world
|
35
|
+
=> "hello world, thank you"
|
36
|
+
|
37
|
+
You can write callbacks currently in the following forms:
|
38
|
+
|
39
|
+
* before :world, :hello, :hi, :you
|
40
|
+
* before :world do
|
41
|
+
puts "hello "
|
42
|
+
end
|
43
|
+
* before :world, {:hello => "OutsideClass"}
|
44
|
+
* before :world, {:hello => OutsideClass}
|
45
|
+
|
46
|
+
Note on the last two:
|
47
|
+
If you call the last style with a string, it expects the OutsideClass
|
48
|
+
If you call the last one, your class with create a method that calls new on the class that you send to it, It will keep
|
49
|
+
|
50
|
+
== INSTALL:
|
51
|
+
|
52
|
+
gem install backcall
|
53
|
+
|
54
|
+
== LICENSE:
|
55
|
+
|
56
|
+
(The MIT License)
|
57
|
+
|
58
|
+
Copyright (c) 2008 Ari Lerner. CitrusByte
|
59
|
+
|
60
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
61
|
+
a copy of this software and associated documentation files (the
|
62
|
+
'Software'), to deal in the Software without restriction, including
|
63
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
64
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
65
|
+
permit persons to whom the Software is furnished to do so, subject to
|
66
|
+
the following conditions:
|
67
|
+
|
68
|
+
The above copyright notice and this permission notice shall be
|
69
|
+
included in all copies or substantial portions of the Software.
|
70
|
+
|
71
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
72
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
73
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
74
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
75
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
76
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
77
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'echoe'
|
3
|
+
|
4
|
+
task :default => :test
|
5
|
+
|
6
|
+
Echoe.new("backcall") do |p|
|
7
|
+
p.author = "Ari Lerner"
|
8
|
+
p.email = "ari.lerner@citrusbyte.com"
|
9
|
+
p.summary = "Add basic memory-efficient before and after callbacks, easily"
|
10
|
+
p.url = "http://blog.citrusbyte.com"
|
11
|
+
p.dependencies = %w(facets)
|
12
|
+
p.install_message = "For more information, check http://blog.citrusbyte.com\n*** Ari Lerner @ <ari.lerner@citrusbyte.com> ***"
|
13
|
+
p.include_rakefile = true
|
14
|
+
end
|
data/backcall.gemspec
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
|
2
|
+
# Gem::Specification for Backcall-0.0.2
|
3
|
+
# Originally generated by Echoe
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = %q{backcall}
|
7
|
+
s.version = "0.0.2"
|
8
|
+
|
9
|
+
s.specification_version = 2 if s.respond_to? :specification_version=
|
10
|
+
|
11
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
12
|
+
s.authors = ["Ari Lerner"]
|
13
|
+
s.date = %q{2008-06-12}
|
14
|
+
s.description = %q{Add basic memory-efficient before and after callbacks, easily}
|
15
|
+
s.email = %q{ari.lerner@citrusbyte.com}
|
16
|
+
s.extra_rdoc_files = ["CHANGELOG", "lib/backcall.rb", "lib/core/proc.rb", "README"]
|
17
|
+
s.files = ["CHANGELOG", "lib/backcall.rb", "lib/core/proc.rb", "Manifest", "Rakefile", "README", "spec/callback_spec.rb", "spec/spec_helper.rb", "backcall.gemspec"]
|
18
|
+
s.has_rdoc = true
|
19
|
+
s.homepage = %q{http://blog.citrusbyte.com}
|
20
|
+
s.post_install_message = %q{For more information, check http://blog.citrusbyte.com
|
21
|
+
*** Ari Lerner @ <ari.lerner@citrusbyte.com> ***}
|
22
|
+
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Backcall", "--main", "README"]
|
23
|
+
s.require_paths = ["lib"]
|
24
|
+
s.rubyforge_project = %q{backcall}
|
25
|
+
s.rubygems_version = %q{1.1.1}
|
26
|
+
s.summary = %q{Add basic memory-efficient before and after callbacks, easily}
|
27
|
+
|
28
|
+
s.add_dependency(%q<facets>, [">= 0"])
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
# # Original Rakefile source (requires the Echoe gem):
|
33
|
+
#
|
34
|
+
# require 'rubygems'
|
35
|
+
# require 'echoe'
|
36
|
+
#
|
37
|
+
# task :default => :test
|
38
|
+
#
|
39
|
+
# Echoe.new("backcall") do |p|
|
40
|
+
# p.author = "Ari Lerner"
|
41
|
+
# p.email = "ari.lerner@citrusbyte.com"
|
42
|
+
# p.summary = "Add basic memory-efficient before and after callbacks, easily"
|
43
|
+
# p.url = "http://blog.citrusbyte.com"
|
44
|
+
# p.dependencies = %w(facets)
|
45
|
+
# p.install_message = "For more information, check http://blog.citrusbyte.com\n*** Ari Lerner @ <ari.lerner@citrusbyte.com> ***"
|
46
|
+
# p.include_rakefile = true
|
47
|
+
# end
|
data/lib/backcall.rb
ADDED
@@ -0,0 +1,134 @@
|
|
1
|
+
=begin rdoc
|
2
|
+
Basic callbacks
|
3
|
+
=end
|
4
|
+
# Require core changes
|
5
|
+
Dir[File.join(File.dirname(__FILE__), "core/*")].each {|a| require a }
|
6
|
+
|
7
|
+
module Callbacks
|
8
|
+
module ClassMethods
|
9
|
+
def define_callback_module(mod)
|
10
|
+
callbacks << mod
|
11
|
+
end
|
12
|
+
def define_callback_class(cla)
|
13
|
+
classes << cla
|
14
|
+
end
|
15
|
+
def callback(type, m, *args, &block)
|
16
|
+
arr = []
|
17
|
+
args.each do |arg|
|
18
|
+
arr << case arg.class.to_s
|
19
|
+
when "Hash"
|
20
|
+
arg.collect do |meth, klass|
|
21
|
+
case klass.class.to_s
|
22
|
+
when "String"
|
23
|
+
define_callback_class(klass)
|
24
|
+
"self.#{klass.to_s.downcase}.#{meth}(self)"
|
25
|
+
else
|
26
|
+
"#{klass}.send :#{meth}, self"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
when "Symbol"
|
30
|
+
"self.send :#{arg}, self"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
string = ""
|
35
|
+
if block_given?
|
36
|
+
num = store_proc(block.to_proc)
|
37
|
+
arr << <<-EOM
|
38
|
+
self.class.get_proc(#{num}).bind(self).call
|
39
|
+
EOM
|
40
|
+
end
|
41
|
+
|
42
|
+
string = create_eval_for_mod_with_string_and_type!(m, type) do
|
43
|
+
arr.join("\n")
|
44
|
+
end
|
45
|
+
|
46
|
+
mMode = Module.new {eval string}
|
47
|
+
|
48
|
+
define_callback_module(mMode)
|
49
|
+
end
|
50
|
+
def before(m, *args, &block)
|
51
|
+
callback(:before, m, *args, &block)
|
52
|
+
end
|
53
|
+
def after(m, *args, &block)
|
54
|
+
callback(:after, m, *args, &block)
|
55
|
+
end
|
56
|
+
|
57
|
+
def create_eval_for_mod_with_string_and_type!(meth, type=nil, &block)
|
58
|
+
str = ""
|
59
|
+
case type
|
60
|
+
when :before
|
61
|
+
str << <<-EOD
|
62
|
+
def #{meth}(*args)
|
63
|
+
#{yield}
|
64
|
+
super
|
65
|
+
end
|
66
|
+
EOD
|
67
|
+
when :after
|
68
|
+
str << <<-EOD
|
69
|
+
def #{meth}(*args)
|
70
|
+
super
|
71
|
+
#{yield}
|
72
|
+
end
|
73
|
+
EOD
|
74
|
+
else
|
75
|
+
str << <<-EOD
|
76
|
+
def #{meth}(*args)
|
77
|
+
#{yield}
|
78
|
+
end
|
79
|
+
EOD
|
80
|
+
end
|
81
|
+
str
|
82
|
+
end
|
83
|
+
|
84
|
+
def callbacks
|
85
|
+
@callbacks ||= []
|
86
|
+
end
|
87
|
+
def classes
|
88
|
+
@classes ||= []
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
module InstanceMethods
|
93
|
+
def initialize(*args)
|
94
|
+
extend_callbacks
|
95
|
+
extend_callback_methods
|
96
|
+
end
|
97
|
+
|
98
|
+
def extend_callback_methods
|
99
|
+
unless self.class.classes.empty?
|
100
|
+
self.class.classes.each do |klass|
|
101
|
+
m = %{def #{klass.to_s.downcase};@#{klass.to_s.downcase} ||= #{klass}.new;end}
|
102
|
+
self.class.class_eval m unless self.class.method_defined?(m)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def extend_callbacks
|
108
|
+
unless self.class.callbacks.empty?
|
109
|
+
self.class.callbacks.each do |mod|
|
110
|
+
self.extend(mod)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
module ProcStoreMethods
|
117
|
+
def store_proc(proc)
|
118
|
+
proc_storage << proc
|
119
|
+
proc_storage.index(proc)
|
120
|
+
end
|
121
|
+
def get_proc(num)
|
122
|
+
proc_storage[num]
|
123
|
+
end
|
124
|
+
def proc_storage
|
125
|
+
@proc_store ||= []
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def self.included(receiver)
|
130
|
+
receiver.extend ClassMethods
|
131
|
+
receiver.extend ProcStoreMethods
|
132
|
+
receiver.send :include, InstanceMethods
|
133
|
+
end
|
134
|
+
end
|
data/lib/core/proc.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
class Proc
|
2
|
+
def bind(object)
|
3
|
+
block, time = self, Time.now
|
4
|
+
(class << object; self; end).class_eval do
|
5
|
+
method_name = "__bind_#{time.to_i}_#{time.usec}"
|
6
|
+
define_method(method_name, &block)
|
7
|
+
method = instance_method(method_name)
|
8
|
+
remove_method(method_name)
|
9
|
+
method
|
10
|
+
end.bind(object)
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,200 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
class TestCallbacks
|
4
|
+
include Callbacks
|
5
|
+
attr_reader :str
|
6
|
+
|
7
|
+
before :world, :hello
|
8
|
+
after :world, :thanks
|
9
|
+
|
10
|
+
def hello(caller)
|
11
|
+
string << "hello "
|
12
|
+
end
|
13
|
+
def world
|
14
|
+
string << "world"
|
15
|
+
end
|
16
|
+
def thanks(caller)
|
17
|
+
string << ", thank you"
|
18
|
+
end
|
19
|
+
after :pop, :boom
|
20
|
+
def pop
|
21
|
+
string << "pop"
|
22
|
+
end
|
23
|
+
def boom(caller)
|
24
|
+
string << " goes boom"
|
25
|
+
end
|
26
|
+
def string
|
27
|
+
@str ||= String.new
|
28
|
+
end
|
29
|
+
end
|
30
|
+
describe "Callbacks" do
|
31
|
+
before(:each) do
|
32
|
+
@klass = TestCallbacks.new
|
33
|
+
end
|
34
|
+
it "should retain it's class identifier" do
|
35
|
+
@klass.class.should == TestCallbacks
|
36
|
+
end
|
37
|
+
it "should callback the method before the method runs" do
|
38
|
+
@klass.world.should == "hello world, thank you"
|
39
|
+
end
|
40
|
+
it "should callback the method before the method runs" do
|
41
|
+
@klass.pop.should == "pop goes boom"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
class TestMultipleCallbacks
|
45
|
+
include Callbacks
|
46
|
+
attr_reader :str
|
47
|
+
def hi(caller)
|
48
|
+
string << "hi, "
|
49
|
+
end
|
50
|
+
def hello(caller)
|
51
|
+
string << "hello "
|
52
|
+
end
|
53
|
+
def world
|
54
|
+
string << "world"
|
55
|
+
end
|
56
|
+
def string
|
57
|
+
@str ||= String.new
|
58
|
+
end
|
59
|
+
before :world, :hi, :hello
|
60
|
+
end
|
61
|
+
describe "Multiple callbacks" do
|
62
|
+
before(:each) do
|
63
|
+
@klass = TestMultipleCallbacks.new
|
64
|
+
end
|
65
|
+
it "should be able to have multiple callbacks on the same call" do
|
66
|
+
@klass.world.should == "hi, hello world"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
class OutsideClass
|
70
|
+
def self.hello(caller)
|
71
|
+
puts "hello"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
class TestOutsideClass
|
75
|
+
include Callbacks
|
76
|
+
before :world, {:hello => OutsideClass}
|
77
|
+
def world
|
78
|
+
"world"
|
79
|
+
end
|
80
|
+
end
|
81
|
+
describe "Options" do
|
82
|
+
before(:each) do
|
83
|
+
@c = TestOutsideClass.new
|
84
|
+
end
|
85
|
+
it "should be able to pass external class options to the callback" do
|
86
|
+
OutsideClass.should_receive(:hello).and_return "hello"
|
87
|
+
@c.world
|
88
|
+
end
|
89
|
+
end
|
90
|
+
class BlockClass
|
91
|
+
include Callbacks
|
92
|
+
before :world do
|
93
|
+
string << "hello "
|
94
|
+
end
|
95
|
+
def world
|
96
|
+
string << "world"
|
97
|
+
end
|
98
|
+
def string
|
99
|
+
@string ||= ""
|
100
|
+
end
|
101
|
+
end
|
102
|
+
describe "Block callbacks" do
|
103
|
+
it "should call the block on the callback" do
|
104
|
+
BlockClass.new.world.should == "hello world"
|
105
|
+
end
|
106
|
+
end
|
107
|
+
class BlockAndMethodClass
|
108
|
+
include Callbacks
|
109
|
+
before :world, :hi do
|
110
|
+
string << "hello "
|
111
|
+
end
|
112
|
+
def world
|
113
|
+
string << "world"
|
114
|
+
end
|
115
|
+
def hi(caller)
|
116
|
+
string << "hi, "
|
117
|
+
end
|
118
|
+
def string
|
119
|
+
@string ||= ""
|
120
|
+
end
|
121
|
+
end
|
122
|
+
describe "Block and method callbacks" do
|
123
|
+
it "should call the block on the callback and add the block" do
|
124
|
+
BlockAndMethodClass.new.world.should == "hi, hello world"
|
125
|
+
end
|
126
|
+
end
|
127
|
+
class ExternalMethodCallClass
|
128
|
+
include Callbacks
|
129
|
+
before :world, :hello
|
130
|
+
after :hello, :peter
|
131
|
+
|
132
|
+
def world
|
133
|
+
string << "world"
|
134
|
+
end
|
135
|
+
def hello(caller)
|
136
|
+
string << "hello "
|
137
|
+
end
|
138
|
+
def peter(caller)
|
139
|
+
string << "peter "
|
140
|
+
end
|
141
|
+
def string
|
142
|
+
@string ||= ""
|
143
|
+
end
|
144
|
+
end
|
145
|
+
describe "External method callbacks inside a method" do
|
146
|
+
it "should call the block on the callback and add the " do
|
147
|
+
ExternalMethodCallClass.new.world.should == "hello peter world"
|
148
|
+
end
|
149
|
+
end
|
150
|
+
class OutsideBindingClass
|
151
|
+
def hello(caller)
|
152
|
+
caller.string << "hello"
|
153
|
+
end
|
154
|
+
end
|
155
|
+
class BindingClass
|
156
|
+
include Callbacks
|
157
|
+
before :world, :hello => "OutsideBindingClass"
|
158
|
+
def world
|
159
|
+
string << "#{@hello} world"
|
160
|
+
end
|
161
|
+
def string
|
162
|
+
@string ||= ""
|
163
|
+
end
|
164
|
+
end
|
165
|
+
describe "Methods" do
|
166
|
+
it "should have access to the local variables of the call" do
|
167
|
+
BindingClass.new.world.should == "hello world"
|
168
|
+
end
|
169
|
+
end
|
170
|
+
class EvilOutsideClass
|
171
|
+
attr_reader :name
|
172
|
+
def get_name(caller)
|
173
|
+
@name = caller.hello
|
174
|
+
end
|
175
|
+
def show_name(caller)
|
176
|
+
@name
|
177
|
+
end
|
178
|
+
end
|
179
|
+
class BindingClass
|
180
|
+
include Callbacks
|
181
|
+
before :print, {:get_name => "EvilOutsideClass"}
|
182
|
+
def print
|
183
|
+
"hello"
|
184
|
+
end
|
185
|
+
def hello
|
186
|
+
"franke"
|
187
|
+
end
|
188
|
+
end
|
189
|
+
describe "Variables on the plugin callbacker class" do
|
190
|
+
it "should call the methods from the class itself on a singeton method" do
|
191
|
+
BindingClass.new.methods.include?("eviloutsideclass").should == true
|
192
|
+
end
|
193
|
+
it "should call get_name on EvilOutsideClass" do
|
194
|
+
@bc = BindingClass.new
|
195
|
+
@eoc = EvilOutsideClass.new
|
196
|
+
@bc.should_receive("eviloutsideclass").and_return(@eoc)
|
197
|
+
@eoc.should_receive("get_name").and_return("bob")
|
198
|
+
@bc.print
|
199
|
+
end
|
200
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: auser-backcall
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Ari Lerner
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2008-06-12 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: facets
|
17
|
+
version_requirement:
|
18
|
+
version_requirements: !ruby/object:Gem::Requirement
|
19
|
+
requirements:
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: "0"
|
23
|
+
version:
|
24
|
+
description: Add basic memory-efficient before and after callbacks, easily
|
25
|
+
email: ari.lerner@citrusbyte.com
|
26
|
+
executables: []
|
27
|
+
|
28
|
+
extensions: []
|
29
|
+
|
30
|
+
extra_rdoc_files:
|
31
|
+
- CHANGELOG
|
32
|
+
- lib/backcall.rb
|
33
|
+
- lib/core/proc.rb
|
34
|
+
- README
|
35
|
+
files:
|
36
|
+
- CHANGELOG
|
37
|
+
- lib/backcall.rb
|
38
|
+
- lib/core/proc.rb
|
39
|
+
- Manifest
|
40
|
+
- Rakefile
|
41
|
+
- README
|
42
|
+
- spec/callback_spec.rb
|
43
|
+
- spec/spec_helper.rb
|
44
|
+
- backcall.gemspec
|
45
|
+
has_rdoc: true
|
46
|
+
homepage: http://blog.citrusbyte.com
|
47
|
+
post_install_message: |-
|
48
|
+
For more information, check http://blog.citrusbyte.com
|
49
|
+
*** Ari Lerner @ <ari.lerner@citrusbyte.com> ***
|
50
|
+
rdoc_options:
|
51
|
+
- --line-numbers
|
52
|
+
- --inline-source
|
53
|
+
- --title
|
54
|
+
- Backcall
|
55
|
+
- --main
|
56
|
+
- README
|
57
|
+
require_paths:
|
58
|
+
- lib
|
59
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: "0"
|
64
|
+
version:
|
65
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - ">="
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: "0"
|
70
|
+
version:
|
71
|
+
requirements: []
|
72
|
+
|
73
|
+
rubyforge_project: backcall
|
74
|
+
rubygems_version: 1.0.1
|
75
|
+
signing_key:
|
76
|
+
specification_version: 2
|
77
|
+
summary: Add basic memory-efficient before and after callbacks, easily
|
78
|
+
test_files: []
|
79
|
+
|