onebusaway-sdk 0.1.0.pre.alpha.205 → 0.1.0.pre.alpha.207

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 (150) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +32 -20
  3. data/lib/onebusaway-sdk/base_client.rb +63 -91
  4. data/lib/onebusaway-sdk/base_model.rb +489 -514
  5. data/lib/onebusaway-sdk/base_page.rb +35 -15
  6. data/lib/onebusaway-sdk/client.rb +1 -3
  7. data/lib/onebusaway-sdk/errors.rb +15 -19
  8. data/lib/onebusaway-sdk/extern.rb +1 -4
  9. data/lib/onebusaway-sdk/models/references.rb +0 -21
  10. data/lib/onebusaway-sdk/models/report_problem_with_stop_retrieve_params.rb +0 -21
  11. data/lib/onebusaway-sdk/models/report_problem_with_trip_retrieve_params.rb +0 -23
  12. data/lib/onebusaway-sdk/pooled_net_requester.rb +53 -54
  13. data/lib/onebusaway-sdk/request_options.rb +4 -11
  14. data/lib/onebusaway-sdk/resources/agencies_with_coverage.rb +0 -2
  15. data/lib/onebusaway-sdk/resources/agency.rb +0 -2
  16. data/lib/onebusaway-sdk/resources/arrival_and_departure.rb +0 -3
  17. data/lib/onebusaway-sdk/resources/block.rb +0 -2
  18. data/lib/onebusaway-sdk/resources/config.rb +0 -2
  19. data/lib/onebusaway-sdk/resources/current_time.rb +0 -2
  20. data/lib/onebusaway-sdk/resources/report_problem_with_stop.rb +0 -2
  21. data/lib/onebusaway-sdk/resources/report_problem_with_trip.rb +0 -2
  22. data/lib/onebusaway-sdk/resources/route.rb +0 -2
  23. data/lib/onebusaway-sdk/resources/route_ids_for_agency.rb +0 -2
  24. data/lib/onebusaway-sdk/resources/routes_for_agency.rb +0 -2
  25. data/lib/onebusaway-sdk/resources/routes_for_location.rb +0 -2
  26. data/lib/onebusaway-sdk/resources/schedule_for_route.rb +0 -2
  27. data/lib/onebusaway-sdk/resources/schedule_for_stop.rb +0 -2
  28. data/lib/onebusaway-sdk/resources/search_for_route.rb +0 -2
  29. data/lib/onebusaway-sdk/resources/search_for_stop.rb +0 -2
  30. data/lib/onebusaway-sdk/resources/shape.rb +0 -2
  31. data/lib/onebusaway-sdk/resources/stop.rb +0 -2
  32. data/lib/onebusaway-sdk/resources/stop_ids_for_agency.rb +0 -2
  33. data/lib/onebusaway-sdk/resources/stops_for_agency.rb +0 -2
  34. data/lib/onebusaway-sdk/resources/stops_for_location.rb +0 -2
  35. data/lib/onebusaway-sdk/resources/stops_for_route.rb +0 -2
  36. data/lib/onebusaway-sdk/resources/trip.rb +0 -2
  37. data/lib/onebusaway-sdk/resources/trip_details.rb +0 -2
  38. data/lib/onebusaway-sdk/resources/trip_for_vehicle.rb +0 -2
  39. data/lib/onebusaway-sdk/resources/trips_for_location.rb +0 -2
  40. data/lib/onebusaway-sdk/resources/trips_for_route.rb +0 -2
  41. data/lib/onebusaway-sdk/resources/vehicles_for_agency.rb +0 -2
  42. data/lib/onebusaway-sdk/util.rb +297 -96
  43. data/lib/onebusaway-sdk/version.rb +1 -1
  44. data/lib/onebusaway-sdk.rb +1 -0
  45. data/manifest.yaml +1 -0
  46. data/rbi/lib/onebusaway-sdk/base_client.rbi +52 -35
  47. data/rbi/lib/onebusaway-sdk/base_model.rbi +400 -256
  48. data/rbi/lib/onebusaway-sdk/base_page.rbi +3 -4
  49. data/rbi/lib/onebusaway-sdk/client.rbi +7 -2
  50. data/rbi/lib/onebusaway-sdk/errors.rbi +44 -10
  51. data/rbi/lib/onebusaway-sdk/extern.rbi +1 -1
  52. data/rbi/lib/onebusaway-sdk/models/agencies_with_coverage_list_params.rbi +5 -2
  53. data/rbi/lib/onebusaway-sdk/models/agencies_with_coverage_list_response.rbi +9 -6
  54. data/rbi/lib/onebusaway-sdk/models/agency_retrieve_params.rbi +5 -2
  55. data/rbi/lib/onebusaway-sdk/models/agency_retrieve_response.rbi +6 -6
  56. data/rbi/lib/onebusaway-sdk/models/arrival_and_departure_list_params.rbi +5 -2
  57. data/rbi/lib/onebusaway-sdk/models/arrival_and_departure_list_response.rbi +95 -14
  58. data/rbi/lib/onebusaway-sdk/models/arrival_and_departure_retrieve_params.rbi +2 -9
  59. data/rbi/lib/onebusaway-sdk/models/arrival_and_departure_retrieve_response.rbi +93 -12
  60. data/rbi/lib/onebusaway-sdk/models/block_retrieve_params.rbi +5 -2
  61. data/rbi/lib/onebusaway-sdk/models/block_retrieve_response.rbi +14 -20
  62. data/rbi/lib/onebusaway-sdk/models/config_retrieve_params.rbi +5 -2
  63. data/rbi/lib/onebusaway-sdk/models/config_retrieve_response.rbi +8 -14
  64. data/rbi/lib/onebusaway-sdk/models/current_time_retrieve_params.rbi +5 -2
  65. data/rbi/lib/onebusaway-sdk/models/current_time_retrieve_response.rbi +6 -6
  66. data/rbi/lib/onebusaway-sdk/models/references.rbi +60 -43
  67. data/rbi/lib/onebusaway-sdk/models/report_problem_with_stop_retrieve_params.rbi +10 -6
  68. data/rbi/lib/onebusaway-sdk/models/report_problem_with_trip_retrieve_params.rbi +15 -6
  69. data/rbi/lib/onebusaway-sdk/models/response_wrapper.rbi +4 -2
  70. data/rbi/lib/onebusaway-sdk/models/route_ids_for_agency_list_params.rbi +5 -2
  71. data/rbi/lib/onebusaway-sdk/models/route_ids_for_agency_list_response.rbi +4 -4
  72. data/rbi/lib/onebusaway-sdk/models/route_retrieve_params.rbi +5 -2
  73. data/rbi/lib/onebusaway-sdk/models/route_retrieve_response.rbi +6 -6
  74. data/rbi/lib/onebusaway-sdk/models/routes_for_agency_list_params.rbi +5 -2
  75. data/rbi/lib/onebusaway-sdk/models/routes_for_agency_list_response.rbi +6 -6
  76. data/rbi/lib/onebusaway-sdk/models/routes_for_location_list_params.rbi +2 -2
  77. data/rbi/lib/onebusaway-sdk/models/routes_for_location_list_response.rbi +6 -6
  78. data/rbi/lib/onebusaway-sdk/models/schedule_for_route_retrieve_params.rbi +5 -8
  79. data/rbi/lib/onebusaway-sdk/models/schedule_for_route_retrieve_response.rbi +19 -16
  80. data/rbi/lib/onebusaway-sdk/models/schedule_for_stop_retrieve_params.rbi +5 -8
  81. data/rbi/lib/onebusaway-sdk/models/schedule_for_stop_retrieve_response.rbi +14 -14
  82. data/rbi/lib/onebusaway-sdk/models/search_for_route_list_params.rbi +4 -2
  83. data/rbi/lib/onebusaway-sdk/models/search_for_route_list_response.rbi +6 -6
  84. data/rbi/lib/onebusaway-sdk/models/search_for_stop_list_params.rbi +4 -2
  85. data/rbi/lib/onebusaway-sdk/models/search_for_stop_list_response.rbi +6 -6
  86. data/rbi/lib/onebusaway-sdk/models/shape_retrieve_params.rbi +5 -2
  87. data/rbi/lib/onebusaway-sdk/models/shape_retrieve_response.rbi +7 -6
  88. data/rbi/lib/onebusaway-sdk/models/stop_ids_for_agency_list_params.rbi +5 -2
  89. data/rbi/lib/onebusaway-sdk/models/stop_ids_for_agency_list_response.rbi +4 -4
  90. data/rbi/lib/onebusaway-sdk/models/stop_retrieve_params.rbi +5 -2
  91. data/rbi/lib/onebusaway-sdk/models/stop_retrieve_response.rbi +6 -6
  92. data/rbi/lib/onebusaway-sdk/models/stops_for_agency_list_params.rbi +5 -2
  93. data/rbi/lib/onebusaway-sdk/models/stops_for_agency_list_response.rbi +4 -4
  94. data/rbi/lib/onebusaway-sdk/models/stops_for_location_list_params.rbi +6 -2
  95. data/rbi/lib/onebusaway-sdk/models/stops_for_location_list_response.rbi +6 -6
  96. data/rbi/lib/onebusaway-sdk/models/stops_for_route_list_params.rbi +4 -2
  97. data/rbi/lib/onebusaway-sdk/models/stops_for_route_list_response.rbi +14 -14
  98. data/rbi/lib/onebusaway-sdk/models/trip_detail_retrieve_params.rbi +10 -2
  99. data/rbi/lib/onebusaway-sdk/models/trip_detail_retrieve_response.rbi +54 -23
  100. data/rbi/lib/onebusaway-sdk/models/trip_for_vehicle_retrieve_params.rbi +9 -8
  101. data/rbi/lib/onebusaway-sdk/models/trip_for_vehicle_retrieve_response.rbi +54 -23
  102. data/rbi/lib/onebusaway-sdk/models/trip_retrieve_params.rbi +5 -2
  103. data/rbi/lib/onebusaway-sdk/models/trip_retrieve_response.rbi +6 -6
  104. data/rbi/lib/onebusaway-sdk/models/trips_for_location_list_params.rbi +12 -12
  105. data/rbi/lib/onebusaway-sdk/models/trips_for_location_list_response.rbi +56 -16
  106. data/rbi/lib/onebusaway-sdk/models/trips_for_route_list_params.rbi +6 -2
  107. data/rbi/lib/onebusaway-sdk/models/trips_for_route_list_response.rbi +54 -16
  108. data/rbi/lib/onebusaway-sdk/models/vehicles_for_agency_list_params.rbi +3 -2
  109. data/rbi/lib/onebusaway-sdk/models/vehicles_for_agency_list_response.rbi +52 -14
  110. data/rbi/lib/onebusaway-sdk/pooled_net_requester.rbi +28 -13
  111. data/rbi/lib/onebusaway-sdk/request_options.rbi +25 -2
  112. data/rbi/lib/onebusaway-sdk/resources/agencies_with_coverage.rbi +4 -2
  113. data/rbi/lib/onebusaway-sdk/resources/agency.rbi +8 -3
  114. data/rbi/lib/onebusaway-sdk/resources/arrival_and_departure.rbi +14 -3
  115. data/rbi/lib/onebusaway-sdk/resources/block.rbi +8 -3
  116. data/rbi/lib/onebusaway-sdk/resources/config.rbi +3 -2
  117. data/rbi/lib/onebusaway-sdk/resources/current_time.rbi +3 -2
  118. data/rbi/lib/onebusaway-sdk/resources/report_problem_with_stop.rbi +9 -2
  119. data/rbi/lib/onebusaway-sdk/resources/report_problem_with_trip.rbi +14 -2
  120. data/rbi/lib/onebusaway-sdk/resources/route.rbi +8 -3
  121. data/rbi/lib/onebusaway-sdk/resources/route_ids_for_agency.rbi +8 -3
  122. data/rbi/lib/onebusaway-sdk/resources/routes_for_agency.rbi +8 -3
  123. data/rbi/lib/onebusaway-sdk/resources/routes_for_location.rbi +3 -2
  124. data/rbi/lib/onebusaway-sdk/resources/schedule_for_route.rbi +11 -3
  125. data/rbi/lib/onebusaway-sdk/resources/schedule_for_stop.rbi +11 -3
  126. data/rbi/lib/onebusaway-sdk/resources/search_for_route.rbi +10 -3
  127. data/rbi/lib/onebusaway-sdk/resources/search_for_stop.rbi +10 -3
  128. data/rbi/lib/onebusaway-sdk/resources/shape.rbi +8 -3
  129. data/rbi/lib/onebusaway-sdk/resources/stop.rbi +8 -3
  130. data/rbi/lib/onebusaway-sdk/resources/stop_ids_for_agency.rbi +8 -3
  131. data/rbi/lib/onebusaway-sdk/resources/stops_for_agency.rbi +8 -3
  132. data/rbi/lib/onebusaway-sdk/resources/stops_for_location.rbi +16 -3
  133. data/rbi/lib/onebusaway-sdk/resources/stops_for_route.rbi +12 -3
  134. data/rbi/lib/onebusaway-sdk/resources/trip.rbi +8 -3
  135. data/rbi/lib/onebusaway-sdk/resources/trip_details.rbi +12 -2
  136. data/rbi/lib/onebusaway-sdk/resources/trip_for_vehicle.rbi +11 -2
  137. data/rbi/lib/onebusaway-sdk/resources/trips_for_location.rbi +12 -2
  138. data/rbi/lib/onebusaway-sdk/resources/trips_for_route.rbi +15 -3
  139. data/rbi/lib/onebusaway-sdk/resources/vehicles_for_agency.rbi +10 -3
  140. data/rbi/lib/onebusaway-sdk/util.rbi +214 -83
  141. data/rbi/lib/onebusaway-sdk/version.rbi +1 -1
  142. data/sig/onebusaway-sdk/base_client.rbs +9 -8
  143. data/sig/onebusaway-sdk/base_model.rbs +8 -6
  144. data/sig/onebusaway-sdk/base_page.rbs +1 -1
  145. data/sig/onebusaway-sdk/errors.rbs +6 -5
  146. data/sig/onebusaway-sdk/pooled_net_requester.rbs +11 -4
  147. data/sig/onebusaway-sdk/request_options.rbs +4 -0
  148. data/sig/onebusaway-sdk/util.rbs +46 -2
  149. data/sig/onebusaway-sdk/version.rbs +1 -1
  150. metadata +4 -4
