dup_eval 0.1.0

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