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