@@ -3,20 +3,17 @@
3
3
  module OnebusawaySDK
4
4
  # rubocop:disable Metrics/ModuleLength
5
5
 
6
- # @private
7
- #
6
+ # @api private
8
7
  module Util
9
- # @private
8
+ # @api private
10
9
  #
11
10
  # @return [Float]
12
- #
13
11
  def self.monotonic_secs = Process.clock_gettime(Process::CLOCK_MONOTONIC)
14
12
 
15
13
  class << self
16
- # @private
14
+ # @api private
17
15
  #
18
16
  # @return [String]
19
- #
20
17
  def arch
21
18
  case (arch = RbConfig::CONFIG["arch"])&.downcase
22
19
  in nil
@@ -32,10 +29,9 @@ module OnebusawaySDK
32
29
  end
33
30
  end
34
31
 
35
- # @private
32
+ # @api private
36
33
  #
37
34
  # @return [String]
38
- #
39
35
  def os
40
36
  case (host = RbConfig::CONFIG["host_os"])&.downcase
41
37
  in nil
@@ -57,12 +53,11 @@ module OnebusawaySDK
57
53
  end
58
54
 
59
55
  class << self
60
- # @private
56
+ # @api private
61
57
  #
62
58
  # @param input [Object]
63
59
  #
