I have a name spaced class..
"CommonCar::RedTrunk"
I need to convert it to an underscored string "common_car_red_trunk"
, but when I use
"CommonCar::RedTrunk".underscore
, I get "common_car/red_trunk"
instead.
Is there another method to accomplish what I need?
"CommonCar::RedTrunk".gsub(':', '').underscore
or:
"CommonCar::RedTrunk".sub('::', '').underscore
or:
"CommonCar::RedTrunk".tr(':', '').underscore
Or turn any of these around and do the underscore()
first, followed by whatever method you want to use to replace "/" with "_".
While all of these methods look basically the same, there are subtle differences that can be very impactful.
In short:
gsub()
– uses a regex to do pattern matching, therefore, it's finding any occurrence of ":"
and replacing it with ""
.
sub()
– uses a regex to do pattern matching, similarly to gsub()
, with the exception that it's only finding the first occurrence (the "g" in gsub()
meaning "global"). This is why when using that method, it was necessary to use "::"
, otherwise a single ":"
would have been left. Keep in mind with this method, it will only work with a single-nested namespace. Meaning "CommonCar::RedTrunk::BigWheels"
would have been transformed to "CommonCarRedTrunk::BigWheels"
.
tr()
– uses the string parameters as arrays of single character replacments. In this case, because we're only replacing a single character, it'll work identically to gsub()
. However, if you wanted to replace "on" with "EX", for example, gsub("on", "EX")
would produce "CommEXCar::RedTrunk"
while tr("on", "EX")
would produce "CEmmEXCar::RedTruXk"
.
https://apidock.com/ruby/String/gsub
https://apidock.com/ruby/String/sub
https://apidock.com/ruby/String/tr
This is a pure-Ruby solution.
r = /(?<=[a-z])(?=[A-Z])|::/
"CommonCar::RedTrunk".gsub(r, '_').downcase
#=> "common_car_red_trunk"
See (the first form of) String#gsub and String#downcase.
The regular expression can be made self-documenting by writing it in free-spacing mode:
r = /
(?<=[a-z]) # assert that the previous character is lower-case
(?=[A-Z]) # assert that the following character is upper-case
| # or
:: # match '::'
/x # free-spacing regex definition mode
(?<=[a-z])
is a positive lookbehind; (?=[A-Z])
is a positive lookahead.
Note that /(?<=[a-z])(?=[A-Z])/
matches an empty ("zero-width") string. r
matches, for example, the empty string between 'Common'
and 'Car'
, because it is preceeded by a lower-case letter and followed by an upper-case letter.
I don't know Rails but I'm guessing you could write
"CommonCar::RedTrunk".delete(':').underscore
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With