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