64
- # @return [Boolean, Object]
65
- #
60
+ # @return [Boolean]
66
61
  def primitive?(input)
67
62
  case input
68
63
  in true | false | Integer | Float | Symbol | String
@@ -72,12 +67,11 @@ module OnebusawaySDK
72
67
  end
73
68
  end
74
69
 
75
- # @private
70
+ # @api private
76
71
  #
77
72
  # @param input [Object]
78
73
  #
79
74
  # @return [Boolean, Object]
80
- #
81
75
  def coerce_boolean(input)
82
76
  case input.is_a?(String) ? input.downcase : input
83
77
  in Numeric
@@ -91,13 +85,12 @@ module OnebusawaySDK
91
85
  end
92
86
  end
93
87
 
94
- # @private
88
+ # @api private
95
89
  #
96
90
  # @param input [Object]
97
91
  #
98
92
  # @raise [ArgumentError]
99
93
  # @return [Boolean, nil]
100
- #
101
94
  def coerce_boolean!(input)
102
95
  case coerce_boolean(input)
103
96
  in true | false | nil => coerced
@@ -107,12 +100,11 @@ module OnebusawaySDK
107
100
  end
108
101
  end
109
102
 
110
- # @private
103
+ # @api private
111
104
  #
112
105
  # @param input [Object]
