1# Copyright (c) 2006-2008, The RubyCocoa Project. 2# Copyright (c) 2001-2006, FUJIMOTO Hisakuni. 3# All Rights Reserved. 4# 5# RubyCocoa is free software, covered under either the Ruby's license or the 6# LGPL. See the COPYRIGHT file for more information. 7 8require 'osx/objc/oc_wrapper' 9 10OSX._ignore_ns_override = true 11 12module OSX 13 14 # Utility for private use 15 module RangeUtil 16 def self.normalize(range, count) 17 n = range.first 18 n += count if n < 0 19 last = range.last 20 last += count if last < 0 21 last += 1 unless range.exclude_end? 22 len = last - n 23 len = 0 if len < 0 24 len = count - n if count < n + len 25 [n, len, last] 26 end 27 end 28 29 # Enumerable module for NSValue types 30 module NSEnumerable 31 include Enumerable 32 33 def grep(pattern) 34 result = [] 35 if block_given? 36 each {|i| result << (yield i) if pattern === i } 37 else 38 each {|i| result << i if pattern === i } 39 end 40 result.to_ns 41 end 42 43 def map 44 result = [] 45 each {|i| result << (yield i) } 46 result.to_ns 47 end 48 alias_method :collect, :map 49 50 def select 51 result = [] 52 each {|i| result << i if yield i } 53 result.to_ns 54 end 55 alias_method :find_all, :select 56 57 def partition 58 selected = [] 59 others = [] 60 each do |i| 61 if yield i 62 selected << i 63 else 64 others << i 65 end 66 end 67 [selected, others].to_ns 68 end 69 70 def reject 71 result = [] 72 each {|i| result << i unless yield i } 73 result.to_ns 74 end 75 76 def sort(&block) 77 to_a.sort(&block).to_ns 78 end 79 80 def sort_by 81 map {|i| [(yield i), i]}.sort {|a,b| a[0] <=> b[0]}.map! {|i| i[1]} 82 end 83 84 def zip(*args) 85 if block_given? 86 each_with_index do |obj,n| 87 cur = [] 88 [self, *args].each {|i| cur << i[n] } 89 yield cur 90 end 91 nil 92 else 93 result = [] 94 each_with_index do |obj,n| 95 cur = [] 96 [self, *args].each {|i| cur << i[n] } 97 result << cur 98 end 99 result.to_ns 100 end 101 end 102 end 103 104 # NSString additions 105 class NSString 106 include OSX::OCObjWrapper 107 108 def dup 109 mutableCopy 110 end 111 112 def clone 113 obj = dup 114 obj.freeze if frozen? 115 obj.taint if tainted? 116 obj 117 end 118 119 # enable to treat as String 120 def to_str 121 self.to_s 122 end 123 124 # comparison between Ruby String and Cocoa NSString 125 def ==(other) 126 if other.is_a? OSX::NSString 127 isEqualToString?(other) 128 elsif other.respond_to? :to_str 129 self.to_s == other.to_str 130 else 131 false 132 end 133 end 134 135 def <=>(other) 136 if other.respond_to? :to_str 137 self.to_str <=> other.to_str 138 else 139 nil 140 end 141 end 142 143 def inspect 144 "#<#{self.class.to_s.gsub(/^OSX::/, '')} \"#{self.to_s}\">" 145 end 146 147 def hash 148 oc_hash 149 end 150 151 def pretty_print(q) 152 self.to_s.pretty_print(q) 153 end 154 155 # responds to Ruby String methods 156 alias_method :_rbobj_respond_to?, :respond_to? 157 def respond_to?(mname, private = false) 158 String.public_method_defined?(mname) or _rbobj_respond_to?(mname, private) 159 end 160 161 alias_method :objc_method_missing, :method_missing 162 def method_missing(mname, *args, &block) 163 if mname == :match || mname == :=~ 164 i = mname == :match ? 0 : 1 165 warn "#{caller[i]}: 'NSString##{mname}' doesn't work correctly. Because it returns byte indexes. Please use 'String##{mname}' instead." 166 end 167 168 ## TODO: should test "respondsToSelector:" 169 if String.public_method_defined?(mname) && (mname != :length) 170 # call as Ruby string 171 rcv = to_s 172 org_val = rcv.dup 173 result = rcv.send(mname, *args, &block) 174 if result.__id__ == rcv.__id__ 175 result = self 176 end 177 # bang methods modify receiver itself, need to set the new value. 178 # if the receiver is immutable, NSInvalidArgumentException raises. 179 if rcv != org_val 180 setString(rcv) 181 end 182 else 183 # call as objc string 184 result = objc_method_missing(mname, *args) 185 end 186 result 187 end 188 189 def =~(*args) 190 method_missing(:=~, *args) 191 end 192 193 # For NSString duck typing 194 195 def [](*args) 196 _read_impl(:[], args) 197 end 198 alias_method :slice, :[] 199 200 def []=(*args) 201 count = length 202 case args.length 203 when 2 204 first, second = args 205 case first 206 when Numeric,OSX::NSNumber 207 n = first.to_i 208 n += count if n < 0 209 if n < 0 || count <= n 210 raise IndexError, "index #{first.to_i} out of string" 211 end 212 self[n..n] = second 213 when String,OSX::NSString 214 str = first 215 str = str.to_ns if str.is_a?(String) 216 n = index(str) 217 unless n 218 raise IndexError, "string not matched" 219 end 220 self[n...n+str.length] = second 221 when Range 222 n, len = OSX::RangeUtil.normalize(first, count) 223 if n < 0 || count < n 224 raise RangeError, "#{first} out of range" 225 end 226 value = second 227 case value 228 when Numeric,OSX::NSNumber 229 value = OSX::NSString.stringWithFormat("%C", value.to_i) 230 when String,OSX::NSString 231 else 232 raise TypeError, "can't convert #{val.class} into String" 233 end 234 if len > 0 235 deleteCharactersInRange(OSX::NSRange.new(n, len)) 236 end 237 insertString_atIndex(value, n) 238 value 239 #when Regexp 240 else 241 raise TypeError, "can't convert #{first.class} into Integer" 242 end 243 when 3 244 first = args.first 245 case first 246 when Numeric,OSX::NSNumber 247 n, len, value = args 248 unless len.is_a?(Numeric) || len.is_a?(OSX::NSNumber) 249 raise TypeError, "can't convert #{len.class} into Integer" 250 end 251 n = n.to_i 252 len = len.to_i 253 n += count if n < 0 254 if n < 0 || count < n 255 raise IndexError, "index #{first.to_i} out of string" 256 end 257 if len < 0 258 raise IndexError, "negative length (#{len})" 259 end 260 self[n...n+len] = value 261 #when Regexp 262 else 263 raise TypeError, "can't convert #{first.class} into Integer" 264 end 265 else 266 raise ArgumentError, "wrong number of arguments (#{args.length} for 3)" 267 end 268 end 269 270 def %(args) 271 if args.is_a?(Array) || args.is_a?(OSX::NSArray) 272 args = args.map {|i| i.is_a?(OSX::NSObject) ? i.to_ruby : i } 273 end 274 (to_s % args).to_ns 275 end 276 277 def *(times) 278 unless times.is_a?(Numeric) || times.is_a?(OSX::NSNumber) 279 raise TypeError, "can't convert #{times.class} into Integer" 280 end 281 (to_s * times.to_i).to_ns 282 end 283 284 def +(other) 285 unless other.is_a?(String) || other.is_a?(OSX::NSString) 286 raise TypeError, "can't convert #{other.class} into String" 287 end 288 s = mutableCopy 289 s.appendString(other) 290 s 291 end 292 293 def <<(other) 294 case other 295 when Numeric,OSX::NSNumber 296 i = other.to_i 297 if 0 <= i && i < 65536 298 appendString(OSX::NSString.stringWithFormat("%C", i)) 299 else 300 raise TypeError, "can't convert #{other.class} into String" 301 end 302 when String,OSX::NSString 303 appendString(other) 304 else 305 raise TypeError, "can't convert #{other.class} into String" 306 end 307 self 308 end 309 alias_method :concat, :<< 310 311 def capitalize 312 if length > 0 313 substringToIndex(1).upcase + substringFromIndex(1).downcase 314 else 315 ''.to_ns 316 end 317 end 318 319 def capitalize! 320 s = capitalize 321 if self != s 322 setString(s) 323 self 324 else 325 nil 326 end 327 end 328 329 def casecmp(other) 330 caseInsensitiveCompare(other) 331 end 332 333 def center(len, padstr=' ') 334 if !len.is_a?(Numeric) && !len.is_a?(OSX::NSNumber) 335 raise TypeError, "can't convert #{len.class} into Integer" 336 end 337 if !padstr.is_a?(String) && !padstr.is_a?(OSX::NSString) 338 raise TypeError, "can't convert #{padstr.class} into String" 339 end 340 len = len.to_i 341 padstr = padstr.to_ns if padstr.is_a?(String) 342 padlen = padstr.length 343 if padlen == 0 344 raise ArgumentError, "zero width padding" 345 end 346 curlen = length 347 if len <= curlen 348 mutableCopy 349 else 350 len -= curlen 351 leftlen = len / 2 352 rightlen = len - leftlen 353 s = ''.to_ns 354 if leftlen > 0 355 s << padstr * (leftlen / padlen) 356 leftlen %= padlen 357 s << padstr.substringToIndex(leftlen) if leftlen > 0 358 end 359 s << self 360 if rightlen > 0 361 s << padstr * (rightlen / padlen) 362 rightlen %= padlen 363 s << padstr.substringToIndex(rightlen) if rightlen > 0 364 end 365 s 366 end 367 end 368 369 def chomp(rs=$/) 370 return mutableCopy unless rs 371 if rs.empty? 372 prev = self 373 while prev != (s = prev.chomp) 374 prev = s 375 end 376 s 377 else 378 if rs == "\n" 379 if hasSuffix("\r\n") 380 substringToIndex(length-2).mutableCopy 381 elsif hasSuffix("\n") || hasSuffix("\r") 382 substringToIndex(length-1).mutableCopy 383 else 384 mutableCopy 385 end 386 else 387 if hasSuffix(rs) 388 rs = rs.to_ns if rs.is_a?(String) 389 substringToIndex(length-rs.length).mutableCopy 390 else 391 mutableCopy 392 end 393 end 394 end 395 end 396 397 def chomp!(rs=$/) 398 s = chomp(rs) 399 if self != s 400 setString(s) 401 self 402 else 403 nil 404 end 405 end 406 407 def chop 408 len = length 409 if len == 0 410 ''.to_ns 411 elsif hasSuffix("\r\n") 412 substringToIndex(len-2).mutableCopy 413 else 414 substringToIndex(len-1).mutableCopy 415 end 416 end 417 418 def chop! 419 s = chop 420 if self != s 421 setString(s) 422 self 423 else 424 nil 425 end 426 end 427 428 def chr 429 if empty? 430 ''.to_ns 431 else 432 substringToIndex(1).mutableCopy 433 end 434 end 435 436 def clear 437 setString('') 438 self 439 end 440 441 def count(*chars) 442 to_s.count(*chars) 443 end 444 445 def crypt(salt) 446 to_s.crypt(salt.to_s).to_ns 447 end 448 449 def delete(*strs) 450 to_s.delete(*strs).to_ns 451 end 452 453 def delete!(*strs) 454 s = to_s 455 result = s.delete!(*strs) 456 if result 457 setString(s) 458 self 459 else 460 nil 461 end 462 end 463 464 def downcase 465 lowercaseString.mutableCopy 466 end 467 468 def downcase! 469 s = lowercaseString 470 if self != s 471 setString(s) 472 self 473 else 474 nil 475 end 476 end 477 478 def dump 479 to_s.dump.to_ns 480 end 481 482 def each_byte(&block) 483 to_s.each_byte(&block) 484 self 485 end 486 487 def each_line(rs=$/) 488 if rs == nil 489 yield mutableCopy 490 else 491 if rs.empty? 492 paragraph_mode = true 493 sep = $/*2 494 lf = $/ 495 sep = sep.to_ns if sep.is_a?(String) 496 lf = lf.to_ns if lf.is_a?(String) 497 else 498 paragraph_mode = false 499 sep = rs 500 sep = sep.to_ns if sep.is_a?(String) 501 end 502 503 pos = 0 504 count = length 505 loop do 506 break if count <= pos 507 n = index(sep, pos) 508 unless n 509 yield self[pos..-1] 510 break 511 end 512 len = sep.length 513 if paragraph_mode 514 loop do 515 start = n + len 516 break if self[start,lf.length] != lf 517 len += lf.length 518 end 519 end 520 yield self[pos...n+len] 521 pos = n + len 522 end 523 end 524 self 525 end 526 alias_method :each, :each_line 527 528 def empty? 529 length == 0 530 end 531 532 def end_with?(str) 533 hasSuffix(str) 534 end 535 536 def gsub(*args, &block) 537 to_s.gsub(*args, &block).to_ns 538 end 539 540 def gsub!(*args, &block) 541 s = to_s 542 result = s.gsub!(*args, &block) 543 if result 544 setString(s) 545 self 546 else 547 nil 548 end 549 end 550 551 def hex 552 to_s.hex 553 end 554 555 def include?(str) 556 index(str) != nil 557 end 558 559 def index(pattern, pos=0) 560 case pattern 561 when Numeric,OSX::NSNumber 562 i = pattern.to_i 563 if 0 <= i && i < 65536 564 s = OSX::NSString.stringWithFormat("%C", i) 565 else 566 return nil 567 end 568 when String,OSX::NSString 569 s = pattern 570 s = s.to_ns if s.is_a?(String) 571 #when Regexp 572 else 573 raise TypeError, "can't convert #{pattern.class} into String" 574 end 575 576 if s.empty? 577 0 578 else 579 len = length 580 n = pos.to_i 581 n += len if n < 0 582 if n < 0 || len <= n 583 return nil 584 end 585 range = rangeOfString_options_range(s, 0, OSX::NSRange.new(n, len - n)) 586 if range.not_found? 587 nil 588 else 589 range.location 590 end 591 end 592 end 593 594 def insert(n, other) 595 unless n.is_a?(Numeric) || n.is_a?(OSX::NSNumber) 596 raise TypeError, "can't convert #{n.class} into Integer" 597 end 598 unless other.is_a?(String) || other.is_a?(OSX::NSString) 599 raise TypeError, "can't convert #{other.class} into String" 600 end 601 n = n.to_i 602 if n == -1 603 appendString(other) 604 else 605 len = length 606 n += len + 1 if n < 0 607 if n < 0 || len < n 608 raise IndexError, "index #{n} out of string" 609 else 610 insertString_atIndex(other, n) 611 end 612 end 613 self 614 end 615 616 def intern 617 to_s.intern 618 end 619 alias_method :to_sym, :intern 620 621 def lines 622 result = [] 623 each_line {|i| result << i } 624 result.to_ns 625 end 626 627 def ljust(len, padstr=' ') 628 if !len.is_a?(Numeric) && !len.is_a?(OSX::NSNumber) 629 raise TypeError, "can't convert #{len.class} into Integer" 630 end 631 if !padstr.is_a?(String) && !padstr.is_a?(OSX::NSString) 632 raise TypeError, "can't convert #{padstr.class} into String" 633 end 634 len = len.to_i 635 padstr = padstr.to_ns if padstr.is_a?(String) 636 padlen = padstr.length 637 if padlen == 0 638 raise ArgumentError, "zero width padding" 639 end 640 s = mutableCopy 641 curlen = length 642 if len <= curlen 643 s 644 else 645 len -= curlen 646 s << padstr * (len / padlen) 647 len %= padlen 648 s << padstr.substringToIndex(len) if len > 0 649 s 650 end 651 end 652 653 def lstrip 654 cs = OSX::NSCharacterSet.characterSetWithCharactersInString(" \t\r\n\f\v").invertedSet 655 r = rangeOfCharacterFromSet(cs) 656 if r.not_found? 657 ''.to_ns 658 else 659 substringFromIndex(r.location).mutableCopy 660 end 661 end 662 663 def lstrip! 664 s = lstrip 665 if self != s 666 setString(s) 667 self 668 else 669 nil 670 end 671 end 672 673 def next 674 to_s.next.to_ns 675 end 676 alias_method :succ, :next 677 678 def next! 679 setString(self.next) 680 self 681 end 682 alias_method :succ!, :next! 683 684 def oct 685 to_s.oct 686 end 687 688 def ord 689 if length > 0 690 characterAtIndex(0) 691 else 692 0 693 end 694 end 695 696 def partition(sep) 697 r = rangeOfString(sep) 698 if r.not_found? 699 left = mutableCopy 700 right = ''.to_ns 701 sep = right.mutableCopy 702 else 703 left = substringToIndex(r.location).mutableCopy 704 right = substringFromIndex(r.location + r.length).mutableCopy 705 sep = substringWithRange(r).mutableCopy 706 end 707 [left, sep, right].to_ns 708 end 709 710 def replace(other) 711 setString(other) 712 self 713 end 714 715 def reverse 716 s = ''.to_ns 717 (length-1).downto(0) do |i| 718 s.appendFormat("%C", characterAtIndex(i)) 719 end 720 s 721 end 722 723 def reverse! 724 setString(reverse) 725 self 726 end 727 728 def rindex(pattern, pos=self.length) 729 case pattern 730 when Numeric,OSX::NSNumber 731 i = pattern.to_i 732 if 0 <= i && i < 65536 733 s = OSX::NSString.stringWithFormat("%C", i) 734 else 735 return nil 736 end 737 when String,OSX::NSString 738 s = pattern 739 s = s.to_ns if s.is_a?(String) 740 #when Regexp 741 else 742 raise TypeError, "can't convert #{pattern.class} into String" 743 end 744 745 if s.empty? 746 length 747 else 748 len = length 749 n = pos.to_i 750 n += len if n < 0 751 if n < 0 752 return nil 753 end 754 n += s.length 755 n = len if len < n 756 range = rangeOfString_options_range(s, OSX::NSBackwardsSearch, OSX::NSRange.new(0, n)) 757 if range.not_found? 758 nil 759 else 760 range.location 761 end 762 end 763 end 764 765 def rjust(len, padstr=' ') 766 if !len.is_a?(Numeric) && !len.is_a?(OSX::NSNumber) 767 raise TypeError, "can't convert #{len.class} into Integer" 768 end 769 if !padstr.is_a?(String) && !padstr.is_a?(OSX::NSString) 770 raise TypeError, "can't convert #{padstr.class} into String" 771 end 772 len = len.to_i 773 padstr = padstr.to_ns if padstr.is_a?(String) 774 padlen = padstr.length 775 if padlen == 0 776 raise ArgumentError, "zero width padding" 777 end 778 curlen = length 779 if len <= curlen 780 mutableCopy 781 else 782 s = ''.to_ns 783 len -= curlen 784 s << padstr * (len / padlen) 785 len %= padlen 786 s << padstr.substringToIndex(len) if len > 0 787 s << self 788 s 789 end 790 end 791 792 def rpartition(sep) 793 r = rangeOfString_options(sep, OSX::NSBackwardsSearch) 794 if r.not_found? 795 left = mutableCopy 796 right = ''.to_ns 797 sep = right.mutableCopy 798 else 799 left = substringToIndex(r.location).mutableCopy 800 right = substringFromIndex(r.location + r.length).mutableCopy 801 sep = substringWithRange(r).mutableCopy 802 end 803 [left, sep, right].to_ns 804 end 805 806 def rstrip 807 cs = OSX::NSCharacterSet.characterSetWithCharactersInString(" \t\r\n\f\v").invertedSet 808 r = rangeOfCharacterFromSet_options(cs, OSX::NSBackwardsSearch) 809 if r.not_found? 810 ''.to_ns 811 else 812 substringToIndex(r.location + 1).mutableCopy 813 end 814 end 815 816 def rstrip! 817 s = rstrip 818 if self != s 819 setString(s) 820 self 821 else 822 nil 823 end 824 end 825 826 def scan(re, &block) 827 if block 828 to_s.scan(re) {|i| block.call(i.to_ns)}.to_ns 829 else 830 to_s.scan(re).to_ns 831 end 832 end 833 834 def size 835 length 836 end 837 838 def slice!(*args) 839 _read_impl(:slice!, args) 840 end 841 842 def split(sep=$;, limit=0) 843 sep = sep.to_ns if sep.is_a?(String) 844 result = [] 845 if sep && sep.empty? 846 if limit > 0 847 0.upto(limit-2) do |i| 848 result << self[i..i] 849 end 850 result << substringFromIndex(limit-1).mutableCopy if limit < length 851 else 852 0.upto(length-1) {|i| result << self[i..i]} 853 if limit == 0 854 while last = result[-1] && last.empty? 855 result.delete_at(-1) 856 end 857 end 858 end 859 else 860 space = ' '.to_ns 861 if sep.nil? || sep.isEqualTo(space) 862 str = lstrip 863 sep = space 864 else 865 str = self 866 end 867 868 n = nil 869 pos = 0 870 count = str.length 871 872 loop do 873 break if limit > 0 && result.size >= limit -1 874 break if count <= pos 875 n = str.index(sep, pos) 876 break unless n 877 len = sep.length 878 s = str[pos...n] 879 result << s unless s.empty? && sep == space 880 pos = n + len 881 end 882 883 result << str.substringFromIndex(pos).mutableCopy 884 885 if limit == 0 886 while (last = result[-1]) && last.empty? 887 result.delete_at(-1) 888 end 889 end 890 end 891 result.to_ns 892 end 893 894 def squeeze(*chars) 895 to_s.squeeze(*chars).to_ns 896 end 897 898 def squeeze!(*chars) 899 s = to_s 900 result = s.squeeze!(*chars) 901 if result 902 setString(s) 903 self 904 else 905 nil 906 end 907 end 908 909 def start_with?(str) 910 hasPrefix(str) 911 end 912 913 def strip 914 cs = OSX::NSCharacterSet.characterSetWithCharactersInString(" \t\r\n\f\v") 915 stringByTrimmingCharactersInSet(cs).mutableCopy 916 end 917 918 def strip! 919 s = strip 920 if self != s 921 setString(s) 922 self 923 else 924 nil 925 end 926 end 927 928 def sub(*args, &block) 929 to_s.sub(*args, &block).to_ns 930 end 931 932 def sub!(*args, &block) 933 s = to_s 934 result = s.sub!(*args, &block) 935 if result 936 setString(s) 937 self 938 else 939 nil 940 end 941 end 942 943 def sum(bits=16) 944 bits = bits.to_i if bits.is_a?(OSX::NSNumber) 945 n = 0 946 0.upto(length-1) {|i| n += characterAtIndex(i) } 947 n = n & ((1 << bits) - 1) if bits > 0 948 n 949 end 950 951 def swapcase 952 to_s.swapcase.to_ns 953 end 954 955 def swapcase! 956 s = swapcase 957 if self != s 958 setString(s) 959 self 960 else 961 nil 962 end 963 end 964 965 def to_f 966 to_s.to_f 967 end 968 969 def to_i(base=10) 970 to_s.to_i(base) 971 end 972 973 def tr(pattern, replace) 974 to_s.tr(pattern, replace).to_ns 975 end 976 977 def tr!(pattern, replace) 978 s = to_s 979 result = s.tr!(pattern, replace) 980 if result 981 setString(s) 982 self 983 else 984 nil 985 end 986 end 987 988 def tr_s(pattern, replace) 989 to_s.tr_s(pattern, replace).to_ns 990 end 991 992 def tr_s!(pattern, replace) 993 s = to_s 994 result = s.tr_s!(pattern, replace) 995 if result 996 setString(s) 997 self 998 else 999 nil 1000 end 1001 end 1002 1003 def upcase 1004 uppercaseString.mutableCopy 1005 end 1006 1007 def upcase! 1008 s = uppercaseString 1009 if self != s 1010 setString(s) 1011 self 1012 else 1013 nil 1014 end 1015 end 1016 1017 def upto(max) 1018 max = max.to_ns unless max.is_a?(NSString) 1019 (self..max).each {|i| yield i} 1020 self 1021 end 1022 1023 private 1024 1025 def _read_impl(method, args) 1026 slice = method == :slice! 1027 count = length 1028 case args.length 1029 when 1 1030 first = args.first 1031 case first 1032 when Numeric,OSX::NSNumber 1033 _read_impl_num(slice, first.to_i, count) 1034 when String,OSX::NSString 1035 _read_impl_str(slice, first.to_ns) 1036 #when Regexp 1037 when Range 1038 _read_impl_range(slice, first, count) 1039 else 1040 raise TypeError, "can't convert #{first.class} into Integer" 1041 end 1042 when 2 1043 first, second = args 1044 case first 1045 when Numeric,OSX::NSNumber 1046 unless second.is_a?(Numeric) || second.is_a?(OSX::NSNumber) 1047 raise TypeError, "can't convert #{second.class} into Integer" 1048 end 1049 _read_impl_num_len(method, first.to_i, second.to_i, count) 1050 #when Regexp 1051 else 1052 raise TypeError, "can't convert #{first.class} into Integer" 1053 end 1054 else 1055 raise ArgumentError, "wrong number of arguments (#{args.length} for 2)" 1056 end 1057 end 1058 1059 def _read_impl_num(slice, num, count) 1060 num += count if num < 0 1061 if 0 <= num && num < count 1062 c = characterAtIndex(num) 1063 deleteCharactersInRange(OSX::NSRange.new(num, 1)) if slice 1064 c 1065 else 1066 nil 1067 end 1068 end 1069 1070 def _read_impl_str(slice, str) 1071 n = index(str) 1072 if n 1073 s = str.mutableCopy 1074 deleteCharactersInRange(OSX::NSRange.new(n, str.length)) if slice 1075 s 1076 else 1077 nil 1078 end 1079 end 1080 1081 def _read_impl_range(slice, range, count) 1082 n, len = OSX::RangeUtil.normalize(range, count) 1083 if 0 <= n && n < count 1084 range = OSX::NSRange.new(n, len) 1085 s = substringWithRange(range).mutableCopy 1086 deleteCharactersInRange(range) if slice 1087 s 1088 elsif n == count 1089 ''.to_ns 1090 else 1091 nil 1092 end 1093 end 1094 1095 def _read_impl_num_len(method, num, len, count) 1096 num += count if num < 0 1097 if num < 0 || count < num 1098 nil 1099 elsif len < 0 1100 nil 1101 else 1102 _read_impl(method, [num...num+len]) 1103 end 1104 end 1105 end 1106 1107 # NSArray additions 1108 class NSArray 1109 include OSX::OCObjWrapper 1110 1111 def dup 1112 mutableCopy 1113 end 1114 1115 def clone 1116 obj = dup 1117 obj.freeze if frozen? 1118 obj.taint if tainted? 1119 obj 1120 end 1121 1122 # enable to treat as Array 1123 def to_ary 1124 to_a 1125 end 1126 1127 # comparison between Ruby Array and Cocoa NSArray 1128 def ==(other) 1129 if other.is_a? OSX::NSArray 1130 isEqualToArray?(other) 1131 elsif other.respond_to? :to_ary 1132 to_a == other.to_ary 1133 else 1134 false 1135 end 1136 end 1137 1138 def <=>(other) 1139 if other.respond_to? :to_ary 1140 to_a <=> other.to_ary 1141 else 1142 nil 1143 end 1144 end 1145 1146 # For NSArray duck typing 1147 1148 def each 1149 iter = objectEnumerator 1150 while obj = iter.nextObject 1151 yield obj 1152 end 1153 self 1154 end 1155 1156 def reverse_each 1157 iter = reverseObjectEnumerator 1158 while obj = iter.nextObject 1159 yield obj 1160 end 1161 self 1162 end 1163 1164 def [](*args) 1165 _read_impl(:[], args) 1166 end 1167 alias_method :slice, :[] 1168 1169 def []=(*args) 1170 count = self.count 1171 case args.length 1172 when 2 1173 case args.first 1174 when Numeric 1175 n, value = args 1176 unless n.is_a?(Numeric) || n.is_a?(OSX::NSNumber) 1177 raise TypeError, "can't convert #{n.class} into Integer" 1178 end 1179 if value == nil 1180 raise ArgumentError, "attempt insert nil to NSArray" 1181 end 1182 n = n.to_i 1183 n += count if n < 0 1184 if 0 <= n && n < count 1185 replaceObjectAtIndex_withObject(n, value) 1186 elsif n == count 1187 addObject(value) 1188 else 1189 raise IndexError, "index #{args[0]} out of array" 1190 end 1191 value 1192 when Range 1193 range, value = args 1194 n, len = OSX::RangeUtil.normalize(range, count) 1195 if n < 0 || count < n 1196 raise RangeError, "#{range} out of range" 1197 end 1198 1199 if 0 <= n && n < count 1200 if len > 0 1201 removeObjectsInRange(OSX::NSRange.new(n, len)) 1202 end 1203 if value != nil 1204 if value.is_a?(Array) || value.is_a?(OSX::NSArray) 1205 unless value.empty? 1206 indexes = OSX::NSIndexSet.indexSetWithIndexesInRange(NSRange.new(n, value.length)) 1207 insertObjects_atIndexes(value, indexes) 1208 end 1209 else 1210 insertObject_atIndex(value, n) 1211 end 1212 end 1213 else 1214 if value != nil 1215 if value.is_a?(Array) || value.is_a?(OSX::NSArray) 1216 unless value.empty? 1217 addObjectsFromArray(value) 1218 end 1219 else 1220 addObject(value) 1221 end 1222 end 1223 end 1224 value 1225 else 1226 raise ArgumentError, "wrong number of arguments (#{args.length} for 3)" 1227 end 1228 when 3 1229 n, len, value = args 1230 unless n.is_a?(Numeric) || n.is_a?(OSX::NSNumber) 1231 raise TypeError, "can't convert #{n.class} into Integer" 1232 end 1233 unless len.is_a?(Numeric) || len.is_a?(OSX::NSNumber) 1234 raise TypeError, "can't convert #{len.class} into Integer" 1235 end 1236 n = n.to_i 1237 len = len.to_i 1238 n += count if n < 0 1239 if n < 0 || count < n 1240 raise IndexError, "index #{args[0]} out of array" 1241 end 1242 if len < 0 1243 raise IndexError, "negative length (#{len})" 1244 end 1245 self[n...n+len] = value 1246 else 1247 raise ArgumentError, "wrong number of arguments (#{args.length} for 3)" 1248 end 1249 end 1250 1251 def <<(obj) 1252 addObject(obj) 1253 self 1254 end 1255 1256 def &(other) 1257 ary = other 1258 unless ary.is_a?(Array) || ary.is_a?(OSX::NSArray) 1259 if ary.respond_to?(:to_ary) 1260 ary = ary.to_ary 1261 unless ary.is_a?(Array) || ary.is_a?(OSX::NSArray) 1262 raise TypeError, "can't convert #{other.class} into Array" 1263 end 1264 else 1265 raise TypeError, "can't convert #{other.class} into Array" 1266 end 1267 end 1268 result = [].to_ns 1269 dic = {}.to_ns 1270 each {|i| dic.setObject_forKey(i, i) } 1271 ary.each do |i| 1272 if dic.objectForKey(i) 1273 result.addObject(i) 1274 dic.removeObjectForKey(i) 1275 end 1276 end 1277 result 1278 end 1279 1280 def |(other) 1281 ary = other 1282 unless ary.is_a?(Array) || ary.is_a?(OSX::NSArray) 1283 if ary.respond_to?(:to_ary) 1284 ary = ary.to_ary 1285 unless ary.is_a?(Array) || ary.is_a?(OSX::NSArray) 1286 raise TypeError, "can't convert #{other.class} into Array" 1287 end 1288 else 1289 raise TypeError, "can't convert #{other.class} into Array" 1290 end 1291 end 1292 result = [].to_ns 1293 dic = {}.to_ns 1294 [self, ary].each do |obj| 1295 obj.each do |i| 1296 unless dic.objectForKey(i) 1297 dic.setObject_forKey(i, i) 1298 result.addObject(i) 1299 end 1300 end 1301 end 1302 result 1303 end 1304 1305 def *(arg) 1306 case arg 1307 when Numeric 1308 (to_a * arg).to_ns 1309 when String 1310 join(arg) 1311 else 1312 raise TypeError, "can't convert #{arg.class} into Integer" 1313 end 1314 end 1315 1316 def +(other) 1317 ary = other 1318 unless ary.is_a?(Array) || ary.is_a?(OSX::NSArray) 1319 if ary.respond_to?(:to_ary) 1320 ary = ary.to_ary 1321 unless ary.is_a?(Array) || ary.is_a?(OSX::NSArray) 1322 raise TypeError, "can't convert #{other.class} into Array" 1323 end 1324 else 1325 raise TypeError, "can't convert #{other.class} into Array" 1326 end 1327 end 1328 result = mutableCopy 1329 result.addObjectsFromArray(other) 1330 result 1331 end 1332 1333 def -(other) 1334 ary = other 1335 unless ary.is_a?(Array) || ary.is_a?(OSX::NSArray) 1336 if ary.respond_to?(:to_ary) 1337 ary = ary.to_ary 1338 unless ary.is_a?(Array) || ary.is_a?(OSX::NSArray) 1339 raise TypeError, "can't convert #{other.class} into Array" 1340 end 1341 else 1342 raise TypeError, "can't convert #{other.class} into Array" 1343 end 1344 end 1345 result = [].to_ns 1346 dic = {}.to_ns 1347 ary.each {|i| dic.setObject_forKey(i, i) } 1348 each {|i| result.addObject(i) unless dic.objectForKey(i) } 1349 result 1350 end 1351 1352 def assoc(key) 1353 each do |i| 1354 if i.is_a? OSX::NSArray 1355 unless i.empty? 1356 return i if i.first.isEqual(key) 1357 end 1358 end 1359 end 1360 nil 1361 end 1362 1363 def at(pos) 1364 self[pos] 1365 end 1366 1367 def clear 1368 removeAllObjects 1369 self 1370 end 1371 1372 def collect! 1373 copy.each_with_index {|i,n| replaceObjectAtIndex_withObject(n, (yield i)) } 1374 self 1375 end 1376 alias_method :map!, :collect! 1377 1378 # does nothing because NSArray cannot have nil 1379 def compact; mutableCopy; end 1380 def compact!; nil; end 1381 1382 def concat(other) 1383 addObjectsFromArray(other) 1384 self 1385 end 1386 1387 def delete(val) 1388 indexes = OSX::NSMutableIndexSet.indexSet 1389 each_with_index {|i,n| indexes.addIndex(n) if i.isEqual(val) } 1390 removeObjectsAtIndexes(indexes) if indexes.count > 0 1391 if indexes.count > 0 1392 val 1393 else 1394 if block_given? 1395 yield 1396 end 1397 nil 1398 end 1399 end 1400 1401 def delete_at(pos) 1402 unless pos.is_a? Numeric 1403 raise TypeError, "can't convert #{pos.class} into Integer" 1404 end 1405 count = self.count 1406 pos = pos.to_i 1407 pos += count if pos < 0 1408 if 0 <= pos && pos < count 1409 result = self[pos] 1410 removeObjectAtIndex(pos) 1411 result 1412 else 1413 nil 1414 end 1415 end 1416 1417 def delete_if(&block) 1418 reject!(&block) 1419 self 1420 end 1421 1422 def reject! 1423 indexes = OSX::NSMutableIndexSet.indexSet 1424 each_with_index {|i,n| indexes.addIndex(n) if yield i } 1425 if indexes.count > 0 1426 removeObjectsAtIndexes(indexes) 1427 self 1428 else 1429 nil 1430 end 1431 end 1432 1433 def each_index 1434 each_with_index {|i,n| yield n } 1435 end 1436 1437 def empty? 1438 count == 0 1439 end 1440 1441 def fetch(*args) 1442 count = self.count 1443 len = args.length 1444 if len == 0 || len > 2 1445 raise ArgumentError, "wrong number of arguments (#{len} for 2)" 1446 end 1447 index = args.first 1448 unless index.is_a? Numeric 1449 raise TypeError, "can't convert #{index.class} into Integer" 1450 end 1451 index = index.to_i 1452 index += count if index < 0 1453 if 0 <= index && index < count 1454 objectAtIndex(index) 1455 else 1456 if len == 2 1457 args[1] 1458 elsif block_given? 1459 yield 1460 else 1461 raise IndexError, "index #{args.first} out of array" 1462 end 1463 end 1464 end 1465 1466 def fill(*args, &block) 1467 count = self.count 1468 len = args.length 1469 len -= 1 unless block 1470 case len 1471 when 0 1472 val = args.first 1473 n = -1 1474 map! do |i| 1475 n += 1 1476 block ? block.call(n) : val 1477 end 1478 when 1 1479 if block 1480 first = args.first 1481 else 1482 val, first = args 1483 end 1484 case first 1485 when Numeric 1486 start = first.to_i 1487 start += count if start < 0 1488 n = -1 1489 map! do |i| 1490 n += 1 1491 if start <= n 1492 block ? block.call(n) : val 1493 else 1494 i 1495 end 1496 end 1497 when Range 1498 range = first 1499 left, len, right = OSX::RangeUtil.normalize(range, count) 1500 if left < 0 || count < left 1501 raise RangeError, "#{range} out of range" 1502 end 1503 n = -1 1504 map! do |i| 1505 n += 1 1506 if left <= n && n < right 1507 block ? block.call(n) : val 1508 else 1509 i 1510 end 1511 end 1512 (n+1).upto(right-1) do |i| 1513 n += 1 1514 addObject(block ? block.call(n) : val) 1515 end 1516 self 1517 else 1518 raise TypeError, "can't convert #{first.class} into Integer" 1519 end 1520 when 2 1521 if block 1522 first, len = args 1523 else 1524 val, first, len = args 1525 end 1526 start = first 1527 unless start.is_a? Numeric 1528 raise TypeError, "can't convert #{start.class} into Integer" 1529 end 1530 unless len.is_a? Numeric 1531 raise TypeError, "can't convert #{len.class} into Integer" 1532 end 1533 start = start.to_i 1534 len = len.to_i 1535 start += count if start < 0 1536 if start < 0 || count < start 1537 raise IndexError, "index #{first} out of array" 1538 end 1539 len = 0 if len < 0 1540 if block 1541 fill(start...start+len, &block) 1542 else 1543 fill(val, start...start+len) 1544 end 1545 else 1546 raise ArgumentError, "wrong number of arguments (#{args.length} for 2)" 1547 end 1548 end 1549 1550 def first(n=nil) 1551 if n 1552 if n.is_a? Numeric 1553 len = n.to_i 1554 if len < 0 1555 raise ArgumentError, "negative array size (or size too big)" 1556 end 1557 self[0...n] 1558 else 1559 raise TypeError, "can't convert #{n.class} into Integer" 1560 end 1561 else 1562 self[0] 1563 end 1564 end 1565 1566 def flatten 1567 result = [].to_ns 1568 each do |i| 1569 if i.is_a? OSX::NSArray 1570 result.addObjectsFromArray(i.flatten) 1571 else 1572 result.addObject(i) 1573 end 1574 end 1575 result 1576 end 1577 1578 def flatten! 1579 flat = true 1580 result = [].to_ns 1581 each do |i| 1582 if i.is_a? OSX::NSArray 1583 flat = false 1584 result.addObjectsFromArray(i.flatten) 1585 else 1586 result.addObject(i) 1587 end 1588 end 1589 if flat 1590 nil 1591 else 1592 setArray(result) 1593 self 1594 end 1595 end 1596 1597 def include?(val) 1598 index(val) != nil 1599 end 1600 1601 def index(*args) 1602 if block_given? 1603 each_with_index {|i,n| return n if yield i} 1604 elsif args.length == 1 1605 val = args.first 1606 each_with_index {|i,n| return n if i.isEqual(val)} 1607 else 1608 raise ArgumentError, "wrong number of arguments (#{args.length} for 1)" 1609 end 1610 nil 1611 end 1612 1613 def insert(n, *vals) 1614 if n == -1 1615 push(*vals) 1616 else 1617 n += count + 1 if n < 0 1618 self[n, 0] = vals 1619 end 1620 self 1621 end 1622 1623 def join(sep=$,) 1624 s = '' 1625 each do |i| 1626 s += sep if sep && !s.empty? 1627 if i == self 1628 s << '[...]' 1629 elsif i.is_a? OSX::NSArray 1630 s << i.join(sep) 1631 else 1632 s << i.to_s 1633 end 1634 end 1635 s 1636 end 1637 1638 def last(n=nil) 1639 if n 1640 if n.is_a? Numeric 1641 len = n.to_i 1642 if len < 0 1643 raise ArgumentError, "negative array size (or size too big)" 1644 end 1645 if len == 0 1646 [].to_ns 1647 elsif len >= count 1648 mutableCopy 1649 else 1650 self[(-len)..-1] 1651 end 1652 else 1653 raise TypeError, "can't convert #{n.class} into Integer" 1654 end 1655 else 1656 self[-1] 1657 end 1658 end 1659 1660 def pack(template) 1661 to_ruby.pack(template) 1662 end 1663 1664 def pop 1665 if count > 0 1666 result = lastObject 1667 removeLastObject 1668 result 1669 else 1670 nil 1671 end 1672 end 1673 1674 def push(*args) 1675 case args.length 1676 when 0 1677 ; 1678 when 1 1679 addObject(args.first) 1680 else 1681 addObjectsFromArray(args) 1682 end 1683 self 1684 end 1685 1686 def rassoc(key) 1687 each do |i| 1688 if i.is_a? OSX::NSArray 1689 if i.count >= 1 1690 return i if i[1].isEqual(key) 1691 end 1692 end 1693 end 1694 nil 1695 end 1696 1697 def replace(another) 1698 setArray(another) 1699 self 1700 end 1701 1702 def reverse 1703 to_a.reverse.to_ns 1704 end 1705 1706 def reverse! 1707 setArray(to_a.reverse) 1708 self 1709 end 1710 1711 def rindex(*args) 1712 if block_given? 1713 n = count 1714 reverse_each do |i| 1715 n -= 1 1716 return n if yield i 1717 end 1718 elsif args.length == 1 1719 val = args.first 1720 n = count 1721 reverse_each do |i| 1722 n -= 1 1723 return n if i.isEqual(val) 1724 end 1725 else 1726 raise ArgumentError, "wrong number of arguments (#{args.length} for 1)" 1727 end 1728 nil 1729 end 1730 1731 def shift 1732 unless empty? 1733 result = objectAtIndex(0) 1734 removeObjectAtIndex(0) 1735 result 1736 else 1737 nil 1738 end 1739 end 1740 1741 def count 1742 oc_count 1743 end 1744 1745 def size 1746 count 1747 end 1748 alias_method :length, :size 1749 alias_method :nitems, :size 1750 1751 def slice!(*args) 1752 _read_impl(:slice!, args) 1753 end 1754 1755 def sort!(&block) 1756 setArray(to_a.sort(&block)) 1757 self 1758 end 1759 1760 def to_splat 1761 to_a 1762 end 1763 1764 def transpose 1765 to_a.transpose.to_ns 1766 end 1767 1768 def uniq 1769 result = [].to_ns 1770 dic = {}.to_ns 1771 each do |i| 1772 unless dic.has_key?(i) 1773 dic.setObject_forKey(i, i) 1774 result.addObject(i) 1775 end 1776 end 1777 result 1778 end 1779 1780 def uniq! 1781 if empty? 1782 nil 1783 else 1784 dic = {}.to_ns 1785 indexes = OSX::NSMutableIndexSet.indexSet 1786 each_with_index do |i,n| 1787 if dic.has_key?(i) 1788 indexes.addIndex(n) 1789 else 1790 dic.setObject_forKey(i, i) 1791 end 1792 end 1793 if indexes.count > 0 1794 removeObjectsAtIndexes(indexes) 1795 self 1796 else 1797 nil 1798 end 1799 end 1800 end 1801 1802 def unshift(*args) 1803 if count == 0 1804 push(*args) 1805 else 1806 case args.length 1807 when 0 1808 ; 1809 when 1 1810 insertObject_atIndex(args.first, 0) 1811 else 1812 indexes = OSX::NSIndexSet.indexSetWithIndexesInRange(NSRange.new(0, args.length)) 1813 insertObjects_atIndexes(args, indexes) 1814 end 1815 self 1816 end 1817 end 1818 1819 def values_at(*indexes) 1820 indexes.map {|i| self[i]}.to_ns 1821 end 1822 alias_method :indexes, :values_at 1823 alias_method :indices, :values_at 1824 1825 def inspect 1826 "#<#{self.class.to_s.gsub(/^OSX::/, '')} #{ self.to_a.inspect }>" 1827 end 1828 1829 def pretty_print(q) 1830 self.to_a.pretty_print(q) 1831 end 1832 1833 private 1834 1835 def _read_impl(method, args) 1836 slice = method == :slice! 1837 count = self.count 1838 case args.length 1839 when 1 1840 first = args.first 1841 case first 1842 when Numeric,OSX::NSNumber 1843 _read_impl_num(slice, first.to_i, count) 1844 when Range 1845 _read_impl_range(slice, first, count) 1846 else 1847 raise TypeError, "can't convert #{args.first.class} into Integer" 1848 end 1849 when 2 1850 n, len = args 1851 unless n.is_a?(Numeric) || n.is_a?(OSX::NSNumber) 1852 raise TypeError, "can't convert #{n.class} into Integer" 1853 end 1854 unless len.is_a?(Numeric) || len.is_a?(OSX::NSNumber) 1855 raise TypeError, "can't convert #{len.class} into Integer" 1856 end 1857 _read_impl_num_len(slice, method, n.to_i, len.to_i, count) 1858 else 1859 raise ArgumentError, "wrong number of arguments (#{args.length} for 2)" 1860 end 1861 end 1862 1863 def _read_impl_num(slice, num, count) 1864 num += count if num < 0 1865 if 0 <= num && num < count 1866 result = objectAtIndex(num) 1867 removeObjectAtIndex(num) if slice 1868 result 1869 else 1870 nil 1871 end 1872 end 1873 1874 def _read_impl_range(slice, range, count) 1875 n, len = OSX::RangeUtil.normalize(range, count) 1876 if n < 0 || count < n 1877 return nil 1878 end 1879 1880 if 0 <= n && n < count 1881 nsrange = OSX::NSRange.new(n, len) 1882 indexes = OSX::NSIndexSet.indexSetWithIndexesInRange(nsrange) 1883 result = objectsAtIndexes(indexes).mutableCopy 1884 removeObjectsAtIndexes(indexes) if slice 1885 result 1886 else 1887 [].to_ns 1888 end 1889 end 1890 1891 def _read_impl_num_len(slice, method, num, len, count) 1892 if len < 0 1893 nil 1894 else 1895 num += count if num < 0 1896 if num < 0 1897 nil 1898 else 1899 _read_impl(method, [num...num+len]) 1900 end 1901 end 1902 end 1903 1904 # the behavior of Array#slice is different from 1.8.6 or earlier 1905 # against an out of range argument 1906 if RUBY_VERSION <= '1.8.6' 1907 def _read_impl_range(slice, range, count) 1908 n, len = OSX::RangeUtil.normalize(range, count) 1909 if n < 0 || count < n 1910 if slice 1911 # raises RangeError, 1.8.7 or later returns nil 1912 raise RangeError, "#{first} out of range" 1913 end 1914 return nil 1915 end 1916 1917 if 0 <= n && n < count 1918 nsrange = OSX::NSRange.new(n, len) 1919 indexes = OSX::NSIndexSet.indexSetWithIndexesInRange(nsrange) 1920 result = objectsAtIndexes(indexes).mutableCopy 1921 removeObjectsAtIndexes(indexes) if slice 1922 result 1923 else 1924 [].to_ns 1925 end 1926 end 1927 1928 def _read_impl_num_len(slice, method, num, len, count) 1929 if len < 0 1930 if slice 1931 # raises IndexError, 1.8.7 or later returns nil 1932 raise IndexError, "negative length (#{len})" 1933 end 1934 nil 1935 else 1936 num += count if num < 0 1937 if num < 0 1938 nil 1939 else 1940 _read_impl(method, [num...num+len]) 1941 end 1942 end 1943 end 1944 1945 end 1946 end 1947 1948 class NSArray 1949 include NSEnumerable 1950 end 1951 1952 # NSDictionary additions 1953 class NSDictionary 1954 include OSX::OCObjWrapper 1955 1956 def dup 1957 mutableCopy 1958 end 1959 1960 def clone 1961 obj = dup 1962 obj.freeze if frozen? 1963 obj.taint if tainted? 1964 obj 1965 end 1966 1967 # enable to treat as Hash 1968 def to_hash 1969 h = {} 1970 each {|k,v| h[k] = v } 1971 h 1972 end 1973 1974 # comparison between Ruby Hash and Cocoa NSDictionary 1975 def ==(other) 1976 if other.is_a? OSX::NSDictionary 1977 isEqualToDictionary?(other) 1978 elsif other.respond_to? :to_hash 1979 to_hash == other.to_hash 1980 else 1981 false 1982 end 1983 end 1984 1985 def <=>(other) 1986 if other.respond_to? :to_hash 1987 to_hash <=> other.to_hash 1988 else 1989 nil 1990 end 1991 end 1992 1993 # For NSDictionary duck typing 1994 def each 1995 iter = keyEnumerator 1996 while key = iter.nextObject 1997 yield [key, objectForKey(key)] 1998 end 1999 self 2000 end 2001 2002 def each_pair 2003 iter = keyEnumerator 2004 while key = iter.nextObject 2005 yield key, objectForKey(key) 2006 end 2007 self 2008 end 2009 2010 def each_key 2011 iter = keyEnumerator 2012 while key = iter.nextObject 2013 yield key 2014 end 2015 self 2016 end 2017 2018 def each_value 2019 iter = objectEnumerator 2020 while obj = iter.nextObject 2021 yield obj 2022 end 2023 self 2024 end 2025 2026 def [](key) 2027 result = objectForKey(key) 2028 if result 2029 result 2030 else 2031 default(key) 2032 end 2033 end 2034 2035 def []=(key, obj) 2036 setObject_forKey(obj, key) 2037 obj 2038 end 2039 alias_method :store, :[]= 2040 2041 def clear 2042 removeAllObjects 2043 self 2044 end 2045 2046 def default(*args) 2047 if args.length <= 1 2048 if @default_proc 2049 @default_proc.call(self, args.first) 2050 elsif @default 2051 @default 2052 else 2053 nil 2054 end 2055 else 2056 raise ArgumentError, "wrong number of arguments (#{args.length} for 2)" 2057 end 2058 end 2059 2060 def default=(value) 2061 @default = value 2062 end 2063 2064 def default_proc 2065 @default_proc 2066 end 2067 2068 def default_proc=(value) 2069 @default_proc = value 2070 end 2071 2072 def delete(key) 2073 obj = objectForKey(key) 2074 if obj 2075 removeObjectForKey(key) 2076 obj 2077 else 2078 if block_given? 2079 yield key 2080 else 2081 nil 2082 end 2083 end 2084 end 2085 2086 def delete_if(&block) 2087 reject!(&block) 2088 self 2089 end 2090 2091 def fetch(key, *args) 2092 result = objectForKey(key) 2093 if result 2094 result 2095 else 2096 if args.length > 0 2097 args.first 2098 elsif block_given? 2099 yield key 2100 else 2101 raise IndexError, "key not found" 2102 end 2103 end 2104 end 2105 2106 def reject! 2107 keys = [].to_ns 2108 each {|key,value| keys.addObject(key) if yield key, value } 2109 if keys.count > 0 2110 removeObjectsForKeys(keys) 2111 self 2112 else 2113 nil 2114 end 2115 end 2116 2117 def empty? 2118 count == 0 2119 end 2120 2121 def has_key?(key) 2122 objectForKey(key) != nil 2123 end 2124 alias_method :include?, :has_key? 2125 alias_method :key?, :has_key? 2126 alias_method :member?, :has_key? 2127 2128 def has_value?(value) 2129 each_value {|i| return true if i.isEqual?(value) } 2130 false 2131 end 2132 alias_method :value?, :has_value? 2133 2134 def invert 2135 dic = {}.to_ns 2136 each_pair {|key,value| dic[value] = key } 2137 dic 2138 end 2139 2140 def key(val) 2141 each_pair {|key,value| return key if value.isEqual?(val) } 2142 nil 2143 end 2144 2145 def keys 2146 allKeys 2147 end 2148 2149 def merge(other, &block) 2150 dic = mutableCopy 2151 dic.merge!(other, &block) 2152 dic 2153 end 2154 2155 def merge!(other) 2156 if block_given? 2157 other.each do |key,value| 2158 if mine = objectForKey(key) 2159 setObject_forKey((yield key, mine, value), key) 2160 else 2161 setObject_forKey(value,key) 2162 end 2163 end 2164 else 2165 other.each {|key,value| setObject_forKey(value, key) } 2166 end 2167 self 2168 end 2169 alias_method :update, :merge! 2170 2171 def shift 2172 if empty? 2173 default 2174 else 2175 key = allKeys.objectAtIndex(0) 2176 value = objectForKey(key) 2177 removeObjectForKey(key) 2178 [key, value].to_ns 2179 end 2180 end 2181 2182 def count 2183 oc_count 2184 end 2185 def size 2186 count 2187 end 2188 alias_method :length, :size 2189 2190 def rehash; self; end 2191 2192 def reject(&block) 2193 to_hash.delete_if(&block) 2194 end 2195 2196 def replace(other) 2197 setDictionary(other) 2198 self 2199 end 2200 2201 def values 2202 allValues 2203 end 2204 2205 def values_at(*args) 2206 result = [] 2207 args.each do |k| 2208 if v = objectForKey(k) 2209 result << v 2210 else 2211 result << default 2212 end 2213 end 2214 result.to_ns 2215 end 2216 2217 def inspect 2218 "#<#{self.class.to_s.gsub(/^OSX::/, '')} #{ self.to_hash.inspect }>" 2219 end 2220 2221 def pretty_print(q) 2222 self.to_hash.pretty_print(q) 2223 end 2224 end 2225 class NSDictionary 2226 include NSEnumerable 2227 end 2228 2229 class NSUserDefaults 2230 def [] (key) 2231 self.objectForKey(key) 2232 end 2233 2234 def []= (key, obj) 2235 self.setObject_forKey(obj, key) 2236 end 2237 2238 def delete (key) 2239 self.removeObjectForKey(key) 2240 end 2241 end 2242 2243 # NSData additions 2244 class NSData 2245 def rubyString 2246 cptr = self.bytes 2247 return cptr.bytestr( self.length ) 2248 end 2249 end 2250 2251 # NSIndexSet additions 2252 class NSIndexSet 2253 def to_a 2254 result = [] 2255 index = self.firstIndex 2256 until index == OSX::NSNotFound 2257 result << index 2258 index = self.indexGreaterThanIndex(index) 2259 end 2260 return result 2261 end 2262 2263 def inspect 2264 "#<#{self.class.to_s.gsub(/^OSX::/, '')} #{ self.to_a.inspect }>" 2265 end 2266 end 2267 2268 # NSSelectionArray additions 2269 class NSSelectionArray 2270 # workdaround for Tiger 2271 def to_a 2272 ary = [] 2273 (0...count).each {|i| ary << objectAtIndex(i) } 2274 ary 2275 end 2276 end 2277 2278 # NSEnumerator additions 2279 class NSEnumerator 2280 def to_a 2281 self.allObjects.to_a 2282 end 2283 end 2284 2285 # NSNumber additions 2286 class NSNumber 2287 def to_i 2288 self.stringValue.to_s.to_i 2289 end 2290 2291 def to_f 2292 self.doubleValue 2293 end 2294 2295 def float? 2296 warn "#{caller[0]}: 'NSNumber#float?' is now deprecated and its use is discouraged, please use integer? instead." 2297 OSX::CFNumberIsFloatType(self) 2298 end 2299 2300 def integer? 2301 !OSX::CFNumberIsFloatType(self) 2302 end 2303 2304 def bool? 2305 OSX::CFGetTypeID(self) == OSX::CFBooleanGetTypeID() 2306 end 2307 2308 def ==(other) 2309 if other.is_a? NSNumber 2310 isEqualToNumber?(other) 2311 elsif other.is_a? Numeric 2312 if integer? 2313 to_i == other 2314 else 2315 to_f == other 2316 end 2317 else 2318 false 2319 end 2320 end 2321 2322 def <=>(other) 2323 if other.is_a? NSNumber 2324 compare(other) 2325 elsif other.is_a? Numeric 2326 if integer? 2327 to_i <=> other 2328 else 2329 to_f <=> other 2330 end 2331 else 2332 nil 2333 end 2334 end 2335 2336 def inspect 2337 if bool? 2338 "#<#{self.class.to_s.gsub(/^OSX::/, '')} #{ (self == 1) ? true : false }>" 2339 else 2340 "#<#{self.class.to_s.gsub(/^OSX::/, '')} #{self.description}>" 2341 end 2342 end 2343 end 2344 2345 # NSCFBoolean additions 2346 class NSCFBoolean 2347 def inspect 2348 "#<#{self.class.to_s.gsub(/^OSX::/, '')} #{ (self == 1) ? true : false }>" 2349 end 2350 end 2351 2352 # NSDate additions 2353 class NSDate 2354 def to_time 2355 Time.at(self.timeIntervalSince1970) 2356 end 2357 def inspect 2358 "#<#{self.class.to_s.gsub(/^OSX::/, '')} #{self.description}>" 2359 end 2360 end 2361 2362 # NSObject additions 2363 class NSObject 2364 def to_ruby 2365 case self 2366 when OSX::NSDate 2367 self.to_time 2368 when OSX::NSCFBoolean 2369 self.boolValue 2370 when OSX::NSNumber 2371 if self.bool? 2372 self == 1 2373 elsif self.integer? 2374 self.to_i 2375 else 2376 self.to_f 2377 end 2378 when OSX::NSString 2379 self.to_s 2380 when OSX::NSAttributedString 2381 self.string.to_s 2382 when OSX::NSArray 2383 self.to_a.map { |x| x.is_a?(OSX::NSObject) ? x.to_ruby : x } 2384 when OSX::NSDictionary 2385 h = {} 2386 self.each do |x, y| 2387 x = x.to_ruby if x.is_a?(OSX::NSObject) 2388 y = y.to_ruby if y.is_a?(OSX::NSObject) 2389 h[x] = y 2390 end 2391 h 2392 else 2393 self 2394 end 2395 end 2396 end 2397end 2398 2399OSX._ignore_ns_override = false 2400