Created
May 28, 2018 10:22
-
-
Save fgimian/7ac343880045b8d303bf8b260d09cf59 to your computer and use it in GitHub Desktop.
The following Crystal code attempts to implement custom YAML tag processing
This file contains hidden or 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
require "yaml" | |
# The default representation of null values in Crystal is an empty value which while valid | |
# (see http://yaml.org/type/null.html) but is less familiar and clear to me, use the string | |
# "null" instead | |
struct Nil | |
def to_yaml(yaml : YAML::Nodes::Builder) | |
yaml.scalar "null" | |
end | |
end | |
class FotsiesYAMLParser < YAML::Schema::Core::Parser | |
protected def parse_join | |
# TODO: what does anchor actually do? is it needed? e.g. anchor new_mapping | |
data = parse_sequence | |
# TODO: how do we add a value to the sequence and return that | |
# Error: undefined method '<<' for Bool (compile-time type is (Array(YAML::Any) | Bool | Float64 | Hash(YAML::Any, YAML::Any) | Int64 | Set(YAML::Any) | Slice(UInt8) | String | Time | Nil)) | |
# value = data.raw | |
# value << YAML::Any.new("string") | |
# Scalars | |
value = "my string" | |
# value = 123.to_i64 # Integers must be 64-bit | |
# value = true | |
# value = 1234.46 | |
# value = nil | |
# Arrays | |
# value = [] of YAML::Any | |
# value << YAML::Any.new("string") | |
# value << YAML::Any.new(123.to_i64) | |
# value << YAML::Any.new(123) | |
# value << YAML::Any.new(true) | |
# value << YAML::Any.new(123.5) | |
# value << YAML::Any.new(nil) | |
# Mappings | |
# value = {} of YAML::Any => YAML::Any | |
# value[YAML::Any.new("hi1")] = YAML::Any.new("string") | |
# value[YAML::Any.new("hi2")] = YAML::Any.new(123.to_i64) | |
# value[YAML::Any.new("hi3")] = YAML::Any.new(123) | |
# value[YAML::Any.new("hi4")] = YAML::Any.new(true) | |
# value[YAML::Any.new("hi5")] = YAML::Any.new(123.5) | |
# value[YAML::Any.new("hi6")] = YAML::Any.new(nil) | |
YAML::Any.new value | |
end | |
protected def parse_manipulate | |
data = parse_mapping | |
value = data.raw | |
YAML::Any.new value | |
end | |
protected def parse_upper | |
data = parse_scalar | |
YAML::Any.new(data.to_s.upcase) | |
end | |
private def process_fots_tag(pull_parser, tag) | |
# Checking the type of data beneath the tag | |
# puts "scalar: #{pull_parser.kind.scalar?}" | |
# puts "alias: #{pull_parser.kind.alias?}" | |
# puts "sequence_start: #{pull_parser.kind.sequence_start?}" | |
# puts "mapping_start: #{pull_parser.kind.mapping_start?}" | |
case tag | |
when "!join" # sequence | |
parse_join | |
when "!manipulate" # mapping | |
parse_manipulate | |
when "!upper" # scalar | |
parse_upper | |
else | |
nil | |
end | |
end | |
def process_tag(tag) | |
# TODO: how do we call the parent method here | |
# super | |
if value = process_fots_tag(@pull_parser, tag) | |
yield value | |
end | |
end | |
end | |
data = <<-END | |
--- | |
types: [1, 1.2, abc, true, null] | |
joining: !join [a, b, c, d] | |
thingo: !manipulate | |
name: fots | |
age: 30 | |
wow: !upper make me uppercase | |
END | |
data = FotsiesYAMLParser.new(data).parse | |
puts data.to_yaml |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment