Convertendo string de snake_case para CamelCase em Ruby

171

Estou tentando converter um nome de estojo de cobra para estojo de camelo. Existem métodos internos?

Por exemplo: "app_user"para"AppUser"

(Eu tenho uma string que "app_user"eu quero converter isso em modelo AppUser).

Lohith MV
fonte

Respostas:

251

Se você estiver usando o Rails, String # camelize é o que você está procurando.

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

Se você deseja obter uma classe real, use String # constantize em cima disso.

"app_user".camelize.constantize
Sergio Tulentsev
fonte
44
Você deve adicionar que esta é uma adição do Rails ao String, não funciona com Ruby puro.
iGEL 29/03
2
Está marcado ruby-on-rails, então, acho que não é um problema. Mas obrigado por mencionar.
Sergio Tulentsev
6
Você não precisa camelizar antes de se manter constante. Use em #classifyvez disso. "some_namespace/module/class_name".classify => "SomeNamespace::Module::ClassName"
Chris Heald
5
@chris #classify: Não é o mesmo. #classify retorna uma string, enquanto #constantize procura constante no contexto (e precisa camelize). 'active_record'.constantize fornece erro,' active_record'.camelize.constantize retorna a constante ActiveRecord, 'active_record'.classify retorna a string' ActiveRecord '. E se você tiver 'no_class'.camelize.constantize, obterá um erro (sem NoClass constante), mas' no_class'.classify retornará felizmente a string 'NoClass'.
Kanat Bolazar
Para usar esses métodos do Rails a partir do Ruby puro, require "active_support/core_ext/string"basta que o Rails já esteja instalado.
Masa Sakano
120

Que tal este?

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

Encontrado nos comentários aqui: Classifique uma string Ruby

Ver comentário de Wayne Conrad

user3869936
fonte
10
Você é demais, obrigado. Eu não queria incluir bibliotecas de trilhos apenas para uma tarefa tão pequena. Isso é lindo. :)
Gerry
11
Essa é uma das únicas respostas reais para a pergunta. Não usando bibliotecas do Rails.
Luis Ortega Araneda 16/09
40

Se você usa Rails, use classify. Ele lida bem com casos de borda.

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

Nota:

Esta resposta é específica para a descrição dada na pergunta (não é específica para o título da pergunta). Se alguém estiver tentando converter uma string em caixa de camelo, deve usar a resposta de Sergio . O interlocutor afirma que ele deseja converter app_userpara AppUser(não App_user), portanto, esta resposta ..

Harish Shetty
fonte
4
Para ambientes Rails, isso é perfeito.
Ghayes
Observe que classifyretorna uma string, você precisa chamar constantizedepois para convertê-la em uma classe real.
Stefan
1
Uma ressalva importante classifyé que as seqüências de caracteres pluralizadas se tornarão singulares ... 'age_in_years'.classifytornaAgeInYear
br3nt
@ br3nt não pluralizar desde activerecord4.2.11
Ulysse BN
23

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

Para fins de aprendizado:

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"

E para a variante lowerCase:

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"
Senhor preto
fonte
6
@pguardiario se a roda for chamada ActiveSupport , reinvente-a.
shime
Eu acho que a variante lowerCase está errada. O bloco de injectar não deve manipular directamente o tampão mas retornar o novo valor para o tampão:self.split('_').inject([]){ |buffer,e| buffer + [buffer.empty? ? e : e.capitalize] }.join
Sven Koschnicke
19

Referência para soluções Ruby puras

Eu tomei todas as possibilidades que eu tinha em mente para fazê-lo com código ruby ​​puro, aqui estão elas:

  • capitalizar e gsub

    'app_user'.capitalize.gsub(/_(\w)/){$1.upcase}
  • dividir e mapear usando &abreviação (graças à resposta do usuário3869936)

    'app_user'.split('_').map(&:capitalize).join
  • divisão e mapa (graças à resposta do Sr. Black)

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

E aqui está o Benchmark para todos esses, podemos ver que o gsub é muito ruim para isso. Eu usei 126 080 palavras.

                              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
fonte
11

Cheguei aqui procurando o inverso da sua pergunta, passando de estojo de camelo para estojo de cobra. Use sublinhado para isso (não decamelize):

AppUser.name.underscore # => "app_user"

ou, se você já tiver uma sequência de camel case:

"AppUser".underscore # => "app_user"

ou, se você deseja obter o nome da tabela, provavelmente é por isso que deseja o caso da cobra:

AppUser.name.tableize # => "app_users"

Mike
fonte
Por que não usar AppUser.table_name? Você também garantirá o nome da tabela verdadeira, se não for app_users, mas algo definido em outro lugar.
Ulysse BN
3

Sinto-me um pouco desconfortável ao adicionar mais respostas aqui. Decidiu optar pela abordagem de rubi puro mais legível e mínima, desconsiderando a boa referência do @ ulysse-bn. Embora :classmode seja uma cópia de @ user3869936, o :methodmodo que não vejo em nenhuma outra resposta aqui.

  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

O resultado é:

[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
fonte
1
O estojo de camelo é de fato o primeiro mais baixo. Caso contrário, chama-se PascalCase (ou às vezes maiúscula). Embora nesta questão seja ambíguo!
Ulysse BN
2
@UlysseBN, tbh Não conheço a história das palavras. As reivindicações da Wikipedia PascalCasesão um subconjunto de CamelCase. Também era isso que eu sabia - aquele estojo de camelo aplicado a ambos. Mas eu nunca investiguei. Obrigado por mencionar o PascalCase. pt.wikipedia.org/wiki/Camel_case
akostadinov 28/03
2
Esta é a melhor resposta na página imo. Seria bom se a :methodversão fizesse o downcaseprimeiro, para poder ser usada em ambos lower_snake_casee UPPER_SNAKE_CASE.
skagedal 29/09/18
0

A maioria dos outros métodos listados aqui é específica do Rails. Se você quiser fazer isso com Ruby puro, a seguir, é a maneira mais concisa que eu criei (obrigado a @ ulysse-bn pela melhoria sugerida)

x="this_should_be_camel_case"
x.gsub(/(?:_|^)(\w)/){$1.upcase}
    #=> "ThisShouldBeCamelCase"
masukomi
fonte
Sua definição de "estojo de camelo" é muito limitada. Os nomes de classe em Java e Ruby, por exemplo, são maiúsculas de minúsculas MyFavoriteClass ... mas também não possuem uma letra inicial em maiúscula. Às vezes, o estojo de camelo possui tampas iniciais. às vezes não.
Masukomi 4/03/16
Usar 2 Regex onde você pode usar apenas um é um exagero. Você pode usar apenas o grupo que não captura:x.gsub(/(?:_|^)(\w)/){$1.upcase}
Ulysse BN 26/06
@UlysseBN, e estamos de volta à sua gsubsolução, que parece ser mais lenta em comparação com a mapsolução.
akostadinov 28/03
0

Estender String para adicionar Camelize

No Ruby puro, você pode estender a classe de string usando exatamente o mesmo código do 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
fonte