code-ruby 4.0.1 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 04a1a64dae9f86bb218f016da7f56a7d4358d4dc63c620132ce58dd0a8d96b7d
4
- data.tar.gz: 3735d10e82af9370ed1c4cff86e5c3965678a7b22e3a5ea709f11eda601d49b7
3
+ metadata.gz: 2296ee1cc187e2213bbefbb8306efe2de92e79e21b12d8ff5f3472d5ce18eb30
4
+ data.tar.gz: ca3868cf9a4c2c58560a2c81130f633aced9c16a47af11d2386ea5c79a8ba6ce
5
5
  SHA512:
6
- metadata.gz: d3c2288da223c047a41c6f6f30eba9c22c4e3ec7e4b058390530c0036a20d42580ce4755620345c4ff2c8403c0ffd9381d3a4865f690aedc2e4483617c695852
7
- data.tar.gz: f21b89e07ec4f156d8ed3eec697902da23cd6dc269a74eeee375a7cc06b83bd78f22d8dee9613a10e9546908379f1128d75f104549d5c16650d81849e08f94b0
6
+ metadata.gz: 9efaa6dd86c9e6484184ab83e2d4df371f32e737e507e90e60e9151acac473ec029eeecc26e123b577343286712197430c6828de4f340ea88effa592958f451b
7
+ data.tar.gz: f16dba556195a93d2b564511a020cf6bca95c24a86534ddb063573619c214b9fbc0439842621d9ef1244cd59cbb3e3fff1544dfd9c4074e96adc5c7541e1c4ee
data/VERSION CHANGED
@@ -1 +1 @@
1
- 4.0.1
1
+ 4.0.2
data/bin/code CHANGED
@@ -3,6 +3,7 @@
3
3
 
4
4
  require_relative "../lib/code-ruby"
5
5
  require "dorian/arguments"
6
+ require "pp"
6
7
 
7
8
  parsed =
