core/stx_goodies_xtreams_core.st
author Martin Kobetic
Sun, 17 Nov 2013 00:22:31 -0500
changeset 144 e193a6772be4
parent 129 6336404a548f
permissions -rw-r--r--
merging
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
55
e44717ae3e6c packaging
mkobetic
parents:
diff changeset
     1
"{ Package: 'stx:goodies/xtreams/core' }"
e44717ae3e6c packaging
mkobetic
parents:
diff changeset
     2
e44717ae3e6c packaging
mkobetic
parents:
diff changeset
     3
LibraryDefinition subclass:#stx_goodies_xtreams_core
e44717ae3e6c packaging
mkobetic
parents:
diff changeset
     4
	instanceVariableNames:''
e44717ae3e6c packaging
mkobetic
parents:
diff changeset
     5
	classVariableNames:''
e44717ae3e6c packaging
mkobetic
parents:
diff changeset
     6
	poolDictionaries:''
e44717ae3e6c packaging
mkobetic
parents:
diff changeset
     7
	category:'* Projects & Packages *'
e44717ae3e6c packaging
mkobetic
parents:
diff changeset
     8
!
e44717ae3e6c packaging
mkobetic
parents:
diff changeset
     9
85
mkobetic
parents: 74
diff changeset
    10
stx_goodies_xtreams_core comment:'Xtreams is a generalized stream/iterator framework providing simple, unified API for reading from various kinds of *sources* and writing into various kinds of *destinations* (Collections, Sockets, Files, Pipes, etc). Streams themselves can be sources or destinations as well, allowing to *stack* streams on top of each other. At the bottom of such stack is some kind of non-stream (e.g. a collection), we will call it a *terminal*. Directly above it is a specialized stream providing a streaming facade over the terminal. The rest of the streams in the stack we''ll call *transforms*. Their primary purpose is to perform some kind of transformation on the elements that are passing through. Application code interacts with the top stream of the stack the same way it would with any other stream (or stream stack) producing/consuming the same elements. The goal of the framework is to provide consistent behavior of different stacks so that the application code can treat them the same way regardless of what exactly is the ultimate source or destination. For example an application analyzing binary data should be able to treat the source stream the same way if it is a simple stream over a ByteArray or if it is a stack providing contents of a specific binary part of a mulitpart, gziped and chunked HTTP response coming through a socket. Xtreams is an attempt to achieve this goal in a scalable and efficient manner.
mkobetic
parents: 74
diff changeset
    11
mkobetic
parents: 74
diff changeset
    12
Note that the sequence of streams in a stack cannot be completely arbitrary. Each transform constrains the type of input it accepts and the type of output it produces. Since the adjacent streams in a stack are linked so that input of one is connected to the output of the other, they need to produce/consume same type of elements . For example, a "character encoding" read transform converting bytes to characters can only sit on top of a stream that produces bytes (0..255). These constraints are not checked when the stack is being constructed, it is up to the application code to make sure the streams in the stack are compatible with their adjacent streams.
mkobetic
parents: 74
diff changeset
    13
mkobetic
parents: 74
diff changeset
    14
The framework is split into several packages:
mkobetic
parents: 74
diff changeset
    15
|| *Package Xtreams-*                           ||      *Notes* ||
mkobetic
parents: 74
diff changeset
    16
|| [Core]                       ||      Defines the API and core classes        ||
mkobetic
parents: 74
diff changeset
    17
|| [Terminals]          ||      Streams for all supported terminals (Collections, Blocks, Files, Sockets, Pipes, etc) ||
mkobetic
parents: 74
diff changeset
    18
|| [Transforms] ||      Core transform streams (collection style, encodings, marshaling, etc) ||
mkobetic
parents: 74
diff changeset
    19
|| [Substreams] ||      Streams embedded in other streams, slicing and stitching streams ||
mkobetic
parents: 74
diff changeset
    20
|| [Multiplexing]       ||      A substreaming protocol for sharing a paired read/write stream ||
109
9587e2df7029 Merged in latest version
Jan Vrany <jan.vrany@fit.cvut.cz>
parents: 106
diff changeset
    21
|| [Crypto]             ||      Cryptographic transforms (hashing, encryption, etc) ||
9587e2df7029 Merged in latest version
Jan Vrany <jan.vrany@fit.cvut.cz>
parents: 106
diff changeset
    22
|| [Xtras]                      ||      Additional non-core transforms (e.g. compression) ||
85
mkobetic
parents: 74
diff changeset
    23
|| [Parsing]            ||      PEG parsing for Xtreams with a collection of parsers/generators (PEG, Smalltalk, Javascript, Wiki, etc) ||
mkobetic
parents: 74
diff changeset
    24
mkobetic
parents: 74
diff changeset
    25
mkobetic
parents: 74
diff changeset
    26
        == Stream Creation ==
mkobetic
parents: 74
diff changeset
    27
mkobetic
parents: 74
diff changeset
    28
Xtreams strictly separate read and write streams. This allows for simpler API with better consistency. If necessary it would be quite simple to create a wrapper that holds a separate read and write stream and dispatches the read operations to one and write operations to the other.
mkobetic
parents: 74
diff changeset
    29
mkobetic
parents: 74
diff changeset
    30
Streams are primarily created by messages with -ing suffix on the first keyword (it often is a simple unary message). A read stream on top of an arbitrary *source* terminal is created by sending message #reading to it. The source can be a collection, an IOAccessor (socket, pipe), aFilename, etc. For an exhaustive list of supported types of sources see package Xtreams-Terminals. If #reading is sent to a read stream, the same stream is returned.
mkobetic
parents: 74
diff changeset
    31
mkobetic
parents: 74
diff changeset
    32
Similarly, a write stream is created by sending #writing to a *destination* terminal. Generally the same kinds of objects can serve as sources or destinations, Xtreams-Terminals provides further details on what those are. Message #writing sent to a write stream returns the same stream.
mkobetic
parents: 74
diff changeset
    33
mkobetic
parents: 74
diff changeset
    34
mkobetic
parents: 74
diff changeset
    35
        == Basic Operations ==
mkobetic
parents: 74
diff changeset
    36
mkobetic
parents: 74
diff changeset
    37
Here are few simple examples showing equivalent code in classic streams and xtreams:
mkobetic
parents: 74
diff changeset
    38
{{{
mkobetic
parents: 74
diff changeset
    39
        "classic"       ''hello world'' readStream next: 5.
mkobetic
parents: 74
diff changeset
    40
        "xtreams"       ''hello world'' reading read: 5.
mkobetic
parents: 74
diff changeset
    41
}}}
mkobetic
parents: 74
diff changeset
    42
{{{
mkobetic
parents: 74
diff changeset
    43
        "classic"       String new writeStream nextPutAll: ''hello''; contents
mkobetic
parents: 74
diff changeset
    44
        "xtreams"       String new writing write: ''hello''; close; terminal
mkobetic
parents: 74
diff changeset
    45
}}}
mkobetic
parents: 74
diff changeset
    46
