Module: Psychgus

Extended by:
PsychDropIn
Includes:
Stylables, Stylers
Defined in:
lib/psychgus.rb,
lib/psychgus/ext.rb,
lib/psychgus/styler.rb,
lib/psychgus/stylers.rb,
lib/psychgus/version.rb,
lib/psychgus/blueberry.rb,
lib/psychgus/stylables.rb,
lib/psychgus/ext/core_ext.rb,
lib/psychgus/ext/node_ext.rb,
lib/psychgus/super_sniffer.rb,
lib/psychgus/ext/yaml_tree_ext.rb,
lib/psychgus/styled_tree_builder.rb,
lib/psychgus/super_sniffer/parent.rb,
lib/psychgus/styled_document_stream.rb

Overview

Psychgus uses the core standard library Psych for working with YAML and extends it so that developers can easily style the YAML according to their needs. Thank you to the people that worked and continue to work hard on that project.

The name comes from the well-styled character Gus from the TV show Psych.

Create a Styler

First, we will create a Styler.

All you need to do is add include Psychgus::Styler to a class.

Here is a complex Styler for the examples below:

require 'psychgus'

class BurgerStyler  # Mix in methods needed for styling

  include Psychgus::Styler

  def initialize(sniffer=nil)
    if sniffer.nil?()
      @class_level = 0
      @class_position = 0
    else
      # For the Class Example
      @class_level = sniffer.level
      @class_position = sniffer.position
    end
  end

  # Style all nodes (Psych::Nodes::Node)
  def style(sniffer,node)
    # Remove "!ruby/object:..." for classes
    node.tag = nil if node.node_of?(:mapping,:scalar,:sequence)

    # This is another way to do the above
    #node.tag = nil if node.respond_to?(:tag=)
  end

  # Style aliases (Psych::Nodes::Alias)
  def style_alias(sniffer,node)
  end

  # Style maps (Psych::Nodes::Mapping)
  # - Hashes (key/value pairs)
  # - Example: "Burgers: Classic {}"
  def style_mapping(sniffer,node)
    parent = sniffer.parent

    if !parent.nil?()      # BBQ

      node.style = Psychgus::MAPPING_FLOW if parent.node_of?(:scalar) &&
                                             parent.value.casecmp('BBQ') == 0
    end
  end

  # Style scalars (Psych::Nodes::Scalar)
  # - Any text (non-alias)
  def style_scalar(sniffer,node)
    parent = sniffer.parent

    # Single quote scalars that are not keys to a map
    # - "child_key?" is the same as "child_type == :key"
    node.style = Psychgus::SCALAR_SINGLE_QUOTED unless parent.child_key?()

    # Remove colon (change symbols into strings)
    node.value = node.value.sub(':','')

    # Change lettuce to spinach
    node.value = 'Spinach' if node.value.casecmp('Lettuce') == 0

    # Capitalize each word
    node.value = node.value.split(' ').map do |v|
      if v.casecmp('BBQ') == 0
        v.upcase()
      else
        v.capitalize()
      end
    end.join(' ')
  end

  # Style sequences (Psych::Nodes::Sequence)
  # - Arrays
  # - Example: "[Lettuce, Onions, Pickles, Tomatoes]"
  def style_sequence(sniffer,node)
    relative_level = (sniffer.level - @class_level) + 1

    node.style = Psychgus::SEQUENCE_FLOW if sniffer.level >= 4

    # Make "[Ketchup, Mustard]" a block for the Class Example
    node.style = Psychgus::SEQUENCE_BLOCK if relative_level == 7
  end
end

Examples:

Hash example

require 'psychgus'

burgers = {
  :Burgers => {
    :Classic => {
      :Sauce  => %w(Ketchup Mustard),
      :Cheese => 'American',
      :Bun    => 'Sesame Seed'
    },
    :BBQ => {
      :Sauce  => 'Honey BBQ',
      :Cheese => 'Cheddar',
      :Bun    => 'Kaiser'
    },
    :Fancy => {
      :Sauce  => 'Spicy Wasabi',
      :Cheese => 'Smoked Gouda',
      :Bun    => 'Hawaiian'
    }
  },
  :Toppings => [
    'Mushrooms',
    %w(Lettuce Onions Pickles Tomatoes),
    [%w(Ketchup Mustard), %w(Salt Pepper)]
  ]
}
burgers[:Favorite] = burgers[:Burgers][:BBQ] # Alias

