KobbyAdarkwa
KobbyAdarkwa

Reputation: 181

Convert string to camel case in Ruby

Working on a Ruby challenge to convert dash/underscore delimited words into camel casing. The first word within the output should be capitalized only if the original word was capitalized (known as Upper Camel Case).

My solution so far..:

def to_camel_case(str)
str.split('_,-').collect.camelize(:lower).join 
end

However .camelize(:lower) is a rails method I believe and doesn't work with Ruby. Is there an alternative method, equally as simplistic? I can't seem to find one. Or do I need to approach the challenge from a completely different angle?

main.rb:4:in `to_camel_case': undefined method `camelize' for #<Enumerator: []:collect> (NoMethodError)
    from main.rb:7:in `<main>'

Upvotes: 0

Views: 3671

Answers (3)

Cary Swoveland
Cary Swoveland

Reputation: 110745

I assume that:

  • Each "word" is made up of one or more "parts".
  • Each part is made of up characters other than spaces, hypens and underscores.
  • The first character of each part is a letter.
  • Each successive pair of parts is separated by a hyphen or underscore.
  • It is desired to return a string obtained by modifying each part and removing the hypen or underscore that separates each successive pair of parts.
  • For each part all letters but the first are to be converted to lowercase.
  • All characters in each part of a word that are not letters are to remain unchanged.
  • The first letter of the first part is to remain unchanged.
  • The first letter of each part other than the first is to be capitalized (if not already capitalized).
  • Words are separated by spaces.

It this describes the problem correctly the following method could be used.

R = /(?:(?<=^| )|[_-])[A-Za-z][^ _-]*/
def to_camel_case(str)
  str.gsub(R) do |s|
    c1 = s[0]
    case c1
    when /[A-Za-z]/
      c1 + s[1..-1].downcase
    else
      s[1].upcase + s[2..-1].downcase
    end
  end
end
to_camel_case "Little Miss-muffet sat_on_HE$R Tuffett eating-her_cURDS And_whey"
  # => "Little MissMuffet satOnHe$r Tuffett eatingHerCurds AndWhey"

The regular expression is can be written in free-spacing mode to make it self-documenting.

R = /
    (?:         # begin non-capture group
      (?<=^| )  # use a positive lookbehind to assert that the next character
                # is preceded by the beginning of the string or a space
    |           # or
      [_-]      # match '_' or '-'
    )           # end non-capture group
    [A-Za-z]    # match a letter
    [^ _-]*     # match 0+ characters other than ' ', '_' and '-'
    /x          # free-spacing regex definition mode

Upvotes: 6

iGian
iGian

Reputation: 11193

In pure Ruby, no Rails, given str = 'my-var_name' you could do:

delimiters = Regexp.union(['-', '_'])
str.split(delimiters).then { |first, *rest| [first, rest.map(&:capitalize)].join }

#=> "myVarName"

Where str = 'My-var_name' the result is "MyVarName", since the first element of the splitting result is untouched, while the rest is mapped to be capitalized.

It works only with "dash/underscore delimited words", no spaces, or you need to split by spaces, then map with the presented method.


This method is using string splitting by delimiters, as explained here Split string by multiple delimiters, chained with Object#then.

Upvotes: 2

Casper
Casper

Reputation: 34338

Most Rails methods can be added into basic Ruby projects without having to pull in the whole Rails source.

The trick is to figure out the minimum amount of files to require in order to define the method you need. If we go to APIDock, we can see that camelize is defined in active_support/inflector/methods.rb.

Therefore active_support/inflector seems like a good candidate to try. Let's test it:

irb(main)> require 'active_support/inflector'
=> true
irb(main)> 'foo_bar'.camelize
=> "FooBar"

Seems to work. Note that this assumes you already ran gem install activesupport earlier. If not, then do it first (or add it to your Gemfile).

Upvotes: 2

Related Questions