From: Rob Biedenharn Date: 2007-06-03T00:28:11+09:00 Subject: Re: Getting the last N bytes of a string: On Jun 2, 2007, at 10:07 AM, Lloyd Linklater wrote: > ok, I have a question now. In the original post, he wanted to cover > errors caused by undersized strings. I have been trying to grok the > "zen of ruby" from posts in here and I thought that writing Ruby-ish > code involves two things: 1. making it so that it reads as plain > English and 2. Letting Ruby do the work for you. > > I could do it easily enough in Pascal, for example: > > s := @s[length(s) - 10]; > > but then we need to check for length errors as mentioned before. > > Here comes the question, why was my approach wrong? I am assuming > that > it was horrible because no one even bothered to tell me that I was > being > a total goober by saying this: > > 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.reverse.slice(0..9).reverse > > I know that just having working code is not enough or we could use C# > and have done with it. How do we make it readable? How do we let > Ruby > do the work? > > It seems to me that approaches like str[/(.{1,10}\z)/] are neither > plain > language readable nor letting Ruby do the work as it seems that the > work > is in the coding. > > Assuming that all the variations work equally well, how does one > choose > which is the more "ruby like" in its approach? How can I tell which > approach is ugly and which is elegant? > > -- > Posted via http://www.ruby-forum.com/. Well, this is how Rails solves this in ActiveSupport vendor/rails/activesupport/lib/active_support/core_ext/string/access.rb module ActiveSupport #:nodoc: module CoreExtensions #:nodoc: module String #:nodoc: # Makes it easier to access parts of a string, such as specific characters and substrings. module Access #snip... # Returns the last character of the string or the last +limit + characters. # # Examples: # "hello".last # => "o" # "hello".last(2) # => "lo" # "hello".last(10) # => "hello" def last(limit = 1) (chars[(-limit)..-1] || self).to_s end end end end end Which is mixed into String by: vendor/rails/activesupport/lib/active_support/core_ext/string.rb require File.dirname(__FILE__) + '/string/inflections' require File.dirname(__FILE__) + '/string/conversions' require File.dirname(__FILE__) + '/string/access' require File.dirname(__FILE__) + '/string/starts_ends_with' require File.dirname(__FILE__) + '/string/iterators' require File.dirname(__FILE__) + '/string/unicode' class String #:nodoc: include ActiveSupport::CoreExtensions::String::Access include ActiveSupport::CoreExtensions::String::Conversions include ActiveSupport::CoreExtensions::String::Inflections include ActiveSupport::CoreExtensions::String::StartsEndsWith include ActiveSupport::CoreExtensions::String::Iterators include ActiveSupport::CoreExtensions::String::Unicode end So I'd venture to say that the Ruby Way is to simply open up the String class and give it a new method. Since there is already an Array#first that gives [1,2,3,4].first(2) => [1,2], it just seems right to match that with .last and move the pair onto String treating the individual characters like the elements of the Array. Although the longer-term would seem to be to reconcile the [] behavior with Ranges: >> "abcde"[0...3] => "abc" >> "abcde"[-3..-1] => "cde" >> "abcdefghijklmno"[-10..-1] => "fghijklmno" >> "abcdefghijklmno"[0...10] => "abcdefghij" >> "abcd"[0...10] => "abcd" >> "abcd"[-10..-1] => nil If only that were also "abcd". -Rob Rob Biedenharn http://agileconsultingllc.com Rob@AgileConsultingLLC.com