puts burgers.to_yaml(indent: 3,stylers: BurgerStyler.new,deref_aliases: true)

# Output:
# ---
# Burgers:
#    Classic:
#       Sauce: ['Ketchup', 'Mustard']
#       Cheese: 'American'
#       Bun: 'Sesame Seed'
#    BBQ: {Sauce: 'Honey BBQ', Cheese: 'Cheddar', Bun: 'Kaiser'}
#    Fancy:
#       Sauce: 'Spicy Wasabi'
#       Cheese: 'Smoked Gouda'
#       Bun: 'Hawaiian'
# Toppings:
# - 'Mushrooms'
# - ['Spinach', 'Onions', 'Pickles', 'Tomatoes']
# - [['Ketchup', 'Mustard'], ['Salt', 'Pepper']]
# Favorite:
#    Sauce: 'Honey BBQ'
#    Cheese: 'Cheddar'
#    Bun: 'Kaiser'

Class example

require 'psychgus'

class Burger
  attr_accessor :bun
  attr_accessor :cheese
  attr_accessor :sauce

  def initialize(sauce,cheese,bun)
    @bun = bun
    @cheese = cheese
    @sauce = sauce
  end

  # You can still use Psych's encode_with(), no problem
  #def encode_with(coder)
  #  coder['Bun'] = @bun
  #  coder['Cheese'] = @cheese
  #  coder['Sauce'] = @sauce
  #end
end

class Burgers
  include Psychgus::Blueberry

  attr_accessor :burgers
  attr_accessor :toppings
  attr_accessor :favorite

  def initialize()
    @burgers = {
      'Classic' => Burger.new(['Ketchup','Mustard'],'American','Sesame Seed'),
      'BBQ'     => Burger.new('Honey BBQ','Cheddar','Kaiser'),
      'Fancy'   => Burger.new('Spicy Wasabi','Smoked Gouda','Hawaiian')
    }

    @toppings = [
      'Mushrooms',
      %w(Lettuce Onions Pickles Tomatoes),
      [%w(Ketchup Mustard),%w(Salt Pepper)]
    ]

    @favorite = @burgers['BBQ'] # Alias
  end

  def psychgus_stylers(sniffer)
    return BurgerStyler.new(sniffer)
  end

  # You can still use Psych's encode_with(), no problem
  #def encode_with(coder)
  #  coder['Burgers'] = @burgers
  #  coder['Toppings'] = @toppings
  #  coder['Favorite'] = @favorite
  #end
end

burgers = Burgers.new
puts burgers.to_yaml(indent: 3,deref_aliases: true)

# Output:
# ---
# Burgers:
#    Classic:
#       Bun: 'Sesame Seed'
#       Cheese: 'American'
#       Sauce:
#       - 'Ketchup'
#       - 'Mustard'
#    BBQ: {Bun: 'Kaiser', Cheese: 'Cheddar', Sauce: 'Honey BBQ'}
#    Fancy:
#       Bun: 'Hawaiian'
#       Cheese: 'Smoked Gouda'
#       Sauce: 'Spicy Wasabi'
# Toppings:
# - 'Mushrooms'
# - ['Spinach', 'Onions', 'Pickles', 'Tomatoes']
# - [['Ketchup', 'Mustard'], ['Salt', 'Pepper']]
# Favorite:
#    Bun: 'Kaiser'
#    Cheese: 'Cheddar'
#    Sauce: 'Honey BBQ'

Emitting / Parsing examples

styler = BurgerStyler.new()
options = {:indentation=>3,:stylers=>styler,:deref_aliases=>true}
yaml = burgers.to_yaml(options)

# High-level emitting
Psychgus.dump(burgers,options)
Psychgus.dump_file('burgers.yaml',burgers,options)
burgers.to_yaml(options)

# High-level parsing
# - Because to_ruby() will be called, just use Psych:
#   - load(), load_file(), load_stream(), safe_load()

# Mid-level emitting
stream = Psychgus.parse_stream(yaml,stylers: styler,deref_aliases: true)

