[Ruby] string.to_primitive and string.to_collection

Michael Judge mjudge at surveycomplete.com
Tue Oct 3 17:49:25 PDT 2006


I don't contribute to the mailing list often, but today I was working on 
a DSL and came up with an interesting pair of snippets for working with 
user data.

-----

Snippet 1: Convert a string to its most appropriate primitive type 
(i.e., string, integer or float.)

Examples:

  "12".to_primitive #=> 12
  "13.8".to_primitive #=> 13.8
  "abc".to_primitive #=> "abc"

Code:

  class String
    def to_primitive
      begin
        return Integer(self)
      rescue
        # Try next.
      end

      begin
        return Float(self)
      rescue
        # Try next.
      end     
     
      return self
    end
  end

-----

Snippet 2.  Convert a multi-line string into its most appropriate 
collection type (i.e., array or hash.)   For hashes, each line should 
fit the format: key. value or key: value.  (The key should be one word.)

How is this useful?  Well, you can fake a here-doc constructor for 
hashes and arrays.

Examples:

    # Hashes
    %{
      1. Angie
      2. David
      3. Google
      4. Elliott
      5. Michelle
      6. Stephen
      7. Cort
    }.to_collection

    => {5=>"Michelle", 6=>"Stephen", 1=>"Angie", 7=>"Cort", 2=>"David",
    3=>"Google", 4=>"Elliott"}

    # Arrays
     %{
      Angie
      David
      Google
      Elliott
      Michelle
      Stephen
      Cort
    }.to_collection

    => ["Angie", "David", "Google", "Elliott", "Michelle", "Stephen",
    "Cort"]

    # Real-world example:

    question "s2a" {
      label "What was the research you participated in about? (MARK ALL
    THAT APPLY.)"

      multiple %{
        1. Automobiles
        2. Arts and crafts products
        3. Office products
        4. Computers
        5. Food or beverages
        6. None of these     
      }
    }

    # method 'multiple' prefers a hash or array parameter.  It uses
    .to_collection to convert incoming strings.

Snippet Code:

    class String
      def to_collection
          hash_types = {}
          array_types = []
         
          self.each_line do |line|
            case line.strip!
              when /^([^\s\:\.]+)\s*[\:\.]\s*(.*?)$/
                hash_types[$1.to_primitive] = $2.to_primitive
              when ""
                # Ignore blank lines
              else
                array_types << line.to_primitive
            end
          end
         
          throw "hash and list styles intermixed" unless
    hash_types.empty? or array_types.empty?

          return '' if hash_types.empty? and array_types.empty?
          return hash_types unless hash_types.empty?
          return array_types unless array_types.empty?
        end
    end

-----

I'm always interested in easier ways to construct arrays and hashes 
inline.  If anyone has an alternate, I'd love to hear it.  It was only 
recently that I discovered %{} for multi-line strings.

(By the way, I did look into YAML.   The character escaping frightened 
me a little.)

-----

Michael Judge


More information about the Ruby mailing list