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