stream.to_yaml()

# Mid-level parsing
Psychgus.parse(yaml,stylers: styler,deref_aliases: true)
Psychgus.parse_file('burgers.yaml',stylers: styler,deref_aliases: true)
Psychgus.parse_stream(yaml,stylers: styler,deref_aliases: true)

# Low-level emitting
tree_builder = Psychgus::StyledTreeBuilder.new(styler,deref_aliases: true)
visitor = Psych::Visitors::YAMLTree.create(options,tree_builder)

visitor << burgers
visitor.tree.to_yaml

# Low-level parsing
parser = Psychgus.parser(stylers: styler,deref_aliases: true)

parser.parse(yaml)
parser.handler
parser.handler.root

Author:

  • Jonathan Bradley Whited (@esotericpig)

Since:

  • 1.0.0

Defined Under Namespace

Modules: Blueberry, Ext, PsychDropIn, Stylables, Styler, Stylers Classes: StyledDocumentStream, StyledTreeBuilder, SuperSniffer

Constant Summary collapse

NODE_CLASS_ALIASES =

Since:

  • 1.0.0

{:Doc => :Document,:Map => :Mapping,:Seq => :Sequence}
OPTIONS_ALIASES =

Since:

  • 1.0.0

{:canon => :canonical,:indent => :indentation}
MAPPING_ANY =

Since:

  • 1.0.0

node_const(:mapping,:any)
MAPPING_BLOCK =

Since:

  • 1.0.0

node_const(:mapping,:block)
MAPPING_FLOW =

Since:

  • 1.0.0

node_const(:mapping,:flow)
MAP_ANY =

Since:

  • 1.0.0

MAPPING_ANY
MAP_BLOCK =

Since:

  • 1.0.0

MAPPING_BLOCK
MAP_FLOW =

Since:

  • 1.0.0

MAPPING_FLOW
SCALAR_ANY =

Since:

  • 1.0.0

node_const(:scalar,:any)
SCALAR_PLAIN =

Since:

  • 1.0.0

node_const(:scalar,:plain)
SCALAR_SINGLE_QUOTED =

Since:

  • 1.0.0

node_const(:scalar,:single_quoted)
SCALAR_DOUBLE_QUOTED =

Since:

  • 1.0.0

node_const(:scalar,:double_quoted)
SCALAR_LITERAL =

Since:

  • 1.0.0

node_const(:scalar,:literal)
SCALAR_FOLDED =

Since:

  • 1.0.0

node_const(:scalar,:folded)
SEQUENCE_ANY =

Since:

  • 1.0.0

node_const(:sequence,:any)
SEQUENCE_BLOCK =

Since:

  • 1.0.0

node_const(:sequence,:block)
SEQUENCE_FLOW =

Since:

  • 1.0.0

node_const(:sequence,:flow)
SEQ_ANY =

Since:

  • 1.0.0

SEQUENCE_ANY
SEQ_BLOCK =

Since:

  • 1.0.0

SEQUENCE_BLOCK
SEQ_FLOW =

Since:

  • 1.0.0

SEQUENCE_FLOW
STREAM_ANY =

Since:

  • 1.0.0

node_const(:stream,:any)
STREAM_UTF8 =

Since:

  • 1.0.0

node_const(:stream,:utf8)
STREAM_UTF16LE =

Since:

  • 1.0.0

node_const(:stream,:utf16le)
STREAM_UTF16BE =

Since:

  • 1.0.0

node_const(:stream,:utf16be)
VERSION =

Version of this gem in “#.#.#” format

Since:

  • 1.0.0

'1.3.2'

Class Method Summary collapse

Methods included from PsychDropIn

add_builtin_type, add_domain_type, add_tag, load, load_file, load_stream, remove_type, safe_load, to_json

Class Method Details

.dump(object, io = nil, **options) ⇒ String, Object

Convert object to YAML and dump to io.

object, io, and options are used like in Psych.dump so can be a drop-in replacement for Psych.

Parameters:

  • object (Object)

    the Object to convert to YAML and dump

  • io (nil, IO, Hash) (defaults to: nil)

    the IO to dump the YAML to or the options Hash; if nil, will use StringIO

  • options (Hash)

    the options (or keyword args) to use; see dump_stream

Returns:

  • (String, Object)

    the result of converting object to YAML using the params

See Also:

Since:

  • 1.0.0



397
398
399
# File 'lib/psychgus.rb', line 397

def self.dump(object,io=nil,**options)
  return dump_stream(object,io: io,**options)
end

.dump_file(filename, *objects, mode: 'w', perm: nil, opt: nil, **options) ⇒ Object

Convert objects to YAML and dump to a file.

Examples:

Psychgus.dump_file('my_dir/my_file.yaml',my_object1,my_object2,mode: 'w:UTF-16',
                   stylers: MyStyler.new())
Psychgus.dump_file('my_file.yaml',my_object,stylers: [MyStyler1.new(),MyStyler2.new()])

Parameters:

  • filename (String)

    the name of the file (and path) to dump to

  • objects (Object, Array<Object>)

    the Object(s) to convert to YAML and dump

  • mode (String, Integer) (defaults to: 'w')

    the IO open mode to use; examples:

    'w:UTF-8'

    create a new file or truncate an existing file and use UTF-8 encoding;

    'a:UTF-16'

    create a new file or append to an existing file and use UTF-16 encoding

  • perm (Integer) (defaults to: nil)

    the permission bits to use (platform dependent)

  • opt (Hash) (defaults to: nil)

    Hash of keyword args to pass to File.open()

  • options (Hash)

    the options (or keyword args) to use; see dump_stream

See Also:

Since:

  • 1.0.0



423
424
425
426
427
428
429
# File 'lib/psychgus.rb', line 423

def self.dump_file(filename,*objects,mode: 'w',perm: nil,opt: nil,**options)
  opt = Hash(opt)
  
  File.open(filename,mode,perm,**opt) do |file|
    file.write(dump_stream(*objects,**options))
  end
end

.dump_stream(*objects, io: nil, stylers: nil, deref_aliases: false, **options) ⇒ String, Object

Convert objects to YAML and dump to io.

io and options are used like in Psych.dump so can be a drop-in replacement for Psych.

Parameters:

  • objects (Object, Array<Object>)

    the Object(s) to convert to YAML and dump

  • io (nil, IO, Hash) (defaults to: nil)

    the IO to dump the YAML to or the options Hash; if nil, will use StringIO

  • stylers (nil, Styler, Array<Styler>) (defaults to: nil)

    the Styler(s) to use when converting to YAML

  • deref_aliases (true, false) (defaults to: false)

    whether to dereference aliases; output the actual value instead of the alias

  • options (Hash)

    the options (or keyword args) to use when converting to YAML:

    :indent

    Alias for :indentation. :indentation will override this.

    :indentation

    Default: 2. Number of space characters used to indent. Acceptable value should be in 0..9 range, else ignored.

    :line_width

    Default: 0 (meaning “wrap at 81”). Max character to wrap line at.

    :canon

    Alias for :canonical. :canonical will override this.

    :canonical

    Default: false. Write “canonical” YAML form (very verbose, yet strictly formal).

    :header

    Default: false. Write %YAML [version] at the beginning of document.

Returns:

  • (String, Object)

    the result of converting object to YAML using the params

See Also:

Since:

  • 1.0.0



457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
# File 'lib/psychgus.rb', line 457

def self.dump_stream(*objects,io: nil,stylers: nil,deref_aliases: false,**options)
  # If you call this method with only a Hash that uses symbols as keys,
  # then options will be set to the Hash, instead of objects.
  # 
  # For example, the below will be stored in options, not objects:
  # - dump_stream({:coffee => {:roast => [],:style => []}})
  # 
  # This if-statement is guaranteed because dump_stream([]) and dump_stream(nil)
  # will produce [[]] and [nil], which are not empty.
  # 
  # dump_stream() w/o any args is the only problem, but resolved w/ [nil].
  if objects.empty?()
    objects = options.empty?() ? [nil] : [options]
    options = {}
  end
  
  if Hash === io
    options = io
    io = nil
  end
  
  if !options.empty?()
    OPTIONS_ALIASES.each do |option_alias,actual_option|
      if options.key?(option_alias) && !options.key?(actual_option)
        options[actual_option] = options[option_alias]
      end
    end
  end
  
  visitor = Psych::Visitors::YAMLTree.create(options,StyledTreeBuilder.new(*stylers,
    deref_aliases: deref_aliases))
  
  if objects.empty?()    # Else, will throw a cryptic NoMethodError:
    # - "psych/tree_builder.rb:in `set_end_location': undefined method `end_line=' for nil:NilClass (NoMethodError)"
    # 
    # This should never occur because of the if-statement at the top of this method.

    visitor << nil
  else
    objects.each do |object|
      visitor << object
    end
  end
  
  return visitor.tree.yaml(io,options)
