Clojurescript advanced compilation unreachable-code - clojurescript

I have just added a new library(https://github.com/ptaoussanis/tempura/blob/master/README.md ) to my Clojurescript project.
WARNING: /matter/titan/source/titan-ui/out/taoensso/tempura/impl.js:96: WARNING - unreachable code}catch (e20422){if((e20422 instanceof Error)){
I also get this error :
Use of undeclared Var goog.structs/Map
(def ^:private coerce-xhr-params "Returns [<uri> <?data>]"
(let [url-encode
(fn url-encode
([params]
(when (seq params)
(-> params clj->js gstructs/Map. gquery-data/createFromMap .toString)))
^---
([uri params]
(let [qstr (url-encode params)
uri-with-query (if (str/blank? qstr) uri (str uri "?" qstr))]
[uri-with-query nil])))
Do I need to write an 'extern' for this? What does that look like?

It's hard to tell from your code and question details, but I assume you're having trouble with library call in advanced compilation mode.
The modern simple way is to skip externs thing altogether and just write calls/gets not in interop form, but by using https://github.com/binaryage/cljs-oops library.
You won't have to do anything else then - all your code will survive advanced compilation by default, no externs needed!
e.g. (.-nativeProp obj) would look like (oget obj "nativeProp"), and ocall is used for function calls correspondingly.

Related

How to catch parse errors in Lucerne (common lisp)

I'm trying to build a simple rest api in Lucerne, but the clack:call method fails if the json is malformed. So, I extended the bass-app class and added an around method:
(defclass tracker-app (base-app) ()
(:documentation "An extension of lucerne's base app to control behavior"))
(defmethod clack:call :around ((app tracker-app) env)
(handler-case (call-next-method)
(fast-http:cb-message-complete (e)
(vom:error "could not build message body: ~a" e)
(respond nil :status 400))
(:no-error (res) res)))
(defapp server :class 'tracker-app)
(start server :server woo)
But the parse error continues to crash the server.
I don't know much about clos, so I'm worried I've misunderstood how to catch errors in this context.
Edit: Added start information
Edit: Added stack trace
Assuming *features* does not contain :catch-any-error, here is a complete test case:
(ql:quickload :lucerne)
(defpackage :so.lucerne (:use :cl :lucerne))
(in-package :so.lucerne)
(defclass tracker-app (base-app) ()
(:documentation "An extension of lucerne's base app to control behavior"))
(defmethod clack:call :around ((app tracker-app) env)
(handler-case (call-next-method)
(fast-http:cb-message-complete (e)
(warn "could not build message body: ~a" e)
(respond nil :status 400))
#+catch-any-error
(error (e) (break "BREAK with ~a" e))
(:no-error (res) res)))
(defmethod clack:call ((app tracker-app) env)
(error "Oh No"))
(defapp server :class 'tracker-app)
(start server :server :woo)
When I try to load localhost:8000, the following error is shown:
Callback Error: the message-complete callback failed
Oh No
[Condition of type FAST-HTTP.ERROR:CB-MESSAGE-COMPLETE]
Pressing Enter on [Condition of type FAST-HTTP.ERROR:CB-MESSAGE-COMPLETE] gives:
#<FAST-HTTP.ERROR:CB-MESSAGE-COMPLETE {10048315C3}>
--------------------
The object is a CONDITION of type FAST-HTTP.ERROR:CB-MESSAGE-COMPLETE.
FORMAT-CONTROL: NIL
FORMAT-ARGUMENTS: NIL
DESCRIPTION: "the message-complete callback failed"
ERROR: #<SIMPLE-ERROR "Oh No" {1004831583}>
The error wraps another error.
Now if I (push :catch-any-error *features*) and recompile the above method, the same test makes the code reach the (break ...) statement, which is shown as BREAK with Oh No.
Explanation
No fast-http:cb-message-complete is caught, and in fact no such condition is signaled at this point; instead at this location we only can catch the specific error that was signaled. It is only higher up in the call stack that errors are wrapped inside fast-http:cb-message-complete errors.
Solution
In your case you can directly catch jonathan.error:<jonathan-error> (unusual naming convention, but ok), the base class of all errors in the jonathan library (you could catch the specific error type, but then you risk missing some other cases).
[This answer is wrong: fast-http.error:cb-message-complete & fast-http:cb-message-complete seem to be the same symbol. I am leaving it here for posterity.]
You are not handling the right condition (and in fact I'm not sure you're handling a condition which exists at all, which I'd expect the system to have warned about perhaps, although perhaps it can't).
You need to handle fast-http.error:cb-message-complete, but your handler specifies fast-http:cb-message-complete. The first of these is a condition (defined here, while the second is I think implicitly define here and is not a condition but the name of a function I think.
A more general trick is to try to handle some much-too-general error: you will probably end up handling things you don't know how to handle, but if your handler gets invoked you know that the call stack looks like you think it does when the error is signalled. Then you can start handling the errors you actually care about. In this case that probably means fast-http.error:callback-error I think.

Why do js functions fail when I assign them to a local variable?

In clojurescript 1.9.89 and Chrome 50.0.2661.102, I can create a log statement like:
(js/console.log "works")
But I can't create one like:
(def brokenlog js/console.log)
(brokenlog "but not here")
--> #object[TypeError TypeError: Illegal invocation]
When I try to compare these approaches by printing the value of my own brokenlog function, it looks just like the "real one" -- that is, both brokenlog and js/console.log evaluate for me as:
#object[log "function log() { [native code] }"]
Similarly, I see this behavior with:
cljs.user=> (js/document.querySelector "body")
#object[HTMLBodyElement [object HTMLBodyElement]]
cljs.user=> (def l js/document.querySelector)
#'cljs.user/l
cljs.user=> (l "body")
#object[TypeError TypeError: Illegal invocation]
nil
Upgrading to Chrome 52 fixes the console.log behavior, but not the document.querySelector behavior.
So I have two questions:
1. What am I missing
2. Where are the official docs I should be reading that would explain it?
Thanks!
Which browser and clojurescript version you are using?
the following code should work on your browser if it display nil into box.
.as-console-wrapper .as-console {
display: none;
}
<pre><code class="language-klipse">
(js/console.log "Work!")
(def brokenlog js/console.log)
(brokenlog "Work again!")
; two line should be seen in your browser log
</code></pre>
<script>
window.klipse_settings = {
selector: '.language-klipse', // css selector for the html elements you want to klipsify
};
</script>
<script src="http://app.klipse.tech/plugin/js/klipse_plugin.js?"></script>
<link href="http://app.klipse.tech/css/codemirror.css" rel="stylesheet"/>
EDIT
Here is the clojurescript
(ns hello-world.core)
(def mylog js/console.log)
(mylog "Hello")
compiled to javascript
hello_world.core.mylog = console.log;
hello_world.core.mylog.call(null,"Hello");
console.log.call(null, ....) trigger the chrome bug, console.log expecting this is the console object. It should be fixed as mentioned in the issue log https://bugs.chromium.org/p/chromium/issues/detail?id=167911.

Parsing JSON with Brightscript

I'm trying to parse JSON, based on the example here: http://blog.roku.com/developer/2012/07/16/json-support-comes-to-roku/
jsonAsString = ReadAsciiFile("pkg:/json/sample1.json")
m.json = ParseJSON(jsonAsString)
ShowPosterScreen(m.json.Videos, true)
I get this message in the debugger console:
Current Function:
057: Function LoadJSONFile() as void
058: jsonAsString = ReadAsciiFile("pkg:/json/sample1.json")
059: m.json = ParseJSON(jsonAsString)
060: ShowPosterScreen(m.json.Videos, true)
061: End Function
'Dot' Operator attempted with invalid BrightScript Component or interface reference. (runtime error &hec) in ...AALAE4Bk/pkg:/source/main.brs(60)
060: ShowPosterScreen(m.json.Videos, true)
Backtrace:
Function loadjsonfile() As
file/line: /tmp/plugin/D...AALAE4Bk/pkg:/source/main.brs(60)
Function handlebuttonpress(id As Integer) As
file/line: /tmp/plugin/D...AALAE4Bk/pkg:/source/main.brs(51)
Function main() As
file/line: /tmp/plugin/D...AALAE4Bk/pkg:/source/main.brs(26)
Local Variables:
global &h0020 rotINTERFACE:ifGlobal
m &h0010 bsc:roAssociativeArray, refcnt=4
jsonasstring &h8010 bsc:roString (2.1 was String), refcnt=1
BrightScript Debugger>
UPDATE: If I include a Makefile and zip the contents and load through development browser...it works. Not working when exporting through Eclipse.
That sounds like a bug in the Eclipse Brightscript plugin of some kind, most likely, in some way it is not loading the file containing your ShowPosterScreen function.
Please check the Roku Developer forum, at the very top is the section for discussion of the Eclipse Plugin. Here is a direct link.

Calling a ".done" JS callback

I'm having some trouble with wrapping a JS library because I can't get a .done callback to work correctly. In JavaScript the code would look like this:
db.values("inventory").done(function(item) {
console.log(item);
});
So I tried a couple (very dirty) ClojureScript methods to translate this:
(defn log []
(console/log "working?"))
(defn stock []
(#(.done % log) (.values db "inventory")))
and
(defn stock []
(js* "db.values('inventory').done(function(item) {
console.log(item);
})"))
but neither of these worked. The error message is always something like: db.values(...).done is not a function
Are there any protocol extensions (or anything else) that could be used here to cover the JS callback? Otherwise, can goog.async.Deferred somehow intercept the callback again?
maybe this helps you!
I've done from node but it must work from browser with a little details
First for the demo code I've prepared a mock js lib to simulate yours (my_api.js)
This is my_api.js
console.log("my_api.js");
var db={};
db.item="";
db.values=function(_string_){
db.item="loadign_"+_string_;
return this;
};
db.done=function(_fn_){
_fn_(db.item);
};
var api={hello:"ey ", db:db};
module.exports=api;
// your pretended chain calls
// db.values("inventory").done(function(item) {
// console.log(item);
// });
And from clojurescript code ...
(ns cljs-demo.hello)
(defn example_callback []
(let [my-api (js/require "./my_api") ; the api.js lib used for this example
db (aget my-api "db") ; this is your db object
my_fn (fn [item] ;this is your callback function
(println "printing from clojurescript" item)
)
]
(do
(-> db (.values "inventory") (.done my_fn)) ;; calling your js in a similar way you want in js
;; or
(.done (.values db "inventory_bis") my_fn) ;; calling nested form in the standar lisp manner
)
)
)
(set! *main-cli-fn* example_callback) ;default node function
And from console (node.js)
node your_output_node.js
And you'll obtain
printing from clojurescript loadign_inventory
printing from clojurescript loadign_inventory_bis
Good Luck,
Juan

Using hunchentoot to parse post request sent by model.save() in Backbone.js

I am a javascript/web application newbie and trying to implement my first web application using hunchentoot and backbone.js. The first thing I was experimenting is to understand how model.fetch() and model.save() work.
It seems to me that model.fetch() fires a "GET" request and model.save() fires a "POST" request instead. Therefore, I wrote a easy-handler in hunchentoot as below:
(hunchentoot:define-easy-handler (dataset-handler :uri "/dataset") ()
(setf (hunchentoot:content-type*) "text/html")
;; get the request type, canbe :get or :post
(let ((request-type (hunchentoot:request-method hunchentoot:*request*)))
(cond ((eq request-type :get)
(dataset-update)
;; return the json boject constructed by jsown
(jsown:to-json (list :obj
(cons "length" *dataset-size*)
(cons "folder" *dataset-folder*)
(cons "list" *dataset-list*))))
((eq request-type :post)
;; have no idea on what to do here
....))))
This is designed to handle the fetch/save of a model whose corresponding url is "/dataset". The fetch works fine, but I got really confused by the save(). I saw the "post" request fired and handled by the easy-handler, but the request seems to have only a meaningful header, I cannot find the actual json object hidden in the request. So my question is
How can I get the json object out of the post request fired by model.save(), so that later json library (e.g., jsown) can be used to parse it?
What should hunchentoot reply in order to let the client know that the "save" is successful?
I tried "post-parameters" function in hunchentoot and it returns nil, and didn't see many people using hunchentoot+backbone.js by googling. It is also helpful if you can direct me to some articles/blog posts that help understanding how the backbone.js save() works.
Thank you very much for your patience!
Thanks to wvxvw's comments, I found the solution to this question. The json object can be retrieved by calling hunchentoot:raw-post-data. To be more detailed, we first call (hunchentoot:raw-post-data :force-text t) to get the post data as a string, and then feed it to jsown:parse. A complete easy-handler is shown below:
(hunchentoot:define-easy-handler (some-handler :uri "/some") ()
(setf (hunchentoot:content-type*) "text/html")
(let ((request-type (hunchentoot:request-method hunchentoot:*request*)))
(cond ((eq request-type :get) ... );; handle get request
((eq request-type :post)
(let* ((data-string (hunchentoot:raw-post-data :force-text t))
(json-obj (jsown:parse data-string))) ;; use jsown to parse the string
.... ;; play with json-obj
data-string))))) ;; return the original post data string, so that the save() in backbone.js will be notified about the success.
Hope this helps others who have the same confusion.