# De-camelcase a filename

**URL:** <https://www.ruby-forum.com/t/de-camelcase-a-filename/108232>\
**Category:** Ruby\
**Created:** [June 30, 2007, 7:34pm UTC](https://www.ruby-forum.com/t/de-camelcase-a-filename/108232 "2007-06-30T19:34:13Z")\
**Posts on this page:** 17\
**Page:** 1

<div class="post-metadata">

**Author:** ![ktheory](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/k/e480ec/32.png) [@ktheory](https://www.ruby-forum.com/u/ktheory)\
**Post date:** [June 30, 2007, 7:34pm UTC](https://www.ruby-forum.com/t/de-camelcase-a-filename/108232/1 "2007-06-30T19:34:13Z")

</div>

how can a take a string file name like MyTestCase.rb and change it to  
my\_test\_case.rb?

thanks

---

<div class="post-metadata">

**Author:** ![ktheory](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/k/e480ec/32.png) [@ktheory](https://www.ruby-forum.com/u/ktheory)\
**Post date:** [June 30, 2007, 7:43pm UTC](https://www.ruby-forum.com/t/de-camelcase-a-filename/108232/2 "2007-06-30T19:43:51Z")

</div>

On 6/30/07, Aaron S. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> how can a take a string file name like MyTestCase.rb and change it to  
> my\_test\_case.rb?

I’m a novice at Ruby, but this might help:

irb(main):013:0\> ‘MyTestCase’.gsub(/[A-Z]/) {  
irb(main):014:1\* |p| ‘\_’ + p.downcase  
irb(main):015:1\> }  
=\> “\_my\_test\_case”

then:

irb(main):020:0\> “\_my\_test\_case”[1…-1]  
=\> “my\_test\_case”

Veterans can provide more succinct ways though 🙂

Cheers,  
Swaroop

---

<div class="post-metadata">

**Author:** ![ktheory](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/k/e480ec/32.png) [@ktheory](https://www.ruby-forum.com/u/ktheory)\
**Post date:** [June 30, 2007, 8:34pm UTC](https://www.ruby-forum.com/t/de-camelcase-a-filename/108232/3 "2007-06-30T20:34:54Z")

</div>

> Veterans can provide more succinct ways though 🙂

I wouldn’t consider myself a veteran yet, but here’s how Rails does it:

camel\_cased\_word.to\_s.gsub(/::/, ‘/’).  
gsub(/([A-Z]+)([A-Z][a-z])/,’\1\_\2’).  
gsub(/([a-z\d])([A-Z])/,’\1\_\2’).  
tr("-", “\_”).  
downcase

That also changes :: to /, so it’s handy for translating a module name  
to a file path. It’s not exactly more succinct, but you can cut it down  
as you see fit.

Brett

---

<div class="post-metadata">

**Author:** ![ktheory](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/k/e480ec/32.png) [@ktheory](https://www.ruby-forum.com/u/ktheory)\
**Post date:** [June 30, 2007, 10:18pm UTC](https://www.ruby-forum.com/t/de-camelcase-a-filename/108232/4 "2007-06-30T22:18:05Z")

</div>

From: “Swaroop C H” [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)

> then:
> 
> irb(main):020:0\> “\_my\_test\_case”[1…-1]  
> =\> “my\_test\_case”

Here’s another way:

irb(main):078:0\> “FooBarBaz”.split(/(?=[A-Z])/).map{|w|  
w.downcase}.join(“\_”)  
=\> “foo\_bar\_baz”

Regards,

Bill

---

<div class="post-metadata">

**Author:** ![ktheory](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/k/e480ec/32.png) [@ktheory](https://www.ruby-forum.com/u/ktheory)\
**Post date:** [July 1, 2007, 12:55am UTC](https://www.ruby-forum.com/t/de-camelcase-a-filename/108232/5 "2007-07-01T00:55:00Z")

</div>

John J. wrote:

> On Jun 30, 2007, at 3:17 PM, Bill K. wrote:
> 
> > > =\> “\_my\_test\_case”
> > 
> > Regards,
> > 
> > Bill
> 
> Just be careful of any code that has dependencies on the camelCaps  
> version!  
> You might even write a conditional require statement to check for  
> both versions.

Thanks everyone!

---

<div class="post-metadata">

**Author:** ![ktheory](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/k/e480ec/32.png) [@ktheory](https://www.ruby-forum.com/u/ktheory)\
**Post date:** [July 1, 2007, 12:27am UTC](https://www.ruby-forum.com/t/de-camelcase-a-filename/108232/6 "2007-07-01T00:27:22Z")

</div>

On Jun 30, 2007, at 3:17 PM, Bill K. wrote:

> > =\> “\_my\_test\_case”
> 
> Regards,
> 
> Bill

Just be careful of any code that has dependencies on the camelCaps  
version!  
You might even write a conditional require statement to check for  
both versions.

---

<div class="post-metadata">

**Author:** ![ktheory](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/k/e480ec/32.png) [@ktheory](https://www.ruby-forum.com/u/ktheory)\
**Post date:** [July 2, 2007, 6:06pm UTC](https://www.ruby-forum.com/t/de-camelcase-a-filename/108232/7 "2007-07-02T18:06:51Z")

</div>

How about this:  
“FooBarBaz”.split(/(?=[A-Z])/).join(’\_’).downcase

---

<div class="post-metadata">

**Author:** ![ktheory](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/k/e480ec/32.png) [@ktheory](https://www.ruby-forum.com/u/ktheory)\
**Post date:** [July 2, 2007, 4:42pm UTC](https://www.ruby-forum.com/t/de-camelcase-a-filename/108232/8 "2007-07-02T16:42:59Z")

</div>

On Saturday, June 30 2007, Bill K. wrote:

> > irb(main):015:1\> }  
> > w.downcase}.join("\_") =\> “foo\_bar\_baz”  
> > After seeing this split -\> map -\> join in my scripts, I came up with  
> > smj:

class String  
def smj(s, j=s, &b)  
r = self.split(s).map(&b)  
j ? r.join(j) : r  
end  
end

So the above would become:  
“FooBarBaz”.smj(/(?=[A-Z])/, ‘\_’) { |w| w.downcase } #=\> “foo\_bar\_baz”

I love Pe…Ruby! I love Ruby!

-Ben Kudria

---

<div class="post-metadata">

**Author:** ![ktheory](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/k/e480ec/32.png) [@ktheory](https://www.ruby-forum.com/u/ktheory)\
**Post date:** [July 2, 2007, 6:42pm UTC](https://www.ruby-forum.com/t/de-camelcase-a-filename/108232/9 "2007-07-02T18:42:38Z")

</div>

From: “Roseanne Z.” [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)

> How about this:  
> “FooBarBaz”.split(/(?=[A-Z])/).join(‘\_’).downcase

Nice… (why didn’t I think of that 🙂

Regards,

Bill

---

<div class="post-metadata">

**Author:** ![ktheory](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/k/e480ec/32.png) [@ktheory](https://www.ruby-forum.com/u/ktheory)\
**Post date:** [July 2, 2007, 10:48pm UTC](https://www.ruby-forum.com/t/de-camelcase-a-filename/108232/10 "2007-07-02T22:48:06Z")

</div>

Aaron S. wrote:

> how can a take a string file name like MyTestCase.rb and change it to  
> my\_test\_case.rb?
> 
> thanks

Possibly overkill, but you can use ActiveSupport, it has this  
functionality built in:

irb(main):001:0\> require ‘rubygems’  
=\> true  
irb(main):002:0\> require ‘active\_support’  
=\> true  
irb(main):003:0\> “ThisIsATest”.underscore  
=\> “this\_is\_a\_test”

---

<div class="post-metadata">

**Author:** ![ktheory](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/k/e480ec/32.png) [@ktheory](https://www.ruby-forum.com/u/ktheory)\
**Post date:** [July 2, 2007, 7:44pm UTC](https://www.ruby-forum.com/t/de-camelcase-a-filename/108232/11 "2007-07-02T19:44:45Z")

</div>

On Jul 2, 2007, at 9:41 AM, Bill K. wrote:

> From: “Roseanne Z.” [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)
> 
> > How about this:  
> > “FooBarBaz”.split(/(?=[A-Z])/).join(‘\_’).downcase
> 
> Nice… (why didn’t I think of that 🙂

This is the cleanest I’ve come up with:

class String

# “FooBar”.snake\_case #=\> “foo\_bar”

def snake\_case  
gsub(/\B[A-Z]/, ‘\_&’).downcase  
end  
end

Cheers-

– Ezra Z.  
– Lead Rails Evangelist  
– removed\_email\_address@domain.invalid  
– Engine Y., Serious Rails Hosting  
– (866) 518-YARD (9273)

---

<div class="post-metadata">

**Author:** ![ktheory](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/k/e480ec/32.png) [@ktheory](https://www.ruby-forum.com/u/ktheory)\
**Post date:** [August 22, 2007, 9:01pm UTC](https://www.ruby-forum.com/t/de-camelcase-a-filename/108232/12 "2007-08-22T21:01:09Z")

</div>

On 8/22/07, Daniel B. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> > 
> 
> “CheckHostIP”.gsub(/\B[A-Z]/, ‘\_&’).downcase =\> “check\_host\_i\_p”
> 
> But I want “check\_host\_ip”. It’s probably a simple tweak, but I’m  
> having trouble finding it at the moment. Suggestions?
> 
> Thanks,
> 
> Dan

I guess there can be no general solution, I would like  
HostIP → host\_ip  
but  
AHostIP → a\_host\_ip

maybe you can use a dictonary of Uppercase Abbreviations as a  
preparatory step?

Robert

---

<div class="post-metadata">

**Author:** ![ktheory](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/k/e480ec/32.png) [@ktheory](https://www.ruby-forum.com/u/ktheory)\
**Post date:** [August 22, 2007, 8:40pm UTC](https://www.ruby-forum.com/t/de-camelcase-a-filename/108232/13 "2007-08-22T20:40:06Z")

</div>

On Jul 2, 11:42 am, Ezra Z. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> class String
> 
> # “FooBar”.snake\_case #=\> “foo\_bar”
> 
> def snake\_case  
> gsub(/\B[A-Z]/, ‘\_&’).downcase  
> end  
> end

Both of these solutions have a problem with back to back caps. For  
example:

“CheckHostIP”.gsub(/\B[A-Z]/, ‘\_&’).downcase =\> “check\_host\_i\_p”

But I want “check\_host\_ip”. It’s probably a simple tweak, but I’m  
having trouble finding it at the moment. Suggestions?

Thanks,

Dan

---

<div class="post-metadata">

**Author:** ![ktheory](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/k/e480ec/32.png) [@ktheory](https://www.ruby-forum.com/u/ktheory)\
**Post date:** [August 22, 2007, 9:07pm UTC](https://www.ruby-forum.com/t/de-camelcase-a-filename/108232/14 "2007-08-22T21:07:10Z")

</div>

Hi –

On Thu, 23 Aug 2007, Robert D. wrote:

> > > This is the cleanest I’ve come up with:
> 
> HostIP --\> host\_ip  
> but  
> AHostIP --\> a\_host\_ip

Here’s how ActiveSupport does it:

def underscore(camel\_cased\_word)  
camel\_cased\_word.to\_s.gsub(/::/, ‘/’).  
gsub(/([A-Z]+)([A-Z][a-z])/,’\1\_\2’).  
gsub(/([a-z\d])([A-Z])/,’\1\_\2’).  
tr("-", “\_”).  
downcase  
end

David

---

<div class="post-metadata">

**Author:** ![ktheory](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/k/e480ec/32.png) [@ktheory](https://www.ruby-forum.com/u/ktheory)\
**Post date:** [August 22, 2007, 10:05pm UTC](https://www.ruby-forum.com/t/de-camelcase-a-filename/108232/15 "2007-08-22T22:05:06Z")

</div>

On 8/22/07, David A. Black [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> > > > > > “FooBarBaz”.split(/(?=[A-Z])/).join(‘\_’).downcase  
> > > > > > end
> 
> ```
> camel_cased_word.to_s.gsub(/::/, '/').
> gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
> gsub(/([a-z\d])([A-Z])/,'\1_\2').
> tr("-", "_").
> downcase
> 
> ```
> 
> end
> 
> David

Sure that is quite clever, but it will e.g. fail on “AMACAddress”  
which I want to have as a\_mac\_address, well but that was a little side  
issue of Dan, I guess this is the best solution for OP’s problem.  
I just wanted to point Dan to the fact that he would need a dictionary.

Cheers

Robert

---

<div class="post-metadata">

**Author:** ![ktheory](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/k/e480ec/32.png) [@ktheory](https://www.ruby-forum.com/u/ktheory)\
**Post date:** [August 28, 2007, 2:35am UTC](https://www.ruby-forum.com/t/de-camelcase-a-filename/108232/16 "2007-08-28T02:35:46Z")

</div>

- Daniel B. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) (2007-08-22) schrieb:

> “CheckHostIP”.gsub(/\B[A-Z]/, ‘\_&’).downcase =\> “check\_host\_i\_p”

“CheckHostIP”.gsub(/\B[A-Z]+/, ‘\_&’).downcase =\> “check\_host\_ip”

mfg, simon … l

---

<div class="post-metadata">

**Author:** ![ktheory](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/k/e480ec/32.png) [@ktheory](https://www.ruby-forum.com/u/ktheory)\
**Post date:** [August 28, 2007, 5:52am UTC](https://www.ruby-forum.com/t/de-camelcase-a-filename/108232/17 "2007-08-28T05:52:58Z")

</div>

On Aug 22, 2007, at 12:35 PM, Daniel B. wrote:

> Both of these solutions have a problem with back to back caps. For  
> example:
> 
> “CheckHostIP”.gsub(/\B[A-Z]/, ‘\_&’).downcase =\> “check\_host\_i\_p”
> 
> But I want “check\_host\_ip”. It’s probably a simple tweak, but I’m  
> having trouble finding it at the moment. Suggestions?

cfp:~ \> cat a.rb  
require ‘rubygems’  
require ‘alib’

p(alib.util.snake\_case(“CheckHostIP”))

cfp:~ \> ruby a.rb  
“check\_host\_ip”

def snake\_case string  
return string unless string =~ %r/[A-Z]/  
string.reverse.scan(%r/[A-Z]+|[^A-Z]\*[A-Z]+?/).reverse.map{|  
word| word.reverse.downcase}.join ‘\_’  
end

kind regards.

a @ [http://drawohara.com/](http://drawohara.com/)
