dup_eval 0.1.0
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/README.markdown +47 -0
- data/dup_eval.gemspec +17 -0
- data/lib/dup_eval.rb +85 -0
- data/test/dup_eval_test.rb +89 -0
- metadata +65 -0
data/README.markdown
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
Dup\_eval
|
2
|
+
========
|
3
|
+
|
4
|
+
This is an alternative to \_why's mix\_eval C extension. It provides identical functionality to mix\_eval as well as the following extra
|
5
|
+
functionality:
|
6
|
+
* Ability to mix in Objects/Classes (using Object2module)
|
7
|
+
* Thread-safety
|
8
|
+
|
9
|
+
Dup\_eval is based on coderrr's idea for dupping the binding of a block (http://coderrr.wordpress.com/2008/11/14/making-mixico-thread-safe/)
|
10
|
+
|
11
|
+
NOTE:
|
12
|
+
Dup\_eval is still in proof of concept stage, use at own risk!
|
13
|
+
|
14
|
+
Example use:
|
15
|
+
===========
|
16
|
+
|
17
|
+
#create our object
|
18
|
+
o = Object.new
|
19
|
+
|
20
|
+
#give it a method
|
21
|
+
class << o
|
22
|
+
def hello; print "Hello! "; end
|
23
|
+
end
|
24
|
+
|
25
|
+
#create a method in the current binding
|
26
|
+
def goodbye; puts "Goodbye!"; end
|
27
|
+
|
28
|
+
o.dup_eval { hello; goodbye } #=> "Hello! Goodbye!"
|
29
|
+
|
30
|
+
From above, both the methods of the object itself and the binding of the block are available to the block.
|
31
|
+
|
32
|
+
#we can also choose which objects we want to eval the block with respect to (we can have more than one)
|
33
|
+
o1 = Object.new
|
34
|
+
class << o1; ...define methods here... end
|
35
|
+
|
36
|
+
o2 = Object.new
|
37
|
+
class << o2; ...define methods here... end
|
38
|
+
|
39
|
+
o3 = Object.new
|
40
|
+
class << o3; ...define methods here... end
|
41
|
+
|
42
|
+
#create a method in the current binding
|
43
|
+
def goodbye; puts "Goodbye!"; end
|
44
|
+
|
45
|
+
o1.dup_eval_with(o1, o2, o3) { o1_method; o2_method; o3_method; goodbye }
|
46
|
+
|
47
|
+
As shown above we can have the block access methods in many objects (as many as we want). The objects may also be either Objects, Classes, or Modules.
|
data/dup_eval.gemspec
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = "dup_eval"
|
3
|
+
s.version = "0.1.0"
|
4
|
+
s.summary = "souped up version of instance_eval in the vein of mix_eval"
|
5
|
+
s.email = "jrmair@gmail.com"
|
6
|
+
s.homepage = "http://banisterfiend.wordpress.com"
|
7
|
+
s.description = "see http://github.com/why/mixico"
|
8
|
+
s.has_rdoc = false
|
9
|
+
s.authors = ["banister", "coderrr"]
|
10
|
+
s.files = [
|
11
|
+
"README.markdown",
|
12
|
+
"dup_eval.gemspec",
|
13
|
+
"lib/dup_eval.rb"
|
14
|
+
]
|
15
|
+
s.test_files = ["test/dup_eval_test.rb"]
|
16
|
+
s.add_dependency("RubyInline", [">= 3.6.7"])
|
17
|
+
end
|
data/lib/dup_eval.rb
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'inline'
|
3
|
+
require 'object2module'
|
4
|
+
|
5
|
+
class Object
|
6
|
+
inline do |builder|
|
7
|
+
builder.prefix %{
|
8
|
+
#define KLASS_OF(o) RCLASS(RBASIC(o)->klass)
|
9
|
+
}
|
10
|
+
|
11
|
+
builder.c %{
|
12
|
+
void redirect_tbls(VALUE obj) {
|
13
|
+
unsigned long orig_iv_tbl, orig_m_tbl;
|
14
|
+
orig_iv_tbl = (unsigned long)ROBJECT(self)->iv_tbl;
|
15
|
+
orig_m_tbl = (unsigned long)KLASS_OF(self)->m_tbl;
|
16
|
+
ROBJECT(self)->iv_tbl = ROBJECT(obj)->iv_tbl;
|
17
|
+
KLASS_OF(self)->m_tbl = KLASS_OF(obj)->m_tbl;
|
18
|
+
rb_iv_set(self, "__orig_m_tbl__", orig_m_tbl);
|
19
|
+
rb_iv_set(self, "__orig_iv_tbl__", orig_iv_tbl);
|
20
|
+
}
|
21
|
+
}
|
22
|
+
|
23
|
+
#restore needed, or else GC will crash
|
24
|
+
builder.c %{
|
25
|
+
void restore_tbls() {
|
26
|
+
KLASS_OF(self)->m_tbl = (struct st_table *)rb_iv_get(self, "__orig_m_tbl__");
|
27
|
+
ROBJECT(self)->iv_tbl = (struct st_table *)rb_iv_get(self, "__orig_iv_tbl__");
|
28
|
+
}
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
class Class
|
35
|
+
inline do |builder|
|
36
|
+
builder.c %{
|
37
|
+
void redirect_tbls(VALUE class) {
|
38
|
+
unsigned long orig_iv_tbl, orig_m_tbl;
|
39
|
+
orig_iv_tbl = (unsigned long)RCLASS(self)->iv_tbl;
|
40
|
+
orig_m_tbl = (unsigned long)RCLASS(self)->m_tbl;
|
41
|
+
RCLASS(self)->iv_tbl = RCLASS(class)->iv_tbl;
|
42
|
+
RCLASS(self)->m_tbl = RCLASS(class)->m_tbl;
|
43
|
+
rb_iv_set(self, "__orig_iv_tbl__", orig_iv_tbl);
|
44
|
+
rb_iv_set(self, "__orig_m_tbl__", orig_m_tbl);
|
45
|
+
}
|
46
|
+
}
|
47
|
+
|
48
|
+
#restore needed, or else GC will crash
|
49
|
+
builder.c %{
|
50
|
+
void restore_tbls() {
|
51
|
+
RCLASS(self)->m_tbl = (struct st_table *)rb_iv_get(self, "__orig_m_tbl__");
|
52
|
+
RCLASS(self)->iv_tbl = (struct st_table *)rb_iv_get(self, "__orig_iv_tbl__");
|
53
|
+
}
|
54
|
+
}
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
class Proc
|
59
|
+
def _context
|
60
|
+
eval('self', self)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
class Object
|
65
|
+
def dup_eval(*mods, &blk)
|
66
|
+
#default value is self
|
67
|
+
mods = self if mods.empty?
|
68
|
+
|
69
|
+
duped_context = blk._context.dup
|
70
|
+
#make sure the singleton class is in existence
|
71
|
+
class << duped_context; self; end
|
72
|
+
|
73
|
+
duped_context.redirect_tbls(blk._context)
|
74
|
+
|
75
|
+
duped_context.gen_extend(*mods)
|
76
|
+
begin
|
77
|
+
m = duped_context.is_a?(Module) ? :class_eval : :instance_eval
|
78
|
+
duped_context.send(m, &blk)
|
79
|
+
ensure
|
80
|
+
duped_context.restore_tbls
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
alias_method :dup_eval_with, :dup_eval
|
85
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
|
3
|
+
require File.dirname(__FILE__) + "/../lib/dup_eval"
|
4
|
+
|
5
|
+
class Dup_EvalTest < Test::Unit::TestCase
|
6
|
+
def setup
|
7
|
+
@p = Proc.new do
|
8
|
+
assert_equal :bink, bink
|
9
|
+
assert_equal :local_method, local_method
|
10
|
+
end
|
11
|
+
|
12
|
+
@p2 = Proc.new do
|
13
|
+
assert_equal :bink, bink
|
14
|
+
assert_equal :bunk, bunk
|
15
|
+
assert_equal :local_method, local_method
|
16
|
+
end
|
17
|
+
|
18
|
+
@m = Module.new do
|
19
|
+
def bink
|
20
|
+
:bink
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
@o = Object.new
|
25
|
+
class << @o
|
26
|
+
def bink
|
27
|
+
:bink
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
@o2 = Object.new
|
32
|
+
class <<@o2
|
33
|
+
def bunk
|
34
|
+
:bunk
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
@c = Class.new
|
39
|
+
@c.class_eval do
|
40
|
+
def bink
|
41
|
+
:bink
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
#a method in the local binding
|
47
|
+
#used for testing
|
48
|
+
def local_method
|
49
|
+
:local_method
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_mixing_in_self_when_object
|
53
|
+
o = Object.new
|
54
|
+
class << o
|
55
|
+
def bink
|
56
|
+
:bink
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
o.dup_eval(&@p)
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_mixing_in_self_when_class
|
64
|
+
c = Class.new
|
65
|
+
c.class_eval do
|
66
|
+
def bink
|
67
|
+
:bink
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
c.dup_eval(&@p)
|
72
|
+
end
|
73
|
+
|
74
|
+
def test_mixing_in_module
|
75
|
+
Module.new.dup_eval_with(@m, &@p)
|
76
|
+
end
|
77
|
+
|
78
|
+
def test_mixing_in_object
|
79
|
+
Module.new.dup_eval_with(@o, &@p)
|
80
|
+
end
|
81
|
+
|
82
|
+
def test_mixing_in_class
|
83
|
+
Module.new.dup_eval_with(@c, &@p)
|
84
|
+
end
|
85
|
+
|
86
|
+
def test_mixing_in_multi_objects
|
87
|
+
Module.new.dup_eval_with(@o, @o2, &@p2)
|
88
|
+
end
|
89
|
+
end
|
metadata
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: dup_eval
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- banister
|
8
|
+
- coderrr
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2008-12-17 00:00:00 +13:00
|
14
|
+
default_executable:
|
15
|
+
dependencies:
|
16
|
+
- !ruby/object:Gem::Dependency
|
17
|
+
name: RubyInline
|
18
|
+
type: :runtime
|
19
|
+
version_requirement:
|
20
|
+
version_requirements: !ruby/object:Gem::Requirement
|
21
|
+
requirements:
|
22
|
+
- - ">="
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: 3.6.7
|
25
|
+
version:
|
26
|
+
description: see http://github.com/why/mixico
|
27
|
+
email: jrmair@gmail.com
|
28
|
+
executables: []
|
29
|
+
|
30
|
+
extensions: []
|
31
|
+
|
32
|
+
extra_rdoc_files: []
|
33
|
+
|
34
|
+
files:
|
35
|
+
- README.markdown
|
36
|
+
- dup_eval.gemspec
|
37
|
+
- lib/dup_eval.rb
|
38
|
+
has_rdoc: false
|
39
|
+
homepage: http://banisterfiend.wordpress.com
|
40
|
+
post_install_message:
|
41
|
+
rdoc_options: []
|
42
|
+
|
43
|
+
require_paths:
|
44
|
+
- lib
|
45
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - ">="
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: "0"
|
50
|
+
version:
|
51
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: "0"
|
56
|
+
version:
|
57
|
+
requirements: []
|
58
|
+
|
59
|
+
rubyforge_project:
|
60
|
+
rubygems_version: 1.2.0
|
61
|
+
signing_key:
|
62
|
+
specification_version: 2
|
63
|
+
summary: souped up version of instance_eval in the vein of mix_eval
|
64
|
+
test_files:
|
65
|
+
- test/dup_eval_test.rb
|