rkamyk-ya2yaml 0.26

Sign up to get free protection for your applications and to get access to all the features.
Files changed (7) hide show
  1. data/LICENSE +19 -0
  2. data/README +113 -0
  3. data/lib/ya2yaml.rb +359 -0
  4. data/test/t.gif +0 -0
  5. data/test/t.yaml +5 -0
  6. data/test/test.rb +382 -0
  7. metadata +57 -0
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2006 Akira FUNAI <funai.akira@gmail.com>
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a
4
+ copy of this software and associated documentation files (the "Software"),
5
+ to deal in the Software without restriction, including without limitation
6
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
7
+ and/or sell copies of the Software, and to permit persons to whom the
8
+ Software is furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
16
+ THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19
+ DEALINGS IN THE SOFTWARE.
data/README ADDED
@@ -0,0 +1,113 @@
1
+ = Ya2YAML - An UTF8 safe YAML dumper
2
+
3
+ Project Contact: Akira FUNAI <mailto:funai.akira@gmail.com>
4
+
5
+ Ya2YAML is "yet another to_yaml". It emits YAML document with complete UTF8 support (string/binary detection, "\u" escape sequences and Unicode specific line breaks). I hope someone might find it useful until Syck/RbYAML come out with UTF8/16 support.
6
+
7
+ == Usage
8
+
9
+ *code*:
10
+
11
+ $KCODE = 'UTF8'
12
+ require 'ya2yaml'
13
+
14
+ obj = [
15
+ "abc\nxyz\n",
16
+ "日本語\n文字列\n",
17
+ "\xfd\xfe\xff",
18
+ ]
19
+ puts obj.ya2yaml(:syck_compatible => true)
20
+
21
+ *output*:
22
+
23
+ ---
24
+ - |
25
+ abc
26
+ xyz
27
+ - |
28
+ 日本語
29
+ 文字列
30
+ - !binary |
31
+ /f7/
32
+
33
+ == Method and Objects
34
+
35
+ When you require 'ya2yaml', public method 'Object#ya2yaml' is defined. Currently these Objects are supported.
36
+
37
+ as YAML generic types:
38
+ - Array
39
+ - Hash
40
+ - NilClass
41
+ - String
42
+ - TrueClass
43
+ - FalseClass
44
+ - Fixnum
45
+ - Bignum
46
+ - Float
47
+ - Date
48
+ - Time
49
+
50
+ as Ruby specific types:
51
+ - Symbol
52
+ - Range
53
+ - Regexp
54
+ - Struct
55
+ - everything else as a generic Object (serializes instance variables)
56
+
57
+ A String which contains any non-UTF8 character will be regarded as "binary" and encoded in BASE64.
58
+
59
+ == Options
60
+
61
+ # set them individually
62
+ obj.ya2yaml(
63
+ :indent_size => 4,
64
+ :hash_order => ['name','age','address'],
65
+ :minimum_block_length => 16,
66
+ :printable_with_syck => true,
67
+ :escape_b_specific => true,
68
+ :escape_as_utf8 => true
69
+ )
70
+
71
+ # or simply set this for a safe roundtrip with Syck.
72
+ obj.ya2yaml(:syck_compatible => true)
73
+
74
+ **CAUTION** Some of these options are to avoid compatibility issue with Syck. When you set these options to false, the emitted YAML document might not be loadable with YAML.load() although the syntax is valid.
75
+
76
+ - :indent_size
77
+ - default: 2
78
+ - Number of indentation spaces for a level.
79
+
80
+ - :hash_order
81
+ - default: nil
82
+ - Array of hash keys indicating sort order (this option only works on a top-level hash).
83
+
84
+ - :minimum_block_length
85
+ - default: 0
86
+ - Minimum length of a string emitted in block scalar style. If a string is shorter than this value, it will be emitted in one line.
87
+
88
+ - :printable_with_syck
89
+ - default: false
90
+ - When set to true, Ya2YAML will regard some kind of strings (which cause Syck roundtrip failures) as "non-printable" and double-quote them.
91
+
92
+ - :escape_b_specific
93
+ - default: false
94
+ - When set to true, Ya2YAML will regard Unicode specific line breaks (LS and PS) as "non-printable" and escape them.
95
+
96
+ - :escape_as_utf8
97
+ - default: false
98
+ - When set to true, Ya2YAML uses Ruby-like escape sequences in UTF8 code instead of "\uXXXX" style in UCS code. It also suppresses use of "\L" and "\P" (escape sequences for LS and PS).
99
+
100
+ - :syck_compatible
101
+ - default: false
102
+ - When set to true, These options are set to true at once. You have to set this to false when you set them individually.
103
+ - :printable_with_syck
104
+ - :escape_b_specific
105
+ - :escape_as_utf8
106
+
107
+ == More information
108
+
109
+ Visit http://rubyforge.org/projects/ya2yaml
110
+
111
+ == License
112
+
113
+ Ya2YAML is distributed with a MIT license, which can be found in the file LICENSE.
@@ -0,0 +1,359 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # $Id: ya2yaml.rb,v 0.26 2007-01-19 20:42:42+09 funai Exp funai $
4
+ #
5
+ # Author:: Akira FUNAI
6
+ # Copyright:: Copyright (c) 2006 Akira FUNAI
7
+ # License:: MIT License
8
+
9
+ class Ya2YAML
10
+
11
+ def initialize(options = {})
12
+ options[:indent_size] = 2 if options[:indent_size].to_i <= 0
13
+ options[:minimum_block_length] = 0 if options[:minimum_block_length].to_i <= 0
14
+ options.update(
15
+ {
16
+ :printable_with_syck => true,
17
+ :escape_b_specific => true,
18
+ :escape_as_utf8 => true,
19
+ }
20
+ ) if options[:syck_compatible]
21
+
22
+ @options = options
23
+ end
24
+
25
+ def _ya2yaml(obj)
26
+ throw 'set $KCODE to "UTF8".' if $KCODE != 'UTF8'
27
+ '--- ' + emit(obj,1) + "\n"
28
+ end
29
+
30
+ private
31
+
32
+ def emit(obj,level)
33
+ case obj.class.to_s
34
+ when 'Array'
35
+ if (obj.length == 0)
36
+ '[]'
37
+ else
38
+ indent = "\n" + s_indent(level - 1)
39
+ obj.collect {|o|
40
+ indent + '- ' + emit(o,level + 1)
41
+ }.join('')
42
+ end
43
+ when 'Hash'
44
+ if (obj.length == 0)
45
+ '{}'
46
+ else
47
+ indent = "\n" + s_indent(level - 1)
48
+ hash_order = @options[:hash_order]
49
+ if (hash_order && level == 1)
50
+ hash_keys = obj.keys.sort {|x,y|
51
+ x_order = hash_order.index(x) ? hash_order.index(x) : Float::MAX
52
+ y_order = hash_order.index(y) ? hash_order.index(y) : Float::MAX
53
+ o = (x_order <=> y_order)
54
+ (o != 0) ? o : (x.to_s <=> y.to_s)
55
+ }
56
+ else
57
+ hash_keys = obj.keys.sort {|x,y| x.to_s <=> y.to_s }
58
+ end
59
+ hash_keys.collect {|k|
60
+ key = emit(k,level + 1)
61
+ indent + key + ': ' + emit(obj[k],level + 1)
62
+ }.join('')
63
+ end
64
+ when 'NilClass'
65
+ '~'
66
+ when 'String'
67
+ emit_string(obj,level)
68
+ when 'TrueClass','FalseClass'
69
+ obj.to_s
70
+ when 'Fixnum','Bignum','Float'
71
+ obj.to_s
72
+ when 'Date'
73
+ obj.to_s
74
+ when 'Time'
75
+ offset = obj.gmtoff
76
+ off_hm = sprintf(
77
+ '%+.2d:%.2d',
78
+ (offset / 3600.0).to_i,
79
+ (offset % 3600.0) / 60
80
+ )
81
+ u_sec = (obj.usec != 0) ? sprintf(".%.6d",obj.usec) : ''
82
+ obj.strftime("%Y-%m-%d %H:%M:%S#{u_sec} #{off_hm}")
83
+ when 'Symbol'
84
+ '!ruby/symbol ' + obj.to_s
85
+ when 'Range'
86
+ '!ruby/range ' + obj.to_s
87
+ when 'Regexp'
88
+ '!ruby/regexp ' + obj.inspect
89
+ else
90
+ case
91
+ when obj.is_a?(Struct)
92
+ struct_members = {}
93
+ obj.each_pair{|k,v| struct_members[k.to_s] = v }
94
+ '!ruby/struct:' + obj.class.to_s.sub(/^(Struct::(.+)|.*)$/,'\2') + ' ' +
95
+ emit(struct_members,level + 1)
96
+ else
97
+ # serialized as a generic object
98
+ object_members = {}
99
+ obj.instance_variables.each{|k,v|
100
+ object_members[k.sub(/^@/,'')] = obj.instance_variable_get(k)
101
+ }
102
+ '!ruby/object:' + obj.class.to_s + ' ' +
103
+ emit(object_members,level + 1)
104
+ end
105
+ end
106
+ end
107
+
108
+ def emit_string(str,level)
109
+ (is_string,is_printable,is_one_line,is_one_plain_line) = string_type(str)
110
+ if is_string
111
+ if is_printable
112
+ if is_one_plain_line
113
+ emit_simple_string(str,level)
114
+ else
115
+ (is_one_line || str.length < @options[:minimum_block_length]) ?
116
+ emit_quoted_string(str,level) :
117
+ emit_block_string(str,level)
118
+ end
119
+ else
120
+ emit_quoted_string(str,level)
121
+ end
122
+ else
123
+ emit_base64_binary(str,level)
124
+ end
125
+ end
126
+
127
+ def emit_simple_string(str,level)
128
+ str
129
+ end
130
+
131
+ def emit_block_string(str,level)
132
+ str = normalize_line_break(str)
133
+
134
+ indent = s_indent(level)
135
+ indentation_indicator = (str =~ /\A /) ? indent.size.to_s : ''
136
+ str =~ /(#{REX_NORMAL_LB}*)\z/
137
+ chomping_indicator = case $1.length
138
+ when 0
139
+ '-'
140
+ when 1
141
+ ''
142
+ else
143
+ '+'
144
+ end
145
+
146
+ str.chomp!
147
+ str.gsub!(/#{REX_NORMAL_LB}/) {
148
+ $1 + indent
149
+ }
150
+ '|' + indentation_indicator + chomping_indicator + "\n" + indent + str
151
+ end
152
+
153
+ def emit_quoted_string(str,level)
154
+ str = yaml_escape(normalize_line_break(str))
155
+ if (str.length < @options[:minimum_block_length])
156
+ str.gsub!(/#{REX_NORMAL_LB}/) { ESCAPE_SEQ_LB[$1] }
157
+ else
158
+ str.gsub!(/#{REX_NORMAL_LB}$/) { ESCAPE_SEQ_LB[$1] }
159
+ str.gsub!(/(#{REX_NORMAL_LB}+)(.)/) {
160
+ trail_c = $3
161
+ $1 + trail_c.sub(/([\t ])/) { ESCAPE_SEQ_WS[$1] }
162
+ }
163
+ indent = s_indent(level)
164
+ str.gsub!(/#{REX_NORMAL_LB}/) {
165
+ ESCAPE_SEQ_LB[$1] + "\\\n" + indent
166
+ }
167
+ end
168
+ '"' + str + '"'
169
+ end
170
+
171
+ def emit_base64_binary(str,level)
172
+ indent = "\n" + s_indent(level)
173
+ base64 = [str].pack('m')
174
+ '!binary |' + indent + base64.gsub(/\n(?!\z)/,indent)
175
+ end
176
+
177
+ def string_type(str)
178
+ (ucs_codes = str.unpack('U*')) rescue (
179
+ # ArgumentError -> binary data
180
+ return false,false,false,false
181
+ )
182
+ if (
183
+ @options[:printable_with_syck] &&
184
+ str =~ /\A#{REX_ANY_LB}* | #{REX_ANY_LB}*\z|#{REX_ANY_LB}{2}\z/
185
+ )
186
+ # detour Syck bug
187
+ return true,false,is_one_line?(str),false
188
+ end
189
+ ucs_codes.each {|ucs_code|
190
+ return true,false,is_one_line?(str),false unless is_printable?(ucs_code)
191
+ }
192
+ return true,true,is_one_line?(str),is_one_plain_line?(str)
193
+ end
194
+
195
+ def is_printable?(ucs_code)
196
+ # YAML 1.1 / 4.1.1.
197
+ (
198
+ [0x09,0x0a,0x0d,0x85].include?(ucs_code) ||
199
+ (ucs_code <= 0x7e && ucs_code >= 0x20) ||
200
+ (ucs_code <= 0xd7ff && ucs_code >= 0xa0) ||
201
+ (ucs_code <= 0xfffd && ucs_code >= 0xe000) ||
202
+ (ucs_code <= 0x10ffff && ucs_code >= 0x10000)
203
+ ) &&
204
+ !(
205
+ # treat LS/PS as non-printable characters
206
+ @options[:escape_b_specific] &&
207
+ (ucs_code == 0x2028 || ucs_code == 0x2029)
208
+ )
209
+ end
210
+
211
+ def is_one_line?(str)
212
+ str !~ /#{REX_ANY_LB}(?!\z)/
213
+ end
214
+
215
+ def is_one_plain_line?(str)
216
+ # YAML 1.1 / 4.6.11.
217
+ str !~ /^([\-\?:,\[\]\{\}\#&\*!\|>'"%@`\s]|---|\.\.\.)/ &&
218
+ str !~ /[:\#\s\[\]\{\},]/ &&
219
+ str !~ /#{REX_ANY_LB}/ &&
220
+ str !~ /^(#{REX_BOOL}|#{REX_FLOAT}|#{REX_INT}|#{REX_MERGE}
221
+ |#{REX_NULL}|#{REX_TIMESTAMP}|#{REX_VALUE})$/x
222
+ end
223
+
224
+ def s_indent(level)
225
+ # YAML 1.1 / 4.2.2.
226
+ ' ' * (level * @options[:indent_size])
227
+ end
228
+
229
+ def normalize_line_break(str)
230
+ # YAML 1.1 / 4.1.4.
231
+ str.gsub(/(#{REX_CRLF}|#{REX_CR}|#{REX_NEL})/,"\n")
232
+ end
233
+
234
+ def yaml_escape(str)
235
+ # YAML 1.1 / 4.1.6.
236
+ str.gsub(/[^a-zA-Z0-9]/u) {|c|
237
+ ucs_code, = (c.unpack('U') rescue [??])
238
+ case
239
+ when ESCAPE_SEQ[c]
240
+ ESCAPE_SEQ[c]
241
+ when is_printable?(ucs_code)
242
+ c
243
+ when @options[:escape_as_utf8]
244
+ '\\x' + c.unpack('H2' * c.size).join('\\x')
245
+ when ucs_code == 0x2028 || ucs_code == 0x2029
246
+ ESCAPE_SEQ_LB[c]
247
+ when ucs_code <= 0x7f
248
+ sprintf('\\x%.2x',ucs_code)
249
+ when ucs_code <= 0xffff
250
+ sprintf('\\u%.4x',ucs_code)
251
+ else
252
+ sprintf('\\U%.8x',ucs_code)
253
+ end
254
+ }
255
+ end
256
+
257
+ module Constants
258
+ UCS_0X85 = [0x85].pack('U') # c285@UTF8 Unicode next line
259
+ UCS_0XA0 = [0xa0].pack('U') # c2a0@UTF8 Unicode non-breaking space
260
+ UCS_0X2028 = [0x2028].pack('U') # e280a8@UTF8 Unicode line separator
261
+ UCS_0X2029 = [0x2029].pack('U') # e280a9@UTF8 Unicode paragraph separator
262
+
263
+ # non-break characters
264
+ ESCAPE_SEQ = {
265
+ "\x00" => '\\0',
266
+ "\x07" => '\\a',
267
+ "\x08" => '\\b',
268
+ "\x0b" => '\\v',
269
+ "\x0c" => '\\f',
270
+ "\x1b" => '\\e',
271
+ "\"" => '\\"',
272
+ "\\" => '\\\\',
273
+ }
274
+
275
+ # non-breaking space
276
+ ESCAPE_SEQ_NS = {
277
+ UCS_0XA0 => '\\_',
278
+ }
279
+
280
+ # white spaces
281
+ ESCAPE_SEQ_WS = {
282
+ "\x09" => '\\t',
283
+ " " => '\\x20',
284
+ }
285
+
286
+ # line breaks
287
+ ESCAPE_SEQ_LB ={
288
+ "\x0a" => '\\n',
289
+ "\x0d" => '\\r',
290
+ UCS_0X85 => '\\N',
291
+ UCS_0X2028 => '\\L',
292
+ UCS_0X2029 => '\\P',
293
+ }
294
+
295
+ # regexps for line breaks
296
+ REX_LF = Regexp.escape("\x0a")
297
+ REX_CR = Regexp.escape("\x0d")
298
+ REX_CRLF = Regexp.escape("\x0d\x0a")
299
+ REX_NEL = Regexp.escape(UCS_0X85)
300
+ REX_LS = Regexp.escape(UCS_0X2028)
301
+ REX_PS = Regexp.escape(UCS_0X2029)
302
+
303
+ REX_ANY_LB = /(#{REX_LF}|#{REX_CR}|#{REX_NEL}|#{REX_LS}|#{REX_PS})/
304
+ REX_NORMAL_LB = /(#{REX_LF}|#{REX_LS}|#{REX_PS})/
305
+
306
+ # regexps for language-Independent types for YAML1.1
307
+ REX_BOOL = /
308
+ y|Y|yes|Yes|YES|n|N|no|No|NO
309
+ |true|True|TRUE|false|False|FALSE
310
+ |on|On|ON|off|Off|OFF
311
+ /x
312
+ REX_FLOAT = /
313
+ [-+]?([0-9][0-9_]*)?\.[0-9.]*([eE][-+][0-9]+)? # (base 10)
314
+ |[-+]?[0-9][0-9_]*(:[0-5]?[0-9])+\.[0-9_]* # (base 60)
315
+ |[-+]?\.(inf|Inf|INF) # (infinity)
316
+ |\.(nan|NaN|NAN) # (not a number)
317
+ /x
318
+ REX_INT = /
319
+ [-+]?0b[0-1_]+ # (base 2)
320
+ |[-+]?0[0-7_]+ # (base 8)
321
+ |[-+]?(0|[1-9][0-9_]*) # (base 10)
322
+ |[-+]?0x[0-9a-fA-F_]+ # (base 16)
323
+ |[-+]?[1-9][0-9_]*(:[0-5]?[0-9])+ # (base 60)
324
+ /x
325
+ REX_MERGE = /
326
+ <<
327
+ /x
328
+ REX_NULL = /
329
+ ~ # (canonical)
330
+ |null|Null|NULL # (English)
331
+ | # (Empty)
332
+ /x
333
+ REX_TIMESTAMP = /
334
+ [0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9] # (ymd)
335
+ |[0-9][0-9][0-9][0-9] # (year)
336
+ -[0-9][0-9]? # (month)
337
+ -[0-9][0-9]? # (day)
338
+ ([Tt]|[ \t]+)[0-9][0-9]? # (hour)
339
+ :[0-9][0-9] # (minute)
340
+ :[0-9][0-9] # (second)
341
+ (\.[0-9]*)? # (fraction)
342
+ (([ \t]*)Z|[-+][0-9][0-9]?(:[0-9][0-9])?)? # (time zone)
343
+ /x
344
+ REX_VALUE = /
345
+ =
346
+ /x
347
+ end
348
+
349
+ include Constants
350
+
351
+ end
352
+
353
+ class Object
354
+ def ya2yaml(options = {})
355
+ Ya2YAML.new(options)._ya2yaml(self)
356
+ end
357
+ end
358
+
359
+ __END__
Binary file
@@ -0,0 +1,5 @@
1
+ ---
2
+ list:
3
+ - perl
4
+ - ruby
5
+ - python
@@ -0,0 +1,382 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # $Id: test.rb,v 1.4 2007-01-19 20:41:37+09 funai Exp funai $
4
+
5
+ $: << (File.dirname(__FILE__) + '/../lib')
6
+
7
+ Dir.chdir(File.dirname(__FILE__))
8
+
9
+ $KCODE = 'UTF8'
10
+ require 'ya2yaml'
11
+
12
+ require 'yaml'
13
+ require 'test/unit'
14
+
15
+ class TC_Ya2YAML < Test::Unit::TestCase
16
+
17
+ @@struct_klass = Struct::new('Foo',:bar,:buz)
18
+ class Moo
19
+ attr_accessor :val1,:val2
20
+ def initialize(val1,val2)
21
+ @val1 = val1
22
+ @val2 = val2
23
+ end
24
+ def ==(k)
25
+ (k.class == self.class) &&
26
+ (k.val1 == self.val1) &&
27
+ (k.val2 == self.val2)
28
+ end
29
+ end
30
+ puts "test may take minutes. please wait.\n"
31
+
32
+ def setup
33
+ @text = ''
34
+ @gif = ''
35
+ File.open('./t.yaml','r') {|f| @text = f.read}
36
+ File.open('./t.gif','r') {|f| @gif = f.read}
37
+
38
+ @struct = @@struct_klass.new('barbarbar',@@struct_klass.new('baaaar',12345))
39
+ @klass = Moo.new('boobooboo',Time.new())
40
+ end
41
+
42
+ def test_options
43
+ [
44
+ [
45
+ {},
46
+ "--- \n- \"\\u0086\"\n- |-\n a\xe2\x80\xa8 b\xe2\x80\xa9 c\n- |4-\n abc\n xyz\n",
47
+ ],
48
+ [
49
+ {:indent_size => 4},
50
+ "--- \n- \"\\u0086\"\n- |-\n a\xe2\x80\xa8 b\xe2\x80\xa9 c\n- |8-\n abc\n xyz\n",
51
+ ],
52
+ [
53
+ {:minimum_block_length => 16},
54
+ "--- \n- \"\\u0086\"\n- \"a\\Lb\\Pc\"\n- \" abc\\nxyz\"\n",
55
+ ],
56
+ # [
57
+ # {:emit_c_document_end => true},
58
+ # "--- \n- \"\\u0086\"\n- |-\n a\xe2\x80\xa8 b\xe2\x80\xa9 c\n- |4-\n abc\n xyz\n...\n",
59
+ # ],
60
+ [
61
+ {:printable_with_syck => true},
62
+ "--- \n- \"\\u0086\"\n- |-\n a\xe2\x80\xa8 b\xe2\x80\xa9 c\n- \" abc\\n\\\n xyz\"\n",
63
+ ],
64
+ [
65
+ {:escape_b_specific => true},
66
+ "--- \n- \"\\u0086\"\n- \"a\\Lb\\Pc\"\n- |4-\n abc\n xyz\n",
67
+ ],
68
+ [
69
+ {:escape_as_utf8 => true},
70
+ "--- \n- \"\\xc2\\x86\"\n- |-\n a\xe2\x80\xa8 b\xe2\x80\xa9 c\n- |4-\n abc\n xyz\n",
71
+ ],
72
+ [
73
+ {:syck_compatible => true},
74
+ "--- \n- \"\\xc2\\x86\"\n- \"a\\xe2\\x80\\xa8b\\xe2\\x80\\xa9c\"\n- \" abc\\n\\\n xyz\"\n",
75
+ ],
76
+ ].each {|opt,yaml|
77
+ y = ["\xc2\x86","a\xe2\x80\xa8b\xe2\x80\xa9c"," abc\nxyz"].ya2yaml(opt)
78
+ # puts y
79
+
80
+ assert_equal(y,yaml)
81
+ }
82
+ end
83
+
84
+ def test_hash_order
85
+ [
86
+ [
87
+ nil,
88
+ "--- \na: 1\nb: 2\nc: 3\n",
89
+ ],
90
+ [
91
+ [],
92
+ "--- \na: 1\nb: 2\nc: 3\n",
93
+ ],
94
+ [
95
+ ['c','b','a'],
96
+ "--- \nc: 3\nb: 2\na: 1\n",
97
+ ],
98
+ [
99
+ ['b'],
100
+ "--- \nb: 2\na: 1\nc: 3\n",
101
+ ],
102
+ ].each {|hash_order,yaml|
103
+ y = {
104
+ 'a' => 1,
105
+ 'c' => 3,
106
+ 'b' => 2,
107
+ }.ya2yaml(
108
+ :hash_order => hash_order
109
+ )
110
+ # p y
111
+ assert_equal(y,yaml)
112
+ }
113
+ end
114
+
115
+ def test_normalize_line_breaks
116
+ [
117
+ ["\n\n\n\n", "--- \"\\n\\n\\n\\n\"\n",],
118
+ ["\r\n\r\n\r\n", "--- \"\\n\\n\\n\"\n",],
119
+ ["\r\n\n\n", "--- \"\\n\\n\\n\"\n",],
120
+ ["\n\r\n\n", "--- \"\\n\\n\\n\"\n",],
121
+ ["\n\n\r\n", "--- \"\\n\\n\\n\"\n",],
122
+ ["\n\n\n\r", "--- \"\\n\\n\\n\\n\"\n",],
123
+ ["\r\r\n\r", "--- \"\\n\\n\\n\"\n",],
124
+ ["\r\r\r\r", "--- \"\\n\\n\\n\\n\"\n",],
125
+ ["\r\xc2\x85\r\n", "--- \"\\n\\n\\n\"\n",],
126
+ ["\r\xe2\x80\xa8\r\n","--- \"\\n\\L\\n\"\n",],
127
+ ["\r\xe2\x80\xa9\r\n","--- \"\\n\\P\\n\"\n",],
128
+ ].each {|src,yaml|
129
+ y = src.ya2yaml(
130
+ :minimum_block_length => 16
131
+ )
132
+ # p y
133
+ assert_equal(y,yaml)
134
+ }
135
+ end
136
+
137
+ def test_structs
138
+ [
139
+ [Struct.new('Hoge',:foo).new(123),"--- !ruby/struct:Hoge \n foo: 123\n",],
140
+ [Struct.new(:foo).new(123), "--- !ruby/struct: \n foo: 123\n",],
141
+ ].each {|src,yaml|
142
+ y = src.ya2yaml()
143
+ assert_equal(y,yaml)
144
+ }
145
+ end
146
+
147
+ def test_roundtrip_single_byte_char
148
+ ("\x00".."\x7f").each {|c|
149
+ y = c.ya2yaml()
150
+ # puts y
151
+ r = YAML.load(y)
152
+ assert_equal((c == "\r" ? "\n" : c),r) # "\r" is normalized as "\n".
153
+ }
154
+ end
155
+
156
+ def test_roundtrip_multi_byte_char
157
+ [
158
+ 0x80,
159
+ 0x85,
160
+ 0xa0,
161
+ 0x07ff,
162
+ 0x0800,
163
+ 0x0fff,
164
+ 0x1000,
165
+ 0x2028,
166
+ 0x2029,
167
+ 0xcfff,
168
+ 0xd000,
169
+ 0xd7ff,
170
+ 0xe000,
171
+ 0xfffd,
172
+ 0x10000,
173
+ 0x3ffff,
174
+ 0x40000,
175
+ 0xfffff,
176
+ 0x100000,
177
+ 0x10ffff,
178
+ ].each {|ucs_code|
179
+ [-1,0,1].each {|ofs|
180
+ (c = [ucs_code + ofs].pack('U')) rescue next
181
+ c_hex = c.unpack('H8')
182
+ y = c.ya2yaml(
183
+ :escape_b_specific => true,
184
+ :escape_as_utf8 => true
185
+ )
186
+ # puts y
187
+ r = YAML.load(y)
188
+ assert_equal(
189
+ [c_hex,(c =~ /\xc2\x85/u ? "\n" : c)],
190
+ [c_hex,r]
191
+ ) # "\N" is normalized as "\n".
192
+ }
193
+ }
194
+ end
195
+
196
+ def test_roundtrip_ambiguous_string
197
+ [
198
+ 'true',
199
+ 'false',
200
+ 'TRUE',
201
+ 'FALSE',
202
+ 'Y',
203
+ 'N',
204
+ 'y',
205
+ 'n',
206
+ 'on',
207
+ 'off',
208
+ true,
209
+ false,
210
+ '0b0101',
211
+ '-0b0101',
212
+ 0b0101,
213
+ -0b0101,
214
+ '031',
215
+ '-031',
216
+ 031,
217
+ -031,
218
+ '123.001e-1',
219
+ '123.01',
220
+ '123',
221
+ 123.001e-1,
222
+ 123.01,
223
+ 123,
224
+ '-123.001e-1',
225
+ '-123.01',
226
+ '-123',
227
+ -123.001e-1,
228
+ -123.01,
229
+ -123,
230
+ 'INF',
231
+ 'inf',
232
+ 'NaN',
233
+ 'nan',
234
+ '0xfe2a',
235
+ '-0xfe2a',
236
+ 0xfe2a,
237
+ -0xfe2a,
238
+ '1:23:32.0200',
239
+ '1:23:32',
240
+ '-1:23:32.0200',
241
+ '-1:23:32',
242
+ '<<',
243
+ '~',
244
+ 'null',
245
+ 'nUll',
246
+ 'Null',
247
+ 'NULL',
248
+ '',
249
+ nil,
250
+ '2006-09-12',
251
+ '2006-09-11T17:28:07Z',
252
+ '2006-09-11T17:28:07+09:00',
253
+ '2006-09-11 17:28:07.662694 +09:00',
254
+ '=',
255
+ ].each {|c|
256
+ ['','hoge'].each {|ext|
257
+ src = c.class == String ? (c + ext) : c
258
+ y = src.ya2yaml(
259
+ :escape_as_utf8 => true
260
+ )
261
+ # puts y
262
+ r = YAML.load(y)
263
+ assert_equal(src,r)
264
+ }
265
+ }
266
+ end
267
+
268
+ def test_roundtrip_string
269
+ chars = "aあ\t\-\?,\[\{\#&\*!\|>'\"\%\@\`.\\ \n\xc2\xa0\xe2\x80\xa8".split('')
270
+
271
+ chars.each {|i|
272
+ chars.each {|j|
273
+ chars.each {|k|
274
+ chars.each {|l|
275
+ src = i + j + k + l
276
+ y = src.ya2yaml(
277
+ :printable_with_syck => true,
278
+ :escape_b_specific => true,
279
+ :escape_as_utf8 => true
280
+ )
281
+ # puts y
282
+ r = YAML.load(y)
283
+ assert_equal(src,r)
284
+ }
285
+ }
286
+ }
287
+ }
288
+ end
289
+
290
+ def test_roundtrip_types
291
+ objects = [
292
+ [],
293
+ [1],
294
+ {},
295
+ {'foo' => 'bar'},
296
+ nil,
297
+ 'hoge',
298
+ "abc\nxyz\n",
299
+ "\xff\xff",
300
+ true,
301
+ false,
302
+ 1000,
303
+ 1000.1,
304
+ -1000,
305
+ -1000.1,
306
+ Date.today(),
307
+ Time.new(),
308
+ :foo,
309
+ 1..10,
310
+ /abc\nxyz/i,
311
+ @struct,
312
+ @klass,
313
+ ]
314
+
315
+ objects.each {|obj|
316
+ src = case obj.class.to_s
317
+ when 'Array'
318
+ (obj.length) == 0 ? [] : objects
319
+ when 'Hash'
320
+ if (obj.length) == 0
321
+ {}
322
+ else
323
+ h = {}
324
+ c = 0
325
+ objects.each {|val|
326
+ h[c] = {}
327
+ objects.each {|key|
328
+ h[c][key] = val unless (key.class == Hash || key.class == Moo)
329
+ }
330
+ c += 1
331
+ }
332
+ h
333
+ end
334
+ else
335
+ obj
336
+ end
337
+ y = src.ya2yaml(
338
+ :syck_compatible => true
339
+ )
340
+ # puts y
341
+
342
+ r = YAML.load(y)
343
+ assert_equal(src,r)
344
+ }
345
+ end
346
+
347
+ def test_roundtrip_various
348
+ [
349
+ [1,2,['c','d',[[['e']],[]],'f'],3,Time.new(),[[:foo]],nil,true,false,[],{},{[123,223]=>456},{[1]=>2,'a'=>'b','c' => [9,9,9],Time.new() => 'hoge'},],
350
+ [],
351
+ {[123,223]=>456},
352
+ {},
353
+ {'foo' => {1 => {2=>3,4=>5},6 => [7,8]}},
354
+ "abc",
355
+ " abc\n def\ndef\ndef\ndef\ndef\n",
356
+ "abc\n def\ndef\n",
357
+ "abc\n def\ndef\n\n",
358
+ "abc\n def\ndef\n\n ",
359
+ "abc\n def\ndef\n \n",
360
+ "abc\n def\ndef \n \n",
361
+ "abc\n def\ndef \n \n ",
362
+ ' ほげほげほげ',
363
+ {"ほげ\nほげ\n ほげ" => 123},
364
+ [["ほげ\nほげ\n ほげ"]],
365
+ "ほげh\x4fge\nほげ\nほげ",
366
+ [{'ほげ'=>'abc',"ほげ\nほげ"=>'ほげ'},'ほげ',@text],
367
+ [Date.today,-9.011,0.023,4,-5,{1=>-2,-1=>@text,'_foo'=>'bar','ぬお-ぬお'=>321}],
368
+ {1=>-2,-1=>@gif,'_foo'=>'bar','ぬお-ぬお'=>321},
369
+ ].each {|src|
370
+ y = src.ya2yaml(
371
+ :syck_compatible => true
372
+ )
373
+ # puts y
374
+
375
+ r = YAML.load(y)
376
+ assert_equal(src,r)
377
+ }
378
+ end
379
+
380
+ end
381
+
382
+ __END__
metadata ADDED
@@ -0,0 +1,57 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rkamyk-ya2yaml
3
+ version: !ruby/object:Gem::Version
4
+ version: "0.26"
5
+ platform: ruby
6
+ authors:
7
+ - Akira FUNAI
8
+ autorequire: ya2yaml
9
+ bindir: bin
10
+ cert_chain:
11
+ date: 2009-11-16 10:00:00 +01:00
12
+ default_executable:
13
+ dependencies: []
14
+
15
+ description:
16
+ email: funai.akira@gmail.com
17
+ executables: []
18
+
19
+ extensions: []
20
+
21
+ extra_rdoc_files:
22
+ - README
23
+ files:
24
+ - lib/ya2yaml.rb
25
+ - README
26
+ - LICENSE
27
+ - test/t.gif
28
+ - test/t.yaml
29
+ - test/test.rb
30
+ has_rdoc: true
31
+ homepage: http://rubyforge.org/projects/ya2yaml/
32
+ licenses: []
33
+
34
+ post_install_message:
35
+ rdoc_options:
36
+ - --main
37
+ - README
38
+ - --charset
39
+ - UTF8
40
+ require_paths:
41
+ - lib
42
+ required_ruby_version: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">"
45
+ - !ruby/object:Gem::Version
46
+ version: 0.0.0
47
+ version:
48
+ required_rubygems_version:
49
+ requirements: []
50
+
51
+ rubyforge_project:
52
+ rubygems_version: 1.3.5
53
+ signing_key:
54
+ specification_version: 1
55
+ summary: An UTF8 safe YAML dumper.
56
+ test_files:
57
+ - test/test.rb