clj-commons / camel-snake-kebab Goto Github PK
View Code? Open in Web Editor NEWA Clojure[Script] library for word case conversions
Home Page: https://clj-commons.org/camel-snake-kebab/
License: Eclipse Public License 1.0
A Clojure[Script] library for word case conversions
Home Page: https://clj-commons.org/camel-snake-kebab/
License: Eclipse Public License 1.0
This should remove the need for having both master
and stable
branches (which are confusing).
I would argue that a large percentage of those seeking this library are looking for a way to 'clojurefy' a map. I'm not sure how you feel about this, but it would be nice to add the map-keys function in the README.MD to the library itself.
Thoughts?
If we supply nil to a conversion function, it throws an AssertionError
(csk/->kebab-case-keyword nil)
Execution error (AssertionError) at camel-snake-kebab.core/->kebab-case-keyword (core.cljc:21).
Assert failed: (clojure.core/not (clojure.core/nil? s__20671__auto__))
(cske/transform-keys csk/->kebab-case-keyword {nil "bar"})
Execution error (AssertionError) at camel-snake-kebab.core/->kebab-case-keyword (core.cljc:21).
Assert failed: (clojure.core/not (clojure.core/nil? s__20671__auto__))
We had an issue in production where this happened w/ some unexpected input and since it is an Error and not an Exception some things we're not handled properly.
Does it make sense to return nil on nil input? This feels a bit more idiomatic clojure usage to me.
Error : An Error “indicates serious problems that a reasonable application should not try to catch.”
Exceptions : An Exception “indicates conditions that a reasonable application might want to catch.”
At the very least throwing IllegalArgumentException
or something may be better than an AssertionError
?
i am using this to convert camel case json to clojure kabab case keywords...
i have found that this conversion is extremely slow!
please offer memoized versions in this lib. :)
Latest version uploaded was 0.4.0
it seems.
Thanks for the lib! 😉
What do you think about extending the conversion functions to include a return type?
Something like:
(defn ->snake_case_keyword
[s]
(-> s name ->snake_case keyword)
(defn ->CamelCaseSymbol
[s]
(-> s name ->CamelCase symbol))
(defn ->kebab-case-string
[s]
(-> s name ->kebab-case))
It would be trivial to write a macro to make these conversions, and I would be happy to do it if you think it is a good idea. I keep running into cases where I need to do this moving in and out of databases.
In project.clj, the :license
:name
is "Eclipse Public License" but there are multiple versions.
https://spdx.org/licenses/ recommends the name "Eclipse Public License 1.0" as the official name.
Sometimes I need to convert keywords and environment variables to/from the Java system properties syntax that environ uses, eg:
:database-url -> DATABASE_URL -> database.url
Would be nice if this library had that option.
(let [s "word100word"]
(= (->snake_case (->kebab-case s))
"word100word"))
=> false
becaouse
(->kebab-case "word100word")
=> "word-100-word"
(->snake_case "word-100-word")
=> "word_100_word"
(->snake_case "word100word")
=> "word_100word"
In my opinion numbers case should be recognised as a case of the preceding word
Instead of returning the string unchanged, this
(camel-snake-kebab.core/->snake_case "a" :separator \a)
results in
NullPointerException
clojure.string/lower-case (string.clj:217)
clojure.string/lower-case (string.clj:213)
camel-snake-kebab.internals.misc/convert-case (misc.cljc:8)
camel-snake-kebab.internals.misc/convert-case (misc.cljc:5)
clojure.core/apply (core.clj:673)
clojure.core/apply (core.clj:660)
camel-snake-kebab.core/->snake-case/convert-case--1573--auto----1639 (core.cljc:20)
camel-snake-kebab.internals.alter-name/eval1554/fn--1555 (alter_name.cljc:11)
camel-snake-kebab.internals.alter-name/eval1535/fn--1536/G--1526--1543 (alter_name.cljc:4)
camel-snake-kebab.core/->snake-case (core.cljc:20)
camel-snake-kebab.core/->snake-case (core.cljc:20)
for a map such as { 1 {:a "b"} }
, calling transform-keys ->kebab-case-keyword
would throw an exception since it tries to symbolize the numerical key.
ClassCastException java.lang.Long cannot be cast to clojure.lang.Named clojure.core/name (core.clj:1587)
The desirable result is that numerical keys are kept in tact and only text keys are converted.
I'm using camel-snake-kebab in a cljs project. I get the following error:
WARNING: Use of undeclared Var camel-snake-kebab.internals.alter-name/alter-name
My project.
[org.clojure/clojurescript "0.0-2850" :scope "provided"]
[lein-cljsbuild "1.0.6-SNAPSHOT"]
(camel-snake-kebab.core/->PascalCase 1)
;; => java.lang.IllegalArgumentException: No implementation of method: :alter-name of protocol: #'camel-snake-kebab.internals.alter-name/AlterName found for class: java.lang.Long
What do you think of an implementation that will return the original number instead of an exception?
Running transform-keys
on a map clears its' meta-data
user=> (def m1 ^{:hello "world"} {:foo-bar 1})
#'user/m1
user=> (meta m1)
{:hello "world"}
user=> (-> (transform-keys ->camelCaseKeyword m1) meta)
nil
user=>
Upon inspection, the new 0.2.0 version of camel-snake-kebab on Clojars does not seem to contain the actual core.clj file (only macros.clj), probably due to a cljx packaging issue. Having never used the cljx toolset, I can't offer any quick solutions, but thought you should know.
Thanks for the neat library!
cljx, nrepl, clojurescript-test, etc. are declared as runtime dependencies in the deployed poms for at least 0.3.0 and 0.3.1. I'm not sure why.
0.1.3 seems to be having problems. 0.1.2 is fine.
$ lein deps
Retrieving camel-snake-kebab/camel-snake-kebab/0.1.3/camel-snake-kebab-0.1.3.jar from clojars
Could not find artifact camel-snake-kebab:camel-snake-kebab:jar:0.1.3 in central (http://repo1.maven.org/maven2/)
Could not transfer artifact camel-snake-kebab:camel-snake-kebab:jar:0.1.3 from/to clojars (https://clojars.org/repo/): Checksum validation failed, no checksums available from the repository
This could be due to a typo in :dependencies or network issues.
If you are behind a proxy, try setting the 'http_proxy' environment variable.
…in order to get rid of this warning:
WARNING!!! version ranges found for:
[camel-snake-kebab "0.3.1"] -> [com.keminglabs/cljx "0.4.0"] -> [org.clojars.trptcolin/sjacket "0.1.0.6"] -> [org.clojure/clojure "[1.3.0,)"]
Consider using [camel-snake-kebab "0.3.1" :exclusions [org.clojure/clojure]].
[camel-snake-kebab "0.3.1"] -> [com.keminglabs/cljx "0.4.0"] -> [org.clojars.trptcolin/sjacket "0.1.0.6"] -> [net.cgrand/regex "1.1.0"] -> [org.clojure/clojure "[1.2.0,)"]
Consider using [camel-snake-kebab "0.3.1" :exclusions [org.clojure/clojure]].
[camel-snake-kebab "0.3.1"] -> [com.keminglabs/cljx "0.4.0"] -> [org.clojars.trptcolin/sjacket "0.1.0.6"] -> [net.cgrand/parsley "0.9.1"] -> [org.clojure/clojure "[1.2.0,)"]
Consider using [camel-snake-kebab "0.3.1" :exclusions [org.clojure/clojure]].
[camel-snake-kebab "0.3.1"] -> [com.keminglabs/cljx "0.4.0"] -> [org.clojars.trptcolin/sjacket "0.1.0.6"] -> [net.cgrand/parsley "0.9.1"] -> [net.cgrand/regex "1.1.0"] -> [org.clojure/clojure "[1.2.0,)"]
Consider using [camel-snake-kebab "0.3.1" :exclusions [org.clojure/clojure]].
Your project's documentation explicitly recommends using :use
in the ns macro. There is no reason to use it over :require + :refer
. Please the latter as it is much less confusing to beginners and is also less likely to cause conflicts.
Any string that starts with an underscore or dash has the underscore or dash removed in the result.
ex:
(->kebab-case "_my_string") => "my-string"
(->kebab-case "-my-string") => "my-string"
ex of NullPointerException:
(->kebab-case "-") =throws=> NullPointerException java.lang.NullPointerException
(->kebab-case "_") =throws=> NullPointerException java.lang.NullPointerException
This is also true for any number of dashes or underscores:
(->kebab-case "__----__----") =throws=> NullPointerException java.lang.NullPointerException
Also, empty strings throw the same exception:
(csk/->kebab-case "") =throws=> NullPointerException java.lang.NullPointerException
Since they all send nil to clojure.string/lower-case instead of empty string or leaving the dashes and underscores intact
Should there be a counterpart to transform-keys
called transform-values
? This would apply t
to non-map leaves.
I have a current project where a kebabed value can appear both in key position and value position, so I need to transform it consistently.
I'm happy to submit a pull-request if this is something CSK is interested in.
Single-part Clojure namespaces have some issues when integrating with Java, because they're compiled into classes that lack a containing package. Consider a two-part namespace instead (e.g. camel-snake-kebab.core
or camel-snake-kebab.conversions
).
When converting
(->snake_case "XMLsettingsAndOtherThings")
"xm_lsettings_and_other_things"
Is there a way to convert it to "xml_settings_and_other_things"
Perhaps insert dashes on case change?
Hi there,
I'm a Cursive user and it would be really great to get commit 13dda807 into a release to prevent it complaining about undeclared symbols.
At the moment I'm using lein-git-down to fetch from github but this is non-ideal as it places requirements on consuming projects of any libraries.
Would it be possible to get a new release into maven or clojars?
Thanks,
Toby
Converting to plain text would be useful for constructing user messages e.g.
(defn validate-field [object attr]
(when-not (object attr)
(str (csk/->plain-text attr) " is mandatory")))
(validate-field user :work-email-address)
=> "Work email address is mandatory"
You'd probably need upper case, lower case, sentence case and title case.
Would love to have :kebab-case => "Kebab Case"
for display purposes.
I'm using camel-snake-kebab in a cljs (+Om) project and I'm having trouble when any type of error occurs (syntax error, etc, unrelated to using camel-snake-kebab). I get the following error in my browser:
Uncaught Error: Undefined nameToPath for camel_snake_kebab.core
and I'm unable to recompile using lein cljsbuild auto
. I have to completely rebuild the project to remove the error.
This bit us when using friend and its namespaced keywords:
cemerick.friend=> (->kebab-case ::identity)
;=> :identity
cemerick.friend=> ::identity
;=> :cemerick.friend/identity
cemerick.friend=> (= ::identity :identity)
;=> false
Of course we wouldn't do this directly, but there was a middleware kebab-casing all the request map keys, so we lost the keyword namespace information, making for some tricky debugging.
It would be nice if (->kebab-case :cemerick.friend/identity)
was just :cemerick.friend/identity
. Related:
cemerick.friend=> (->kebab-case "cemerick.friend/identity")
"cemerick-.friend-/identity"
I'm not sure if .
and /
should be treated specially or not, but I'm guessing this would affect any potential fix.
[camel-snake-kebab "0.3.1"] -> [com.keminglabs/cljx "0.4.0"] -> [org.clojars.trptcolin/sjacket "0.1.0.6"] -> [org.clojure/clojure "[1.3.0,)"]
Consider using [camel-snake-kebab "0.3.1" :exclusions [org.clojure/clojure]]
please in your project.clj exclude clojure from cljx
Expected
(->kebab-case-keyword :hmm.com/MonkeyFace)
=> :hmm.com/monkey-face
Actual
=> monkey-face
See:
> camel_snake_kebab.core.__GT_kebab_case("blah:1:blah");
"blah:-1:blah"
is this expected?
When using camel-snake-kebab
in clojurescript, running fighweel and tests at the same time i get this error:
Error refreshing environment: Syntax error compiling at (camel_snake_kebab/core.cljc:16:1).
The line specified is the first line where a conversion is defined with the defconversion
macro from camel-snake-kebab.macros
:
(defconversion "PascalCase" clojure.string/capitalize clojure.string/capitalize "")
I don't know the exact reason for why this fails, but it has something to do with the conversion functions being defined with a macro. Redefining the conversion functions with defn
and not requiring camel-snake-kebab-core
solves the issue for me:
(ns my-conversions
(:require [camel-snake-kebab.internals.misc :as csk-misc]
[camel-snake-kebab.extras :as cks-extras]
[camel-snake-kebab.internals.alter-name :refer [alter-name]]
[clojure.string :as string]))
(defn convert-case
[first-fn rest-fn sep s]
(alter-name s (partial csk-misc/convert-case first-fn rest-fn sep)))
(defn ->PascalCase [x] (convert-case string/capitalize string/capitalize "" x))
(defn ->Camel_Snake_Case [x] (convert-case string/capitalize string/capitalize "_" x))
(defn ->camelCase [x] (convert-case string/lower-case string/capitalize "" x))
(defn ->SCREAMING_SNAKE_CASE [x] (convert-case string/upper-case string/upper-case "_" x))
(defn ->snake_case [x] (convert-case string/lower-case string/lower-case "_" x))
(defn ->kebab-case [x] (convert-case string/lower-case string/lower-case "-" x))
(defn ->HTTP-Header-Case [x] (convert-case csk-misc/capitalize-http-header csk-misc/capitalize-http-header "_" x))
All of these are type preserving, but I don't see the need for defining explicit type converting functions like ->kebab-case-keyword
when you can just do (comp keyword ->kebab-case)
?
As far as I can tell this works the same as when using defconversion
, I might be missing something here though so please correct me if I'm wrong.
This isn't really a bug per-se with camel-snake-kebab (which is fab!) but I thought you should know that it doesn't deploy on Tomcat 6/7 or 8 with either JDK 6 or 7. It fails with NoClassDefFoundError:camel_snake_kebab/core$__GT_CamelCaseString(wrong name: camel_snake_kebab/core$__GT_camelCaseString)
.
EDIT: it also fails with the downloaded jetty distribution (i.e. building a war and dropping it into jetty/webapps).
Running it through lein repl works fine, it is just something funny with Tomcat and jetty. Thought you might like to know :).
The previous update took place on Oct 19, 2020; and since then there were five PRs, the last of which is essential for my codebase. Can you release a new version containing the latest PR? It will be much appreciated. @qerub
There's unexpected behavior when mixing numbers and characters on an identifier which is not demonstrated on any of the tests.
This makes sense:
(->kebab-case-keyword :user_id)
=> :user-id
(->kebab-case-keyword :user_1)
=> :user-1
But then...
(->kebab-case-keyword :user1_124)
=> :user-1-124
(->kebab-case-keyword :user1)
=> :user-1
It gets worse:
(->kebab-case-keyword :object1a2)
=> :object-1a-2
While I can see from the source this is the intended grouping behavior, this goes agains the principle of least surprise. I'm not sending a PR to change it since I expect it would break existing use (need to assume that someone, somewhere is relying on this).
Thoughts? What was the rationale behind this?
This looks related to #22.
I personally rather like bijections more than coercions.
E.g., if I have a web API that is supposed to accept snake case query params and I use ->kebab-case
to translate them to the codebase's internal format, then what I really have is an API that accepts snake case and kebab case and arbitrary combinations of the two. And this bothers me a bit.
Would it be welcome to add functions to this library that convert from one format to another and perhaps throw exceptions if the input is not in the expected format?
Converting with transform-keys using the clojure.core.bean function gives the error:
UnsupportedOperationException empty clojure.core.proxy$clojure.lang.APersistentMap$ff19274a.empty (:-1)
Here is an example:
$ clj -Sdeps "{:deps {camel-snake-kebab {:mvn/version "0.4.0"}}}"
Clojure 1.9.0
user=> (require ['camel-snake-kebab.core :refer :all])
nil
user=> (require ['camel-snake-kebab.extras :refer :all])
nil
(->> (java.util.Date.)
(bean)
(transform-keys ->kebab-case)
:timezone-offset)
UnsupportedOperationException empty clojure.core.proxy$clojure.lang.APersistentMap$ff19274a.empty (:-1)
Interestingly, transform-keys works fine if I use a map directly, but not from the results the bean function:
user=> (bean (java.util.Date.))
{:day 5, :date 8, :time 1528508211784, :month 5, :seconds 51, :year 118, :class java.util.Date, :timezoneOffset 300, :hours 20, :minutes 36}
user=> (transform-keys ->kebab-case-keyword {:day 5, :date 8, :time 1528508211784, :month 5, :seconds 51, :year 118, :class java.util.Date, :timezoneOffset 300, :hours 20, :minutes 36})
{:day 5, :date 8, :time 1528508211784, :month 5, :timezone-offset 300, :seconds 51, :year 118, :class java.util.Date, :hours 20, :minutes 36}
Is there any way to avoid numbers creating separators? Had a quick scan of the code but couldn't see an obvious workaround. Thanks.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.