Nothing terribly surprising here, just some API changes. Note that xtreams do not provide the #contents message. It''s a read operation and as such it doesn''t really fit a write stream. Consequently it only works in specific circumstances (e.g. above), but not in a case like this for example:
mkobetic
parents: 74
diff changeset
    47
{{{
mkobetic
parents: 74
diff changeset
    48
        (ByteArray new withEncoding: #ascii) writeStream nextPutAll: ''Hello''; contents
mkobetic
parents: 74
diff changeset
    49
}}}
mkobetic
parents: 74
diff changeset
    50
Instead, in Xtreams, if you close a write stream on a collection it will trim the underlying collection down to the actual content. So the collection itself corresponds to stream #contents after closing. This provides equivalent capability within the constraints of generally applicable write stream API. Message #terminal can be used to retrieve the underlying terminal from a stream or stream stack. Message #conclusion can be used as a convenient shortcut combining #close and #terminal together.
mkobetic
parents: 74
diff changeset
    51
mkobetic
parents: 74
diff changeset
    52
Here''s a rough correspondence table of the most common API
mkobetic
parents: 74
diff changeset
    53
mkobetic
parents: 74
diff changeset
    54
||      *classic*                       ||      *xtreams*                               ||
mkobetic
parents: 74
diff changeset
    55
||      next                                    ||      get                                             ||
mkobetic
parents: 74
diff changeset
    56
||      nextPut:                                ||      put:                                            ||
mkobetic
parents: 74
diff changeset
    57
||      next:                           ||      read:                                   ||
mkobetic
parents: 74
diff changeset
    58
||      next:into:startingAt:   ||      read:into:/read:into:at:                ||
mkobetic
parents: 74
diff changeset
    59
||      nextPutAll:                     ||      write:                                  ||
mkobetic
parents: 74
diff changeset
    60
||      next:putAll:startingAt: ||      write:from:/write:from:at:      ||
mkobetic
parents: 74
diff changeset
    61
||      upToEnd                 ||      rest                                            ||
mkobetic
parents: 74
diff changeset
    62
||      skip:                           ||      ++                                              ||
mkobetic
parents: 74
diff changeset
    63
mkobetic
parents: 74
diff changeset
    64
mkobetic
parents: 74
diff changeset
    65
        == Stream Copying ==
mkobetic
parents: 74
diff changeset
    66
mkobetic
parents: 74
diff changeset
    67
Another useful difference is that read streams can be used as arguments of write: and write:from:. This provides a simple and efficient way of copying from stream to stream. Providing this capability at the API level allows for interesting optimizations, for example copying between two collection streams will eventually boil down to a single copy operation between the underlying collections. So the classic (slow) stream copying pattern
mkobetic
parents: 74
diff changeset
    68
{{{
mkobetic
parents: 74
diff changeset
    69
        source := ''Hello World'' readStream.
mkobetic
parents: 74
diff changeset
    70
        destination := String new writeStream.
mkobetic
parents: 74
diff changeset
    71
        [ source atEnd ] whileFalse: [ destination nextPut: source next ].
mkobetic
parents: 74
diff changeset
    72
        destination contents
mkobetic
parents: 74
diff changeset
    73
}}}
mkobetic
parents: 74
diff changeset
    74
becomes simple and optimal
mkobetic
parents: 74
diff changeset
    75
{{{
mkobetic
parents: 74
diff changeset
    76
        String new writing write: ''Hello World'' reading; conclusion
mkobetic
parents: 74
diff changeset
    77
}}}
mkobetic
parents: 74
diff changeset
    78
mkobetic
parents: 74
diff changeset
    79
mkobetic
parents: 74
diff changeset
    80
        == End Of Stream ==
mkobetic
parents: 74
diff changeset
    81
mkobetic
parents: 74
diff changeset
    82
Another difference that you''ll probably notice early on is that reading past the end of stream is not a notification which returns nil by default. With Xtreams it is always an exception, Incomplete, the same way you get IncompleteNextCountError with #next:/#next:into:startingAt: (but not with #next). Incomplete always carries count of elements that were read or written successfully, and optionally also the destination or source collection and start parameters to provide easy access to whatever was successfully processed. Similarly, the positioning APIs report the actual change of position, with collection and start being nil. As usual the stream that raises the exception is the originator.
mkobetic
parents: 74
diff changeset
    83
{{{
129
6336404a548f - stx_goodies_xtreams_core
Martin Kobetic
parents: 109
diff changeset
    84
        [ ''Hello World!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!'' reading ++ 6; read: 50 ] on: Incomplete do: [ :ex | ex contents ]
85
mkobetic
parents: 74
diff changeset
    85
}}}
mkobetic
parents: 74
diff changeset
    86
Another significant difference is that xtreams do not provide the #atEnd test. Depending on the type of stream, implementing such test may require an actual read attempt to be able to answer. Once you perform a read, you''ll need to cache the element if the stream is not positionable. This gets even more complicated with complex stream stacks. Instead xtreams provide several alternatives each suitable for different circumstances. Message #rest reads everything that is left in the stream and automatically handles the Incomplete exception at the end.
mkobetic
parents: 74
diff changeset
    87
{{{
129
6336404a548f - stx_goodies_xtreams_core
Martin Kobetic
parents: 109
diff changeset
    88
        ''Hello World!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!'' reading read: 6; rest
85
mkobetic
parents: 74
diff changeset
    89
}}}
mkobetic
parents: 74
diff changeset
    90
If you don''t want to collect all the elements in the collection, xtreams also support collection style iteration protocols
mkobetic
parents: 74
diff changeset
    91
{{{
129
6336404a548f - stx_goodies_xtreams_core
Martin Kobetic
parents: 109
diff changeset
    92
        ''Hello World!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!'' reading
85
mkobetic
parents: 74
diff changeset
    93
                read: 6;
mkobetic
parents: 74
diff changeset
    94
                inject: 0 into: [ :count :each | count + 1 ]
mkobetic
parents: 74
diff changeset
    95
}}}
mkobetic
parents: 74
diff changeset
    96
For comparison here''s a common "read line by line" example in both classic and xtream style
mkobetic
parents: 74
diff changeset
    97
{{{
mkobetic
parents: 74
diff changeset
    98
        text := ''line1\line2\line3\line4'' withCRs readStream.
mkobetic
parents: 74
diff changeset
    99
        lines := OrderedCollection new.
mkobetic
parents: 74
diff changeset
   100
        [ text atEnd ] whileFalse: [ lines add: (text upTo: Character cr) ].
mkobetic
parents: 74
diff changeset
   101
        lines
mkobetic
parents: 74
diff changeset
   102
}}}
mkobetic
parents: 74
diff changeset
   103
{{{
mkobetic
parents: 74
diff changeset
   104
        text := ''line1\line2\line3\line4'' withCRs reading.
mkobetic
parents: 74
diff changeset
   105
        slicer := (text ending: Character cr) slicing.
mkobetic
parents: 74
diff changeset
   106
        slicer collect: [ :line | line rest ]
mkobetic
parents: 74
diff changeset
   107
}}}
mkobetic
parents: 74
diff changeset
   108
The xtreams example relies on some features that are yet to be discussed, but the point we''re trying to make here is that there''s often better way to handle the classic pattern. For example if you want only up to first 3 characters from each line, just change the ''line rest'' bit into ''(line limiting: 3) rest''. The slicing layer will take care of aligning the underlying stream for you automatically, whereas in the classic case the code would have to handle it explicitly. It''s also worth noting that the xtreams solution will do it efficiently. Each line can be processed as a stream of its own avoiding creation of unnecessary and potentially costly garbage.
mkobetic
parents: 74
diff changeset
   109
mkobetic
parents: 74
diff changeset
   110
Obviously, if you can''t find more suitable solution, any use of atEnd can be replaced by an Incomplete handler. For example the usual looping pattern
mkobetic
parents: 74
diff changeset
   111
{{{
mkobetic
parents: 74
diff changeset
   112
        [ stream atEnd ] whileFalse: [ ... ]
mkobetic
parents: 74
diff changeset
   113
}}}
mkobetic
parents: 74
diff changeset
   114
can be converted to
mkobetic
parents: 74
diff changeset
   115
{{{
mkobetic
parents: 74
diff changeset
   116
        [ [ ... ] repeat ] on: Incomplete do: [ :ex | ]
mkobetic
parents: 74
diff changeset
   117
}}}
mkobetic
parents: 74
diff changeset
   118
mkobetic
parents: 74
diff changeset
   119
The stream can be ended in a way that it wasn''t closed, but an error was raised. Usually this is a kind of OsError and it is not the same as knowing that a stream closed. The Incomplete exception does not raise when an OsError occurs on the underlying terminal. An example of where this distinction matters would be HTTP/1.0 where the body contents are sent to you and you know that the body is completely sent when the connection closes - however, if you receive an OsError before the Incomplete then you know you did not receive the entire body. Better protocols of course give you an indication of how much content there should be, so usually you want to catch OsError at a higher level of your application.
mkobetic
parents: 74
diff changeset
   120
mkobetic
parents: 74
diff changeset
   121
mkobetic
parents: 74
diff changeset
   122
        == Enumeration ==
mkobetic
parents: 74
diff changeset
   123
mkobetic
parents: 74
diff changeset
   124
As was alluded to above, read streams provide all the traditional, collection style enumeration API: #collect:, #select:, #inject:into:, etc. Including some of the more recent additions like #do:separatedBy: and #groupedBy. This allows certain level of polymorphism with Collections. It''s not clear at this point how far should we take this. For example we also provide concatenation of read streams with #, as an experimental feature (in Xtreams-Xtras).
mkobetic
parents: 74
diff changeset
   125
mkobetic
parents: 74
diff changeset
   126
mkobetic
parents: 74
diff changeset
   127
        == Closing ==
mkobetic
parents: 74
diff changeset
   128
mkobetic
parents: 74
diff changeset
   129
It is beneficial to get into the habit of always closing a stream when you''re done with it. However, it is worth noting, you should never close a stream that you did not create. If you are handed a stream from a framework or library, you should expect the framework or library to close it when execution control returns to it. Even though in particular cases it may end up being a noop, not making that assumption in your algorithm may extend its applicability to wider range of streams and stream stacks. Closing the stream isn''t necessarily just a matter of releasing resources. Especially with write streams it may be important to perform additional activity to properly terminate the stream. Some of these might be unobvious implementation aspects that may need to be properly cleared out. For example, current implementation of generic TransformWriteStream involves a background process which won''t be terminated if the stream is not closed. Given that even read transforms may involve arbitrary side-effects, similar precautions apply to read streams as well. The best approach is to always close a stream when you''re done with it.
mkobetic
parents: 74
diff changeset
   130
mkobetic
parents: 74
diff changeset
   131
mkobetic
parents: 74
diff changeset
   132
        == Positioning / Seeking ==
mkobetic
parents: 74
diff changeset
   133
mkobetic
parents: 74
diff changeset
   134
Not all streams are naturally positionable. Traditionally, an algorithm that required positionability was restricted to naturally positionable streams. Xtreams attempt to bridge this gap by providing positioning for non-positionable streams via a specialized buffering transform (PositionRead/WriteStream). To make sure a stream is positionable, send it #positioning. It returns the same stream if it already is positionable.
mkobetic
parents: 74
diff changeset
   135
{{{
mkobetic
parents: 74
diff changeset
   136
        Random new reading positioning read: 5; -- 2; read: 2
mkobetic
parents: 74
diff changeset
   137
}}}
mkobetic
parents: 74
diff changeset
   138
The positioning API imitates pointer arithmetic. Only skipping forward (++) and skipping to the end (-= 0) is available on both positionable and non-positionable streams.
mkobetic
parents: 74
diff changeset
   139
mkobetic
parents: 74
diff changeset
   140
||      *message*       ||      *notes* ||
mkobetic
parents: 74
diff changeset
   141
||      position                ||      returns current position from the beginning(1) of the stream ||
mkobetic
parents: 74
diff changeset
   142
||      position:               ||      sets current position from the beginning(1) of the stream ||
mkobetic
parents: 74
diff changeset
   143
||      available       ||      how many elements are left from current position to the end(1) ||
mkobetic
parents: 74
diff changeset
   144
||      length          ||      total size of the stream (position + available) ||
mkobetic
parents: 74
diff changeset
   145
||      ++                      ||      skips forward specified number of elements ||
mkobetic
parents: 74
diff changeset
   146
||      --                      ||      skips backward specified number of elements ||
mkobetic
parents: 74
diff changeset
   147
||      -=                      ||      skips backward specified number of elements from the end(1) of the stream ||
mkobetic
parents: 74
diff changeset
   148
||      +=                      ||      skips forward specified number of elements from the beginning(1) of the stream ||
mkobetic
parents: 74
diff changeset
   149
mkobetic
parents: 74
diff changeset
   150
Some streams, such as sequenceable collection write streams and file write streams, can be positioned past the end of their current size. In this situation, #position:, #-= and #+= can all position the stream beyond the current size. The size of the stream will not change until an actual write is performed. It is possible to use -= with a negative argument to move from the end of the stream in to its future. This mode of operation is called "sparse writing".
mkobetic
parents: 74
diff changeset
   151
mkobetic
parents: 74
diff changeset
   152
(1) Note that interpretation of beginning of the stream is slightly different in the case of the augmented non-positionable streams. The true beginning of the stream may not be reachable by the time the stream is wrapped in the positioning layer, so the beginning refers to the position at the time the stream is wrapped (unless specific buffering strategy, e.g. a ring buffer, moves the beginning of the buffer forward, in which case the beginning of the stream moves with it). This applies equally to read and write streams.
mkobetic
parents: 74
diff changeset
   153
mkobetic
parents: 74
diff changeset
   154
The backward skipping operators -- and -= cannot skip past the beginning of the stream. Incomplete will be raised if such request is made leaving the stream positioned at the beginning. Similarly the forward skipping operators += and ++ cannot skip past the end of the stream, and raises Incomplete if such request is made leaving the stream positioned at the end.
mkobetic
parents: 74
diff changeset
   155
{{{
mkobetic
parents: 74
diff changeset
   156
                [ Random new reading positioning read: 5; -- 8 ] on: Incomplete do: [ :ex | ex count ]
mkobetic
parents: 74
diff changeset
   157
}}}
mkobetic
parents: 74
diff changeset
   158
mkobetic
parents: 74
diff changeset
   159
There are several things to keep in mind when using the positioning/buffering transform. Some methods of the positioning API need to discover the end of the underlying stream, specifically #-=, #available and #length. These will cause the underlying stream to seek to the end immediately (filling up the positioning buffer along the way). Consequently, if the underlying stream is infinite, these operations will not return (potentially exhausting available memory, if the buffering strategy in use keeps growing the buffer).
mkobetic
parents: 74
diff changeset
   160
mkobetic
parents: 74
diff changeset
   161
Once added the positioning layer cannot be removed arbitrarily. In the case of read streams the underlying stream is always aligned with the end of the positioning buffer. With write stream the underlying destination stream is aligned with the beginning of the positioning buffer, i.e. the elements are written when they either fall out of the bottom of the buffer (e.g. in case of fixed size ring buffer) or the stream is explicitly flushed (all buffered elements are written and buffer is reinitialized). While it should be safe to remove the positioning layer when its position is aligned with the underlying stream, it''s best to avoid it altogether. Consequently, if an algorithm requires a positionable stream, it should be the caller''s responsibility to pass in a positionable stream, not the algorithm attempting to turn arbitrary stream into a positionable one, because the positioning layer usually cannot be passed back to the caller.
mkobetic
parents: 74
diff changeset
   162
mkobetic
parents: 74
diff changeset
   163
Buffering requires memory and different algorithms may require different buffering strategies. There are several Buffer classes available that are used throughout the framework for various purposes. Streams that employ buffers allow to replace the default buffer with a different one via the #buffer: message. For example if an algorithm only needs to be able to peek up to five elements ahead, RingBuffer of size 5 is efficient and doesn''t waste memory.
mkobetic
parents: 74
diff changeset
   164
mkobetic
parents: 74
diff changeset
   165
mkobetic
parents: 74
diff changeset
   166
        == Exploring ==
mkobetic
parents: 74
diff changeset
   167
mkobetic
parents: 74
diff changeset
   168
Any positionable stream can be explored. The #explore: method is an enhancement of the classic #peek. A ''stream peek'' can be replaced with
mkobetic
parents: 74
diff changeset
   169
{{{
mkobetic
parents: 74
diff changeset
   170
        stream explore: [ stream get ]
mkobetic
parents: 74
diff changeset
   171
}}}
mkobetic
parents: 74
diff changeset
   172
The advantage of #explore: is that the block allows arbitrary activity with the stream. The stream will return back to its original position when the block completes. For example you can peek for arbitrary number of elements, not just one:
mkobetic
parents: 74
diff changeset
   173
{{{
mkobetic
parents: 74
diff changeset
   174
        actions at: (stream explore: [ stream read: 3 ]))
mkobetic
parents: 74
diff changeset
   175
                ifAbsent: [ "not an action ID, do something else with the stream" ]
mkobetic
parents: 74
diff changeset
   176
                ifPresent: [ :action | stream ++ 3. action value: stream ]
mkobetic
parents: 74
diff changeset
   177
}}}
mkobetic
parents: 74
diff changeset
   178
