Created
April 22, 2019 21:01
-
-
Save jesseadams/4cb0351761b6a77db76a22adc2312a75 to your computer and use it in GitHub Desktop.
Psych monkey patch
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Psych's first step is to parse the Yaml into an AST of Node objects | |
# so we open the Node class and add a way to track the line. | |
class Psych::Nodes::Node | |
attr_accessor :line | |
end | |
# We need to provide a handler that will add the line to the node | |
# as it is parsed. TreeBuilder is the "usual" handler, that | |
# creates the AST. | |
class LineNumberHandler < Psych::TreeBuilder | |
# The handler needs access to the parser in order to call mark | |
attr_accessor :parser | |
# We are only interested in scalars, so here we override | |
# the method so that it calls mark and adds the line info | |
# to the node. | |
def scalar value, anchor, tag, plain, quoted, style | |
mark = parser.mark | |
s = super | |
s.line = mark.line | |
s | |
end | |
end | |
# The next step is to convert the AST to a Ruby object. | |
# Psych does this using the visitor pattern with the ToRuby | |
# visitor. Here we patch ToRuby rather than inherit from it | |
# as it makes the last step a little easier. | |
class Psych::Visitors::ToRuby | |
def revive_hash hash, o | |
o.children.each_slice(2) { |k,v| | |
key = accept(k) | |
val = accept(v) | |
# This is the important bit. If the value is a scalar, | |
# we replace it with the desired hash. | |
if v.is_a? ::Psych::Nodes::Scalar | |
val = { "value" => val, "line" => v.start_line + 1} # line is 0 based, so + 1 | |
end | |
hash[key] = val | |
} | |
hash | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment