From: Robert Klemme Date: 2004-10-25T17:24:07+09:00 Subject: Re: [rcr] String#first / String#last "Simon Strandgaard" schrieb im Newsbeitrag news:200410241739.14922.neoneye@adslhome.dk... > On Sunday 24 October 2004 15:37, ts wrote: > > >>>>> "S" == Simon Strandgaard writes: > > > > S> raise TypeError, "cannot convert #{n.class} to Integer" unless > > n.kind_of? S> (Integer) > > > > svg% ruby -e 'class A; def to_int() 2 end; end; p [1,2,3].first(A.new)' > > [1, 2] > > svg% > > > > > > Guy Decoux > > > Ok.. I think I have fixed this issue now. > > > irb(main):001:0> 'abc'.last(3) > => "abc" > irb(main):002:0> class A; def to_int; 2 end; end > => nil > irb(main):003:0> 'abc'.last(A.new) > => "bc" > irb(main):004:0> class B; def to_int; 'a' end; end > => nil > irb(main):005:0> 'abc'.last(B.new) > TypeError: B#to_int should return Integer > from ./a.rb:22:in `last' > from (irb):5 > irb(main):006:0> > > > > New implementation is here: > > class String > def first(length=nil) > length ||= 1 > unless length.respond_to?(:to_int) > raise TypeError, "cannot convert #{length.class} to Integer" > end > n = length.to_int > unless n.kind_of?(Integer) > raise TypeError, "#{length.class}#to_int should return Integer" > end > raise ArgumentError, "negative string size" if n < 0 > n = [n, self.size].min > self[0, n] > end > def last(length=nil) > length ||= 1 > unless length.respond_to?(:to_int) > raise TypeError, "cannot convert #{length.class} to Integer" > end > n = length.to_int > unless n.kind_of?(Integer) > raise TypeError, "#{length.class}#to_int should return Integer" > end > raise ArgumentError, "negative string size" if n < 0 > n = [n, self.size].min > self[-n, n] > end > end > > > btw: Is this better? I'd prefer class String def first(n) n = n.to_int raise ArgumentError, "negative string size" if n < 0 self[0,n] end def last(n) n = n.to_int raise ArgumentError, "negative string size" if n < 0 self[-n,n] || self[-length,length] end end Notes: - You don't need the type check for n because #to_int will throw if n does not have it. - You don't need the min in first, because String#[] takes care of that already. - A default value does not make sense IMHO, because with #first() (i.e. without arg) I'd expect to get the first character ("foo"[0]) which is something different). Kind regards robert