mkobetic
parents: 74
diff changeset
   179
Positionable write streams can also be explored. The motivating use case is attempting a complex write and being able to abandon it if it doesn''t work out.
mkobetic
parents: 74
diff changeset
   180
{{{
mkobetic
parents: 74
diff changeset
   181
        String new writing
mkobetic
parents: 74
diff changeset
   182
                write: ''Hello '';
129
6336404a548f - stx_goodies_xtreams_core
Martin Kobetic
parents: 109
diff changeset
   183
                explore: [ :stream | stream write: ''Fooled!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!'' ];
6336404a548f - stx_goodies_xtreams_core
Martin Kobetic
parents: 109
diff changeset
   184
                write: ''World!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!'';
85
mkobetic
parents: 74
diff changeset
   185
                conclusion
mkobetic
parents: 74
diff changeset
   186
}}}
mkobetic
parents: 74
diff changeset
   187
{{{
mkobetic
parents: 74
diff changeset
   188
        String new writing
mkobetic
parents: 74
diff changeset
   189
                write: ''Hello '';
129
6336404a548f - stx_goodies_xtreams_core
Martin Kobetic
parents: 109
diff changeset
   190
                explore: [ :stream | stream write: ''World!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!'' ];
85
mkobetic
parents: 74
diff changeset
   191
                -= 0;
mkobetic
parents: 74
diff changeset
   192
                conclusion
mkobetic
parents: 74
diff changeset
   193
}}}
mkobetic
parents: 74
diff changeset
   194