8
9
  Dorian::Arguments.parse(
@@ -37,8 +38,6 @@ parsed =
37
38
  abort Code::Version.to_s if parsed.options.version
38
39
  abort parsed.help if parsed.options.help
39
40
 
40
- MAX_ARGUMENT_FILES = 1000
41
-
42
41
  def glob_pattern?(value)
43
42
  value.match?(/[*?\[\]{]/)
44
43
  end
@@ -47,35 +46,22 @@ def timeout
47
46
  @timeout ||= @parsed_timeout
48
47
  end
49
48
 
50
- def with_timeout(&)
51
- Timeout.timeout(timeout, &)
49
+ def with_timeout(&block)
50
+ Timeout.timeout(timeout, &block)
52
51
  rescue Timeout::Error
53
52
  raise Code::Error, "timeout"
54
53
  end
55
54
 
56
- def append_limited(buffer, value, label: "input")
57
- value = value.to_s
58
- if buffer.bytesize + value.bytesize > Code::MAX_INPUT_BYTES
59
- raise Code::Error, "#{label} is too large"
60
- end
61
-
62
- buffer << value
63
- end
64
-
65
55
  def read_file(path)
66
56
  raise Code::Error, "#{path} is not a regular file" unless File.file?(path)
67
57
 
68
58
  File.open(path, "rb") do |file|
69
- data = file.read(Code::MAX_INPUT_BYTES + 1).to_s
70
- Code.ensure_input_size!(data, label: path)
71
- data
59
+ file.read.to_s
72
60
  end
73
61
  end
74
62
 
75
63
  def read_stdin
76
- data = $stdin.read(Code::MAX_INPUT_BYTES + 1).to_s
77
- Code.ensure_input_size!(data, label: "stdin")
78
- data
64
+ $stdin.read.to_s
79
65
  end
80
66
 
81
67
  def expand_arguments(arguments)
@@ -94,10 +80,6 @@ def expand_arguments(arguments)
94
80
  else
95
81
  remaining_arguments << argument
96
82
  end
97
-
98
- if expanded_files.size > MAX_ARGUMENT_FILES
99
- raise Code::Error, "too many input files"
100
- end
101
83
  end
102
84
 
103
85
  [expanded_files, remaining_arguments]
@@ -118,22 +100,20 @@ begin
118
100
  expanded_argument_files, remaining_arguments =
119
101
  expand_arguments(parsed.arguments)
120
102
 
121
- if option_input.present? && File.exist?(option_input)
122
- append_limited(buffer, read_file(option_input))
123
- else
124
- append_limited(buffer, option_input)
125
- end
103
+ buffer <<
104
+ if option_input.present? && File.exist?(option_input)
105
+ read_file(option_input)
106
+ else
107
+ option_input
108
+ end
126
109
 
127
- append_limited(buffer, remaining_arguments.join(" "))
110
+ buffer << remaining_arguments.join(" ")
128
111
 
129
112
  input_files = parsed.files + expanded_argument_files
130
- if input_files.size > MAX_ARGUMENT_FILES
131
- raise Code::Error, "too many input files"
132
- end
133
113
 
134
114
  input_files.each.with_index do |file, index|
135
- append_limited(buffer, "\n\n") if index.positive?
136
- append_limited(buffer, read_file(file), label: file)
115
+ buffer << "\n\n" if index.positive?
116
+ buffer << read_file(file)
137
117
  end
138
118
 
139
119
  buffer
@@ -155,7 +135,11 @@ end
155
135
 
156
136
  if parsed.options.parse
157
137
  begin
158
- pp Code.parse(input, timeout: timeout)
138
+ output = StringIO.new
139
+ with_timeout { PP.pp(Code.parse(input, timeout: timeout), output) }
140
+ print output.string
141
+ rescue SystemStackError
142
+ warn "timeout"
159
143
  rescue StandardError => e
160
144
  warn e.message
161
145
  end
@@ -483,7 +483,7 @@ class Code
483
483
  self.class.new(self)
484
484
  end
485
485
 
486
- def code_deep_duplicate(_seen = {})
486
+ def code_deep_duplicate
487
487
  self.class.new(self)
488
488
  end
489
489
 
@@ -14,7 +14,12 @@ class Code
14
14
  end
15
15
 
16
16
  def evaluate(**args)
17
- Object::Function.new(@parameters, @body, args.fetch(:context))
17
+ Object::Function.new(
18
+ @parameters,
19
+ @body,
20
+ args.fetch(:context),
21
+ args.fetch(:previous_object)
22
+ )
18
23
  end
19
24
  end
20
25
 
@@ -21,11 +21,11 @@ class Code
21
21
  args
22
22
  end
23
23
  last = Object::Nothing.new
24
- root_object = args.fetch(:root_object, args.fetch(:object))
24
+ object = args.fetch(:previous_object)
25
25
 
26
26
  begin
27
27
  (@statements || []).each do |statement|
28
- last = statement.evaluate(**statement_args, object: root_object)
28
+ last = statement.evaluate(**statement_args, object: object)
29
29
  end
30
30
  rescue Error::Retry
31
31
  retry if control_flow_scope == :group
@@ -48,10 +48,10 @@ class Code
48
48
 
49
49
  def resolve(**args)
50
50
  last = Object::Nothing.new
51
- root_object = args.fetch(:root_object, args.fetch(:object))
51
+ object = args.fetch(:previous_object)
52
52
 
53
53
  (@statements || []).each do |statement|
54
- last = statement.resolve(**args, object: root_object)
54
+ last = statement.resolve(**args, object: object)
55
55
  end
56
56
 
57
57
  last
@@ -13,7 +13,12 @@ class Code
13
13
  end
14
14
 
15
15
  def evaluate(**args)
16
- Object::Function.new(@parameters, @body, args.fetch(:context))
16
+ Object::Function.new(
17
+ @parameters,
18
+ @body,
19
+ args.fetch(:context),
20
+ args.fetch(:previous_object)
21
+ )
17
22
  end
18
23
  end
19
24
  end
@@ -54,7 +54,7 @@ class Code
54
54
  right.statement.evaluate(
55
55
  **args,
56
56
  object: left,
57
- previous_object: args.fetch(:object)
57
+ previous_object: args.fetch(:previous_object)
58
58
  )
59
59
  elsif right.safe_call?
60
60
  if left.is_an?(Object::Nothing)
@@ -63,7 +63,7 @@ class Code
63
63
  right.statement.evaluate(
64
64
  **args,
65
65
  object: left,
66
- previous_object: args.fetch(:object)
66
+ previous_object: args.fetch(:previous_object)
67
67
  )
68
68
  end
69
69
  elsif (right.or? && left.truthy?) || (right.and? && left.falsy?)
@@ -88,7 +88,7 @@ class Code
88
88
  other.statement.resolve(
89
89
  **args,
90
90
  object: list.code_last,
91
- previous_object: args.fetch(:object)
91
+ previous_object: args.fetch(:previous_object)
92
92
  )
93
93
 
94
94
  if resolved.is_a?(Object::IdentifierList)
@@ -13,8 +13,7 @@ class Code
13
13
 
14
14
  def evaluate(**args)
15
15
  left = @left&.evaluate(**args) || Object::Nothing.new
16
- index_args =
17
- args.merge(object: args.fetch(:previous_object, args.fetch(:object)))
16
+ index_args = args.merge(object: args.fetch(:previous_object))
18
17
 
19
18
  (@statements || []).reduce(left) do |object, statement|
20
19
  object.code_fetch(statement.evaluate(**index_args))
@@ -31,8 +30,7 @@ class Code
31
30
  Object::IdentifierList.new([left])
32
31
  end
33
32
 
34
- index_args =
35
- args.merge(object: args.fetch(:previous_object, args.fetch(:object)))
33
+ index_args = args.merge(object: args.fetch(:previous_object))
36
34
 
37
35
  (@statements || []).each do |statement|
38
36
  list.code_append(statement.evaluate(**index_args))
@@ -135,6 +135,7 @@ class Code
135
135
  code_function.code_parameters,
136
136
  code_function.code_body.raw,
137
137
  code_function.definition_context,
138
+ code_function.definition_object,
138
139
  parent: self
139
140
  )
140
141
  end
@@ -42,33 +42,9 @@ class Code
42
42
  {}
43
43
  end
44
44
 
45
- class ScopedObject < Object
46
- def call(**args)
47
- code_operator = args.fetch(:operator, nil).to_code
48
- code_context = args.fetch(:context).to_code
49
-
50
- code_context = code_context.code_lookup!(code_operator)
51
- code_result = code_context.code_fetch(code_operator)
52
-
53
- if code_result.is_a?(Super) ||
54
- (
55
- code_result.is_a?(Function) &&
56
- args.fetch(:explicit_arguments, false)
57
- )
58
- code_result.call(**args, operator: nil)
59
- else
60
- sig(args)
61
- code_result
62
- end
63
- end
64
- end
65
-
66
- attr_reader :trusted
67
-
68
45
  def initialize(*args, **_kargs, &_block)
69
- @trusted = args.first.is_a?(Node::Code)
70
46
  self.raw =
71
- (trusted ? args.first : Node::Code.new(::Code.parse(args.first.to_s)))
47
+ (args.first.is_a?(Node::Code) ? args.first : Node::Code.new(::Code.parse(args.first.to_s)))
72
48
  end
73
49
 
74
50
  def self.code_evaluate(*args, **globals)
@@ -103,25 +79,13 @@ class Code
103
79
  end
104
80
  end
105
81
 
106
- def code_evaluate(trusted_evaluation: false, **globals)
107
- raw.evaluate(
108
- **evaluation_globals(globals, trusted_evaluation: trusted_evaluation)
109
- )
82
+ def code_evaluate(**globals)
83
+ raw.evaluate(**globals)
110
84
  end
111
85
 
112
- def code_deep_duplicate(_seen = {})
86
+ def code_deep_duplicate
113
87
  self.class.new(raw)
114
88
  end
115
-
116
- private
117
-
118
- def evaluation_globals(globals, trusted_evaluation:)
119
- return globals if trusted && trusted_evaluation
120
-
121
- object = ScopedObject.new
122
-
123
- globals.merge(context: Context.new, object: object, root_object: object)
124
- end
125
89
  end
126
90
  end
127
91
  end
@@ -67,20 +67,15 @@ class Code
67
67
  Context.new(raw.merge(other.raw), parent || other.parent)
68
68
  end
69
69
 
70
- def code_deep_duplicate(seen = {})
71
- seen.compare_by_identity unless seen.compare_by_identity?
72
- return seen[self] if seen.key?(self)
73
-
70
+ def code_deep_duplicate
74
71
  duplicate = Context.new
75
- seen[self] = duplicate
76
-
77
72
  raw.each do |key, value|
78
73
  duplicate.code_set(
79
- key.code_deep_duplicate(seen),
80
- value.code_deep_duplicate(seen)
74
+ key.code_deep_duplicate,
75
+ value.code_deep_duplicate
81
76
  )
82
77
  end
83
- duplicate.parent = parent&.code_deep_duplicate(seen)
78
+ duplicate.parent = parent
84
79
  duplicate
85
80
  end
86
81
 
@@ -2934,17 +2934,13 @@ class Code
2934
2934
  pair ? List.new(pair) : Nothing.new
2935
2935
  end
2936
2936
 
2937
- def code_deep_duplicate(seen = {})
2938
- seen.compare_by_identity unless seen.compare_by_identity?
2939
- return seen[self] if seen.key?(self)
2940
-
2937
+ def code_deep_duplicate
2941
2938
  duplicate = Dictionary.new
2942
- seen[self] = duplicate
2943
2939
 
2944
2940
  raw.each do |key, value|
2945
2941
  duplicate.code_set(
2946
- key.code_deep_duplicate(seen),
2947
- value.code_deep_duplicate(seen)
2942
+ key.code_deep_duplicate,
2943
+ value.code_deep_duplicate
2948
2944
  )
2949
2945
  end
2950
2946
 
@@ -24,6 +24,16 @@ class Code
24
24
  "((a, b = 2) => { a + b }).call(3)"
25
25
  ]
