Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Don't use a separate context for the repl. #1904

Closed
wants to merge 1 commit into from

3 participants

@isaacs
Owner

Fix #1484
Fix #1834
Fix #1482
Fix #771

It's been a while now, and we've seen how this separate context thing
works. It constantly confuses people, and no one actually uses '.clear'
anyway, so the benefit of that feature does not justify the constant
WTFery.

This makes repl.context actually be a getter that returns the global
object, and prints a deprecation warning. The '.clear' command is gone,
and will report that it's an invalid repl keyword. Tests updated to
allow the require, module, and exports globals, which are still
available in the repl just like they were before, by making them global.

@isaacs isaacs Don't use a separate context for the repl.
Fix #1484
Fix #1834
Fix #1482
Fix #771

It's been a while now, and we've seen how this separate context thing
works.  It constantly confuses people, and no one actually uses '.clear'
anyway, so the benefit of that feature does not justify the constant
WTFery.

This makes repl.context actually be a getter that returns the global
object, and prints a deprecation warning.  The '.clear' command is gone,
and will report that it's an invalid repl keyword.  Tests updated to
allow the require, module, and exports globals, which are still
available in the repl just like they were before, by making them global.
73dcc62
@bnoordhuis

LGTM, works as advertised.

@isaacs
Owner

@ry Can you comment? It wouldn't be hard to keep this around as an optional argument to the repl, or even as a default that's disabled in the repl setup in node.js. More discussion (mostly cheers and outrage) in the linked bugs.

@ry
ry commented

LGTM.

@isaacs
Owner

Landed on b70fed4

@isaacs isaacs closed this
@satyr satyr referenced this pull request from a commit in satyr/coco
@satyr satyr command: REPL now runs in `global` as per joyent/node#1904 94f85ce
@michaelficarra michaelficarra referenced this pull request in jashkenas/coffeescript
Merged

Allow user-added globals on the REPL #1661

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Oct 18, 2011
  1. @isaacs

    Don't use a separate context for the repl.

    isaacs authored
    Fix #1484
    Fix #1834
    Fix #1482
    Fix #771
    
    It's been a while now, and we've seen how this separate context thing
    works.  It constantly confuses people, and no one actually uses '.clear'
    anyway, so the benefit of that feature does not justify the constant
    WTFery.
    
    This makes repl.context actually be a getter that returns the global
    object, and prints a deprecation warning.  The '.clear' command is gone,
    and will report that it's an invalid repl keyword.  Tests updated to
    allow the require, module, and exports globals, which are still
    available in the repl just like they were before, by making them global.
This page is out of date. Refresh to see the latest.
Showing with 40 additions and 103 deletions.
  1. +1 −17 doc/api/repl.markdown
  2. +28 −86 lib/repl.js
  3. +11 −0 test/common.js