109
9587e2df7029 Merged in latest version
Jan Vrany <jan.vrany@fit.cvut.cz>
parents: 106
diff changeset
   195
The most common kind of exploration is to ''peek'' ahead by one element only. This is a short hand for aStream explore: [aStream get], eg:
9587e2df7029 Merged in latest version
Jan Vrany <jan.vrany@fit.cvut.cz>
parents: 106
diff changeset
   196
{{{
9587e2df7029 Merged in latest version
Jan Vrany <jan.vrany@fit.cvut.cz>
parents: 106
diff changeset
   197
        ''Hello'' reading peek.
9587e2df7029 Merged in latest version
Jan Vrany <jan.vrany@fit.cvut.cz>
parents: 106
diff changeset
   198
}}}
9587e2df7029 Merged in latest version
Jan Vrany <jan.vrany@fit.cvut.cz>
parents: 106
diff changeset
   199
85
mkobetic
parents: 74
diff changeset
   200
mkobetic
parents: 74
diff changeset
   201
        == Write vs Insert ==
mkobetic
parents: 74
diff changeset
   202
mkobetic
parents: 74
diff changeset
   203
At times it is useful to be able to insert elements into the existing content of a positionable write stream. All the #write:... methods have an #insert:... equivalent for that purpose. Insert at the end of the stream has the same effect as write, similarly insert: on non-positionable stream is the same as write:.
mkobetic
parents: 74
diff changeset
   204
{{{
mkobetic
parents: 74
diff changeset
   205
        String new writing
129
6336404a548f - stx_goodies_xtreams_core
Martin Kobetic
parents: 109
diff changeset
   206
                write: ''Hello World!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!'';
85
mkobetic
parents: 74
diff changeset
   207
                += 5;
mkobetic
parents: 74
diff changeset
   208
                insert: '', Hello'';
mkobetic
parents: 74
diff changeset
   209
                -= 0;
mkobetic
parents: 74
diff changeset
   210
                conclusion
mkobetic
parents: 74
diff changeset
   211
}}}
mkobetic
parents: 74
diff changeset
   212
