From 06b50ecb98ad2635c6565c6a16ee28a5168f9964 Mon Sep 17 00:00:00 2001 From: Jeremy Ashkenas Date: Sun, 7 Mar 2010 21:49:08 -0500 Subject: [PATCH] unifying all of the server-side evaluation under CoffeeScript.run -- this means that __filename and __dirname and relative requires should work from all angles under Node.js --- Cakefile | 5 ++--- lib/cake.js | 2 +- lib/coffee-script.js | 9 +++++++++ lib/command.js | 13 ++++++------- lib/repl.js | 14 ++++++++------ src/cake.coffee | 2 +- src/coffee-script.coffee | 8 ++++++++ src/command.coffee | 11 ++++------- src/repl.coffee | 6 ++++-- 9 files changed, 43 insertions(+), 27 deletions(-) diff --git a/Cakefile b/Cakefile index a11b83cd..46a0a623 100644 --- a/Cakefile +++ b/Cakefile @@ -73,6 +73,5 @@ task 'test', 'run the CoffeeScript language test suite', -> puts '\033[0;32mpassed ' + test_count + ' tests in ' + time + ' seconds\033[0m' fs.readdir 'test', (err, files) -> for file in files - fs.readFile 'test/' + file, (err, source) -> - js: coffee.compile source - process.compile js, file \ No newline at end of file + fs.readFile 'test/' + file, (err, code) -> + coffee.run code, file \ No newline at end of file diff --git a/lib/cake.js b/lib/cake.js index 1a4d59e9..4726e65d 100755 --- a/lib/cake.js +++ b/lib/cake.js @@ -52,7 +52,7 @@ throw new Error("Cakefile not found in " + (process.cwd())); } args = process.argv.slice(2, process.argv.length); - eval(coffee.compile(fs.readFileSync('Cakefile'))); + coffee.run(fs.readFileSync('Cakefile'), 'Cakefile'); oparse = new optparse.OptionParser(switches); if (!(args.length)) { return print_tasks(); diff --git a/lib/coffee-script.js b/lib/coffee-script.js index 9905c3a7..4d420380 100644 --- a/lib/coffee-script.js +++ b/lib/coffee-script.js @@ -34,6 +34,15 @@ exports.nodes = function nodes(code) { return parser.parse(lexer.tokenize(code)); }; + // Compile and execute a string of CoffeeScript (on the server), correctly + // setting `__filename`, `__dirname`, and relative `require()`. + exports.run = function run(code, source, options) { + var __dirname, __filename; + __filename = source; + __dirname = path.dirname(source); + module.filename = source; + return eval(exports.compile(code, options)); + }; // The real Lexer produces a generic stream of tokens. This object provides a // thin wrapper around it, compatible with the Jison API. We can then pass it // directly as a "Jison lexer". diff --git a/lib/command.js b/lib/command.js index e73548e4..cacd0c42 100644 --- a/lib/command.js +++ b/lib/command.js @@ -80,13 +80,15 @@ // in common. If evaluating the script directly sets `__filename`, `__dirname` // and `module.filename` to be correct relative to the script's path. compile_script = function compile_script(source, code) { - var __dirname, __filename, js, o; + var js, o; o = options; try { if (o.tokens) { return print_tokens(CoffeeScript.tokens(code)); } else if (o.nodes) { return puts(CoffeeScript.nodes(code).toString()); + } else if (o.run) { + return CoffeeScript.run(code, source, compile_options()); } else { js = CoffeeScript.compile(code, compile_options()); if (o.compile) { @@ -95,11 +97,6 @@ return lint(js); } else if (o.print || o.eval) { return print(js); - } else { - __filename = source; - __dirname = path.dirname(source); - module.filename = source; - return eval(js); } } } catch (err) { @@ -199,8 +196,10 @@ // Use the [OptionParser module](optparse.html) to extract all options from // `process.argv` that are specified in `SWITCHES`. parse_options = function parse_options() { + var o; option_parser = new optparse.OptionParser(SWITCHES, BANNER); - options = option_parser.parse(process.argv); + o = (options = option_parser.parse(process.argv)); + options.run = !(o.compile || o.print || o.lint || o.eval); return sources = options.arguments.slice(2, options.arguments.length); }; // The compile-time options to pass to the CoffeeScript compiler. diff --git a/lib/repl.js b/lib/repl.js index a97dbd6b..68681a6d 100644 --- a/lib/repl.js +++ b/lib/repl.js @@ -1,5 +1,5 @@ (function(){ - var CoffeeScript, prompt, quit, run; + var CoffeeScript, prompt, run; // A very simple Read-Eval-Print-Loop. Compiles one line at a time to JavaScript // and evaluates it. Good for simple tests, or poking around the **Node.js** API. // Using it looks like this: @@ -9,19 +9,21 @@ // Our prompt. prompt = 'coffee> '; // Quick alias for quitting the REPL. - quit = function quit() { - return process.exit(0); - }; + process.mixin({ + quit: function quit() { + return process.exit(0); + } + }); // The main REPL function. **run** is called every time a line of code is entered. // Attempt to evaluate the command. If there's an exception, print it out instead // of exiting. run = function run(code) { var val; try { - val = eval(CoffeeScript.compile(code, { + val = CoffeeScript.run(code, 'repl', { no_wrap: true, globals: true - })); + }); if (val !== undefined) { p(val); } diff --git a/src/cake.coffee b/src/cake.coffee index 5141e6a5..3b13cea7 100644 --- a/src/cake.coffee +++ b/src/cake.coffee @@ -46,7 +46,7 @@ exports.run: -> path.exists 'Cakefile', (exists) -> throw new Error("Cakefile not found in ${process.cwd()}") unless exists args: process.argv[2...process.argv.length] - eval coffee.compile fs.readFileSync 'Cakefile' + coffee.run fs.readFileSync('Cakefile'), 'Cakefile' oparse: new optparse.OptionParser switches return print_tasks() unless args.length options: oparse.parse(args) diff --git a/src/coffee-script.coffee b/src/coffee-script.coffee index 455dcee6..eede926f 100644 --- a/src/coffee-script.coffee +++ b/src/coffee-script.coffee @@ -35,6 +35,14 @@ exports.tokens: (code) -> exports.nodes: (code) -> parser.parse lexer.tokenize code +# Compile and execute a string of CoffeeScript (on the server), correctly +# setting `__filename`, `__dirname`, and relative `require()`. +exports.run: (code, source, options) -> + __filename: source + __dirname: path.dirname source + module.filename: source + eval exports.compile code, options + # The real Lexer produces a generic stream of tokens. This object provides a # thin wrapper around it, compatible with the Jison API. We can then pass it # directly as a "Jison lexer". diff --git a/src/command.coffee b/src/command.coffee index 19049f73..e439e7bd 100644 --- a/src/command.coffee +++ b/src/command.coffee @@ -78,16 +78,12 @@ compile_script: (source, code) -> try if o.tokens then print_tokens CoffeeScript.tokens code else if o.nodes then puts CoffeeScript.nodes(code).toString() + else if o.run then CoffeeScript.run code, source, compile_options() else js: CoffeeScript.compile code, compile_options() if o.compile then write_js source, js else if o.lint then lint js else if o.print or o.eval then print js - else - __filename: source - __dirname: path.dirname source - module.filename: source - eval js catch err if o.watch then puts err.message else throw err @@ -142,8 +138,9 @@ print_tokens: (tokens) -> # `process.argv` that are specified in `SWITCHES`. parse_options: -> option_parser: new optparse.OptionParser SWITCHES, BANNER - options: option_parser.parse(process.argv) - sources: options.arguments[2...options.arguments.length] + o: options: option_parser.parse(process.argv) + options.run: not (o.compile or o.print or o.lint or o.eval) + sources: options.arguments[2...options.arguments.length] # The compile-time options to pass to the CoffeeScript compiler. compile_options: -> diff --git a/src/repl.coffee b/src/repl.coffee index ab98d93e..d5276b88 100644 --- a/src/repl.coffee +++ b/src/repl.coffee @@ -11,14 +11,16 @@ CoffeeScript: require 'coffee-script' prompt: 'coffee> ' # Quick alias for quitting the REPL. -quit: -> process.exit(0) +process.mixin { + quit: -> process.exit(0) +} # The main REPL function. **run** is called every time a line of code is entered. # Attempt to evaluate the command. If there's an exception, print it out instead # of exiting. run: (code) -> try - val: eval CoffeeScript.compile code, {no_wrap: true, globals: true} + val: CoffeeScript.run code, 'repl', {no_wrap: true, globals: true} p val if val isnt undefined catch err puts err.stack or err.toString()