end

.hierarchy(*objects, **kargs) ⇒ String

Get a visual hierarchy of the levels as a String.

This is useful for determining the correct level/position when writing a Styler.

Examples:

require 'psychgus'

burgers = {
  :burgers => {
    :classic => {:sauce  => %w(Ketchup Mustard),
                 :cheese => 'American',
                 :bun    => 'Sesame Seed'},
    :bbq     => {:sauce  => 'Honey BBQ',
                 :cheese => 'Cheddar',
                 :bun    => 'Kaiser'},
    :fancy   => {:sauce  => 'Spicy Wasabi',
                 :cheese => 'Smoked Gouda',
                 :bun    => 'Hawaiian'}
  },
  :toppings => [
    'Mushrooms',
    %w(Lettuce Onions Pickles Tomatoes),
    [%w(Ketchup Mustard), %w(Salt Pepper)]
  ]
}

puts Psychgus.hierarchy(burgers)

# Output:
# ---
# (level:position):current_node - <parent:(parent_level:parent_position)>
# ---
# (1:1):Psych::Nodes::Stream - <root:(0:0)>
# (1:1):Psych::Nodes::Document - <stream:(1:1)>
# (1:1):Psych::Nodes::Mapping - <doc:(1:1)>
#  (2:1)::burgers - <map:(1:1)>
#   (3:1):Psych::Nodes::Mapping - <:burgers:(2:1)>
#    (4:1)::classic - <map:(3:1)>
#     (5:1):Psych::Nodes::Mapping - <:classic:(4:1)>
#      (6:1)::sauce - <map:(5:1)>
#       (7:1):Psych::Nodes::Sequence - <:sauce:(6:1)>
#        (8:1):Ketchup - <seq:(7:1)>
#        (8:2):Mustard - <seq:(7:1)>
#      (6:2)::cheese - <map:(5:1)>
#       (7:1):American - <:cheese:(6:2)>
#      (6:3)::bun - <map:(5:1)>
#       (7:1):Sesame Seed - <:bun:(6:3)>
#    (4:2)::bbq - <map:(3:1)>
#     (5:1):Psych::Nodes::Mapping - <:bbq:(4:2)>
#      (6:1)::sauce - <map:(5:1)>
#       (7:1):Honey BBQ - <:sauce:(6:1)>
#      (6:2)::cheese - <map:(5:1)>
#       (7:1):Cheddar - <:cheese:(6:2)>
#      (6:3)::bun - <map:(5:1)>
#       (7:1):Kaiser - <:bun:(6:3)>
#    (4:3)::fancy - <map:(3:1)>
#     (5:1):Psych::Nodes::Mapping - <:fancy:(4:3)>
#      (6:1)::sauce - <map:(5:1)>
#       (7:1):Spicy Wasabi - <:sauce:(6:1)>
#      (6:2)::cheese - <map:(5:1)>
#       (7:1):Smoked Gouda - <:cheese:(6:2)>
#      (6:3)::bun - <map:(5:1)>
#       (7:1):Hawaiian - <:bun:(6:3)>
#  (2:2)::toppings - <map:(1:1)>
#   (3:1):Psych::Nodes::Sequence - <:toppings:(2:2)>
#    (4:1):Mushrooms - <seq:(3:1)>
#    (4:2):Psych::Nodes::Sequence - <seq:(3:1)>
#     (5:1):Lettuce - <seq:(4:2)>
#     (5:2):Onions - <seq:(4:2)>
#     (5:3):Pickles - <seq:(4:2)>
#     (5:4):Tomatoes - <seq:(4:2)>
#    (4:3):Psych::Nodes::Sequence - <seq:(3:1)>
#     (5:1):Psych::Nodes::Sequence - <seq:(4:3)>
#      (6:1):Ketchup - <seq:(5:1)>
#      (6:2):Mustard - <seq:(5:1)>
#     (5:2):Psych::Nodes::Sequence - <seq:(4:3)>
#      (6:1):Salt - <seq:(5:2)>
#      (6:2):Pepper - <seq:(5:2)>