26
26
  },
27
+ "new" => {
28
+ name: "new",
29
+ description:
30
+ "evaluates the function body as a constructor with the provided arguments.",
31
+ examples: [
32
+ "Widget = () => { self.name = :widget return(self) } Widget.new.name",
33
+ "User = (name:) => { self.name = name return(self) } User.new(name: :ada).name",
34
+ "Counter = () => { self.count = 0 return(self) } Counter.new.count"
35
+ ]
36
+ },
27
37
  "extend" => {
28
38
  name: "extend",
29
39
  description:
@@ -84,6 +94,7 @@ class Code
84
94
  attr_reader :code_parameters,
85
95
  :code_body,
86
96
  :definition_context,
97
+ :definition_object,
87
98
  :instance_functions,
88
99
  :parent
89
100
 
@@ -97,6 +108,7 @@ class Code
97
108
 
98
109
  @code_body = Code.new(args.second.presence)
99
110
  @definition_context = args.third if args.third.is_a?(Context)
111
+ @definition_object = args.fourth if args.fourth.is_a?(Object)
100
112
  @parent = parent.to_code
101
113
  self.functions = functions.to_code
102
114
  self.functions = Dictionary.new if self.functions.nothing?
@@ -116,8 +128,11 @@ class Code
116
128
  code_arguments = args.fetch(:arguments, List.new).to_code
117
129
  code_value = code_arguments.code_first
118
130
  globals = multi_fetch(args, *GLOBALS)
131
+ operator_name = code_operator.to_s
132
+ operator_name = "" if operator_name == "new" &&
133
+ code_has_key?(code_operator).falsy?
119
134
 
120
- case code_operator.to_s
135
+ case operator_name
121
136
  when "", "call"
122
137
  sig(args) { signature_for_call }
123
138
  code_call(
@@ -171,6 +186,7 @@ class Code
171
186
  )
172
187
  code_arguments = arguments.to_code
173
188
  code_context = Context.new({}, definition_context || globals[:context])
189
+ evaluation_object = definition_object || globals.fetch(:previous_object)
174
190
  code_self = bound_self.to_code
175
191
  if (code_self.nil? || code_self.nothing?) && parent.is_a?(Class)
176
192
  code_self = parent.code_call(*arguments, **globals)
@@ -254,7 +270,8 @@ class Code
254
270
  code_default.code_evaluate(
255
271
  **globals,
256
272
  context: code_context,
257
- trusted_evaluation: true
273
+ object: evaluation_object,
274
+ previous_object: evaluation_object
258
275
  )
259
276
  else
260
277
  code_default
@@ -272,7 +289,8 @@ class Code
272
289
  **globals,
273
290
  constructing_literal_classes: constructing_literal_classes,
274
291
  context: code_context,
275
- trusted_evaluation: true
292
+ object: evaluation_object,
293
+ previous_object: evaluation_object
276
294
  )