mkobetic
parents: 74
diff changeset
   213
mkobetic
parents: 74
diff changeset
   214
        == Buffered Writing ==
mkobetic
parents: 74
diff changeset
   215
mkobetic
parents: 74
diff changeset
   216
When writing to a write stream, it is the habit of Xtreams to always send data through immediately. There are cases where sending data immediately (eg: through a socket or protocol) could cause a protocol to become "chatty". When you know where it is you can safely flush to keep a protocol happy, it is useful to buffer up write data before transmitting it.
mkobetic
parents: 74
diff changeset
   217
mkobetic
parents: 74
diff changeset
   218
{{{
mkobetic
parents: 74
diff changeset
   219
        (ByteArray new writing buffering: 10)
mkobetic
parents: 74
diff changeset
   220
                write: #[ 1 2 3 4 5 ];
mkobetic
parents: 74
diff changeset
   221
                write: #[ 6 7 8 9 0 ];
mkobetic
parents: 74
diff changeset
   222
                put: 11;
mkobetic
parents: 74
diff changeset
   223
                flush;
mkobetic
parents: 74
diff changeset
   224
                conclusion.
mkobetic
parents: 74
diff changeset
   225
}}}
mkobetic
parents: 74
diff changeset
   226
'
mkobetic
parents: 74
diff changeset
   227
!
mkobetic
parents: 74
diff changeset
   228
