tomlrb 2.0.4 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,279 +0,0 @@
1
- # frozen-string-literal: true
2
-
3
- module Tomlrb
4
- class Handler
5
- attr_reader :output, :symbolize_keys
6
-
7
- def initialize(**options)
8
- @output = {}
9
- @current = @output
10
- @stack = []
11
- @array_names = []
12
- @current_table = []
13
- @keys = Keys.new
14
- @symbolize_keys = options[:symbolize_keys]
15
- end
16
-
17
- def set_context(identifiers, is_array_of_tables: false)
18
- if identifiers.empty?
19
- raise ParseError, 'Array needs a name'
20
- end
21
-
22
- @current_table = identifiers.dup
23
- @keys.add_table_key identifiers, is_array_of_tables
24
- @current = @output
25
-
26
- deal_with_array_of_tables(identifiers, is_array_of_tables) do |identifierz|
27
- identifierz.each do |k|
28
- k = k.to_sym if @symbolize_keys
29
- if @current[k].is_a?(Array)
30
- @current = @current[k].last
31
- else
32
- @current[k] ||= {}
33
- @current = @current[k]
34
- end
35
- end
36
- end
37
- end
38
-
39
- def deal_with_array_of_tables(identifiers, is_array_of_tables)
40
- stringified_identifier = identifiers.join('.')
41
-
42
- if is_array_of_tables
43
- @array_names << stringified_identifier
44
- last_identifier = identifiers.pop
45
- elsif @array_names.include?(stringified_identifier)
46
- raise ParseError, 'Cannot define a normal table with the same name as an already established array'
47
- end
48
-
49
- yield(identifiers)
50
-
51
- if is_array_of_tables
52
- last_identifier = last_identifier.to_sym if @symbolize_keys
53
- @current[last_identifier] ||= []
54
- raise ParseError, "Cannot use key #{last_identifier} for both table and array at once" unless @current[last_identifier].respond_to?(:<<)
55
- @current[last_identifier] << {}
56
- @current = @current[last_identifier].last
57
- end
58
- end
59
-
60
- def assign(k)
61
- @keys.add_pair_key k, @current_table
62
- current = @current
63
- while (key = k.shift)
64
- key = key.to_sym if @symbolize_keys
65
- current = assign_key_path(current, key, k.empty?)
66
- end
67
- end
68
-
69
- def push(o)
70
- @stack << o
71
- end
72
-
73
- def push_inline(inline_arrays)
74
- merged_inline = {}
75
- keys = Keys.new
76
-
77
- inline_arrays.each do |inline_array|
78
- current = merged_inline
79
- value = inline_array.pop
80
- keys.add_table_key inline_array, value.is_a?(Array)
81
-
82
- inline_array.each_with_index do |inline_key, inline_index|
83
- inline_key = inline_key.to_sym if @symbolize_keys
84
- last_key = inline_index == inline_array.size - 1
85
-
86
- if last_key
87
- if current[inline_key].nil?
88
- keys.add_pair_key [inline_key], []
89
-
90
- current[inline_key] = value
91
- else
92
- raise Key::KeyConflict, "Inline key #{inline_key} is already used"
93
- end
94
- else
95
- current[inline_key] ||= {}
96
- current = current[inline_key]
97
- end
98
- end
99
- end
100
-
101
- push(merged_inline)
102
- end
103
-
104
- def start_(type)
105
- push([type])
106
- end
107
-
108
- def end_(type)
109
- array = []
110
- while (value = @stack.pop) != [type]
111
- raise ParseError, 'Unclosed table' if @stack.empty?
112
-
113
- array.unshift(value)
114
- end
115
- array
116
- end
117
-
118
- def validate_value(value)
119
- if value.nil?
120
- raise ParseError, 'Value must be present'
121
- end
122
- end
123
-
124
- private
125
-
126
- def assign_key_path(current, key, key_emptied)
127
- existed = current.key?(key)
128
- raise ParseError, "Cannot overwrite value with key #{key}" if existed && !current[key].is_a?(Hash)
129
- if key_emptied
130
- raise ParseError, "Cannot overwrite value with key #{key}" unless current.is_a?(Hash)
131
-
132
- value = @stack.pop
133
- raise ParseError, "Cannot overwrite value with key #{key}" if current[key].is_a?(Hash) && !value.is_a?(Hash)
134
- current[key] = value
135
- return current
136
- end
137
- current[key] ||= {}
138
- current[key]
139
- end
140
- end
141
-
142
- class Keys
143
- def initialize
144
- @keys = {}
145
- end
146
-
147
- def add_table_key(keys, is_array_of_tables = false)
148
- self << [keys, [], is_array_of_tables]
149
- end
150
-
151
- def add_pair_key(keys, context)
152
- self << [context, keys, false]
153
- end
154
-
155
- def <<(keys)
156
- table_keys, pair_keys, is_array_of_tables = keys
157
- current = @keys
158
- current = append_table_keys(current, table_keys, pair_keys.empty?, is_array_of_tables)
159
- append_pair_keys(current, pair_keys, table_keys.empty?, is_array_of_tables)
160
- end
161
-
162
- private
163
-
164
- def append_table_keys(current, table_keys, pair_keys_empty, is_array_of_tables)
165
- table_keys.each_with_index do |key, index|
166
- declared = (index == table_keys.length - 1) && pair_keys_empty
167
- if index.zero?
168
- current = find_or_create_first_table_key(current, key, declared, is_array_of_tables)
169
- else
170
- current <<= [key, :table, declared, is_array_of_tables]
171
- end
172
- end
173
-
174
- current.clear_children if is_array_of_tables
175
- current
176
- end
177
-
178
- def find_or_create_first_table_key(current, key, declared, is_array_of_tables)
179
- existed = current[key]
180
- if existed && existed.type == :pair
181
- raise Key::KeyConflict, "Key #{key} is already used as #{existed.type} key"
182
- end
183
- if existed && existed.declared? && declared && ! is_array_of_tables
184
- raise Key::KeyConflict, "Key #{key} is already used"
185
- end
186
- k = existed || Key.new(key, :table, declared)
187
- k.declared = k.declared? || declared
188
- current[key] = k
189
- k
190
- end
191
-
192
- def append_pair_keys(current, pair_keys, table_keys_empty, is_array_of_tables)
193
- pair_keys.each_with_index do |key, index|
194
- declared = index == pair_keys.length - 1
195
- if index.zero? && table_keys_empty
196
- current = find_or_create_first_pair_key(current, key, declared, table_keys_empty)
197
- else
198
- key = current << [key, :pair, declared, is_array_of_tables]
199
- current = key
200
- end
201
- end
202
- end
203
-
204
- def find_or_create_first_pair_key(current, key, declared, table_keys_empty)
205
- existed = current[key]
206
- if existed && (existed.type == :pair) && declared && table_keys_empty
207
- raise Key::KeyConflict, "Key #{key} is already used"
208
- end
209
- k = Key.new(key, :pair, declared)
210
- current[key] = k
211
- k
212
- end
213
- end
214
-
215
- class Key
216
- class KeyConflict < ParseError; end
217
-
218
- attr_reader :key, :type
219
- attr_writer :declared
220
-
221
- def initialize(key, type, declared = false)
222
- @key = key
223
- @type = type
224
- @declared = declared
225
- @children = {}
226
- end
227
-
228
- def declared?
229
- @declared
230
- end
231
-
232
- def <<(key_type_declared)
233
- key, type, declared, is_array_of_tables = key_type_declared
234
- existed = @children[key]
235
- validate_already_declared_as_different_key(type, declared, existed)
236
- validate_already_declared_as_non_array_table(type, is_array_of_tables, declared, existed)
237
- validate_path_already_created_as_different_type(type, declared, existed)
238
- validate_path_already_declared_as_different_type(type, declared, existed)
239
- validate_already_declared_as_same_key(declared, existed)
240
- @children[key] = existed || self.class.new(key, type, declared)
241
- end
242
-
243
- def clear_children
244
- @children.clear
245
- end
246
-
247
- private
248
-
249
- def validate_already_declared_as_different_key(type, _declared, existed)
250
- if existed && existed.declared? && existed.type != type
251
- raise KeyConflict, "Key #{existed.key} is already used as #{existed.type} key"
252
- end
253
- end
254
-
255
- def validate_already_declared_as_non_array_table(type, is_array_of_tables, declared, existed)
256
- if declared && type == :table && existed && existed.declared? && !is_array_of_tables
257
- raise KeyConflict, "Key #{existed.key} is already used"
258
- end
259
- end
260
-
261
- def validate_path_already_created_as_different_type(type, declared, existed)
262
- if declared && (type == :table) && existed && (existed.type == :pair) && !existed.declared?
263
- raise KeyConflict, "Key #{existed.key} is already used as #{existed.type} key"
264
- end
265
- end
266
-
267
- def validate_path_already_declared_as_different_type(type, declared, existed)
268
- if !declared && (type == :pair) && existed && (existed.type == :pair) && existed.declared?
269
- raise KeyConflict, "Key #{key} is already used as #{type} key"
270
- end
271
- end
272
-
273
- def validate_already_declared_as_same_key(declared, existed)
274
- if existed && !existed.declared? && declared
275
- raise KeyConflict, "Key #{existed.key} is already used as #{existed.type} key"
276
- end
277
- end
278
- end
279
- end
data/lib/tomlrb/parser.y DELETED
@@ -1,230 +0,0 @@
1
- class Tomlrb::GeneratedParser
2
- token IDENTIFIER STRING_MULTI STRING_BASIC STRING_LITERAL_MULTI STRING_LITERAL DATETIME LOCAL_TIME INTEGER NON_DEC_INTEGER FLOAT FLOAT_KEYWORD BOOLEAN NEWLINE EOS
3
- rule
4
- expressions
5
- | expressions expression
6
- | expressions EOS
7
- ;
8
- expression
9
- : table
10
- | assignment
11
- | inline_table
12
- | NEWLINE
13
- ;
14
- table
15
- : table_start table_identifier table_end newlines
16
- | table_start table_identifier table_end EOS
17
- | table_start table_end newlines
18
- | table_start table_end EOS
19
- ;
20
- table_start
21
- : '[' '[' { @handler.start_(:array_of_tables) }
22
- | '[' { @handler.start_(:table) }
23
- ;
24
- ;
25
- table_end
26
- : ']' ']' { array = @handler.end_(:array_of_tables); @handler.set_context(array, is_array_of_tables: true) }
27
- | ']' { array = @handler.end_(:table); @handler.set_context(array) }
28
- ;
29
- table_identifier
30
- : table_identifier '.' table_identifier_component { @handler.push(val[2]) }
31
- | table_identifier '.' FLOAT { val[2].split('.').each { |k| @handler.push(k) } }
32
- | FLOAT {
33
- keys = val[0].split('.')
34
- @handler.start_(:table)
35
- keys.each { |key| @handler.push(key) }
36
- }
37
- | table_identifier_component { @handler.push(val[0]) }
38
- ;
39
- table_identifier_component
40
- : IDENTIFIER
41
- | STRING_BASIC { result = StringUtils.replace_escaped_chars(val[0]) }
42
- | STRING_LITERAL
43
- | INTEGER
44
- | NON_DEC_INTEGER
45
- | FLOAT_KEYWORD
46
- | BOOLEAN
47
- | DATETIME { result = val[0][0] }
48
- | LOCAL_TIME { result = val[0][0] }
49
- ;
50
- inline_table
51
- : inline_table_start inline_table_end
52
- | inline_table_start inline_continued inline_table_end
53
- ;
54
- inline_table_start
55
- : '{' { @handler.start_(:inline) }
56
- ;
57
- inline_table_end
58
- : '}' {
59
- array = @handler.end_(:inline)
60
- @handler.push_inline(array)
61
- }
62
- ;
63
- inline_continued
64
- : inline_assignment
65
- | inline_assignment inline_next
66
- ;
67
- inline_next
68
- : ',' inline_continued
69
- ;
70
- inline_assignment
71
- : inline_assignment_key '=' value {
72
- keys = @handler.end_(:inline_keys)
73
- @handler.push(keys)
74
- }
75
- ;
76
- inline_assignment_key
77
- : inline_assignment_key '.' assignment_key_component {
78
- @handler.push(val[2])
79
- }
80
- | inline_assignment_key '.' FLOAT { val[2].split('.').each { |k| @handler.push(k) } }
81
- | FLOAT {
82
- keys = val[0].split('.')
83
- @handler.start_(:inline_keys)
84
- keys.each { |key| @handler.push(key) }
85
- }
86
- | assignment_key_component {
87
- @handler.start_(:inline_keys)
88
- @handler.push(val[0])
89
- }
90
- ;
91
- assignment
92
- : assignment_key '=' value EOS {
93
- keys = @handler.end_(:keys)
94
- value = keys.pop
95
- @handler.validate_value(value)
96
- @handler.push(value)
97
- @handler.assign(keys)
98
- }
99
- | assignment_key '=' value NEWLINE {
100
- keys = @handler.end_(:keys)
101
- value = keys.pop
102
- @handler.validate_value(value)
103
- @handler.push(value)
104
- @handler.assign(keys)
105
- }
106
- ;
107
- assignment_key
108
- : assignment_key '.' assignment_key_component { @handler.push(val[2]) }
109
- | assignment_key '.' FLOAT { val[2].split('.').each { |k| @handler.push(k) } }
110
- | FLOAT {
111
- keys = val[0].split('.')
112
- @handler.start_(:keys)
113
- keys.each { |key| @handler.push(key) }
114
- }
115
- | assignment_key_component { @handler.start_(:keys); @handler.push(val[0]) }
116
- ;
117
- assignment_key_component
118
- : IDENTIFIER
119
- | STRING_BASIC { result = StringUtils.replace_escaped_chars(val[0]) }
120
- | STRING_LITERAL
121
- | INTEGER
122
- | NON_DEC_INTEGER
123
- | FLOAT_KEYWORD
124
- | BOOLEAN
125
- | DATETIME { result = val[0][0] }
126
- | LOCAL_TIME { result = val[0][0] }
127
- ;
128
- array
129
- : start_array array_first_value array_values comma end_array
130
- | start_array array_first_value array_values end_array
131
- | start_array array_first_value comma end_array
132
- | start_array array_first_value end_array
133
- | start_array end_array
134
- ;
135
- array_first_value
136
- : newlines non_nil_value
137
- | non_nil_value
138
- ;
139
- array_values
140
- : array_values array_value
141
- | array_value
142
- ;
143
- array_value
144
- : comma newlines non_nil_value
145
- | comma non_nil_value
146
- ;
147
- start_array
148
- : '[' { @handler.start_(:array) }
149
- ;
150
- end_array
151
- : newlines ']' { array = @handler.end_(:array); @handler.push(array.compact) }
152
- | ']' { array = @handler.end_(:array); @handler.push(array.compact) }
153
- ;
154
- comma
155
- : newlines ','
156
- | ','
157
- ;
158
- newlines
159
- : newlines NEWLINE
160
- | NEWLINE
161
- ;
162
- value
163
- : scalar { @handler.push(val[0]) }
164
- | array
165
- | inline_table
166
- ;
167
- non_nil_value
168
- : non_nil_scalar { @handler.push(val[0]) }
169
- | array
170
- | inline_table
171
- ;
172
- scalar
173
- : string
174
- | literal
175
- ;
176
- non_nil_scalar
177
- : string
178
- | non_nil_literal
179
- ;
180
- literal
181
- | non_nil_literal
182
- ;
183
- non_nil_literal
184
- : FLOAT { result = val[0].to_f }
185
- | FLOAT_KEYWORD {
186
- v = val[0]
187
- result = if v.end_with?('nan')
188
- Float::NAN
189
- else
190
- (v[0] == '-' ? -1 : 1) * Float::INFINITY
191
- end
192
- }
193
- | INTEGER { result = val[0].to_i }
194
- | NON_DEC_INTEGER {
195
- base = case val[0][1]
196
- when 'x' then 16
197
- when 'o' then 8
198
- when 'b' then 2
199
- end
200
- result = val[0].to_i(base)
201
- }
202
- | BOOLEAN { result = val[0] == 'true' ? true : false }
203
- | DATETIME {
204
- _str, year, month, day, hour, min, sec, offset = val[0]
205
- result = if offset.nil?
206
- if hour.nil?
207
- LocalDate.new(year, month, day)
208
- else
209
- LocalDateTime.new(year, month, day, hour, min || 0, sec.to_f)
210
- end
211
- else
212
- # Patch for 24:00:00 which Ruby parses
213
- if hour.to_i == 24 && min.to_i == 0 && sec.to_i == 0
214
- hour = (hour.to_i + 1).to_s
215
- end
216
-
217
- time = Time.new(year, month, day, hour || 0, min || 0, sec.to_f, offset)
218
- # Should be out of parser.y?
219
- raise ArgumentError, "Invalid Offset Date-Time: #{year}-#{month}-#{day}T#{hour}:#{min}:#{sec}#{offset}" unless min.to_i == time.min && hour.to_i == time.hour && day.to_i == time.day && month.to_i == time.month && year.to_i == time.year
220
- time
221
- end
222
- }
223
- | LOCAL_TIME { result = LocalTime.new(*val[0][1..-1]) }
224
- ;
225
- string
226
- : STRING_MULTI { result = StringUtils.replace_escaped_chars(StringUtils.multiline_replacements(val[0])) }
227
- | STRING_BASIC { result = StringUtils.replace_escaped_chars(val[0]) }
228
- | STRING_LITERAL_MULTI { result = StringUtils.strip_spaces(val[0]) }
229
- | STRING_LITERAL { result = val[0] }
230
- ;
@@ -1,92 +0,0 @@
1
- # frozen-string-literal: true
2
-
3
- require 'strscan'
4
-
5
- module Tomlrb
6
- class Scanner
7
- COMMENT =
8
- /#[^\u0000-\u0008\u000A-\u001F\u007F]*/.freeze
9
- IDENTIFIER =
10
- /[A-Za-z0-9_-]+/.freeze
11
- SPACE =
12
- /[ \t]/.freeze
13
- NEWLINE =
14
- /(?:[ \t]*(?:\r?\n)[ \t]*)+/.freeze
15
- STRING_BASIC =
16
- /(")(?:\\?[^\u0000-\u0008\u000A-\u001F\u007F\\]|(?:\\[^\u0000-\u0008\u000A-\u001F\u007F]))*?\1/.freeze
17
- STRING_MULTI =
18
- /"{3}([^\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F]*?(?<!\\)"{3,5})/m.freeze
19
- STRING_LITERAL =
20
- /(')(?:\\?[^\u0000-\u0008\u000A-\u001F\u007F])*?\1/.freeze
21
- STRING_LITERAL_MULTI =
22
- /'{3}([^\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F]*?'{3,5})/m.freeze
23
- DATETIME =
24
- /(-?\d{4})-([01]\d)-([0-3]\d)(?:(?:t|\s)([0-2]\d):([0-5]\d):([0-6]\d(?:\.\d+)?))?(z|[-+][01]\d:\d{2})?/i.freeze
25
- LOCAL_TIME =
26
- /([0-2]\d):([0-5]\d):([0-6]\d(?:\.\d+)?)/.freeze
27
- FLOAT =
28
- /[+-]?(?:(?:\d|[1-9](?:_?\d)*)\.\d(?:_?\d)*|\d+(?=[eE]))(?:[eE][+-]?[0-9]+(_[0-9])*[0-9]*)?(?!\w)/.freeze
29
- FLOAT_KEYWORD =
30
- /[+-]?(?:inf|nan)\b/.freeze
31
- INTEGER =
32
- /[+-]?([1-9](_?\d)*|0)(?![A-Za-z0-9_-]+)/.freeze
33
- NON_DEC_INTEGER =
34
- /0(?:x[0-9A-Fa-f](_?[0-9A-Fa-f])*|o[0-7](_?[0-7])*|b[01](_?[01])*)/.freeze
35
- BOOLEAN =
36
- /true|false/.freeze
37
- SPACED_ARRAY_OF_TABLES_START =
38
- /^\[[ \t]+\[(#{IDENTIFIER}|#{STRING_BASIC}|#{STRING_LITERAL}|#{INTEGER}|#{NON_DEC_INTEGER}|#{FLOAT_KEYWORD}|#{BOOLEAN})\]\]$/.freeze
39
- SPACED_ARRAY_OF_TABLES_END =
40
- /^\[\[(#{IDENTIFIER}|#{STRING_BASIC}|#{STRING_LITERAL}|#{INTEGER}|#{NON_DEC_INTEGER}|#{FLOAT_KEYWORD}|#{BOOLEAN})\][ \t]+\]$/.freeze
41
- SPACED_ARRAY_OF_TABLES_BOTH =
42
- /^\[[ \t]+\[(#{IDENTIFIER}|#{STRING_BASIC}|#{STRING_LITERAL}|#{INTEGER}|#{NON_DEC_INTEGER}|#{FLOAT_KEYWORD}|#{BOOLEAN})\][ \t]+\]$/.freeze
43
-
44
- def initialize(io)
45
- @ss = StringScanner.new(io.read)
46
- @eos = false
47
- end
48
-
49
- def next_token
50
- case
51
- when @ss.scan(NEWLINE) then [:NEWLINE, nil]
52
- when @ss.scan(SPACED_ARRAY_OF_TABLES_START) then raise ParseError.new('Array of tables has spaces in starting brackets')
53
- when @ss.scan(SPACED_ARRAY_OF_TABLES_END) then raise ParseError.new('Array of tables has spaces in ending brackets')
54
- when @ss.scan(SPACED_ARRAY_OF_TABLES_BOTH) then raise ParseError.new('Array of tables has spaces in starting and ending brackets')
55
- when @ss.scan(SPACE) then next_token
56
- when @ss.scan(COMMENT) then next_token
57
- when @ss.scan(DATETIME) then process_datetime
58
- when @ss.scan(LOCAL_TIME) then process_local_time
59
- when text = @ss.scan(STRING_MULTI) then [:STRING_MULTI, text[3..-4]]
60
- when text = @ss.scan(STRING_BASIC) then [:STRING_BASIC, text[1..-2]]
61
- when text = @ss.scan(STRING_LITERAL_MULTI) then [:STRING_LITERAL_MULTI, text[3..-4]]
62
- when text = @ss.scan(STRING_LITERAL) then [:STRING_LITERAL, text[1..-2]]
63
- when text = @ss.scan(FLOAT) then [:FLOAT, text]
64
- when text = @ss.scan(FLOAT_KEYWORD) then [:FLOAT_KEYWORD, text]
65
- when text = @ss.scan(INTEGER) then [:INTEGER, text]
66
- when text = @ss.scan(NON_DEC_INTEGER) then [:NON_DEC_INTEGER, text]
67
- when text = @ss.scan(BOOLEAN) then [:BOOLEAN, text]
68
- when text = @ss.scan(IDENTIFIER) then [:IDENTIFIER, text]
69
- when @ss.eos? then process_eos
70
- else x = @ss.getch; [x, x]
71
- end
72
- end
73
-
74
- def process_datetime
75
- offset = @ss[7].gsub(/[zZ]/, '+00:00') if @ss[7]
76
- args = [@ss[0], @ss[1], @ss[2], @ss[3], @ss[4], @ss[5], @ss[6], offset]
77
- [:DATETIME, args]
78
- end
79
-
80
- def process_local_time
81
- args = [@ss[0], @ss[1], @ss[2], @ss[3].to_f]
82
- [:LOCAL_TIME, args]
83
- end
84
-
85
- def process_eos
86
- return if @eos
87
-
88
- @eos = true
89
- [:EOS, nil]
90
- end
91
- end
92
- end
@@ -1,40 +0,0 @@
1
- # frozen-string-literal: true
2
-
3
- module Tomlrb
4
- class StringUtils
5
- SPECIAL_CHARS = {
6
- '\\t' => "\t",
7
- '\\b' => "\b",
8
- '\\f' => "\f",
9
- '\\n' => "\n",
10
- '\\r' => "\r",
11
- '\\"' => '"',
12
- '\\\\' => '\\'
13
- }.freeze
14
-
15
- def self.multiline_replacements(str)
16
- strip_spaces(str).gsub(/\\+\s*\n\s*/) do |matched|
17
- if matched.match(/\\+/)[0].length.odd?
18
- matched.gsub(/\\\s*\n\s*/, '')
19
- else
20
- matched
21
- end
22
- end
23
- end
24
-
25
- def self.replace_escaped_chars(str)
26
- str.gsub(/\\(u[\da-fA-F]{4}|U[\da-fA-F]{8}|.)/) do |m|
27
- if m.size == 2
28
- SPECIAL_CHARS[m] || (raise Tomlrb::ParseError.new "Escape sequence #{m} is reserved")
29
- else
30
- m[2..-1].to_i(16).chr(Encoding::UTF_8)
31
- end
32
- end
33
- end
34
-
35
- def self.strip_spaces(str)
36
- str[0] = '' if str[0] == "\n"
37
- str
38
- end
39
- end
40
- end