277
295
  .tap { persist_instance_functions(code_self) }
278
296
  rescue Error::Return => e
@@ -340,6 +358,7 @@ class Code
340
358
  code_function.code_parameters,
341
359
  code_function.code_body.raw,
342
360
  code_function.definition_context,
361
+ code_function.definition_object,
343
362
  parent: self,
344
363
  functions: functions.code_deep_duplicate
345
364
  )
@@ -348,22 +367,19 @@ class Code
348
367
  end
349
368
  end
350
369
 
351
- def code_deep_duplicate(seen = {})
352
- seen.compare_by_identity unless seen.compare_by_identity?
353
- return seen[self] if seen.key?(self)
354
-
370
+ def code_deep_duplicate
355
371
  duplicate = Function.new
356
- seen[self] = duplicate
357
372
 
358
373
  duplicate.code_replace(
359
- code_parameters: code_parameters.code_deep_duplicate(seen),
360
- code_body: code_body.code_deep_duplicate(seen),
361
- definition_context: definition_context&.code_deep_duplicate(seen),
374
+ code_parameters: code_parameters.code_deep_duplicate,
375
+ code_body: code_body.code_deep_duplicate,
376
+ definition_context: definition_context&.code_deep_duplicate,
377
+ definition_object: definition_object,
362
378
  parent:
363
- parent.is_a?(Function) ? parent.code_deep_duplicate(seen) : parent,
364
- functions: functions.code_deep_duplicate(seen),
365
- instance_functions: instance_functions.code_deep_duplicate(seen),
366
- documentation: documentation.code_deep_duplicate(seen)
379
+ parent.is_a?(Function) ? parent.code_deep_duplicate : parent,
380
+ functions: functions.code_deep_duplicate,
381
+ instance_functions: instance_functions.code_deep_duplicate,
382
+ documentation: documentation.code_deep_duplicate
367
383
  )
