1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
15 # Refine `Serializable::inspect` to show more useful information
18 import serialization_core
19 private import caching
21 private fun inspect_testing
: Bool do return "NIT_TESTING".environ
== "true"
23 # Serialization engine writing the object attributes to strings
24 private class InspectSerializer
25 super CachingSerializer
27 # Target writing stream
30 redef var current_object
= null
32 var first_object
: nullable Object = null
34 redef fun serialize
(object
)
36 if object
== null then
39 if current_object
== null then
43 var last_object
= current_object
44 current_object
= object
45 object
.accept_inspect_serializer
self
46 current_object
= last_object
50 var first_attribute_serialized
= false
52 redef fun serialize_attribute
(name
, value
)
54 if first_attribute_serialized
then
58 first_attribute_serialized
= true
67 redef fun serialize_reference
(object
)
69 if cache
.has_object
(object
) then
71 var id
= object
.object_id
72 if inspect_testing
then id
= cache
.id_for
(object
)
75 stream
.write object
.class_name
79 else if object
!= first_object
and (not object
isa DirectSerializable) then
80 # Another object, print class and id only
81 var id
= object
.object_id
82 if inspect_testing
then id
= cache
.new_id_for
(object
)
85 stream
.write object
.class_name
96 redef class Serializable
98 # Improve the default inspection reading serializable attributes
100 # Simple immutable data are inspected as they would be written in Nit code.
103 # assert 123.inspect == "123"
104 # assert 1.5.inspect == "1.5"
105 # assert 0xa1u8.inspect == "0xa1u8"
106 # assert 'c'.inspect == "'c'"
107 # assert "asdf\n".inspect == "\"asdf\\n\""
110 # Inspections of mutable serializable objects show their dynamic type,
111 # their `object_id` and their first level attributes. When testing,
112 # the `object_id` is replaced by an id unique to each call to `inspect`.
119 # var o: nullable Object
122 # var class_with_null = new MyClass(123)
123 # assert class_with_null.to_s == class_with_null.inspect
124 # assert class_with_null.to_s == "<MyClass#0 i:123, o:null>"
126 # var class_with_other = new MyClass(456, class_with_null)
127 # assert class_with_other.to_s == "<MyClass#0 i:456, o:<MyClass#1>>"
129 # var class_with_cycle = new MyClass(789)
130 # class_with_cycle.o = class_with_cycle
131 # assert class_with_cycle.to_s == "<MyClass#0 i:789, o:<MyClass#0>>"
134 # Items of collections are flattened and appended to the output.
137 # assert [1, 2, 3].inspect == "<Array[Int]#0 [1, 2, 3]>"
139 # var set = new HashSet[Object].from([1, 1.5, "two": Object])
140 # assert set.inspect == """<HashSet[Object]#0 [1, 1.5, "two"]>"""
142 # var map = new Map[Int, String]
145 # assert map.inspect == """<HashMap[Int, String]#0 {1:"one", 2:"two"}>"""
148 # Inspections producing over 80 characters are cut short.
151 # var long_class = new MyClass(123456789, "Some " + "very "*8 + "long string")
152 # assert long_class.to_s == "<MyClass#0 i:123456789, o:\"Some very very very very very very very very long s…>"
156 var stream
= new StringWriter
157 var serializer
= new InspectSerializer(stream
)
158 serializer
.serialize
self
160 var str
= stream
.to_s
164 if str
.length
> max_length
then
165 str
= str
.substring
(0, max_length-2
) + "…>"
171 private fun accept_inspect_serializer
(v
: InspectSerializer)
175 v
.stream
.write class_name
179 if inspect_testing
then id
= v
.cache
.new_id_for
(self)
180 v
.stream
.write id
.to_s
182 accept_inspect_serializer_core v
187 private fun accept_inspect_serializer_core
(v
: InspectSerializer)
188 do v
.serialize_core
(self)
192 redef fun accept_inspect_serializer
(v
) do v
.stream
.write to_s
196 redef fun accept_inspect_serializer
(v
) do v
.stream
.write to_s
200 redef fun accept_inspect_serializer
(v
) do v
.stream
.write to_s
204 redef fun accept_inspect_serializer
(v
)
207 v
.stream
.write to_s
.escape_to_nit
213 redef fun accept_inspect_serializer
(v
)
221 redef fun accept_inspect_serializer_core
(v
)
224 v.stream.write to_s.escape_to_nit
225 v.stream.write_char '"'
231 redef fun accept_inspect_serializer(v)
234 v.stream.write escape_to_nit
239 redef class Collection[E]
240 private fun serialize_as_inspect(v: InspectSerializer)
251 if not v.try_to_serialize(e) then
253 v.stream.write e.inspect
260 redef class SimpleCollection[E]
261 redef fun accept_inspect_serializer_core(v)
264 serialize_as_inspect v
268 redef class Map[K, V]
269 redef fun accept_inspect_serializer_core(v)
274 for key, val in self do
279 if not v.try_to_serialize(key) then
281 v.stream.write key.inspect
286 if not v.try_to_serialize(val) then
288 v.stream.write val.inspect