eval_in 0.1.3 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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