113
106
  #
114
107
  # @return [Integer, Object]
115
- #
116
108
  def coerce_integer(input)
117
109
  case input
118
110
  in true
@@ -124,12 +116,11 @@ module OnebusawaySDK
124
116
  end
125
117
  end
126
118
 
127
- # @private
119
+ # @api private
128
120
  #
129
121
  # @param input [Object]
130
122
  #
131
123
  # @return [Float, Object]
132
- #
133
124
  def coerce_float(input)
134
125
  case input
135
126
  in true
@@ -141,12 +132,11 @@ module OnebusawaySDK
141
132
  end
142
133
  end
143
134
 
144
- # @private
135
+ # @api private
145
136
  #
146
137
  # @param input [Object]
147
138
  #
148
139
  # @return [Hash{Object=>Object}, Object]
149
- #
150
140
  def coerce_hash(input)
151
141
  case input
152
142
  in NilClass | Array | Set | Enumerator
@@ -165,14 +155,13 @@ module OnebusawaySDK
165
155
  OMIT = Object.new.freeze
166
156
 
167
157
  class << self
168
- # @private
158
+ # @api private
169
159
  #
170
160
  # @param lhs [Object]
171
161
  # @param rhs [Object]
172
162
  # @param concat [Boolean]
173
163
  #
174
164
  # @return [Object]
175
- #
176
165
  private def deep_merge_lr(lhs, rhs, concat: false)
177
166
  case [lhs, rhs, concat]
178
167
  in [Hash, Hash, _]
@@ -191,7 +180,7 @@ module OnebusawaySDK
191
180
  end
192
181
  end
193
182
 
194
- # @private
183
+ # @api private
195
184
  #
