local_eval 0.2.0 → 0.2.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.
- data/README.markdown +28 -12
- data/Rakefile +2 -2
- data/lib/local_eval/version.rb +1 -1
- data/lib/local_eval.rb +68 -23
- data/lib/local_eval_flymake.rb +133 -0
- data/test/helper1.rb +12 -2
- data/test/helper1_flymake.rb +83 -0
- data/test/test.rb +22 -4
- data/test/test_flymake.rb +152 -0
- data/test/test_segfault.rb +26 -0
- data/test/test_segfault2.rb +8 -0
- data/test/test_segfault_flymake.rb +25 -0
- metadata +14 -8
data/README.markdown
CHANGED
@@ -38,32 +38,48 @@ block:
|
|
38
38
|
example: capture
|
39
39
|
--------------------
|
40
40
|
|
41
|
-
`
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
41
|
+
Since `local_eval` does not alter the `self` inside a block,
|
42
|
+
all methods with an implied receiver will be invoked with respect to
|
43
|
+
this self. This means that all mutator methods defined on the receiver
|
44
|
+
will modify state on the block's self rather than on the receiver's
|
45
|
+
self. This is unlikely to be the desired behaviour; and so
|
46
|
+
using the `capture` method we can redirect the method lookup to
|
47
|
+
the actual receiver. All code captured by the `capture` block
|
48
|
+
will be `instance_eval`'d against the actual receiver of the method.
|
49
|
+
|
50
|
+
class C
|
51
|
+
class << self
|
52
|
+
attr_reader :hello
|
53
|
+
def self.capture_test
|
54
|
+
|
55
|
+
# this code will be run against C
|
56
|
+
capture { @hello = :captured }
|
57
|
+
|
58
|
+
# this code will be run against the block context
|
59
|
+
@goodbye = :goobye
|
60
|
+
end
|
47
61
|
end
|
48
62
|
end
|
49
|
-
|
50
|
-
n = Object.new
|
51
|
-
n.gen_extend o
|
52
|
-
n.bye #=> :bye
|
53
63
|
|
64
|
+
C.local_eval { capture_test }
|
65
|
+
|
66
|
+
C.hello #=> :captured
|
67
|
+
@goodbye #=> :goodbye
|
68
|
+
|
54
69
|
How it works
|
55
70
|
--------------
|
56
71
|
|
57
|
-
|
72
|
+
Makes use of companion libraries: Remix and Object2module
|
58
73
|
|
59
74
|
Companion Libraries
|
60
75
|
--------------------
|
61
76
|
|
62
|
-
|
77
|
+
LocalEval is one of a series of experimental libraries that mess with
|
63
78
|
the internals of Ruby to bring new and interesting functionality to
|
64
79
|
the language, see also:
|
65
80
|
|
66
81
|
* [Remix](http://github.com/banister/remix) - Makes ancestor chains read/write
|
82
|
+
* [Object2module](http://github.com/banister/object2module) - Enables you to include/extend Object/Classes.
|
67
83
|
* [Include Complete](http://github.com/banister/include_complete) - Brings in
|
68
84
|
module singleton classes during an include. No more ugly ClassMethods and included() hook hacks.
|
69
85
|
* [Prepend](http://github.com/banister/prepend) - Prepends modules in front of a class; so method lookup starts with the module
|
data/Rakefile
CHANGED
@@ -18,8 +18,8 @@ def apply_spec_defaults(s)
|
|
18
18
|
s.email = 'jrmair@gmail.com'
|
19
19
|
s.description = s.summary
|
20
20
|
s.require_path = 'lib'
|
21
|
-
s.add_dependency("remix",">=0.4.
|
22
|
-
s.add_dependency("object2module",">=0.4.
|
21
|
+
s.add_dependency("remix",">=0.4.9")
|
22
|
+
s.add_dependency("object2module",">=0.4.5")
|
23
23
|
s.homepage = "http://banisterfiend.wordpress.com"
|
24
24
|
s.has_rdoc = 'yard'
|
25
25
|
s.files = Dir["ext/**/extconf.rb", "ext/**/*.h", "ext/**/*.c", "lib/**/*.rb",
|
data/lib/local_eval/version.rb
CHANGED
data/lib/local_eval.rb
CHANGED
@@ -5,25 +5,25 @@ require 'remix'
|
|
5
5
|
require 'object2module'
|
6
6
|
|
7
7
|
module LocalEval
|
8
|
-
|
9
|
-
# Thread-local name for the hidden self used by `capture`
|
10
|
-
# @return [String] The name of the hidden self used by `capture`
|
11
|
-
def self.context_self_name
|
12
|
-
"@__self__#{Thread.current.object_id}"
|
13
|
-
end
|
14
|
-
|
15
|
-
module ClassExtensions
|
16
|
-
|
17
|
-
# Find the instance associated with the singleton class
|
18
|
-
# @return [Object] Instance associated with the singleton class
|
19
|
-
def __attached__
|
20
|
-
ObjectSpace.each_object(self).first
|
21
|
-
end
|
22
|
-
end
|
23
8
|
|
24
9
|
module ObjectExtensions
|
25
10
|
|
26
|
-
|
11
|
+
# A more general version of `local_eval`.
|
12
|
+
# `local_eval_with` allows you to inject arbitrary functionality
|
13
|
+
# from any number of objects into the block.
|
14
|
+
# @param [Array] objs The objects to provide functionality to the block
|
15
|
+
# @return The value of the block
|
16
|
+
# @example
|
17
|
+
# class A; def self.a; puts "a"; end; end
|
18
|
+
# class B; def self.b; puts "b"; end; end
|
19
|
+
# class C; def self.c; puts "c"; end; end
|
20
|
+
# local_eval_with(A, B, C) { a; b; c }
|
21
|
+
# #=> "a"
|
22
|
+
# #=> "b"
|
23
|
+
# #=> "c"
|
24
|
+
def local_eval_with(*objs, &block)
|
25
|
+
raise "need a block" if !block_given?
|
26
|
+
|
27
27
|
objs = Array(self) if objs.empty?
|
28
28
|
context = eval('self', block.binding)
|
29
29
|
|
@@ -40,11 +40,58 @@ module LocalEval
|
|
40
40
|
# mix the anonymous module into the block context
|
41
41
|
context.temp_extend functionality, &block
|
42
42
|
end
|
43
|
-
alias_method :local_eval_with, :local_eval
|
44
|
-
|
45
|
-
# This form is meant to be called without a receiver
|
46
43
|
private :local_eval_with
|
47
44
|
|
45
|
+
# Performs a `local_eval` on the block with respect to the
|
46
|
+
# receiver.
|
47
|
+
# `local_eval` has some advantages over `instance_eval` in that it
|
48
|
+
# does not change `self`. Instead, the functionality in the block
|
49
|
+
# context is supplemented by the functionality in the
|
50
|
+
# receiver.
|
51
|
+
# @return The return value of the block
|
52
|
+
# @yield The block to `local_eval`
|
53
|
+
# @example local ivars can be looked up
|
54
|
+
# class C
|
55
|
+
# def hello(name)
|
56
|
+
# "hello #{name}!"
|
57
|
+
# end
|
58
|
+
# end
|
59
|
+
#
|
60
|
+
# o = C.new
|
61
|
+
#
|
62
|
+
# @name = "John"
|
63
|
+
# o.local_eval { hello(@name) } #=> "hello John!"
|
64
|
+
def local_eval(&block)
|
65
|
+
local_eval_with(&block)
|
66
|
+
end
|
67
|
+
|
68
|
+
# Since `local_eval` does not alter the `self` inside a block,
|
69
|
+
# all methods with an implied receiver will be invoked with respect to
|
70
|
+
# this self. This means that all mutator methods defined on the receiver
|
71
|
+
# will modify state on the block's self rather than on the receiver's
|
72
|
+
# self. This is unlikely to be the desired behaviour; and so
|
73
|
+
# using the `capture` method we can redirect the method lookup to
|
74
|
+
# the actual receiver. All code captured by the `capture` block
|
75
|
+
# will be `instance_eval`'d against the actual receiver of the
|
76
|
+
# method.
|
77
|
+
# @return The return value of the block.
|
78
|
+
# @yield The block to be evaluated in the receiver's context.
|
79
|
+
# @example
|
80
|
+
# class C
|
81
|
+
# def self.hello() @hello end
|
82
|
+
# def self.capture_test
|
83
|
+
#
|
84
|
+
# # this code will be run against C
|
85
|
+
# capture { @hello = :captured }
|
86
|
+
#
|
87
|
+
# # this code will be run against the block context
|
88
|
+
# @goodbye = :goobye
|
89
|
+
# end
|
90
|
+
# end
|
91
|
+
#
|
92
|
+
# C.local_eval { capture_test }
|
93
|
+
# C.hello #=> :captured
|
94
|
+
# @goodbye #=> :goodbye
|
48
95
|
def capture(&block)
|
49
96
|
|
50
97
|
# 1. Get name of enclosing method (method that invoked
|
@@ -59,13 +106,11 @@ module LocalEval
|
|
59
106
|
attached_object = method_owner.__attached__
|
60
107
|
attached_object.instance_eval &block
|
61
108
|
end
|
109
|
+
alias_method :__capture__, :capture
|
110
|
+
|
62
111
|
end
|
63
112
|
end
|
64
113
|
|
65
|
-
class Class
|
66
|
-
include LocalEval::ClassExtensions
|
67
|
-
end
|
68
|
-
|
69
114
|
class Object
|
70
115
|
include LocalEval::ObjectExtensions
|
71
116
|
end
|
@@ -0,0 +1,133 @@
|
|
1
|
+
direc = File.dirname(__FILE__)
|
2
|
+
|
3
|
+
require "#{direc}/local_eval/version"
|
4
|
+
require 'remix'
|
5
|
+
require 'object2module'
|
6
|
+
|
7
|
+
module LocalEval
|
8
|
+
module ClassExtensions
|
9
|
+
|
10
|
+
# Find the instance associated with the singleton class
|
11
|
+
# @return [Object] Instance associated with the singleton class
|
12
|
+
def __attached__
|
13
|
+
ObjectSpace.each_object(self).first
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
module ObjectExtensions
|
18
|
+
|
19
|
+
# A more general version of `local_eval`.
|
20
|
+
# `local_eval_with` allows you to inject arbitrary functionality
|
21
|
+
# from any number of objects into the block. Methods that use a
|
22
|
+
# `capture` block are invoked on the object that defines the
|
23
|
+
# method (and not the local context).
|
24
|
+
# @param [Array] objs The objects to provide functionality to the block
|
25
|
+
# @return The value of the block
|
26
|
+
# @example
|
27
|
+
# class A; def self.a; puts "a"; end; end
|
28
|
+
# class B; def self.b; puts "b"; end; end
|
29
|
+
# class C; def self.c; puts "c"; end; end
|
30
|
+
# local_eval_with(A, B, C) { a; b; c }
|
31
|
+
# #=> "a"
|
32
|
+
# #=> "b"
|
33
|
+
# #=> "c"
|
34
|
+
def local_eval_with(*objs, &block)
|
35
|
+
raise "need a block" if !block_given?
|
36
|
+
|
37
|
+
objs = Array(self) if objs.empty?
|
38
|
+
context = eval('self', block.binding)
|
39
|
+
|
40
|
+
# if the receiver is the same as the block context then don't
|
41
|
+
# mix in anything, as functionality is already present.
|
42
|
+
if objs.include?(context)
|
43
|
+
objs.delete(context)
|
44
|
+
return yield if objs.empty?
|
45
|
+
end
|
46
|
+
|
47
|
+
# add functionality to anonymous module to ease mixing and unmixing
|
48
|
+
functionality = Module.new.gen_include *objs.map { |o| o.is_a?(Module) ? o.singleton_class : o }
|
49
|
+
|
50
|
+
# mix the anonymous module into the block context
|
51
|
+
context.temp_extend functionality, &block
|
52
|
+
end
|
53
|
+
private :local_eval_with
|
54
|
+
|
55
|
+
# Performs a `local_eval` on the block with respect to the
|
56
|
+
# receiver.
|
57
|
+
# `local_eval` has some advantages over `instance_eval` in that it
|
58
|
+
# does not change `self`. Instead, the functionality in the local
|
59
|
+
# context is supplemented by the functionality in the
|
60
|
+
# receiver. Further, if receiver methods utilize a `capture` block
|
61
|
+
# then the receiver of that `local_eval` becomes the receiver of that
|
62
|
+
# method call (rather than the local context).
|
63
|
+
# @return The return value of the block
|
64
|
+
# @yield The block to `local_eval`
|
65
|
+
# @example local ivars can be looked up
|
66
|
+
# class C
|
67
|
+
# def hello(name)
|
68
|
+
# "hello #{name}!"
|
69
|
+
# end
|
70
|
+
# end
|
71
|
+
#
|
72
|
+
# o = C.new
|
73
|
+
#
|
74
|
+
# @name = "John"
|
75
|
+
# o.local_eval { hello(@name) } #=> "hello John!"
|
76
|
+
def local_eval(&block)
|
77
|
+
local_eval_with(&block)
|
78
|
+
end
|
79
|
+
|
80
|
+
# Since `local_eval` does not alter the `self` inside a block,
|
81
|
+
# all methods with an implied receiver will be invoked with respect to
|
82
|
+
# this self. This means that all mutator methods defined on the receiver
|
83
|
+
# will modify state on the block's self rather than on the receiver's
|
84
|
+
# self. This is unlikely to be the desired behaviour; and so
|
85
|
+
# using the `capture` method we can redirect the method lookup to
|
86
|
+
# the actual receiver. All code captured by the `capture` block
|
87
|
+
# will be `instance_eval`'d against the actual receiver of the
|
88
|
+
# method.
|
89
|
+
# @return The return value of the block.
|
90
|
+
# @yield The block to be evaluated in the receiver's context.
|
91
|
+
# @example
|
92
|
+
# class C
|
93
|
+
# attr_reader :hello
|
94
|
+
# def self.capture_test
|
95
|
+
#
|
96
|
+
# # this code will be run against C
|
97
|
+
# capture { @hello = :captured }
|
98
|
+
#
|
99
|
+
# # this code will be run against the block context
|
100
|
+
# @goodbye = :goobye
|
101
|
+
# end
|
102
|
+
# end
|
103
|
+
#
|
104
|
+
# C.local_eval { capture_test }
|
105
|
+
# C.hello #=> :captured
|
106
|
+
# @goodbye #=> :goodbye
|
107
|
+
def capture(&block)
|
108
|
+
|
109
|
+
# 1. Get name of enclosing method (method that invoked
|
110
|
+
# `capture ` block)
|
111
|
+
# 2. Find owner of enclosing method (owner is guaranteed to be
|
112
|
+
# a singleton class)
|
113
|
+
# 4. Find associated object (attached object) of the singleton class
|
114
|
+
# 5. This object will be the receiver of the method call, so
|
115
|
+
# instance_eval on it.
|
116
|
+
method_name = eval('__method__', block.binding)
|
117
|
+
|
118
|
+
method_owner = method(method_name).owner
|
119
|
+
attached_object = method_owner.__attached__
|
120
|
+
attached_object.instance_eval &block
|
121
|
+
end
|
122
|
+
alias_method :__capture__, :capture
|
123
|
+
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
class Class
|
128
|
+
include LocalEval::ClassExtensions
|
129
|
+
end
|
130
|
+
|
131
|
+
class Object
|
132
|
+
include LocalEval::ObjectExtensions
|
133
|
+
end
|
data/test/helper1.rb
CHANGED
@@ -5,7 +5,7 @@ end
|
|
5
5
|
Reset = proc do
|
6
6
|
O = Object.new
|
7
7
|
O2 = Object.new
|
8
|
-
|
8
|
+
O3 = Object.new
|
9
9
|
class A
|
10
10
|
def self.a
|
11
11
|
:a
|
@@ -23,7 +23,7 @@ Reset = proc do
|
|
23
23
|
:o
|
24
24
|
end
|
25
25
|
|
26
|
-
def
|
26
|
+
def ivar_set1(var, val)
|
27
27
|
instance_variable_set(var, val)
|
28
28
|
end
|
29
29
|
|
@@ -43,6 +43,16 @@ Reset = proc do
|
|
43
43
|
end
|
44
44
|
end
|
45
45
|
|
46
|
+
class << O3
|
47
|
+
def receiver_ivar_set3
|
48
|
+
capture {
|
49
|
+
@receiver_ivar3 = :receiver3
|
50
|
+
}
|
51
|
+
@ivar3 = :ivar3
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
|
46
56
|
class C
|
47
57
|
def self.build_proc
|
48
58
|
proc { love }
|
@@ -0,0 +1,83 @@
|
|
1
|
+
class Module
|
2
|
+
public :remove_const, :include, :remove_method
|
3
|
+
end
|
4
|
+
|
5
|
+
Reset = proc do
|
6
|
+
O = Object.new
|
7
|
+
O2 = Object.new
|
8
|
+
O3 = Object.new
|
9
|
+
class A
|
10
|
+
def self.a
|
11
|
+
:a
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class B
|
16
|
+
def self.b
|
17
|
+
:b
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class << O
|
22
|
+
def hello
|
23
|
+
:o
|
24
|
+
end
|
25
|
+
|
26
|
+
def ivar_set1(var, val)
|
27
|
+
instance_variable_set(var, val)
|
28
|
+
end
|
29
|
+
|
30
|
+
def receiver_ivar_set
|
31
|
+
capture {
|
32
|
+
@receiver_ivar = :receiver
|
33
|
+
}
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
class << O2
|
39
|
+
def receiver_ivar_set2
|
40
|
+
capture {
|
41
|
+
@receiver_ivar2 = :receiver2
|
42
|
+
}
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
class << O3
|
47
|
+
def receiver_ivar_set3
|
48
|
+
capture {
|
49
|
+
@receiver_ivar3 = :receiver3
|
50
|
+
}
|
51
|
+
@ivar3 = :ivar3
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
|
56
|
+
class C
|
57
|
+
def self.build_proc
|
58
|
+
proc { love }
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.hello
|
62
|
+
:c
|
63
|
+
end
|
64
|
+
|
65
|
+
def self.c
|
66
|
+
:c
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.ivar(v)
|
70
|
+
v
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
module M
|
75
|
+
def self.hello
|
76
|
+
:m
|
77
|
+
end
|
78
|
+
|
79
|
+
def m
|
80
|
+
:m
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
data/test/test.rb
CHANGED
@@ -14,7 +14,7 @@ describe LocalEval do
|
|
14
14
|
end
|
15
15
|
|
16
16
|
after do
|
17
|
-
[:A, :B, :C, :M, :O, :O2].each do |c|
|
17
|
+
[:A, :B, :C, :M, :O, :O2, :O3].each do |c|
|
18
18
|
Object.remove_const(c)
|
19
19
|
end
|
20
20
|
end
|
@@ -77,9 +77,9 @@ describe LocalEval do
|
|
77
77
|
|
78
78
|
it 'should make the method set a local ivar' do
|
79
79
|
instance_variable_defined?(:@v).should == false
|
80
|
-
lambda {
|
81
|
-
O.local_eval {
|
82
|
-
lambda {
|
80
|
+
lambda { ivar_set1 }.should.raise NameError
|
81
|
+
O.local_eval { ivar_set1(:@v, 10) }
|
82
|
+
lambda { ivar_set1 }.should.raise NameError
|
83
83
|
@v.should == 10
|
84
84
|
end
|
85
85
|
|
@@ -130,6 +130,24 @@ describe LocalEval do
|
|
130
130
|
O2.instance_variable_get(:@receiver_ivar2).should == :receiver2
|
131
131
|
O.instance_variable_get(:@receiver_ivar).should == :receiver
|
132
132
|
end
|
133
|
+
|
134
|
+
it 'should separate the two different selves in a method when using capture' do
|
135
|
+
O3.instance_variable_defined?(:@receiver_ivar).should == false
|
136
|
+
instance_variable_defined?(:@ivar3).should == false
|
137
|
+
O3.local_eval { receiver_ivar_set3 }
|
138
|
+
O3.instance_variable_get(:@receiver_ivar3).should == :receiver3
|
139
|
+
instance_variable_get(:@ivar3).should == :ivar3
|
140
|
+
remove_instance_variable(:@ivar3)
|
141
|
+
end
|
142
|
+
|
143
|
+
it 'should work in an instance_eval' do
|
144
|
+
o = Object.new
|
145
|
+
o.instance_eval do
|
146
|
+
O3.local_eval { receiver_ivar_set3 }
|
147
|
+
O3.instance_variable_get(:@receiver_ivar3).should == :receiver3
|
148
|
+
instance_variable_get(:@ivar3).should == :ivar3
|
149
|
+
end
|
150
|
+
end
|
133
151
|
end
|
134
152
|
|
135
153
|
describe 'mixing in a module' do
|
@@ -0,0 +1,152 @@
|
|
1
|
+
direc = File.dirname(__FILE__)
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require "#{direc}/../lib/local_eval"
|
5
|
+
require "#{direc}/helper1"
|
6
|
+
|
7
|
+
puts "Testing LocalEval version #{LocalEval::VERSION}..."
|
8
|
+
puts "With Remix version #{Remix::VERSION} and Object2module version #{Object2module::VERSION}"
|
9
|
+
puts "Ruby version #{RUBY_VERSION}"
|
10
|
+
|
11
|
+
describe LocalEval do
|
12
|
+
before do
|
13
|
+
Reset.call
|
14
|
+
end
|
15
|
+
|
16
|
+
after do
|
17
|
+
[:A, :B, :C, :M, :O, :O2, :O3].each do |c|
|
18
|
+
Object.remove_const(c)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe 'mixing in an object' do
|
23
|
+
it 'should mix in and mixout the object and make functionality available to block' do
|
24
|
+
lambda { hello }.should.raise NameError
|
25
|
+
O.local_eval { hello }.should == :o
|
26
|
+
lambda { hello }.should.raise NameError
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'should not error when receiver is the same as block context' do
|
30
|
+
lambda { local_eval { :hello } }.should.not.raise ArgumentError
|
31
|
+
local_eval { :hello }.should == :hello
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'should mix implicit self into context of block' do
|
35
|
+
def self.love; :love; end
|
36
|
+
local_eval(&C.build_proc).should == :love
|
37
|
+
self.singleton_class.remove_method(:love)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe 'local_eval_with' do
|
42
|
+
it 'should mix in multiple objects and make functionality available to the block' do
|
43
|
+
lambda { a }.should.raise NameError
|
44
|
+
lambda { b }.should.raise NameError
|
45
|
+
lambda { local_eval_with(A, B) { a; b; } }.should.not.raise NameError
|
46
|
+
lambda { a }.should.raise NameError
|
47
|
+
lambda { b }.should.raise NameError
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'should not error when mixing in multiple objects that include the context of the block' do
|
51
|
+
lambda { local_eval_with(self, A, B) { a; b } }.should.not.raise NameError
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
describe 'mixing in a class' do
|
56
|
+
it 'should mix in and mixout the class' do
|
57
|
+
lambda { hello }.should.raise NameError
|
58
|
+
C.local_eval { c }.should == :c
|
59
|
+
lambda { hello }.should.raise NameError
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'should mixin and mixout a class/module chain' do
|
63
|
+
C.extend M
|
64
|
+
lambda { c }.should.raise NameError
|
65
|
+
lambda { m }.should.raise NameError
|
66
|
+
C.local_eval { c.should == :c; m.should == :m }
|
67
|
+
lambda { c }.should.raise NameError
|
68
|
+
lambda { m }.should.raise NameError
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
describe 'ivars in the block' do
|
73
|
+
it 'should make ivars accessible to, and modifiable by, block' do
|
74
|
+
O.local_eval { @x = 5 }
|
75
|
+
@x.should == 5
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'should make the method set a local ivar' do
|
79
|
+
instance_variable_defined?(:@v).should == false
|
80
|
+
lambda { ivar_set }.should.raise NameError
|
81
|
+
O.local_eval { ivar_set(:@v, 10) }
|
82
|
+
lambda { ivar_set }.should.raise NameError
|
83
|
+
@v.should == 10
|
84
|
+
end
|
85
|
+
|
86
|
+
it 'should make local ivars accessible to mixed in methods' do
|
87
|
+
@y = 10
|
88
|
+
lambda { ivar(@y) }.should.raise NameError
|
89
|
+
C.local_eval { ivar(@y) }.should == 10
|
90
|
+
@y.should == 10
|
91
|
+
lambda { ivar(@y) }.should.raise NameError
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
describe 'capture block' do
|
96
|
+
it 'should make capture evaluate the method in receiver context' do
|
97
|
+
instance_variable_defined?(:@receiver_ivar).should == false
|
98
|
+
lambda { receiver_ivar_set }.should.raise NameError
|
99
|
+
O.local_eval { receiver_ivar_set }
|
100
|
+
instance_variable_defined?(:@receiver_ivar).should == false
|
101
|
+
O.instance_variable_get(:@receiver_ivar).should == :receiver
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'should redirect methods to appropriate receivers' do
|
105
|
+
O.instance_variable_defined?(:@receiver_ivar2).should == false
|
106
|
+
O2.instance_variable_defined?(:@receiver_ivar2).should == false
|
107
|
+
instance_variable_defined?(:@receiver_ivar).should == false
|
108
|
+
instance_variable_defined?(:@receiver_ivar2).should == false
|
109
|
+
lambda { receiver_ivar_set; receiver_ivar_set2 }.should.raise NameError
|
110
|
+
local_eval_with(O, O2) { receiver_ivar_set; receiver_ivar_set2 }
|
111
|
+
instance_variable_defined?(:@receiver_ivar).should == false
|
112
|
+
instance_variable_defined?(:@receiver_ivar2).should == false
|
113
|
+
O.instance_variable_get(:@receiver_ivar).should == :receiver
|
114
|
+
O2.instance_variable_get(:@receiver_ivar2).should == :receiver2
|
115
|
+
end
|
116
|
+
|
117
|
+
it 'should not prevent method lookup on capture-methods on objects that are not involved in the local_eval' do
|
118
|
+
O2.instance_variable_defined?(:@receiver_ivar2).should == false
|
119
|
+
O.local_eval { O2.receiver_ivar_set2.should == :receiver2 }
|
120
|
+
O2.instance_variable_get(:@receiver_ivar2).should == :receiver2
|
121
|
+
end
|
122
|
+
|
123
|
+
it 'should work properly with nested local_evals' do
|
124
|
+
O.local_eval do
|
125
|
+
O2.local_eval { receiver_ivar_set2 }
|
126
|
+
lambda { receiver_ivar_set2 }.should.raise NameError
|
127
|
+
receiver_ivar_set
|
128
|
+
end
|
129
|
+
|
130
|
+
O2.instance_variable_get(:@receiver_ivar2).should == :receiver2
|
131
|
+
O.instance_variable_get(:@receiver_ivar).should == :receiver
|
132
|
+
end
|
133
|
+
|
134
|
+
it 'should separate the two different selves in a method when using capture' do
|
135
|
+
O3.instance_variable_defined?(:@receiver_ivar).should == false
|
136
|
+
instance_variable_defined?(:@ivar3).should == false
|
137
|
+
O3.local_eval { receiver_ivar_set3 }
|
138
|
+
O3.instance_variable_get(:@receiver_ivar3).should == :receiver3
|
139
|
+
instance_variable_get(:@ivar3).should == :ivar3
|
140
|
+
remove_instance_variable(:@ivar3)
|
141
|
+
end
|
142
|
+
|
143
|
+
end
|
144
|
+
|
145
|
+
describe 'mixing in a module' do
|
146
|
+
it 'should mix in and mixout the module' do
|
147
|
+
lambda { hello }.should.raise NameError
|
148
|
+
M.local_eval { hello }.should == :m
|
149
|
+
lambda { hello }.should.raise NameError
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
direc = File.dirname(__FILE__)
|
2
|
+
require "rubygems"
|
3
|
+
require "#{direc}/../lib/local_eval"
|
4
|
+
require 'mult'
|
5
|
+
|
6
|
+
C = Object.new
|
7
|
+
class << C
|
8
|
+
def hello
|
9
|
+
capture { @hello = :captures
|
10
|
+
}
|
11
|
+
@goodbye = :captured
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# C.local_eval { hello }
|
16
|
+
# C.hello
|
17
|
+
# puts @goodbye
|
18
|
+
|
19
|
+
o = Object.new
|
20
|
+
o.instance_eval {
|
21
|
+
C.local_eval { hello }
|
22
|
+
puts @goodbye
|
23
|
+
puts C.instance_variable_get(:@hello)
|
24
|
+
# puts @hello
|
25
|
+
puts self.object_id
|
26
|
+
}
|
@@ -0,0 +1,25 @@
|
|
1
|
+
direc = File.dirname(__FILE__)
|
2
|
+
require "rubygems"
|
3
|
+
require "#{direc}/../lib/local_eval"
|
4
|
+
require 'mult'
|
5
|
+
|
6
|
+
class C
|
7
|
+
attr_reader :hello
|
8
|
+
def self.hello
|
9
|
+
capture { @hello = :captures }
|
10
|
+
@goodbye = :captured
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
C.local_eval { hello }
|
15
|
+
@goodbye
|
16
|
+
C.hello
|
17
|
+
m = Module.new
|
18
|
+
m.gen_include Module.new.singleton_class
|
19
|
+
|
20
|
+
o = Object.new
|
21
|
+
o.instance_eval {
|
22
|
+
# o.actual_class = C
|
23
|
+
self.temp_extend(m) { puts self
|
24
|
+
# C.local_eval { puts self }
|
25
|
+
}
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 2
|
8
|
-
-
|
9
|
-
version: 0.2.
|
8
|
+
- 2
|
9
|
+
version: 0.2.2
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- John Mair (banisterfiend)
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-11-
|
17
|
+
date: 2010-11-16 00:00:00 +13:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -28,8 +28,8 @@ dependencies:
|
|
28
28
|
segments:
|
29
29
|
- 0
|
30
30
|
- 4
|
31
|
-
-
|
32
|
-
version: 0.4.
|
31
|
+
- 9
|
32
|
+
version: 0.4.9
|
33
33
|
type: :runtime
|
34
34
|
version_requirements: *id001
|
35
35
|
- !ruby/object:Gem::Dependency
|
@@ -43,8 +43,8 @@ dependencies:
|
|
43
43
|
segments:
|
44
44
|
- 0
|
45
45
|
- 4
|
46
|
-
-
|
47
|
-
version: 0.4.
|
46
|
+
- 5
|
47
|
+
version: 0.4.5
|
48
48
|
type: :runtime
|
49
49
|
version_requirements: *id002
|
50
50
|
description: instance_eval without changing self
|
@@ -59,12 +59,18 @@ files:
|
|
59
59
|
- lib/local_eval/version.rb
|
60
60
|
- lib/local_eval/version_flymake.rb
|
61
61
|
- lib/local_eval.rb
|
62
|
+
- lib/local_eval_flymake.rb
|
62
63
|
- test/helper1.rb
|
64
|
+
- test/helper1_flymake.rb
|
63
65
|
- test/test.rb
|
66
|
+
- test/test_flymake.rb
|
67
|
+
- test/test_segfault.rb
|
68
|
+
- test/test_segfault2.rb
|
69
|
+
- test/test_segfault_flymake.rb
|
64
70
|
- CHANGELOG
|
65
71
|
- README.markdown
|
66
72
|
- Rakefile
|
67
|
-
has_rdoc:
|
73
|
+
has_rdoc: true
|
68
74
|
homepage: http://banisterfiend.wordpress.com
|
69
75
|
licenses: []
|
70
76
|
|