psych 3.0.3.pre1 → 3.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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