eval_in 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +1 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +36 -0
- data/Readme.md +186 -0
- data/eval_in.gemspec +51 -0
- data/lib/eval_in/version.rb +3 -0
- data/lib/eval_in.rb +97 -0
- data/spec/eval_in_spec.rb +226 -0
- metadata +111 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 233dd4fa01b53aaaee164ea7805c97c0e3b334c8
|
4
|
+
data.tar.gz: b3e36f9036a0b3c36ab51bfa862bf0a811f851c9
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 95b82288f75842f9927fbbd67515f704b60cb355d967f8a773277ccd212e503cc011678544bc937648a17653dfc2a14fbb107fc93305950f84608b48d8d086cd
|
7
|
+
data.tar.gz: f20e17beab81a2e5b9de1d392b3765cea6333edc09944584d7d7eb08aedb161f6359c13eb72778b3087a4c7081336acf079a634cbd94426f60cbd02edcf6d5df
|
data/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
*.gem
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
eval_in (0.1.0)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: https://rubygems.org/
|
8
|
+
specs:
|
9
|
+
addressable (2.3.6)
|
10
|
+
crack (0.4.2)
|
11
|
+
safe_yaml (~> 1.0.0)
|
12
|
+
diff-lcs (1.2.5)
|
13
|
+
rspec (3.0.0)
|
14
|
+
rspec-core (~> 3.0.0)
|
15
|
+
rspec-expectations (~> 3.0.0)
|
16
|
+
rspec-mocks (~> 3.0.0)
|
17
|
+
rspec-core (3.0.4)
|
18
|
+
rspec-support (~> 3.0.0)
|
19
|
+
rspec-expectations (3.0.4)
|
20
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
21
|
+
rspec-support (~> 3.0.0)
|
22
|
+
rspec-mocks (3.0.4)
|
23
|
+
rspec-support (~> 3.0.0)
|
24
|
+
rspec-support (3.0.4)
|
25
|
+
safe_yaml (1.0.3)
|
26
|
+
webmock (1.18.0)
|
27
|
+
addressable (>= 2.3.6)
|
28
|
+
crack (>= 0.3.2)
|
29
|
+
|
30
|
+
PLATFORMS
|
31
|
+
ruby
|
32
|
+
|
33
|
+
DEPENDENCIES
|
34
|
+
eval_in!
|
35
|
+
rspec (~> 3.0)
|
36
|
+
webmock (~> 1.18)
|
data/Readme.md
ADDED
@@ -0,0 +1,186 @@
|
|
1
|
+
EvalIn
|
2
|
+
======
|
3
|
+
|
4
|
+
Safely evaluates code (Ruby and others) by sending it through https://eval.in
|
5
|
+
|
6
|
+
Languages and Versions
|
7
|
+
----------------------
|
8
|
+
|
9
|
+
<table>
|
10
|
+
<tr>
|
11
|
+
<th align="left">C</th>
|
12
|
+
</td>
|
13
|
+
<td>
|
14
|
+
c/gcc-4.4.3<br />
|
15
|
+
c/gcc-4.9.1<br />
|
16
|
+
</td>
|
17
|
+
</tr>
|
18
|
+
<tr>
|
19
|
+
<th align="left">C++</th>
|
20
|
+
</td>
|
21
|
+
<td>
|
22
|
+
c++/c++11-gcc-4.9.1<br />
|
23
|
+
c++/gcc-4.4.3<br />
|
24
|
+
c++/gcc-4.9.1<br />
|
25
|
+
</td>
|
26
|
+
</tr>
|
27
|
+
<tr>
|
28
|
+
<th align="left">CoffeeScript</th>
|
29
|
+
</td>
|
30
|
+
<td>
|
31
|
+
coffeescript/node-0.10.29-coffee-1.7.1<br />
|
32
|
+
</td>
|
33
|
+
</tr>
|
34
|
+
<tr>
|
35
|
+
<th align="left">Fortran</th>
|
36
|
+
</td>
|
37
|
+
<td>
|
38
|
+
fortran/f95-4.4.3<br />
|
39
|
+
</td>
|
40
|
+
</tr>
|
41
|
+
<tr>
|
42
|
+
<th align="left">Haskell</th>
|
43
|
+
</td>
|
44
|
+
<td>
|
45
|
+
haskell/hugs98-sep-2006<br />
|
46
|
+
</td>
|
47
|
+
</tr>
|
48
|
+
<tr>
|
49
|
+
<th align="left">Io</th>
|
50
|
+
</td>
|
51
|
+
<td>
|
52
|
+
io/io-20131204<br />
|
53
|
+
</td>
|
54
|
+
</tr>
|
55
|
+
<tr>
|
56
|
+
<th align="left">JavaScript</th>
|
57
|
+
</td>
|
58
|
+
<td>
|
59
|
+
javascript/node-0.10.29<br />
|
60
|
+
</td>
|
61
|
+
</tr>
|
62
|
+
<tr>
|
63
|
+
<th align="left">Lua</th>
|
64
|
+
</td>
|
65
|
+
<td>
|
66
|
+
lua/lua-5.1.5<br />
|
67
|
+
lua/lua-5.2.3<br />
|
68
|
+
</td>
|
69
|
+
</tr>
|
70
|
+
<tr>
|
71
|
+
<th align="left">OCaml</th>
|
72
|
+
</td>
|
73
|
+
<td>
|
74
|
+
ocaml/ocaml-4.01.0<br />
|
75
|
+
</td>
|
76
|
+
</tr>
|
77
|
+
<tr>
|
78
|
+
<th align="left">PHP</th>
|
79
|
+
</td>
|
80
|
+
<td>
|
81
|
+
php/php-5.5.14<br />
|
82
|
+
</td>
|
83
|
+
</tr>
|
84
|
+
<tr>
|
85
|
+
<th align="left">Pascal</th>
|
86
|
+
</td>
|
87
|
+
<td>
|
88
|
+
pascal/fpc-2.6.4<br />
|
89
|
+
</td>
|
90
|
+
</tr>
|
91
|
+
<tr>
|
92
|
+
<th align="left">Perl</th>
|
93
|
+
</td>
|
94
|
+
<td>
|
95
|
+
perl/perl-5.20.0<br />
|
96
|
+
</td>
|
97
|
+
</tr>
|
98
|
+
<tr>
|
99
|
+
<th align="left">Python</th>
|
100
|
+
</td>
|
101
|
+
<td>
|
102
|
+
python/cpython-2.7.8<br />
|
103
|
+
python/cpython-3.4.1<br />
|
104
|
+
</td>
|
105
|
+
</tr>
|
106
|
+
<tr>
|
107
|
+
<th align="left">Ruby</th>
|
108
|
+
</td>
|
109
|
+
<td>
|
110
|
+
ruby/mri-1.0<br />
|
111
|
+
ruby/mri-1.8.7<br />
|
112
|
+
ruby/mri-1.9.3<br />
|
113
|
+
ruby/mri-2.0.0<br />
|
114
|
+
ruby/mri-2.1<br />
|
115
|
+
</td>
|
116
|
+
</tr>
|
117
|
+
<tr>
|
118
|
+
<th align="left">Slash</th>
|
119
|
+
</td>
|
120
|
+
<td>
|
121
|
+
slash/slash-head<br />
|
122
|
+
</td>
|
123
|
+
</tr>
|
124
|
+
<tr>
|
125
|
+
<th align="left">x86 Assembly</th>
|
126
|
+
</td>
|
127
|
+
<td>
|
128
|
+
assembly/nasm-2.07<br />
|
129
|
+
</td>
|
130
|
+
</tr>
|
131
|
+
</table>
|
132
|
+
|
133
|
+
|
134
|
+
Example
|
135
|
+
-------
|
136
|
+
|
137
|
+
It's this simple:
|
138
|
+
|
139
|
+
```ruby
|
140
|
+
require 'eval_in'
|
141
|
+
|
142
|
+
result = EvalIn.call 'puts "hello, #{gets}"', stdin: 'world', language: "ruby/mri-2.1"
|
143
|
+
|
144
|
+
result.exitstatus # => 0
|
145
|
+
result.language # => "ruby/mri-2.1"
|
146
|
+
result.language_friendly # => "Ruby — MRI 2.1"
|
147
|
+
result.code # => "puts \"hello, \#{gets}\""
|
148
|
+
result.output # => "hello, world\n"
|
149
|
+
result.status # => "OK (0.052 sec real, 0.059 sec wall, 9 MB, 21 syscalls)"
|
150
|
+
```
|
151
|
+
|
152
|
+
Essentially a wrapper around:
|
153
|
+
|
154
|
+
```sh
|
155
|
+
curl https://eval.in/ \
|
156
|
+
-i \
|
157
|
+
-d utf8=√ \
|
158
|
+
-d code='print "hello #{gets}"' \
|
159
|
+
-d execute=on \
|
160
|
+
-d lang=ruby/mri-1.9.3 \
|
161
|
+
-d input=world \
|
162
|
+
| ruby -ane 'puts "#{$F[1]}.json" if /^Loc/' \
|
163
|
+
| xargs curl
|
164
|
+
```
|
165
|
+
|
166
|
+
Attribution
|
167
|
+
-----------
|
168
|
+
|
169
|
+
Thanks to [Charlie Sommerville](https://twitter.com/charliesome) for making eval-in.
|
170
|
+
|
171
|
+
Thanks to Mon Oui, I partially stole the implementation from his gem [cinch-eval-in](http://rubygems.org/gems/cinch-eval-in)
|
172
|
+
|
173
|
+
|
174
|
+
License
|
175
|
+
-------
|
176
|
+
|
177
|
+
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
|
178
|
+
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
179
|
+
|
180
|
+
0. You just DO WHAT THE FUCK YOU WANT TO.
|
181
|
+
|
182
|
+
No Warranty
|
183
|
+
-----------
|
184
|
+
|
185
|
+
The software is provided "as is", without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose and noninfringement. In no event shall the authors or copyright holders be liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in connection with the software or the use or other dealings in the software.
|
186
|
+
|
data/eval_in.gemspec
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "eval_in/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "eval_in"
|
7
|
+
s.version = EvalIn::VERSION
|
8
|
+
s.authors = ["Josh Cheek"]
|
9
|
+
s.email = ["josh.cheek@gmail.com"]
|
10
|
+
s.homepage = "https://github.com/JoshCheek/eval_in"
|
11
|
+
s.summary = %q{Evaluates code (Ruby and others) safely by sending it to https://eval.in}
|
12
|
+
s.description = <<-DESCRIPTION.gsub(/^ /, '')
|
13
|
+
Safely evaluates code (Ruby and others) by sending it through https://eval.in
|
14
|
+
|
15
|
+
== Languages and Versions
|
16
|
+
|
17
|
+
C | GCC 4.4.3, GCC 4.9.1
|
18
|
+
C++ | C++11 (GCC 4.9.1), GCC 4.4.3, GCC 4.9.1
|
19
|
+
CoffeeScript | CoffeeScript 1.7.1 (Node 0.10.29)
|
20
|
+
Fortran | F95 (GCC 4.4.3)
|
21
|
+
Haskell | Hugs98 September 2006
|
22
|
+
Io | Io 20131204
|
23
|
+
JavaScript | Node 0.10.29
|
24
|
+
Lua | Lua 5.1.5, Lua 5.2.3
|
25
|
+
OCaml | OCaml 4.01.0
|
26
|
+
PHP | PHP 5.5.14
|
27
|
+
Pascal | Free Pascal 2.6.4
|
28
|
+
Perl | Perl 5.20.0
|
29
|
+
Python | CPython 2.7.8, CPython 3.4.1
|
30
|
+
Ruby | MRI 1.0, MRI 1.8.7, MRI 1.9.3, MRI 2.0.0, MRI 2.1
|
31
|
+
Slash | Slash HEAD
|
32
|
+
x86 Assembly | NASM 2.07
|
33
|
+
|
34
|
+
== Example:
|
35
|
+
|
36
|
+
It's this simple:
|
37
|
+
|
38
|
+
result = EvalIn.call 'puts "hello, world"', language: "ruby/mri-2.1"
|
39
|
+
result.output # "hello, world\n"
|
40
|
+
|
41
|
+
DESCRIPTION
|
42
|
+
s.license = "WTFPL"
|
43
|
+
|
44
|
+
s.files = `git ls-files`.split("\n") - ['docs/seeing is believing.psd'] # remove psd b/c it boosts the gem size from 50kb to 20mb O.o
|
45
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
46
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
47
|
+
s.require_paths = ['lib']
|
48
|
+
|
49
|
+
s.add_development_dependency 'rspec', '~> 3.0'
|
50
|
+
s.add_development_dependency 'webmock', '~> 1.18'
|
51
|
+
end
|
data/lib/eval_in.rb
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'uri'
|
2
|
+
require 'json'
|
3
|
+
require 'net/http'
|
4
|
+
require 'eval_in/version'
|
5
|
+
|
6
|
+
module EvalIn
|
7
|
+
EvalInError = Class.new StandardError
|
8
|
+
RequestError = Class.new EvalInError
|
9
|
+
ResultNotFound = Class.new EvalInError
|
10
|
+
|
11
|
+
KNOWN_LANGUAGES = %w[
|
12
|
+
c/gcc-4.4.3
|
13
|
+
c/gcc-4.9.1
|
14
|
+
c++/c++11-gcc-4.9.1
|
15
|
+
c++/gcc-4.4.3
|
16
|
+
c++/gcc-4.9.1
|
17
|
+
coffeescript/node-0.10.29-coffee-1.7.1
|
18
|
+
fortran/f95-4.4.3
|
19
|
+
haskell/hugs98-sep-2006
|
20
|
+
io/io-20131204
|
21
|
+
javascript/node-0.10.29
|
22
|
+
lua/lua-5.1.5
|
23
|
+
lua/lua-5.2.3
|
24
|
+
ocaml/ocaml-4.01.0
|
25
|
+
php/php-5.5.14
|
26
|
+
pascal/fpc-2.6.4
|
27
|
+
perl/perl-5.20.0
|
28
|
+
python/cpython-2.7.8
|
29
|
+
python/cpython-3.4.1
|
30
|
+
ruby/mri-1.0
|
31
|
+
ruby/mri-1.8.7
|
32
|
+
ruby/mri-1.9.3
|
33
|
+
ruby/mri-2.0.0
|
34
|
+
ruby/mri-2.1
|
35
|
+
slash/slash-head
|
36
|
+
assembly/nasm-2.07
|
37
|
+
]
|
38
|
+
|
39
|
+
class Result
|
40
|
+
attr_accessor :exitstatus, :language, :language_friendly, :code, :output, :status
|
41
|
+
|
42
|
+
def initialize(attributes={})
|
43
|
+
attributes = attributes.dup
|
44
|
+
self.exitstatus = attributes.delete(:exitstatus) || -1
|
45
|
+
self.language = attributes.delete(:language) || ""
|
46
|
+
self.language_friendly = attributes.delete(:language_friendly) || ""
|
47
|
+
self.code = attributes.delete(:code) || ""
|
48
|
+
self.output = attributes.delete(:output) || ""
|
49
|
+
self.status = attributes.delete(:status) || ""
|
50
|
+
$stderr.puts "Unexpected attributes! #{attributes.keys.inspect}" if attributes.any?
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.call(code, options={})
|
55
|
+
build_result get_code post_code(code, options)
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.post_code(code, options)
|
59
|
+
uri = URI(options.fetch(:url, "https://eval.in/"))
|
60
|
+
input = options.fetch(:stdin, "")
|
61
|
+
language = options.fetch(:language)
|
62
|
+
result = Net::HTTP.post_form(uri, "utf8" => "√", "code" => code, "execute" => "on", "lang" => language, "input" => input)
|
63
|
+
if result.code == '302'
|
64
|
+
location = result['location']
|
65
|
+
location += '.json' unless location.end_with? '.json'
|
66
|
+
location
|
67
|
+
elsif KNOWN_LANGUAGES.include? language
|
68
|
+
raise RequestError, "There was an unexpected error, we got back a response code of #{result.code}"
|
69
|
+
else
|
70
|
+
raise RequestError, "Perhaps language is wrong, you provided: #{language.inspect}\n"\
|
71
|
+
"Known languages are: #{KNOWN_LANGUAGES.inspect}"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def self.get_code(location)
|
76
|
+
if body = Net::HTTP.get(URI location)
|
77
|
+
JSON.parse body
|
78
|
+
else
|
79
|
+
raise ResultNotFound, "No json at #{location.inspect}"
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def self.build_result(response_json)
|
84
|
+
status = response_json['status']
|
85
|
+
exitstatus = if !status then nil # let it choose default
|
86
|
+
elsif status =~ /status (\d+)$/ then $1.to_i
|
87
|
+
else 0
|
88
|
+
end
|
89
|
+
|
90
|
+
Result.new exitstatus: exitstatus,
|
91
|
+
language: response_json['lang'],
|
92
|
+
language_friendly: response_json['lang_friendly'],
|
93
|
+
code: response_json['code'],
|
94
|
+
output: response_json['output'],
|
95
|
+
status: response_json['status']
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,226 @@
|
|
1
|
+
require 'eval_in'
|
2
|
+
require 'webmock'
|
3
|
+
WebMock.disable_net_connect!
|
4
|
+
|
5
|
+
RSpec.configure do |config|
|
6
|
+
config.filter_run_excluding integration: true
|
7
|
+
|
8
|
+
config.include Module.new {
|
9
|
+
def assert_result(result, attributes)
|
10
|
+
attributes.each do |key, value|
|
11
|
+
expect(result.public_send key).to eq value
|
12
|
+
end
|
13
|
+
end
|
14
|
+
}
|
15
|
+
|
16
|
+
config.after do
|
17
|
+
WebMock.reset!
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
RSpec.describe EvalIn, integration: true do
|
22
|
+
around do |spec|
|
23
|
+
WebMock.allow_net_connect!
|
24
|
+
spec.call
|
25
|
+
WebMock.disable_net_connect!
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'evaluates Ruby code through eval.in' do
|
29
|
+
result = EvalIn.call 'print "hello, #{gets}"', stdin: "world", language: "ruby/mri-1.9.3"
|
30
|
+
expect(result.exitstatus ).to eq 0
|
31
|
+
expect(result.language ).to eq "ruby/mri-1.9.3"
|
32
|
+
expect(result.language_friendly).to eq "Ruby — MRI 1.9.3"
|
33
|
+
expect(result.code ).to eq 'print "hello, #{gets}"'
|
34
|
+
expect(result.output ).to eq "hello, world"
|
35
|
+
expect(result.status ).to match /OK \([\d.]+ sec real, [\d.]+ sec wall, \d MB, \d+ syscalls\)/
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
RSpec.describe EvalIn::Result do
|
40
|
+
it 'initializes with the provided attributes' do
|
41
|
+
result = EvalIn::Result.new exitstatus: 123,
|
42
|
+
language: 'the language',
|
43
|
+
language_friendly: 'the friendly language',
|
44
|
+
code: 'the code',
|
45
|
+
output: 'the output',
|
46
|
+
status: 'the status'
|
47
|
+
assert_result result,
|
48
|
+
exitstatus: 123,
|
49
|
+
language: 'the language',
|
50
|
+
language_friendly: 'the friendly language',
|
51
|
+
code: 'the code',
|
52
|
+
output: 'the output',
|
53
|
+
status: 'the status'
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'uses sensible type-correct defaults for missing attributes' do
|
57
|
+
assert_result EvalIn::Result.new,
|
58
|
+
exitstatus: -1,
|
59
|
+
language: '',
|
60
|
+
language_friendly: '',
|
61
|
+
code: '',
|
62
|
+
output: '',
|
63
|
+
status: ''
|
64
|
+
assert_result EvalIn::Result.new(language: nil,
|
65
|
+
language_friendly: nil,
|
66
|
+
code: nil,
|
67
|
+
output: nil,
|
68
|
+
status: nil),
|
69
|
+
exitstatus: -1,
|
70
|
+
language: '',
|
71
|
+
language_friendly: '',
|
72
|
+
code: '',
|
73
|
+
output: '',
|
74
|
+
status: ''
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'doesn\'t mutate the input attributes' do
|
78
|
+
attributes = {status: 'OK'}
|
79
|
+
EvalIn::Result.new attributes
|
80
|
+
expect(attributes).to eq status: 'OK'
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'logs extra attributes to the error stream' do
|
84
|
+
expect { EvalIn::Result.new a: 1, b: 2 }.to \
|
85
|
+
output("Unexpected attributes! [:a, :b]\n").to_stderr
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
|
90
|
+
RSpec.describe 'post_code' do
|
91
|
+
include WebMock::API
|
92
|
+
|
93
|
+
# ACTUAL RESPONSE:
|
94
|
+
#
|
95
|
+
# HTTP/1.1 302 Found\r
|
96
|
+
# Server: nginx/1.4.6 (Ubuntu)\r
|
97
|
+
# Date: Sun, 24 Aug 2014 05:57:17 GMT\r
|
98
|
+
# Content-Type: text/html;charset=utf-8\r
|
99
|
+
# Content-Length: 0\r
|
100
|
+
# Connection: keep-alive\r
|
101
|
+
# Location: https://eval.in/182584
|
102
|
+
# X-XSS-Protection: 1; mode=block\r
|
103
|
+
# X-Content-Type-Options: nosniff\r
|
104
|
+
# X-Frame-Options: SAMEORIGIN\r
|
105
|
+
# X-Runtime: 0.042154\r
|
106
|
+
# Strict-Transport-Security: max-age=31536000\r
|
107
|
+
# \r
|
108
|
+
def stub_eval_in(data=expected_data)
|
109
|
+
stub_request(:post, url)
|
110
|
+
.with(:body => data)
|
111
|
+
.to_return(status: 302, headers: {'Location' => result_location})
|
112
|
+
end
|
113
|
+
|
114
|
+
let(:code) { 'print "hello, #{gets}"' }
|
115
|
+
let(:stdin) { "world" }
|
116
|
+
let(:language) { "ruby/mri-1.9.3" }
|
117
|
+
let(:expected_data) { {"utf8" => "√", "code" => code, "execute" => "on", "lang" => language, "input" => stdin} }
|
118
|
+
let(:result_location) { 'https://eval.in/182584' }
|
119
|
+
let(:url) { "https://eval.in/" }
|
120
|
+
|
121
|
+
it 'posts the data to eval_in with utf8, execute on, and the code/language/input forwarded through' do
|
122
|
+
stub_eval_in expected_data
|
123
|
+
EvalIn.post_code code, stdin: stdin, language: language
|
124
|
+
end
|
125
|
+
|
126
|
+
it 'returns the redirect location jsonified' do
|
127
|
+
stub_eval_in expected_data
|
128
|
+
result = EvalIn.post_code code, stdin: stdin, language: language
|
129
|
+
expect(result).to eq "#{result_location}.json"
|
130
|
+
end
|
131
|
+
|
132
|
+
it 'sets input to empty string if not provided' do
|
133
|
+
stub_eval_in expected_data.merge('input' => '')
|
134
|
+
EvalIn.post_code code, language: language
|
135
|
+
end
|
136
|
+
|
137
|
+
it 'raises an ArgumentError error if not given a language' do
|
138
|
+
expect { EvalIn.post_code code, {} }.to raise_error KeyError, /language/
|
139
|
+
end
|
140
|
+
|
141
|
+
it 'can override the url' do
|
142
|
+
url.replace "http://example.com"
|
143
|
+
stub_eval_in
|
144
|
+
EvalIn.post_code code, url: 'http://example.com', stdin: stdin, language: language
|
145
|
+
end
|
146
|
+
|
147
|
+
context 'when it gets a non-redirect' do
|
148
|
+
it 'informs user of language provided and languages known if language is unknown' do
|
149
|
+
stub_request(:post, "https://eval.in/").to_return(status: 406)
|
150
|
+
expect { EvalIn.post_code code, language: 'unknown-language' }.to \
|
151
|
+
raise_error EvalIn::RequestError, /unknown-language.*?ruby\/mri-2.1/m
|
152
|
+
end
|
153
|
+
|
154
|
+
it 'just bubbles the existing error up if it knows the language' do
|
155
|
+
stub_request(:post, "https://eval.in/").to_return(status: 406)
|
156
|
+
expect { EvalIn.post_code code, language: 'ruby/mri-2.1' }.to \
|
157
|
+
raise_error EvalIn::RequestError, /406/
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
|
163
|
+
|
164
|
+
RSpec.describe 'get_code' do
|
165
|
+
include WebMock::API
|
166
|
+
|
167
|
+
def stub_eval_in(options={})
|
168
|
+
stub_request(:get, options.fetch(:url))
|
169
|
+
.to_return(status: options.fetch(:status, 200),
|
170
|
+
body: options.fetch(:json_result, json_result))
|
171
|
+
end
|
172
|
+
|
173
|
+
let(:ruby_result) { {'lang' => 'some lang', 'lang_friendly' => 'some lang friendly', 'code' => 'some code', 'output' => 'some output', 'status' => 'some status'} }
|
174
|
+
let(:json_result) { JSON.dump ruby_result }
|
175
|
+
|
176
|
+
it 'queries the location, and inflates the json' do
|
177
|
+
stub_eval_in(url: "http://example.com/some-result.json")
|
178
|
+
result = EvalIn.get_code "http://example.com/some-result.json"
|
179
|
+
expect(result).to eq ruby_result
|
180
|
+
end
|
181
|
+
|
182
|
+
it 'raises an error when it gets a non-200' do
|
183
|
+
stub_eval_in json_result: '', url: 'http://whatever.com'
|
184
|
+
expect { EvalIn.get_code "http://whatever.com" }.to \
|
185
|
+
raise_error EvalIn::ResultNotFound, %r(http://whatever.com)
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
|
190
|
+
RSpec.describe 'build_result' do
|
191
|
+
let(:language) { 'some lang' }
|
192
|
+
let(:language_friendly) { 'some lang friendly' }
|
193
|
+
let(:code) { 'some code' }
|
194
|
+
let(:output) { 'some output' }
|
195
|
+
let(:status) { 'some status' }
|
196
|
+
let(:response_json) { {'lang' => language, 'lang_friendly' => language_friendly, 'code' => code, 'output' => output, 'status' => status} }
|
197
|
+
|
198
|
+
it 'returns a response for the given response json' do
|
199
|
+
result = EvalIn.build_result response_json
|
200
|
+
assert_result result,
|
201
|
+
exitstatus: 0,
|
202
|
+
language: language,
|
203
|
+
language_friendly: language_friendly,
|
204
|
+
code: code,
|
205
|
+
output: output,
|
206
|
+
status: status
|
207
|
+
end
|
208
|
+
|
209
|
+
# exit: https://eval.in/182586.json
|
210
|
+
# raise: https://eval.in/182587.json
|
211
|
+
# in C: https://eval.in/182588.json
|
212
|
+
it 'sets the exit status to that of the program when it is available' do
|
213
|
+
result = EvalIn.build_result response_json.merge('status' => "Exited with error status 123")
|
214
|
+
expect(result.exitstatus).to eq 123
|
215
|
+
end
|
216
|
+
|
217
|
+
it 'sets the exit status to -1 when it is not available' do
|
218
|
+
result = EvalIn.build_result response_json.merge('status' => nil)
|
219
|
+
expect(result.exitstatus).to eq -1
|
220
|
+
end
|
221
|
+
|
222
|
+
it 'sets the exit status to 0 when the status does not imply a nonzero exit status' do
|
223
|
+
result = EvalIn.build_result response_json.merge('status' => 'OK (0.012 sec real, 0.013 sec wall, 7 MB, 22 syscalls)')
|
224
|
+
expect(result.exitstatus).to eq 0
|
225
|
+
end
|
226
|
+
end
|
metadata
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: eval_in
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Josh Cheek
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-08-24 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rspec
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '3.0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '3.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: webmock
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.18'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.18'
|
41
|
+
description: |+
|
42
|
+
Safely evaluates code (Ruby and others) by sending it through https://eval.in
|
43
|
+
|
44
|
+
== Languages and Versions
|
45
|
+
|
46
|
+
C | GCC 4.4.3, GCC 4.9.1
|
47
|
+
C++ | C++11 (GCC 4.9.1), GCC 4.4.3, GCC 4.9.1
|
48
|
+
CoffeeScript | CoffeeScript 1.7.1 (Node 0.10.29)
|
49
|
+
Fortran | F95 (GCC 4.4.3)
|
50
|
+
Haskell | Hugs98 September 2006
|
51
|
+
Io | Io 20131204
|
52
|
+
JavaScript | Node 0.10.29
|
53
|
+
Lua | Lua 5.1.5, Lua 5.2.3
|
54
|
+
OCaml | OCaml 4.01.0
|
55
|
+
PHP | PHP 5.5.14
|
56
|
+
Pascal | Free Pascal 2.6.4
|
57
|
+
Perl | Perl 5.20.0
|
58
|
+
Python | CPython 2.7.8, CPython 3.4.1
|
59
|
+
Ruby | MRI 1.0, MRI 1.8.7, MRI 1.9.3, MRI 2.0.0, MRI 2.1
|
60
|
+
Slash | Slash HEAD
|
61
|
+
x86 Assembly | NASM 2.07
|
62
|
+
|
63
|
+
== Example:
|
64
|
+
|
65
|
+
It's this simple:
|
66
|
+
|
67
|
+
result = EvalIn.call 'puts "hello, world"', language: "ruby/mri-2.1"
|
68
|
+
result.output # "hello, world
|
69
|
+
"
|
70
|
+
|
71
|
+
email:
|
72
|
+
- josh.cheek@gmail.com
|
73
|
+
executables: []
|
74
|
+
extensions: []
|
75
|
+
extra_rdoc_files: []
|
76
|
+
files:
|
77
|
+
- ".gitignore"
|
78
|
+
- Gemfile
|
79
|
+
- Gemfile.lock
|
80
|
+
- Readme.md
|
81
|
+
- eval_in.gemspec
|
82
|
+
- lib/eval_in.rb
|
83
|
+
- lib/eval_in/version.rb
|
84
|
+
- spec/eval_in_spec.rb
|
85
|
+
homepage: https://github.com/JoshCheek/eval_in
|
86
|
+
licenses:
|
87
|
+
- WTFPL
|
88
|
+
metadata: {}
|
89
|
+
post_install_message:
|
90
|
+
rdoc_options: []
|
91
|
+
require_paths:
|
92
|
+
- lib
|
93
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - ">="
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: '0'
|
98
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
99
|
+
requirements:
|
100
|
+
- - ">="
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: '0'
|
103
|
+
requirements: []
|
104
|
+
rubyforge_project:
|
105
|
+
rubygems_version: 2.2.2
|
106
|
+
signing_key:
|
107
|
+
specification_version: 4
|
108
|
+
summary: Evaluates code (Ruby and others) safely by sending it to https://eval.in
|
109
|
+
test_files:
|
110
|
+
- spec/eval_in_spec.rb
|
111
|
+
has_rdoc:
|