196
185
  # Recursively merge one hash with another. If the values at a given key are not
197
186
  # both hashes, just take the new value.
@@ -203,7 +192,6 @@ module OnebusawaySDK
203
192
  # @param concat [Boolean] whether to merge sequences by concatenation.
204
193
  #
205
194
  # @return [Object]
206
- #
207
195
  def deep_merge(*values, sentinel: nil, concat: false)
208
196
  case values
209
197
  in [value, *values]
@@ -215,7 +203,7 @@ module OnebusawaySDK
215
203
  end
216
204
  end
217
205
 
218
- # @private
206
+ # @api private
219
207
  #
220
208
  # @param data [Hash{Symbol=>Object}, Array<Object>, Object]
221
209
  # @param pick [Symbol, Integer, Array<Symbol, Integer>, nil]
@@ -223,7 +211,6 @@ module OnebusawaySDK
223
211
  # @param blk [Proc, nil]
224
212
  #
225
213
  # @return [Object, nil]
226
- #
227
214
  def dig(data, pick, sentinel = nil, &blk)
228
215
  case [data, pick, blk]
229
216
  in [_, nil, nil]
@@ -248,22 +235,20 @@ module OnebusawaySDK
248
235
  end
249
236
 
250
237
  class << self
251
- # @private
238
+ # @api private
252
239
  #
253
240
  # @param uri [URI::Generic]
254
241
  #
255
242
  # @return [String]
256
- #
257
243
  def uri_origin(uri)
258
244
  "#{uri.scheme}://#{uri.host}#{uri.port == uri.default_port ? '' : ":#{uri.port}"}"
259
245
  end
260
246
 
261
- # @private
247
+ # @api private
262
248
  #
263
249
  # @param path [String, Array<String>]
264
250
  #
265
251
  # @return [String]
266
- #
267
252
  def interpolate_path(path)
268
253
  case path
269
254
  in String
@@ -278,40 +263,37 @@ module OnebusawaySDK
278
263
  end
279
264
 
280
265
  class << self
281
- # @private
266
+ # @api private
282
267
  #
283
268
  # @param query [String, nil]
284
269
  #
285
270
  # @return [Hash{String=>Array<String>}]
286
- #
287
271
  def decode_query(query)
288
272
  CGI.parse(query.to_s)
289
273
  end
290
274
 
291
- # @private
275
+ # @api private
292
276
  #
293
277
  # @param query [Hash{String=>Array<String>, String, nil}, nil]
294
278
  #
295
279
  # @return [String, nil]
296
- #
297
280
  def encode_query(query)
298
281
  query.to_h.empty? ? nil : URI.encode_www_form(query)
299
282
  end
300
283
  end
301
284
 
302
285
  class << self
303
- # @private
286
+ # @api private
304
287
  #
305
288
  # @param url [URI::Generic, String]
306
289
  #
307
290
  # @return [Hash{Symbol=>String, Integer, nil}]
308
- #
309
291
  def parse_uri(url)
310
292
  parsed = URI::Generic.component.zip(URI.split(url)).to_h
311
293
  {**parsed, query: decode_query(parsed.fetch(:query))}
312
294
  end
313
295
 
314
- # @private
296
+ # @api private
315
297
  #
316
298
  # @param parsed [Hash{Symbol=>String, Integer, nil}] .
317
299
  #
@@ -326,12 +308,11 @@ module OnebusawaySDK
326
308
  # @option parsed [Hash{String=>Array<String>}] :query
327
309
  #
328
310
  # @return [URI::Generic]
329
- #
330
311
  def unparse_uri(parsed)
331
312
  URI::Generic.build(**parsed, query: encode_query(parsed.fetch(:query)))
332
313
  end
333
314
 
334
- # @private
315
+ # @api private
335
316
  #
336
317
  # @param lhs [Hash{Symbol=>String, Integer, nil}] .
337
318
  #
@@ -358,7 +339,6 @@ module OnebusawaySDK
358
339
  # @option rhs [Hash{String=>Array<String>}] :query
359
340
  #
360
341
  # @return [URI::Generic]
361
- #
362
342
  def join_parsed_uri(lhs, rhs)
363
343
  base_path, base_query = lhs.fetch_values(:path, :query)
364
344
  slashed = base_path.end_with?("/") ? base_path : "#{base_path}/"
@@ -380,12 +360,11 @@ module OnebusawaySDK
380
360
  end
381
361
 
382
362
  class << self
383
- # @private
363
+ # @api private
384
364
  #
385
365
  # @param headers [Hash{String=>String, Integer, Array<String, Integer, nil>, nil}]
386
366
  #
387
367
  # @return [Hash{String=>String}]
388
- #
389
368
  def normalized_headers(*headers)
390
369
  {}.merge(*headers.compact).to_h do |key, val|
