psych 3.0.3.pre1 → 3.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.
@@ -3,7 +3,7 @@
3
3
  #endif
4
4
 
5
5
  #if HAVE_CONFIG_H
6
- #include <config.h>
6
+ #include "config.h"
7
7
  #endif
8
8
 
9
9
  #include <yaml.h>
@@ -12,16 +12,6 @@
12
12
  #include <limits.h>
13
13
  #include <stddef.h>
14
14
 
15
- #ifndef _MSC_VER
16
- #include <stdint.h>
17
- #else
18
- #ifdef _WIN64
19
- #define PTRDIFF_MAX _I64_MAX
20
- #else
21
- #define PTRDIFF_MAX INT_MAX
22
- #endif
23
- #endif
24
-
25
15
  /*
26
16
  * Memory management.
27
17
  */
@@ -80,6 +70,17 @@ yaml_parser_fetch_more_tokens(yaml_parser_t *parser);
80
70
 
81
71
  #define OUTPUT_RAW_BUFFER_SIZE (OUTPUT_BUFFER_SIZE*2+2)
82
72
 
73
+ /*
74
+ * The maximum size of a YAML input file.
75
+ * This used to be PTRDIFF_MAX, but that's not entirely portable
76
+ * because stdint.h isn't available on all platforms.
77
+ * It is not entirely clear why this isn't the maximum value
78
+ * that can fit into the parser->offset field.
79
+ */
80
+
81
+ #define MAX_FILE_SIZE (~(size_t)0 / 2)
82
+
83
+
83
84
  /*
84
85
  * The size of other stacks and queues.
85
86
  */
@@ -93,7 +94,7 @@ yaml_parser_fetch_more_tokens(yaml_parser_t *parser);
93
94
  */
94
95
 
95
96
  #define BUFFER_INIT(context,buffer,size) \
