1require 'test/unit' 2require_relative 'envutil' 3 4# to supress warnings for future calls of Module#refine 5EnvUtil.suppress_warning do 6 Module.new { 7 refine(Object) {} 8 } 9end 10 11class TestRefinement < Test::Unit::TestCase 12 class Foo 13 def x 14 return "Foo#x" 15 end 16 17 def y 18 return "Foo#y" 19 end 20 21 def a 22 return "Foo#a" 23 end 24 25 def call_x 26 return x 27 end 28 end 29 30 module FooExt 31 refine Foo do 32 def x 33 return "FooExt#x" 34 end 35 36 def y 37 return "FooExt#y " + super 38 end 39 40 def z 41 return "FooExt#z" 42 end 43 44 def a 45 return "FooExt#a" 46 end 47 end 48 end 49 50 module FooExt2 51 refine Foo do 52 def x 53 return "FooExt2#x" 54 end 55 56 def y 57 return "FooExt2#y " + super 58 end 59 60 def z 61 return "FooExt2#z" 62 end 63 end 64 end 65 66 class FooSub < Foo 67 def x 68 return "FooSub#x" 69 end 70 71 def y 72 return "FooSub#y " + super 73 end 74 end 75 76 eval <<-EOF, TOPLEVEL_BINDING 77 using TestRefinement::FooExt 78 79 class TestRefinement::FooExtClient 80 def self.invoke_x_on(foo) 81 return foo.x 82 end 83 84 def self.invoke_y_on(foo) 85 return foo.y 86 end 87 88 def self.invoke_z_on(foo) 89 return foo.z 90 end 91 92 def self.send_z_on(foo) 93 return foo.send(:z) 94 end 95 96 def self.method_z(foo) 97 return foo.method(:z) 98 end 99 100 def self.invoke_call_x_on(foo) 101 return foo.call_x 102 end 103 end 104 EOF 105 106 eval <<-EOF, TOPLEVEL_BINDING 107 using TestRefinement::FooExt 108 using TestRefinement::FooExt2 109 110 class TestRefinement::FooExtClient2 111 def self.invoke_y_on(foo) 112 return foo.y 113 end 114 115 def self.invoke_a_on(foo) 116 return foo.a 117 end 118 end 119 EOF 120 121 def test_override 122 foo = Foo.new 123 assert_equal("Foo#x", foo.x) 124 assert_equal("FooExt#x", FooExtClient.invoke_x_on(foo)) 125 assert_equal("Foo#x", foo.x) 126 end 127 128 def test_super 129 foo = Foo.new 130 assert_equal("Foo#y", foo.y) 131 assert_equal("FooExt#y Foo#y", FooExtClient.invoke_y_on(foo)) 132 assert_equal("Foo#y", foo.y) 133 end 134 135 def test_super_not_chained 136 foo = Foo.new 137 assert_equal("Foo#y", foo.y) 138 assert_equal("FooExt2#y Foo#y", FooExtClient2.invoke_y_on(foo)) 139 assert_equal("Foo#y", foo.y) 140 end 141 142 def test_using_same_class_refinements 143 foo = Foo.new 144 assert_equal("Foo#a", foo.a) 145 assert_equal("FooExt#a", FooExtClient2.invoke_a_on(foo)) 146 assert_equal("Foo#a", foo.a) 147 end 148 149 def test_new_method 150 foo = Foo.new 151 assert_raise(NoMethodError) { foo.z } 152 assert_equal("FooExt#z", FooExtClient.invoke_z_on(foo)) 153 assert_raise(NoMethodError) { foo.z } 154 end 155 156 module RespondTo 157 class Super 158 def foo 159 end 160 end 161 162 class Sub < Super 163 end 164 165 module M 166 refine Sub do 167 def foo 168 end 169 end 170 end 171 end 172 173 def test_send_should_not_use_refinements 174 foo = Foo.new 175 assert_raise(NoMethodError) { foo.send(:z) } 176 assert_raise(NoMethodError) { FooExtClient.send_z_on(foo) } 177 assert_raise(NoMethodError) { foo.send(:z) } 178 179 assert_equal(true, RespondTo::Sub.new.respond_to?(:foo)) 180 end 181 182 def test_method_should_not_use_refinements 183 foo = Foo.new 184 assert_raise(NameError) { foo.method(:z) } 185 assert_raise(NameError) { FooExtClient.method_z(foo) } 186 assert_raise(NameError) { foo.method(:z) } 187 end 188 189 def test_no_local_rebinding 190 foo = Foo.new 191 assert_equal("Foo#x", foo.call_x) 192 assert_equal("Foo#x", FooExtClient.invoke_call_x_on(foo)) 193 assert_equal("Foo#x", foo.call_x) 194 end 195 196 def test_subclass_is_prior 197 sub = FooSub.new 198 assert_equal("FooSub#x", sub.x) 199 assert_equal("FooSub#x", FooExtClient.invoke_x_on(sub)) 200 assert_equal("FooSub#x", sub.x) 201 end 202 203 def test_super_in_subclass 204 sub = FooSub.new 205 assert_equal("FooSub#y Foo#y", sub.y) 206 # not "FooSub#y FooExt#y Foo#y" 207 assert_equal("FooSub#y Foo#y", FooExtClient.invoke_y_on(sub)) 208 assert_equal("FooSub#y Foo#y", sub.y) 209 end 210 211 def test_new_method_on_subclass 212 sub = FooSub.new 213 assert_raise(NoMethodError) { sub.z } 214 assert_equal("FooExt#z", FooExtClient.invoke_z_on(sub)) 215 assert_raise(NoMethodError) { sub.z } 216 end 217 218 def test_module_eval 219 foo = Foo.new 220 assert_equal("Foo#x", foo.x) 221 assert_equal("Foo#x", FooExt.module_eval { foo.x }) 222 assert_equal("Foo#x", FooExt.module_eval("foo.x")) 223 assert_equal("Foo#x", foo.x) 224 end 225 226 def test_instance_eval_without_refinement 227 foo = Foo.new 228 ext_client = FooExtClient.new 229 assert_equal("Foo#x", foo.x) 230 assert_equal("Foo#x", ext_client.instance_eval { foo.x }) 231 assert_equal("Foo#x", foo.x) 232 end 233 234 module FixnumSlashExt 235 refine Fixnum do 236 def /(other) quo(other) end 237 end 238 end 239 240 def test_override_builtin_method 241 assert_equal(0, 1 / 2) 242 assert_equal(Rational(1, 2), eval_using(FixnumSlashExt, "1 / 2")) 243 assert_equal(0, 1 / 2) 244 end 245 246 module FixnumPlusExt 247 refine Fixnum do 248 def self.method_added(*args); end 249 def +(other) "overriden" end 250 end 251 end 252 253 def test_override_builtin_method_with_method_added 254 assert_equal(3, 1 + 2) 255 assert_equal("overriden", eval_using(FixnumPlusExt, "1 + 2")) 256 assert_equal(3, 1 + 2) 257 end 258 259 def test_return_value_of_refine 260 mod = nil 261 result = nil 262 m = Module.new { 263 result = refine(Object) { 264 mod = self 265 } 266 } 267 assert_equal mod, result 268 end 269 270 module RefineSameClass 271 REFINEMENT1 = refine(Fixnum) { 272 def foo; return "foo" end 273 } 274 REFINEMENT2 = refine(Fixnum) { 275 def bar; return "bar" end 276 } 277 REFINEMENT3 = refine(String) { 278 def baz; return "baz" end 279 } 280 end 281 282 def test_refine_same_class_twice 283 assert_equal("foo", eval_using(RefineSameClass, "1.foo")) 284 assert_equal("bar", eval_using(RefineSameClass, "1.bar")) 285 assert_equal(RefineSameClass::REFINEMENT1, RefineSameClass::REFINEMENT2) 286 assert_not_equal(RefineSameClass::REFINEMENT1, RefineSameClass::REFINEMENT3) 287 end 288 289 module FixnumFooExt 290 refine Fixnum do 291 def foo; "foo"; end 292 end 293 end 294 295 def test_respond_to_should_not_use_refinements 296 assert_equal(false, 1.respond_to?(:foo)) 297 assert_equal(false, eval_using(FixnumFooExt, "1.respond_to?(:foo)")) 298 end 299 300 module StringCmpExt 301 refine String do 302 def <=>(other) return 0 end 303 end 304 end 305 306 module ArrayEachExt 307 refine Array do 308 def each 309 super do |i| 310 yield 2 * i 311 end 312 end 313 end 314 end 315 316 def test_builtin_method_no_local_rebinding 317 assert_equal(false, eval_using(StringCmpExt, '"1" >= "2"')) 318 assert_equal(1, eval_using(ArrayEachExt, "[1, 2, 3].min")) 319 end 320 321 module RefinePrependedClass 322 module M1 323 def foo 324 super << :m1 325 end 326 end 327 328 class C 329 prepend M1 330 331 def foo 332 [:c] 333 end 334 end 335 336 module M2 337 refine C do 338 def foo 339 super << :m2 340 end 341 end 342 end 343 end 344 345 def test_refine_prepended_class 346 x = eval_using(RefinePrependedClass::M2, 347 "TestRefinement::RefinePrependedClass::C.new.foo") 348 assert_equal([:c, :m1, :m2], x) 349 end 350 351 def test_refine_module 352 m1 = Module.new 353 assert_raise(TypeError) do 354 Module.new { 355 refine m1 do 356 def foo 357 :m2 358 end 359 end 360 } 361 end 362 end 363 364 def test_refine_neither_class_nor_module 365 assert_raise(TypeError) do 366 Module.new { 367 refine Object.new do 368 end 369 } 370 end 371 assert_raise(TypeError) do 372 Module.new { 373 refine 123 do 374 end 375 } 376 end 377 assert_raise(TypeError) do 378 Module.new { 379 refine "foo" do 380 end 381 } 382 end 383 end 384 385 def test_refine_in_class 386 assert_raise(NoMethodError) do 387 Class.new { 388 refine Fixnum do 389 def foo 390 "c" 391 end 392 end 393 } 394 end 395 end 396 397 def test_main_using 398 assert_in_out_err([], <<-INPUT, %w(:C :M), /Refinements are experimental/) 399 class C 400 def foo 401 :C 402 end 403 end 404 405 module M 406 refine C do 407 def foo 408 :M 409 end 410 end 411 end 412 413 c = C.new 414 p c.foo 415 using M 416 p c.foo 417 INPUT 418 end 419 420 def test_main_using_is_private 421 assert_raise(NoMethodError) do 422 eval("self.using Module.new", TOPLEVEL_BINDING) 423 end 424 end 425 426 def test_no_kernel_using 427 assert_raise(NoMethodError) do 428 using Module.new 429 end 430 end 431 432 def test_no_module_using 433 assert_raise(NoMethodError) do 434 Module.new { 435 using Module.new 436 } 437 end 438 end 439 440 class UsingClass 441 end 442 443 def test_module_using_class 444 c = Class.new 445 assert_raise(TypeError) do 446 eval("using TestRefinement::UsingClass", TOPLEVEL_BINDING) 447 end 448 end 449 450 def test_refine_without_block 451 c1 = Class.new 452 e = assert_raise(ArgumentError) { 453 Module.new do 454 refine c1 455 end 456 } 457 assert_equal("no block given", e.message) 458 end 459 460 module Inspect 461 module M 462 Fixnum = refine(Fixnum) {} 463 end 464 end 465 466 def test_inspect 467 assert_equal("#<refinement:Fixnum@TestRefinement::Inspect::M>", 468 Inspect::M::Fixnum.inspect) 469 end 470 471 def test_using_method_cache 472 assert_in_out_err([], <<-INPUT, %w(:M1 :M2), /Refinements are experimental/) 473 class C 474 def foo 475 "original" 476 end 477 end 478 479 module M1 480 refine C do 481 def foo 482 :M1 483 end 484 end 485 end 486 487 module M2 488 refine C do 489 def foo 490 :M2 491 end 492 end 493 end 494 495 c = C.new 496 using M1 497 p c.foo 498 using M2 499 p c.foo 500 INPUT 501 end 502 503 module RedefineRefinedMethod 504 class C 505 def foo 506 "original" 507 end 508 end 509 510 module M 511 refine C do 512 def foo 513 "refined" 514 end 515 end 516 end 517 518 class C 519 def foo 520 "redefined" 521 end 522 end 523 end 524 525 def test_redefine_refined_method 526 x = eval_using(RedefineRefinedMethod::M, 527 "TestRefinement::RedefineRefinedMethod::C.new.foo") 528 assert_equal("refined", x) 529 end 530 531 module StringExt 532 refine String do 533 def foo 534 "foo" 535 end 536 end 537 end 538 539 module RefineScoping 540 refine String do 541 def foo 542 "foo" 543 end 544 545 def RefineScoping.call_in_refine_block 546 "".foo 547 end 548 end 549 550 def self.call_outside_refine_block 551 "".foo 552 end 553 end 554 555 def test_refine_scoping 556 assert_equal("foo", RefineScoping.call_in_refine_block) 557 assert_raise(NoMethodError) do 558 RefineScoping.call_outside_refine_block 559 end 560 end 561 562 module StringRecursiveLength 563 refine String do 564 def recursive_length 565 if empty? 566 0 567 else 568 self[1..-1].recursive_length + 1 569 end 570 end 571 end 572 end 573 574 def test_refine_recursion 575 x = eval_using(StringRecursiveLength, "'foo'.recursive_length") 576 assert_equal(3, x) 577 end 578 579 module ToJSON 580 refine Integer do 581 def to_json; to_s; end 582 end 583 584 refine Array do 585 def to_json; "[" + map { |i| i.to_json }.join(",") + "]" end 586 end 587 588 refine Hash do 589 def to_json; "{" + map { |k, v| k.to_s.dump + ":" + v.to_json }.join(",") + "}" end 590 end 591 end 592 593 def test_refine_mutual_recursion 594 x = eval_using(ToJSON, "[{1=>2}, {3=>4}].to_json") 595 assert_equal('[{"1":2},{"3":4}]', x) 596 end 597 598 def test_refine_with_proc 599 assert_raise(ArgumentError) do 600 Module.new { 601 refine(String, &Proc.new {}) 602 } 603 end 604 end 605 606 def test_using_in_module 607 assert_raise(RuntimeError) do 608 eval(<<-EOF, TOPLEVEL_BINDING) 609 $main = self 610 module M 611 end 612 module M2 613 $main.send(:using, M) 614 end 615 EOF 616 end 617 end 618 619 def test_using_in_method 620 assert_raise(RuntimeError) do 621 eval(<<-EOF, TOPLEVEL_BINDING) 622 $main = self 623 module M 624 end 625 def call_using_in_method 626 $main.send(:using, M) 627 end 628 call_using_in_method 629 EOF 630 end 631 end 632 633 module IncludeIntoRefinement 634 class C 635 def bar 636 return "C#bar" 637 end 638 639 def baz 640 return "C#baz" 641 end 642 end 643 644 module Mixin 645 def foo 646 return "Mixin#foo" 647 end 648 649 def bar 650 return super << " Mixin#bar" 651 end 652 653 def baz 654 return super << " Mixin#baz" 655 end 656 end 657 658 module M 659 refine C do 660 include Mixin 661 662 def baz 663 return super << " M#baz" 664 end 665 end 666 end 667 end 668 669 eval <<-EOF, TOPLEVEL_BINDING 670 using TestRefinement::IncludeIntoRefinement::M 671 672 module TestRefinement::IncludeIntoRefinement::User 673 def self.invoke_foo_on(x) 674 x.foo 675 end 676 677 def self.invoke_bar_on(x) 678 x.bar 679 end 680 681 def self.invoke_baz_on(x) 682 x.baz 683 end 684 end 685 EOF 686 687 def test_include_into_refinement 688 x = IncludeIntoRefinement::C.new 689 assert_equal("Mixin#foo", IncludeIntoRefinement::User.invoke_foo_on(x)) 690 assert_equal("C#bar Mixin#bar", 691 IncludeIntoRefinement::User.invoke_bar_on(x)) 692 assert_equal("C#baz Mixin#baz M#baz", 693 IncludeIntoRefinement::User.invoke_baz_on(x)) 694 end 695 696 module PrependIntoRefinement 697 class C 698 def bar 699 return "C#bar" 700 end 701 702 def baz 703 return "C#baz" 704 end 705 end 706 707 module Mixin 708 def foo 709 return "Mixin#foo" 710 end 711 712 def bar 713 return super << " Mixin#bar" 714 end 715 716 def baz 717 return super << " Mixin#baz" 718 end 719 end 720 721 module M 722 refine C do 723 prepend Mixin 724 725 def baz 726 return super << " M#baz" 727 end 728 end 729 end 730 end 731 732 eval <<-EOF, TOPLEVEL_BINDING 733 using TestRefinement::PrependIntoRefinement::M 734 735 module TestRefinement::PrependIntoRefinement::User 736 def self.invoke_foo_on(x) 737 x.foo 738 end 739 740 def self.invoke_bar_on(x) 741 x.bar 742 end 743 744 def self.invoke_baz_on(x) 745 x.baz 746 end 747 end 748 EOF 749 750 def test_prepend_into_refinement 751 x = PrependIntoRefinement::C.new 752 assert_equal("Mixin#foo", PrependIntoRefinement::User.invoke_foo_on(x)) 753 assert_equal("C#bar Mixin#bar", 754 PrependIntoRefinement::User.invoke_bar_on(x)) 755 assert_equal("C#baz M#baz Mixin#baz", 756 PrependIntoRefinement::User.invoke_baz_on(x)) 757 end 758 759 module PrependAfterRefine 760 class C 761 def foo 762 "original" 763 end 764 end 765 766 module M 767 refine C do 768 def foo 769 "refined" 770 end 771 772 def bar 773 "refined" 774 end 775 end 776 end 777 778 module Mixin 779 def foo 780 "mixin" 781 end 782 783 def bar 784 "mixin" 785 end 786 end 787 788 class C 789 prepend Mixin 790 end 791 end 792 793 def test_prepend_after_refine 794 x = eval_using(PrependAfterRefine::M, 795 "TestRefinement::PrependAfterRefine::C.new.foo") 796 assert_equal("refined", x) 797 assert_equal("mixin", TestRefinement::PrependAfterRefine::C.new.foo) 798 y = eval_using(PrependAfterRefine::M, 799 "TestRefinement::PrependAfterRefine::C.new.bar") 800 assert_equal("refined", y) 801 assert_equal("mixin", TestRefinement::PrependAfterRefine::C.new.bar) 802 end 803 804 module SuperInBlock 805 class C 806 def foo(*args) 807 [:foo, *args] 808 end 809 end 810 811 module R 812 refine C do 813 def foo(*args) 814 tap do 815 return super(:ref, *args) 816 end 817 end 818 end 819 end 820 end 821 822 def test_super_in_block 823 bug7925 = '[ruby-core:52750] [Bug #7925]' 824 x = eval_using(SuperInBlock::R, 825 "TestRefinement:: SuperInBlock::C.new.foo(#{bug7925.dump})") 826 assert_equal([:foo, :ref, bug7925], x, bug7925) 827 end 828 829 def test_case_dispatch_is_aware_of_refinements 830 assert_in_out_err([], <<-RUBY, ["refinement used"], []) 831 $VERBOSE = nil #to suppress warning "Refinements are experimental, ..." 832 module RefineSymbol 833 refine Symbol do 834 def ===(other) 835 true 836 end 837 end 838 end 839 840 using RefineSymbol 841 842 case :a 843 when :b 844 puts "refinement used" 845 else 846 puts "refinement not used" 847 end 848 RUBY 849 end 850 851 def test_instance_methods 852 bug8881 = '[ruby-core:57080] [Bug #8881]' 853 assert_not_include(Foo.instance_methods(false), :z, bug8881) 854 assert_not_include(FooSub.instance_methods(true), :z, bug8881) 855 end 856 857 def test_method_defined 858 assert_not_send([Foo, :method_defined?, :z]) 859 assert_not_send([FooSub, :method_defined?, :z]) 860 end 861 862 def test_undef_refined_method 863 bug8966 = '[ruby-core:57466] [Bug #8966]' 864 865 assert_in_out_err([], <<-INPUT, ["NameError"], [], bug8966) 866 $VERBOSE = nil #to suppress warning "Refinements are experimental, ..." 867 module Foo 868 refine Object do 869 def foo 870 puts "foo" 871 end 872 end 873 end 874 875 using Foo 876 877 class Object 878 begin 879 undef foo 880 rescue Exception => e 881 p e.class 882 end 883 end 884 INPUT 885 886 assert_in_out_err([], <<-INPUT, ["NameError"], [], bug8966) 887 $VERBOSE = nil #to suppress warning "Refinements are experimental, ..." 888 module Foo 889 refine Object do 890 def foo 891 puts "foo" 892 end 893 end 894 end 895 896 # without `using Foo' 897 898 class Object 899 begin 900 undef foo 901 rescue Exception => e 902 p e.class 903 end 904 end 905 INPUT 906 end 907 908 def test_refine_undefed_method_and_call 909 assert_in_out_err([], <<-INPUT, ["NoMethodError"], []) 910 $VERBOSE = nil #to suppress warning "Refinements are experimental, ..." 911 class Foo 912 def foo 913 end 914 915 undef foo 916 end 917 918 module FooExt 919 refine Foo do 920 def foo 921 end 922 end 923 end 924 925 begin 926 Foo.new.foo 927 rescue => e 928 p e.class 929 end 930 INPUT 931 end 932 933 def test_refine_undefed_method_and_send 934 assert_in_out_err([], <<-INPUT, ["NoMethodError"], []) 935 $VERBOSE = nil #to suppress warning "Refinements are experimental, ..." 936 class Foo 937 def foo 938 end 939 940 undef foo 941 end 942 943 module FooExt 944 refine Foo do 945 def foo 946 end 947 end 948 end 949 950 begin 951 Foo.new.send(:foo) 952 rescue => e 953 p e.class 954 end 955 INPUT 956 end 957 958 def test_adding_private_method 959 bug9452 = '[ruby-core:60111] [Bug #9452]' 960 961 assert_in_out_err([], <<-INPUT, ["Success!", "NoMethodError"], [], bug9452) 962 $VERBOSE = nil #to suppress warning "Refinements are experimental, ..." 963 module R 964 refine Object do 965 def m 966 puts "Success!" 967 end 968 969 private(:m) 970 end 971 end 972 973 using R 974 975 m 976 42.m rescue p($!.class) 977 INPUT 978 end 979 980 def test_making_private_method_public 981 bug9452 = '[ruby-core:60111] [Bug #9452]' 982 983 assert_in_out_err([], <<-INPUT, ["Success!", "Success!"], [], bug9452) 984 $VERBOSE = nil #to suppress warning "Refinements are experimental, ..." 985 class Object 986 private 987 def m 988 end 989 end 990 991 module R 992 refine Object do 993 def m 994 puts "Success!" 995 end 996 end 997 end 998 999 using R 1000 m 1001 42.m 1002 INPUT 1003 end 1004 1005 private 1006 1007 def eval_using(mod, s) 1008 eval("using #{mod}; #{s}", TOPLEVEL_BINDING) 1009 end 1010end 1011