391
370
  case val
@@ -399,93 +378,173 @@ module OnebusawaySDK
399
378
  end
400
379
  end
401
380
 
381
+ # @api private
382
+ #
383
+ # An adapter that satisfies the IO interface required by `::IO.copy_stream`
384
+ class ReadIOAdapter
385
+ # @api private
386
+ #
387
+ # @param max_len [Integer, nil]
388
+ #
389
+ # @return [String]
390
+ private def read_enum(max_len)
391
+ case max_len
392
+ in nil
393
+ @stream.to_a.join
394
+ in Integer
395
+ @buf << @stream.next while @buf.length < max_len
396
+ @buf.slice!(..max_len)
397
+ end
398
+ rescue StopIteration
399
+ @stream = nil
400
+ @buf.slice!(0..)
401
+ end
402
+
403
+ # @api private
404
+ #
405
+ # @param max_len [Integer, nil]
406
+ # @param out_string [String, nil]
407
+ #
408
+ # @return [String, nil]
409
+ def read(max_len = nil, out_string = nil)
410
+ case @stream
411
+ in nil
412
+ nil
413
+ in IO | StringIO
414
+ @stream.read(max_len, out_string)
415
+ in Enumerator
416
+ read = read_enum(max_len)
417
+ case out_string
418
+ in String
419
+ out_string.replace(read)
420
+ in nil
421
+ read
422
+ end
423
+ end
424
+ .tap(&@blk)
425
+ end
426
+
427
+ # @api private
428
+ #
429
+ # @param stream [String, IO, StringIO, Enumerable]
430
+ # @param blk [Proc]
431
+ def initialize(stream, &blk)
432
+ @stream = stream.is_a?(String) ? StringIO.new(stream) : stream
433
+ @buf = String.new.b
434
+ @blk = blk
435
+ end
436
+ end
437
+
402
438
  class << self
403
- # @private
439
+ # @param blk [Proc]
440
+ #
441
+ # @return [Enumerable]
442
+ def string_io(&blk)
443
+ Enumerator.new do |y|
444
+ y.define_singleton_method(:write) do
445
+ self << _1.clone
446
+ _1.bytesize
447
+ end
448
+
449
+ blk.call(y)
450
+ end
451
+ end
452
+ end
453
+
454
+ class << self
455
+ # @api private
404
456
  #
405
- # @param io [StringIO]
457
+ # @param y [Enumerator::Yielder]
406
458
  # @param boundary [String]
407
459
  # @param key [Symbol, String]
408
460
  # @param val [Object]
409
- #
410
- private def encode_multipart_formdata(io, boundary:, key:, val:)
411
- io << "--#{boundary}\r\n"
412
- io << "Content-Disposition: form-data"
461
+ private def encode_multipart_formdata(y, boundary:, key:, val:)
462
+ y << "--#{boundary}\r\n"
463
+ y << "Content-Disposition: form-data"
413
464
  unless key.nil?
414
465
  name = ERB::Util.url_encode(key.to_s)
415
- io << "; name=\"#{name}\""
466
+ y << "; name=\"#{name}\""
416
467
  end
417
468
  if val.is_a?(IO)
418
469
  filename = ERB::Util.url_encode(File.basename(val.to_path))
419
- io << "; filename=\"#{filename}\""
470
+ y << "; filename=\"#{filename}\""
420
471
  end
421
- io << "\r\n"
472
+ y << "\r\n"
422
473
  case val
423
- in IO | StringIO
424
- io << "Content-Type: application/octet-stream\r\n\r\n"
425
- IO.copy_stream(val, io)
474
+ in IO
475
+ y << "Content-Type: application/octet-stream\r\n\r\n"
476
+ IO.copy_stream(val, y)
477
+ in StringIO
478
+ y << "Content-Type: application/octet-stream\r\n\r\n"
479
+ y << val.string
426
480
  in String
427
- io << "Content-Type: application/octet-stream\r\n\r\n"
428
- io << val.to_s
481
+ y << "Content-Type: application/octet-stream\r\n\r\n"
482
+ y << val.to_s
429
483
  in true | false | Integer | Float | Symbol
430
- io << "Content-Type: text/plain\r\n\r\n"
431
- io << val.to_s
484
+ y << "Content-Type: text/plain\r\n\r\n"
485
+ y << val.to_s
432
486
  else
433
- io << "Content-Type: application/json\r\n\r\n"
434
- io << JSON.fast_generate(val)
487
+ y << "Content-Type: application/json\r\n\r\n"
488
+ y << JSON.fast_generate(val)
435
489
  end
436
- io << "\r\n"
490
+ y << "\r\n"
437
491
  end
438
492
 
