How do I get the current module/script/file name in GNU Smalltalk? - filenames

GNU Smalltalk omits the script name in argv.
#!/usr/bin/env gst -f
| argv program |
argv := Smalltalk arguments.
(argv size) > 0 ifTrue: [
program := argv at: 1.
Transcript show: 'Program: ', program; cr.
] ifFalse: [
Transcript show: 'argv = {}'; cr.
]
$ ./scriptname.st
argv = {}
I see two ways to get the script name:
Track down some Smalltalk method which returns the script name akin to Perl's variable $0.
Track down syntax for a multiline shebang and force GST to supply the scriptname as the first member of argv. Here's an example in Common Lisp.

It seems the best that can be done is use shebangs to force the script name to ARGV, then check whether Smalltalk getArgv: 1 ends with a hardcoded string.
Posted here and on Rosetta Code.
"exec" "gst" "-f" "$0" "$0" "$#"
"exit"
Object subclass: ScriptedMain [
ScriptedMain class >> meaningOfLife [ ^42 ]
]
| main |
main := [
Transcript show: 'Main: The meaning of life is ', ((ScriptedMain meaningOfLife) printString); cr.
].
(((Smalltalk getArgc) > 0) and: [ ((Smalltalk getArgv: 1) endsWith: 'scriptedmain.st') ]) ifTrue: [
main value.
]

You can ask the current method where it comes from: thisContext method methodSourceFile printNl.

Related

How to change Boolean variable based on expression?

