icss 0.1.3 → 0.3.2

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.
Files changed (98) hide show
  1. data/.watchr +35 -3
  2. data/CHANGELOG.md +38 -0
  3. data/Gemfile +19 -14
  4. data/README.md +296 -0
  5. data/Rakefile +2 -6
  6. data/TODO.md +13 -0
  7. data/VERSION +1 -1
  8. data/examples/avro_examples/complicated.icss.yaml +14 -13
  9. data/examples/bnc.icss.yaml +70 -0
  10. data/examples/chronic.icss.yaml +3 -3
  11. data/examples/license.icss.yaml +7 -0
  12. data/examples/source1.icss.yaml +4 -0
  13. data/examples/source2.icss.yaml +4 -0
  14. data/examples/test_icss.yaml +67 -0
  15. data/icss.gemspec +103 -43
  16. data/lib/icss.rb +37 -15
  17. data/lib/icss/core_types.rb +19 -0
  18. data/lib/icss/error.rb +4 -0
  19. data/{init.rb → lib/icss/init.rb} +0 -0
  20. data/lib/icss/message.rb +124 -66
  21. data/lib/icss/message/message_sample.rb +144 -0
  22. data/lib/icss/protocol.rb +184 -131
  23. data/lib/icss/protocol/code_asset.rb +18 -0
  24. data/lib/icss/protocol/data_asset.rb +23 -0
  25. data/lib/icss/protocol/license.rb +41 -0
  26. data/lib/icss/protocol/source.rb +37 -0
  27. data/lib/icss/protocol/target.rb +68 -0
  28. data/lib/icss/receiver_model.rb +24 -0
  29. data/lib/icss/receiver_model/active_model_shim.rb +36 -0
  30. data/lib/icss/receiver_model/acts_as_catalog.rb +170 -0
  31. data/lib/icss/receiver_model/acts_as_hash.rb +177 -0
  32. data/lib/icss/receiver_model/acts_as_loadable.rb +47 -0
  33. data/lib/icss/receiver_model/acts_as_tuple.rb +100 -0
  34. data/lib/icss/receiver_model/locale/en.yml +27 -0
  35. data/lib/icss/receiver_model/to_geo_json.rb +19 -0
  36. data/lib/icss/receiver_model/tree_merge.rb +34 -0
  37. data/lib/icss/receiver_model/validations.rb +31 -0
  38. data/lib/icss/serialization.rb +51 -0
  39. data/lib/icss/serialization/zaml.rb +443 -0
  40. data/lib/icss/type.rb +148 -501
  41. data/lib/icss/type/base_type.rb +0 -0
  42. data/lib/icss/type/named_type.rb +184 -0
  43. data/lib/icss/type/record_field.rb +77 -0
  44. data/lib/icss/type/record_model.rb +49 -0
  45. data/lib/icss/type/record_schema.rb +54 -0
  46. data/lib/icss/type/record_type.rb +325 -0
  47. data/lib/icss/type/simple_types.rb +72 -0
  48. data/lib/icss/type/structured_schema.rb +288 -0
  49. data/lib/icss/type/type_factory.rb +144 -0
  50. data/lib/icss/type/union_schema.rb +41 -0
  51. data/lib/icss/view_helper.rb +56 -19
  52. data/notes/named_array.md +32 -0
  53. data/notes/on_include_vs_extend_etc.rb +176 -0
  54. data/notes/technical_details.md +278 -0
  55. data/spec/core_types_spec.rb +119 -0
  56. data/spec/fixtures/zaml_complex_hash.yaml +35 -0
  57. data/spec/icss_spec.rb +86 -23
  58. data/spec/message/message_sample_spec.rb +4 -0
  59. data/spec/message_spec.rb +139 -0
  60. data/spec/protocol/license_spec.rb +67 -0
  61. data/spec/protocol/protocol_catalog_spec.rb +48 -0
  62. data/spec/protocol/protocol_validations_spec.rb +176 -0
  63. data/spec/protocol/source_spec.rb +65 -0
  64. data/spec/protocol_spec.rb +91 -37
  65. data/spec/receiver_model_spec.rb +111 -0
  66. data/spec/serialization/zaml_spec.rb +81 -0
  67. data/spec/serialization/zaml_test.rb +473 -0
  68. data/spec/serialization_spec.rb +63 -0
  69. data/spec/spec_helper.rb +24 -7
  70. data/spec/support/icss_test_helper.rb +67 -0
  71. data/spec/support/load_example_protocols.rb +17 -0
  72. data/spec/type/base_type_spec.rb +0 -0
  73. data/spec/type/named_type_spec.rb +75 -0
  74. data/spec/type/record_field_spec.rb +44 -0
  75. data/spec/type/record_model_spec.rb +206 -0
  76. data/spec/type/record_schema_spec.rb +161 -0
  77. data/spec/type/record_type_spec.rb +155 -0
  78. data/spec/type/simple_types_spec.rb +121 -0
  79. data/spec/type/structured_schema_spec.rb +300 -0
  80. data/spec/type/type_catalog_spec.rb +44 -0
  81. data/spec/type/type_factory_spec.rb +93 -0
  82. data/spec/type/union_schema_spec.rb +0 -0
  83. data/spec/type_spec.rb +63 -0
  84. metadata +205 -144
  85. data/CHANGELOG.textile +0 -9
  86. data/Gemfile.lock +0 -40
  87. data/README.textile +0 -29
  88. data/lib/icss/brevity.rb +0 -136
  89. data/lib/icss/code_asset.rb +0 -16
  90. data/lib/icss/core_ext.rb +0 -9
  91. data/lib/icss/data_asset.rb +0 -22
  92. data/lib/icss/old.rb +0 -96
  93. data/lib/icss/protocol_set.rb +0 -48
  94. data/lib/icss/sample_message_call.rb +0 -142
  95. data/lib/icss/target.rb +0 -72
  96. data/lib/icss/type/factory.rb +0 -196
  97. data/lib/icss/validations.rb +0 -16
  98. data/spec/validations_spec.rb +0 -171
@@ -0,0 +1,111 @@
1
+ require File.expand_path('spec_helper', File.dirname(__FILE__))
2
+ require 'icss'
3
+ require ENV.root_path('spec/support/icss_test_helper')
4
+ include IcssTestHelper
5
+
6
+ describe Icss::ReceiverModel do
7
+ before do
8
+ IcssTestHelper.remove_icss_constants('Handy', 'UnderHandy')
9
+ class Icss::Handy < Icss::SmurfModel ; end
10
+ class Icss::UnderHandy < Icss::Handy ; end
11
+ end
12
+
13
+ context 'field validations' do
14
+ before do
15
+ Icss::Handy.field :rangey, Integer, :validates => { :inclusion => { :in => 0..9 }}
16
+ Icss::Handy.field :mandatory, Integer, :validates => { :presence => true }
17
+ Icss::Handy.field :patternish, String, :validates => { :format => { :with => /eat$/ } }
18
+ end
19
+ let(:good_smurf){ Icss::Handy.receive(:rangey => 5, :patternish => 'smurfberry crunch is fun to eat', :mandatory => 1) }
20
+ let(:bad_smurf ){ Icss::Handy.receive(:rangey => 10, :patternish => 'smurfnuggets!') }
21
+
22
+ it 'are applied, and pass when good' do
23
+ good_smurf.should be_valid
24
+ end
25
+
26
+ it 'are applied, and fail when bad' do
27
+ bad_smurf.should_not be_valid
28
+ bad_smurf.errors.should == {
29
+ :rangey => ["is not included in the list"],
30
+ :mandatory => ["can't be blank"],
31
+ :patternish => ["is invalid"]
32
+ }
33
+ bad_smurf.rangey = 3 ; bad_smurf.mandatory = 7 ; bad_smurf.patternish = "a very smurfy breakfast treat"
34
+ bad_smurf.should be_valid
35
+ bad_smurf.errors.should be_empty
36
+ end
37
+
38
+ it 'inherit' do
39
+ under_handy = Icss::UnderHandy.receive(:rangey => -1, :patternish => 'smurfberry crunch is fun to eat', :mandatory => 1)
40
+ under_handy.should_not be_valid
41
+ under_handy.errors.keys.should == [:rangey]
42
+ under_handy.rangey = 1
43
+ under_handy.should be_valid
44
+ end
45
+
46
+ it ':required => true is sugar for ":validates => { :presence => true }"' do
47
+ Icss::Handy.field :also_mandatory, Integer, :required => true
48
+ good_smurf.should_not be_valid
49
+ good_smurf.errors.should == { :also_mandatory => ["can't be blank"], }
50
+ good_smurf.also_mandatory = 88
51
+ good_smurf.should be_valid
52
+ end
53
+ end
54
+
55
+ # context ':index => ' do
56
+ # it 'primary key'
57
+ # it 'foreign key'
58
+ # it 'uniqueness constraint'
59
+ # end
60
+ #
61
+ # # context ':accessor / :reader / :writer' do
62
+ # # it ':private -- attr_whatever is private'
63
+ # # it ':protected -- attr_whatever is protected'
64
+ # # it ':none -- no accessor/reader/writer'
65
+ # # end
66
+ #
67
+ # context ':after_receive'
68
+ #
69
+ # context ':i18n_key'
70
+ # context ':human_name => '
71
+ # context ':singular_name => '
72
+ # context ':plural_name => '
73
+ # context ':uncountable => '
74
+ #
75
+ # context :serialization
76
+ # it '#serializable_hash'
77
+ #
78
+ # # constant
79
+ # # mass assignment security: accessible,
80
+ #
81
+ # it 'works on the parent Meta module type, not '
82
+ #
83
+ #
84
+ # context 'has properties' do
85
+ # it 'described by its #fields'
86
+ #
87
+ # context 'container types' do
88
+ #
89
+ # it 'field foo, Array, :items => FooClass validates instances are is_a?(FooClass)'
90
+ # it 'field foo, Array, :with => FooFactory validates instances are is_a?(FooFactory.product_klass)'
91
+ #
92
+ # it ''
93
+ #
94
+ # end
95
+ # end
96
+ #
97
+ # context 'special properties' do
98
+ # it '_domain_id_field'
99
+ # it '_primary_location_field'
100
+ # it '_slug' # ??
101
+ # end
102
+ #
103
+ # context 'name' do
104
+ # context ':i18n_key'
105
+ # context ':human_name => '
106
+ # context ':singular_name => '
107
+ # context ':plural_name => '
108
+ # context ':uncountable => '
109
+ # end
110
+
111
+ end
@@ -0,0 +1,81 @@
1
+ # -*- coding: utf-8 -*-
2
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
3
+ require 'yaml'
4
+ require 'icss/serialization/zaml'
5
+
6
+ describe ZAML do
7
+ describe '#to_zaml' do
8
+ [nil, :my_sym, true, false, 69, 69.0, /my_regexp/,
9
+ ArgumentError.new('my_exception'),
10
+ 'my_str',
11
+ {'simple' => :hash, :items => {2 => /pairs/}},
12
+ ['arr', :items, 4, /things/], Time.now, (3..69),
13
+ ].each do |obj|
14
+ it "serializes a #{obj.class}" do
15
+ obj.to_zaml.should == obj.to_yaml
16
+ end
17
+ end
18
+ end
19
+
20
+ BASIC_HASH = {
21
+ :name => "a few",
22
+ :nested => "elements",
23
+ :including => "line\nbreaking\nstrings",
24
+ :and_including => "newline terminated\nline\nbreaking\nstrings\n",
25
+ :so => ":what
26
+ :dyathink, :of, :that
27
+ "
28
+ }
29
+
30
+ def complex_hash
31
+ { 'complex' => :hash,
32
+ :items => {2 => /pairs/},
33
+ 'Iñtërnâtiônàlizætiøn' => "look out for 'funny quotes'.",
34
+ :and => [BASIC_HASH, { :name => 'bob' }, [], ],
35
+ }
36
+ end
37
+
38
+ def complex_hash_with_comments
39
+ {
40
+ ZAML::Comment.new("first comment") => 1,
41
+ 'complex' => :hash,
42
+ :items => {2 => /pairs/},
43
+ 'Iñtërnâtiônàlizætiøn' => "look out for 'funny quotes'.",
44
+ :and => [
45
+ ZAML::Comment.new("informative comments"),
46
+ BASIC_HASH,
47
+ ZAML::Comment.new("more informative comments, \nspread across\n multiple lines"),
48
+ {
49
+ :name => 'bob',
50
+ ZAML::Comment.new("comment can be in hash key, \nspread across\n multiple lines;") => :zaml_ignores_their_hash_val
51
+ },
52
+ ZAML.padding(3),
53
+ [ZAML::Comment.new("does the right thing \neven when\nis the only item")],
54
+ ],
55
+ }
56
+ end
57
+
58
+ context 'valign' do
59
+ it 'accepts an option, defaults to nil' do
60
+ obj = ZAML.new(:valign => 24)
61
+ obj.valign.should == 24
62
+ obj = ZAML.new()
63
+ obj.valign.should == nil
64
+ end
65
+
66
+ it 'aligns things' do
67
+ obj = complex_hash_with_comments
68
+ yaml_str = ZAML.dump(obj, '', :valign => 24 )
69
+ # puts yaml_str
70
+ from_yaml = YAML.load(yaml_str)
71
+ from_yaml.should == complex_hash
72
+ end
73
+
74
+ it 'matches sample' do
75
+ expected_yaml_str = File.read(ENV.root_path('spec/fixtures/zaml_complex_hash.yaml'))
76
+ yaml_str = ZAML.dump(complex_hash_with_comments, '', :valign => 24 )
77
+ # puts yaml_str
78
+ yaml_str.should == expected_yaml_str
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,473 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- encoding: utf-8 -*-
3
+
4
+ require 'test/unit'
5
+ require 'yaml'
6
+
7
+ $LOAD_PATH.unshift(File.expand_path('../../lib', File.dirname(__FILE__)))
8
+ require 'icss/serialization/zaml'
9
+
10
+ DICT_WORDS_PATH = '/usr/share/dict/words'
11
+ SLOWNESS = 0 # how acceptably slow are you willing to have the tests take
12
+
13
+ ENCODING_KLUDGE = true # YAML loads in UTF-8, causing strings to compare unequal
14
+ INDENTED_ARRAYS_KLUDGE = true # YAML is uglier about indenting arrays under hashes
15
+ YAML_DUPS_STRINGS_KLUDGE = true # YAML in 1.9 is less aggressive about referencing strings
16
+
17
+ class My_class
18
+ def initialize
19
+ @string = 'string...'
20
+ @self = self
21
+ @do_not_store_me = '*************** SHOULD NOT SHOW UP IN OUTPUT ***************'
22
+ end
23
+ def to_yaml_properties
24
+ ['@string', '@self']
25
+ end
26
+ end
27
+
28
+ class ZamlDumpTest < Test::Unit::TestCase
29
+ #
30
+ # This class and the test helper which follow embody what we mean by YAML compatibility.
31
+ # When we do a round-trip dump->load we expect
32
+ # 1) that the data from ZAML.dump will come back correctly
33
+ # 1a) all vales will be correct
34
+ # 1b) only data that should be dumped is
35
+ # 1c) object identity is preseved
36
+ # 2) if YAML.dump also works by these standards the dumped data should
37
+ # generally look like what yaml.rb produces, minus unneeded whitespace
38
+ # (trailing blanks, etc.)
39
+ class Equivalency < Hash
40
+ attr_reader :result,:message
41
+
42
+ def self.test(a,b)
43
+ new.test(a,b)
44
+ end
45
+ def test(a,b)
46
+ @result = equivalent(a,b)
47
+ self
48
+ end
49
+ def note_failure(msg)
50
+ (@message ||= '') << msg
51
+ false
52
+ end
53
+ def same_class(a,b)
54
+ (a.class == b.class) or note_failure("Saw a #{a.class} but expected a #{b.class}\n")
55
+ end
56
+ def seen_either_before(a,b)
57
+ result = (has_key?(a.object_id) or has_key?(b.object_id))
58
+ (self[a.object_id] = self[b.object_id] = size) unless result or a.is_a? Numeric
59
+ result
60
+ end
61
+ def matched_before(a,b)
62
+ (self[a.object_id] == self[b.object_id]) or note_failure("#{a.inspect} [#{a.object_id}] and #{b.inspect} [#{b.object_id}] should refer to the same object.\n")
63
+ end
64
+ def same_object(a,b)
65
+ a.object_id == b.object_id
66
+ end
67
+
68
+ def guess_mapping(a,b)
69
+ result = {}
70
+ a.delete_if{|xa| result[xa] = b.delete(xa) }
71
+ raise "Too many odd keys in a test hash to tell if the results are correct." if a.length > 1
72
+ a.each {|xa| result[xa] = b.pop }
73
+ result
74
+ end
75
+ def same_properties(a,b)
76
+ @what_we_are_looking_at ||= []
77
+ return true if @what_we_are_looking_at.include? [a.object_id,b.object_id]
78
+ @what_we_are_looking_at.push [a.object_id,b.object_id]
79
+ result =
80
+ case a
81
+ when Array
82
+ (a.length == b.length) and a.zip(b).all?{|ia,ib| equivalent(ia,ib) }
83
+ when Hash
84
+ key_map = guess_mapping(a.keys,b.keys)
85
+ a.keys.length == b.keys.length and a.keys.all? {|a_k|
86
+ b_k = key_map[a_k]
87
+ equivalent(a_k,b_k) and equivalent(a[a_k],b[b_k])
88
+ }
89
+ when Exception
90
+ equivalent(a.message,b.message)
91
+ when Time,Date,Numeric,nil,true,false,Range,Symbol,String,Regexp
92
+ a == b
93
+ else
94
+ a.to_yaml_properties.all?{|p| equivalent(a.instance_variable_get(p),b.instance_variable_get(p)) }
95
+ end or note_failure("Expected:\n #{b.inspect}\n but got:\n #{a.inspect}\n")
96
+ @what_we_are_looking_at.pop
97
+ result
98
+ end
99
+ def equivalent(a,b)
100
+ if seen_either_before(a,b) then matched_before(a,b) else
101
+ (same_object(a,b) or (same_class(a,b) and same_properties(a,b))) ; end
102
+ end
103
+ end
104
+ def stripped(x)
105
+ x.gsub(/ +$/,'').chomp.chomp.gsub(/\n+/,"\n")
106
+ end
107
+ def dump_test(obj)
108
+ z_load = YAML.load(z_dump = ZAML.dump(obj)) rescue "ZAML produced something YAML can't load."
109
+ y_load = YAML.load(y_dump = YAML.dump(obj)) rescue "YAML failed to eat it's own dogfood"
110
+ context = {}
111
+ if ENCODING_KLUDGE && (RUBY_VERSION >= "1.9")
112
+ if obj.respond_to?(:encoding) && z_load.respond_to?(:force_encoding) then z_load.force_encoding(obj.encoding) ; end
113
+ end
114
+ test = Equivalency.test(z_load,obj)
115
+ assert_block("Reload discrepancy:\n#{test.message}\nZAML:\"\n#{z_dump}\"\nYAML:\"\n#{y_dump}\"\n\n") { test.result }
116
+ if Equivalency.test(y_load,obj).result and (not obj.is_a? String) and ($skip_text_compare != :skip)
117
+ assert_equal stripped(y_dump), stripped(z_dump), "Dump discrepancy"
118
+ end
119
+ end
120
+
121
+ #
122
+ # dump tests
123
+ #
124
+
125
+ def test_dump_object
126
+ dump_test(Object.new)
127
+ dump_test(My_class.new)
128
+ end
129
+
130
+ def test_dump_nil
131
+ dump_test(nil)
132
+ end
133
+ def test_dump_symbol
134
+ dump_test(:sym)
135
+ end
136
+ def test_dump_true
137
+ dump_test(true)
138
+ end
139
+ def test_dump_false
140
+ dump_test(false)
141
+ end
142
+ def test_dump_numeric
143
+ dump_test(1)
144
+ dump_test(1.1)
145
+ end
146
+ def test_dump_exception
147
+ dump_test(Exception.new('error message'))
148
+ dump_test(ArgumentError.new('error message'))
149
+ end
150
+ def test_dump_regexp
151
+ dump_test(/abc/)
152
+ dump_test(/a.*(b+)/im)
153
+ end
154
+ def test_dump_time
155
+ dump_test(Time.now)
156
+ end
157
+ def test_dump_date
158
+ dump_test(Date.strptime('2008-08-08'))
159
+ end
160
+ def test_dump_range
161
+ dump_test(1..10)
162
+ dump_test('a'...'b')
163
+ end
164
+
165
+ def test_dump_short_strings
166
+ #
167
+ every_character = (0..255).collect{|n| n.chr }
168
+ letters = 'a'..'z'
169
+ some_characters = (0..127).collect{|n| n.chr } - ('A'..'Z').to_a - ('b'..'z').to_a - ('1'..'9').to_a
170
+ fewer_characters = some_characters - every_character[1..31] + ["\n","\r","\t","\e"] - [127.chr,128.chr]
171
+ #
172
+ every_character.each{|c1| dump_test c1 }
173
+ every_character.each{|c1| dump_test "> "+c1 }
174
+ every_character.each_with_index{|c1,idx|
175
+ every_character.each{|c2| dump_test c1+c2 }
176
+ if idx % 16 == 0 then print ',' ; $stdout.flush ; end
177
+ } if SLOWNESS >= 1
178
+
179
+ letters.each{|c1|
180
+ letters.each{|c2|
181
+ print c1,c2,' ',8.chr*3
182
+ STDOUT.flush
183
+ letters.each{|c3|
184
+ dump_test c1+c2+c3
185
+ letters.each{|c4| dump_test c1+c2+c3+c4 }
186
+ }
187
+ }
188
+ GC.start
189
+ } if SLOWNESS >= 2 #slow
190
+ some_characters.each{|c1|
191
+ some_characters.each{|c2|
192
+ print((c1+c2).inspect,' ',8.chr*((c1+c2).inspect.length+8))
193
+ STDOUT.flush
194
+ some_characters.each{|c3|
195
+ some_characters.each{|c4| dump_test c1+c2+c3+c4 }
196
+ }
197
+ GC.start
198
+ }
199
+ } if SLOWNESS >= 3 #slower
200
+ fewer_characters.each{|c1|
201
+ fewer_characters.each{|c2|
202
+ print((c1+c2).inspect,' ',8.chr*((c1+c2).inspect.length+8))
203
+ STDOUT.flush
204
+ fewer_characters.each{|c3|
205
+ fewer_characters.each{|c4|
206
+ fewer_characters.each{|c5| dump_test c1+c2+c3+c4+c5 }
207
+ }
208
+ GC.start
209
+ }
210
+ }
211
+ } if SLOWNESS >= 4 #very slow
212
+ end
213
+
214
+ def test_system_dict_words
215
+ number_of_dict_words_to_test = 10**( SLOWNESS + 2 )
216
+ File.readlines(DICT_WORDS_PATH).take(number_of_dict_words_to_test).each{|w| dump_test w.chomp } if File.exists?(DICT_WORDS_PATH)
217
+ end
218
+
219
+ def test_dump_tricky_strings
220
+ dump_test("")
221
+ dump_test("#")
222
+ dump_test("!")
223
+ dump_test("~")
224
+ dump_test("=")
225
+ dump_test("\n")
226
+ dump_test("\n0")
227
+ dump_test("\n!")
228
+ dump_test("##")
229
+ dump_test("###")
230
+ dump_test("2:7")
231
+ dump_test("1:1 x")
232
+ dump_test(">")
233
+ dump_test(">>")
234
+ dump_test("> >")
235
+ dump_test("> !")
236
+ dump_test(">++ !")
237
+ dump_test(">0+ !")
238
+ dump_test("| |")
239
+ dump_test("0:0")
240
+ dump_test("1:2:3")
241
+ dump_test("+1:2:3")
242
+ dump_test("1:-2:+3")
243
+ dump_test("%.:.")
244
+ dump_test("%.:/")
245
+ dump_test("!\n")
246
+ dump_test("!\n\n")
247
+ dump_test("!\n\n\n\n ")
248
+ dump_test("!\n\n\n\n \n")
249
+ dump_test("!\n\n\n\n \n\n\n")
250
+ dump_test("!\n\n\n\n \n\n\r")
251
+ dump_test("!\n\n\n\n \n\n ")
252
+ dump_test("\n")
253
+ dump_test("\n\n")
254
+ dump_test("\n\n\n")
255
+ dump_test("\n\n\n\n ")
256
+ dump_test("\n\n\n\n \n")
257
+ dump_test(" ")
258
+ dump_test(" \r")
259
+ dump_test("\n\n\n\n \n\n\r")
260
+ dump_test("\n\n\n\n \n\n ")
261
+ end
262
+
263
+ def test_dump_string
264
+ dump_test('str')
265
+ dump_test(" leading and trailing whitespace ")
266
+ dump_test("a string \n with newline")
267
+ dump_test("a string with 'quotes'")
268
+ dump_test("a string with \"double quotes\"")
269
+ dump_test("a string with \\ escape")
270
+ dump_test("a really long string" * 10)
271
+ dump_test("a really long string \n with newline" * 10)
272
+ dump_test("a really long string with 'quotes'" * 10)
273
+ dump_test("a really long string with \"double quotes\"" * 10)
274
+ dump_test("a really long string with \\ escape" * 10)
275
+ dump_test("string with binary data \x00 \x01 \x02")
276
+ dump_test(" funky\n test\n")
277
+ dump_test('"')
278
+ dump_test("'")
279
+ dump_test('\\')
280
+ dump_test("k: v")
281
+ dump_test(":goo")
282
+ dump_test("? foo")
283
+ dump_test("{khkjh}")
284
+ dump_test("[ha]")
285
+ dump_test("- - (text) - -")
286
+ dump_test("\n\n \n \n x\n y\n z\n!\n")
287
+ end
288
+
289
+ def test_dump_strings_that_resemble_literals
290
+ dump_test("true")
291
+ dump_test("false")
292
+ dump_test("null")
293
+ dump_test("yes")
294
+ dump_test("no")
295
+ dump_test("on")
296
+ dump_test("off")
297
+ dump_test("nil")
298
+ dump_test("3")
299
+ dump_test("3.14")
300
+ dump_test("1e-6")
301
+ dump_test("0x345")
302
+ dump_test("-0x345")
303
+ dump_test("1e5")
304
+ end
305
+
306
+ STR = 'happy_str'
307
+
308
+ HASH = {
309
+ :nil => nil,
310
+ :sym => :value,
311
+ :true => true,
312
+ :false => false,
313
+ :int => 100,
314
+ :float => 1.1,
315
+ :regexp => /abc/,
316
+ STR => 'value',
317
+ :range => 1..10
318
+ }
319
+ ARRAY = [ nil, :sym, true, false, 100, 1.1, /abc/, STR, 1..10 ]
320
+
321
+ #
322
+ # hash
323
+ #
324
+
325
+ def test_dump_simple_hash
326
+ dump_test({:key => 'value'})
327
+ end
328
+ def test_dump_hash
329
+ dump_test(HASH)
330
+ end
331
+ def test_dump_simple_nested_hash
332
+ $skip_text_compare = :skip if INDENTED_ARRAYS_KLUDGE
333
+ dump_test({:hash => {:key => 'value'}, :array => [1,2,3]})
334
+ $skip_text_compare = false
335
+ end
336
+ def test_dump_nested_hash
337
+ $skip_text_compare = :skip if INDENTED_ARRAYS_KLUDGE
338
+ dump_test(HASH.merge(:hash => {:hash => {:key => 'value'}}, :array => [[1,2,3]]))
339
+ $skip_text_compare = false
340
+ end
341
+
342
+ # def test_dump_self_referential_hash
343
+ # array = ARRAY + [ARRAY]
344
+ # dump_test(HASH.merge(:hash => HASH, :array => array))
345
+ # end
346
+
347
+ def test_dump_self_referential_hash
348
+ if YAML_DUPS_STRINGS_KLUDGE
349
+ array = ARRAY.dup ; hsh = HASH.dup
350
+ array.delete(STR) ; hsh.delete(STR)
351
+ dump_test(hsh.merge(:hash => hsh, :array => (array + [ array ])))
352
+ else
353
+ array = ARRAY + [ARRAY]
354
+ dump_test(HASH.merge(:hash => HASH, :array => array))
355
+ end
356
+ end
357
+
358
+ def test_dump_singlular_self_referential_hash
359
+ hash = {}
360
+ hash[hash] = hash
361
+ dump_test(hash)
362
+ end
363
+ def test_dump_hash_value_with_colon
364
+ hash = { 'a' => 'a value:', 'b' => 'b value' }
365
+ dump_test(hash)
366
+ end
367
+
368
+ #
369
+ # array
370
+ #
371
+
372
+ def test_dump_simple_array
373
+ dump_test([1,2,3])
374
+ end
375
+ def test_dump_array
376
+ dump_test(ARRAY)
377
+ end
378
+ def test_dump_simple_nested_array
379
+ dump_test([{:key => 'value'}, [1,2,3]])
380
+ end
381
+ def test_dump_nested_array
382
+ $skip_text_compare = :skip if INDENTED_ARRAYS_KLUDGE
383
+ dump_test(ARRAY.concat([{:array => [1,2,3]}, [[1,2,3]]]))
384
+ $skil_text_compare = false
385
+ end
386
+
387
+ def test_dump_self_referential_array
388
+ if YAML_DUPS_STRINGS_KLUDGE
389
+ arr = ARRAY.dup ; hsh = HASH.dup
390
+ arr.delete(STR) ; hsh.delete(STR)
391
+ array = arr + [arr, hsh.merge(:hash => hsh)]
392
+ dump_test(array)
393
+ else
394
+ array = ARRAY + [ARRAY, HASH.merge(:hash => HASH)]
395
+ dump_test(array)
396
+ end
397
+ end
398
+
399
+ def test_dump_singlular_self_referential_array
400
+ array = []
401
+ array << array
402
+ dump_test(array)
403
+ end
404
+
405
+ #
406
+ # dump various data tests
407
+ #
408
+
409
+ my_range = 7..13
410
+ my_obj = My_class.new
411
+ my_dull_object = Object.new
412
+ my_bob = 'bob'
413
+ my_exception = Exception.new("Error message")
414
+ my_runtime_error = RuntimeError.new("This is a runtime error exception")
415
+ wright_joke = %q{
416
+
417
+ I was in the grocery store. I saw a sign that said "pet supplies".
418
+
419
+ So I did.
420
+
421
+ Then I went outside and saw a sign that said "compact cars".
422
+
423
+ -- Steven Wright
424
+ }
425
+ a_box_of_cheese = [:cheese]
426
+ DATA = [1, my_range, my_obj, my_bob, my_dull_object, 2, 'test', " funky\n test\n", true, false,
427
+ {my_obj => 'obj is the key!'},
428
+ {:bob => 6.8, :sam => 9.7, :subhash => {:sh1 => 'one', :sh2 => 'two'}},
429
+ 6, my_bob, my_obj, my_range, 'bob', 1..10, 0...8]
430
+ MORE_DATA = [{
431
+ :a_regexp => /a.*(b+)/im,
432
+ :an_exception => my_exception,
433
+ :a_runtime_error => my_runtime_error,
434
+ :a_long_string => wright_joke}
435
+ ]
436
+ NESTED_ARRAYS = [
437
+ [:one, 'One'],
438
+ [:two, 'Two'],
439
+ a_box_of_cheese,
440
+ [:three, 'Three'],
441
+ [:four, 'Four'],
442
+ a_box_of_cheese,
443
+ [:five, 'Five'],
444
+ [:six, 'Six']
445
+ ]
446
+ COMPLEX_DATA = {
447
+ :data => DATA,
448
+ :more_data => MORE_DATA,
449
+ :nested_arrays => NESTED_ARRAYS
450
+ }
451
+
452
+ def test_dump_DATA
453
+ dump_test(DATA)
454
+ end
455
+ def test_dump_MORE_DATA
456
+ dump_test(MORE_DATA)
457
+ end
458
+ def test_dump_NESTED_ARRAYS
459
+ dump_test(NESTED_ARRAYS)
460
+ end
461
+ def test_dump_COMPLEX_DATA
462
+ dump_test(COMPLEX_DATA)
463
+ end
464
+ def test_indentation_array_edge_cases
465
+ dump_test({[]=>[]})
466
+ dump_test([[]])
467
+ dump_test([[[],[]]])
468
+ end
469
+ def test_string_identity
470
+ a = 'str'
471
+ dump_test([a,a])
472
+ end
473
+ end