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?
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"
=> nil
If only that were also "abcd".
-Rob
Rob Biedenharn
http://agileconsultingllc.com
(e-mail address removed)