vt5491
vt5491

Reputation: 2304

how do you write to a file in clojurescript?

I am running a clojurescript (cljs) browser repl and I want to be able to write some text to a local file.

I tried the following:

(spit "abc.txt" "hello")

but this returns:

#<TypeError: Cannot read property 'call' of undefined>
TypeError: Cannot read property 'call' of undefined

Under a clojure repl this will create file "abc.txt" in the root dir of my project.

I realize that 'spit is a clojure function, but I wonder if there is also some easy way to do this in cljs?

Or is this strictly a JavaScript question and not relevant to clojurescript proper?

Upvotes: 2

Views: 2826

Answers (3)

vt5491
vt5491

Reputation: 2304

node.js example.

Less hassle than writing a cgi. New to node.js, so just a starter. Did not convert to cljs.

// to run:
// node write_file.js
// to call from cmd line:
// curl localhost:9090?fn=test.txt\&msg=hello%20world

var http = require('http');

var fs = require('fs');
var url = require('url');

var server = http.createServer(function(req, res) {
var fn = url.parse(req.url, true).query['fn'];
var msg = url.parse(req.url, true).query['msg'];

fs.writeFile(process.env.HOME + "/vtstuff/tmp/" + fn, msg + "\n",               
  function(err) {

  if(err) {
      return console.log(err);
  }

  console.log("The file was saved!");
  console.log("fn=" + fn);
  console.log("msg=" + msg);
  process.argv.forEach(function (val, index, array) {
        console.log(index + ': ' + val);
  });
  }); 
  res.writeHead(200,{"Content-Type": "text/plain"});
  res.end("wrote file\n");
});

server.listen(9090);

Upvotes: 0

vt5491
vt5491

Reputation: 2304

I am posting this as an example solution, and I am not saying this is how you should do it. I did experience a few "gotchas" however, so I think it's worthwhile to document.

Thank you for your answer. I was just trying to find out if there was some easier way before doing what I knew I would have to do otherwise. I decided to go with a server-side write.

I am using cider, chestnut, and a brepl server interfacing with a chrome client. Since I am not familiar with ring servers, compojure, and embedded jetty servers, I did not know how to add a web service to the brepl server (port 10555). Instead I added one to my local apache server.

Because the request comes in to apache from the the jetty server (as opposed to from a browser), I was getting "cross origin resource sharing" issues, namely message:

No 'Access-Control-Allow-Origin' header is present on the requested resource.

whenever I submitted a request to my service's URL.

I was able to get around this issue by adding the following to my http headers:

     -access_control_allow_credentials => 'true',
     -access_control_allow_origin => 'http://localhost:10555',

That was about the only gotcha. Beyond that, it's a standard cgi solution (yeah, old school -- I come from a perl background). And yes, I know it would have been best if I could have done it in clojure (or Rails).

My cgi ended up looking something like:

#!/usr/bin/perl
use CGI qw(:standard);
print header(
             -type => 'text/html',
             -access_control_allow_credentials => 'true',
             -access_control_allow_origin => 'http://localhost:10555',
                   );

my $q = CGI->new();
my $src = $q->param('src');

# write to file
 open(my $fh, ">>", "vt-src-out.txt")
    or die "cannot open < vt-src-out.txt: $!";

print $fh "$src\n"; 

I used ajax.core as my client api:

:require [ajax.core :refer [GET POST]]

and called the service like:

(GET "http://localhost/cgi-bin/cljs-write-src.cgi" {:params {:src "(defn foo [])(+ 1 1)"}})

Upvotes: 0

freakhill
freakhill

Reputation: 618

From a browser I think you can't (like in JS), because security.

From nodejs check the nodejs doc :)

Now if you mix in a little bit of flash (yuk :|...) there's a JS library for that (that you can use in cljs).

https://github.com/dcneiner/Downloadify

Upvotes: 4

Related Questions