Skip to content

Commit

Permalink
Merge branch 'evals'
Browse files Browse the repository at this point in the history
  • Loading branch information
eritbh committed Mar 18, 2018
2 parents 77609a6 + 0395b35 commit ec10ab0
Show file tree
Hide file tree
Showing 6 changed files with 185 additions and 4 deletions.
4 changes: 0 additions & 4 deletions commands/bash.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,6 @@ module.exports = new Command(['bash', 'sh', 'sys'], function (msg, args) {
return msg.channel.createMessage("You're not my dad.")
}

let content = ''
let activeMsg

msg.channel.createMessage('```\n```').then(outputMsg => {
// Start the process
const childProcess = exec(args.join(' '))
Expand All @@ -34,7 +31,6 @@ module.exports = new Command(['bash', 'sh', 'sys'], function (msg, args) {

// When the process exits, react based on exit code
childProcess.on('exit', code => {
let reaction
if (code === 0) {
react('✅')
} else {
Expand Down
65 changes: 65 additions & 0 deletions commands/eval.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
const {Command} = require('../src/Yuuko')
const superagent = require('superagent')

const codeBlockRegExp = /^[\s\n]*```((javascript|js|ruby|rb|python|py)?\n)?([\S\s]*)\n?```[\s\n]*$/
const inlineCodeRegExp = /^[\s\n]*(``?)(.*)\1[\s\n]*$/

function urlPartForLang (lang) {
switch (lang) {
case 'javascript':
case 'js':
return 'https://hook.io/geo1088/js-eval?code='
case 'ruby':
case 'rb':
return 'https://hook.io/geo1088/ruby-eval?code='
case 'python':
case 'py':
return 'https://hook.io/geo1088/py-exec-then-eval?code='
}
}

module.exports = new Command([
'eval',
'javascript', 'js',
'ruby', 'rb',
'python', 'py'
], function (msg, args, prefix, commandName) {
let code = args.join(' ')
let codeBlockLang
let match
if ((match = code.match(codeBlockRegExp))) {
code = match[3]
codeBlockLang = match[2]
} else if ((match = code.match(inlineCodeRegExp))) {
code = match[2]
}

let url = urlPartForLang(commandName)
if (!url) url = urlPartForLang(codeBlockLang)
if (!url) {
msg.channel.createMessage("Couldn't detect language.")
return
}
url += encodeURIComponent(code)

msg.channel.sendTyping()
superagent.get(url).then(res => {
msg.channel.createMessage(res.text).catch(console.log)
}).catch(err => {
msg.channel.createMessage('' + err).catch(console.log)
})
})
module.exports.help = {
desc: `Evaluates arbitrary code in a third-party sandbox. Supports multiple languages; to specify a language, use a language-specific alias or a code block tagged with the desired language.
For example:
\`\`\`
eval \`\u200b\`\u200b\`ruby
puts "hello"
\`\u200b\`\u200b\`
\`\`\`
and
\`\`\`
rb puts "hello"
\`\`\`
are both valid and will evaluate as Ruby code. Supported languages are Ruby (\`ruby\`, \`rb\`), Python (\`python\`, \`py\`), and Javascript (\`javascript\`, \`js\`).`
}
39 changes: 39 additions & 0 deletions docs/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,45 @@ Chooses a random option from a list of comma-separated options. If you want to i
## `~color <any valid CSS color>`
Gets alternate writings of a CSS color, plus a preview.

## `~eval` (`~rb`, `~py`, `~js`, and others)
Evaluates arbitrary code in a sandbox. Supports Ruby, Python, and Javascript code in a variety of formats.

Code can be passed to this command in several ways:

- Passing code in a code block with a specified language

````
~eval ```rb
puts "hoi"
```
````

````
~eval ```py
print("hoi")
```
````

- Using a language-specific alias, with or without a code block

````
~ruby puts "hoi"
````

````
~python ```py
print("hoi")
```
````

````
~js console.log('hoi')
````

The output of this command reflects the result of the run script. Console messages (`puts`, `print()`, `console.log()`) are shown with comments, and the final output of the script will be shown with syntax highlighting.

Due to limitations in the evaluation system, asynchronous scripts will likely not work.

## `~help [command]`
Displays a list of commands. Include a command name to get information about that command.

Expand Down
28 changes: 28 additions & 0 deletions microservices/js-eval.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
const util = require('util')
const inspectOptions = {depth: 1}

module.exports = function (hook) {
// Override console object for logging stuff
console = {
_lines: [],
_logger (...things) {
this._lines.push(...things.join(' ').split('\n'))
},
_formatLines () {
return this._lines.map(line => line && `//> ${line}\n`).join('')
}
}
console.log = console.error = console.warn = console.info = console._logger

// Get the eval result
let result
try {
result = eval(hook.params.code || '') // eslint-disable-line no-eval
} catch (e) {
result = e
}

// Format the result
const message = '```js\n' + console._formatLines() + util.inspect(result, inspectOptions) + '\n```'
hook.res.end(message)
}
37 changes: 37 additions & 0 deletions microservices/py-exec-then-eval.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import ast

def comment_print(*things):
print('#=>', *things)

def exec_then_eval(code):
try:
block = ast.parse(code, mode='exec')
except Exception as e:
print(repr(e))
return

try:
last = ast.Expression(block.body.pop().value)
except Exception as e:
last = None

_globals = {}
_locals = {'print': comment_print}

try:
exec(compile(block, '<string>', mode='exec'), _globals, _locals)
if last:
print(repr(eval(compile(last, '<string>', mode='eval'), _globals, _locals)))
else:
print('<no returned value>')
except Exception as e:
print(repr(e))

try:
code = Hook['params']['code']
except:
code = ''

print('```py')
exec_then_eval(code)
print('```')
16 changes: 16 additions & 0 deletions microservices/ruby-eval.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
alias old_puts puts
def puts(*things)
things.each do |thing|
old_puts "#=> #{thing}"
end
nil
end

old_puts '```rb'
begin
result = eval Hook['params']['code'] || ''
old_puts result.inspect
rescue Exception => e
old_puts "#{e.class.name}: #{e.message}"
end
old_puts '```'

0 comments on commit ec10ab0

Please sign in to comment.