Project

eval_in

0.0
No commit activity in last 3 years
No release in over 3 years
Safely evaluates code (Ruby and others) by sending it through https://eval.in == Languages and Versions Ruby | MRI 1.0, MRI 1.8.7, MRI 1.9.3, MRI 2.0.0, MRI 2.1 C | GCC 4.4.3, GCC 4.9.1 C++ | C++11 (GCC 4.9.1), GCC 4.4.3, GCC 4.9.1 CoffeeScript | CoffeeScript 1.7.1 (Node 0.10.29) Fortran | F95 (GCC 4.4.3) Haskell | Hugs98 September 2006 Io | Io 20131204 JavaScript | Node 0.10.29 Lua | Lua 5.1.5, Lua 5.2.3 OCaml | OCaml 4.01.0 PHP | PHP 5.5.14 Pascal | Free Pascal 2.6.4 Perl | Perl 5.20.0 Python | CPython 2.7.8, CPython 3.4.1 Slash | Slash HEAD x86 Assembly | NASM 2.07 == Example: It's this simple: result = EvalIn.call 'puts "example"', language: "ruby/mri-2.1" result.output # returns "example\n"
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
 Dependencies

Development

~> 3.0
~> 1.18
 Project Readme

Build Status

EvalIn

Safely evaluates code (Ruby and others) by sending it through https://eval.in

Example

It's this simple:

require 'eval_in'

result = EvalIn.call 'puts "hello, #{gets}"', stdin: 'world', language: "ruby/mri-2.1"

result.output             # => "hello, world\n"
result.exitstatus         # => 0
result.url                # => "https://eval.in/182711.json"
result.language           # => "ruby/mri-2.1"
result.language_friendly  # => "Ruby — MRI 2.1"
result.code               # => "puts \"hello, \#{gets}\""
result.status             # => "OK (0.064 sec real, 0.073 sec wall, 9 MB, 21 syscalls)"

Docs are here.

What languages can this run?

Ruby ruby/mri-1.0
ruby/mri-1.8.7
ruby/mri-1.9.3
ruby/mri-2.0.0
ruby/mri-2.1
C c/gcc-4.4.3
c/gcc-4.9.1
C++ c++/c++11-gcc-4.9.1
c++/gcc-4.4.3
c++/gcc-4.9.1
CoffeeScript coffeescript/node-0.10.29-coffee-1.7.1
Fortran fortran/f95-4.4.3
Haskell haskell/hugs98-sep-2006
Io io/io-20131204
JavaScript javascript/node-0.10.29
Lua lua/lua-5.1.5
lua/lua-5.2.3
OCaml ocaml/ocaml-4.01.0
PHP php/php-5.5.14
Pascal pascal/fpc-2.6.4
Perl perl/perl-5.20.0
Python python/cpython-2.7.8
python/cpython-3.4.1
Slash slash/slash-head
x86 Assembly assembly/nasm-2.07

Mocking for non-prod environments

Wiring the mock in

The mock that is provided will need to be set into place (its interface is in the next section). If the code is directly doing EvalIn.call(...), then it is a hard dependency, and there is no ablity to set the mock into place.

You will need to structure your code such that it receives the eval_in service as an argument, or looks it up in some configuration or something (I strongly prefer the former). This will allow your test environment to give it a mock that tests that it works in all the edge cases, or is just generally benign (doesn't make real http request in tests), your dev environment to give it an EvalIn that looks so close to the real one you wouldn't even know, and your prod environment to give it the actual EvalIn that actually uses the service.

If this is still unclear, here is an example:

  • Here we use whatever EvalIn was injected.
  • Here we inject the real EvalIn for the prod environment.
  • Here we inject a mock that does evaluate code for the development environment.
  • Here we inject a mock result for the test environment.

The provided mock

For a test or dev env where you don't care about correctness, just that it does something that looks real, you can make a mock that has a Result, instantiated with any values you care about.

require 'eval_in/mock'
eval_in = EvalIn::Mock.new(result: EvalIn::Result.new(code: 'injected code', output: 'the output')) 

eval_in.call('overridden code', language: 'irrelevant')
# => #<EvalIn::Result:0x007fb503a7a5e8
#     @code="injected code",
#     @exitstatus=-1,
#     @language="",
#     @language_friendly="",
#     @output="the output",
#     @status="",
#     @url="">

If you want your environment to behave approximately like the real eval_in, you can instantiate a mock that knows how to evaluate code locally. This is necessary, because it doesn't know how to execute these languages (eval.in does that, it just knows how to talk to eval.in). So you must provide it with a list of languages and how to execute them

This is probably idea for a dev environment, the results will be the most realistic.

NOTE THAT THIS DOES NOT WORK ON JRUBY

require 'eval_in/mock'

# a mock that can execute Ruby code and C code
eval_in = EvalIn::Mock.new(languages: {
  'ruby/mri-2.1' => {program: RbConfig.ruby,
                     args: []
                    },
  'c/gcc-4.9.1'  => {program: RbConfig.ruby,
                     args: ['-e',
                            'system "gcc -x c -o /tmp/eval_in_c_example #{ARGV.first}"
                             exec   "/tmp/eval_in_c_example"']
                    },
})

eval_in.call 'puts "hello from ruby!"; exit 123', language: 'ruby/mri-2.1'
# => #<EvalIn::Result:0x007fb503a7d518
#     @code="puts \"hello from ruby!\"; exit 123",
#     @exitstatus=123,
#     @language="ruby/mri-2.1",
#     @language_friendly="ruby/mri-2.1",
#     @output="hello from ruby!\n",
#     @status="OK (0.072 sec real, 0.085 sec wall, 8 MB, 19 syscalls)",
#     @url="https://eval.in/207744.json">

eval_in.call '#include <stdio.h>
int main() {
  puts("hello from c!");
}', language: 'c/gcc-4.9.1'
# => #<EvalIn::Result:0x007fb503a850b0
#     @code="#include <stdio.h>\nint main() {\n  puts(\"hello from c!\");\n}",
#     @exitstatus=0,
#     @language="c/gcc-4.9.1",
#     @language_friendly="c/gcc-4.9.1",
#     @output="hello from c!\n",
#     @status="OK (0.072 sec real, 0.085 sec wall, 8 MB, 19 syscalls)",
#     @url="https://eval.in/207744.json">

You can also provide a callback that will be invoked to handle the request. This is probably ideal for testing more nuanced edge cases that the mock doesn't inherently provide the ability to do.

require 'eval_in/mock'
eval_in = EvalIn::Mock.new on_call: -> code, options { raise EvalIn::RequestError, 'does my code do the right thing in the event of an exception?' }

eval_in.call('code', language: 'any') rescue $! # => #<EvalIn::RequestError: does my code do the right thing in the event of an exception?>

Attribution

Thanks to Charlie Sommerville for making eval-in.

Thanks to Mon Oui, I partially stole the first version of the implementation from his gem cinch-eval-in

Contributing

Fork it, make your changes, send me a pull request. Make sure your code is tested and all tests pass.

Run tests with bundle exec rspec, run integration tests with bundle exec rspec -t integration.

WTFPL License

Copyright (C) 2014 Josh Cheek <josh.cheek@gmail.com>

This program is free software. It comes without any warranty,
to the extent permitted by applicable law.
You can redistribute it and/or modify it under the terms of the
Do What The Fuck You Want To Public License,
Version 2, as published by Sam Hocevar.
See http://www.wtfpl.net/ for more details.