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 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