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.
@@ -0,0 +1,2 @@
1
+ v0.0.2 Extended callbacks to external classes
2
+ v0.0.1 Initial release
@@ -0,0 +1,8 @@
1
+ CHANGELOG
2
+ lib/backcall.rb
3
+ lib/core/proc.rb
4
+ Manifest
5
+ Rakefile
6
+ README
7
+ spec/callback_spec.rb
8
+ spec/spec_helper.rb
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.
@@ -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
@@ -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
@@ -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
@@ -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
@@ -0,0 +1,9 @@
1
+ $:.unshift(File.join(File.dirname(__FILE__), %w(.. lib)))
2
+
3
+ %w(test/spec backcall).each do |library|
4
+ begin
5
+ require library
6
+ rescue
7
+ STDERR.puts "== Cannot run test without #{library}"
8
+ end
9
+ end
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
+