Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Breaks on a clojure.lang.Keyword with a space in it #251

Closed
blak3mill3r opened this issue Aug 3, 2016 · 5 comments
Closed

Breaks on a clojure.lang.Keyword with a space in it #251

blak3mill3r opened this issue Aug 3, 2016 · 5 comments

Comments

@blak3mill3r
Copy link

for example

{:foobar 1
(keyword "Foo Bar") 2} ;; => {:foobar 1, :Foo Bar 2}

cannot be sent with sente, it'll complain of "Bad package" (map literal must contain even number of forms)

Is there a proper way to express that in EDN? It's valid in Clojure and ClojureScript

@danielcompton
Copy link
Collaborator

I highly doubt this is valid EDN. Looking at the printed output, there is no way to tell that Bar is part of the :Foo keyword. You can try printing and reading EDN and I expect you'll get an error there too. Clojure and ClojureScript have looser definitions of what can produce a keyword, than what can be represented in EDN. If you have a look on the Clojure mailing list, you can find this coming up now and again. You can try using the Transit packer if you haven't already, but I would recommend finding another way to represent this, perhaps just using string keys.

@blak3mill3r
Copy link
Author

Well, as far as I can tell, EDN is not formally specified...

edn-format/edn#56

You are correct that clojure.tools.reader.edn/read-string won't accept it:

(edn/read-string "{:Foo bar 3}") => throws

However, clojure.core/prn-str will produce it, and so will taoensso.encore/prn-edn

(clojure.core/prn-str {(keyword "Foo bar") 3}) ;; => "{:Foo bar 3}\n"
(taoensso.encore/pr-edn {(keyword "Foo bar") 3}) ;; => "{:Foo bar 3}"

(-> {(keyword "Foo bar") 3}
    taoensso.encore/pr-edn
    edn/read-string) ;; => throws exception

which is a recipe for pain... since I imagine it's a fairly common pattern. I ran into it because we read a clojure map from MongoDB and try to pass it over a websocket.

I think it'd be good if taoensso.encore/pr-edn would throw an exception instead, since edn/read-string will otherwise (and this will be more difficult to track down)

@blak3mill3r
Copy link
Author

Actually, it looks like the trouble is with clojure.core/pr itself:

(with-out-str (clojure.core/pr (keyword "Foo bar"))) ;; => ":Foo bar"

that doesn't seem right...

@danielcompton
Copy link
Collaborator

danielcompton commented Aug 3, 2016

See the previous discussions here:

http://stackoverflow.com/questions/11282806/clojure-map-key-with-spaces-in-the-key-name
https://groups.google.com/forum/#!topic/clojure/WvXYkvLoQhI
https://groups.google.com/d/msg/clojure/8xe1QYRqfE4/g12gmJSvviMJ

I highly recommend not trying to use keywords with spaces in them. You are liable to run into all sorts of strange issues if you keep going down this road, especially if you're wanting to transfer them between client and server. It looks like Transit supports it, but that doesn't mean that everything else in your app will. My recommendations, in order:

  1. Use string keys
  2. Use keys without spaces so you can use keywords in them
  3. Write some kind of intermediate parser which transforms the keys on the way in and out of Sente

@blak3mill3r
Copy link
Author

Thanks for this, @danielcompton.

For posterity: I switched to using sente's TransitPacker and that's working nicely.

I never intentionally created a keyword with a space in it... it does seem like a bad idea. However, since some libraries (monger in my case) default to converting keys from other formats into clojure keywords, they will sometimes produce keywords with spaces in them.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants