piston_sdk 0.1.0 → 0.2.0

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.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +3 -0
  3. data/CHANGELOG.md +34 -0
  4. data/README.md +1 -1
  5. data/lib/piston_sdk/version.rb +1 -1
  6. data/lib/piston_sdk.rb +178 -62
  7. data/sorbet/config +4 -0
  8. data/sorbet/rbi/annotations/.gitattributes +1 -0
  9. data/sorbet/rbi/annotations/rainbow.rbi +269 -0
  10. data/sorbet/rbi/gems/.gitattributes +1 -0
  11. data/sorbet/rbi/gems/ast@2.4.3.rbi +585 -0
  12. data/sorbet/rbi/gems/benchmark@0.4.1.rbi +619 -0
  13. data/sorbet/rbi/gems/date@3.4.1.rbi +75 -0
  14. data/sorbet/rbi/gems/diff-lcs@1.6.2.rbi +1134 -0
  15. data/sorbet/rbi/gems/erb@5.0.2.rbi +878 -0
  16. data/sorbet/rbi/gems/erubi@1.13.1.rbi +155 -0
  17. data/sorbet/rbi/gems/io-console@0.8.1.rbi +9 -0
  18. data/sorbet/rbi/gems/json@2.14.1.rbi +2101 -0
  19. data/sorbet/rbi/gems/language_server-protocol@3.17.0.5.rbi +9 -0
  20. data/sorbet/rbi/gems/lint_roller@1.1.0.rbi +86 -0
  21. data/sorbet/rbi/gems/logger@1.7.0.rbi +963 -0
  22. data/sorbet/rbi/gems/netrc@0.11.0.rbi +159 -0
  23. data/sorbet/rbi/gems/parallel@1.27.0.rbi +291 -0
  24. data/sorbet/rbi/gems/parser@3.3.9.0.rbi +5535 -0
  25. data/sorbet/rbi/gems/pp@0.6.2.rbi +368 -0
  26. data/sorbet/rbi/gems/prettyprint@0.2.0.rbi +477 -0
  27. data/sorbet/rbi/gems/prism@1.5.1.rbi +42049 -0
  28. data/sorbet/rbi/gems/psych@5.2.6.rbi +2469 -0
  29. data/sorbet/rbi/gems/racc@1.8.1.rbi +160 -0
  30. data/sorbet/rbi/gems/rainbow@3.1.1.rbi +403 -0
  31. data/sorbet/rbi/gems/rake@13.3.0.rbi +3036 -0
  32. data/sorbet/rbi/gems/rbi@0.3.6.rbi +6893 -0
  33. data/sorbet/rbi/gems/rbs@3.9.5.rbi +6978 -0
  34. data/sorbet/rbi/gems/rdoc@6.14.2.rbi +12688 -0
  35. data/sorbet/rbi/gems/regexp_parser@2.11.3.rbi +3845 -0
  36. data/sorbet/rbi/gems/reline@0.6.2.rbi +2441 -0
  37. data/sorbet/rbi/gems/rexml@3.4.4.rbi +5285 -0
  38. data/sorbet/rbi/gems/rspec-core@3.13.5.rbi +11103 -0
  39. data/sorbet/rbi/gems/rspec-expectations@3.13.5.rbi +8189 -0
  40. data/sorbet/rbi/gems/rspec-mocks@3.13.5.rbi +5350 -0
  41. data/sorbet/rbi/gems/rspec-support@3.13.6.rbi +1627 -0
  42. data/sorbet/rbi/gems/rspec@3.13.1.rbi +83 -0
  43. data/sorbet/rbi/gems/rubocop-ast@1.46.0.rbi +7734 -0
  44. data/sorbet/rbi/gems/rubocop@1.80.2.rbi +63356 -0
  45. data/sorbet/rbi/gems/ruby-progressbar@1.13.0.rbi +1318 -0
  46. data/sorbet/rbi/gems/spoom@1.6.3.rbi +6985 -0
  47. data/sorbet/rbi/gems/stringio@3.1.7.rbi +9 -0
  48. data/sorbet/rbi/gems/tapioca@0.16.11.rbi +3628 -0
  49. data/sorbet/rbi/gems/thor@1.4.0.rbi +4399 -0
  50. data/sorbet/rbi/gems/unicode-display_width@3.2.0.rbi +132 -0
  51. data/sorbet/rbi/gems/unicode-emoji@4.1.0.rbi +251 -0
  52. data/sorbet/rbi/gems/yard-sorbet@0.9.0.rbi +435 -0
  53. data/sorbet/rbi/gems/yard@0.9.37.rbi +18379 -0
  54. data/sorbet/tapioca/config.yml +13 -0
  55. data/sorbet/tapioca/require.rb +4 -0
  56. metadata +51 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f0b14b2788360074d5bfbeda204336c00985fd5c02e208f278583da7451ad1da
4
- data.tar.gz: 406925f3cb0152ab40b0e3661d778429fc499cfb45e0cc960f17454e5e8c3f69
3
+ metadata.gz: a36996117e89c98c36fa3479f6789dbc9a1d160c729bcb85660e2dff55064eb0
4
+ data.tar.gz: b4a2ab4d363581f6235c7ac055db053ef474be9640dc5022904eefb5d160efd6
5
5
  SHA512:
6
- metadata.gz: 412636f7247d509bf44532b557de671657702c9fc955013d89be1ba7f65c9823f8b0a87ed51cc946d4b83cbe442aafc89f2b1f2744e904eab3c53e403f95cd3a
7
- data.tar.gz: e134bcf385bbc4fe5a737c3043409730522011cc9e5f31f0718bb9b15f671f8fff25131a675d973c6d33dd004a78b1ffcd1aa69b9b5553ea2f59945c349817c9
6
+ metadata.gz: 663cdbfc6dbf27f92630b907e0920dcd934caee502e67d796daf713cb3156f65c6359aa024a2a42be4f0d1b05de8f76dc99206e477d0aa9895d9302963cbfddd
7
+ data.tar.gz: d55471bfac793667c767f74afa02fcd12bb18fcaf51b00172fbbc1b5546732106763ed2fb15d4252f52bbe87fa2f21ec44ecbbd474fa618c6116718f449cf01d
data/.rubocop.yml CHANGED
@@ -7,6 +7,9 @@ Metrics/AbcSize:
7
7
  Metrics/BlockLength:
8
8
  Enabled: false
9
9
 
10
+ Metrics/ClassLength:
11
+ Enabled: false
12
+
10
13
  Metrics/CyclomaticComplexity:
11
14
  Enabled: false
12
15
 