View
18 doc/api/repl.markdown
@@ -83,28 +83,12 @@ The special variable `_` (underscore) contains the result of the last expression
> _ += 1
4
-The REPL provides access to any variables in the global scope. You can expose
-a variable to the REPL explicitly by assigning it to the `context` object
-associated with each `REPLServer`. For example:
-
- // repl_test.js
- var repl = require("repl"),
- msg = "message";
-
- repl.start().context.m = msg;
-
-Things in the `context` object appear as local within the REPL:
-
- mjr:~$ node repl_test.js
- > m
- 'message'
+The REPL provides access to any variables in the global scope.
There are a few special REPL commands:
- `.break` - While inputting a multi-line expression, sometimes you get lost
or just don't care about completing it. `.break` will start over.
- - `.clear` - Resets the `context` object to an empty object and clears any
- multi-line expression.
- `.exit` - Close the I/O stream, which will cause the REPL to exit.
- `.help` - Show this list of special commands.
View
114 lib/repl.js
@@ -46,6 +46,10 @@ var path = require('path');
var fs = require('fs');
var rl = require('readline');
+global.module = module;
+global.exports = exports;
+global.require = require;
+
// If obj.hasOwnProperty has been overridden, then calling
// obj.hasOwnProperty(prop) will break.
// See: https://github.com/joyent/node/issues/1707
@@ -53,9 +57,6 @@ function hasOwnProperty(obj, prop) {
return Object.prototype.hasOwnProperty.call(obj, prop);
}
-
-var context;
-
exports.disableColors = process.env.NODE_DISABLE_COLORS ? true : false;
// hack for require.resolve("./relative") to work properly.
@@ -71,16 +72,27 @@ exports.writer = util.inspect;
function REPLServer(prompt, stream, eval) {
var self = this;
- self.eval = eval || function(code, context, file, cb) {
+ var contextWarning;
+ Object.defineProperty(this, 'context', {
+ get: function() {
+ if (!contextWarning) {
+ contextWarning = 'repl.context is deprecated.';
+ console.error(contextWarning);
+ }
+ return global;
+ }
+ });
+
+
+ self.eval = eval || function(code, file, cb) {
try {
- var err, result = vm.runInContext(code, context, file);
+ var err, result = vm.runInThisContext(code, file);
} catch (e) {
err = e;
}
cb(err, result);
};
- self.resetContext();
self.bufferedCommand = '';
if (stream) {
@@ -173,14 +185,13 @@ function REPLServer(prompt, stream, eval) {
// First we attempt to eval as expression with parens.
// This catches '{a : 1}' properly.
self.eval('(' + evalCmd + ')',
- self.context,
'repl',
function(e, ret) {
if (e && !isSyntaxError(e)) return finish(e);
if (typeof ret === 'function' || e) {
// Now as statement without parens.
- self.eval(evalCmd, self.context, 'repl', finish);
+ self.eval(evalCmd, 'repl', finish);
} else {
finish(null, ret);
}
@@ -218,7 +229,7 @@ function REPLServer(prompt, stream, eval) {
// If we got any output - print it (if no error)
if (!e && ret !== undefined) {
- self.context._ = ret;
+ global._ = ret;
self.outputStream.write(exports.writer(ret) + '\n');
}
@@ -245,25 +256,12 @@ exports.start = function(prompt, source, eval) {
};
-REPLServer.prototype.createContext = function() {
- var context = vm.createContext();
-
- for (var i in global) context[i] = global[i];
- context.module = module;
- context.require = require;
- context.global = context;
- context.global.global = context;
-
- return context;
-};
-
+var resetWarning;
REPLServer.prototype.resetContext = function(force) {
- if (!context || force) {
- context = this.createContext();
- for (var i in require.cache) delete require.cache[i];
+ if (!resetWarning) {
+ resetWarning = 'REPLServer.resetContext is deprecated.';
+ console.error(resetWarning);
}
-
- this.context = context;
};
REPLServer.prototype.displayPrompt = function() {
@@ -413,26 +411,9 @@ REPLServer.prototype.complete = function(line, callback) {
if (!expr) {
// If context is instance of vm.ScriptContext
// Get global vars synchronously
- if (this.context.constructor.name === 'Context') {
- completionGroups.push(Object.getOwnPropertyNames(this.context));
- addStandardGlobals();
- completionGroupsLoaded();
- } else {
- this.eval('.scope', this.context, 'repl', function(err, globals) {
- if (err || !globals) {
- addStandardGlobals();
- } else if (Array.isArray(globals[0])) {
- // Add grouped globals
- globals.forEach(function(group) {
- completionGroups.push(group);
- });
- } else {
- completionGroups.push(globals);
- addStandardGlobals();
- }
- completionGroupsLoaded();
- });
- }
+ completionGroups.push(Object.getOwnPropertyNames(global));
+ addStandardGlobals();
+ completionGroupsLoaded();
function addStandardGlobals() {
// Global object properties
@@ -457,7 +438,7 @@ REPLServer.prototype.complete = function(line, callback) {
}
} else {
- this.eval(expr, this.context, 'repl', function(e, obj) {
+ this.eval(expr, 'repl', function(e, obj) {
// if (e) console.log(e);
if (obj != null) {
@@ -584,16 +565,6 @@ function defineDefaultCommands(repl) {
}
});
- repl.defineCommand('clear', {
- help: 'Break, and also clear the local context',
- action: function() {
- this.outputStream.write('Clearing context...\n');
- this.bufferedCommand = '';
- this.resetContext(true);
- this.displayPrompt();
- }
- });
-
repl.defineCommand('exit', {
help: 'Exit the repl',
action: function() {
@@ -628,32 +599,3 @@ function trimWhitespace(cmd) {
function regexpEscape(s) {
return s.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
}
-
-
-/**
- * Converts commands that use var and function <name>() to use the
- * local exports.context when evaled. This provides a local context
- * on the REPL.
- *
- * @param {String} cmd The cmd to convert.
- * @return {String} The converted command.
- */
-REPLServer.prototype.convertToContext = function(cmd) {
- var self = this, matches,
- scopeVar = /^\s*var\s*([_\w\$]+)(.*)$/m,
- scopeFunc = /^\s*function\s*([_\w\$]+)/;
-
- // Replaces: var foo = "bar"; with: self.context.foo = bar;
- matches = scopeVar.exec(cmd);
- if (matches && matches.length === 3) {
- return 'self.context.' + matches[1] + matches[2];
- }
-
- // Replaces: function foo() {}; with: foo = function foo() {};
- matches = scopeFunc.exec(self.bufferedCommand);
- if (matches && matches.length === 2) {
- return matches[1] + ' = ' + self.bufferedCommand;
- }
-
- return cmd;
-};
View
11 test/common.js
@@ -123,6 +123,17 @@ process.on('exit', function() {
knownGlobals.push(DataView);
}
+ // repl pollution
+ if (global.hasOwnProperty('module')) {
+ knownGlobals.push(global.module);
+ }
+ if (global.hasOwnProperty('require')) {
+ knownGlobals.push(global.require);
+ }
+ if (global.hasOwnProperty('exports')) {
+ knownGlobals.push(global.exports);
+ }
+
for (var x in global) {
var found = false;
Something went wrong with that request. Please try again.