code-ruby 4.0.0 → 4.0.2
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 +4 -4
- data/VERSION +1 -1
- data/bin/code +21 -34
- data/lib/code/concerns/shared.rb +103 -99
- data/lib/code/format.rb +23 -19
- data/lib/code/network.rb +23 -28
- data/lib/code/node/call.rb +15 -9
- data/lib/code/node/code.rb +5 -5
- data/lib/code/node/function.rb +6 -1
- data/lib/code/node/left_operation.rb +3 -3
- data/lib/code/node/list.rb +10 -8
- data/lib/code/node/square_bracket.rb +2 -2
- data/lib/code/object/boolean.rb +13 -17
- data/lib/code/object/class.rb +33 -27
- data/lib/code/object/code.rb +4 -47
- data/lib/code/object/context.rb +8 -11
- data/lib/code/object/cryptography.rb +12 -6
- data/lib/code/object/date.rb +910 -449
- data/lib/code/object/decimal.rb +229 -856
- data/lib/code/object/dictionary.rb +116 -49
- data/lib/code/object/duration.rb +3 -7
- data/lib/code/object/function.rb +96 -54
- data/lib/code/object/global.rb +122 -209
- data/lib/code/object/html.rb +7 -13
- data/lib/code/object/http.rb +29 -43
- data/lib/code/object/ics.rb +6 -13
- data/lib/code/object/identifier_list.rb +16 -11
- data/lib/code/object/integer.rb +270 -942
- data/lib/code/object/json.rb +8 -28
- data/lib/code/object/list.rb +98 -114
- data/lib/code/object/nothing.rb +11 -11
- data/lib/code/object/number.rb +20 -10
- data/lib/code/object/parameter.rb +18 -9
- data/lib/code/object/range.rb +62 -108
- data/lib/code/object/smtp.rb +20 -15
- data/lib/code/object/string.rb +55 -29
- data/lib/code/object/super.rb +2 -1
- data/lib/code/object/time.rb +1146 -572
- data/lib/code/object/url.rb +4 -2
- data/lib/code/object.rb +119 -80
- data/lib/code/parser.rb +31 -92
- data/lib/code.rb +3 -11
- metadata +3 -23
data/lib/code/object/http.rb
CHANGED
|
@@ -5,7 +5,8 @@ class Code
|
|
|
5
5
|
class Http < Object
|
|
6
6
|
CLASS_DOCUMENTATION = {
|
|
7
7
|
name: "Http",
|
|
8
|
-
description:
|
|
8
|
+
description:
|
|
9
|
+
"sends http requests and returns dictionaries with request and response details.",
|
|
9
10
|
examples: [
|
|
10
11
|
"Http.get(\"http://httpbin.org/status/200\").success?",
|
|
11
12
|
"Http.post(\"http://httpbin.org/status/200\", body: :hello).request.body",
|
|
@@ -15,7 +16,8 @@ class Code
|
|
|
15
16
|
CLASS_FUNCTIONS = {
|
|
16
17
|
"get" => {
|
|
17
18
|
name: "get",
|
|
18
|
-
description:
|
|
19
|
+
description:
|
|
20
|
+
"sends a get request and returns the response dictionary.",
|
|
19
21
|
examples: [
|
|
20
22
|
"Http.get(\"http://httpbin.org/status/200\").code",
|
|
21
23
|
"Http.get(\"http://httpbin.org/status/200\", query: { q: :ruby }).url",
|
|
@@ -24,7 +26,8 @@ class Code
|
|
|
24
26
|
},
|
|
25
27
|
"head" => {
|
|
26
28
|
name: "head",
|
|
27
|
-
description:
|
|
29
|
+
description:
|
|
30
|
+
"sends a head request and returns the response dictionary.",
|
|
28
31
|
examples: [
|
|
29
32
|
"Http.head(\"http://httpbin.org/status/200\").code",
|
|
30
33
|
"Http.head(\"http://httpbin.org/status/204\").status",
|
|
@@ -33,7 +36,8 @@ class Code
|
|
|
33
36
|
},
|
|
34
37
|
"post" => {
|
|
35
38
|
name: "post",
|
|
36
|
-
description:
|
|
39
|
+
description:
|
|
40
|
+
"sends a post request with optional body, form data, and headers.",
|
|
37
41
|
examples: [
|
|
38
42
|
"Http.post(\"http://httpbin.org/status/200\", body: :hello).request.body",
|
|
39
43
|
"Http.post(\"http://httpbin.org/status/200\", data: { a: 1 }).success?",
|
|
@@ -51,7 +55,8 @@ class Code
|
|
|
51
55
|
},
|
|
52
56
|
"delete" => {
|
|
53
57
|
name: "delete",
|
|
54
|
-
description:
|
|
58
|
+
description:
|
|
59
|
+
"sends a delete request and returns the response dictionary.",
|
|
55
60
|
examples: [
|
|
56
61
|
"Http.delete(\"http://httpbin.org/status/200\").success?",
|
|
57
62
|
"Http.delete(\"http://httpbin.org/status/200\", body: :hello).request.body",
|
|
@@ -60,7 +65,8 @@ class Code
|
|
|
60
65
|
},
|
|
61
66
|
"options" => {
|
|
62
67
|
name: "options",
|
|
63
|
-
description:
|
|
68
|
+
description:
|
|
69
|
+
"sends an options request and returns the response dictionary.",
|
|
64
70
|
examples: [
|
|
65
71
|
"Http.options(\"http://httpbin.org/status/200\").method",
|
|
66
72
|
"Http.options(\"http://httpbin.org/status/204\").code",
|
|
@@ -69,7 +75,8 @@ class Code
|
|
|
69
75
|
},
|
|
70
76
|
"trace" => {
|
|
71
77
|
name: "trace",
|
|
72
|
-
description:
|
|
78
|
+
description:
|
|
79
|
+
"sends a trace request and returns the response dictionary.",
|
|
73
80
|
examples: [
|
|
74
81
|
"Http.trace(\"http://httpbin.org/status/200\").method",
|
|
75
82
|
"Http.trace(\"http://httpbin.org/status/204\").code",
|
|
@@ -184,8 +191,6 @@ class Code
|
|
|
184
191
|
network_authentication_required: 511
|
|
185
192
|
}.freeze
|
|
186
193
|
DEFAULT_TIMEOUT = 1.hour.to_f
|
|
187
|
-
MAX_REQUEST_BYTES = ::Code::MAX_INPUT_BYTES
|
|
188
|
-
MAX_RESPONSE_BYTES = ::Code::MAX_INPUT_BYTES
|
|
189
194
|
MAX_HEADER_BYTES = 32.kilobytes
|
|
190
195
|
HEADER_NAME = /\A[A-Za-z0-9!#$%&'*+\-.^_`|~]+\z/
|
|
191
196
|
RESTRICTED_HEADERS = %w[
|
|
@@ -284,15 +289,9 @@ class Code
|
|
|
284
289
|
write_timeout = options.code_get("write_timeout")
|
|
285
290
|
query = options.code_get("query").raw || {}
|
|
286
291
|
query = query.to_a.flatten.map(&:to_s).each_slice(2).to_h.to_query
|
|
287
|
-
validate_payload_size!(username, label: "http username")
|
|
288
|
-
validate_payload_size!(password, label: "http password")
|
|
289
|
-
validate_payload_size!(query, label: "http query")
|
|
290
|
-
validate_payload_size!(body, label: "http request body")
|
|
291
|
-
validate_payload_size!(data.as_json.to_query, label: "http form data") if data.present?
|
|
292
292
|
|
|
293
293
|
url = original_url
|
|
294
294
|
url = "#{url}?#{query}" if query.present?
|
|
295
|
-
validate_payload_size!(url, label: "http url")
|
|
296
295
|
|
|
297
296
|
if username.present? || password.present?
|
|
298
297
|
authorization = ::Base64.strict_encode64("#{username}:#{password}")
|
|
@@ -307,12 +306,9 @@ class Code
|
|
|
307
306
|
http.ipaddr = resolved_ip
|
|
308
307
|
http.use_ssl = true if uri.scheme == "https"
|
|
309
308
|
default_timeout = http_timeout(timeout, DEFAULT_TIMEOUT)
|
|
310
|
-
open_timeout_value =
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
http_timeout(read_timeout, default_timeout)
|
|
314
|
-
write_timeout_value =
|
|
315
|
-
http_timeout(write_timeout, default_timeout)
|
|
309
|
+
open_timeout_value = http_timeout(open_timeout, default_timeout)
|
|
310
|
+
read_timeout_value = http_timeout(read_timeout, default_timeout)
|
|
311
|
+
write_timeout_value = http_timeout(write_timeout, default_timeout)
|
|
316
312
|
|
|
317
313
|
http.open_timeout = open_timeout_value if open_timeout_value
|
|
318
314
|
http.read_timeout = read_timeout_value if read_timeout_value
|
|
@@ -350,10 +346,6 @@ class Code
|
|
|
350
346
|
validate_response_headers!(http_response)
|
|
351
347
|
|
|
352
348
|
http_response.read_body do |chunk|
|
|
353
|
-
if response_body.bytesize + chunk.bytesize > MAX_RESPONSE_BYTES
|
|
354
|
-
raise ::Code::Error, "http response is too large"
|
|
355
|
-
end
|
|
356
|
-
|
|
357
349
|
response_body << chunk
|
|
358
350
|
end
|
|
359
351
|
end
|
|
@@ -383,27 +375,26 @@ class Code
|
|
|
383
375
|
else
|
|
384
376
|
status = STATUS_CODES.key(code) || :ok
|
|
385
377
|
response_headers = response.each_header.to_h
|
|
386
|
-
request_headers =
|
|
387
|
-
List.new(values)
|
|
388
|
-
end
|
|
378
|
+
request_headers =
|
|
379
|
+
request.to_hash.transform_values { |values| List.new(values) }
|
|
389
380
|
body = response_body.to_s
|
|
390
381
|
|
|
391
382
|
Dictionary.new(
|
|
392
|
-
code
|
|
393
|
-
status
|
|
394
|
-
body
|
|
395
|
-
headers
|
|
396
|
-
method
|
|
397
|
-
url
|
|
383
|
+
:code => code,
|
|
384
|
+
:status => status,
|
|
385
|
+
:body => body,
|
|
386
|
+
:headers => response_headers,
|
|
387
|
+
:method => verb,
|
|
388
|
+
:url => url,
|
|
398
389
|
"success?" => code.between?(200, 299),
|
|
399
390
|
"redirect?" => code.between?(300, 399),
|
|
400
|
-
request
|
|
391
|
+
:request => {
|
|
401
392
|
method: verb,
|
|
402
393
|
url: url,
|
|
403
394
|
headers: request_headers,
|
|
404
395
|
body: request.body.to_s
|
|
405
396
|
},
|
|
406
|
-
response
|
|
397
|
+
:response => {
|
|
407
398
|
code: code,
|
|
408
399
|
status: status,
|
|
409
400
|
headers: response_headers,
|
|
@@ -421,7 +412,8 @@ class Code
|
|
|
421
412
|
|
|
422
413
|
def self.same_origin?(new_uri, original_uri)
|
|
423
414
|
new_uri.scheme == original_uri.scheme &&
|
|
424
|
-
new_uri.hostname.to_s.downcase ==
|
|
415
|
+
new_uri.hostname.to_s.downcase ==
|
|
416
|
+
original_uri.hostname.to_s.downcase &&
|
|
425
417
|
new_uri.port == original_uri.port
|
|
426
418
|
end
|
|
427
419
|
|
|
@@ -472,12 +464,6 @@ class Code
|
|
|
472
464
|
raise ::Code::Error, "http response headers are too large"
|
|
473
465
|
end
|
|
474
466
|
|
|
475
|
-
def self.validate_payload_size!(value, label:)
|
|
476
|
-
return if value.to_s.bytesize <= MAX_REQUEST_BYTES
|
|
477
|
-
|
|
478
|
-
raise ::Code::Error, "#{label} is too large"
|
|
479
|
-
end
|
|
480
|
-
|
|
481
467
|
def self.http_timeout(value, default)
|
|
482
468
|
::Code.normalize_timeout!(value.nothing? ? default : value)
|
|
483
469
|
end
|
data/lib/code/object/ics.rb
CHANGED
|
@@ -5,7 +5,8 @@ class Code
|
|
|
5
5
|
class Ics < Object
|
|
6
6
|
CLASS_DOCUMENTATION = {
|
|
7
7
|
name: "Ics",
|
|
8
|
-
description:
|
|
8
|
+
description:
|
|
9
|
+
"parses icalendar text and exposes events as dictionaries.",
|
|
9
10
|
examples: [
|
|
10
11
|
"Ics.parse(\"BEGIN:VCALENDAR\\nBEGIN:VEVENT\\nSUMMARY:meet\\nEND:VEVENT\\nEND:VCALENDAR\")",
|
|
11
12
|
"Ics.parse(\"BEGIN:VCALENDAR\\nVERSION:2.0\\nEND:VCALENDAR\")",
|
|
@@ -43,8 +44,6 @@ class Code
|
|
|
43
44
|
geo
|
|
44
45
|
].freeze
|
|
45
46
|
MISSING_ATTRIBUTE = Object.new.freeze
|
|
46
|
-
MAX_EVENTS = 10_000
|
|
47
|
-
MAX_NESTING = 50
|
|
48
47
|
|
|
49
48
|
def self.call(**args)
|
|
50
49
|
code_operator = args.fetch(:operator, nil).to_code
|
|
@@ -62,10 +61,8 @@ class Code
|
|
|
62
61
|
|
|
63
62
|
def self.code_parse(value)
|
|
64
63
|
source = value.to_code.raw
|
|
65
|
-
::Code.ensure_input_size!(source, label: "ics")
|
|
66
64
|
calendars = ::Icalendar::Calendar.parse(source)
|
|
67
65
|
events = calendars.flat_map(&:events)
|
|
68
|
-
raise Error, "ics has too many events" if events.size > MAX_EVENTS
|
|
69
66
|
|
|
70
67
|
events.map { |event| serialize_event(event) }.to_code
|
|
71
68
|
rescue ::Code::Error
|
|
@@ -127,9 +124,7 @@ class Code
|
|
|
127
124
|
MISSING_ATTRIBUTE
|
|
128
125
|
end
|
|
129
126
|
|
|
130
|
-
def self.serialize_value(value
|
|
131
|
-
raise Error, "ics is too deeply nested" if depth > MAX_NESTING
|
|
132
|
-
|
|
127
|
+
def self.serialize_value(value)
|
|
133
128
|
case value
|
|
134
129
|
when nil
|
|
135
130
|
nil
|
|
@@ -138,17 +133,15 @@ class Code
|
|
|
138
133
|
when ::Symbol, ::Integer, ::Float, ::BigDecimal, true, false
|
|
139
134
|
value
|
|
140
135
|
when ::Array
|
|
141
|
-
value.map { |item| serialize_value(item
|
|
136
|
+
value.map { |item| serialize_value(item) }
|
|
142
137
|
when ::Hash
|
|
143
|
-
value.transform_values
|
|
144
|
-
serialize_value(item, depth: depth + 1)
|
|
145
|
-
end
|
|
138
|
+
value.transform_values { |item| serialize_value(item) }
|
|
146
139
|
else
|
|
147
140
|
serialized_date = serialize_date_like(value)
|
|
148
141
|
return serialized_date unless serialized_date.nil?
|
|
149
142
|
|
|
150
143
|
if value.is_a?(::Icalendar::Value)
|
|
151
|
-
serialize_value(value.value
|
|
144
|
+
serialize_value(value.value)
|
|
152
145
|
else
|
|
153
146
|
normalize_string(value.to_s)
|
|
154
147
|
end
|
|
@@ -5,7 +5,8 @@ class Code
|
|
|
5
5
|
class IdentifierList < List
|
|
6
6
|
CLASS_DOCUMENTATION = {
|
|
7
7
|
name: "IdentifierList",
|
|
8
|
-
description:
|
|
8
|
+
description:
|
|
9
|
+
"stores ordered identifier names used to assign nested values.",
|
|
9
10
|
examples: [
|
|
10
11
|
"IdentifierList",
|
|
11
12
|
"IdentifierList.new([:user, :name]).first",
|
|
@@ -92,11 +93,13 @@ class Code
|
|
|
92
93
|
end
|
|
93
94
|
|
|
94
95
|
if assignment_operator == "="
|
|
95
|
-
receiver
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
96
|
+
receiver
|
|
97
|
+
.call(
|
|
98
|
+
**args,
|
|
99
|
+
operator: "#{raw.last}=",
|
|
100
|
+
arguments: Object::List.new([code_value])
|
|
101
|
+
)
|
|
102
|
+
.tap { persist_class_receiver(receiver, args.fetch(:context)) }
|
|
100
103
|
else
|
|
101
104
|
next_value =
|
|
102
105
|
receiver.call(
|
|
@@ -109,11 +112,13 @@ class Code
|
|
|
109
112
|
arguments: Object::List.new([code_value])
|
|
110
113
|
)
|
|
111
114
|
|
|
112
|
-
receiver
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
115
|
+
receiver
|
|
116
|
+
.call(
|
|
117
|
+
**args,
|
|
118
|
+
operator: "#{raw.last}=",
|
|
119
|
+
arguments: Object::List.new([next_value])
|
|
120
|
+
)
|
|
121
|
+
.tap { persist_class_receiver(receiver, args.fetch(:context)) }
|
|
117
122
|
end
|
|
118
123
|
end
|
|
119
124
|
|