eval_in 0.1.3 → 0.1.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Readme.md +12 -11
- data/eval_in.gemspec +3 -3
- data/lib/eval_in.rb +49 -16
- data/lib/eval_in/version.rb +1 -1
- data/spec/eval_in_spec.rb +92 -4
- metadata +6 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8331a9a20d6f485a925ca9e29ff4daf3c5beebad
|
4
|
+
data.tar.gz: 4c62d600cddd2acf41608da7832a2aa268a5a05e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fd354b9ded63f728f01eb81b37952ae8ba97e2ceae8dd7b1d6e7cb76e06eb0d6eb2395ff74902e71f76497ddf470cf0b4dc49331c0153a2ff2f59aeb9ab9dadd
|
7
|
+
data.tar.gz: 0f15ac725abf2c871d3e50bc08244fbc6a2b8c8173bcdeb068ab4c4c7ed99ebeb53e1f3db0c00e11ab38a07bca5d3cddb142679b906086e76ab6654efa4eaf2c
|
data/Readme.md
CHANGED
@@ -24,11 +24,23 @@ result.code # => "puts \"hello, \#{gets}\""
|
|
24
24
|
result.status # => "OK (0.064 sec real, 0.073 sec wall, 9 MB, 21 syscalls)"
|
25
25
|
```
|
26
26
|
|
27
|
+
Docs are [here](http://rdoc.info/gems/eval_in/frames/EvalIn).
|
27
28
|
|
28
29
|
What languages can this run?
|
29
30
|
----------------------------
|
30
31
|
|
31
32
|
<table>
|
33
|
+
<tr>
|
34
|
+
<th align="left">Ruby</th>
|
35
|
+
</td>
|
36
|
+
<td>
|
37
|
+
ruby/mri-1.0<br />
|
38
|
+
ruby/mri-1.8.7<br />
|
39
|
+
ruby/mri-1.9.3<br />
|
40
|
+
ruby/mri-2.0.0<br />
|
41
|
+
ruby/mri-2.1<br />
|
42
|
+
</td>
|
43
|
+
</tr>
|
32
44
|
<tr>
|
33
45
|
<th align="left">C</th>
|
34
46
|
</td>
|
@@ -125,17 +137,6 @@ What languages can this run?
|
|
125
137
|
python/cpython-3.4.1<br />
|
126
138
|
</td>
|
127
139
|
</tr>
|
128
|
-
<tr>
|
129
|
-
<th align="left">Ruby</th>
|
130
|
-
</td>
|
131
|
-
<td>
|
132
|
-
ruby/mri-1.0<br />
|
133
|
-
ruby/mri-1.8.7<br />
|
134
|
-
ruby/mri-1.9.3<br />
|
135
|
-
ruby/mri-2.0.0<br />
|
136
|
-
ruby/mri-2.1<br />
|
137
|
-
</td>
|
138
|
-
</tr>
|
139
140
|
<tr>
|
140
141
|
<th align="left">Slash</th>
|
141
142
|
</td>
|
data/eval_in.gemspec
CHANGED
@@ -14,6 +14,7 @@ Gem::Specification.new do |s|
|
|
14
14
|
|
15
15
|
== Languages and Versions
|
16
16
|
|
17
|
+
Ruby | MRI 1.0, MRI 1.8.7, MRI 1.9.3, MRI 2.0.0, MRI 2.1
|
17
18
|
C | GCC 4.4.3, GCC 4.9.1
|
18
19
|
C++ | C++11 (GCC 4.9.1), GCC 4.4.3, GCC 4.9.1
|
19
20
|
CoffeeScript | CoffeeScript 1.7.1 (Node 0.10.29)
|
@@ -27,7 +28,6 @@ Gem::Specification.new do |s|
|
|
27
28
|
Pascal | Free Pascal 2.6.4
|
28
29
|
Perl | Perl 5.20.0
|
29
30
|
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
31
|
Slash | Slash HEAD
|
32
32
|
x86 Assembly | NASM 2.07
|
33
33
|
|
@@ -35,8 +35,8 @@ Gem::Specification.new do |s|
|
|
35
35
|
|
36
36
|
It's this simple:
|
37
37
|
|
38
|
-
result = EvalIn.call 'puts "
|
39
|
-
result.output # "
|
38
|
+
result = EvalIn.call 'puts "example"', language: "ruby/mri-2.1"
|
39
|
+
result.output # returns "example\\n"
|
40
40
|
|
41
41
|
DESCRIPTION
|
42
42
|
s.license = "WTFPL"
|
data/lib/eval_in.rb
CHANGED
@@ -43,7 +43,11 @@ module EvalIn
|
|
43
43
|
# The data structure containing the final result
|
44
44
|
# its attributes default to null-objects for their given type
|
45
45
|
class Result
|
46
|
-
|
46
|
+
@attribute_names = [:exitstatus, :language, :language_friendly, :code, :output, :status, :url].freeze
|
47
|
+
attr_accessor *@attribute_names
|
48
|
+
class << self
|
49
|
+
attr_reader :attribute_names
|
50
|
+
end
|
47
51
|
|
48
52
|
def initialize(attributes={})
|
49
53
|
attributes = attributes.dup
|
@@ -54,7 +58,15 @@ module EvalIn
|
|
54
58
|
self.output = attributes.delete(:output) || ""
|
55
59
|
self.status = attributes.delete(:status) || ""
|
56
60
|
self.url = attributes.delete(:url) || ""
|
57
|
-
|
61
|
+
stderr = attributes.delete(:stderr) || $stderr
|
62
|
+
stderr.puts "Unexpected attributes! #{attributes.keys.inspect}" if attributes.any?
|
63
|
+
end
|
64
|
+
|
65
|
+
# Returns representation of the result built out of JSON primitives (hash, string, int)
|
66
|
+
def as_json
|
67
|
+
self.class.attribute_names.each_with_object Hash.new do |name, attributes|
|
68
|
+
attributes[name.to_s] = public_send name
|
69
|
+
end
|
58
70
|
end
|
59
71
|
end
|
60
72
|
|
@@ -69,7 +81,16 @@ module EvalIn
|
|
69
81
|
# result = EvalIn.call 'puts "hello, #{gets}"', stdin: 'world', language: "ruby/mri-2.1"
|
70
82
|
# result.output # => "hello, world\n"
|
71
83
|
def self.call(code, options={})
|
72
|
-
|
84
|
+
fetch_result post_code(code, options)
|
85
|
+
end
|
86
|
+
|
87
|
+
# @param url [String] the url with the result
|
88
|
+
#
|
89
|
+
# @example
|
90
|
+
# result = EvalIn.fetch_result "https://eval.in/147.json"
|
91
|
+
# result.output # => "Hello Charlie! "
|
92
|
+
def self.fetch_result(url)
|
93
|
+
build_result fetch_result_json jsonify_url url
|
73
94
|
end
|
74
95
|
|
75
96
|
# @api private
|
@@ -94,9 +115,7 @@ module EvalIn
|
|
94
115
|
}
|
95
116
|
|
96
117
|
if result.code == '302'
|
97
|
-
|
98
|
-
location += '.json' unless location.end_with? '.json'
|
99
|
-
location
|
118
|
+
jsonify_url result['location']
|
100
119
|
elsif KNOWN_LANGUAGES.include? language
|
101
120
|
raise RequestError, "There was an unexpected error, we got back a response code of #{result.code}"
|
102
121
|
else
|
@@ -107,20 +126,27 @@ module EvalIn
|
|
107
126
|
|
108
127
|
# @api private
|
109
128
|
def self.fetch_result_json(location)
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
129
|
+
# Can't just use Net::HTTP.get, b/c it doesn't use ssl on 1.9.3
|
130
|
+
# https://github.com/ruby/ruby/blob/v2_1_2/lib/net/http.rb#L478-479
|
131
|
+
# https://github.com/ruby/ruby/blob/v1_9_3_547/lib/net/http.rb#L454
|
132
|
+
uri = URI location
|
133
|
+
Net::HTTP.start(uri.hostname, uri.port, use_ssl: (uri.scheme == 'https')) { |http|
|
134
|
+
body = http.request_get(uri.request_uri).body
|
135
|
+
if body
|
136
|
+
JSON.parse(body).merge('url' => location)
|
137
|
+
else
|
138
|
+
raise ResultNotFound, "No json at #{location.inspect}"
|
139
|
+
end
|
140
|
+
}
|
115
141
|
end
|
116
142
|
|
117
143
|
# @api private
|
118
144
|
def self.build_result(response_json)
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
else
|
145
|
+
exitstatus = case response_json['status']
|
146
|
+
when nil then nil # let it choose default
|
147
|
+
when /status (\d+)$/ then $1.to_i
|
148
|
+
when /^Forbidden/ then 1
|
149
|
+
else 0
|
124
150
|
end
|
125
151
|
|
126
152
|
Result.new exitstatus: exitstatus,
|
@@ -131,4 +157,11 @@ module EvalIn
|
|
131
157
|
status: response_json['status'],
|
132
158
|
url: response_json['url']
|
133
159
|
end
|
160
|
+
|
161
|
+
# @api private
|
162
|
+
def self.jsonify_url(url)
|
163
|
+
uri = URI(url)
|
164
|
+
uri.path = Pathname.new(uri.path).sub_ext('.json').to_s
|
165
|
+
uri.to_s
|
166
|
+
end
|
134
167
|
end
|
data/lib/eval_in/version.rb
CHANGED
data/spec/eval_in_spec.rb
CHANGED
@@ -28,15 +28,26 @@ RSpec.describe EvalIn, integration: true do
|
|
28
28
|
end
|
29
29
|
|
30
30
|
it 'evaluates Ruby code through eval.in' do
|
31
|
-
result = EvalIn.call 'print "hello, #{gets}"', stdin: "world", language: "ruby/mri-1
|
31
|
+
result = EvalIn.call 'print "hello, #{gets}"', stdin: "world", language: "ruby/mri-2.1", context: 'eval_in integration test'
|
32
32
|
expect(result.exitstatus ).to eq 0
|
33
|
-
expect(result.language ).to eq "ruby/mri-1
|
34
|
-
expect(result.language_friendly).to eq "Ruby — MRI 1
|
33
|
+
expect(result.language ).to eq "ruby/mri-2.1"
|
34
|
+
expect(result.language_friendly).to eq "Ruby — MRI 2.1"
|
35
35
|
expect(result.code ).to eq 'print "hello, #{gets}"'
|
36
36
|
expect(result.output ).to eq "hello, world"
|
37
37
|
expect(result.status ).to match /OK \([\d.]+ sec real, [\d.]+ sec wall, \d MB, \d+ syscalls\)/
|
38
38
|
expect(result.url ).to match %r(https://eval.in/\d+.json)
|
39
39
|
end
|
40
|
+
|
41
|
+
it 'fetches previous results from eval.in' do
|
42
|
+
result = EvalIn.fetch_result "https://eval.in/147.json"
|
43
|
+
expect(result.exitstatus ).to eq 0
|
44
|
+
expect(result.language ).to eq "ruby/mri-1.9.3"
|
45
|
+
expect(result.language_friendly).to eq "Ruby — MRI 1.9.3"
|
46
|
+
expect(result.code ).to eq %'class Greeter\r\n def initialize(name)\r\n @name = name\r\n end\r\n\r\n def greet\r\n puts \"Hello \#{@name}!\"\r\n end\r\nend\r\n\r\ngreeter = Greeter.new \"Charlie\"\r\ngreeter.greet'
|
47
|
+
expect(result.output ).to eq "Hello Charlie!\n"
|
48
|
+
expect(result.status ).to match /OK \([\d.]+ sec real, [\d.]+ sec wall, \d MB, \d+ syscalls\)/
|
49
|
+
expect(result.url ).to match %r(https://eval.in/147.json)
|
50
|
+
end
|
40
51
|
end
|
41
52
|
|
42
53
|
RSpec.describe EvalIn::Result do
|
@@ -86,10 +97,32 @@ RSpec.describe EvalIn::Result do
|
|
86
97
|
expect(attributes).to eq status: 'OK'
|
87
98
|
end
|
88
99
|
|
89
|
-
it 'logs extra attributes to
|
100
|
+
it 'logs extra attributes to stderr input' do
|
101
|
+
fake_error_stream = StringIO.new
|
102
|
+
EvalIn::Result.new a: 1, b: 2, stderr: fake_error_stream
|
103
|
+
expect(fake_error_stream.string).to eq "Unexpected attributes! [:a, :b]\n"
|
104
|
+
end
|
105
|
+
|
106
|
+
it 'defaults the error stream to $stderr' do
|
90
107
|
expect { EvalIn::Result.new a: 1, b: 2 }.to \
|
91
108
|
output("Unexpected attributes! [:a, :b]\n").to_stderr
|
92
109
|
end
|
110
|
+
|
111
|
+
it 'has an as_json representation which dumps all its keys' do
|
112
|
+
result = EvalIn::Result.new(language: 'l',
|
113
|
+
language_friendly: 'lf',
|
114
|
+
code: 'c',
|
115
|
+
output: 'o',
|
116
|
+
status: 's',
|
117
|
+
url: 'u')
|
118
|
+
expect(result.as_json).to eq 'exitstatus' => -1,
|
119
|
+
'language' => 'l',
|
120
|
+
'language_friendly' => 'lf',
|
121
|
+
'code' => 'c',
|
122
|
+
'output' => 'o',
|
123
|
+
'status' => 's',
|
124
|
+
'url' => 'u'
|
125
|
+
end
|
93
126
|
end
|
94
127
|
|
95
128
|
|
@@ -271,3 +304,58 @@ RSpec.describe 'build_result' do
|
|
271
304
|
expect(result.exitstatus).to eq 1
|
272
305
|
end
|
273
306
|
end
|
307
|
+
|
308
|
+
|
309
|
+
RSpec.describe 'fetch_result' do
|
310
|
+
include WebMock::API
|
311
|
+
|
312
|
+
def stub_eval_in(url)
|
313
|
+
stub_request(:get, url)
|
314
|
+
.to_return(status: 200, body: json_result)
|
315
|
+
end
|
316
|
+
|
317
|
+
let(:ruby_result) { {'lang' => 'some lang', 'lang_friendly' => 'some lang friendly', 'code' => 'some code', 'output' => 'some output', 'status' => 'some status'} }
|
318
|
+
let(:json_result) { JSON.dump ruby_result }
|
319
|
+
|
320
|
+
it 'wraps fetch_result_json and build_result' do
|
321
|
+
url = 'https://eval.in/1.json'
|
322
|
+
stub_eval_in url
|
323
|
+
result = EvalIn.fetch_result url
|
324
|
+
assert_result result,
|
325
|
+
exitstatus: 0,
|
326
|
+
language: ruby_result['lang'],
|
327
|
+
language_friendly: ruby_result['lang_friendly'],
|
328
|
+
code: ruby_result['code'],
|
329
|
+
output: ruby_result['output'],
|
330
|
+
status: ruby_result['status'],
|
331
|
+
url: url
|
332
|
+
end
|
333
|
+
|
334
|
+
it 'jsonifies the url if it isn\'t already' do
|
335
|
+
stub_eval_in 'https://eval.in/1.json'
|
336
|
+
expect(EvalIn.fetch_result('https://eval.in/1').url).to eq 'https://eval.in/1.json'
|
337
|
+
expect(EvalIn.fetch_result('https://eval.in/1.json').url).to eq 'https://eval.in/1.json'
|
338
|
+
end
|
339
|
+
end
|
340
|
+
|
341
|
+
|
342
|
+
RSpec.describe 'jsonify_url' do
|
343
|
+
def assert_transforms(initial_url, expected_url)
|
344
|
+
actual_url = EvalIn.jsonify_url(initial_url)
|
345
|
+
expect(actual_url).to eq expected_url
|
346
|
+
end
|
347
|
+
|
348
|
+
it 'appends .json to a url that is missing it' do
|
349
|
+
assert_transforms 'http://eval.in/1', 'http://eval.in/1.json'
|
350
|
+
assert_transforms 'http://eval.in/1.json', 'http://eval.in/1.json'
|
351
|
+
|
352
|
+
assert_transforms 'http://eval.in/1?a=b', 'http://eval.in/1.json?a=b'
|
353
|
+
assert_transforms 'http://eval.in/1.json?a=b', 'http://eval.in/1.json?a=b'
|
354
|
+
end
|
355
|
+
|
356
|
+
it 'changes .not-json to .json' do
|
357
|
+
assert_transforms 'http://eval.in/1.xml', 'http://eval.in/1.json'
|
358
|
+
assert_transforms 'http://eval.in/1.html', 'http://eval.in/1.json'
|
359
|
+
assert_transforms 'http://eval.in/1.html?a=b', 'http://eval.in/1.json?a=b'
|
360
|
+
end
|
361
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: eval_in
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Josh Cheek
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-08-
|
11
|
+
date: 2014-08-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|
@@ -43,6 +43,7 @@ description: |+
|
|
43
43
|
|
44
44
|
== Languages and Versions
|
45
45
|
|
46
|
+
Ruby | MRI 1.0, MRI 1.8.7, MRI 1.9.3, MRI 2.0.0, MRI 2.1
|
46
47
|
C | GCC 4.4.3, GCC 4.9.1
|
47
48
|
C++ | C++11 (GCC 4.9.1), GCC 4.4.3, GCC 4.9.1
|
48
49
|
CoffeeScript | CoffeeScript 1.7.1 (Node 0.10.29)
|
@@ -56,7 +57,6 @@ description: |+
|
|
56
57
|
Pascal | Free Pascal 2.6.4
|
57
58
|
Perl | Perl 5.20.0
|
58
59
|
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
60
|
Slash | Slash HEAD
|
61
61
|
x86 Assembly | NASM 2.07
|
62
62
|
|
@@ -64,8 +64,8 @@ description: |+
|
|
64
64
|
|
65
65
|
It's this simple:
|
66
66
|
|
67
|
-
result = EvalIn.call 'puts "
|
68
|
-
result.output # "
|
67
|
+
result = EvalIn.call 'puts "example"', language: "ruby/mri-2.1"
|
68
|
+
result.output # returns "example\n"
|
69
69
|
|
70
70
|
email:
|
71
71
|
- josh.cheek@gmail.com
|
@@ -101,7 +101,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
101
101
|
version: '0'
|
102
102
|
requirements: []
|
103
103
|
rubyforge_project:
|
104
|
-
rubygems_version: 2.
|
104
|
+
rubygems_version: 2.4.1
|
105
105
|
signing_key:
|
106
106
|
specification_version: 4
|
107
107
|
summary: Evaluates code (Ruby and others) safely by sending it to https://eval.in
|