mirrors 0.0.1
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.
- checksums.yaml +7 -0
- data/.gitignore +5 -0
- data/.rubocop.yml +2 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +23 -0
- data/LICENSE.txt +59 -0
- data/README.md +1 -0
- data/asdfasdf.rb +53 -0
- data/bin/bundler +17 -0
- data/bin/byebug +17 -0
- data/bin/testunit +8 -0
- data/circle.yml +6 -0
- data/dev.yml +6 -0
- data/lib/mirrors.rb +150 -0
- data/lib/mirrors/class_mirror.rb +197 -0
- data/lib/mirrors/class_mixin.rb +11 -0
- data/lib/mirrors/field_mirror.rb +24 -0
- data/lib/mirrors/field_mirror/class_variable_mirror.rb +23 -0
- data/lib/mirrors/field_mirror/constant_mirror.rb +34 -0
- data/lib/mirrors/field_mirror/instance_variable_mirror.rb +23 -0
- data/lib/mirrors/hook.rb +33 -0
- data/lib/mirrors/index/indexer.rb +6 -0
- data/lib/mirrors/index/marker.rb +40 -0
- data/lib/mirrors/invoke.rb +29 -0
- data/lib/mirrors/method_mirror.rb +206 -0
- data/lib/mirrors/mirror.rb +37 -0
- data/lib/mirrors/object_mirror.rb +25 -0
- data/lib/mirrors/package_inference.rb +164 -0
- data/lib/mirrors/package_inference/class_to_file_resolver.rb +66 -0
- data/lib/mirrors/package_mirror.rb +33 -0
- data/lib/mirrors/visitors/disasm_visitor.rb +11 -0
- data/lib/mirrors/visitors/iseq_visitor.rb +84 -0
- data/lib/mirrors/visitors/references_visitor.rb +58 -0
- data/lib/mirrors/visitors/yasmdata.rb +212 -0
- data/lol.rb +35 -0
- data/mirrors.gemspec +19 -0
- data/test/fixtures/class.rb +29 -0
- data/test/fixtures/field.rb +9 -0
- data/test/fixtures/method.rb +15 -0
- data/test/fixtures/object.rb +5 -0
- data/test/fixtures/reflect.rb +14 -0
- data/test/mirrors/class_mirror_test.rb +87 -0
- data/test/mirrors/field_mirror_test.rb +125 -0
- data/test/mirrors/iseq_visitor_test.rb +56 -0
- data/test/mirrors/marker_test.rb +48 -0
- data/test/mirrors/method_mirror_test.rb +62 -0
- data/test/mirrors/object_mirror_test.rb +16 -0
- data/test/mirrors/package_inference_test.rb +31 -0
- data/test/mirrors/references_visitor_test.rb +30 -0
- data/test/mirrors_test.rb +38 -0
- data/test/test_helper.rb +12 -0
- metadata +137 -0
@@ -0,0 +1,212 @@
|
|
1
|
+
# -*-ruby-*-
|
2
|
+
#
|
3
|
+
|
4
|
+
class VM
|
5
|
+
class InstructionSequence
|
6
|
+
class Instruction
|
7
|
+
InsnID2NO = {
|
8
|
+
nop: 0,
|
9
|
+
getlocal: 1,
|
10
|
+
setlocal: 2,
|
11
|
+
getspecial: 3,
|
12
|
+
setspecial: 4,
|
13
|
+
getinstancevariable: 5,
|
14
|
+
setinstancevariable: 6,
|
15
|
+
getclassvariable: 7,
|
16
|
+
setclassvariable: 8,
|
17
|
+
getconstant: 9,
|
18
|
+
setconstant: 10,
|
19
|
+
getglobal: 11,
|
20
|
+
setglobal: 12,
|
21
|
+
putnil: 13,
|
22
|
+
putself: 14,
|
23
|
+
putobject: 15,
|
24
|
+
putspecialobject: 16,
|
25
|
+
putiseq: 17,
|
26
|
+
putstring: 18,
|
27
|
+
concatstrings: 19,
|
28
|
+
tostring: 20,
|
29
|
+
freezestring: 21,
|
30
|
+
toregexp: 22,
|
31
|
+
newarray: 23,
|
32
|
+
duparray: 24,
|
33
|
+
expandarray: 25,
|
34
|
+
concatarray: 26,
|
35
|
+
splatarray: 27,
|
36
|
+
newhash: 28,
|
37
|
+
newrange: 29,
|
38
|
+
pop: 30,
|
39
|
+
dup: 31,
|
40
|
+
dupn: 32,
|
41
|
+
swap: 33,
|
42
|
+
reverse: 34,
|
43
|
+
reput: 35,
|
44
|
+
topn: 36,
|
45
|
+
setn: 37,
|
46
|
+
adjuststack: 38,
|
47
|
+
defined: 39,
|
48
|
+
checkmatch: 40,
|
49
|
+
checkkeyword: 41,
|
50
|
+
trace: 42,
|
51
|
+
defineclass: 43,
|
52
|
+
send: 44,
|
53
|
+
opt_str_freeze: 45,
|
54
|
+
opt_newarray_max: 46,
|
55
|
+
opt_newarray_min: 47,
|
56
|
+
opt_send_without_block: 48,
|
57
|
+
invokesuper: 49,
|
58
|
+
invokeblock: 50,
|
59
|
+
leave: 51,
|
60
|
+
throw: 52,
|
61
|
+
jump: 53,
|
62
|
+
branchif: 54,
|
63
|
+
branchunless: 55,
|
64
|
+
branchnil: 56,
|
65
|
+
getinlinecache: 57,
|
66
|
+
setinlinecache: 58,
|
67
|
+
once: 59,
|
68
|
+
opt_case_dispatch: 60,
|
69
|
+
opt_plus: 61,
|
70
|
+
opt_minus: 62,
|
71
|
+
opt_mult: 63,
|
72
|
+
opt_div: 64,
|
73
|
+
opt_mod: 65,
|
74
|
+
opt_eq: 66,
|
75
|
+
opt_neq: 67,
|
76
|
+
opt_lt: 68,
|
77
|
+
opt_le: 69,
|
78
|
+
opt_gt: 70,
|
79
|
+
opt_ge: 71,
|
80
|
+
opt_ltlt: 72,
|
81
|
+
opt_aref: 73,
|
82
|
+
opt_aset: 74,
|
83
|
+
opt_aset_with: 75,
|
84
|
+
opt_aref_with: 76,
|
85
|
+
opt_length: 77,
|
86
|
+
opt_size: 78,
|
87
|
+
opt_empty_p: 79,
|
88
|
+
opt_succ: 80,
|
89
|
+
opt_not: 81,
|
90
|
+
opt_regexpmatch1: 82,
|
91
|
+
opt_regexpmatch2: 83,
|
92
|
+
opt_call_c_function: 84,
|
93
|
+
bitblt: 85,
|
94
|
+
answer: 86,
|
95
|
+
getlocal_OP__WC__0: 87,
|
96
|
+
getlocal_OP__WC__1: 88,
|
97
|
+
setlocal_OP__WC__0: 89,
|
98
|
+
setlocal_OP__WC__1: 90,
|
99
|
+
putobject_OP_INT2FIX_O_0_C_: 91,
|
100
|
+
putobject_OP_INT2FIX_O_1_C_: 92,
|
101
|
+
|
102
|
+
}
|
103
|
+
|
104
|
+
def self.id2insn_no(id)
|
105
|
+
if InsnID2NO.key? id
|
106
|
+
InsnID2NO[id]
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
InsnNO2Size = [
|
111
|
+
1, # nop => 0
|
112
|
+
3, # getlocal => 1
|
113
|
+
3, # setlocal => 2
|
114
|
+
3, # getspecial => 3
|
115
|
+
2, # setspecial => 4
|
116
|
+
3, # getinstancevariable => 5
|
117
|
+
3, # setinstancevariable => 6
|
118
|
+
2, # getclassvariable => 7
|
119
|
+
2, # setclassvariable => 8
|
120
|
+
2, # getconstant => 9
|
121
|
+
2, # setconstant => 10
|
122
|
+
2, # getglobal => 11
|
123
|
+
2, # setglobal => 12
|
124
|
+
1, # putnil => 13
|
125
|
+
1, # putself => 14
|
126
|
+
2, # putobject => 15
|
127
|
+
2, # putspecialobject => 16
|
128
|
+
2, # putiseq => 17
|
129
|
+
2, # putstring => 18
|
130
|
+
2, # concatstrings => 19
|
131
|
+
1, # tostring => 20
|
132
|
+
2, # freezestring => 21
|
133
|
+
3, # toregexp => 22
|
134
|
+
2, # newarray => 23
|
135
|
+
2, # duparray => 24
|
136
|
+
3, # expandarray => 25
|
137
|
+
1, # concatarray => 26
|
138
|
+
2, # splatarray => 27
|
139
|
+
2, # newhash => 28
|
140
|
+
2, # newrange => 29
|
141
|
+
1, # pop => 30
|
142
|
+
1, # dup => 31
|
143
|
+
2, # dupn => 32
|
144
|
+
1, # swap => 33
|
145
|
+
2, # reverse => 34
|
146
|
+
1, # reput => 35
|
147
|
+
2, # topn => 36
|
148
|
+
2, # setn => 37
|
149
|
+
2, # adjuststack => 38
|
150
|
+
4, # defined => 39
|
151
|
+
2, # checkmatch => 40
|
152
|
+
3, # checkkeyword => 41
|
153
|
+
2, # trace => 42
|
154
|
+
4, # defineclass => 43
|
155
|
+
4, # send => 44
|
156
|
+
2, # opt_str_freeze => 45
|
157
|
+
2, # opt_newarray_max => 46
|
158
|
+
2, # opt_newarray_min => 47
|
159
|
+
3, # opt_send_without_block => 48
|
160
|
+
4, # invokesuper => 49
|
161
|
+
2, # invokeblock => 50
|
162
|
+
1, # leave => 51
|
163
|
+
2, # throw => 52
|
164
|
+
2, # jump => 53
|
165
|
+
2, # branchif => 54
|
166
|
+
2, # branchunless => 55
|
167
|
+
2, # branchnil => 56
|
168
|
+
3, # getinlinecache => 57
|
169
|
+
2, # setinlinecache => 58
|
170
|
+
3, # once => 59
|
171
|
+
3, # opt_case_dispatch => 60
|
172
|
+
3, # opt_plus => 61
|
173
|
+
3, # opt_minus => 62
|
174
|
+
3, # opt_mult => 63
|
175
|
+
3, # opt_div => 64
|
176
|
+
3, # opt_mod => 65
|
177
|
+
3, # opt_eq => 66
|
178
|
+
5, # opt_neq => 67
|
179
|
+
3, # opt_lt => 68
|
180
|
+
3, # opt_le => 69
|
181
|
+
3, # opt_gt => 70
|
182
|
+
3, # opt_ge => 71
|
183
|
+
3, # opt_ltlt => 72
|
184
|
+
3, # opt_aref => 73
|
185
|
+
3, # opt_aset => 74
|
186
|
+
4, # opt_aset_with => 75
|
187
|
+
4, # opt_aref_with => 76
|
188
|
+
3, # opt_length => 77
|
189
|
+
3, # opt_size => 78
|
190
|
+
3, # opt_empty_p => 79
|
191
|
+
3, # opt_succ => 80
|
192
|
+
3, # opt_not => 81
|
193
|
+
2, # opt_regexpmatch1 => 82
|
194
|
+
3, # opt_regexpmatch2 => 83
|
195
|
+
2, # opt_call_c_function => 84
|
196
|
+
1, # bitblt => 85
|
197
|
+
1, # answer => 86
|
198
|
+
2, # getlocal_OP__WC__0 => 87
|
199
|
+
2, # getlocal_OP__WC__1 => 88
|
200
|
+
2, # setlocal_OP__WC__0 => 89
|
201
|
+
2, # setlocal_OP__WC__1 => 90
|
202
|
+
1, # putobject_OP_INT2FIX_O_0_C_ => 91
|
203
|
+
1, # putobject_OP_INT2FIX_O_1_C_ => 92
|
204
|
+
|
205
|
+
]
|
206
|
+
|
207
|
+
def self.insn_no2size(ins_no)
|
208
|
+
InsnNO2Size[ins_no]
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
data/lol.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'mirrors'
|
2
|
+
require 'byebug'
|
3
|
+
|
4
|
+
module ClassFixtureModule
|
5
|
+
end
|
6
|
+
|
7
|
+
class ClassFixture
|
8
|
+
Foo = "Bar"
|
9
|
+
|
10
|
+
class ClassFixtureNested
|
11
|
+
class ClassFixtureNestedNested
|
12
|
+
end
|
13
|
+
end
|
14
|
+
include ClassFixtureModule
|
15
|
+
|
16
|
+
attr_accessor :b
|
17
|
+
def a
|
18
|
+
@a = 1
|
19
|
+
@@cvb = 1
|
20
|
+
end
|
21
|
+
|
22
|
+
@@cva = 1
|
23
|
+
@civa = 1
|
24
|
+
|
25
|
+
def self.b
|
26
|
+
@@cvc = 1
|
27
|
+
@civb = 1
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class ClassFixtureSubclass < ClassFixture; end
|
32
|
+
class ClassFixtureSubclassSubclass < ClassFixtureSubclass; end
|
33
|
+
|
34
|
+
@m = Mirrors.reflect(ClassFixture)
|
35
|
+
puts "Foo" == @m.constant("Foo").name
|
data/mirrors.gemspec
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = 'mirrors'
|
3
|
+
s.version = '0.0.1'
|
4
|
+
s.platform = Gem::Platform::RUBY
|
5
|
+
s.licenses = ['MIT']
|
6
|
+
s.authors = ['Burke Libbey']
|
7
|
+
s.email = ['burke.libbey@shopify.com']
|
8
|
+
s.homepage = 'https://github.com/Shopify/mirrors'
|
9
|
+
s.summary = 'Mirror API for Ruby'
|
10
|
+
s.description = 'Provides a number of specs and classes that document a mirror API for Ruby.'
|
11
|
+
s.files = `git ls-files`.split("\n")
|
12
|
+
s.test_files = `git ls-files -- spec/*`.split("\n")
|
13
|
+
s.require_paths = ['lib']
|
14
|
+
|
15
|
+
s.add_development_dependency 'minitest', '~> 5.0'
|
16
|
+
s.add_development_dependency 'byebug', '~> 9.0.6'
|
17
|
+
|
18
|
+
s.add_runtime_dependency 'method_source', '~> 0.8'
|
19
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module ClassFixtureModule
|
2
|
+
end
|
3
|
+
|
4
|
+
class ClassFixture
|
5
|
+
Foo = "Bar"
|
6
|
+
|
7
|
+
class ClassFixtureNested
|
8
|
+
class ClassFixtureNestedNested
|
9
|
+
end
|
10
|
+
end
|
11
|
+
include ClassFixtureModule
|
12
|
+
|
13
|
+
attr_accessor :b
|
14
|
+
def a
|
15
|
+
@a = 1
|
16
|
+
@@cvb = 1
|
17
|
+
end
|
18
|
+
|
19
|
+
@@cva = 1
|
20
|
+
@civa = 1
|
21
|
+
|
22
|
+
def self.b
|
23
|
+
@@cvc = 1
|
24
|
+
@civb = 1
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class ClassFixtureSubclass < ClassFixture; end
|
29
|
+
class ClassFixtureSubclassSubclass < ClassFixtureSubclass; end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class MethodSpecFixture
|
2
|
+
def source_location
|
3
|
+
[__FILE__, __LINE__, __method__.to_s, self.class]
|
4
|
+
end
|
5
|
+
|
6
|
+
def removeable_method
|
7
|
+
end
|
8
|
+
|
9
|
+
def method_p_public; end
|
10
|
+
|
11
|
+
def method_p_private; end
|
12
|
+
private :method_p_private
|
13
|
+
def method_p_protected; end
|
14
|
+
protected :method_p_protected
|
15
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module Mirrors
|
4
|
+
class ClassMirrorTest < MiniTest::Test
|
5
|
+
def setup
|
6
|
+
@m = Mirrors.reflect(ClassFixture)
|
7
|
+
super
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_name
|
11
|
+
assert_equal(ClassFixture.name, @m.name)
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_class_variables
|
15
|
+
names = @m.class_variables.collect(&:name)
|
16
|
+
assert_includes(names, "@@cva")
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_class_instance_variables
|
20
|
+
names = @m.class_instance_variables.collect(&:name)
|
21
|
+
assert_includes(names, "@civa")
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_constants
|
25
|
+
names = @m.constants.collect(&:name)
|
26
|
+
assert_includes(names, "Foo")
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_constant
|
30
|
+
assert_equal("Foo", @m.constant("Foo").name)
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_nested_constant
|
34
|
+
cname = ClassFixture::ClassFixtureNested::ClassFixtureNestedNested.name
|
35
|
+
ct = @m.constant(cname)
|
36
|
+
assert_equal("ClassFixtureNestedNested", ct.name)
|
37
|
+
assert_equal(cname, ct.value.name)
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_nested_classes
|
41
|
+
assert_equal(ClassFixture::ClassFixtureNested.name, @m.nested_classes.first.name)
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_instance_methods
|
45
|
+
assert_equal(ClassFixture.instance_methods(false).size, @m.methods.size)
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_instance_method
|
49
|
+
n = ClassFixture.instance_methods.first
|
50
|
+
assert(@m.method(n).mirrors?(ClassFixture.instance_method(n)))
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_ancestors
|
54
|
+
act = @m.ancestors.map(&:name)
|
55
|
+
exp = ClassFixture.ancestors.map(&:name)
|
56
|
+
exp.each do |name|
|
57
|
+
assert_includes(act, name)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def test_superclass
|
62
|
+
assert_equal(ClassFixture.superclass.name, @m.superclass.name)
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_subclasses
|
66
|
+
assert_equal(1, @m.subclasses.size)
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_mixins
|
70
|
+
assert_equal(ClassFixtureModule.name, @m.mixins.first.name)
|
71
|
+
end
|
72
|
+
|
73
|
+
def test_nesting
|
74
|
+
m = Mirrors.reflect(ClassFixture::ClassFixtureNested)
|
75
|
+
nesting = m.nesting
|
76
|
+
assert_equal([ClassFixture::ClassFixtureNested, ClassFixture], nesting)
|
77
|
+
end
|
78
|
+
|
79
|
+
def test_source_locations
|
80
|
+
assert(@m.source_files.any? { |l| l.include?('fixtures/class.rb') })
|
81
|
+
end
|
82
|
+
|
83
|
+
def test_constant_value
|
84
|
+
assert_equal("Bar", @m.constant("Foo").value.name)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,125 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module Mirrors
|
4
|
+
class FieldMirrorTest < MiniTest::Test
|
5
|
+
module FieldMirrorTests
|
6
|
+
def test_name
|
7
|
+
assert_equal(@nom, @m.name)
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_value
|
11
|
+
assert_equal(@nom.sub(/@@?/, ''), @m.value.name)
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_set_value
|
15
|
+
old_value = @o.send(:"#{@class_side}_variable_get", @nom)
|
16
|
+
@m.value = "changed"
|
17
|
+
assert_equal("changed", @o.send(:"#{@class_side}_variable_get", @nom))
|
18
|
+
assert_equal("changed", @m.value.name)
|
19
|
+
@m.value = old_value
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_reports_vars_as_private
|
23
|
+
assert(@m.private?)
|
24
|
+
refute(@m.protected?)
|
25
|
+
refute(@m.public?)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
class InstanceVariableMirrorTest < MiniTest::Test
|
30
|
+
def setup
|
31
|
+
@o = FieldFixture.new
|
32
|
+
@om = Mirrors.reflect(@o)
|
33
|
+
@m = @om.variables.first
|
34
|
+
@nom = "@ivar"
|
35
|
+
@class_side = "instance"
|
36
|
+
super
|
37
|
+
end
|
38
|
+
|
39
|
+
include FieldMirrorTests
|
40
|
+
end
|
41
|
+
|
42
|
+
class ClassInstanceVariableMirrorTest < MiniTest::Test
|
43
|
+
def setup
|
44
|
+
@o = FieldFixture
|
45
|
+
@om = Mirrors.reflect(@o)
|
46
|
+
@m = @om.variables.first
|
47
|
+
@nom = "@civar"
|
48
|
+
@class_side = "instance"
|
49
|
+
super
|
50
|
+
end
|
51
|
+
|
52
|
+
include FieldMirrorTests
|
53
|
+
end
|
54
|
+
|
55
|
+
class ClassVariableMirrorTest < MiniTest::Test
|
56
|
+
def setup
|
57
|
+
@o = FieldFixture
|
58
|
+
@om = Mirrors.reflect(@o)
|
59
|
+
@m = @om.class_variables.first
|
60
|
+
@nom = "@@cvar"
|
61
|
+
@class_side = "class"
|
62
|
+
super
|
63
|
+
end
|
64
|
+
|
65
|
+
include FieldMirrorTests
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
class ConstantMirrorTest < MiniTest::Test
|
70
|
+
def setup
|
71
|
+
@o = FieldFixture
|
72
|
+
@om = Mirrors.reflect(@o)
|
73
|
+
@m = @om.constants.first
|
74
|
+
@name = "CONSTANT"
|
75
|
+
super
|
76
|
+
end
|
77
|
+
|
78
|
+
def test_name
|
79
|
+
assert_equal(@name, @m.name)
|
80
|
+
end
|
81
|
+
|
82
|
+
def test_value
|
83
|
+
assert_equal(@name.downcase, @m.value.name)
|
84
|
+
end
|
85
|
+
|
86
|
+
def test_set_value
|
87
|
+
silence do
|
88
|
+
old_value = @m.value.reflectee
|
89
|
+
@m.value = "changed"
|
90
|
+
assert_equal("changed", @o.const_get(@name))
|
91
|
+
assert_equal("changed", @m.value.name)
|
92
|
+
@m.value = old_value
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def test_public
|
97
|
+
refute(@m.private?)
|
98
|
+
refute(@m.protected?)
|
99
|
+
assert(@m.public?)
|
100
|
+
end
|
101
|
+
|
102
|
+
def test_delete
|
103
|
+
@m.delete
|
104
|
+
refute_includes(@om.constants, @m)
|
105
|
+
@m = @om.reflectee.const_set(@m.name, @name)
|
106
|
+
silence do
|
107
|
+
@om.constant(@name).value = "constant"
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def test_add
|
112
|
+
cst = @om.constant("MyNewlyAddedConstant")
|
113
|
+
refute_includes(@om.constants.map(&:name), "MyNewlyAddedConstant")
|
114
|
+
cst.value = "MyNewlyAddedConstant"
|
115
|
+
assert_includes(@om.constants.map(&:name), "MyNewlyAddedConstant")
|
116
|
+
cst.delete
|
117
|
+
end
|
118
|
+
|
119
|
+
private
|
120
|
+
|
121
|
+
def silence(&block)
|
122
|
+
capture_subprocess_io(&block)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|