Crystal: Add String::dasherize

Created on 2 Jun 2020  路  16Comments  路  Source: crystal-lang/crystal

For example:

"underscored_string".dashserize
# => "underscored-string"

I find myself needing this in macros and in runtime code in various situations throughout multiple projects. It works great in conjunction with underscore:

"LovelyClassName".underscore.dasherize
# => "lovely-class-name"

Doing string.dasherize instead of string.gsub(/_/, "-") is a lot more fun.

I wouldn't mind creating a PR for this.

feature discussion topictext

Most helpful comment

Also, the implementation of dasherize will be gsub('_', '-'), so there's no point in defining such shortcut in the standard library.

All 16 comments

I think underscore and camelcase work because with just those two, they're the inverse of each other. Adding dasherize adds a third leg here and thus confusion.

Should "FooBar".dasherize return "foo-bar"? Or "Foo-Bar"? Should "foo-bar".underscore return "foo_bar"? Should "foo-bar".camelcase return "FooBar"?

The answer is no because then we get into a total mess for things like "FooBar-baz_blub".{dasherize,underscore,camelcase}. But with dasherize in stdlib, either of those assumptions seem valid to me and thus it's not as clear anymore that .camelcase.underscore and .underscore.camelcase should roundtrip.

So I would vote against it :)

That's a very valid point. :) In the past, I have been confused by such situations before.

You probably meant kebab-case, which is like snake_case (or underscore) but with dashes.

I think the letter case doesn't matter for the purpose of the different _cases_, which is simply to separate words; the letter case should probably be kept in either of the three. For example, FooBar returns Foo-Bar, fooBar returns foo-Bar, Foo_bar returns Foo-bar, etc.
Then the user decides on whether to downcase, upcase, or capitalize as necessary.

It seems dasherize in Rails just turns underscores into dashes. That's... not what I expected.

I think adding dasherize with a meaning different than Rails might be confusing. And because it's simply replacing underscores with dashes, I think it's the same as doing .underscore.gsub('_', '-') which is probably more clear.

Also, the implementation of dasherize will be gsub('_', '-'), so there's no point in defining such shortcut in the standard library.

Maybe the method name could be kebaberize instead of dasherize to avoid confusion about their meaning.

I think my point is quite independent from how it's named :)

Agree @hugopl , the only thing is the method name sounds weird: "transform a string to a kebab?" 馃槄

There is already #camelcase, it looks ok to have #kebabcase then.

The implementation is not a good reason enough:

  • #kebabcase may be #underscore.gsub('_', '-')
  • or #underscore may be #kebabcase.gsub('-', '_')
  • or better, put the logic actually in #underscore in a private method, which takes in argument the delimiter a char (- or _), then call this method in both methods.

I meant, I agree that #dasherize may be ambiguous - but #kebabcase is not.

It doesn't change anything about my point. If "FooBar".kebabcase is "foo-bar", should "foo-bar".camelcase become "FooBar" instead of the current "Foo-bar"? Well no, that's not obvious, and an unnecessary breaking change on top of that. It just introduces inconsistency because you inherently can not make a bijective mapping among three functions.

@jhass actually I don't see any confusion if we add this method. Maybe I don't get your point, but let me explain. I mainly see these methods to be used when an identifier must be translated to other language conventions.

Should "FooBar".dasherize return "foo-bar"?

yes

Or "Foo-Bar"?

no, why? should we ask ourselves if "FooBar".underscore should return "Foo_Bar" then?

Should "foo-bar".underscore return "foo_bar"?

yes

Should "foo-bar".camelcase return "FooBar"?

yes

should "foo-bar".camelcase become "FooBar" instead of the current "Foo-bar"?

yes, I think the current behaviour is a bug, because languages commonly using camel case would not accept an identifier like Foo-bar.

I think the expected behaviour is split the original string in words (by dashes, underscores or case change) and reassemble, adjusting the case (dasherize and underscore always works with lowercase)

The current methods are not reversible either. For example:

"FooIO".underscore.camelcase # => "FooIo"
"Foo-Bar".underscore.camelcase # => "Foo-bar"

Are the rules that simple? "FOOBar".underscore # => "foo_bar", not "foob_ar". So yes, part of my argument was maybe a bit straw-man'ish, because the current methods already don't preserve case. I don't know, it already feels hard to follow and this is just adding to this complexity. I'm not sure that's worth it for something so easy to implement domain-specific as you need it. I wouldn't even mind to drop the existing methods.

That's true! is not that simple as I described and I forgot the current implementation takes that into account too. But at least for dashes and underscore it is simpler, and extending the algorithm shouldn't be so complex. But I'm saying this without actually looking at the code.

In hindsight, I have to agree it's adding confusion. But please, please don't let the existing methods go.

so.... this can be closed, right?

Was this page helpful?
0 / 5 - 0 ratings