439
- # @private
493
+ # @api private
494
+ #
495
+ # @param body [Object]
496
+ #
497
+ # @return [Array(String, Enumerable)]
498
+ private def encode_multipart_streaming(body)
499
+ boundary = SecureRandom.urlsafe_base64(60)
500
+
501
+ strio = string_io do |y|
502
+ case body
503
+ in Hash
504
+ body.each do |key, val|
505
+ case val
506
+ in Array if val.all? { primitive?(_1) }
507
+ val.each do |v|
508
+ encode_multipart_formdata(y, boundary: boundary, key: key, val: v)
509
+ end
510
+ else
511
+ encode_multipart_formdata(y, boundary: boundary, key: key, val: val)
512
+ end
513
+ end
514
+ else
515
+ encode_multipart_formdata(y, boundary: boundary, key: nil, val: body)
516
+ end
517
+ y << "--#{boundary}--\r\n"
518
+ end
519
+
520
+ [boundary, strio]
521
+ end
522
+
523
+ # @api private
440
524
  #
441
525
  # @param headers [Hash{String=>String}]
442
526
  # @param body [Object]
443
527
  #
444
528
  # @return [Object]
445
- #
446
529
  def encode_content(headers, body)
447
530
  content_type = headers["content-type"]
448
531
  case [content_type, body]
449
- in ["application/json", Hash | Array]
532
+ in [%r{^application/(?:vnd\.api\+)?json}, Hash | Array]
450
533
  [headers, JSON.fast_generate(body)]
534
+ in [%r{^application/(?:x-)?jsonl}, Enumerable]
535
+ [headers, body.lazy.map { JSON.fast_generate(_1) }]
451
536
  in [%r{^multipart/form-data}, Hash | IO | StringIO]
452
- boundary = SecureRandom.urlsafe_base64(60)
453
- strio = StringIO.new.tap do |io|
454
- case body
455
- in Hash
456
- body.each do |key, val|
457
- case val
458
- in Array if val.all? { primitive?(_1) }
459
- val.each do |v|
460
- encode_multipart_formdata(io, boundary: boundary, key: key, val: v)
461
- end
462
- else
463
- encode_multipart_formdata(io, boundary: boundary, key: key, val: val)
464
- end
465
- end
466
- else
467
- encode_multipart_formdata(io, boundary: boundary, key: nil, val: body)
468
- end
469
- io << "--#{boundary}--\r\n"
470
- io.rewind
471
- end
472
- headers = {
473
- **headers,
474
- "content-type" => "#{content_type}; boundary=#{boundary}",
475
- "transfer-encoding" => "chunked"
476
- }
537
+ boundary, strio = encode_multipart_streaming(body)
538
+ headers = {**headers, "content-type" => "#{content_type}; boundary=#{boundary}"}
477
539
  [headers, strio]
478
540
  in [_, StringIO]
479
541
  [headers, body.string]
480
- in [_, IO]
481
- headers = {**headers, "transfer-encoding" => "chunked"}
482
- [headers, body]
483
542
  else
484
543
  [headers, body]
485
544
  end
486
545
  end
487
546
 
488
- # @private
547
+ # @api private
489
548
  #
490
549
  # @param headers [Hash{String=>String}, Net::HTTPHeader]
491
550
  # @param stream [Enumerable]
@@ -493,10 +552,9 @@ module OnebusawaySDK
493
552
  #
494
553
  # @raise [JSON::ParserError]
495
554
  # @return [Object]
496
- #
497
555
  def decode_content(headers, stream:, suppress_error: false)
498
556
  case headers["content-type"]
499
- in %r{^application/json}
557
+ in %r{^application/(?:vnd\.api\+)?json}
500
558
  json = stream.to_a.join
501
559
  begin
502
560
  JSON.parse(json, symbolize_names: true)
@@ -504,6 +562,14 @@ module OnebusawaySDK
504
562
  raise e unless suppress_error
505
563
  json
506
564
  end
565
+ in %r{^application/(?:x-)?jsonl}
566
+ lines = decode_lines(stream)
567
+ chain_fused(lines) do |y|
568
+ lines.each { y << JSON.parse(_1, symbolize_names: true) }
569
+ end
570
+ in %r{^text/event-stream}
571
+ lines = decode_lines(stream)
572
+ decode_sse(lines)
507
573
  in %r{^text/}
508
574
  stream.to_a.join
509
575
  else
@@ -512,6 +578,141 @@ module OnebusawaySDK
512
578
  end
513
579
  end
514
580
  end
