1
1
defmodule Toml.Document do
2
2
@ moduledoc false
3
-
3
+
4
4
# Represents a TOML document, and handles conversion to a plain map
5
5
# See `Toml.Builder` for the actual logic for constructing the document.
6
6
7
7
defstruct [ :keys , :comments , :open_table , :comment_stack , :keyfun , :transforms ]
8
-
8
+
9
9
# A key is either binary or atom depending on the decoder option value
10
10
@ type key :: binary | atom | term
11
-
11
+
12
12
# A value is the fully decoded value from the TOML
13
- @ type value :: % { key => value }
14
- | { :table_array , [ % { key => value } ] }
15
- | number
16
- | binary
17
- | NaiveDateTime . t
18
- | DateTime . t
19
- | Date . t
20
- | Time . t
21
- | [ value ]
22
-
13
+ @ type value ::
14
+ % { key => value }
15
+ | { :table_array , [ % { key => value } ] }
16
+ | number
17
+ | binary
18
+ | NaiveDateTime . t ( )
19
+ | DateTime . t ( )
20
+ | Date . t ( )
21
+ | Time . t ( )
22
+ | [ value ]
23
+
23
24
# A keypath is a list of keys, they are all of the same key type
24
25
@ type keypath :: list ( binary ) | list ( atom ) | list ( term )
25
-
26
+
26
27
@ type t :: % __MODULE__ {
27
- keys: % { key => value } ,
28
- comments: % { keypath => binary } ,
29
- open_table: keypath | nil ,
30
- comment_stack: [ binary ] ,
31
- keyfun: nil | ( ( binary ) -> term | no_return ) ,
32
- transforms: [ Toml.Transform . t ]
33
- }
34
-
28
+ keys: % { key => value } ,
29
+ comments: % { keypath => binary } ,
30
+ open_table: keypath | nil ,
31
+ comment_stack: [ binary ] ,
32
+ keyfun: nil | ( binary -> term | no_return ) ,
33
+ transforms: [ Toml.Transform . t ( ) ]
34
+ }
35
+
35
36
@ doc """
36
37
Create a new empty TOML document
37
38
"""
38
- @ spec new ( Toml . opts ) :: t
39
+ @ spec new ( Toml . opts ( ) ) :: t
39
40
def new ( opts ) when is_list ( opts ) do
40
41
keyfun = to_key_fun ( Keyword . get ( opts , :keys , :strings ) )
41
42
transforms = Keyword . get ( opts , :transforms , [ ] )
43
+
42
44
% __MODULE__ {
43
- keys: % { } ,
44
- comments: % { } ,
45
+ keys: % { } ,
46
+ comments: % { } ,
45
47
open_table: nil ,
46
48
comment_stack: [ ] ,
47
49
keyfun: keyfun ,
48
50
transforms: transforms
49
51
}
50
52
end
51
-
53
+
52
54
@ doc """
53
55
Convert the given TOML document to a plain map.
54
-
56
+
55
57
During conversion to a plain map, keys are converted according
56
58
to the key type defined when the document was created.
57
59
@@ -68,9 +70,11 @@ defmodule Toml.Document do
68
70
case ts do
69
71
[ ] ->
70
72
nil
73
+
71
74
ts when is_list ( ts ) ->
72
75
Toml.Transform . compose ( ts )
73
76
end
77
+
74
78
{ :ok , to_map2 ( keys , keyfun , transform ) }
75
79
catch
76
80
_ , { :error , { :keys , { :non_existing_atom , _ } } } = err ->
@@ -81,19 +85,23 @@ defmodule Toml.Document do
81
85
defp to_map2 ( m , nil , nil ) when is_map ( m ) do
82
86
for { k , v } <- m , into: % { } , do: { k , to_map3 ( k , v , nil , nil ) }
83
87
end
88
+
84
89
defp to_map2 ( m , keyfun , nil ) when is_map ( m ) and is_function ( keyfun , 1 ) do
85
- for { k , v } <- m , into: % { } do
90
+ for { k , v } <- m , into: % { } do
86
91
k2 = keyfun . ( k )
87
92
{ k2 , to_map3 ( k2 , v , keyfun , nil ) }
88
93
end
89
94
end
95
+
90
96
defp to_map2 ( m , nil , transform ) when is_map ( m ) and is_function ( transform , 2 ) do
91
97
for { k , v } <- m , into: % { } do
92
98
v2 = to_map3 ( k , v , nil , transform )
93
99
{ k , v2 }
94
100
end
95
101
end
96
- defp to_map2 ( m , keyfun , transform ) when is_map ( m ) and is_function ( keyfun , 1 ) and is_function ( transform , 2 ) do
102
+
103
+ defp to_map2 ( m , keyfun , transform )
104
+ when is_map ( m ) and is_function ( keyfun , 1 ) and is_function ( transform , 2 ) do
97
105
for { k , v } <- m , into: % { } do
98
106
k2 = keyfun . ( k )
99
107
v2 = to_map3 ( k2 , v , keyfun , transform )
@@ -104,39 +112,46 @@ defmodule Toml.Document do
104
112
# Called when a table value is being converted
105
113
defp to_map3 ( _key , % _ { } = s , _keyfun , nil ) , do: s
106
114
defp to_map3 ( key , % _ { } = s , _keyfun , transform ) , do: transform . ( key , s )
115
+
107
116
defp to_map3 ( key , list , keyfun , nil ) when is_list ( list ) do
108
117
for v <- list , do: to_map3 ( key , v , keyfun , nil )
109
118
end
119
+
110
120
defp to_map3 ( key , list , _keyfun , transform ) when is_list ( list ) do
111
121
transform . ( key , list )
112
122
end
113
- defp to_map3 ( _key , { :table_array , list } , keyfun , transform ) do
123
+
124
+ defp to_map3 ( _key , { :table_array , list } , keyfun , transform ) do
114
125
for v <- Enum . reverse ( list ) do
115
126
to_map2 ( v , keyfun , transform )
116
127
end
117
128
end
129
+
118
130
defp to_map3 ( _key , v , keyfun , nil ) when is_map ( v ) do
119
131
to_map2 ( v , keyfun , nil )
120
132
end
133
+
121
134
defp to_map3 ( key , v , keyfun , transform ) when is_map ( v ) and is_function ( transform ) do
122
135
transform . ( key , to_map2 ( v , keyfun , transform ) )
123
136
end
137
+
124
138
defp to_map3 ( _key , v , _keyfun , nil ) , do: v
125
139
defp to_map3 ( key , v , _keyfun , transform ) , do: transform . ( key , v )
126
-
140
+
127
141
# Convert the value of `:keys` to a key conversion function (if not already one)
128
142
defp to_key_fun ( :atoms ) , do: & to_atom / 1
129
143
defp to_key_fun ( :atoms! ) , do: & to_existing_atom / 1
130
144
defp to_key_fun ( :strings ) , do: nil
131
145
defp to_key_fun ( fun ) when is_function ( fun , 1 ) , do: fun
132
-
146
+
133
147
# Convert the given key (as binary) to an atom
134
148
# Handle converting uppercase keys to module names rather than plain atoms
135
149
defp to_atom ( << c :: utf8 , _ :: binary >> = key ) when c >= ?A and c <= ?Z do
136
150
Module . concat ( [ key ] )
137
151
end
152
+
138
153
defp to_atom ( key ) , do: String . to_atom ( key )
139
-
154
+
140
155
# Convert the given key (as binary) to an existing atom
141
156
# Handle converting uppercase keys to module names rather than plain atoms
142
157
#
@@ -146,12 +161,13 @@ defmodule Toml.Document do
146
161
Module . concat ( [ String . to_existing_atom ( key ) ] )
147
162
rescue
148
163
_ ->
149
- throw { :error , { :keys , { :non_existing_atom , key } } }
164
+ throw ( { :error , { :keys , { :non_existing_atom , key } } } )
150
165
end
166
+
151
167
defp to_existing_atom ( key ) do
152
168
String . to_existing_atom ( key )
153
169
rescue
154
170
_ ->
155
- throw { :error , { :keys , { :non_existing_atom , key } } }
171
+ throw ( { :error , { :keys , { :non_existing_atom , key } } } )
156
172
end
157
173
end
0 commit comments