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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e2ac0ca50e404a1fc715b523bc8b9db45a535408
4
- data.tar.gz: 10ea5829dd2688d4d8ef0cb99e96698e444e4705
3
+ metadata.gz: 8331a9a20d6f485a925ca9e29ff4daf3c5beebad
4
+ data.tar.gz: 4c62d600cddd2acf41608da7832a2aa268a5a05e
5
5
  SHA512:
6
- metadata.gz: 6765c3a9120b8799828308b123b383c8534ef2efeb4be536a3f42416109ca67b984bb435147091fadee23596a3a25e599c832eb7eb185ea3f79f643a0b25c56b
7
- data.tar.gz: 2a522bc23122290b37ec8f41de2b87206764db9699fb61fc577660fe685accdb93efd468f894d162046fb34975c0516ccff5b4eeec1a7b49e8259ee44d1a9a41
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>
@@ -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 "hello, world"', language: "ruby/mri-2.1"
39
- result.output # "hello, world\\n"
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"
@@ -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
- attr_accessor :exitstatus, :language, :language_friendly, :code, :output, :status, :url
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
- $stderr.puts "Unexpected attributes! #{attributes.keys.inspect}" if attributes.any?
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
- build_result fetch_result_json post_code(code, options)
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
- location = result['location']
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
- if body = Net::HTTP.get(URI location)
111
- JSON.parse(body).merge('url' => location)
112
- else
113
- raise ResultNotFound, "No json at #{location.inspect}"
114
- end
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
- status = response_json['status']
120
- exitstatus = if !status then nil # let it choose default
121
- elsif status =~ /status (\d+)$/ then $1.to_i
122
- elsif status =~ /^Forbidden/ then 1
123
- else 0
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
@@ -1,3 +1,3 @@
1
1
  module EvalIn
2
- VERSION = '0.1.3'
2
+ VERSION = '0.1.4'
3
3
  end
@@ -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.9.3", context: 'eval_in integration test'
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.9.3"
34
- expect(result.language_friendly).to eq "Ruby — MRI 1.9.3"
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 the error stream' do
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.3
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-27 00:00:00.000000000 Z
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 "hello, world"', language: "ruby/mri-2.1"
68
- result.output # "hello, world\n"
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.2.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