368
384
  duplicate
369
385
  end
@@ -375,11 +391,13 @@ class Code
375
391
  parent:,
376
392
  functions:,
377
393
  instance_functions:,
378
- documentation:
394
+ documentation:,
395
+ definition_object: nil
379
396
  )
380
397
  @code_parameters = code_parameters
381
398
  @code_body = code_body
382
399
  @definition_context = definition_context
400
+ @definition_object = definition_object
383
401
  @parent = parent
384
402
  self.functions = functions
385
403
  @instance_functions = instance_functions
@@ -535,7 +535,7 @@ class Code
535
535
  end
536
536
  when "context"
537
537
  sig(args)
538
- code_context.code_deep_duplicate
538
+ code_context
539
539
  when "Object"
540
540
  sig(args)
541
541
  if code_arguments.any?
@@ -265,7 +265,6 @@ class Code
265
265
  args.first
266
266
  else
267
267
  source = args.first.to_s
268
- ::Code.ensure_input_size!(source, label: "html")
269
268
  Nokogiri.HTML(source)
270
269
  end
271
270
  end
@@ -385,10 +384,7 @@ class Code
385
384
  value_or_function.to_code
386
385
  end
387
386
 
388
- source = code_value.to_s
389
- ::Code.ensure_input_size!(source, label: "html")
390
-
391
- String.new(Nokogiri::HTML.fragment(source).text)
387
+ String.new(Nokogiri::HTML.fragment(code_value.to_s).text)
392
388
  rescue Error::Break => e
393
389
  e.code_value
394
390
  end
@@ -473,18 +469,14 @@ class Code
473
469
  if code_value.is_an?(Html)
474
470
  Html.new(fragment_from_html(code_value))
475
471
  else
476
- source = code_value.to_s
477
- ::Code.ensure_input_size!(source, label: "html")
478
- Html.new(Nokogiri::HTML::DocumentFragment.parse(source))
472
+ Html.new(Nokogiri::HTML::DocumentFragment.parse(code_value.to_s))
479
473
  end
480
474
  rescue Error::Break => e
481
475
  e.code_value
482
476
  end
483
477
 
484
478
  def self.fragment_from_html(html)
485
- source = html.to_html
486
- ::Code.ensure_input_size!(source, label: "html")
487
- Nokogiri::HTML::DocumentFragment.parse(source)
479
+ Nokogiri::HTML::DocumentFragment.parse(html.to_html)
488
480
  end
489
481
 
490
482
  def call(**args)
@@ -191,8 +191,6 @@ class Code
191
191
  network_authentication_required: 511
192
192
  }.freeze
193
193
  DEFAULT_TIMEOUT = 1.hour.to_f
194
- MAX_REQUEST_BYTES = ::Code::MAX_INPUT_BYTES
195
- MAX_RESPONSE_BYTES = ::Code::MAX_INPUT_BYTES
196
194
  MAX_HEADER_BYTES = 32.kilobytes
