diff --git a/doc/features.md b/doc/features.md new file mode 100644 index 0000000..9581dad --- /dev/null +++ b/doc/features.md @@ -0,0 +1,181 @@ +# Features + +SIXX is a multi-platform XML serializer/deserializer for Smalltalk. You can exchange various Smalltalk objects among different (dialect) images. + +## How to use + +### Basic writing/reading + +SIXX is very easy to use. Like #storeString, You can generate a SIXX string by #sixxString. + +```smalltalk +array := Array with: 1 with: 'Hello' with: Date today. +array sixxString. +``` + +This code generates the following SIXX string: + +```xml +' + 1 + Hello + 16 June 2002 +' +``` + +This string can be read by #readSixxFrom:. + +```smalltalk +Object readSixxFrom: sixxString. "sixxString is the above string" +``` + +### Stream writing/reading + +SixxWriteStream and SixxReadStream are provided so that you can write/read Smalltalk objects in a way similar to binary object stream (BOSS in VW, and the ReferenceStream in Squeak). + +In order to write objects to an external file, you can: + +```smalltalk +sws := SixxWriteStream newFileNamed: 'obj.sixx'. +sws nextPut: object. "an object" +sws nextPutAll: objects. "collection of objects" +sws close. +``` + +And to read objects from an external file: + +```smalltalk +srs := SixxReadStream readOnlyFileNamed: 'obj.sixx'. +objects := srs contents. +srs close. +``` + +### SIXX hooks + +#### Customizing serialization + +| Hook method | Description | +| --------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Object>>sixxPrepareWrite | It is called before the instance is written in SIXX. | +| Object>>sixxWriteValue | Return the object actually serialized. | +| Object>>sixxIgnorableInstVarNames | Specify the instance variables that are not written in SIXX. | +| Object>>sixxNonReferencableInstVarNames | Specify the instance variables that should not be referenced in SIXX. Values are always written redundantly. It is useful for small literal objects like String, Number, etc. | +| Object>>sixxReferenceIdInContext: | Return unique id that can be referenced from other objects in SIXX. It is useful when objects have their own unique id. | + +#### Customizing deserialization + +| Hook method | Description | +| ---------------------- | ---------------------------------------------------------------- | +| Object>>sixxInitialize | It is called immediately after the instance is read from SIXX | +| Object>>sixxReadValue | Return the object for the client from the deserialized instance. | + +### ShapeChanger + +SixxShapeChangeReadStream enables you to read class shape changed instances. It supports renamed, removed and newly added instance variables. + +```smalltalk +srs := SixxShapeChangeReadStream on: oldSixx readStream. +srs shapeChangers at:#SmallIntegerOLD put: SmallInteger . "simple renaming" + +srs shapeChangers at: #SixxShapeChangedObject put: SixxMockShapeChanger. +"You can implement ShapeChanger for more complex conversion. " +``` + +To define a new ShapeChanger, you should subclass base ShapeChanger class and override three methods. + +| Hook method | Description | +| ------------------------------------------------------ | ------------------------------------------------------------------------------------- | +| YourShapeChanger>>shapeChangedObjectClass | Return a newly introduced class for old instances. | +| YourShapeChanger>>sixxInstVarNamed: varName put: value | Override this method for setting converted values to the shape changed object. | +| YourShapeChanger>>initializeShapeChangedObject | Override this method for setting newly introduced values to the shape changed object. | + +For example: (YourShapeChanger>>sixxInstVarNamed: varName put:) + +```smalltalk +sixxInstVarNamed: varName put: value + "#oldNamedVar1 inst var was renamed to #renamedAtt1" + varName == #oldNamedVar1 ifTrue: [^self attributesMap at: #renamedAtt1 put: value]. + + "#oldNamedVar2 inst var was removed." + varName == #oldNamedVar2 ifTrue: [^self]. + + super sixxInstVarNamed: varName put: value +``` + +From SIXX 0.3, you can apply ShapeChanger(s) without using SixxShapeChangeReadStream. + +```smalltalk +obj := SixxContext evaluate: [Object readSixxFrom: oldSixx] shapeChangersBy: [:shapeChangers | shapeChangers at: #SixxShapeChangedObject put: SixxSomeShapeChanger]. +``` + +### Formatter + +Formatter is a new SIXX function for customizing SIXX format without subclassing. + +Normally, you can customize SIXX serialization format by overriding hooks such as #sixxWriteValue, #sixxIgnorableInstVarNames. However, sometimes you would like to customize serialization format more dynamically. +For example, you may want to change default Array serialization format to compact one, if the array includes only primitive (literal) elements. + +Suppose there is an array like: + +```smalltalk +array := #(1 2 3 4 5). +``` + +By default, the array will be serialized if you evaluate: + +```smalltalk +array sixxString. "print it" +``` + +```xml +' + 1 + 2 + 3 + 4 + 5 +' +``` + +This format is reasonable for supporting complex array, but the format could be space-consuming if the array contains only primitive (literal) elements. By setting a Formatter, you can use more compact format for Array. + +```smalltalk +SixxContext formatters: {SixxMockLiteralArrayFormatter on: Array}. +``` + +After that, the format will be: + +```xml +' + #(1 2 3 4 5) +' +``` + +You can reset the formatter by: + +```smalltalk +SixxContext resetFormatters. +``` + +For convenience, there is a method to switch formatter temporarily. + +```smalltalk +SixxContext applyFormatters: {SixxMockLiteralArrayFormatter on: Array} while: [ +array sixxString. +] +``` + +Or, you can even use: + +```smalltalk +SixxContext evaluate: [array sixxString] formattersBy: [:formatters | formatters add: (SixxMockLiteralArrayFormatter on: Array)]. +``` + +In short, Formatter can be used: + +- For customizing SIXX format dynamically. +- For overriding SIXX format of the existing classes temporarily.