-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
/
to_yaml.cr
167 lines (147 loc) · 3.42 KB
/
to_yaml.cr
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
class Object
def to_yaml
String.build do |io|
to_yaml(io)
end
end
def to_yaml(io : IO)
# First convert the object to an in-memory tree.
# With this, `to_yaml` will be invoked just once
# on every object and we can use anchors and aliases
# for objects that are serialized multiple times.
nodes_builder = YAML::Nodes::Builder.new
to_yaml(nodes_builder)
# Then we convert the tree to YAML.
YAML.build(io) do |builder|
nodes_builder.document.to_yaml(builder)
end
end
end
class Hash
def to_yaml(yaml : YAML::Nodes::Builder)
yaml.mapping(reference: self) do
each do |key, value|
key.to_yaml(yaml)
value.to_yaml(yaml)
end
end
end
end
class Array
def to_yaml(yaml : YAML::Nodes::Builder)
yaml.sequence(reference: self) do
each &.to_yaml(yaml)
end
end
end
struct Tuple
def to_yaml(yaml : YAML::Nodes::Builder)
yaml.sequence do
each &.to_yaml(yaml)
end
end
end
struct NamedTuple
def to_yaml(yaml : YAML::Nodes::Builder)
yaml.mapping do
{% for key in T.keys %}
{{key.symbolize}}.to_yaml(yaml)
self[{{key.symbolize}}].to_yaml(yaml)
{% end %}
end
end
end
class String
def to_yaml(yaml : YAML::Nodes::Builder)
if YAML::Schema::Core.reserved_string?(self)
yaml.scalar self, style: YAML::ScalarStyle::DOUBLE_QUOTED
else
yaml.scalar self
end
end
end
struct Number
def to_yaml(yaml : YAML::Nodes::Builder)
yaml.scalar self.to_s
end
end
struct Nil
def to_yaml(yaml : YAML::Nodes::Builder)
yaml.scalar ""
end
end
struct Bool
def to_yaml(yaml : YAML::Nodes::Builder)
yaml.scalar self
end
end
struct Set
def to_yaml(yaml : YAML::Nodes::Builder)
yaml.sequence do
each &.to_yaml(yaml)
end
end
end
struct Symbol
def to_yaml(yaml : YAML::Nodes::Builder)
yaml.scalar self
end
end
struct Enum
def to_yaml(yaml : YAML::Nodes::Builder)
yaml.scalar value
end
end
struct Time
def to_yaml(yaml : YAML::Nodes::Builder)
yaml.scalar Time::Format::YAML_DATE.format(self)
end
end
struct Time::Format
def to_yaml(value : Time, yaml : YAML::Nodes::Builder)
yaml.scalar format(value)
end
end
module Time::EpochConverter
def self.to_yaml(value : Time, yaml : YAML::Nodes::Builder)
yaml.scalar value.to_unix
end
end
module Time::EpochMillisConverter
def self.to_yaml(value : Time, yaml : YAML::Nodes::Builder)
yaml.scalar value.to_unix_ms
end
end
# Converter to be used with `YAML.mapping`
# to serialize the `Array(T)` elements with the custom converter.
#
# ```
# require "yaml"
#
# class Timestamp
# YAML.mapping({
# values: {type: Array(Time), converter: YAML::ArrayConverter(Time::EpochConverter)},
# })
# end
#
# timestamp = Timestamp.from_yaml(%({"values":[1459859781,1567628762]}))
# timestamp.values # => [2016-04-05 12:36:21 UTC, 2019-09-04 20:26:02 UTC]
# timestamp.to_yaml # => ---\nvalues:\n- 1459859781\n- 1567628762\n
# ```
module YAML::ArrayConverter(Converter)
def self.to_yaml(values : Array, yaml : YAML::Nodes::Builder)
yaml.sequence(reference: self) do
values.each do |value|
Converter.to_yaml(value, yaml)
end
end
end
end
struct Slice
def to_yaml(yaml : YAML::Nodes::Builder)
{% if T != UInt8 %}
{% raise "Can only serialize Slice(UInt8), not #{@type}}" %}
{% end %}
yaml.scalar Base64.encode(self), tag: "tag:yaml.org,2002:binary"
end
end