1require_relative '../spec_helper'
2require_relative '../fixtures/constants'
3require_relative 'fixtures/constants_sclass'
4require_relative 'fixtures/constant_visibility'
5
6# Read the documentation in fixtures/constants.rb for the guidelines and
7# rationale for the structure and organization of these specs.
8
9describe "Literal (A::X) constant resolution" do
10  describe "with statically assigned constants" do
11    it "searches the immediate class or module scope first" do
12      ConstantSpecs::ClassA::CS_CONST10.should == :const10_10
13      ConstantSpecs::ModuleA::CS_CONST10.should == :const10_1
14      ConstantSpecs::ParentA::CS_CONST10.should == :const10_5
15      ConstantSpecs::ContainerA::CS_CONST10.should == :const10_2
16      ConstantSpecs::ContainerA::ChildA::CS_CONST10.should == :const10_3
17    end
18
19    it "searches a module included in the immediate class before the superclass" do
20      ConstantSpecs::ContainerA::ChildA::CS_CONST15.should == :const15_1
21    end
22
23    it "searches the superclass before a module included in the superclass" do
24      ConstantSpecs::ContainerA::ChildA::CS_CONST11.should == :const11_1
25    end
26
27    it "searches a module included in the superclass" do
28      ConstantSpecs::ContainerA::ChildA::CS_CONST12.should == :const12_1
29    end
30
31    it "searches the superclass chain" do
32      ConstantSpecs::ContainerA::ChildA::CS_CONST13.should == :const13
33    end
34
35    it "searches Object if no class or module qualifier is given" do
36      CS_CONST1.should == :const1
37      CS_CONST10.should == :const10_1
38    end
39
40    it "searches Object after searching other scopes" do
41      module ConstantSpecs::SpecAdded1
42        CS_CONST10.should == :const10_1
43      end
44    end
45
46    it "searches Object if a toplevel qualifier (::X) is given" do
47      ::CS_CONST1.should == :const1
48      ::CS_CONST10.should == :const10_1
49    end
50
51    it "does not search the singleton class of the class or module" do
52      lambda do
53        ConstantSpecs::ContainerA::ChildA::CS_CONST14
54      end.should raise_error(NameError)
55      lambda { ConstantSpecs::CS_CONST14 }.should raise_error(NameError)
56    end
57  end
58
59  describe "with dynamically assigned constants" do
60    it "searches the immediate class or module scope first" do
61      ConstantSpecs::ClassB::CS_CONST101 = :const101_1
62      ConstantSpecs::ClassB::CS_CONST101.should == :const101_1
63
64      ConstantSpecs::ParentB::CS_CONST101 = :const101_2
65      ConstantSpecs::ParentB::CS_CONST101.should == :const101_2
66
67      ConstantSpecs::ContainerB::CS_CONST101 = :const101_3
68      ConstantSpecs::ContainerB::CS_CONST101.should == :const101_3
69
70      ConstantSpecs::ContainerB::ChildB::CS_CONST101 = :const101_4
71      ConstantSpecs::ContainerB::ChildB::CS_CONST101.should == :const101_4
72
73      ConstantSpecs::ModuleA::CS_CONST101 = :const101_5
74      ConstantSpecs::ModuleA::CS_CONST101.should == :const101_5
75    end
76
77    it "searches a module included in the immediate class before the superclass" do
78      ConstantSpecs::ParentB::CS_CONST102 = :const102_1
79      ConstantSpecs::ModuleF::CS_CONST102 = :const102_2
80      ConstantSpecs::ContainerB::ChildB::CS_CONST102.should == :const102_2
81    end
82
83    it "searches the superclass before a module included in the superclass" do
84      ConstantSpecs::ModuleE::CS_CONST103 = :const103_1
85      ConstantSpecs::ParentB::CS_CONST103 = :const103_2
86      ConstantSpecs::ContainerB::ChildB::CS_CONST103.should == :const103_2
87    end
88
89    it "searches a module included in the superclass" do
90      ConstantSpecs::ModuleA::CS_CONST104 = :const104_1
91      ConstantSpecs::ModuleE::CS_CONST104 = :const104_2
92      ConstantSpecs::ContainerB::ChildB::CS_CONST104.should == :const104_2
93    end
94
95    it "searches the superclass chain" do
96      ConstantSpecs::ModuleA::CS_CONST105 = :const105
97      ConstantSpecs::ContainerB::ChildB::CS_CONST105.should == :const105
98    end
99
100    it "searches Object if no class or module qualifier is given" do
101      CS_CONST106 = :const106
102      CS_CONST106.should == :const106
103    end
104
105    it "searches Object if a toplevel qualifier (::X) is given" do
106      ::CS_CONST107 = :const107
107      ::CS_CONST107.should == :const107
108    end
109
110    it "does not search the singleton class of the class or module" do
111      class << ConstantSpecs::ContainerB::ChildB
112        CS_CONST108 = :const108_1
113      end
114
115      lambda do
116        ConstantSpecs::ContainerB::ChildB::CS_CONST108
117      end.should raise_error(NameError)
118
119      module ConstantSpecs
120        class << self
121          CS_CONST108 = :const108_2
122        end
123      end
124
125      lambda { ConstantSpecs::CS_CONST108 }.should raise_error(NameError)
126    end
127
128    it "returns the updated value when a constant is reassigned" do
129      ConstantSpecs::ClassB::CS_CONST109 = :const109_1
130      ConstantSpecs::ClassB::CS_CONST109.should == :const109_1
131
132      -> {
133        ConstantSpecs::ClassB::CS_CONST109 = :const109_2
134      }.should complain(/already initialized constant/)
135      ConstantSpecs::ClassB::CS_CONST109.should == :const109_2
136    end
137
138    it "evaluates the right hand side before evaluating a constant path" do
139      mod = Module.new
140
141      mod.module_eval <<-EOC
142        ConstantSpecsRHS::B = begin
143          module ConstantSpecsRHS; end
144
145          "hello"
146        end
147      EOC
148
149      mod::ConstantSpecsRHS::B.should == 'hello'
150    end
151  end
152
153  it "raises a NameError if no constant is defined in the search path" do
154    lambda { ConstantSpecs::ParentA::CS_CONSTX }.should raise_error(NameError)
155  end
156
157  it "sends #const_missing to the original class or module scope" do
158    ConstantSpecs::ClassA::CS_CONSTX.should == :CS_CONSTX
159  end
160
161  it "evaluates the qualifier" do
162    ConstantSpecs.get_const::CS_CONST2.should == :const2
163  end
164
165  it "raises a TypeError if a non-class or non-module qualifier is given" do
166    lambda { CS_CONST1::CS_CONST }.should raise_error(TypeError)
167    lambda { 1::CS_CONST         }.should raise_error(TypeError)
168    lambda { "mod"::CS_CONST     }.should raise_error(TypeError)
169    lambda { false::CS_CONST     }.should raise_error(TypeError)
170  end
171end
172
173describe "Constant resolution within methods" do
174  describe "with statically assigned constants" do
175    it "searches the immediate class or module scope first" do
176      ConstantSpecs::ClassA.const10.should == :const10_10
177      ConstantSpecs::ParentA.const10.should == :const10_5
178      ConstantSpecs::ContainerA.const10.should == :const10_2
179      ConstantSpecs::ContainerA::ChildA.const10.should == :const10_3
180
181      ConstantSpecs::ClassA.new.const10.should == :const10_10
182      ConstantSpecs::ParentA.new.const10.should == :const10_5
183      ConstantSpecs::ContainerA::ChildA.new.const10.should == :const10_3
184    end
185
186    it "searches a module included in the immediate class before the superclass" do
187      ConstantSpecs::ContainerA::ChildA.const15.should == :const15_1
188      ConstantSpecs::ContainerA::ChildA.new.const15.should == :const15_1
189    end
190
191    it "searches the superclass before a module included in the superclass" do
192      ConstantSpecs::ContainerA::ChildA.const11.should == :const11_1
193      ConstantSpecs::ContainerA::ChildA.new.const11.should == :const11_1
194    end
195
196    it "searches a module included in the superclass" do
197      ConstantSpecs::ContainerA::ChildA.const12.should == :const12_1
198      ConstantSpecs::ContainerA::ChildA.new.const12.should == :const12_1
199    end
200
201    it "searches the superclass chain" do
202      ConstantSpecs::ContainerA::ChildA.const13.should == :const13
203      ConstantSpecs::ContainerA::ChildA.new.const13.should == :const13
204    end
205
206    it "searches the lexical scope of the method not the receiver's immediate class" do
207      ConstantSpecs::ContainerA::ChildA.const19.should == :const19_1
208    end
209
210    it "searches the lexical scope of a singleton method" do
211      ConstantSpecs::CS_CONST18.const17.should == :const17_1
212    end
213
214    it "does not search the lexical scope of the caller" do
215      lambda { ConstantSpecs::ClassA.const16 }.should raise_error(NameError)
216    end
217
218    it "searches the lexical scope of a block" do
219      ConstantSpecs::ClassA.const22.should == :const22_1
220    end
221
222    it "searches Object as a lexical scope only if Object is explicitly opened" do
223      ConstantSpecs::ContainerA::ChildA.const20.should == :const20_1
224      ConstantSpecs::ContainerA::ChildA.const21.should == :const21_1
225    end
226
227    it "does not search the lexical scope of qualifying modules" do
228      lambda do
229        ConstantSpecs::ContainerA::ChildA.const23
230      end.should raise_error(NameError)
231    end
232  end
233
234  describe "with dynamically assigned constants" do
235    it "searches the immediate class or module scope first" do
236      ConstantSpecs::ModuleA::CS_CONST201 = :const201_1
237
238      class ConstantSpecs::ClassB; CS_CONST201 = :const201_2; end
239      ConstantSpecs::ParentB::CS_CONST201 = :const201_3
240      ConstantSpecs::ContainerB::CS_CONST201 = :const201_4
241      ConstantSpecs::ContainerB::ChildB::CS_CONST201 = :const201_5
242
243      ConstantSpecs::ClassB.const201.should == :const201_2
244      ConstantSpecs::ParentB.const201.should == :const201_3
245      ConstantSpecs::ContainerB.const201.should == :const201_4
246      ConstantSpecs::ContainerB::ChildB.const201.should == :const201_5
247
248      ConstantSpecs::ClassB.new.const201.should == :const201_2
249      ConstantSpecs::ParentB.new.const201.should == :const201_3
250      ConstantSpecs::ContainerB::ChildB.new.const201.should == :const201_5
251    end
252
253    it "searches a module included in the immediate class before the superclass" do
254      ConstantSpecs::ParentB::CS_CONST202 = :const202_2
255      ConstantSpecs::ContainerB::ChildB::CS_CONST202 = :const202_1
256
257      ConstantSpecs::ContainerB::ChildB.const202.should == :const202_1
258      ConstantSpecs::ContainerB::ChildB.new.const202.should == :const202_1
259    end
260
261    it "searches the superclass before a module included in the superclass" do
262      ConstantSpecs::ParentB::CS_CONST203 = :const203_1
263      ConstantSpecs::ModuleE::CS_CONST203 = :const203_2
264
265      ConstantSpecs::ContainerB::ChildB.const203.should == :const203_1
266      ConstantSpecs::ContainerB::ChildB.new.const203.should == :const203_1
267    end
268
269    it "searches a module included in the superclass" do
270      ConstantSpecs::ModuleA::CS_CONST204 = :const204_2
271      ConstantSpecs::ModuleE::CS_CONST204 = :const204_1
272
273      ConstantSpecs::ContainerB::ChildB.const204.should == :const204_1
274      ConstantSpecs::ContainerB::ChildB.new.const204.should == :const204_1
275    end
276
277    it "searches the superclass chain" do
278      ConstantSpecs::ModuleA::CS_CONST205 = :const205
279
280      ConstantSpecs::ContainerB::ChildB.const205.should == :const205
281      ConstantSpecs::ContainerB::ChildB.new.const205.should == :const205
282    end
283
284    it "searches the lexical scope of the method not the receiver's immediate class" do
285      ConstantSpecs::ContainerB::ChildB::CS_CONST206 = :const206_2
286      class ConstantSpecs::ContainerB::ChildB
287        class << self
288          CS_CONST206 = :const206_1
289        end
290      end
291
292      ConstantSpecs::ContainerB::ChildB.const206.should == :const206_1
293    end
294
295    it "searches the lexical scope of a singleton method" do
296      ConstantSpecs::CS_CONST207 = :const207_1
297      ConstantSpecs::ClassB::CS_CONST207 = :const207_2
298
299      ConstantSpecs::CS_CONST208.const207.should == :const207_1
300    end
301
302    it "does not search the lexical scope of the caller" do
303      ConstantSpecs::ClassB::CS_CONST209 = :const209
304
305      lambda { ConstantSpecs::ClassB.const209 }.should raise_error(NameError)
306    end
307
308    it "searches the lexical scope of a block" do
309      ConstantSpecs::ClassB::CS_CONST210 = :const210_1
310      ConstantSpecs::ParentB::CS_CONST210 = :const210_2
311
312      ConstantSpecs::ClassB.const210.should == :const210_1
313    end
314
315    it "searches Object as a lexical scope only if Object is explicitly opened" do
316      Object::CS_CONST211 = :const211_1
317      ConstantSpecs::ParentB::CS_CONST211 = :const211_2
318      ConstantSpecs::ContainerB::ChildB.const211.should == :const211_1
319
320      Object::CS_CONST212 = :const212_2
321      ConstantSpecs::ParentB::CS_CONST212 = :const212_1
322      ConstantSpecs::ContainerB::ChildB.const212.should == :const212_1
323    end
324
325    it "returns the updated value when a constant is reassigned" do
326      ConstantSpecs::ParentB::CS_CONST213 = :const213_1
327      ConstantSpecs::ContainerB::ChildB.const213.should == :const213_1
328      ConstantSpecs::ContainerB::ChildB.new.const213.should == :const213_1
329
330      -> {
331        ConstantSpecs::ParentB::CS_CONST213 = :const213_2
332      }.should complain(/already initialized constant/)
333      ConstantSpecs::ContainerB::ChildB.const213.should == :const213_2
334      ConstantSpecs::ContainerB::ChildB.new.const213.should == :const213_2
335    end
336
337    it "does not search the lexical scope of qualifying modules" do
338      ConstantSpecs::ContainerB::CS_CONST214 = :const214
339
340      lambda do
341        ConstantSpecs::ContainerB::ChildB.const214
342      end.should raise_error(NameError)
343    end
344  end
345
346  it "raises a NameError if no constant is defined in the search path" do
347    lambda { ConstantSpecs::ParentA.constx }.should raise_error(NameError)
348  end
349
350  it "sends #const_missing to the original class or module scope" do
351    ConstantSpecs::ClassA.constx.should == :CS_CONSTX
352    ConstantSpecs::ClassA.new.constx.should == :CS_CONSTX
353  end
354
355  describe "with ||=" do
356    it "assigns a scoped constant if previously undefined" do
357      ConstantSpecs.should_not have_constant(:OpAssignUndefined)
358      module ConstantSpecs
359        OpAssignUndefined ||= 42
360      end
361      ConstantSpecs::OpAssignUndefined.should == 42
362      ConstantSpecs::OpAssignUndefinedOutside ||= 42
363      ConstantSpecs::OpAssignUndefinedOutside.should == 42
364      ConstantSpecs.send(:remove_const, :OpAssignUndefined)
365      ConstantSpecs.send(:remove_const, :OpAssignUndefinedOutside)
366    end
367
368    it "assigns a global constant if previously undefined" do
369      OpAssignGlobalUndefined ||= 42
370      ::OpAssignGlobalUndefinedExplicitScope ||= 42
371      OpAssignGlobalUndefined.should == 42
372      ::OpAssignGlobalUndefinedExplicitScope.should == 42
373      Object.send :remove_const, :OpAssignGlobalUndefined
374      Object.send :remove_const, :OpAssignGlobalUndefinedExplicitScope
375    end
376
377  end
378
379  describe "with &&=" do
380    it "re-assigns a scoped constant if already true" do
381      module ConstantSpecs
382        OpAssignTrue = true
383      end
384      suppress_warning do
385        ConstantSpecs::OpAssignTrue &&= 1
386      end
387      ConstantSpecs::OpAssignTrue.should == 1
388      ConstantSpecs.send :remove_const, :OpAssignTrue
389    end
390
391    it "leaves scoped constant if not true" do
392      module ConstantSpecs
393        OpAssignFalse = false
394      end
395      ConstantSpecs::OpAssignFalse &&= 1
396      ConstantSpecs::OpAssignFalse.should == false
397      ConstantSpecs.send :remove_const, :OpAssignFalse
398    end
399  end
400end
401
402describe "Constant resolution within a singleton class (class << obj)" do
403  it "works like normal classes or modules" do
404    ConstantSpecs::CS_SINGLETON1.foo.should == 1
405  end
406
407  it "uses its own namespace for each object" do
408    a = ConstantSpecs::CS_SINGLETON2[0].foo
409    b = ConstantSpecs::CS_SINGLETON2[1].foo
410    [a, b].should == [1, 2]
411  end
412
413  it "uses its own namespace for nested modules" do
414    a = ConstantSpecs::CS_SINGLETON3[0].x
415    b = ConstantSpecs::CS_SINGLETON3[1].x
416    a.should_not equal(b)
417  end
418
419  it "allows nested modules to have proper resolution" do
420    a = ConstantSpecs::CS_SINGLETON4_CLASSES[0].new
421    b = ConstantSpecs::CS_SINGLETON4_CLASSES[1].new
422    [a.foo, b.foo].should == [1, 2]
423  end
424end
425
426describe "top-level constant lookup" do
427  context "on a class" do
428    ruby_version_is "" ... "2.5" do
429      it "searches Object successfully after searching other scopes" do
430        ->() {
431          String::Hash.should == Hash
432        }.should complain(/toplevel constant Hash referenced by/)
433      end
434    end
435
436    ruby_version_is "2.5" do
437      it "does not search Object after searching other scopes" do
438        ->() { String::Hash }.should raise_error(NameError)
439      end
440    end
441  end
442
443  it "searches Object unsuccessfully when searches on a module" do
444    ->() { Enumerable::Hash }.should raise_error(NameError)
445  end
446end
447
448describe "Module#private_constant marked constants" do
449
450  it "remain private even when updated" do
451    mod = Module.new
452    mod.const_set :Foo, true
453    mod.send :private_constant, :Foo
454    -> {
455      mod.const_set :Foo, false
456    }.should complain(/already initialized constant/)
457
458    lambda {mod::Foo}.should raise_error(NameError)
459  end
460
461  ruby_version_is "2.6" do
462    it "sends #const_missing to the original class or module" do
463      mod = Module.new
464      mod.const_set :Foo, true
465      mod.send :private_constant, :Foo
466      def mod.const_missing(name)
467        name == :Foo ? name : super
468      end
469
470      mod::Foo.should == :Foo
471    end
472  end
473
474  describe "in a module" do
475    it "cannot be accessed from outside the module" do
476      lambda do
477        ConstantVisibility::PrivConstModule::PRIVATE_CONSTANT_MODULE
478      end.should raise_error(NameError)
479    end
480
481    it "cannot be reopened as a module from scope where constant would be private" do
482      lambda do
483        module ConstantVisibility::ModuleContainer::PrivateModule; end
484      end.should raise_error(NameError)
485    end
486
487    it "cannot be reopened as a class from scope where constant would be private" do
488      lambda do
489        class ConstantVisibility::ModuleContainer::PrivateClass; end
490      end.should raise_error(NameError)
491    end
492
493    it "can be reopened as a module where constant is not private" do
494      module ::ConstantVisibility::ModuleContainer
495        module PrivateModule
496          X = 1
497        end
498
499        PrivateModule::X.should == 1
500      end
501    end
502
503    it "can be reopened as a class where constant is not private" do
504      module ::ConstantVisibility::ModuleContainer
505        class PrivateClass
506          X = 1
507        end
508
509        PrivateClass::X.should == 1
510      end
511    end
512
513    it "is not defined? with A::B form" do
514      defined?(ConstantVisibility::PrivConstModule::PRIVATE_CONSTANT_MODULE).should == nil
515    end
516
517    it "can be accessed from the module itself" do
518      ConstantVisibility::PrivConstModule.private_constant_from_self.should be_true
519    end
520
521    it "is defined? from the module itself" do
522      ConstantVisibility::PrivConstModule.defined_from_self.should == "constant"
523    end
524
525    it "can be accessed from lexical scope" do
526      ConstantVisibility::PrivConstModule::Nested.private_constant_from_scope.should be_true
527    end
528
529    it "is defined? from lexical scope" do
530      ConstantVisibility::PrivConstModule::Nested.defined_from_scope.should == "constant"
531    end
532
533    it "can be accessed from classes that include the module" do
534      ConstantVisibility::PrivConstModuleChild.new.private_constant_from_include.should be_true
535    end
536
537    it "is defined? from classes that include the module" do
538      ConstantVisibility::PrivConstModuleChild.new.defined_from_include.should == "constant"
539    end
540  end
541
542  describe "in a class" do
543    it "cannot be accessed from outside the class" do
544      lambda do
545        ConstantVisibility::PrivConstClass::PRIVATE_CONSTANT_CLASS
546      end.should raise_error(NameError)
547    end
548
549    it "cannot be reopened as a module" do
550      lambda do
551        module ConstantVisibility::ClassContainer::PrivateModule; end
552      end.should raise_error(NameError)
553    end
554
555    it "cannot be reopened as a class" do
556      lambda do
557        class ConstantVisibility::ClassContainer::PrivateClass; end
558      end.should raise_error(NameError)
559    end
560
561    it "can be reopened as a module where constant is not private" do
562      class ::ConstantVisibility::ClassContainer
563        module PrivateModule
564          X = 1
565        end
566
567        PrivateModule::X.should == 1
568      end
569    end
570
571    it "can be reopened as a class where constant is not private" do
572      class ::ConstantVisibility::ClassContainer
573        class PrivateClass
574          X = 1
575        end
576
577        PrivateClass::X.should == 1
578      end
579    end
580
581    it "is not defined? with A::B form" do
582      defined?(ConstantVisibility::PrivConstClass::PRIVATE_CONSTANT_CLASS).should == nil
583    end
584
585    it "can be accessed from the class itself" do
586      ConstantVisibility::PrivConstClass.private_constant_from_self.should be_true
587    end
588
589    it "is defined? from the class itself" do
590      ConstantVisibility::PrivConstClass.defined_from_self.should == "constant"
591    end
592
593    it "can be accessed from lexical scope" do
594      ConstantVisibility::PrivConstClass::Nested.private_constant_from_scope.should be_true
595    end
596
597    it "is defined? from lexical scope" do
598      ConstantVisibility::PrivConstClass::Nested.defined_from_scope.should == "constant"
599    end
600
601    it "can be accessed from subclasses" do
602      ConstantVisibility::PrivConstClassChild.new.private_constant_from_subclass.should be_true
603    end
604
605    it "is defined? from subclasses" do
606      ConstantVisibility::PrivConstClassChild.new.defined_from_subclass.should == "constant"
607    end
608  end
609
610  describe "in Object" do
611    it "cannot be accessed using ::Const form" do
612      lambda do
613        ::PRIVATE_CONSTANT_IN_OBJECT
614      end.should raise_error(NameError)
615    end
616
617    it "is not defined? using ::Const form" do
618      defined?(::PRIVATE_CONSTANT_IN_OBJECT).should == nil
619    end
620
621    it "can be accessed through the normal search" do
622      PRIVATE_CONSTANT_IN_OBJECT.should == true
623    end
624
625    it "is defined? through the normal search" do
626      defined?(PRIVATE_CONSTANT_IN_OBJECT).should == "constant"
627    end
628  end
629
630  describe "NameError by #private_constant" do
631    it "has :receiver and :name attributes" do
632      lambda do
633        ConstantVisibility::PrivConstClass::PRIVATE_CONSTANT_CLASS
634      end.should raise_error(NameError) {|e|
635        e.receiver.should == ConstantVisibility::PrivConstClass
636        e.name.should == :PRIVATE_CONSTANT_CLASS
637      }
638
639      lambda do
640        ConstantVisibility::PrivConstModule::PRIVATE_CONSTANT_MODULE
641      end.should raise_error(NameError) {|e|
642        e.receiver.should == ConstantVisibility::PrivConstModule
643        e.name.should == :PRIVATE_CONSTANT_MODULE
644      }
645    end
646
647    it "has the defined class as the :name attribute" do
648      lambda do
649        ConstantVisibility::PrivConstClassChild::PRIVATE_CONSTANT_CLASS
650      end.should raise_error(NameError) {|e|
651        e.receiver.should == ConstantVisibility::PrivConstClass
652        e.name.should == :PRIVATE_CONSTANT_CLASS
653      }
654
655      lambda do
656        ConstantVisibility::PrivConstModuleChild::PRIVATE_CONSTANT_MODULE
657      end.should raise_error(NameError) {|e|
658        ruby_bug "#14853", ""..."2.5.2" do
659          e.receiver.should == ConstantVisibility::PrivConstModule
660        end
661        e.name.should == :PRIVATE_CONSTANT_MODULE
662      }
663    end
664  end
665end
666
667describe "Module#public_constant marked constants" do
668  before :each do
669    @module = ConstantVisibility::PrivConstModule.dup
670  end
671
672  describe "in a module" do
673    it "can be accessed from outside the module" do
674      @module.send :public_constant, :PRIVATE_CONSTANT_MODULE
675      @module::PRIVATE_CONSTANT_MODULE.should == true
676    end
677
678    it "is defined? with A::B form" do
679      @module.send :public_constant, :PRIVATE_CONSTANT_MODULE
680      defined?(@module::PRIVATE_CONSTANT_MODULE).should == "constant"
681    end
682  end
683
684  describe "in a class" do
685    before :each do
686      @class = ConstantVisibility::PrivConstClass.dup
687    end
688
689    it "can be accessed from outside the class" do
690      @class.send :public_constant, :PRIVATE_CONSTANT_CLASS
691      @class::PRIVATE_CONSTANT_CLASS.should == true
692    end
693
694    it "is defined? with A::B form" do
695      @class.send :public_constant, :PRIVATE_CONSTANT_CLASS
696      defined?(@class::PRIVATE_CONSTANT_CLASS).should == "constant"
697    end
698  end
699
700  describe "in Object" do
701    after :each do
702      ConstantVisibility.reset_private_constants
703    end
704
705    it "can be accessed using ::Const form" do
706      Object.send :public_constant, :PRIVATE_CONSTANT_IN_OBJECT
707      ::PRIVATE_CONSTANT_IN_OBJECT.should == true
708    end
709
710    it "is defined? using ::Const form" do
711      Object.send :public_constant, :PRIVATE_CONSTANT_IN_OBJECT
712      defined?(::PRIVATE_CONSTANT_IN_OBJECT).should == "constant"
713    end
714  end
715end
716