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.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/bin/code +21 -34
  4. data/lib/code/concerns/shared.rb +103 -99
  5. data/lib/code/format.rb +23 -19
  6. data/lib/code/network.rb +23 -28
  7. data/lib/code/node/call.rb +15 -9
  8. data/lib/code/node/code.rb +5 -5
  9. data/lib/code/node/function.rb +6 -1
  10. data/lib/code/node/left_operation.rb +3 -3
  11. data/lib/code/node/list.rb +10 -8
  12. data/lib/code/node/square_bracket.rb +2 -2
  13. data/lib/code/object/boolean.rb +13 -17
  14. data/lib/code/object/class.rb +33 -27
  15. data/lib/code/object/code.rb +4 -47
  16. data/lib/code/object/context.rb +8 -11
  17. data/lib/code/object/cryptography.rb +12 -6
  18. data/lib/code/object/date.rb +910 -449
  19. data/lib/code/object/decimal.rb +229 -856
  20. data/lib/code/object/dictionary.rb +116 -49
  21. data/lib/code/object/duration.rb +3 -7
  22. data/lib/code/object/function.rb +96 -54
  23. data/lib/code/object/global.rb +122 -209
  24. data/lib/code/object/html.rb +7 -13
  25. data/lib/code/object/http.rb +29 -43
  26. data/lib/code/object/ics.rb +6 -13
  27. data/lib/code/object/identifier_list.rb +16 -11
  28. data/lib/code/object/integer.rb +270 -942
  29. data/lib/code/object/json.rb +8 -28
  30. data/lib/code/object/list.rb +98 -114
  31. data/lib/code/object/nothing.rb +11 -11
  32. data/lib/code/object/number.rb +20 -10
  33. data/lib/code/object/parameter.rb +18 -9
  34. data/lib/code/object/range.rb +62 -108
  35. data/lib/code/object/smtp.rb +20 -15
  36. data/lib/code/object/string.rb +55 -29
  37. data/lib/code/object/super.rb +2 -1
  38. data/lib/code/object/time.rb +1146 -572
  39. data/lib/code/object/url.rb +4 -2
  40. data/lib/code/object.rb +119 -80
  41. data/lib/code/parser.rb +31 -92
  42. data/lib/code.rb +3 -11
  43. metadata +3 -23
@@ -5,7 +5,8 @@ class Code
5
5
  class Http < Object
6
6
  CLASS_DOCUMENTATION = {
7
7
  name: "Http",
8
- description: "sends http requests and returns dictionaries with request and response details.",
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: "sends a get request and returns the response dictionary.",
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: "sends a head request and returns the response dictionary.",
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: "sends a post request with optional body, form data, and headers.",
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: "sends a delete request and returns the response dictionary.",
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: "sends an options request and returns the response dictionary.",
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: "sends a trace request and returns the response dictionary.",
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
- http_timeout(open_timeout, default_timeout)
312
- read_timeout_value =
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 = request.to_hash.transform_values do |values|
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: code,
393
- status: status,
394
- body: body,
395
- headers: response_headers,
396
- method: verb,
397
- url: 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 == original_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
@@ -5,7 +5,8 @@ class Code
5
5
  class Ics < Object
6
6
  CLASS_DOCUMENTATION = {
7
7
  name: "Ics",
8
- description: "parses icalendar text and exposes events as dictionaries.",
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, depth: 0)
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, depth: depth + 1) }
136
+ value.map { |item| serialize_value(item) }
142
137
  when ::Hash
143
- value.transform_values do |item|
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, depth: depth + 1)
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: "stores ordered identifier names used to assign nested values.",
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.call(
96
- **args,
97
- operator: "#{raw.last}=",
98
- arguments: Object::List.new([code_value])
99
- ).tap { persist_class_receiver(receiver, args.fetch(:context)) }
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.call(
113
- **args,
114
- operator: "#{raw.last}=",
115
- arguments: Object::List.new([next_value])
116
- ).tap { persist_class_receiver(receiver, args.fetch(:context)) }
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