Parameters:

Returns:

  • (String)

    the visual hierarchy of levels

See Also:

Since:

  • 1.2.0



592
593
594
595
596
597
598
# File 'lib/psychgus.rb', line 592

def self.hierarchy(*objects,**kargs)
  styler = Stylers::HierarchyStyler.new(**kargs)
  
  dump_stream(*objects,stylers: styler,**kargs)
  
  return styler.to_s()
end

.node_class(name) ⇒ Class

Get a Class (constant) from Psych::Nodes.

Some names have aliases:

:doc => :document
:map => :mapping
:seq => :sequence

Parameters:

  • name (Symbol, String)

    the name of the class from Psych::Nodes

Returns:

  • (Class)

    a class from Psych::Nodes

See Also:

Since:

  • 1.0.0



333
334
335
336
337
338
339
340
# File 'lib/psychgus.rb', line 333

def self.node_class(name)
  name = name.to_sym().capitalize()
  
  actual_name = NODE_CLASS_ALIASES[name]
  name = actual_name unless actual_name.nil?()
  
  return Psych::Nodes.const_get(name)
end

.node_const(class_name, const_name, lenient = true) ⇒ Integer, Object

Get a constant from a Psych::Nodes class (using node_class).

Parameters:

  • class_name (Symbol, String)

    the name of the class to get using node_class

  • const_name (Symbol, String)

    the constant to get from the class

  • lenient (true, false) (defaults to: true)

    if true, will return 0 if not const_defined?(), else raise an error

Returns:

  • (Integer, Object)

    the constant value from the class (usually an int)

See Also:

Since:

  • 1.0.0



351
352
353
354
355
356
357
# File 'lib/psychgus.rb', line 351

def self.node_const(class_name,const_name,lenient=true)
  node_class = node_class(class_name)
  const_name = const_name.to_sym().upcase()
  
  return 0 if lenient && !node_class.const_defined?(const_name,true)
  return node_class.const_get(const_name,true)
end

.parse(yaml, **kargs) ⇒ Psych::Nodes::Document

Parse yaml into a Psych::Nodes::Document.

If you're just going to call to_ruby(), then using this method is unnecessary, and the styler(s) will do nothing for you.

Parameters:

  • yaml (String)

    the YAML to parse

  • kargs (Hash)

    the keyword args to use; see parse_stream

Returns:

  • (Psych::Nodes::Document)

    the parsed Document node

See Also:

Since:

  • 1.0.0



613
614
615
616
617
618
619
# File 'lib/psychgus.rb', line 613

def self.parse(yaml,**kargs)
  parse_stream(yaml,**kargs) do |node|
    return node
  end
  
  return false
end

.parse_file(filename, fallback: false, mode: 'r:BOM|UTF-8', opt: nil, **kargs) ⇒ Psych::Nodes::Document

Parse a YAML file into a Psych::Nodes::Document.

If you're just going to call to_ruby(), then using this method is unnecessary, and the styler(s) will do nothing for you.

Parameters:

  • filename (String)

    the name of the YAML file (and path) to parse

  • fallback (Object) (defaults to: false)

    the return value when nothing is parsed

  • mode (String, Integer) (defaults to: 'r:BOM|UTF-8')

    the IO open mode to use; example: 'r:BOM|UTF-8'

  • opt (Hash) (defaults to: nil)

    Hash of keyword args to pass to File.open()

  • kargs (Hash)

    the keyword args to use; see parse_stream

Returns:

  • (Psych::Nodes::Document)

    the parsed Document node

See Also:

  • parse_stream
  • Psych.parse_file
  • Psych::Nodes::Document
  • File.open
  • IO.new

Since:

  • 1.0.0



639
640
641
642
643
644
645
646
647
# File 'lib/psychgus.rb', line 639

