203

I am trying to convert a name from snake case to camel case. Are there any built-in methods?

Eg: "app_user" to "AppUser"

(I have a string "app_user" I want to convert that to model AppUser).

Stefan
  • 109,145
  • 14
  • 143
  • 218
Lohith MV
  • 3,798
  • 11
  • 31
  • 44
  • Does this answer your question? [Converting camel case to underscore case in ruby](https://stackoverflow.com/questions/1509915/converting-camel-case-to-underscore-case-in-ruby) – Eyeslandic Aug 13 '20 at 22:11

10 Answers10

306

If you're using Rails, String#camelize is what you're looking for.

  "active_record".camelize                # => "ActiveRecord"
  "active_record".camelize(:lower)        # => "activeRecord"

If you want to get an actual class, you should use String#constantize on top of that.

"app_user".camelize.constantize
Hubro
  • 56,214
  • 69
  • 228
  • 381
Sergio Tulentsev
  • 226,338
  • 43
  • 373
  • 367
  • 48
    You should add that this is a Rails addition to String, it doesn't work with pure Ruby. – iGEL Mar 29 '13 at 21:49
  • 2
    It's tagged `ruby-on-rails`, so, I guess, it's not a problem. But thanks for mentioning. – Sergio Tulentsev Apr 24 '13 at 18:16
  • 7
    You don't need to camelize before constantizing. Use `#classify` instead. `"some_namespace/module/class_name".classify => "SomeNamespace::Module::ClassName"` – Chris Heald May 06 '13 at 23:14
  • 6
    @chris #classify: Not the same. #classify returns a string, whereas #constantize looks up constant in context (and does need camelize). 'active_record'.constantize gives error, 'active_record'.camelize.constantize returns the constant ActiveRecord, 'active_record'.classify returns the string 'ActiveRecord'. And if you did 'no_class'.camelize.constantize you'd get error (no such constant NoClass), but 'no_class'.classify happily returns 'NoClass' string. – Kanat Bolazar Apr 13 '15 at 22:10
  • 1
    In order to use these methods of Rails from pure Ruby, `require "active_support/core_ext/string"` is suffice, providing Rails is installed already. – Masa Sakano Jun 23 '18 at 02:03
143

How about this one?

"hello_world".split('_').collect(&:capitalize).join #=> "HelloWorld"

Found in the comments here: Classify a Ruby string

See comment by Wayne Conrad

Community
  • 1
  • 1
user3869936
  • 1,431
  • 1
  • 9
  • 2
51

If you use Rails, Use classify. It handles edge cases well.

"app_user".classify # => AppUser
"user_links".classify   # => UserLink

Note:

This answer is specific to the description given in the question(it is not specific to the question title). If one is trying to convert a string to camel-case they should use Sergio's answer. The questioner states that he wants to convert app_user to AppUser (not App_user), hence this answer..

Daniel Garmoshka
  • 5,849
  • 39
  • 40
Harish Shetty
  • 64,083
  • 21
  • 152
  • 198
26

Source: http://rubydoc.info/gems/extlib/0.9.15/String#camel_case-instance_method

For learning purposes:

class String
  def camel_case
    return self if self !~ /_/ && self =~ /[A-Z]+.*/
    split('_').map{|e| e.capitalize}.join
  end
end

"foo_bar".camel_case          #=> "FooBar"

And for the lowerCase variant:

class String
  def camel_case_lower
    self.split('_').inject([]){ |buffer,e| buffer.push(buffer.empty? ? e : e.capitalize) }.join
  end
end

"foo_bar".camel_case_lower          #=> "fooBar"
BenKoshy
  • 33,477
  • 14
  • 111
  • 80
Mr. Black
  • 11,692
  • 13
  • 60
  • 85
  • 7
    @pguardiario if the wheel is called *ActiveSupport*, please reinvent it. – shime Jan 11 '15 at 17:24
  • I think the lowerCase variant is wrong. The inject block should not directly manipulate the buffer but return the new value for the buffer: `self.split('_').inject([]){ |buffer,e| buffer + [buffer.empty? ? e : e.capitalize] }.join` – Sven Koschnicke Aug 24 '17 at 12:29
20

Benchmark for pure Ruby solutions

I took every possibilities I had in mind to do it with pure ruby code, here they are :

  • capitalize and gsub

    'app_user'.capitalize.gsub(/_(\w)/){$1.upcase}
    
  • split and map using & shorthand (thanks to user3869936’s answer)

    'app_user'.split('_').map(&:capitalize).join
    
  • split and map (thanks to Mr. Black’s answer)

    'app_user'.split('_').map{|e| e.capitalize}.join
    

And here is the Benchmark for all of these, we can see that gsub is quite bad for this. I used 126 080 words.

                              user     system      total        real
capitalize and gsub  :      0.360000   0.000000   0.360000 (  0.357472)
split and map, with &:      0.190000   0.000000   0.190000 (  0.189493)
split and map        :      0.170000   0.000000   0.170000 (  0.171859)
Ulysse BN
  • 10,116
  • 7
  • 54
  • 82
12

I got here looking for the inverse of your question, going from camel case to snake case. Use underscore for that (not decamelize):

AppUser.name.underscore # => "app_user"

or, if you already have a camel case string:

"AppUser".underscore # => "app_user"

or, if you want to get the table name, which is probably why you'd want the snake case:

AppUser.name.tableize # => "app_users"

mike
  • 219
  • 2
  • 9
  • Why not using `AppUser.table_name`? You will also ensure to have the true table name if it is not app_users, but something defined elsewhere. – Ulysse BN Aug 22 '18 at 07:51
4

I feel a little uneasy to add more answers here. Decided to go for the most readable and minimal pure ruby approach, disregarding the nice benchmark from @ulysse-bn. While :class mode is a copy of @user3869936, the :method mode I don't see in any other answer here.

  def snake_to_camel_case(str, mode: :class)
    case mode
    when :class
      str.split('_').map(&:capitalize).join
    when :method
      str.split('_').inject { |m, p| m + p.capitalize }
    else
      raise "unknown mode #{mode.inspect}"
    end
  end

Result is:

[28] pry(main)> snake_to_camel_case("asd_dsa_fds", mode: :class)
=> "AsdDsaFds"
[29] pry(main)> snake_to_camel_case("asd_dsa_fds", mode: :method)
=> "asdDsaFds"
akostadinov
  • 17,364
  • 6
  • 77
  • 85
  • 1
    Camel case is in fact first lower. Otherwise it is named PascalCase (or sometimes upper camel case). Even though in this question it is ambiguous! – Ulysse BN Mar 28 '18 at 18:23
  • 2
    @UlysseBN, tbh I'm not into history of the words. Wikipedia claims `PascalCase` is a subset of `CamelCase`. Also this is what I knew - that camel case applied to both. But I have never investigated. Thanks for mentioning PascalCase though. https://en.wikipedia.org/wiki/Camel_case – akostadinov Mar 28 '18 at 20:48
  • 2
    This is the best answer on the page imo. It would be nice if the `:method` version did a `downcase` first so it can be used on both `lower_snake_case` and `UPPER_SNAKE_CASE`. – skagedal Sep 29 '18 at 17:03
2

Extend String to Add Camelize

In pure Ruby you could extend the string class using code lifted from Rails .camelize

class String
  def camelize(uppercase_first_letter = true)
    string = self
    if uppercase_first_letter
      string = string.sub(/^[a-z\d]*/) { |match| match.capitalize }
    else
      string = string.sub(/^(?:(?=\b|[A-Z_])|\w)/) { |match| match.downcase }
    end
    string.gsub(/(?:_|(\/))([a-z\d]*)/) { "#{$1}#{$2.capitalize}" }.gsub("/", "::")
  end
end
Cameron Lowell Palmer
  • 21,528
  • 7
  • 125
  • 126
2

The ruby core itself has no support to convert a string from snake case to (upper) camel case (also known as pascal case).

So you need either to make your own implementation or use an existing gem.

There is a small ruby gem called lucky_case which allows you to convert a string from any of the 10+ supported cases to another case easily:

require 'lucky_case'

# to get upper camel case (pascal case) as string
LuckyCase.pascal_case('app_user') # => 'AppUser'
# to get the pascal case constant
LuckyCase.constantize('app_user') # => AppUser
# or the opposite way
LuckyCase.snake_case('AppUser')   # => app_user

You can even monkey patch the String class if you want to:

require 'lucky_case/string'

'app_user'.pascal_case # => 'AppUser'
'app_user'.constantize # => AppUser
# ...

Have a look at the offical repository for more examples and documentation:

https://github.com/magynhard/lucky_case

magynhard
  • 158
  • 7
0

Most of the other methods listed here are Rails specific. If you want do do this with pure Ruby, the following is the most concise way I've come up with (thanks to @ulysse-bn for the suggested improvement)

x="this_should_be_camel_case"
x.gsub(/(?:_|^)(\w)/){$1.upcase}
    #=> "ThisShouldBeCamelCase"
masukomi
  • 10,313
  • 10
  • 40
  • 49
  • Your definition of "camel case" is too limited. Class names in Java, and Ruby, for example, *are* camel case MyFavoriteClass... but they also don't have a lower cased initial letter. sometimes camel case has initial caps. sometimes it doesn't. – masukomi Mar 04 '16 at 17:00
  • Using 2 Regex where you can use only one is overkill. You can use only non capturing group: `x.gsub(/(?:_|^)(\w)/){$1.upcase}` – Ulysse BN Jun 26 '17 at 15:10
  • @UlysseBN, and we are back to your `gsub` solution it seems which is slower compared to the `map` solution. – akostadinov Mar 28 '18 at 18:02
  • It's not complicated: camelCase has a lowercase first character. PascalCase has an uppercase first character. I blame rails for having a camelize method which defaults to returning PascalCase. https://apidock.com/rails/String/camelize – Darren Hicks Feb 18 '21 at 00:11
  • While you may be technically or historically correct Darren, the community does not make that distinction. For example, Java class names have upper case first letters and, in almost every article / post that mentions it the convention is called "camel case", even those written long before Rails. Lower first letters are also described as "camel case" essentially everywhere. Both are "camel case" by the modern definition. – masukomi Mar 08 '21 at 18:39