197
195
  HEADER_NAME = /\A[A-Za-z0-9!#$%&'*+\-.^_`|~]+\z/
198
196
  RESTRICTED_HEADERS = %w[
@@ -291,17 +289,9 @@ class Code
291
289
  write_timeout = options.code_get("write_timeout")
292
290
  query = options.code_get("query").raw || {}
293
291
  query = query.to_a.flatten.map(&:to_s).each_slice(2).to_h.to_query
294
- validate_payload_size!(username, label: "http username")
295
- validate_payload_size!(password, label: "http password")
296
- validate_payload_size!(query, label: "http query")
297
- validate_payload_size!(body, label: "http request body")
298
- if data.present?
299
- validate_payload_size!(data.as_json.to_query, label: "http form data")
300
- end
301
292
 
302
293
  url = original_url
303
294
  url = "#{url}?#{query}" if query.present?
304
- validate_payload_size!(url, label: "http url")
305
295
 
306
296
  if username.present? || password.present?
307
297
  authorization = ::Base64.strict_encode64("#{username}:#{password}")
@@ -356,10 +346,6 @@ class Code
356
346
  validate_response_headers!(http_response)
357
347
 
358
348
  http_response.read_body do |chunk|
359
- if response_body.bytesize + chunk.bytesize > MAX_RESPONSE_BYTES
360
- raise ::Code::Error, "http response is too large"
361
- end
362
-
363
349
  response_body << chunk
364
350
  end
365
351
  end
@@ -478,12 +464,6 @@ class Code
478
464
  raise ::Code::Error, "http response headers are too large"
479
465
  end
480
466
 
481
- def self.validate_payload_size!(value, label:)
482
- return if value.to_s.bytesize <= MAX_REQUEST_BYTES
483
-
484
- raise ::Code::Error, "#{label} is too large"
485
- end
486
-
487
467
  def self.http_timeout(value, default)
488
468
  ::Code.normalize_timeout!(value.nothing? ? default : value)
489
469
  end
@@ -44,8 +44,6 @@ class Code
44
44
  geo
45
45
  ].freeze
46
46
  MISSING_ATTRIBUTE = Object.new.freeze
47
- MAX_EVENTS = 10_000
48
- MAX_NESTING = 50
49
47
 
50
48
  def self.call(**args)
51
49
  code_operator = args.fetch(:operator, nil).to_code
@@ -63,10 +61,8 @@ class Code
63
61
 
64
62
  def self.code_parse(value)
65
63
  source = value.to_code.raw
66
- ::Code.ensure_input_size!(source, label: "ics")
67
64
  calendars = ::Icalendar::Calendar.parse(source)
68
65
  events = calendars.flat_map(&:events)
69
- raise Error, "ics has too many events" if events.size > MAX_EVENTS
70
66
 
71
67
  events.map { |event| serialize_event(event) }.to_code
72
68
  rescue ::Code::Error
@@ -128,9 +124,7 @@ class Code
128
124
  MISSING_ATTRIBUTE
129
125
  end
130
126
 
131
- def self.serialize_value(value, depth: 0)
132
- raise Error, "ics is too deeply nested" if depth > MAX_NESTING
133
-
127
+ def self.serialize_value(value)
134
128
  case value
135
129
  when nil
136
130
  nil
@@ -139,17 +133,15 @@ class Code
139
133
  when ::Symbol, ::Integer, ::Float, ::BigDecimal, true, false
140
134
  value
141
135
  when ::Array
142
- value.map { |item| serialize_value(item, depth: depth + 1) }
136
+ value.map { |item| serialize_value(item) }
143
137
  when ::Hash
144
- value.transform_values do |item|
145
- serialize_value(item, depth: depth + 1)
146
- end
138
+ value.transform_values { |item| serialize_value(item) }
147
139
  else
148
140
  serialized_date = serialize_date_like(value)
149
141
  return serialized_date unless serialized_date.nil?
150
142
 
151
143
  if value.is_a?(::Icalendar::Value)
152
- serialize_value(value.value, depth: depth + 1)
144
+ serialize_value(value.value)
153
145
  else
154
146
  normalize_string(value.to_s)
155
147
  end
@@ -41,9 +41,6 @@ class Code
41
41
  {}
42
42
  end
43
43
 
44
- MAX_NESTING = 100
45
- MAX_ITEMS = 10_000
46
-
47
44
  def self.call(**args)
48
45
  code_operator = args.fetch(:operator, nil).to_code
49
46
  code_arguments = args.fetch(:arguments, []).to_code
@@ -71,10 +68,8 @@ class Code
71
68
 
72
69
  def self.code_parse(value)
73
70
  code_value = value.to_code
74
- ::Code.ensure_input_size!(code_value.raw, label: "json")
75
71
 
76
72
  parsed = ::JSON.parse(code_value.raw)
77
- validate_shape!(parsed)
78
73
  parsed.to_code
79
74
  rescue JSON::ParserError
80
75
  Nothing.new
@@ -83,26 +78,6 @@ class Code
83
78
  def self.code_generate(value, pretty: nil)
84
79
  value.to_code.code_to_json(pretty: pretty)
85
80
  end
86
-
87
- def self.validate_shape!(value, depth: 0, count: 0)
88
- raise Error, "json is too deeply nested" if depth > MAX_NESTING
89
- raise Error, "json has too many items" if count > MAX_ITEMS
90
-
91
- case value
92
- when ::Array
93
- count += value.size
94
- value.each do |item|
95
- count = validate_shape!(item, depth: depth + 1, count: count)
96
- end
97
- when ::Hash
98
- count += value.size
99
- value.each_value do |item|
100
- count = validate_shape!(item, depth: depth + 1, count: count)
101
- end
102
- end
103
-
104
- count
105
- end
106
81
  end
107
82
  end
108
83
  end
@@ -5060,14 +5060,10 @@ class Code
5060
5060
  raw.inject(&:code_plus) || Nothing.new
5061
5061
  end
5062
5062
 
5063
- def code_deep_duplicate(seen = {})
5064
- seen.compare_by_identity unless seen.compare_by_identity?
5065
- return seen[self] if seen.key?(self)
5066
-
5063
+ def code_deep_duplicate
5067
5064
  duplicate = List.new
5068
- seen[self] = duplicate
5069
5065
  duplicate.raw.concat(
5070
- raw.map { |value| value.code_deep_duplicate(seen) }
5066
+ raw.map { |value| value.code_deep_duplicate }
5071
5067
  )
5072
5068
  duplicate
5073
5069
  end
@@ -104,9 +104,6 @@ class Code
104
104
 
105
105
  resolved_ip = validate_delivery_target!(address, port)
106
106
 
107
- encoded_message = mail.encoded
108
- ::Code.ensure_input_size!(encoded_message, label: "smtp message")
109
-
110
107
  deliver_mail(
111
108
  mail,
112
109
  address: address,
@@ -965,7 +965,9 @@ class Code
965
965
  }
966
966
  }