55
e44717ae3e6c packaging
mkobetic
parents:
diff changeset
   229
e44717ae3e6c packaging
mkobetic
parents:
diff changeset
   230
!stx_goodies_xtreams_core class methodsFor:'description'!
e44717ae3e6c packaging
mkobetic
parents:
diff changeset
   231
e44717ae3e6c packaging
mkobetic
parents:
diff changeset
   232
excludedFromPreRequisites
e44717ae3e6c packaging
mkobetic
parents:
diff changeset
   233
    "list all packages which should be ignored in the automatic
e44717ae3e6c packaging
mkobetic
parents:
diff changeset
   234
     preRequisites scan. See #preRequisites for more."
e44717ae3e6c packaging
mkobetic
parents:
diff changeset
   235
e44717ae3e6c packaging
mkobetic
parents:
diff changeset
   236
    ^ #(
e44717ae3e6c packaging
mkobetic
parents:
diff changeset
   237
    )
109
9587e2df7029 Merged in latest version
Jan Vrany <jan.vrany@fit.cvut.cz>
parents: 106
diff changeset
   238
!
9587e2df7029 Merged in latest version
Jan Vrany <jan.vrany@fit.cvut.cz>
parents: 106
diff changeset
   239
9587e2df7029 Merged in latest version
Jan Vrany <jan.vrany@fit.cvut.cz>
parents: 106
diff changeset
   240
preRequisites
9587e2df7029 Merged in latest version
Jan Vrany <jan.vrany@fit.cvut.cz>
parents: 106
diff changeset
   241
    "list all required packages.
9587e2df7029 Merged in latest version
Jan Vrany <jan.vrany@fit.cvut.cz>
parents: 106
diff changeset
   242
     This list can be maintained manually or (better) generated and
9587e2df7029 Merged in latest version
Jan Vrany <jan.vrany@fit.cvut.cz>
parents: 106
diff changeset
   243
     updated by scanning the superclass hierarchies and looking for
9587e2df7029 Merged in latest version
Jan Vrany <jan.vrany@fit.cvut.cz>
parents: 106
diff changeset
   244
     global variable accesses. (the browser has a menu function for that)
9587e2df7029 Merged in latest version
Jan Vrany <jan.vrany@fit.cvut.cz>
parents: 106
diff changeset
   245
     Howevery, often too much is found, and you may want to explicitely
9587e2df7029 Merged in latest version
Jan Vrany <jan.vrany@fit.cvut.cz>
parents: 106
diff changeset
   246
     exclude individual packages in the #excludedFromPrerequisites method."
9587e2df7029 Merged in latest version
Jan Vrany <jan.vrany@fit.cvut.cz>
parents: 106
diff changeset
   247
9587e2df7029 Merged in latest version
Jan Vrany <jan.vrany@fit.cvut.cz>
parents: 106
diff changeset
   248
    ^ #(
9587e2df7029 Merged in latest version
Jan Vrany <jan.vrany@fit.cvut.cz>
parents: 106
diff changeset
   249
        #'stx:goodies/xtreams/support'
9587e2df7029 Merged in latest version
Jan Vrany <jan.vrany@fit.cvut.cz>
parents: 106
diff changeset
   250
        #'stx:libbasic'    "Object - superclass of Xtreams::ElasticBuffer "
9587e2df7029 Merged in latest version
Jan Vrany <jan.vrany@fit.cvut.cz>
parents: 106
diff changeset
   251
    )
55
e44717ae3e6c packaging
mkobetic
parents:
diff changeset
   252
! !
e44717ae3e6c packaging
mkobetic
parents:
diff changeset
   253
e44717ae3e6c packaging
mkobetic
parents:
diff changeset
   254
!stx_goodies_xtreams_core class methodsFor:'description - contents'!
e44717ae3e6c packaging
mkobetic
parents:
diff changeset
   255
e44717ae3e6c packaging
mkobetic
parents:
diff changeset
   256
classNamesAndAttributes
e44717ae3e6c packaging
mkobetic
parents:
diff changeset
   257
    "lists the classes which are to be included in the project.
e44717ae3e6c packaging
mkobetic
parents:
diff changeset
   258
     Each entry in the list may be: a single class-name (symbol),
e44717ae3e6c packaging
mkobetic
parents:
diff changeset
   259
     or an array-literal consisting of class name and attributes.
e44717ae3e6c packaging
mkobetic
parents:
diff changeset
   260
     Attributes are: #autoload or #<os> where os is one of win32, unix,..."
e44717ae3e6c packaging
mkobetic
parents:
diff changeset
   261
e44717ae3e6c packaging
mkobetic
parents:
diff changeset
   262
    ^ #(
e44717ae3e6c packaging
mkobetic
parents:
diff changeset
   263
        "<className> or (<className> attributes...) in load order"
e44717ae3e6c packaging
mkobetic
parents:
diff changeset
   264
        #'Xtreams::Buffer'
e44717ae3e6c packaging
mkobetic
parents:
diff changeset
   265
        #'Xtreams::Incomplete'