581
+
582
+ class << self
583
+ # @api private
584
+ #
585
+ # https://doc.rust-lang.org/std/iter/trait.FusedIterator.html
586
+ #
587
+ # @param enum [Enumerable]
588
+ # @param external [Boolean]
589
+ # @param close [Proc]
590
+ #
591
+ # @return [Enumerable]
592
+ def fused_enum(enum, external: false, &close)
593
+ fused = false
594
+ iter = Enumerator.new do |y|
595
+ next if fused
596
+
597
+ fused = true
598
+ if external
599
+ loop { y << enum.next }
600
+ else
601
+ enum.each(&y)
602
+ end
603
+ ensure
604
+ close&.call
605
+ close = nil
606
+ end
607
+
608
+ iter.define_singleton_method(:rewind) do
609
+ fused = true
610
+ self
611
+ end
612
+ iter
613
+ end
614
+
615
+ # @api private
616
+ #
617
+ # @param enum [Enumerable, nil]
618
+ def close_fused!(enum)
619
+ return unless enum.is_a?(Enumerator)
620
+
621
+ # rubocop:disable Lint/UnreachableLoop
622
+ enum.rewind.each { break }
623
+ # rubocop:enable Lint/UnreachableLoop
624
+ end
625
+
626
+ # @api private
627
+ #
628
+ # @param enum [Enumerable, nil]
629
+ # @param blk [Proc]
630
+ #
631
+ # @return [Enumerable]
632
+ def chain_fused(enum, &blk)
633
+ iter = Enumerator.new { blk.call(_1) }
634
+ fused_enum(iter) { close_fused!(enum) }
635
+ end
636
+ end
637
+
638
+ class << self
639
+ # @api private
640
+ #
641
+ # @param enum [Enumerable]
642
+ #
643
+ # @return [Enumerable]
644
+ def decode_lines(enum)
645
+ re = /(\r\n|\r|\n)/
646
+ buffer = String.new.b
647
+ cr_seen = nil
648
+
649
+ chain_fused(enum) do |y|
650
+ enum.each do |row|
651
+ offset = buffer.bytesize
652
+ buffer << row
653
+ while (match = re.match(buffer, cr_seen&.to_i || offset))
654
+ case [match.captures.first, cr_seen]
655
+ in ["\r", nil]
656
+ cr_seen = match.end(1)
657
+ next
658
+ in ["\r" | "\r\n", Integer]
659
+ y << buffer.slice!(..(cr_seen.pred))
660
+ else
661
+ y << buffer.slice!(..(match.end(1).pred))
662
+ end
663
+ offset = 0
664
+ cr_seen = nil
665
+ end
666
+ end
667
+
668
+ y << buffer.slice!(..(cr_seen.pred)) unless cr_seen.nil?
669
+ y << buffer unless buffer.empty?
670
+ end
671
+ end
672
+
673
+ # @api private
674
+ #
675
+ # https://html.spec.whatwg.org/multipage/server-sent-events.html#parsing-an-event-stream
676
+ #
677
+ # @param lines [Enumerable]
678
+ #
679
+ # @return [Hash{Symbol=>Object}]
680
+ def decode_sse(lines)
681
+ # rubocop:disable Metrics/BlockLength
682
+ chain_fused(lines) do |y|
683
+ blank = {event: nil, data: nil, id: nil, retry: nil}
684
+ current = {}
685
+
686
+ lines.each do |line|
687
+ case line.sub(/\R$/, "")
688
+ in ""
689
+ next if current.empty?
690
+ y << {**blank, **current}
691
+ current = {}
692
+ in /^:/
693
+ next
694
+ in /^([^:]+):\s?(.*)$/
695
+ field, value = Regexp.last_match.captures
696
+ case field
697
+ in "event"
698
+ current.merge!(event: value)
699
+ in "data"
700
+ (current[:data] ||= String.new.b) << (value << "\n")
701
+ in "id" unless value.include?("\0")
702
+ current.merge!(id: value)
703
+ in "retry" if /^\d+$/ =~ value
704
+ current.merge!(retry: Integer(value))
705
+ else
706
+ end
707
+ else
708
+ end
709
+ end
710
+ # rubocop:enable Metrics/BlockLength
711
+
712
+ y << {**blank, **current} unless current.empty?
713
+ end
714
+ end
715
+ end
515
716
  end
516
717
 
517
718
  # rubocop:enable Metrics/ModuleLength
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module OnebusawaySDK
4
- VERSION = "0.1.0-alpha.205"
4
+ VERSION = "0.1.0-alpha.207"
5
5
  end
@@ -7,6 +7,7 @@ require "erb"
7
7
  require "etc"
8
8
  require "json"
9
9
  require "net/http"
10
+ require "pathname"
10
11
  require "rbconfig"
11
12
  require "securerandom"
12
13
  require "set"
data/manifest.yaml CHANGED
@@ -5,6 +5,7 @@ dependencies:
5
5
  - etc
6
6
  - json
7
7
  - net/http
8
+ - pathname
8
9
  - rbconfig
9
10
  - securerandom
10
11
  - set