local_eval 0.2.2 → 0.2.4
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 +2 -2
- data/Rakefile +1 -1
- data/lib/local_eval.rb +0 -1
- data/lib/local_eval/version.rb +1 -1
- data/test/helper1.rb +13 -0
- data/test/helper1_flymake.rb +1 -0
- data/test/test.rb +22 -0
- data/test/test_flymake.rb +19 -3
- data/test/test_segfault.rb +6 -3
- data/test/test_segfault2.rb +1 -1
- metadata +6 -8
- data/lib/local_eval_flymake.rb +0 -133
- data/test/test_segfault_flymake.rb +0 -25
data/README.markdown
CHANGED
@@ -40,10 +40,10 @@ example: capture
|
|
40
40
|
|
41
41
|
Since `local_eval` does not alter the `self` inside a block,
|
42
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
|
43
|
+
this local self. This means that all mutator methods defined on the receiver
|
44
44
|
will modify state on the block's self rather than on the receiver's
|
45
45
|
self. This is unlikely to be the desired behaviour; and so
|
46
|
-
|
46
|
+
we can use the `capture` method to redirect method lookup to
|
47
47
|
the actual receiver. All code captured by the `capture` block
|
48
48
|
will be `instance_eval`'d against the actual receiver of the method.
|
49
49
|
|
data/Rakefile
CHANGED
@@ -19,7 +19,7 @@ def apply_spec_defaults(s)
|
|
19
19
|
s.description = s.summary
|
20
20
|
s.require_path = 'lib'
|
21
21
|
s.add_dependency("remix",">=0.4.9")
|
22
|
-
s.add_dependency("object2module",">=0.
|
22
|
+
s.add_dependency("object2module",">=0.5.0")
|
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.rb
CHANGED
data/lib/local_eval/version.rb
CHANGED
data/test/helper1.rb
CHANGED
data/test/helper1_flymake.rb
CHANGED
data/test/test.rb
CHANGED
@@ -36,6 +36,25 @@ describe LocalEval do
|
|
36
36
|
local_eval(&C.build_proc).should == :love
|
37
37
|
self.singleton_class.remove_method(:love)
|
38
38
|
end
|
39
|
+
|
40
|
+
it 'should not segfault when inspecting self inside a local_eval' do
|
41
|
+
O2.local_eval { self }.should.not == nil
|
42
|
+
O2.local_eval { self }.should.not == nil
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'should mix in entire object inheritance chain, including singleton' do
|
46
|
+
c = C2.new
|
47
|
+
def c.sing
|
48
|
+
:sing
|
49
|
+
end
|
50
|
+
|
51
|
+
c.local_eval { c1.should == :c1; c2.should == :c2; sing.should == :sing }
|
52
|
+
|
53
|
+
lambda { c1 }.should.raise NameError
|
54
|
+
lambda { sing }.should.raise NameError
|
55
|
+
lambda { c2 }.should.raise NameError
|
56
|
+
end
|
57
|
+
|
39
58
|
end
|
40
59
|
|
41
60
|
describe 'local_eval_with' do
|
@@ -148,6 +167,9 @@ describe LocalEval do
|
|
148
167
|
instance_variable_get(:@ivar3).should == :ivar3
|
149
168
|
end
|
150
169
|
end
|
170
|
+
|
171
|
+
|
172
|
+
|
151
173
|
end
|
152
174
|
|
153
175
|
describe 'mixing in a module' do
|
data/test/test_flymake.rb
CHANGED
@@ -36,6 +36,11 @@ describe LocalEval do
|
|
36
36
|
local_eval(&C.build_proc).should == :love
|
37
37
|
self.singleton_class.remove_method(:love)
|
38
38
|
end
|
39
|
+
|
40
|
+
it 'should not segfault when inspecting self inside a local_eval' do
|
41
|
+
O2.local_eval { self.inspect }
|
42
|
+
end
|
43
|
+
|
39
44
|
end
|
40
45
|
|
41
46
|
describe 'local_eval_with' do
|
@@ -77,9 +82,9 @@ describe LocalEval do
|
|
77
82
|
|
78
83
|
it 'should make the method set a local ivar' do
|
79
84
|
instance_variable_defined?(:@v).should == false
|
80
|
-
lambda {
|
81
|
-
O.local_eval {
|
82
|
-
lambda {
|
85
|
+
lambda { ivar_set1 }.should.raise NameError
|
86
|
+
O.local_eval { ivar_set1(:@v, 10) }
|
87
|
+
lambda { ivar_set1 }.should.raise NameError
|
83
88
|
@v.should == 10
|
84
89
|
end
|
85
90
|
|
@@ -140,6 +145,17 @@ describe LocalEval do
|
|
140
145
|
remove_instance_variable(:@ivar3)
|
141
146
|
end
|
142
147
|
|
148
|
+
it 'should work in an instance_eval' do
|
149
|
+
o = Object.new
|
150
|
+
o.instance_eval do
|
151
|
+
O3.local_eval { receiver_ivar_set3 }
|
152
|
+
O3.instance_variable_get(:@receiver_ivar3).should == :receiver3
|
153
|
+
instance_variable_get(:@ivar3).should == :ivar3
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
|
158
|
+
|
143
159
|
end
|
144
160
|
|
145
161
|
describe 'mixing in a module' do
|
data/test/test_segfault.rb
CHANGED
@@ -16,11 +16,14 @@ end
|
|
16
16
|
# C.hello
|
17
17
|
# puts @goodbye
|
18
18
|
|
19
|
+
k = C.singleton_class.singleton_class.singleton_class
|
20
|
+
|
19
21
|
o = Object.new
|
20
22
|
o.instance_eval {
|
21
|
-
|
23
|
+
k.local_eval { puts self; puts self.singleton_class.ancestors }
|
22
24
|
puts @goodbye
|
23
25
|
puts C.instance_variable_get(:@hello)
|
24
|
-
# puts @hello
|
25
|
-
puts self.object_id
|
26
26
|
}
|
27
|
+
|
28
|
+
V = Class.new
|
29
|
+
puts V.ancestors
|
data/test/test_segfault2.rb
CHANGED
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
|
+
- 4
|
9
|
+
version: 0.2.4
|
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-17 00:00:00 +13:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -42,9 +42,9 @@ dependencies:
|
|
42
42
|
- !ruby/object:Gem::Version
|
43
43
|
segments:
|
44
44
|
- 0
|
45
|
-
- 4
|
46
45
|
- 5
|
47
|
-
|
46
|
+
- 0
|
47
|
+
version: 0.5.0
|
48
48
|
type: :runtime
|
49
49
|
version_requirements: *id002
|
50
50
|
description: instance_eval without changing self
|
@@ -59,18 +59,16 @@ 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
|
63
62
|
- test/helper1.rb
|
64
63
|
- test/helper1_flymake.rb
|
65
64
|
- test/test.rb
|
66
65
|
- test/test_flymake.rb
|
67
66
|
- test/test_segfault.rb
|
68
67
|
- test/test_segfault2.rb
|
69
|
-
- test/test_segfault_flymake.rb
|
70
68
|
- CHANGELOG
|
71
69
|
- README.markdown
|
72
70
|
- Rakefile
|
73
|
-
has_rdoc:
|
71
|
+
has_rdoc: yard
|
74
72
|
homepage: http://banisterfiend.wordpress.com
|
75
73
|
licenses: []
|
76
74
|
|
data/lib/local_eval_flymake.rb
DELETED
@@ -1,133 +0,0 @@
|
|
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
|
@@ -1,25 +0,0 @@
|
|
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
|
-
}
|