def self.parse_file(filename,fallback: false,mode: 'r:BOM|UTF-8',opt: nil,**kargs)
  opt = Hash(opt)
  
  result = File.open(filename,mode,**opt) do |file|
    parse(file,filename: filename,**kargs)
  end
  
  return result || fallback
end

.parse_stream(yaml, filename: nil, stylers: nil, deref_aliases: false, **options, &block) ⇒ Psych::Nodes::Stream

Parse yaml into a Psych::Nodes::Stream for one document or for multiple documents in one YAML.

If you're just going to call to_ruby(), then using this method is unnecessary, and the styler(s) will do nothing for you.

Examples:

burgers = <<EOY
---
Burgers:
  Classic:
    BBQ: {Sauce: Honey BBQ, Cheese: Cheddar, Bun: Kaiser}
---
Toppings:
- [Mushrooms, Mustard]
- [Salt, Pepper, Pickles]
---
`Invalid`
EOY

i = 0

begin
  Psychgus.parse_stream(burgers,filename: 'burgers.yaml') do |document|
    puts "Document ##{i += 1}"
    puts document.to_ruby
  end
rescue Psych::SyntaxError => err
  puts "File: #{err.file}"
end

# Output:
#   Document #1
#   {"Burgers"=>{"Classic"=>{"BBQ"=>{"Sauce"=>"Honey BBQ", "Cheese"=>"Cheddar", "Bun"=>"Kaiser"}}}}
#   Document #2
#   {"Toppings"=>[["Mushrooms", "Mustard"], ["Salt", "Pepper", "Pickles"]]}
#   File: burgers.yaml

Parameters:

  • yaml (String)

    the YAML to parse

  • filename (String) (defaults to: nil)

    the filename to pass as file to the Error potentially raised

  • stylers (nil, Styler, Array<Styler>) (defaults to: nil)

    the Styler(s) to use when parsing the YAML

  • deref_aliases (true, false) (defaults to: false)

    whether to dereference aliases; output the actual value instead of the alias

  • block (Proc)

    an optional block for parsing multiple documents

Returns:

  • (Psych::Nodes::Stream)

    the parsed Stream node

See Also:

Since:

  • 1.0.0



699
700
701
702
703
704
705
706
707
708
709
710
711
# File 'lib/psychgus.rb', line 699

def self.parse_stream(yaml,filename: nil,stylers: nil,deref_aliases: false,**options,&block)
  if block_given?()
    parser = Psych::Parser.new(StyledDocumentStream.new(*stylers,deref_aliases: deref_aliases,**options,
      &block))
    
    return parser.parse(yaml,filename)
  else
    parser = self.parser(stylers: stylers,deref_aliases: deref_aliases,**options)
    parser.parse(yaml,filename)
    
    return parser.handler.root
  end
end

.parser(stylers: nil, deref_aliases: false, **options) ⇒ Psych::Parser

Create a new styled Psych::Parser for parsing YAML.

Examples:

class CoffeeStyler
  include Psychgus::Styler

  def style_sequence(sniffer,node)
    node.style = Psychgus::SEQUENCE_FLOW
  end
end

coffee = <<EOY
Coffee:
  Roast:
    - Light
    - Medium
    - Dark
  Style:
    - Cappuccino
    - Latte
    - Mocha
EOY

parser = Psychgus.parser(stylers: CoffeeStyler.new)
parser.parse(coffee)
puts parser.handler.root.to_yaml

# Output:
#   Coffee:
#     Roast: [Light, Medium, Dark]
#     Style: [Cappuccino, Latte, Mocha]

Parameters:

  • stylers (nil, Styler, Array<Styler>) (defaults to: nil)

    the Styler(s) to use when parsing the YAML

  • deref_aliases (true, false) (defaults to: false)

    whether to dereference aliases; output the actual value instead of the alias

Returns:

  • (Psych::Parser)

    the new styled Parser

See Also:

Since:

  • 1.0.0



753
754
755
# File 'lib/psychgus.rb', line 753

def self.parser(stylers: nil,deref_aliases: false,**options)
  return Psych::Parser.new(StyledTreeBuilder.new(*stylers,deref_aliases: deref_aliases,**options))
end