e44717ae3e6c packaging
mkobetic
parents:
diff changeset
   266
        #'Xtreams::ReadStream'
e44717ae3e6c packaging
mkobetic
parents:
diff changeset
   267
        #'Xtreams::WriteStream'
109
9587e2df7029 Merged in latest version
Jan Vrany <jan.vrany@fit.cvut.cz>
parents: 106
diff changeset
   268
        #'stx_goodies_xtreams_core'
55
e44717ae3e6c packaging
mkobetic
parents:
diff changeset
   269
        #'Xtreams::PositionReadStream'
e44717ae3e6c packaging
mkobetic
parents:
diff changeset
   270
        #'Xtreams::PositionWriteStream'
e44717ae3e6c packaging
mkobetic
parents:
diff changeset
   271
        #'Xtreams::RingBuffer'
e44717ae3e6c packaging
mkobetic
parents:
diff changeset
   272
        #'Xtreams::ElasticBuffer'
e44717ae3e6c packaging
mkobetic
parents:
diff changeset
   273
    )
e44717ae3e6c packaging
mkobetic
parents:
diff changeset
   274
!
e44717ae3e6c packaging
mkobetic
parents:
diff changeset
   275
e44717ae3e6c packaging
mkobetic
parents:
diff changeset
   276
extensionMethodNames
e44717ae3e6c packaging
mkobetic
parents:
diff changeset
   277
    "lists the extension methods which are to be included in the project.
e44717ae3e6c packaging
mkobetic
parents:
diff changeset
   278
     Entries are 2-element array literals, consisting of class-name and selector."
e44717ae3e6c packaging
mkobetic
parents:
diff changeset
   279
e44717ae3e6c packaging
mkobetic
parents:
diff changeset
   280
    ^ #(
e44717ae3e6c packaging
mkobetic
parents:
diff changeset
   281
        Object streamingInsert:into:
e44717ae3e6c packaging
mkobetic
parents:
diff changeset
   282
        Object streamingInsertInto:
e44717ae3e6c packaging
mkobetic
parents:
diff changeset
   283
        Object streamingPrintOn:
e44717ae3e6c packaging
mkobetic
parents:
diff changeset
   284
        Object streamingWrite:into:
e44717ae3e6c packaging
mkobetic
parents:
diff changeset
   285
        Object streamingWriteInto:
e44717ae3e6c packaging
mkobetic
parents:
diff changeset
   286
        SequenceableCollection streamingInsert:into:
e44717ae3e6c packaging
mkobetic
parents:
diff changeset
   287
        SequenceableCollection streamingInsertInto:
e44717ae3e6c packaging
mkobetic
parents:
diff changeset
   288
        SequenceableCollection streamingWrite:into:
e44717ae3e6c packaging
mkobetic
parents:
diff changeset
   289
        SequenceableCollection streamingWriteInto:
e44717ae3e6c packaging
mkobetic
parents:
diff changeset
   290
    )
e44717ae3e6c packaging
mkobetic
parents:
diff changeset
   291
! !
e44717ae3e6c packaging
mkobetic
parents:
diff changeset
   292
129
6336404a548f - stx_goodies_xtreams_core
Martin Kobetic
parents: 109
diff changeset
   293
!stx_goodies_xtreams_core class methodsFor:'description - project information'!
6336404a548f - stx_goodies_xtreams_core
Martin Kobetic
parents: 109
diff changeset
   294
6336404a548f - stx_goodies_xtreams_core
Martin Kobetic
parents: 109
diff changeset
   295
legalCopyright
6336404a548f - stx_goodies_xtreams_core
Martin Kobetic
parents: 109
diff changeset
   296
6336404a548f - stx_goodies_xtreams_core
Martin Kobetic
parents: 109
diff changeset
   297
        ^'Copyright 2010-2013 Cincom Systems, Martin Kobetic and Michael Lucas-Smith'
6336404a548f - stx_goodies_xtreams_core
Martin Kobetic
parents: 109
diff changeset
   298
! !
6336404a548f - stx_goodies_xtreams_core
Martin Kobetic
parents: 109
diff changeset
   299
55
e44717ae3e6c packaging
mkobetic
parents:
diff changeset
   300
!stx_goodies_xtreams_core class methodsFor:'documentation'!
e44717ae3e6c packaging
mkobetic
parents:
diff changeset
   301
109
9587e2df7029 Merged in latest version
Jan Vrany <jan.vrany@fit.cvut.cz>
parents: 106
diff changeset
   302
version_HG
9587e2df7029 Merged in latest version
Jan Vrany <jan.vrany@fit.cvut.cz>
parents: 106
diff changeset
   303
    ^ '$Changeset: <not expanded> $'
55
e44717ae3e6c packaging
mkobetic
parents:
diff changeset
   304
! !
109
9587e2df7029 Merged in latest version
Jan Vrany <jan.vrany@fit.cvut.cz>
parents: 106
diff changeset
   305