[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

[rcr] String#first / String#last

Simon Strandgaard

10/24/2004 1:32:00 PM

problem:
I often use a range to extract the beginning/ending letters..
like this "string"[-4, 4] #-> "ring"
It feels somewhat redundant that I have to type the length 2 times.
A very simple operation that easily can confuse people if they
are browsing through others code.. this is a place where one easily can
introduce off-by-one errors.


motivation:
When looking at the Array class I see that it has #first and #last
methods.. just for this purpose, to extract the sub-array either
from the beginning or the ending.
Why not also use #first and #last on String ?


proposal:
"ruby".first(2) #=> "ru"
"ruby".last(3) #=> "uby"


implementation:
class String
def first(n=nil)
n ||= 1
raise TypeError, "cannot convert #{n.class} to Integer" unless n.kind_of?
(Integer)
raise ArgumentError, "negative string size" if n < 0
n = [n, self.size].min
self[0, n]
end
def last(n=nil)
n ||= 1
raise TypeError, "cannot convert #{n.class} to Integer" unless n.kind_of?
(Integer)
raise ArgumentError, "negative string size" if n < 0
n = [n, self.size].min
self[-n, n]
end
end


open questions:

Some encodings has variable length chars, where a char may
span between 1 and 5 bytes. This raises the question:
how should the argument to #first be interpreted?
should it interpret as bytes or chars?


Is this a good or a bad proposal?

--
Simon Strandgaard


29 Answers

ts

10/24/2004 1:38:00 PM

0

>>>>> "S" == Simon Strandgaard <neoneye@adslhome.dk> 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







T. Onoma

10/24/2004 1:47:00 PM

0

On Sunday 24 October 2004 09:32 am, Simon Strandgaard wrote:
| class String
|   def first(n=nil)
n = (n || 1).to_i
|     raise ArgumentError, "negative string size" if n < 0
|     n = [n, self.size].min
|     self[0, n]
|   end
|   def last(n=nil)
n = (n || 1).to_i
|     raise ArgumentError, "negative string size" if n < 0
|     n = [n, self.size].min
|     self[-n, n]
|   end
| end

Would you say that's better, or no?

Thanks,
T.



Shashank Date

10/24/2004 1:51:00 PM

0

Simon Strandgaard wrote:


> Is this a good or a bad proposal?

I will vote for it. May I propose aliasing left and right to first and
last?

> Simon Strandgaard
-- shanko

Simon Strandgaard

10/24/2004 1:53:00 PM

0

On Sunday 24 October 2004 15:37, ts wrote:
> >>>>> "S" == Simon Strandgaard <neoneye@adslhome.dk> 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?

--
Simon Strandgaard


Simon Strandgaard

10/24/2004 2:42:00 PM

0

On Sunday 24 October 2004 15:54, Shashank Date wrote:
> Simon Strandgaard wrote:
> > Is this a good or a bad proposal?
>
> I will vote for it. May I propose aliasing left and right to first and
> last?


I have submitted this RCR here.. (and I have mentioned you idea)
http://rcrchive.net/rcr/...



On IRC, Florian Gross suggested to add #first= and #last=,
that works this way:

"string".last="foo" #=> "strfoo"

It seems as a good idea.

--
Simon Strandgaard


Florian Gross

10/24/2004 3:47:00 PM

0

Simon Strandgaard wrote:

> On IRC, Florian Gross suggested to add #first= and #last=,
> that works this way:
>
> "string".last="foo" #=> "strfoo"

That is what Christian Neukirchen suggested, in my opinion
"string".last="foo" should change the string to "strinfoo". That would
also allow "string".last *= 2 to work as expected.

Regards,
Florian Gross

Gavin Kistner

10/24/2004 3:53:00 PM

0

On Oct 24, 2004, at 7:54 AM, Shashank Date wrote:
> I will vote for it. May I propose aliasing left and right to first and
> last?

Given the presence of right-to-left languages in the world, and
possible some-day support for them, I think first/last is a better
choice.



T. Onoma

10/24/2004 4:08:00 PM

0

On Sunday 24 October 2004 09:52 am, Simon Strandgaard wrote:
| 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?

Yes, I think so, but this might be even more so,

begin
n = length.to_int
rescue NoMethodError
raise TypeError, "cannot convert #{length.class} to Integer"
end

also

| unless n.kind_of?(Integer)
| raise TypeError, "#{length.class}#to_int should return Integer"
| end

I don't think this is really needed, since such a bug would be worked out else
where. (That #to_int might be used usefully for something other then
returning an integer is extremely unlikely and thus not worth the check).

T.


ts

10/24/2004 4:13:00 PM

0

>>>>> "t" == trans (T Onoma) <transami@runbox.com> writes:

t> On Sunday 24 October 2004 09:52 am, Simon Strandgaard wrote:

t> | unless n.kind_of?(Integer)
t> | raise TypeError, "#{length.class}#to_int should return Integer"
t> | end

t> I don't think this is really needed, since such a bug would be worked out else
t> where. (That #to_int might be used usefully for something other then
t> returning an integer is extremely unlikely and thus not worth the check).

svg% ruby -e 'class A; def to_int() "a" end end; [1,2].first(A.new)'
-e:1:in `first': A#to_int should return Integer (TypeError)
from -e:1
svg%


Guy Decoux





Shashank Date

10/24/2004 4:26:00 PM

0

Gavin Kistner wrote:
> On Oct 24, 2004, at 7:54 AM, Shashank Date wrote:
>
>> I will vote for it. May I propose aliasing left and right to first and
>> last?
>
>
> Given the presence of right-to-left languages in the world, and possible
> some-day support for them, I think first/last is a better choice.

Hmmm... never thought of that. Nice catch, Gavin.
So, how about:

str.left(6)

should show the left 6 chars/codes of the string, regardless.

Another RCR then ?

-- shanko