ClojureScript

Consider to export cljs.core.*print-fn*

Details

  • Type: Enhancement Enhancement
  • Status: Closed Closed
  • Priority: Trivial Trivial
  • Resolution: Completed
  • Affects Version/s: None
  • Fix Version/s: None
  • Component/s: None
  • Labels:
    None

Description

External tools often have the need to redefine ClojureScript's
cljs.core.print-fn var in order to get printing in different
runtimes working. In a browser environment it is usually
redefined to console.log for example.

This works fine in whitespace and simple mode because the
cljs.core.print-fn var is accessible from the outside
environment. However, in advanced mode the cljs.core.print-fn
gets renamed and external tools can't access this var anymore.

Since it looks like redefining cljs.core.print-fn is common
task, it would make sense to add ^:export to it's meta data to
prevent the Goolge Closure Compiler from renaming it.

References:

Activity

Hide
Roman Scherer added a comment -
Unfortunatly it's not that easy. Advanced compilation is quite a
beast. I added :export true to the meta data of *print-fn*, build a
ClojureScript release and put it into my local Maven repo. Changed the
ClojureScript version in clojurescript.test and recompiled. The var is
exported:

    function s() {
      d(Error("No *print-fn* fn set for evaluation environment"))
    }
   fa("cljs.core._STAR_print_fn_STAR_", s);                                                                                                                                                                                                                                                    

The fn "fa" is the goog/exportSymbol fn, which (i guess) builds up
some nested object and finally assigns "s" under the proper path.

    function fa(a, b) {
      var c = a.split("."), e = ba;                                                                                                                                                                                                                                                            
      !(c[0] in e) && e.execScript && e.execScript("var " + c[0]);                                                                                                                                                                                                                             
      for(var f;c.length && (f = c.shift());) {                                                                                                                                                                                                                                                
        !c.length && b !== g ? e[f] = b : e = e[f] ? e[f] : e[f] = {}
      }
    }  

Assigning cljs.core._STAR_print_fn_STAR_ from the outside just points
anyone actually calling cljs.core._STAR_print_fn_STAR_ to the new
function. I tried this in clojurescript.test:

    #!/usr/bin/env phantomjs

    // reusable phantomjs script for running clojurescript.test tests
    // see http://github.com/cemerick/clojurescript.test for more info

    var p = require('webpage').create();                                                                                                                                                                                                                                                       
    p.injectJs(require('system').args[1]);                                                                                                                                                                                                                                                     

    p.onConsoleMessage = function (x) { console.log(x); };                                                                                                                                                                                                                                     
    // p.evaluate(function () {
    //     cemerick.cljs.test.set_print_fn();                                                                                                                                                                                                                                                  
    // });                                                                                                                                                                                                                                                                                     

    p.evaluate(function () {

      // Try to redefine cljs.core._STAR_print_fn_STAR_
      console.log(cljs.core._STAR_print_fn_STAR_);                                                                                                                                                                                                                                             
      cljs.core._STAR_print_fn_STAR_ = function (x) {
          x = x.replace(/\n/g, "");                                                                                                                                                                                                                                                            
          console.log(x);                                                                                                                                                                                                                                                                      
      };                                                                                                                                                                                                                                                                                       

      // BUT THIS HAS TO BE REDEFINED
      console.log(s);                                                                                                                                                                                                                                                                          
      s = function (x) {
          x = x.replace(/\n/g, "");                                                                                                                                                                                                                                                            
          console.log(x);                                                                                                                                                                                                                                                                      
      };                                                                                                                                                                                                                                                                                       
    });                                                                                                                                                                                                                                                                                        

    var success = p.evaluate(function () {
      var results = cemerick.cljs.test.run_all_tests();                                                                                                                                                                                                                                        
      console.log(results);                                                                                                                                                                                                                                                                    
      return cemerick.cljs.test.successful_QMARK_(results);                                                                                                                                                                                                                                    
    });                                                                                                                                                                                                                                                                                        

    phantom.exit(success ? 0 : 1);                                                                                                                                                                                                                                                             


Anyone else calling the renamed "s" still has a problem. We actually
need to reasign "s", which external tools still don't know by name.

In clojurescript.test I solved this dilemma by providing
something like this:

    (defn ^:export set-print-fn! [f]
      (set! cljs.core.*print-fn* f))

and pass the print fn as an argument

    cemerick.cljs.test.set_print_fn_BANG_(function(x) {
        x = x.replace(/\n/g, "");                                                                                                                                                                                                                                                              
        console.log(x);                                                                                                                                                                                                                                                                        
    });                                                                                                                                                                                                                                                                                        