data/CHANGELOG.md ADDED
@@ -0,0 +1,34 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
+
7
+ ## [Unreleased]
8
+
9
+ ### Added
10
+
11
+ ### Changed
12
+
13
+ ### Deprecated
14
+
15
+ ### Removed
16
+
17
+ ### Fixed
18
+
19
+ ### Security
20
+
21
+ ## 0.2.0 2025-09-28
22
+
23
+ ### Added
24
+
25
+ - [Sorbet](https://sorbet.org/) type assertions.
26
+ - Support for platforms `x86_64-darwin-23` and `x86_64-linux`
27
+
28
+ ### Changed
29
+
30
+ - Improve documentation comments.
31
+
32
+ ## 0.1.0 - 2025-09-21
33
+
34
+ This is the first release of *piston_sdk*! :tada:
data/README.md CHANGED
@@ -12,7 +12,7 @@
12
12
 
13
13
  <div align="center">
14
14
 
15
- [![GitHub Actions](https://img.shields.io/github/actions/workflow/status/alvii147/piston-ruby-sdk/main.yml?branch=main&label=GitHub%20Actions&logo=github)](https://github.com/alvii147/piston-ruby-sdk/actions) [![License](https://img.shields.io/github/license/alvii147/piston-ruby-sdk)](https://github.com/alvii147/piston-ruby-sdk/blob/main/LICENSE)
15
+ [![Gem Version](https://badge.fury.io/rb/piston_sdk.svg)](https://badge.fury.io/rb/piston_sdk) [![GitHub Actions](https://img.shields.io/github/actions/workflow/status/alvii147/piston-ruby-sdk/main.yml?branch=main&label=GitHub%20Actions&logo=github)](https://github.com/alvii147/piston-ruby-sdk/actions) [![License](https://img.shields.io/github/license/alvii147/piston-ruby-sdk)](https://github.com/alvii147/piston-ruby-sdk/blob/main/LICENSE)
16
16
 
17
17
  </div>
18
18
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PistonSDK
4
- VERSION = "0.1.0"
4
+ VERSION = "0.2.0"
5
5
  end
data/lib/piston_sdk.rb CHANGED
@@ -1,78 +1,155 @@
1
+ # typed: true
1
2
  # frozen_string_literal: true
2
3
 
3
4
  require "net/http"
4
5
  require "json"
6
+ require "sorbet-runtime"
5
7
  require_relative "piston_sdk/version"
6
8
 
7
9
  # A minimal Ruby gem for using the [Piston API](https://github.com/engineer-man/piston).
8
10
  module PistonSDK
9
11
  # Data representation of a Piston runtime.
10
12
  class Runtime
11
- attr_reader :language, :version, :aliases, :runtime
13
+ extend T::Sig
14
+
15
+ sig { returns(String) }
16
+ attr_reader :language
17
+
18
+ sig { returns(String) }
19
+ attr_reader :version
20
+
21
+ sig { returns(T::Array[String]) }
22
+ attr_reader :aliases
23
+
24
+ sig { returns(T.nilable(String)) }
25
+ attr_reader :runtime
12
26
 
13
27
  # Create a new Piston runtime.
14
28
  #
15
- # @param data [Hash] JSON data.
29
+ # @param data [Hash] JSON data
30
+ sig { params(data: T::Hash[String, T.untyped]).void }
16
31
  def initialize(data)
17
- @language = data["language"]
18
- @version = data["version"]
19
- @aliases = data["aliases"]
20
- @runtime = data["runtime"]
32
+ @language = T.let(data["language"], String)
33
+ @version = T.let(data["version"], String)
34
+ @aliases = T.let(data["aliases"], T::Array[String])
35
+ @runtime = T.let(data["runtime"], T.nilable(String))
21
36
  end
22
37
  end
23
38
 
24
39
  # Data representation of Piston execution step details.
25
40
  class ExecutionStepDetails
26
- attr_reader :stdout, :stderr, :output, :code, :signal, :message, :status, :cpu_time, :wall_time, :memory
41
+ extend T::Sig
42
+
43
+ sig { returns(String) }
44
+ attr_reader :stdout
45
+
46
+ sig { returns(String) }
47
+ attr_reader :stderr
48
+
49
+ sig { returns(String) }
50
+ attr_reader :output
51
+
52
+ sig { returns(T.nilable(Integer)) }
53
+ attr_reader :code
54
+
55
+ sig { returns(T.nilable(String)) }
56
+ attr_reader :signal
57
+
58
+ sig { returns(T.nilable(String)) }
59
+ attr_reader :message
60
+
61
+ sig { returns(T.nilable(String)) }
62
+ attr_reader :status
63
+
64
+ sig { returns(T.nilable(Integer)) }
65
+ attr_reader :cpu_time
66
+
67
+ sig { returns(T.nilable(Integer)) }
68
+ attr_reader :wall_time
69
+
70
+ sig { returns(T.nilable(Integer)) }
71
+ attr_reader :memory
27
72
 
28
73
  # Create new Piston execution step details.
29
74
  #
30
- # @param data [Hash] JSON data.
75
+ # @param data [Hash] JSON data
76
+ sig { params(data: T::Hash[String, T.untyped]).void }
31
77
  def initialize(data)
32
- @stdout = data["stdout"] unless data["stdout"].nil?
33
- @stderr = data["stderr"] unless data["stderr"].nil?
34
- @output = data["output"] unless data["output"].nil?
35
- @code = data["code"] unless data["code"].nil?
36
- @signal = data["signal"] unless data["signal"].nil?
37
- @message = data["message"] unless data["message"].nil?
38
- @status = data["status"] unless data["status"].nil?
39
- @cpu_time = data["cpu_time"] unless data["cpu_time"].nil?
40
- @wall_time = data["wall_time"] unless data["wall_time"].nil?
41
- @memory = data["memory"] unless data["memory"].nil?
78
+ @stdout = T.let(data["stdout"], String)
79
+ @stderr = T.let(data["stderr"], String)
80
+ @output = T.let(data["output"], String)
81
+ @code = T.let(data["code"], T.nilable(Integer))
82
+ @signal = T.let(data["signal"], T.nilable(String))
83
+ @message = T.let(data["message"], T.nilable(String))
84
+ @status = T.let(data["status"], T.nilable(String))
85
+ @cpu_time = T.let(data["cpu_time"], T.nilable(Integer))
86
+ @wall_time = T.let(data["wall_time"], T.nilable(Integer))
87
+ @memory = T.let(data["memory"], T.nilable(Integer))
42
88
  end
43
89
  end
44
90
 
45
91
  # Data representation of Piston execution results.
46
92
  class ExecutionResults
47
- attr_reader :language, :version, :run, :compile
93
+ extend T::Sig
94
+
95
+ sig { returns(String) }
96
+ attr_reader :language
97
+
98
+ sig { returns(String) }
99
+ attr_reader :version
100
+
101
+ sig { returns(ExecutionStepDetails) }
102
+ attr_reader :run
103
+
104
+ sig { returns(T.nilable(ExecutionStepDetails)) }
105
+ attr_reader :compile
48
106
 
49
107
  # Create new Piston execution results.
50
108
  #
51
- # @param data [Hash] JSON data.
109
+ # @param data [Hash] JSON data
110
+ sig { params(data: T::Hash[String, T.untyped]).void }
52
111
  def initialize(data)
53
- @language = data["language"]
54
- @version = data["version"]
55
- @run = ExecutionStepDetails.new(data["run"]) unless data["run"].nil?
56
- @compile = ExecutionStepDetails.new(data["compile"]) unless data["compile"].nil?
112
+ @language = T.let(data["language"], String)
113
+ @version = T.let(data["version"], String)
114
+ @run = T.let(ExecutionStepDetails.new(data["run"]), ExecutionStepDetails)
115
+ @compile = T.let(
116
+ data["compile"] ? ExecutionStepDetails.new(data["compile"]) : nil,
117
+ T.nilable(ExecutionStepDetails)
118
+ )
57
119
  end
58
120
  end
59
121
 
60
122
  # HTTP client for the Piston API.
61
123
  class Client
124
+ extend T::Sig
125
+
62
126
  # Create a new client.
63
127
  #
64
- # @param base_url [String] Base URL for API.
128
+ # @param base_url [String] Base URL for API
129
+ # @param retries [Integer] Number of automatic retries to perform when rate limit is reached
65
130
  # @param compile_timeout [Integer, nil] The maximum wall-time allowed for the compile stage to finish before bailing
66
- # out in milliseconds.
131
+ # out in milliseconds
67
132
  # @param run_timeout [Integer, nil] The maximum wall-time allowed for the run stage to finish before bailing out in
68
- # milliseconds.
133
+ # milliseconds
69
134
  # @param compile_cpu_time [Integer, nil] The maximum CPU-time allowed for the compile stage to finish before bailing
70
- # out in milliseconds.
135
+ # out in milliseconds
71
136
  # @param run_cpu_time [Integer, nil] The maximum CPU-time allowed for the run stage to finish before bailing out in
72
- # milliseconds.
137
+ # milliseconds
73
138
  # @param compile_memory_limit [Integer, nil] The maximum amount of memory the compile stage is allowed to use in
74
- # bytes.
75
- # @param run_memory_limit [Integer, nil] The maximum amount of memory the run stage is allowed to use in bytes.
139
+ # bytes
140
+ # @param run_memory_limit [Integer, nil] The maximum amount of memory the run stage is allowed to use in bytes
141
+ sig do
142
+ params(
143
+ base_url: String,
144
+ retries: Integer,
145
+ compile_timeout: T.nilable(Integer),
146
+ run_timeout: T.nilable(Integer),
147
+ compile_cpu_time: T.nilable(Integer),
148
+ run_cpu_time: T.nilable(Integer),
149
+ compile_memory_limit: T.nilable(Integer),
150
+ run_memory_limit: T.nilable(Integer)
151
+ ).void
152
+ end
76
153
  def initialize(
77
154
  base_url: "https://emkc.org/api/v2/piston",
78
155
  retries: 3,
@@ -83,32 +160,48 @@ module PistonSDK
83
160
  compile_memory_limit: nil,
84
161
  run_memory_limit: nil
85
162
  )
86
- @uri = URI(base_url)
87
- @retries = retries
88
- @compile_timeout = compile_timeout
89
- @run_timeout = run_timeout
90
- @compile_cpu_time = compile_cpu_time
91
- @run_cpu_time = run_cpu_time
92
- @compile_memory_limit = compile_memory_limit
93
- @run_memory_limit = run_memory_limit
94
- @files = []
95
-
96
- @http = Net::HTTP.new(@uri.host, @uri.port)
163
+ @uri = T.let(URI(base_url), URI::Generic)
164
+ @retries = T.let(retries, Integer)
165
+ @compile_timeout = T.let(compile_timeout, T.nilable(Integer))
166
+ @run_timeout = T.let(run_timeout, T.nilable(Integer))
167
+ @compile_cpu_time = T.let(compile_cpu_time, T.nilable(Integer))
168
+ @run_cpu_time = T.let(run_cpu_time, T.nilable(Integer))
169
+ @compile_memory_limit = T.let(compile_memory_limit, T.nilable(Integer))
170
+ @run_memory_limit = T.let(run_memory_limit, T.nilable(Integer))
171
+ @files = T.let([], T::Array[T::Hash[Symbol, String]])
172
+
173
+ @http = T.let(Net::HTTP.new(@uri.host, @uri.port), Net::HTTP)
97
174
  @http.use_ssl = true
98
175
 
99
- @method_classes = Hash.new(Net::HTTP::Get)
100
- @method_classes[:get] = Net::HTTP::Get
101
- @method_classes[:post] = Net::HTTP::Post
176
+ @method_classes = T.let(
177
+ {
178
+ get: Net::HTTP::Get,
179
+ post: Net::HTTP::Post
180
+ },
181
+ T::Hash[Symbol, T.class_of(Net::HTTPRequest)]
182
+ )
102
183
  end
103
184
 
104
185
  # Perform raw HTTP request using exponential backoff on retries.
105
186
  #
106
- # @param method [Symbol] HTTP method.
107
- # @param path [String] URL Path.
187
+ # @param method [Symbol] HTTP method
188
+ # @param path [String] URL Path
108
189
  # @param body [Hash, nil] Optional request body
109
- # @return [Hash, Array] JSON response.
190
+ # @return [Hash, Array] JSON response
191
+ sig do
192
+ params(
193
+ method: Symbol,
194
+ path: String,
195
+ body: T.nilable(T::Hash[Symbol, T.untyped])
196
+ ).returns(
197
+ T.any(
198
+ T::Hash[T.untyped, T.untyped],
199
+ T::Array[T.untyped]
200
+ )
201
+ )
202
+ end
110
203
  def request(method: :get, path: "", body: nil)
111
- req = @method_classes[method].new("#{@uri}#{path}")
204
+ req = T.must(@method_classes[method]).new("#{@uri}#{path}")
112
205
  req["Content-Type"] = "application/json"
113
206
  req.body = body.to_json unless body.nil?
114
207
  res = @http.request(req)
@@ -118,20 +211,29 @@ module PistonSDK
118
211
 
119
212
  case res
120
213
  when Net::HTTPOK
121
- return JSON.parse(res.body)
214
+ return JSON.parse(res.body || "{}")
122
215
  when Net::HTTPTooManyRequests
123
216
  sleep 2**attempt
124
217
  else
125
218
  raise "Request failed with status code #{res.code}, #{res.body}"
126
219
  end
127
220
  end
221
+
222
+ raise "Request failed due to rate limits after too many attempts"
128
223
  end
129
224
 
130
225
  # Add file to be sent to Piston for execution.
131
226
  #
132
- # @param content [String] Content of the files to upload.
133
- # @param name [String, nil] Name of the file to upload.
134
- # @param encoding [String, nil] Encoding scheme used for the file content.
227
+ # @param content [String] Content of the files to upload
228
+ # @param name [String, nil] Name of the file to upload
229
+ # @param encoding [String, nil] Encoding scheme used for the file content
230
+ sig do
231
+ params(
232
+ content: String,
233
+ name: T.nilable(String),
234
+ encoding: T.nilable(String)
235
+ ).void
236
+ end
135
237
  def add_file(content:, name: nil, encoding: nil)
136
238
  file = {
137
239
  name: name,
@@ -142,25 +244,37 @@ module PistonSDK
142
244
  @files << file
143
245
  end
144
246
 
145
- # Clear all files.
247
+ # Clear all files
248
+ sig { void }
146
249
  def clear_files
147
250
  @files.clear
148
251
  end
149
252
 
150
253
  # Get supported languages along with the current version and aliases.
151
254
  #
152
- # @return [Array<Runtime>] Array of runtimes.
255
+ # @return [Array<Runtime>] List of supported runtimes
256
+ sig { returns(T::Array[Runtime]) }
153
257
  def runtimes
154
- request(method: :get, path: "/runtimes").map { |data| Runtime.new(data) }
258
+ request(method: :get, path: "/runtimes").map do |data|
259
+ Runtime.new(T.cast(data, T::Hash[String, T.untyped]))
260
+ end
155
261
  end
156
262
 
157
263
  # Execute code for a given language and version using the added files.
158
264
  #
159
- # @param language [String] Language to use for execution.
160
- # @param version [String] Version of the language to use for execution.
161
- # @param stdin [String, nil] Text to pass as stdin to the program.
162
- # @param args [Array<String>] Arguments to pass to the program.
163
- # @return [ExecutionResults] Execution results.
265
+ # @param language [String] Language to use for execution
266
+ # @param version [String] Version of the language to use for execution
267
+ # @param stdin [String, nil] Text to pass as stdin to the program
268
+ # @param args [Array<String>] Arguments to pass to the program
269
+ # @return [ExecutionResults] Execution results
270
+ sig do
271
+ params(
272
+ language: String,
273
+ version: String,
274
+ stdin: T.nilable(String),
275
+ args: T.nilable(T::Array[String])
276
+ ).returns(ExecutionResults)
277
+ end
164
278
  def execute(language:, version:, stdin: nil, args: nil)
165
279
  body = {
166
280
  language: language,
@@ -176,7 +290,9 @@ module PistonSDK
176
290
  run_memory_limit: @run_memory_limit
177
291
  }.compact
178
292
 
179
- ExecutionResults.new(request(method: :post, path: "/execute", body: body))
293
+ ExecutionResults.new(
294
+ T.cast(request(method: :post, path: "/execute", body: body), T::Hash[String, T.untyped])
295
+ )
180
296
  end
181
297
 
182
298
  private :request
data/sorbet/config ADDED
@@ -0,0 +1,4 @@
1
+ --dir
2
+ .
3
+ --ignore=tmp/
4
+ --ignore=vendor/
@@ -0,0 +1 @@
1
+ **/*.rbi linguist-vendored=true