96
- (((buffer).start = yaml_malloc(size)) ? \
97
+ (((buffer).start = (yaml_char_t *)yaml_malloc(size)) ? \
97
98
  ((buffer).last = (buffer).pointer = (buffer).start, \
98
99
  (buffer).end = (buffer).start+(size), \
99
100
  1) : \
@@ -133,7 +134,7 @@ yaml_string_join(
133
134
  (value).pointer = (string))
134
135
 
135
136
  #define STRING_INIT(context,string,size) \
136
- (((string).start = yaml_malloc(size)) ? \
137
+ (((string).start = YAML_MALLOC(size)) ? \
137
138
  ((string).pointer = (string).start, \
138
139
  (string).end = (string).start+(size), \
139
140
  memset((string).start, 0, (size)), \
@@ -174,14 +175,14 @@ yaml_string_join(
174
175
  * Check the octet at the specified position.
175
176
  */
176
177
 
177
- #define CHECK_AT(string,octet,offset) \
178
+ #define CHECK_AT(string,octet,offset) \
178
179
  ((string).pointer[offset] == (yaml_char_t)(octet))
179
180
 
180
181
  /*
181
182
  * Check the current octet in the buffer.
182
183
  */
183
184
 
184
- #define CHECK(string,octet) CHECK_AT((string),(octet),0)
185
+ #define CHECK(string,octet) (CHECK_AT((string),(octet),0))
185
186
 
186
187
  /*
187
188
  * Check if the character at the specified position is an alphabetical
@@ -423,10 +424,10 @@ yaml_stack_extend(void **start, void **top, void **end);
423
424
  YAML_DECLARE(int)
424
425
  yaml_queue_extend(void **start, void **head, void **tail, void **end);
425
426
 
426
- #define STACK_INIT(context,stack,size) \
427
- (((stack).start = yaml_malloc((size)*sizeof(*(stack).start))) ? \
427
+ #define STACK_INIT(context,stack,type) \
428
+ (((stack).start = (type)yaml_malloc(INITIAL_STACK_SIZE*sizeof(*(stack).start))) ? \
428
429
  ((stack).top = (stack).start, \
429
- (stack).end = (stack).start+(size), \
430
+ (stack).end = (stack).start+INITIAL_STACK_SIZE, \
430
431
  1) : \
431
432
  ((context)->error = YAML_MEMORY_ERROR, \
432
433
  0))
@@ -456,8 +457,8 @@ yaml_queue_extend(void **start, void **head, void **tail, void **end);
456
457
  #define POP(context,stack) \
457
458
  (*(--(stack).top))
458
459
 
459
- #define QUEUE_INIT(context,queue,size) \
460
- (((queue).start = yaml_malloc((size)*sizeof(*(queue).start))) ? \
460
+ #define QUEUE_INIT(context,queue,size,type) \
461
+ (((queue).start = (type)yaml_malloc((size)*sizeof(*(queue).start))) ? \
461
462
  ((queue).head = (queue).tail = (queue).start, \
462
463
  (queue).end = (queue).start+(size), \
463
464
  1) : \
@@ -660,3 +661,28 @@ yaml_queue_extend(void **start, void **head, void **tail, void **end);
660
661
  (node).data.mapping.pairs.end = (node_pairs_end), \
661
662
  (node).data.mapping.pairs.top = (node_pairs_start), \
662
663
  (node).data.mapping.style = (node_style))
664
+
665
+ /* Strict C compiler warning helpers */
666
+
667
+ #if defined(__clang__) || defined(__GNUC__)
668
+ # define HASATTRIBUTE_UNUSED
669
+ #endif
670
+ #ifdef HASATTRIBUTE_UNUSED
671
+ # define __attribute__unused__ __attribute__((__unused__))
672
+ #else
673
+ # define __attribute__unused__
674
+ #endif
675
+
676
+ /* Shim arguments are arguments that must be included in your function,
677
+ * but serve no purpose inside. Silence compiler warnings. */
678
+ #define SHIM(a) /*@unused@*/ a __attribute__unused__
679
+
680
+ /* UNUSED_PARAM() marks a shim argument in the body to silence compiler warnings */
681
+ #ifdef __clang__
682
+ # define UNUSED_PARAM(a) (void)(a);
683
+ #else
684
+ # define UNUSED_PARAM(a) /*@-noeffect*/if (0) (void)(a)/*@=noeffect*/;
685
+ #endif
686
+
687
+ #define YAML_MALLOC_STATIC(type) (type*)yaml_malloc(sizeof(type))
688
+ #define YAML_MALLOC(size) (yaml_char_t *)yaml_malloc(size)
@@ -3,13 +3,14 @@ require 'psych/versions'
3
3
  case RUBY_ENGINE
4
4
  when 'jruby'
5
5
  require 'psych_jars'
6
- org.jruby.ext.psych.PsychLibrary.new.load(JRuby.runtime, false)
7
- else
8
- begin
9
- require "#{RUBY_VERSION[/\d+\.\d+/]}/psych.so"
10
- rescue LoadError
11
- require 'psych.so'
6
+ if JRuby::Util.respond_to?(:load_ext)
7
+ JRuby::Util.load_ext('org.jruby.ext.psych.PsychLibrary')
8
+ else
9
+ require 'java'; require 'jruby'
10
+ org.jruby.ext.psych.PsychLibrary.new.load(JRuby.runtime, false)
12
11
  end
12
+ else
13
+ require 'psych.so'
13
14
  end
14
15
  require 'psych/nodes'
15
16
  require 'psych/streaming'
@@ -31,7 +32,7 @@ require 'psych/class_loader'
31
32
  # = Overview
32
33
  #
33
34
  # Psych is a YAML parser and emitter.
34
- # Psych leverages libyaml [Home page: http://pyyaml.org/wiki/LibYAML]
35
+ # Psych leverages libyaml [Home page: https://pyyaml.org/wiki/LibYAML]
35
36
  # or [HG repo: https://bitbucket.org/xi/libyaml] for its YAML parsing
36
37
  # and emitting capabilities. In addition to wrapping libyaml, Psych also
37
38
  # knows how to serialize and de-serialize most Ruby objects to and from
@@ -230,14 +231,16 @@ require 'psych/class_loader'
230
231
  module Psych
231
232
  # The version of libyaml Psych is using
232
233
  LIBYAML_VERSION = Psych.libyaml_version.join '.'
233
-
234
- FALLBACK = Struct.new :to_ruby # :nodoc:
234
+ # Deprecation guard
235
+ NOT_GIVEN = Object.new
236
+ private_constant :NOT_GIVEN
235
237
 
236
238
  ###
237
239
  # Load +yaml+ in to a Ruby data structure. If multiple documents are
238
240
  # provided, the object contained in the first document will be returned.
239
- # +filename+ will be used in the exception message if any exception is raised
240
- # while parsing.
241
+ # +filename+ will be used in the exception message if any exception
242
+ # is raised while parsing. If +yaml+ is empty, it returns
243
+ # the specified +fallback+ return value, which defaults to +false+.
241
244
  #
242
245
  # Raises a Psych::SyntaxError when a YAML syntax error is detected.
243
246
  #
@@ -247,7 +250,7 @@ module Psych
247
250
  # Psych.load("---\n - a\n - b") # => ['a', 'b']
248
251
  #
249
252
  # begin
250
- # Psych.load("--- `", "file.txt")
253
+ # Psych.load("--- `", filename: "file.txt")
251
254
  # rescue Psych::SyntaxError => ex
252
255
  # ex.file # => 'file.txt'
253
256
  # ex.message # => "(file.txt): found character that cannot start any token"
@@ -259,10 +262,21 @@ module Psych
259
262
  # Psych.load("---\n foo: bar") # => {"foo"=>"bar"}
260
263
  # Psych.load("---\n foo: bar", symbolize_names: true) # => {:foo=>"bar"}
261
264
  #
262
- def self.load yaml, filename = nil, fallback: false, symbolize_names: false
263
- result = parse(yaml, filename, fallback: fallback)
264
- result = result.to_ruby if result
265
- symbolize_names!(result) if symbolize_names
265
+ # Raises a TypeError when `yaml` parameter is NilClass
266
+ #
267
+ # NOTE: This method *should not* be used to parse untrusted documents, such as
268
+ # YAML documents that are supplied via user input. Instead, please use the
269
+ # safe_load method.
270
+ #
271
+ def self.load yaml, legacy_filename = NOT_GIVEN, filename: nil, fallback: false, symbolize_names: false, freeze: false
272
+ if legacy_filename != NOT_GIVEN
273
+ warn_with_uplevel 'Passing filename with the 2nd argument of Psych.load is deprecated. Use keyword argument like Psych.load(yaml, filename: ...) instead.', uplevel: 1 if $VERBOSE
274
+ filename = legacy_filename
275
+ end
276
+
277
+ result = parse(yaml, filename: filename)
278
+ return fallback unless result
279
+ result = result.to_ruby(symbolize_names: symbolize_names, freeze: freeze) if result
266
280
  result
267
281
  end
268
282
 
@@ -279,27 +293,27 @@ module Psych
279
293
  # * Hash
280
294
  #
281
295
  # Recursive data structures are not allowed by default. Arbitrary classes
282
- # can be allowed by adding those classes to the +whitelist+. They are
296
+ # can be allowed by adding those classes to the +permitted_classes+ keyword argument. They are
283
297
  # additive. For example, to allow Date deserialization:
284
298
  #
285
- # Psych.safe_load(yaml, [Date])
299
+ # Psych.safe_load(yaml, permitted_classes: [Date])
286
300
  #
287
301
  # Now the Date class can be loaded in addition to the classes listed above.
288
302
  #
289
- # Aliases can be explicitly allowed by changing the +aliases+ parameter.
303
+ # Aliases can be explicitly allowed by changing the +aliases+ keyword argument.
290
304
  # For example:
291
305
  #
292
306
  # x = []
293
307
  # x << x
294
308
  # yaml = Psych.dump x
295
309
  # Psych.safe_load yaml # => raises an exception
296
- # Psych.safe_load yaml, [], [], true # => loads the aliases
310
+ # Psych.safe_load yaml, aliases: true # => loads the aliases
297
311
  #
298
312
  # A Psych::DisallowedClass exception will be raised if the yaml contains a
299
- # class that isn't in the whitelist.
313
+ # class that isn't in the +permitted_classes+ list.
300
314
  #
301
315
  # A Psych::BadAlias exception will be raised if the yaml contains aliases
302
- # but the +aliases+ parameter is set to false.
316
+ # but the +aliases+ keyword argument is set to false.
303
317
  #
304
318
  # +filename+ will be used in the exception message if any exception is raised
305
319
  # while parsing.
@@ -310,20 +324,39 @@ module Psych
310
324
  # Psych.safe_load("---\n foo: bar") # => {"foo"=>"bar"}
311
325
  # Psych.safe_load("---\n foo: bar", symbolize_names: true) # => {:foo=>"bar"}
312
326
  #
313
- def self.safe_load yaml, whitelist_classes = [], whitelist_symbols = [], aliases = false, filename = nil, symbolize_names: false
314
- result = parse(yaml, filename)
315
- return unless result
327
+ def self.safe_load yaml, legacy_permitted_classes = NOT_GIVEN, legacy_permitted_symbols = NOT_GIVEN, legacy_aliases = NOT_GIVEN, legacy_filename = NOT_GIVEN, permitted_classes: [], permitted_symbols: [], aliases: false, filename: nil, fallback: nil, symbolize_names: false, freeze: false
328
+ if legacy_permitted_classes != NOT_GIVEN
329
+ warn_with_uplevel 'Passing permitted_classes with the 2nd argument of Psych.safe_load is deprecated. Use keyword argument like Psych.safe_load(yaml, permitted_classes: ...) instead.', uplevel: 1 if $VERBOSE
330
+ permitted_classes = legacy_permitted_classes
331
+ end
316
332
 
317
- class_loader = ClassLoader::Restricted.new(whitelist_classes.map(&:to_s),
318
- whitelist_symbols.map(&:to_s))
319
- scanner = ScalarScanner.new class_loader
320
- if aliases
321
- visitor = Visitors::ToRuby.new scanner, class_loader
322
- else
323
- visitor = Visitors::NoAliasRuby.new scanner, class_loader
333
+ if legacy_permitted_symbols != NOT_GIVEN
334
+ warn_with_uplevel 'Passing permitted_symbols with the 3rd argument of Psych.safe_load is deprecated. Use keyword argument like Psych.safe_load(yaml, permitted_symbols: ...) instead.', uplevel: 1 if $VERBOSE
335
+ permitted_symbols = legacy_permitted_symbols
324
336
  end
337
+
338
+ if legacy_aliases != NOT_GIVEN
339
+ warn_with_uplevel 'Passing aliases with the 4th argument of Psych.safe_load is deprecated. Use keyword argument like Psych.safe_load(yaml, aliases: ...) instead.', uplevel: 1 if $VERBOSE
340
+ aliases = legacy_aliases
341
+ end
342
+
343
+ if legacy_filename != NOT_GIVEN
344
+ warn_with_uplevel 'Passing filename with the 5th argument of Psych.safe_load is deprecated. Use keyword argument like Psych.safe_load(yaml, filename: ...) instead.', uplevel: 1 if $VERBOSE
345
+ filename = legacy_filename
346
+ end
347
+
348
+ result = parse(yaml, filename: filename)
349
+ return fallback unless result
350
+
351
+ class_loader = ClassLoader::Restricted.new(permitted_classes.map(&:to_s),
352
+ permitted_symbols.map(&:to_s))
353
+ scanner = ScalarScanner.new class_loader
354
+ visitor = if aliases
355
+ Visitors::ToRuby.new scanner, class_loader, symbolize_names: symbolize_names, freeze: freeze
356
+ else
357
+ Visitors::NoAliasRuby.new scanner, class_loader, symbolize_names: symbolize_names, freeze: freeze
358
+ end
325
359
  result = visitor.accept result
326
- symbolize_names!(result) if symbolize_names
327
360
  result
328
361
  end
329
362
 
@@ -339,28 +372,40 @@ module Psych
339
372
  # Psych.parse("---\n - a\n - b") # => #<Psych::Nodes::Document:0x00>
340
373
  #
341
374
  # begin
342
- # Psych.parse("--- `", "file.txt")
375
+ # Psych.parse("--- `", filename: "file.txt")
343
376
  # rescue Psych::SyntaxError => ex
344
377
  # ex.file # => 'file.txt'
345
378
  # ex.message # => "(file.txt): found character that cannot start any token"
346
379
  # end
347
380
  #
348
381
  # See Psych::Nodes for more information about YAML AST.
349
- def self.parse yaml, filename = nil, fallback: false
350
- parse_stream(yaml, filename) do |node|
382
+ def self.parse yaml, legacy_filename = NOT_GIVEN, filename: nil, fallback: NOT_GIVEN
383
+ if legacy_filename != NOT_GIVEN
384
+ warn_with_uplevel 'Passing filename with the 2nd argument of Psych.parse is deprecated. Use keyword argument like Psych.parse(yaml, filename: ...) instead.', uplevel: 1 if $VERBOSE
385
+ filename = legacy_filename
386
+ end
387
+
388
+ parse_stream(yaml, filename: filename) do |node|
351
389
  return node
352
390
  end
353
- fallback
391
+
392
+ if fallback != NOT_GIVEN
393
+ warn_with_uplevel 'Passing the `fallback` keyword argument of Psych.parse is deprecated.', uplevel: 1 if $VERBOSE
394
+ fallback
395
+ else
396
+ false
397
+ end
354
398
  end
355
399
 
356
400
  ###
357
401
  # Parse a file at +filename+. Returns the Psych::Nodes::Document.
358
402
  #
359
403
  # Raises a Psych::SyntaxError when a YAML syntax error is detected.
360
- def self.parse_file filename
361
- File.open filename, 'r:bom|utf-8' do |f|
362
- parse f, filename
404
+ def self.parse_file filename, fallback: false
405
+ result = File.open filename, 'r:bom|utf-8' do |f|
406
+ parse f, filename: filename
363
407
  end
408
+ result || fallback
364
409
  end
365
410
 
366
411
  ###
@@ -389,14 +434,21 @@ module Psych
389
434
  # end
390
435
  #
391
436
  # begin
392
- # Psych.parse_stream("--- `", "file.txt")
437
+ # Psych.parse_stream("--- `", filename: "file.txt")
393
438
  # rescue Psych::SyntaxError => ex
394
439
  # ex.file # => 'file.txt'
395
440
  # ex.message # => "(file.txt): found character that cannot start any token"
396
441
  # end
397
442
  #
443
+ # Raises a TypeError when NilClass is passed.
444
+ #
398
445
  # See Psych::Nodes for more information about YAML AST.
399
- def self.parse_stream yaml, filename = nil, &block
446
+ def self.parse_stream yaml, legacy_filename = NOT_GIVEN, filename: nil, &block
447
+ if legacy_filename != NOT_GIVEN
448
+ warn_with_uplevel 'Passing filename with the 2nd argument of Psych.parse_stream is deprecated. Use keyword argument like Psych.parse_stream(yaml, filename: ...) instead.', uplevel: 1 if $VERBOSE
449
+ filename = legacy_filename
450
+ end
451
+
400
452
  if block_given?
401
453
  parser = Psych::Parser.new(Handlers::DocumentStream.new(&block))
402
454
  parser.parse yaml, filename
@@ -497,14 +549,22 @@ module Psych
497
549
  # end
498
550
  # list # => ['foo', 'bar']
499
551
  #
500
- def self.load_stream yaml, filename = nil
501
- if block_given?
502
- parse_stream(yaml, filename) do |node|
503
- yield node.to_ruby
504
- end
505
- else
506
- parse_stream(yaml, filename).children.map { |child| child.to_ruby }
552
+ def self.load_stream yaml, legacy_filename = NOT_GIVEN, filename: nil, fallback: []
553
+ if legacy_filename != NOT_GIVEN
554
+ warn_with_uplevel 'Passing filename with the 2nd argument of Psych.load_stream is deprecated. Use keyword argument like Psych.load_stream(yaml, filename: ...) instead.', uplevel: 1 if $VERBOSE
555
+ filename = legacy_filename
507
556
  end
557
+
558
+ result = if block_given?
559
+ parse_stream(yaml, filename: filename) do |node|
560
+ yield node.to_ruby
561
+ end
562
+ else
563
+ parse_stream(yaml, filename: filename).children.map(&:to_ruby)
564
+ end
565
+
566
+ return fallback if result.is_a?(Array) && result.empty?
567
+ result
508
568
  end
509
569
 
510
570
  ###
@@ -513,7 +573,7 @@ module Psych
513
573
  # the specified +fallback+ return value, which defaults to +false+.
514
574
  def self.load_file filename, fallback: false
515
575
  File.open(filename, 'r:bom|utf-8') { |f|
516
- self.load f, filename, fallback: FALLBACK.new(fallback)
576
+ self.load f, filename: filename, fallback: fallback
517
577
  }
518
578
  end
519
579
 
@@ -542,18 +602,20 @@ module Psych
542
602
  @dump_tags[klass] = tag
543
603
  end
544
604
 
545
- def self.symbolize_names!(result)
546
- case result
547
- when Hash
548
- result.keys.each do |key|
549
- result[key.to_sym] = symbolize_names!(result.delete(key))
550
- end
551
- when Array
552
- result.map! { |r| symbolize_names!(r) }
605
+ # Workaround for emulating `warn '...', uplevel: 1` in Ruby 2.4 or lower.
606
+ def self.warn_with_uplevel(message, uplevel: 1)
607
+ at = parse_caller(caller[uplevel]).join(':')
608
+ warn "#{at}: #{message}"
609
+ end
610
+
611
+ def self.parse_caller(at)
612
+ if /^(.+?):(\d+)(?::in `.*')?/ =~ at
613
+ file = $1
614
+ line = $2.to_i
615
+ [file, line]
553
616
  end
554
- result
555
617
  end
556
- private_class_method :symbolize_names!
618
+ private_class_method :warn_with_uplevel, :parse_caller
557
619
 
558
620
  class << self
559
621
  attr_accessor :load_tags
@@ -105,7 +105,7 @@ module Psych
105
105
  # - first element
106
106
  # - *ponies
107
107
  #
108
- # &ponies is the achor, *ponies is the alias. In this case, alias is
108
+ # &ponies is the anchor, *ponies is the alias. In this case, alias is
109
109
  # called with "ponies".
110
110
  def alias anchor
111
111
  end
@@ -46,8 +46,8 @@ module Psych
46
46
  # Convert this node to Ruby.
47
47
  #
48
48
  # See also Psych::Visitors::ToRuby
49
- def to_ruby
50
- Visitors::ToRuby.create.accept(self)
49
+ def to_ruby(symbolize_names: false, freeze: false)
50
+ Visitors::ToRuby.create(symbolize_names: symbolize_names, freeze: freeze).accept(self)
51
51
  end
52
52
  alias :transform :to_ruby
53
53