In summary, exporting *print-fn* does not help as I initially
thought. You have to get to the renamed var. We could provide the
mentioned set-print-fn! from above for tools to use. But then
this could be done by tools themself.

Any other thoughts?


Show
Roman Scherer added a comment -
Unfortunatly it's not that easy. Advanced compilation is quite a
beast. I added :export true to the meta data of *print-fn*, build a
ClojureScript release and put it into my local Maven repo. Changed the
ClojureScript version in clojurescript.test and recompiled. The var is
exported:

    function s() {
      d(Error("No *print-fn* fn set for evaluation environment"))
    }
   fa("cljs.core._STAR_print_fn_STAR_", s);                                                                                                                                                                                                                                                    

The fn "fa" is the goog/exportSymbol fn, which (i guess) builds up
some nested object and finally assigns "s" under the proper path.

    function fa(a, b) {
      var c = a.split("."), e = ba;                                                                                                                                                                                                                                                            
      !(c[0] in e) && e.execScript && e.execScript("var " + c[0]);                                                                                                                                                                                                                             
      for(var f;c.length && (f = c.shift());) {                                                                                                                                                                                                                                                
        !c.length && b !== g ? e[f] = b : e = e[f] ? e[f] : e[f] = {}
      }
    }  

Assigning cljs.core._STAR_print_fn_STAR_ from the outside just points
anyone actually calling cljs.core._STAR_print_fn_STAR_ to the new
function. I tried this in clojurescript.test:

    #!/usr/bin/env phantomjs

    // reusable phantomjs script for running clojurescript.test tests
    // see http://github.com/cemerick/clojurescript.test for more info

    var p = require('webpage').create();                                                                                                                                                                                                                                                       
    p.injectJs(require('system').args[1]);                                                                                                                                                                                                                                                     

    p.onConsoleMessage = function (x) { console.log(x); };                                                                                                                                                                                                                                     
    // p.evaluate(function () {
    //     cemerick.cljs.test.set_print_fn();                                                                                                                                                                                                                                                  
    // });                                                                                                                                                                                                                                                                                     

    p.evaluate(function () {

      // Try to redefine cljs.core._STAR_print_fn_STAR_
      console.log(cljs.core._STAR_print_fn_STAR_);                                                                                                                                                                                                                                             
      cljs.core._STAR_print_fn_STAR_ = function (x) {
          x = x.replace(/\n/g, "");                                                                                                                                                                                                                                                            
          console.log(x);                                                                                                                                                                                                                                                                      
      };                                                                                                                                                                                                                                                                                       

      // BUT THIS HAS TO BE REDEFINED
      console.log(s);                                                                                                                                                                                                                                                                          
      s = function (x) {
          x = x.replace(/\n/g, "");                                                                                                                                                                                                                                                            
          console.log(x);                                                                                                                                                                                                                                                                      
      };                                                                                                                                                                                                                                                                                       
    });                                                                                                                                                                                                                                                                                        

    var success = p.evaluate(function () {
      var results = cemerick.cljs.test.run_all_tests();                                                                                                                                                                                                                                        
      console.log(results);                                                                                                                                                                                                                                                                    
      return cemerick.cljs.test.successful_QMARK_(results);                                                                                                                                                                                                                                    
    });                                                                                                                                                                                                                                                                                        

    phantom.exit(success ? 0 : 1);                                                                                                                                                                                                                                                             


Anyone else calling the renamed "s" still has a problem. We actually
need to reasign "s", which external tools still don't know by name.

In clojurescript.test I solved this dilemma by providing
something like this:

    (defn ^:export set-print-fn! [f]
      (set! cljs.core.*print-fn* f))

and pass the print fn as an argument

    cemerick.cljs.test.set_print_fn_BANG_(function(x) {
        x = x.replace(/\n/g, "");                                                                                                                                                                                                                                                              
        console.log(x);                                                                                                                                                                                                                                                                        
    });                                                                                                                                                                                                                                                                                        

In summary, exporting *print-fn* does not help as I initially
thought. You have to get to the renamed var. We could provide the
mentioned set-print-fn! from above for tools to use. But then
this could be done by tools themself.

Any other thoughts?


Hide
David Nolen added a comment -

I'm fine with this change. Patch welcome.

Show
David Nolen added a comment - I'm fine with this change. Patch welcome.
Hide
Roman Scherer added a comment -

Ok, here is the patch.

Show
Roman Scherer added a comment - Ok, here is the patch.

People

Vote (0)
Watch (1)

Dates

  • Created:
    Updated:
    Resolved: