How to write txt file in smalltalk - smalltalk

I try with this code:
f := 'testfile.txt' asFileReference.
f2 := f writeStream.
f2 nextPutAll: 'hello world'.
f2 close.
f content.
But I get this exception:
**FileDoesNotExistException**

'testfile.txt' asFileReference
writeStreamDo: [ :stream | stream << 'Hello, World!' ].
This should work. But this is another way to express what you did before so I suspect some writing permission is wrong or something around that.

Just to add to Estaban's response, one surprising behaviour of Pharo is that writeStreamDo overwrites the existing file, so if the existing file is longer than the new data, you end up with the new data and the tail end of the old data. Fortunately, there is a simple solution: you can simply include truncate. So a slightly "safer" version is:
'testfile.txt' asFileReference
writeStreamDo: [ :stream | stream truncate. stream << 'Hello, World!' ].

Related

How to use text file as input to feed in the interactive input of smalltalk and redirect output to a file

I am struggling to find out is there a way to feed input
to the interactive command of gst a.st b.st ... -
and redirect the output. Normally, the interactive buffer will
have st> ... and when you type a command it will output something by calling
the default/override displayString method to the interactive output. How to get the input
and feed the output using linux command or maybe a tiny smalltalk test script to do that.
Thank you.
Here's a contrived demonstration program. It reads in strings from standard input until EOF, sorts them, then prints them out:
input := stdin nextLine.
c := OrderedCollection new.
[ input ~= nil ] whileTrue: [
c add: input.
input := stdin nextLine.
].
c sort do: [ :each | each printNl ]
You can run it interactively (pressed Ctrl-D after entering hhh):
$ gst sortprog.st
tttt
aaa
vvvv
hhh
'aaa'
'hhh'
'tttt'
'vvvv'
Or I can create a text file test.in with the following contents:
tttt
aaa
vvvv
hhh
Then run:
$ gst sortprog.st < test.in > test.out
And then check the contents of the output file:
$ cat test.out
'aaa'
'hhh'
'tttt'
'vvvv'
If your program has prompts, they will appear in the output file, of course. Anything going to stdout will go to that file.

Smalltalk Error handling with Transcript

Suppose I have the following method:
MyClass>>addCategory: aCategory toEvent: anEvent
| cat |
cat := anEvent addCategory: aCategory
...
Now, the method #addCategory can either return some other object (e.g. something of class Foo) or throw an error (using Error signal: 'message').
In case of an error, I would like to print the message of the error on the Transcript.
In case of an object, I would like to print some message on the Transcript (e.g. Transcript show: 'Category added!') and return the object.
I have been looking at aBlock ifError: aBlock, something like this:
MyClass>>addCategory: aCategory toEvent: anEvent
| cat |
cat := [anEvent addCategory: aCategory] ifError: [ :err | Transcript show: err. ]
...
But I can't quite figure out how to handle the variable cat afterwards, in order to get the behavior I want.
Here is another way to do the same. The idea is to enclose your code as if would not fail and wrap it with an on: Error
MyClass>>addCategory: aCategory toEvent: anEvent
| cat |
[
cat := anEvent addCategory: aCategory.
Transcript show: 'Category added!']
on: Error
do: [:err | Transcript show: err messageText].
^cat
Notice that cat will not get assigned in case of Error and hence the method will answer with nil. Notice also that there is no need to ^nil from within the error-handler block.
Remember that the idea of on:do: is to allow you to write naïve code and then handle possible error conditions without inlining them into the error-free section of your code.
[
<my naive
and clean
lines of code>] on: Error do: [:err | oops!]
Your solution is ok but inlines error handling code inside the main code, making it a little bit harder for the reader to get the main idea of the relevant code.
One possible way to solve this is the following:
MyClass>>addCategory: aCategory toEvent: anEvent
| cat |
cat := [ anEvent addCategory: aCategory] on: Error do [ :err | Transcript show: err messageText. ^nil. ]
Transcript show: 'Category added!'.
^cat
This solution will print the error to the Transcript and return nil from the method. In case there is no error, the code will continue, print the message on the Transcript and return the object.
This might not be the best solution, but it is one possible way of doing it. As long as you don't mind that nil is returned in case of an error.

smalltalk inspect - output to transcript or file

Smalltalk inspect is a powerful tool. Is there any (easy) way to get the information from inspect and show it in Transcript window or write into a file instead of showing it in new window?
I need it because I want to create a kind of debbuger for a program that runs as unix process (not a 'window' program) and logs information into a log file.
Thanks for help!
If you're asking whether something is built in, then I don't think so (although it would help if you tagged the question with which Smalltalk you are using).
Although it would be pretty easy to walk over the inst vars and roll your own (although maybe not for immediate objects), the "easiest" way might be to look at the inspector code and see how it operates. For example, in Pharo 4.0 one could (very basically) leverage the inspector code like so:
i := EyeInspector inspector: 1.
Transcript show: i objectClass; cr.
i elements do: [ :e | Transcript show: e; cr ].
which would print:
SmallInteger
'self'->1
'hex'->1
'octal'->1
'binary'->1
'character'->Character home
In Pharo, you can also get all of the Transcript output going to the console with:
NonInteractiveTranscript stdout install
If you are about debugging, you can have debugger interactions dump things into files (of course, you'll not be able to step in there but it can be useful for headless systems):
NonInteractiveUIManager compile: 'openDebuggerOn: process context: context label: title contents: contentsStringOrNil fullView: bool
| out |
out := VTermOutputDriver stdout.
out
<< ''NonInteractive Debugger: '';
<< title;
cr.
contentsStringOrNil ifNotNil: [ out << contentsStringOrNil; cr ].
(context stackOfSize: 20) do: [:s | out << s printString; cr ].
out << ''------------------------------''; cr; cr.
^ self nonInteractiveWarning: ''Opening Debugger''' classified: #'ui-requests'.
This and Sean's answer should go a long way.
You can get back to normal with the Transcript with:
ThreadSafeTranscript install.
Pharo 3.0 here.

How to increase Transcript buffer size?

I am working with Pharo 3 and I use the Transcript to record operations.
However the size of the current buffer is short for my needs. How to increase it? There is characterLimit but this is a method constant and therefore not easy to set up without changing a core package.
I do not want to use NonInteractiveTranscript because I want to stay in the image.
No, there is no other way to change the buffer length of the Transcript then to modify #characterLimit (usually of ThreadSafeTranscript). However, try inspecting ThreadSafeTranscript allInstances and you'll see that the underlying stream is much longer (50000 something is the write limit there). So, whatever you're printing to Transcript is not actually lost but just not visible.
That being said, using Transcript for extensive output is generally not a good idea because:
output is cut off (as you've already seen)
Transcript is really slow when called repeatedly:
try
1 to: 10000 do: [ :i | Transcript show: i ]
vs.
Transcript show: (String streamContents: [ :stream |
1 to: 10000 do: [ :i | stream nextPutAll: i asString ] ])
you can't use the output somewhere else (e.g. to write to file or pass along to a method)
In my opinion Transcript is ok for occasional quick debugging but shouldn't be used for anything application related.

Using Squeak from a shell

Can I launch Squeak as a REPL (no GUI), where I can enter and evaluate Smalltalk expressions? I know the default image don't allow this. Is there any documentation on how to build a minimum image that can be accessed from a command-line shell?
Here is a (hackish) solution:
First, you need OSProcess, so run this in a Workspace:
Gofer new squeaksource:'OSProcess'; package:'OSProcess';load.
Next, put this in the file repl.st:
OSProcess thisOSProcess stdOut
nextPutAll: 'Welcome to the simple Smalltalk REPL';
nextPut: Character lf; nextPut: $>; flush.
[ |input|
[ input := OSProcess readFromStdIn.
input size > 0 ifTrue: [
OSProcess thisOSProcess stdOut
nextPutAll: ((Compiler evaluate: input) asString;
nextPut: Character lf; nextPut: $>; flush
]
] repeat.
]forkAt: (Processor userBackgroundPriority)
And last, run this command:
squeak -headless path/to/squeak.image /absolute/path/to/repl.st
You can now have fun with a Smalltalk REPL. Dont forget to type in the command:
Smalltalk snapshot:true andQuit:true
if you want to save your changes.
Now, onto the explanation of this solution:
OSProcess is a package that allows to run other processes, read from stdin, and write to stdout and stderr. You can access the stdout AttachableFileStream with OSProcess thisOSProcess (the current process, aka squeak).
Next, you run an infinite loop at userBackgroundPriority (to let other processes run). In this infinite loop, you use Compiler evaluate: to execute the input.
And you run this in a script with a headless image.
As of Pharo 2.0 (and 1.3/1.4 with the fix described below), there are no more hacks necessary. The following snippet will turn your vanilla Pharo image into a REPL server...
From https://gist.github.com/2604215:
"Works out of the box in Pharo 2.0. For prior versions (definitely works in 1.3 and 1.4), first file in https://gist.github.com/2602113"
| command |
[
command := FileStream stdin nextLine.
command ~= 'exit' ] whileTrue: [ | result |
result := Compiler evaluate: command.
FileStream stdout nextPutAll: result asString; lf ].
Smalltalk snapshot: false andQuit: true.
If you want the image to always be a REPL, put the code in a #startup: method; otherwise, pass the script at the command line when you want REPL mode, like:
"/path/to/vm" -headless "/path/to/Pharo-2.0.image" "/path/to/gistfile1.st"
Please visit:
http://map.squeak.org/package/2c3b916b-75e2-455b-b25d-eba1bbc94b84
and Run Smalltalk on server without GUI?
The project http://www.squeaksource.com/SecureSqueak.html includes a REPL package that may provide much of what you are looking for.