I'm trying to change the value of a Boolean variable using expression in bash script (Debian Jessie) but it's not working as intended!
Here is my code
vld=true
while ! [ $vld ]
do
echo "Enter a number: [1-30]:"
read myinput
$vld=[ $myinput -ge 1 ] && [ $myinput -le 30 ]
done
echo "Your number is $myinput
When I this script it says:
8: ./test.sh true=[: not found
Then it keeps on the loop as the variable is not receiving the result of the expression but is used itself!

SmallTalk - Printing contents of an OrderedCollection object using Transcript

|oc|
oc := OrderedCollection new.
oc add: 2.
oc add: #(4 9).
oc Transcript show: self; cr.
Upon running the following code in Pharo, I am getting the message:
MessageNotUnderstood: OrderedCollection>> Transcript
When replacing 'self' with 'oc' I am still getting the same error. I am looking for a way to output the collection using the Transcript.
Why can't Transcript be the receiver of my code?
Remember the object message: parameter syntax: you're trying to send the Transcript message to the oc object, and then send the show: message to the object returned by that, with the self parameter.
What you really want to do is ask the Transcript object to show: your oc object. So, do that: send Transcript the show: message with oc as a parameter: Transcript show: oc. That will show the string representation of the collection.
If you were to print each member of the collection (instead of printing the collection itself), you should use the do: method to iterate over them: oc do: [ :element | Transcript show: element ]. Here you print each of the collection's member string representation.
oc := OrderedCollection new.
oc add: 2.
oc add: #(4 9).
Transcript show: 'Show the collection:'; cr.
Transcript show: oc; cr.
Transcript show: 'Show each element:'; cr.
oc do: [ :element | Transcript show: element; cr ].
Gives this output:
Show the collection:
an OrderedCollection(2 #(4 9))
Show each element:
2
#(4 9)
Also:
oc do: [ :each | Transcript show: each; cr ]
Somewhat shorter:
oc do: [:each | each logCr ]

Python's if __name__=="__main__" idiom for GNU Smalltalk?

Does such a thing exist?
Ruby:
if __FILE__ == $0
main
end
Perl:
unless(caller) {
main;
}
Lua:
if type(package.loaded[(...)]) ~= "userdata" then
main(arg)
else
module(..., package.seeall)
end
Exotic multiline shebangs and argv trickery do the job.
See Rosetta Code.
scriptedmain.st:
"exec" "gst" "-f" "$0" "$0" "$#"
"exit"
Object subclass: ScriptedMain [
ScriptedMain class >> meaningOfLife [ ^42 ]
]
| main |
main := [
Transcript show: 'Main: The meaning of life is ', ((ScriptedMain meaningOfLife) printString); cr.
].
(((Smalltalk getArgc) > 0) and: [ ((Smalltalk getArgv: 1) endsWith: 'scriptedmain.st') ]) ifTrue: [
main value.
].

How to camelCase a String in Pharo?

I'm trying to get from:
'hello how are you today'
to
'helloHowAreYouToday'
And I thought asCapitalizedPhrase asLegalSelector would do the trick, but it doesn't.
What's the proper way to do this?
EDIT:
I think I should clarify my question; I already have a way to transform a string into a camelCase selector:
|aString aCamelCaseString|
aString := aString findTokens: $ .
aCamelCaseString := aString first.
aString allButFirst do: [:each | aCamelCaseString := aCamelCaseString , each capitalized].
I was just wondering whether Pharo has a standard system method to achieve the same :)
How about this?
| tokens |
tokens := 'this is a selector' findTokens: Character space.
tokens allButFirst
inject: tokens first
into: [:selector :token | selector, token capitalized]
I don't think there's an existing method doing this.
Here's an implementation that solves your problem:
input := 'hello how are you today'.
output := String streamContents: [ :stream |
| capitalize |
capitalize := false.
input do: [ :char |
char = Character space
ifTrue: [ capitalize := true ]
ifFalse: [
stream nextPut: (capitalize
ifTrue: [ char asUppercase ]
ifFalse: [ char ]).
capitalize := false ] ] ].
Edit: note, in comparison to Frank's solution this one is longer but it does not break for empty input and it does not create a new string instance for each step since it streams over the input, which is more efficient (in case you have large strings).
You don't say which version of Pharo you're using, but in the stable 5.0,
'hello world this is a selector' asCamelCase asValidSelector
yields
helloWorldThisIsASelector
To get what I'm using run:
curl get.pharo.org/50+vm | bash
I know this is old but Squeak has a useful implementation (String>>asCamelCase) which basically does this:
(String
streamContents: [:stream | 'hello world' substrings
do: [:sub | stream nextPutAll: sub capitalized]]) asLegalSelector

Is it possible to override rebol path operator?

It is possible to overide rebol system words like print, make etc., so is it possible to do the same with the path operator ? Then what's the syntax ?
Another possible approach is to use REBOL meta-programming capabilities and preprocess your own code to catch path accesses and add your handler code. Here's an example :
apply-my-rule: func [spec [block!] /local value][
print [
"-- path access --" newline
"object:" mold spec/1 newline
"member:" mold spec/2 newline
"value:" mold set/any 'value get in get spec/1 spec/2 newline
"--"
]
:value
]
my-do: func [code [block!] /local rule pos][
parse code rule: [
any [
pos: path! (
pos: either object? get pos/1/1 [
change/part pos reduce ['apply-my-rule to-block pos/1] 1
][
next pos
]
) :pos
| into rule ;-- dive into nested blocks
| skip ;-- skip every other values
]
]
do code
]
;-- example usage --
obj: make object! [
a: 5
]
my-do [
print mold obj/a
]
This will give you :
-- path access --
object: obj
member: a
value: 5
--
5
Another (slower but more flexible) approach could also be to pass your code in string mode to the preprocessor allowing freeing yourself from any REBOL specific syntax rule like in :
my-alternative-do {
print mold obj..a
}
The preprocessor code would then spot all .. places and change the code to properly insert calls to 'apply-my-rule, and would in the end, run the code with :
do load code
There's no real limits on how far you can process and change your whole code at runtime (the so-called "block mode" of the first example being the most efficient way).
You mean replace (say)....
print mold system/options
with (say)....
print mold system..options
....where I've replaced REBOL's forward slash with dot dot syntax?
Short answer: no. Some things are hardwired into the parser.