auser-backcall 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
|