967
967
  ]
968
- )
968
+ ),
969
+ nil,
970
+ Global.new
969
971
  )
970
972
  end
971
973
 
data/lib/code/parser.rb CHANGED
@@ -73,7 +73,6 @@ class Code
73
73
  SUFFIX_PUNCTUATION = %w[! ?].freeze
74
74
 
75
75
  ASSIGNMENT_RHS_MIN_BP = 20
76
- MAX_NESTING = 200
77
76
  INFIX_PRECEDENCE = {
78
77
  "if" => [10, 9],
79
78
  "unless" => [10, 9],
@@ -129,7 +128,6 @@ class Code
129
128
 
130
129
  def initialize(input)
131
130
  @input = input.to_s
132
- ensure_source_nesting_limit!(@input)
133
131
  @tokens = lex(@input)
134
132
  @index = 0
135
133
  end
@@ -976,67 +974,6 @@ class Code
976
974
  raise Error, "#{message} at #{token.position}"
977
975
  end
978
976
 
979
- def ensure_source_nesting_limit!(source)
980
- depth = 0
981
- quote = nil
982
- escaped = false
983
- index = 0
984
-
985
- while index < source.length
986
- char = source[index]
987
- if quote
988
- if escaped
989
- escaped = false
990
- elsif char == "\\"
991
- escaped = true
992
- elsif char == quote
993
- quote = nil
994
- end
995
- index += 1
996
- next
997
- end
998
-
999
- if %w[' "].include?(char)
1000
- quote = char
1001
- elsif char == "#"
1002
- index += 1
1003
- index += 1 while index < source.length &&
1004
- !NEWLINE_CHARACTERS.include?(source[index])
1005
- next
1006
- elsif source[index, 2] == "//"
1007
- index += 2
1008
- index += 1 while index < source.length &&
1009
- !NEWLINE_CHARACTERS.include?(source[index])
1010
- next
1011
- elsif source[index, 2] == "/*"
1012
- index += 2
1013
- index += 1 while index < source.length && source[index, 2] != "*/"
1014
- index += 2 if source[index, 2] == "*/"
1015
- next
1016
- elsif "([{".include?(char)
1017
- depth += 1
1018
- if depth > MAX_NESTING
1019
- raise_parse_error_at("source is too deeply nested", index)
1020
- end
1021
- elsif ")]}".include?(char)
1022
- depth -= 1 if depth.positive?
1023
- end
1024
- index += 1
1025
- end
1026
- end
1027
-
1028
- def raise_parse_error_at(message, position)
1029
- token =
1030
- Token.new(
1031
- type: :unknown,
1032
- value: "",
1033
- position: position,
1034
- newline_before: false,
1035
- space_before: false
1036
- )
1037
- raise_parse_error(message, token)
1038
- end
1039
-
1040
977
  def lex(source)
1041
978
  tokens = []
1042
979
  index = 0
data/lib/code.rb CHANGED
@@ -1,9 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Code
4
- GLOBALS = %i[context error input object output root_object source].freeze
4
+ GLOBALS = %i[context error input object output previous_object source].freeze
5
5
  DEFAULT_TIMEOUT = 1.hour.to_f
6
- MAX_INPUT_BYTES = 10.megabytes
7
6
  LOCALES = %w[en fr].freeze
8
7
 
9
8
  def initialize(
@@ -27,7 +26,6 @@ class Code
27
26
  def self.parse(source, timeout: DEFAULT_TIMEOUT)
28
27
  timeout = normalize_timeout!(timeout)
29
28
 
30
- ensure_input_size!(source, label: "source")
31
29
  Timeout.timeout(timeout) { Parser.parse(source).to_raw }
32
30
  rescue Timeout::Error
33
31
  raise Error, "timeout"
@@ -50,16 +48,10 @@ class Code
50
48
  Format.format(parse_tree)
51
49
  end
52
50
 
53
- def self.ensure_input_size!(source, limit: MAX_INPUT_BYTES, label: "input")
54
- return if source.to_s.bytesize <= limit
55
-
56
- raise Error, "#{label} is too large"
57
- end
58
-
59
51
  def self.normalize_timeout!(timeout)
60
52
  timeout = DEFAULT_TIMEOUT if timeout.nil?
61
53
  timeout = timeout.to_f
62
- raise Error, "timeout must be positive" unless timeout.positive?
54
+ raise Error, "timeout must be non-negative" unless timeout >= 0
63
55
 
64
56
  timeout
65
57
  end
@@ -75,7 +67,7 @@ class Code
75
67
  input: input,
76
68
  object: object,
77
69
  output: output,
78
- root_object: object,
70
+ previous_object: object,
79
71
  source: source,
80
72
  timeout: timeout
81
73
  )
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: code-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.0.1
4
+ version: 4.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dorian Marié
@@ -249,26 +249,6 @@ dependencies:
249
249
  - - "<"
250
250
  - !ruby/object:Gem::Version
251
251
  version: '2'
252
- - !ruby/object:Gem::Dependency
253
- name: ruby-prof
254
- requirement: !ruby/object:Gem::Requirement
255
- requirements:
256
- - - ">="
257
- - !ruby/object:Gem::Version
258
- version: '2.0'
259
- - - "<"
260
- - !ruby/object:Gem::Version
261
- version: '3'
262
- type: :runtime
263
- prerelease: false
264
- version_requirements: !ruby/object:Gem::Requirement
265
- requirements:
266
- - - ">="
267
- - !ruby/object:Gem::Version
268
- version: '2.0'
269
- - - "<"
270
- - !ruby/object:Gem::Version
271
- version: '3'
272
252
  - !ruby/object:Gem::Dependency
273
253
  name: uri
274
254
  requirement: !ruby/object:Gem::Requirement
@@ -309,7 +289,7 @@ dependencies:
309
289
  - - "<"
310
290
  - !ruby/object:Gem::Version
311
291
  version: '3'
312
- description: a programming language for the internet
292
+ description: a compact, embeddable scripting language for the internet
313
293
  email: dorian@dorianmarie.com
314
294
  executables:
315
295
  - code
@@ -420,7 +400,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
420
400
  requirements:
421
401
  - - ">="
422
402
  - !ruby/object:Gem::Version
423
- version: '3.4'
403
+ version: '3.0'
424
404
  required_rubygems_version: !ruby/object:Gem::Requirement
425
405
  requirements:
426
406
  - - ">="