rebound 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,14 @@
1
+ === 0.0.2 / 2008-07-21
2
+
3
+ * Added JavaScript-esque ability to show method definition
4
+ for unbound methods like so:
5
+
6
+ m = Person.instance_method(:hello)
7
+ puts m.to_s(:ruby)
8
+
9
+ * Using new to_s abilities to enable the binding of unbound
10
+ methods that take block arguments.
11
+
12
+ === 0.0.1 / 2008-07-20
13
+
14
+ * Had an idea. Made it a gem.
@@ -0,0 +1,8 @@
1
+ History.txt
2
+ Manifest.txt
3
+ README.textile
4
+ Rakefile
5
+ rebound.gemspec
6
+ lib/rebound.rb
7
+ spec/rebound_spec.rb
8
+ spec/spec_helper.rb
@@ -0,0 +1,74 @@
1
+ h1. rebound
2
+
3
+ By default, instances of UnboundMethod can only be bound to objects that
4
+ are a kind_of? the method's original class. Pretty lame.
5
+
6
+ rebound allows unbound methods (instances of UnboundMethod class) to be
7
+ bound to objects of any class. It uses the alias_method_chain pattern to
8
+ accomplish this, meaning you also get a bind_without_indifference method
9
+ that retains the original behavior.
10
+
11
+ "http://github.com/nakajima/rebound":http://github.com/nakajima/rebound
12
+
13
+ h3. USAGE
14
+
15
+ <pre>
16
+ class Guy
17
+ def greet
18
+ puts "Hello!"
19
+ end
20
+ end
21
+
22
+ class Girl
23
+ # No #greet method here
24
+ end
25
+
26
+ girl = Girl.new
27
+
28
+ m = Guy.instance_method(:greet)
29
+
30
+ m.bind(girl)
31
+
32
+ girl.greet # => Hello!
33
+ </pre>
34
+
35
+ h3. TODO:
36
+
37
+ * Could probably use some more specs, since I'm pretty sure I didn't think
38
+ of everything.
39
+
40
+ h3. REQUIREMENTS:
41
+
42
+ * ParseTree
43
+ * Ruby2Ruby
44
+
45
+ h3. Credit
46
+
47
+ I'm just standing on "Ryan Davis'":http://www.zenspider.com shoulders with
48
+ this project. He did all the hard work. I just did something cool with it.
49
+ (Which isn't to say that what he did wasn't cool, since what he did is *way*
50
+ cooler than what you see here.)
51
+
52
+ Also, "Magnus Holm":http://judofyr.net contributed a patch that made things
53
+ cleaner behind the scenes.
54
+
55
+ Copyright (c) 2008 Pat Nakajima
56
+
57
+ Permission is hereby granted, free of charge, to any person obtaining
58
+ a copy of this software and associated documentation files (the
59
+ 'Software'), to deal in the Software without restriction, including
60
+ without limitation the rights to use, copy, modify, merge, publish,
61
+ distribute, sublicense, and/or sell copies of the Software, and to
62
+ permit persons to whom the Software is furnished to do so, subject to
63
+ the following conditions:
64
+
65
+ The above copyright notice and this permission notice shall be
66
+ included in all copies or substantial portions of the Software.
67
+
68
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
69
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
70
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
71
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
72
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
73
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
74
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,4 @@
1
+ desc "Run specs"
2
+ task :default do
3
+ puts `spec spec/ --colour`
4
+ end
@@ -0,0 +1,44 @@
1
+ module Nakajima
2
+ module Rebound
3
+ VERSION = '0.0.2'
4
+ end
5
+ end
6
+
7
+ %w(rubygems ruby2ruby).each { |lib| require lib } unless defined?(Ruby2Ruby)
8
+
9
+ class UnboundMethod
10
+ # eval's and memoizes the output of Ruby2Ruby's #to_ruby method
11
+ def to_proc
12
+ @to_proc ||= eval(to_ruby)
13
+ end
14
+
15
+ alias_method :to_s_without_ruby, :to_s
16
+ # This is sort of ugly, but it does allow us to bind methods that
17
+ # take block arguments (you can't use block arguments with blocks).
18
+ def to_s_with_ruby(opt=nil)
19
+ (opt != :ruby) ? to_s_without_ruby : begin
20
+ @to_s ||= begin
21
+ res = to_ruby
22
+ res.gsub!(/\Aproc \{ /, "def #{name}") # Replace proc definition
23
+ res.gsub!(/\|([^\|]*)\|\n/, "(#{'\1'})\n") # Use method param declaration
24
+ res.gsub!(/\}\z/, 'end') # Replace proc end brace
25
+ res
26
+ end
27
+ end
28
+ end
29
+ alias_method :to_s, :to_s_with_ruby
30
+
31
+ # Simple string name. Taken from Pat Maddox's with_context
32
+ def name
33
+ @name ||= to_s.split("#").last.delete(">")
34
+ end
35
+
36
+ alias_method :bind_without_indifference, :bind
37
+ # Allows an unbound method to be bound to any object, instead
38
+ # of only those of the same class. Goes with original #bind method
39
+ # first, and if that fails, meta_def's using #to_proc
40
+ def bind_with_indifference(obj)
41
+ bind_without_indifference(obj) rescue class << obj; self end.class_eval(to_s(:ruby))
42
+ end
43
+ alias_method :bind, :bind_with_indifference
44
+ end
@@ -0,0 +1,20 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = %q{rebound}
3
+ s.version = "0.0.2"
4
+
5
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
6
+ s.authors = ["Pat Nakajima"]
7
+ s.date = %q{2008-07-20}
8
+ s.description = %q{By default, instances of UnboundMethod can only be bound to objects that are a kind_of? the method's original class. Pretty lame. rebound allows unbound methods (instances of UnboundMethod class) to be bound to objects of any class. It uses the alias_method_chain pattern to accomplish this, meaning you also get a bind_without_indifference method that retains the original behavior.}
9
+ s.email = ["patnakajima@gmail.com"]
10
+ s.extra_rdoc_files = ["History.txt", "Manifest.txt", "README.textile"]
11
+ s.files = ["History.txt", "Manifest.txt", "README.textile", "Rakefile", "lib/rebound.rb", "spec/rebound_spec.rb", "spec/spec_helper.rb", "rebound.gemspec"]
12
+ s.has_rdoc = true
13
+ s.homepage = %q{http://github.com/nakajima/rebound}
14
+ s.rdoc_options = ["--main", "README.textile"]
15
+ s.require_paths = ["lib"]
16
+ s.rubygems_version = %q{1.2.0}
17
+ s.summary = %q{By default, instances of UnboundMethod can only be bound to objects that are a kind_of? the method's original class. This fixes that.}
18
+ s.test_files = ["spec/rebound_spec.rb"]
19
+ s.add_dependency('ruby2ruby', [">= 1.1.9"])
20
+ end
@@ -0,0 +1,100 @@
1
+ require File.join(File.dirname(__FILE__), 'spec_helper')
2
+
3
+ describe UnboundMethod do
4
+ before(:each) do
5
+ @a = Class.new { def foo; :bar end }
6
+ @b = Class.new { def called?; @called end }
7
+ @mod = Module.new { def call; @called = true; end }
8
+ @object_a = @a.new
9
+ @object_b = @b.new
10
+ end
11
+
12
+ describe "#name" do
13
+ it "should return name" do
14
+ m = @a.instance_method(:foo)
15
+ m.name.should == 'foo'
16
+ end
17
+ end
18
+
19
+ describe "#to_s" do
20
+ it "should provide source" do
21
+ m = @a.instance_method(:foo)
22
+ m.to_s(:ruby).should == "def foo()\n :bar\nend"
23
+ end
24
+
25
+ it "should be memoized" do
26
+ m = @a.instance_method(:foo)
27
+ m.should_receive(:to_ruby).once.and_return(proc { :bar }.to_ruby)
28
+ 2.times { m.to_s(:ruby) }
29
+ end
30
+ end
31
+
32
+ describe "#bind" do
33
+ it "should bind method from Class.instance_method to object of different class" do
34
+ m = @a.instance_method(:foo)
35
+ m.bind(@object_b)
36
+ @object_b.foo.should == :bar
37
+ end
38
+
39
+ it "should bind singleton method to object of different class" do
40
+ class << @object_a; def greet; :hello end end
41
+ m = @object_a.method(:greet).unbind
42
+ m.bind(@object_b)
43
+ @object_b.greet.should == :hello
44
+ end
45
+
46
+ it "should bind methods that take an argument" do
47
+ class << @object_a; def greet(name); "hello #{name}" end end
48
+ m = @object_a.method(:greet).unbind
49
+ m.bind(@object_b)
50
+ @object_b.greet('pat').should == "hello pat"
51
+ end
52
+
53
+ it "should bind methods that take splat of arguments" do
54
+ class << @object_a
55
+ def add_these(container, *args)
56
+ args.each { |a| container << a }
57
+ end
58
+ end
59
+ m = @object_a.method(:add_these).unbind
60
+ m.bind(@object_b)
61
+ collector = []
62
+ @object_b.add_these(collector, 'pat', 'tim', 'drew')
63
+ collector.should == ['pat', 'tim', 'drew']
64
+ end
65
+
66
+ it "should bind methods that take block" do
67
+ class << @object_a
68
+ def append(&block)
69
+ res = [:original]
70
+ res << yield
71
+ res
72
+ end
73
+ end
74
+
75
+ m = @object_a.method(:append).unbind
76
+ m.bind(@object_b)
77
+ @object_b.append { :addition }.should == [:original, :addition]
78
+ end
79
+
80
+ it "should bind module instance method" do
81
+ m = @mod.instance_method(:call)
82
+ m.bind(@object_b)
83
+ @object_b.call
84
+ @object_b.should be_called
85
+ end
86
+ end
87
+
88
+ describe "#to_proc" do
89
+ it "should return proc version" do
90
+ m = @a.instance_method(:foo)
91
+ m.to_proc.call.should == :bar
92
+ end
93
+
94
+ it "should be memoized" do
95
+ m = @a.instance_method(:foo)
96
+ m.should_receive(:to_ruby).once.and_return(proc { :bar }.to_ruby)
97
+ 2.times { m.to_proc }
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,3 @@
1
+ require File.join(File.dirname(__FILE__), '..', 'lib', 'rebound')
2
+ require 'rubygems'
3
+ require 'spec'
metadata ADDED
@@ -0,0 +1,73 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rebound
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Pat Nakajima
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-07-20 00:00:00 -04:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: ruby2ruby
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 1.1.9
24
+ version:
25
+ description: By default, instances of UnboundMethod can only be bound to objects that are a kind_of? the method's original class. Pretty lame. rebound allows unbound methods (instances of UnboundMethod class) to be bound to objects of any class. It uses the alias_method_chain pattern to accomplish this, meaning you also get a bind_without_indifference method that retains the original behavior.
26
+ email:
27
+ - patnakajima@gmail.com
28
+ executables: []
29
+
30
+ extensions: []
31
+
32
+ extra_rdoc_files:
33
+ - History.txt
34
+ - Manifest.txt
35
+ - README.textile
36
+ files:
37
+ - History.txt
38
+ - Manifest.txt
39
+ - README.textile
40
+ - Rakefile
41
+ - lib/rebound.rb
42
+ - spec/rebound_spec.rb
43
+ - spec/spec_helper.rb
44
+ - rebound.gemspec
45
+ has_rdoc: true
46
+ homepage: http://github.com/nakajima/rebound
47
+ post_install_message:
48
+ rdoc_options:
49
+ - --main
50
+ - README.textile
51
+ require_paths:
52
+ - lib
53
+ required_ruby_version: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: "0"
58
+ version:
59
+ required_rubygems_version: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: "0"
64
+ version:
65
+ requirements: []
66
+
67
+ rubyforge_project:
68
+ rubygems_version: 1.3.0
69
+ signing_key:
70
+ specification_version: 2
71
+ summary: By default, instances of UnboundMethod can only be bound to objects that are a kind_of? the method's original class. This fixes that.
72
+ test_files:
73
+ - spec/rebound_spec.rb