├── .github └── workflows │ └── main.yml ├── .smalltalk.ston ├── .squot ├── README.md ├── img ├── architecture.svg ├── banner.svg ├── screencast.gif └── screenshot1.png ├── scripts └── preLoading.st └── src ├── BaselineOfTelegramSmalltalkBot.package ├── .filetree ├── .squot-contents ├── BaselineOfTelegramSmalltalkBot.class │ ├── README.md │ ├── instance │ │ ├── baseline..st │ │ ├── depChangeset..st │ │ ├── depMergeVersion..st │ │ ├── installPreviewDependencies.st │ │ └── projectClass.st │ ├── methodProperties.json │ └── properties.json ├── monticello.meta │ ├── categories.st │ └── initializers.st └── properties.json ├── TelegramSmalltalkBot-Core.package ├── .filetree ├── .squot-contents ├── Collection.extension │ ├── instance │ │ └── asTelegramSmalltalkBotMessageFor..st │ ├── methodProperties.json │ └── properties.json ├── CompiledCode.extension │ ├── instance │ │ └── asTelegramSmalltalkBotMessageFor..st │ ├── methodProperties.json │ └── properties.json ├── Dictionary.extension │ ├── instance │ │ └── asTelegramSmalltalkBotMessageFor..st │ ├── methodProperties.json │ └── properties.json ├── Object.extension │ ├── instance │ │ └── asTelegramSmalltalkBotMessageFor..st │ ├── methodProperties.json │ └── properties.json ├── String.extension │ ├── instance │ │ ├── asTelegramSmalltalkBotMessageFor..st │ │ └── tbWithoutLineEndings.st │ ├── methodProperties.json │ └── properties.json ├── TelegramSmalltalkBot.class │ ├── README.md │ ├── class │ │ ├── repositoryStub.st │ │ ├── repositoryUrl.st │ │ ├── repositoryUrlAboutIsolation.st │ │ └── secrets.st │ ├── instance │ │ ├── answerCommand.message..st │ │ ├── answerDo..st │ │ ├── answerInspect..st │ │ ├── answerPrint..st │ │ ├── doHelp..st │ │ ├── doReset..st │ │ ├── doStart..st │ │ ├── editMessage.changeTo..st │ │ ├── errorText..st │ │ ├── exceptionText..st │ │ ├── generateAnswerTo..st │ │ ├── generateCodeExample.st │ │ ├── handleCommand.message..st │ │ ├── helpStrings.st │ │ ├── initialize.st │ │ ├── isDebugging..st │ │ ├── isDebugging.st │ │ ├── logErrorsDuring.replyTo..st │ │ ├── messageBlocked.withError..st │ │ ├── messageEdited..st │ │ ├── messageReceived..st │ │ ├── messageWith..st │ │ ├── messageWithCollection..st │ │ ├── messageWithDictionary..st │ │ ├── messageWithErrorText..st │ │ ├── messageWithExceptionText..st │ │ ├── messageWithItems.caption..st │ │ ├── messageWithObject..st │ │ ├── messageWithUserText..st │ │ ├── processMessage.andDo..st │ │ ├── processMessage.andDo.ifError..st │ │ ├── removeSession.ifAbsent..st │ │ ├── replyMessage.withHtml..st │ │ ├── replyMessage.withHtmls.beforeSendDo..st │ │ └── sessionFor..st │ ├── methodProperties.json │ └── properties.json ├── TelegramSmalltalkSession.class │ ├── README.md │ ├── instance │ │ ├── basicRecordAnswer..st │ │ ├── basicRecordResult.forMessage..st │ │ ├── bindingOf..st │ │ ├── doSafely.ifError..st │ │ ├── doSafely.on.do.useSandbox..st │ │ ├── evaluate.for.ifError..st │ │ ├── initialize.st │ │ ├── isolationEnabled..st │ │ ├── isolationEnabled.st │ │ ├── maximumMemorySize.st │ │ ├── maximumRecordSize.st │ │ ├── mustDeclareVariables.st │ │ ├── notify.at.in..st │ │ ├── obfuscateSecret..st │ │ ├── pinRecord.to..st │ │ ├── processMessage.ifError..st │ │ ├── receiverFor..st │ │ ├── record.fromAnswer.bot..st │ │ ├── recordedAnswerTo.ifAbsent..st │ │ ├── reset.st │ │ ├── scheduleRecord.fromAnswer..st │ │ ├── secrets.st │ │ ├── tidyUpRecords..st │ │ └── wantsInteractiveErrorCorrection.st │ ├── methodProperties.json │ └── properties.json ├── Text.extension │ ├── instance │ │ └── asTelegramSmalltalkBotMessageFor..st │ ├── methodProperties.json │ └── properties.json ├── monticello.meta │ ├── categories.st │ └── initializers.st └── properties.json └── TelegramSmalltalkBot-Tests.package ├── .filetree ├── .squot-contents ├── TelegramSmalltalkBotTest.class ├── README.md ├── instance │ ├── askBot..st │ ├── botSession.st │ ├── clientChatId.st │ ├── editMessage.text..st │ ├── makeChat.st │ ├── makeMessageFrom..st │ ├── nextMessageId.st │ ├── receiveBotMessagesDuring..st │ ├── receiveEditedBotMessagesDuring..st │ ├── sendMessage..st │ ├── setUp.st │ ├── shouldBotAsked.answer..st │ ├── shouldBotAsked.answerSatisfy..st │ ├── shouldBotAsked.answersSatisfy..st │ ├── someNumber.st │ ├── someString.st │ ├── tearDown.st │ ├── testAnimation.st │ ├── testDialog.st │ ├── testDo.st │ ├── testEditMessage.st │ ├── testForm.st │ ├── testHelp.st │ ├── testInspect.st │ ├── testInternalError.st │ ├── testPrint.st │ ├── testRuntimeError.st │ ├── testSimple.st │ ├── testSound.st │ ├── testStart.st │ ├── testSyntaxError.st │ ├── testText.st │ └── testVariables.st ├── methodProperties.json └── properties.json ├── monticello.meta ├── categories.st └── initializers.st └── properties.json /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: smalltalkCI 2 | 3 | on: 4 | push: 5 | schedule: 6 | - cron: "0 0 * * 1" 7 | 8 | jobs: 9 | build: 10 | runs-on: ubuntu-latest 11 | name: ${{ matrix.smalltalk }} on ${{ matrix.os }} 12 | steps: 13 | - uses: actions/checkout@v2 14 | - uses: hpi-swa/setup-smalltalkCI@v1 15 | id: smalltalkci 16 | with: 17 | smalltalk-image: Squeak64-Trunk 18 | - name: Run test suite 19 | shell: bash 20 | run: smalltalkci -s ${{ steps.smalltalkci.outputs.smalltalk-image }} 21 | timeout-minutes: 15 22 | env: 23 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 24 | # GITHUB_TOKEN lacks permission to read other repositories that are depended in the baseline. 25 | GH_ACCESS_TOKEN: ${{ secrets.GH_ACCESS_TOKEN }} 26 | - name: Send email on failure 27 | if: ${{ github.event_name == 'schedule' && failure() }} 28 | uses: dawidd6/action-send-mail@v2 29 | with: 30 | server_address: ${{ secrets.SMTP_SERVER }} 31 | server_port: ${{ secrets.SMTP_PORT }} 32 | username: ${{ secrets.SMTP_USERNAME }} 33 | password: ${{ secrets.SMTP_PASSWORD }} 34 | subject: GitHub Actions failed for ${{ github.repository }} 35 | body: Build job of ${{ github.repository }} failed! See https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }} for more information. 36 | to: ${{ secrets.MAIL_RECEIVER }} 37 | from: GitHub Actions 38 | -------------------------------------------------------------------------------- /.smalltalk.ston: -------------------------------------------------------------------------------- 1 | SmalltalkCISpec { 2 | #preLoading : 'scripts/preLoading.st', 3 | #loading : [ 4 | SCIMetacelloLoadSpec { 5 | #baseline : 'TelegramSmalltalkBot', 6 | #directory : 'src', 7 | #platforms : [ #squeak ], 8 | #load : [ 'TelegramSmalltalkBot-Tests' ] 9 | } 10 | ], 11 | #testing : { 12 | #packages : [ 'TelegramSmalltalkBot-Tests' ], 13 | #coverage : { 14 | #packages : [ 'TelegramSmalltalkBot-Core' ] 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /.squot: -------------------------------------------------------------------------------- 1 | OrderedDictionary { 2 | 'src\/TelegramSmalltalkBot-Core.package' : #SquotCypressCodeSerializer, 3 | 'src\/TelegramSmalltalkBot-Tests.package' : #SquotCypressCodeSerializer, 4 | 'src\/BaselineOfTelegramSmalltalkBot.package' : #SquotCypressCodeSerializer 5 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TelegramSmalltalkBot 2 | 3 | [](https://github.com/LinqLover/TelegramSmalltalkBot/actions) 4 | [](https://coveralls.io/github/LinqLover/TelegramSmalltalkBot) 5 | [](https://t.me/SqueakSmalltalkBot) 6 | 7 | A Telegram bot that connects you to a remote [Squeak/Smalltalk](https://squeak.org/) image and allows you to explore it by sending Smalltalk expressions to the bot. 8 | Implemented using the [TelegramBot framework](https://github.com/LinqLover/TelegramBot) and [SimulationStudio](https://github.com/LinqLover/SimulationStudio) for sandboxed execution. 9 | 10 |
14 | 15 | Currently available features include, but are not limited to: 16 | 17 | - Evaluate arbitrary Smalltalk expressions 18 | - Multi-user object memory with isolated execution to rule out global side effects in the image 19 | - Select the receiver context (`self`) for your expressions by replying to a specific previous message of the bot 20 | - Edit your messages and answers from the bot will be updated as well 21 | - Multi-media representations of various Smalltalk objects such as `Text`, `Form`, `AnimatedImageMorph`, `AbstractSound`, and others 22 | - Bot commands to create different views of expression results such as `/do`, `/print`, and `inspect` 23 | 24 | To learn more about all capabilities, just [try it out](#try-it-out) and send the `/help` command. 25 | 26 | There is also a [screencast available on YouTube](https://youtu.be/HZCeThLqQmg). 27 | 28 | ## Try it out! 29 | 30 | An instance of the bot is live under [@SqueakSmalltalkBot](https://t.me/SqueakSmalltalkBot). 31 | Just send it a message and say hello! 32 | 33 |{1}
). In addition, I understand the following messages:' format: {self generateCodeExample}); cr; cr].
34 | helpStrings associations
35 | do: [:assoc | stream nextPutAll: ('/{1} - {2}' format: {
36 | assoc key. assoc value})]
37 | separatedBy: [stream cr].
38 | filteredHelpStrings ifEmpty: [
39 | stream cr; cr; nextPutAll: 'Furthermore, you can send your messages to any of my previous replies to choose the receiver context accordingly (i. e., to bind self
to the object from the reply). Last but not least, if you edit any of your messages, I will update my answers accordingly, so together we can erase every trace of your former slips (who controls the past ...). Have fun!'].]).
40 |
41 | (self sessionFor: aMessage chat)
42 | record: '🥚 Congratulations, you uncovered an easter egg! 🎉' asTextFromHtml "Sticker would be even nicer though"
43 | fromAnswer: reply
44 | bot: self.
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkBot.class/instance/doReset..st:
--------------------------------------------------------------------------------
1 | commands
2 | doReset: aMessage
3 |
4 | self removeSession: aMessage chat ifAbsent: [^ self].
5 |
6 | self sendText: 'Session was reset.' toChat: aMessage chat.
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkBot.class/instance/doStart..st:
--------------------------------------------------------------------------------
1 | commands
2 | doStart: aMessage
3 |
4 | ^ self
5 | replyMessage: aMessage
6 | withHtmls: {
7 | 'Welcome to the Squeak/Smalltalk Bot! 👋
8 |
9 | Just send some random Smalltalk code expressions to me and I will try to evaluate each of them in an up-to-date Squeak image for you – what''s that if not Smalltalk in its loveliest form 😏
10 |
11 | You can also prepend commands such as /do or /print to vary my outputs. For an exhaustive list of all the exciting things we can reach together, send /help.'.
12 | 'This bot is open-source and available on GitHub:
13 | 🐙 {1}
14 | We cordially invite you to visit the repository and to contribute. Your bugs will be fixed and your PRs will be merged!' format: {self class repositoryStub. self class repositoryUrl}.
15 | 'Disclaimer: Since Smalltalk is an open system, all data you share with the bot might be visible to other users. We try to prevent this by providing isolation, but for legal reasons, please consider this bot environment as a social network ...' format: {self class repositoryUrlAboutIsolation}.
16 | 'Carpe Squeak! 🐭' }
17 | beforeSendDo: [:message |
18 | message disableWebPagePreview: true]
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkBot.class/instance/editMessage.changeTo..st:
--------------------------------------------------------------------------------
1 | message sending
2 | editMessage: oldMessage changeTo: newMessage
3 | "Avoid to add or remove medias to or from the message, which is currently not supported by the API. See comment in superclass."
4 |
5 | (oldMessage isMediaMessage and: [newMessage isMediaMessage not]) ifTrue: [
6 | newMessage becomeForward: ((newMessage as: TBPhotoMessage)
7 | form: (Form extent: 1 @ 1) "dummy form";
8 | yourself)].
9 | (oldMessage isMediaMessage not and: [newMessage isMediaMessage]) ifTrue: [
10 | newMessage becomeForward: ((newMessage as: TBMessage)
11 | yourself)].
12 |
13 | ^ super editMessage: oldMessage changeTo: newMessage
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkBot.class/instance/errorText..st:
--------------------------------------------------------------------------------
1 | private
2 | errorText: aString
3 |
4 | ^ self exceptionText: aString
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkBot.class/instance/exceptionText..st:
--------------------------------------------------------------------------------
1 | private
2 | exceptionText: aString
3 |
4 | ^ aString asText
5 | beAllItalic;
6 | yourself
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkBot.class/instance/generateAnswerTo..st:
--------------------------------------------------------------------------------
1 | update handling
2 | generateAnswerTo: aMessage
3 | "Generate an answer message to aMessage without sending it to the API.
4 | This method reimplements command parsing from super's #handleMessage:. The reason is that we want to use the same functionality from #messageEdited: which results in the need of a functional interface."
5 |
6 | | answer |
7 | aMessage text ifNotNil: [:text |
8 | self parseCommandIn: aMessage ifFound: [:command |
9 | answer := self answerCommand: command message: aMessage]].
10 |
11 | answer ifNil: [answer := self answerPrint: aMessage].
12 |
13 | ^ answer beReplyTo: aMessage
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkBot.class/instance/generateCodeExample.st:
--------------------------------------------------------------------------------
1 | private
2 | generateCodeExample
3 |
4 | ^ {
5 | '1 + 2 * 3'.
6 | '2 + 3 * 4'.
7 | '6 * 7'.
8 | 'Float pi i exp stringForReadout'.
9 | '(16 factorial + 1) isPrime'.
10 | '(1 to: 9) join asNumber sqrt truncateTo: 1e-3'
11 | } atRandom
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkBot.class/instance/handleCommand.message..st:
--------------------------------------------------------------------------------
1 | update handling
2 | handleCommand: aCommand message: aMessage
3 |
4 | ^ aCommand key
5 | caseOf: {
6 | [#start] -> [self doStart: aMessage].
7 | [#reset] -> [self doReset: aMessage].
8 | [#help] -> [self doHelp: aMessage]. }
9 | otherwise: [super handleCommand: aCommand message: aMessage]
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkBot.class/instance/helpStrings.st:
--------------------------------------------------------------------------------
1 | private
2 | helpStrings
3 |
4 | ^ OrderedDictionary new
5 | at: #print put: 'Evaluate the subsequent expression and answer the result';
6 | at: #do put: 'Evaluate the subsequent expression and answer the result as a printString';
7 | at: #inspect put: 'Evaluate the subsequent expression and answer an inspector view on the result';
8 | at: #reset put: 'Delete the entire session and forget that we have ever known each other';
9 | at: #start put: 'Send the initial greeting message again (just because it is so beautiful)';
10 | at: #help put: 'Show this help';
11 | yourself
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkBot.class/instance/initialize.st:
--------------------------------------------------------------------------------
1 | initialize-release
2 | initialize
3 |
4 | super initialize.
5 |
6 | sessions := Dictionary new.
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkBot.class/instance/isDebugging..st:
--------------------------------------------------------------------------------
1 | accessing
2 | isDebugging: aBoolean
3 |
4 | isDebugging := aBoolean.
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkBot.class/instance/isDebugging.st:
--------------------------------------------------------------------------------
1 | accessing
2 | isDebugging
3 |
4 | ^ isDebugging ifNil: [false]
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkBot.class/instance/logErrorsDuring.replyTo..st:
--------------------------------------------------------------------------------
1 | private
2 | logErrorsDuring: aBlock replyTo: aMessage
3 |
4 | ^ aBlock on: Error, Warning, Halt do: [:error |
5 | self
6 | sendText: (('{1}:\{2}' withCRs asText format: {
7 | 'Sorry, I did something wrong when processing your message' asText beAllBold.
8 | error description })
9 | addAttribute: TextEmphasis italic;
10 | yourself)
11 | toChat: aMessage chat
12 | replyTo: aMessage.
13 |
14 | self isDebugging ifTrue: [error pass]]
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkBot.class/instance/messageBlocked.withError..st:
--------------------------------------------------------------------------------
1 | update handling
2 | messageBlocked: aMessage withError: anError
3 |
4 | self removeSession: aMessage chat ifAbsent: [].
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkBot.class/instance/messageEdited..st:
--------------------------------------------------------------------------------
1 | update handling
2 | messageEdited: aMessage
3 |
4 | | newMessage originalAnswer |
5 | ^ self
6 | logErrorsDuring: [
7 | originalAnswer := (self sessionFor: aMessage chat)
8 | recordedAnswerTo: aMessage
9 | ifAbsent: [^ self].
10 | newMessage := self generateAnswerTo: aMessage.
11 |
12 | self editMessage: originalAnswer changeTo: newMessage]
13 | replyTo: aMessage
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkBot.class/instance/messageReceived..st:
--------------------------------------------------------------------------------
1 | update handling
2 | messageReceived: aMessage
3 |
4 | ^ self
5 | logErrorsDuring: [
6 | | answer |
7 | answer := self generateAnswerTo: aMessage.
8 | self sendMessage: answer]
9 | replyTo: aMessage
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkBot.class/instance/messageWith..st:
--------------------------------------------------------------------------------
1 | message creation
2 | messageWith: anObject
3 |
4 | ^ anObject asTelegramSmalltalkBotMessageFor: self
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkBot.class/instance/messageWithCollection..st:
--------------------------------------------------------------------------------
1 | message creation
2 | messageWithCollection: aCollection
3 |
4 | ^ self
5 | messageWithItems: (aCollection collect: #printString)
6 | caption: ('a {1} with {2} elements:' format: {
7 | aCollection class.
8 | aCollection size })
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkBot.class/instance/messageWithDictionary..st:
--------------------------------------------------------------------------------
1 | message creation
2 | messageWithDictionary: aDictionary
3 |
4 | ^ self
5 | messageWithItems: (aDictionary associations collect: #asString)
6 | caption: ('a {1} with {2} elements:' format: {
7 | aDictionary class.
8 | aDictionary size })
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkBot.class/instance/messageWithErrorText..st:
--------------------------------------------------------------------------------
1 | private
2 | messageWithErrorText: aString
3 |
4 | ^ self messageWithUserText: (self errorText: aString)
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkBot.class/instance/messageWithExceptionText..st:
--------------------------------------------------------------------------------
1 | private
2 | messageWithExceptionText: aString
3 |
4 | ^ self messageWithUserText: (self exceptionText: aString)
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkBot.class/instance/messageWithItems.caption..st:
--------------------------------------------------------------------------------
1 | message creation
2 | messageWithItems: elementStrings caption: aStringOrText
3 |
4 | ^ self messageWithUserText: (Text streamContents: [:stream |
5 | aStringOrText ifNotNil: [stream
6 | nextPutAll: aStringOrText;
7 | cr].
8 | elementStrings
9 | do: [:each | stream
10 | nextPutAll: '• ';
11 | nextPutAll: each tbWithoutLineEndings]
12 | separatedBy: [stream cr]])
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkBot.class/instance/messageWithObject..st:
--------------------------------------------------------------------------------
1 | message creation
2 | messageWithObject: anObject
3 |
4 | ^ self messageWithUserText: anObject asStringOrText
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkBot.class/instance/messageWithUserText..st:
--------------------------------------------------------------------------------
1 | message creation
2 | messageWithUserText: aStringOrText
3 |
4 | aStringOrText ifEmpty: [
5 | ^ self messageWithText: ('an empty {1}({2})' format: {
6 | thisContext objectClass: aStringOrText.
7 | thisContext objectIdentityHash: aStringOrText})].
8 |
9 | ^ self messageWithText: aStringOrText truncated: true
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkBot.class/instance/processMessage.andDo..st:
--------------------------------------------------------------------------------
1 | command processing
2 | processMessage: aMessage andDo: aBlock
3 |
4 | ^ self processMessage: aMessage andDo: aBlock ifError: [:error |
5 | self messageWithExceptionText: error description asString]
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkBot.class/instance/processMessage.andDo.ifError..st:
--------------------------------------------------------------------------------
1 | command processing
2 | processMessage: aMessage andDo: resultBlock ifError: errorBlock
3 |
4 | | session result |
5 | session := self sessionFor: aMessage chat.
6 | result := session
7 | processMessage: aMessage
8 | ifError: [:error | ^ session scheduleRecord: error fromAnswer: [errorBlock cull: error]].
9 | ^ session scheduleRecord: result fromAnswer: [resultBlock value: result]
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkBot.class/instance/removeSession.ifAbsent..st:
--------------------------------------------------------------------------------
1 | accessing - sessions
2 | removeSession: aChat ifAbsent: aBlock
3 |
4 | | session |
5 | session := sessions
6 | removeKey: aChat id
7 | ifAbsent: [^ aBlock value].
8 | session reset. "This would be redundant but helps us fulfill possible duties of deletion before GC rules."
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkBot.class/instance/replyMessage.withHtml..st:
--------------------------------------------------------------------------------
1 | message sending
2 | replyMessage: aMessage withHtml: htmlString
3 |
4 | ^ (self
5 | replyMessage: aMessage
6 | withHtmls: {htmlString}
7 | beforeSendDo: [:message |]) anyOne
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkBot.class/instance/replyMessage.withHtmls.beforeSendDo..st:
--------------------------------------------------------------------------------
1 | message sending
2 | replyMessage: aMessage withHtmls: htmlStrings beforeSendDo: messageBlock
3 |
4 | ^ htmlStrings collect: [:htmlString |
5 | | text message |
6 | text := (HtmlReadWriter on: htmlString readStream)
7 | breakLines: false;
8 | nextText.
9 | message := self messageWithText: text.
10 | messageBlock value: message.
11 | self
12 | sendMessage: message
13 | toChat: aMessage chat]
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkBot.class/instance/sessionFor..st:
--------------------------------------------------------------------------------
1 | accessing - sessions
2 | sessionFor: aChat
3 |
4 | ^ sessions
5 | at: aChat id
6 | ifAbsentPut: [TelegramSmalltalkSession new]
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkBot.class/methodProperties.json:
--------------------------------------------------------------------------------
1 | {
2 | "class" : {
3 | "repositoryStub" : "ct 3/6/2021 04:12",
4 | "repositoryUrl" : "ct 3/6/2021 04:12",
5 | "repositoryUrlAboutIsolation" : "ct 3/7/2021 17:31",
6 | "secrets" : "ct 3/6/2021 13:17" },
7 | "instance" : {
8 | "answerCommand:message:" : "ct 10/3/2020 14:47",
9 | "answerDo:" : "ct 10/3/2020 14:57",
10 | "answerInspect:" : "ct 3/5/2021 14:45",
11 | "answerPrint:" : "ct 10/3/2020 14:57",
12 | "doHelp:" : "ct 3/7/2021 23:55",
13 | "doReset:" : "ct 10/3/2020 18:39",
14 | "doStart:" : "ct 3/7/2021 20:25",
15 | "editMessage:changeTo:" : "ct 10/3/2020 18:48",
16 | "errorText:" : "ct 10/3/2020 14:48",
17 | "exceptionText:" : "ct 10/3/2020 14:48",
18 | "generateAnswerTo:" : "ct 10/3/2020 15:06",
19 | "generateCodeExample" : "ct 3/7/2021 23:38",
20 | "handleCommand:message:" : "ct 3/6/2021 04:05",
21 | "helpStrings" : "ct 3/7/2021 23:53",
22 | "initialize" : "ct 9/9/2020 13:16",
23 | "isDebugging" : "ct 9/22/2020 01:17",
24 | "isDebugging:" : "ct 9/22/2020 01:17",
25 | "logErrorsDuring:replyTo:" : "ct 10/3/2020 18:34",
26 | "messageBlocked:withError:" : "ct 3/22/2021 14:22",
27 | "messageEdited:" : "ct 10/3/2020 13:21",
28 | "messageReceived:" : "ct 10/3/2020 14:58",
29 | "messageWith:" : "ct 10/2/2020 18:47",
30 | "messageWithCollection:" : "ct 9/22/2020 01:53",
31 | "messageWithDictionary:" : "ct 9/22/2020 02:22",
32 | "messageWithErrorText:" : "ct 10/3/2020 17:46",
33 | "messageWithExceptionText:" : "ct 10/3/2020 17:46",
34 | "messageWithItems:caption:" : "ct 1/24/2021 21:31",
35 | "messageWithObject:" : "ct 10/2/2020 18:49",
36 | "messageWithUserText:" : "ct 10/2/2020 18:52",
37 | "processMessage:andDo:" : "ct 10/3/2020 14:58",
38 | "processMessage:andDo:ifError:" : "ct 10/3/2020 14:59",
39 | "removeSession:ifAbsent:" : "ct 10/3/2020 16:08",
40 | "replyMessage:withHtml:" : "ct 3/7/2021 23:39",
41 | "replyMessage:withHtmls:beforeSendDo:" : "ct 3/7/2021 23:39",
42 | "sessionFor:" : "ct 10/3/2020 16:13" } }
43 |
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkBot.class/properties.json:
--------------------------------------------------------------------------------
1 | {
2 | "category" : "TelegramSmalltalkBot-Core",
3 | "classinstvars" : [
4 | ],
5 | "classvars" : [
6 | ],
7 | "commentStamp" : "ct 10/3/2020 21:28",
8 | "instvars" : [
9 | "sessions",
10 | "isDebugging" ],
11 | "name" : "TelegramSmalltalkBot",
12 | "pools" : [
13 | ],
14 | "super" : "TelegramBot",
15 | "type" : "normal" }
16 |
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkSession.class/README.md:
--------------------------------------------------------------------------------
1 | I represent the session environment of a TelegramSmalltalkBot for a particular user. I am capable of holding variable bindings, remembering message references and outputs, and evaluating user code against the session context.
2 |
3 | Instance Variables
4 | bindings: Dictionary that maps strings to user objects.
5 | answers: WeakValueDictionary that stores message sent by the bot associated with their IDs. Used to edit these messages if the referenced message has been edited.
6 | pinnedAnswers: Collection that holds strong references to the answers. See explanation of pinning below.
7 | results: WeakValueDictionary that stores output objects of messages sent by the bot, associated with the messages' IDs. Used to provide the receiver context for a user message referencing to an earlier bot message.
8 | pinnedResults: Collection that holds strong references to the results. See explanation of pinning below.
9 | pinnedClosures: WeakKeyDictionary that holds references to BlockClosures that are registered in the weak-referencing EventManager database.
10 |
11 | # Pinning
12 | To serve scalability when running a bot with many frequent users, I support automatic recycling of older session contents ("records") by making use of the GC. To implement this, the relevant records theirselves (answers and results) are hold using weak references only, and a limittable list of the most recent records is kept in memory using the pinned collections. See #tidyUpRecords: for releasing older records.
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkSession.class/instance/basicRecordAnswer..st:
--------------------------------------------------------------------------------
1 | records
2 | basicRecordAnswer: aMessage
3 |
4 | answers
5 | at: aMessage referenceMessageId
6 | put: aMessage.
7 | self pinRecord: aMessage to: pinnedAnswers.
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkSession.class/instance/basicRecordResult.forMessage..st:
--------------------------------------------------------------------------------
1 | records
2 | basicRecordResult: anObject forMessage: aMessage
3 |
4 | results
5 | at: aMessage messageId
6 | put: anObject.
7 | self pinRecord: anObject to: pinnedResults.
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkSession.class/instance/bindingOf..st:
--------------------------------------------------------------------------------
1 | binding
2 | bindingOf: aString
3 |
4 | self mustDeclareVariables ifTrue: [^ super bindingOf: aString].
5 |
6 | (bindings includesKey: aString) ifFalse: [
7 | bindings at: aString put: nil].
8 | ^ bindings associationAt: aString
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkSession.class/instance/doSafely.ifError..st:
--------------------------------------------------------------------------------
1 | evaluation
2 | doSafely: aBlock ifError: errorBlock
3 |
4 | self flag: #extend. "Here is much more potential for isolation. Transcript forwarding, ToolSet installation, timeouts ..."
5 |
6 | thisContext wrap: [:wrapped | wrapped
7 | valueWithin: 60 seconds
8 | onTimeout: [errorBlock value: 'Expression timed out']].
9 |
10 | ^ self
11 | doSafely:[
12 | thisContext wrap: [:wrapped | SystemChangeNotifier uniqueInstance doSilently: wrapped].
13 | aBlock value]
14 | on: ProvideAnswerNotification, (Error, Warning, Halt), UnhandledError
15 | do: [:error | errorBlock cull: error]
16 | useSandbox: self isolationEnabled
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkSession.class/instance/doSafely.on.do.useSandbox..st:
--------------------------------------------------------------------------------
1 | evaluation
2 | doSafely: aBlock on: exceptionHandler do: exceptionBlock useSandbox: shouldUseSandbox
3 |
4 | | sandbox result |
5 | shouldUseSandbox ifFalse: [
6 | ^ aBlock on: exceptionHandler do: exceptionBlock].
7 |
8 | thisContext insertSender: (Context contextOn: SandboxError do: exceptionBlock).
9 | sandbox := (sandboxMemory ifNil: [Sandbox new] ifNotNil: [Sandbox fromMemory: sandboxMemory])
10 | stepLimit: 10000000;
11 | flag: #todo; "garbage-collect side effects that are not related to bindings"
12 | yourself.
13 | {bindings. bindings array} , bindings array , bindings values do: [:ea |
14 | sandbox addObject: ea].
15 | self secrets do: [:secret |
16 | sandbox patchObject: secret with: (
17 | self obfuscateSecret: secret)].
18 |
19 | result := sandbox
20 | evaluate: aBlock
21 | on: exceptionHandler
22 | do: exceptionBlock.
23 | sandboxMemory := sandbox exportMemory.
24 | self maximumMemorySize ifNotNil: [:maxSize |
25 | | memSize |
26 | memSize := sandboxMemory memorySize.
27 | memSize > maxSize ifTrue: [
28 | [self notify: 'I''m sorry, but you have exceeded your memory limit. Everything will be wiped now']
29 | ensure: [sandboxMemory := nil]].
30 | memSize > (maxSize // 2) ifTrue: [
31 | "self notify: 'You have reached {1}% of your memory limit now. Maybe think about an upgrade or back up your data?'."
32 | self flag: #todo. "A mechanism for warning the user without aborting execution - maybe resume after Warnings by default? But would break threading structure. Or write all warnings into single message?"]].
33 |
34 | self flag: #hack. "Problem: Secret could be anywhere deeply nested in a real object"
35 | (self secrets anySatisfy: [:secret | (result longPrintString ifNil: ['']) includesSubstring: (secret ifNil: [''])])
36 | ifTrue: [^ nil].
37 |
38 | ^ result
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkSession.class/instance/evaluate.for.ifError..st:
--------------------------------------------------------------------------------
1 | evaluation
2 | evaluate: aString for: receiver ifError: aBlock
3 |
4 | ^ self
5 | doSafely: [Compiler new
6 | evaluate: aString
7 | in: nil
8 | to: receiver
9 | environment: Smalltalk globals
10 | notifying: self
11 | ifFail: [aBlock value]
12 | logged: false]
13 | ifError: aBlock
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkSession.class/instance/initialize.st:
--------------------------------------------------------------------------------
1 | initialize-release
2 | initialize
3 |
4 | super initialize.
5 |
6 | bindings := Dictionary new.
7 | answers := WeakValueDictionary new.
8 | results := WeakValueDictionary new.
9 | pinnedAnswers := OrderedCollection new.
10 | pinnedResults := OrderedCollection new.
11 | pinnedClosures := WeakKeyDictionary new.
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkSession.class/instance/isolationEnabled..st:
--------------------------------------------------------------------------------
1 | accessing
2 | isolationEnabled: aBoolean
3 |
4 | isolationEnabled := aBoolean.
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkSession.class/instance/isolationEnabled.st:
--------------------------------------------------------------------------------
1 | accessing
2 | isolationEnabled
3 |
4 | ^ isolationEnabled ifNil: [true]
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkSession.class/instance/maximumMemorySize.st:
--------------------------------------------------------------------------------
1 | accessing
2 | maximumMemorySize
3 | "nil means the GC is disabled"
4 |
5 | ^ 1000000
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkSession.class/instance/maximumRecordSize.st:
--------------------------------------------------------------------------------
1 | accessing
2 | maximumRecordSize
3 | "nil means the GC is disabled"
4 |
5 | ^ nil
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkSession.class/instance/mustDeclareVariables.st:
--------------------------------------------------------------------------------
1 | accessing
2 | mustDeclareVariables
3 |
4 | ^ false
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkSession.class/instance/notify.at.in..st:
--------------------------------------------------------------------------------
1 | evaluation
2 | notify: aString at: location in: source
3 |
4 | | error |
5 | error := (SyntaxErrorNotification
6 | cue: (CompilationCue source: source contents)
7 | doitFlag: true
8 | errorMessage: aString
9 | location: location) signal.
10 | error tryNewSourceIfAvailable.
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkSession.class/instance/obfuscateSecret..st:
--------------------------------------------------------------------------------
1 | private
2 | obfuscateSecret: secret
3 | "Don't let the user be aware of that they were dealing with a secret, just obfuscate it"
4 |
5 | | characters |
6 | secret isText ifTrue: [
7 | ^ Text string: (self obfuscateSecret: secret string) runs: secret runs].
8 | secret isString ifFalse: [^ nil].
9 |
10 | characters := ($a to: $z) , ($A to: $Z) , ($0 to: $9).
11 | ^ (1 to: secret size)
12 | collect: [:i | characters atRandom]
13 | as: String
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkSession.class/instance/pinRecord.to..st:
--------------------------------------------------------------------------------
1 | records
2 | pinRecord: anObject to: pinnedRecords
3 |
4 | pinnedRecords addLast: anObject.
5 |
6 | "Could be theoretically deferred"
7 | self tidyUpRecords: pinnedRecords.
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkSession.class/instance/processMessage.ifError..st:
--------------------------------------------------------------------------------
1 | message processing
2 | processMessage: aMessage ifError: aBlock
3 |
4 | ^ self
5 | evaluate: aMessage mainText
6 | for: (self receiverFor: aMessage replyToMessage)
7 | ifError: aBlock
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkSession.class/instance/receiverFor..st:
--------------------------------------------------------------------------------
1 | accessing
2 | receiverFor: aMessage
3 |
4 | aMessage ifNil: [^ nil].
5 | ^ results
6 | at: aMessage messageId
7 | ifAbsent: [nil]
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkSession.class/instance/record.fromAnswer.bot..st:
--------------------------------------------------------------------------------
1 | records
2 | record: anObject fromAnswer: aMessage bot: aBot
3 |
4 | self basicRecordAnswer: aMessage.
5 | self basicRecordResult: anObject forMessage: aMessage.
6 |
7 | answers
8 | select: [:answer | (answer referenceMessage ifNotNil: #replyToMessage)
9 | ifNil: [false]
10 | ifNotNil: [:previousAnswer | previousAnswer messageId = aMessage messageId]]
11 | thenDo: [:answer | aBot handleEditedMessage: answer referenceMessage].
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkSession.class/instance/recordedAnswerTo.ifAbsent..st:
--------------------------------------------------------------------------------
1 | records
2 | recordedAnswerTo: aMessage ifAbsent: aBlock
3 |
4 | ^ answers
5 | at: aMessage messageId
6 | ifAbsent: aBlock
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkSession.class/instance/reset.st:
--------------------------------------------------------------------------------
1 | initialize-release
2 | reset
3 |
4 | bindings removeAll.
5 | answers removeAll.
6 | results removeAll.
7 | pinnedAnswers removeAll.
8 | pinnedResults removeAll.
9 | pinnedClosures removeAll.
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkSession.class/instance/scheduleRecord.fromAnswer..st:
--------------------------------------------------------------------------------
1 | records
2 | scheduleRecord: anObject fromAnswer: aBlock
3 |
4 | | answer scheduledBlock |
5 | answer := aBlock value.
6 | answer ifNil: [^ answer].
7 |
8 | scheduledBlock := [:bot | self record: anObject fromAnswer: answer bot: bot].
9 | answer
10 | when: #sent
11 | send: #value:
12 | to: scheduledBlock.
13 | pinnedClosures at: answer put: scheduledBlock.
14 |
15 | ^ answer
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkSession.class/instance/secrets.st:
--------------------------------------------------------------------------------
1 | private
2 | secrets
3 |
4 | ^ TelegramSmalltalkBot secrets
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkSession.class/instance/tidyUpRecords..st:
--------------------------------------------------------------------------------
1 | records
2 | tidyUpRecords: pinnedRecords
3 |
4 | | overrun |
5 | overrun := pinnedRecords size - (self maximumRecordSize ifNil: [^ self]).
6 | overrun <= 0 ifTrue: [^ self].
7 |
8 | pinnedRecords removeFirst: overrun.
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkSession.class/instance/wantsInteractiveErrorCorrection.st:
--------------------------------------------------------------------------------
1 | evaluation
2 | wantsInteractiveErrorCorrection
3 |
4 | ^ false
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkSession.class/methodProperties.json:
--------------------------------------------------------------------------------
1 | {
2 | "class" : {
3 | },
4 | "instance" : {
5 | "basicRecordAnswer:" : "ct 9/29/2020 14:23",
6 | "basicRecordResult:forMessage:" : "ct 9/29/2020 14:23",
7 | "bindingOf:" : "ct 9/9/2020 13:59",
8 | "doSafely:ifError:" : "ct 3/6/2021 02:10",
9 | "doSafely:on:do:useSandbox:" : "ct 3/6/2021 14:34",
10 | "evaluate:for:ifError:" : "ct 10/3/2020 18:46",
11 | "initialize" : "ct 10/2/2020 15:51",
12 | "isolationEnabled" : "ct 3/6/2021 02:10",
13 | "isolationEnabled:" : "ct 3/6/2021 02:10",
14 | "maximumMemorySize" : "ct 3/6/2021 02:37",
15 | "maximumRecordSize" : "ct 10/3/2020 21:55",
16 | "mustDeclareVariables" : "ct 9/9/2020 13:52",
17 | "notify:at:in:" : "ct 3/6/2021 14:22",
18 | "obfuscateSecret:" : "ct 3/6/2021 13:25",
19 | "pinRecord:to:" : "ct 9/29/2020 14:23",
20 | "processMessage:ifError:" : "ct 10/3/2020 14:34",
21 | "receiverFor:" : "ct 10/3/2020 16:05",
22 | "record:fromAnswer:bot:" : "ct 3/7/2021 23:45",
23 | "recordedAnswerTo:ifAbsent:" : "ct 9/29/2020 14:24",
24 | "reset" : "ct 10/2/2020 16:01",
25 | "scheduleRecord:fromAnswer:" : "ct 10/2/2020 15:52",
26 | "secrets" : "ct 3/6/2021 13:26",
27 | "tidyUpRecords:" : "ct 9/29/2020 14:19",
28 | "wantsInteractiveErrorCorrection" : "ct 9/9/2020 13:47" } }
29 |
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Core.package/TelegramSmalltalkSession.class/properties.json:
--------------------------------------------------------------------------------
1 | {
2 | "category" : "TelegramSmalltalkBot-Core",
3 | "classinstvars" : [
4 | ],
5 | "classvars" : [
6 | ],
7 | "commentStamp" : "ct 3/6/2021 02:15",
8 | "instvars" : [
9 | "bindings",
10 | "answers",
11 | "pinnedAnswers",
12 | "results",
13 | "pinnedResults",
14 | "pinnedClosures",
15 | "isolationEnabled",
16 | "sandboxMemory" ],
17 | "name" : "TelegramSmalltalkSession",
18 | "pools" : [
19 | ],
20 | "super" : "Object",
21 | "type" : "normal" }
22 |
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Core.package/Text.extension/instance/asTelegramSmalltalkBotMessageFor..st:
--------------------------------------------------------------------------------
1 | *TelegramSmalltalkBot-Core
2 | asTelegramSmalltalkBotMessageFor: aBot
3 |
4 | ^ aBot messageWithUserText: self
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Core.package/Text.extension/methodProperties.json:
--------------------------------------------------------------------------------
1 | {
2 | "class" : {
3 | },
4 | "instance" : {
5 | "asTelegramSmalltalkBotMessageFor:" : "ct 10/2/2020 18:49" } }
6 |
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Core.package/Text.extension/properties.json:
--------------------------------------------------------------------------------
1 | {
2 | "name" : "Text" }
3 |
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Core.package/monticello.meta/categories.st:
--------------------------------------------------------------------------------
1 | SystemOrganization addCategory: #'TelegramSmalltalkBot-Core'!
2 |
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Core.package/monticello.meta/initializers.st:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LinqLover/TelegramSmalltalkBot/9ffd71a4b40aa175aa4e1ae33e42952c84598f9a/src/TelegramSmalltalkBot-Core.package/monticello.meta/initializers.st
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Core.package/properties.json:
--------------------------------------------------------------------------------
1 | {
2 | }
3 |
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Tests.package/.filetree:
--------------------------------------------------------------------------------
1 | {
2 | "noMethodMetaData" : true,
3 | "separateMethodMetaAndSource" : false,
4 | "useCypressPropertiesFile" : true }
5 |
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Tests.package/.squot-contents:
--------------------------------------------------------------------------------
1 | SquotTrackedObjectMetadata {
2 | #objectClassName : #PackageInfo,
3 | #objectsReplacedByNames : true,
4 | #serializer : #SquotCypressCodeSerializer
5 | }
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Tests.package/TelegramSmalltalkBotTest.class/README.md:
--------------------------------------------------------------------------------
1 | I provide acceptance tests for the TelegramSmalltalkBot. An ugly kind of mocking is used for isolating the bot class from the API, which should probably be replaced by composition. See #setUp and note in the class comment of TelegramBot.
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Tests.package/TelegramSmalltalkBotTest.class/instance/askBot..st:
--------------------------------------------------------------------------------
1 | support
2 | askBot: aMessage
3 |
4 | (aMessage respondsTo: #messageId) ifFalse: [
5 | ^ self askBot: (self makeMessageFrom: aMessage)].
6 |
7 | ^ self receiveBotMessagesDuring: [
8 | bot handleMessage: aMessage]
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Tests.package/TelegramSmalltalkBotTest.class/instance/botSession.st:
--------------------------------------------------------------------------------
1 | support
2 | botSession
3 |
4 | ^ bot sessionFor: self makeChat
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Tests.package/TelegramSmalltalkBotTest.class/instance/clientChatId.st:
--------------------------------------------------------------------------------
1 | accessing
2 | clientChatId
3 |
4 | ^ 42
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Tests.package/TelegramSmalltalkBotTest.class/instance/editMessage.text..st:
--------------------------------------------------------------------------------
1 | watcher
2 | editMessage: aMessage text: aStringOrText
3 |
4 | editedMessages at: aMessage messageId put: aStringOrText.
5 |
6 | aMessage text: aStringOrText.
7 | ^ aMessage
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Tests.package/TelegramSmalltalkBotTest.class/instance/makeChat.st:
--------------------------------------------------------------------------------
1 | support
2 | makeChat
3 |
4 | ^ JsonObject new
5 | at: #id put: self clientChatId;
6 | yourself
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Tests.package/TelegramSmalltalkBotTest.class/instance/makeMessageFrom..st:
--------------------------------------------------------------------------------
1 | support
2 | makeMessageFrom: anObject
3 |
4 | | message |
5 | (anObject isString or: [anObject isText]) ifFalse: [
6 | self fail: 'Message type not yet suppported!'].
7 |
8 | message := JsonObject new
9 | at: #text put: anObject;
10 | at: #messageId put: self nextMessageId;
11 | at: #from put: self makeChat;
12 | at: #chat put: (JsonObject new
13 | at: #id put: self clientChatId;
14 | at: #type put: #private;
15 | yourself);
16 | yourself.
17 |
18 | "Add missing TBTextCommand attributes"
19 | message text ifNotNil: [:text | | commandRanges newText |
20 | newText := text asText copy.
21 | commandRanges := newText string allRangesOfRegexMatches: '(?Squeak'' asTextFromHtml'
6 | answerSatisfy: [:answer |
7 | self
8 | assert: 'Squeak'
9 | equals: answer text printHtmlString].
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Tests.package/TelegramSmalltalkBotTest.class/instance/testVariables.st:
--------------------------------------------------------------------------------
1 | tests
2 | testVariables
3 |
4 | self askBot: '/reset'.
5 |
6 | self
7 | shouldBotAsked: 'x := 1. y := x + 1'
8 | answer: '2'.
9 | self
10 | shouldBotAsked: 'y + 1'
11 | answer: '3'.
12 |
13 | self
14 | shouldBotAsked: '/reset'
15 | answerSatisfy: [:answer |
16 | answer text asString asLowercase includesSubstring: 'session'].
17 | self
18 | shouldBotAsked: 'y + 1'
19 | answerSatisfy: [:answer |
20 | answer text asString includesSubstring: 'MessageNotUnderstood: UndefinedObject']
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Tests.package/TelegramSmalltalkBotTest.class/methodProperties.json:
--------------------------------------------------------------------------------
1 | {
2 | "class" : {
3 | },
4 | "instance" : {
5 | "askBot:" : "ct 10/3/2020 14:36",
6 | "botSession" : "ct 3/6/2021 02:14",
7 | "clientChatId" : "ct 10/2/2020 16:07",
8 | "editMessage:text:" : "ct 10/2/2020 16:03",
9 | "makeChat" : "ct 3/6/2021 02:14",
10 | "makeMessageFrom:" : "ct 3/6/2021 02:13",
11 | "nextMessageId" : "ct 9/22/2020 00:03",
12 | "receiveBotMessagesDuring:" : "ct 10/2/2020 14:30",
13 | "receiveEditedBotMessagesDuring:" : "ct 10/2/2020 16:04",
14 | "sendMessage:" : "ct 10/2/2020 16:05",
15 | "setUp" : "ct 11/1/2020 18:02",
16 | "shouldBotAsked:answer:" : "ct 10/2/2020 14:27",
17 | "shouldBotAsked:answerSatisfy:" : "ct 10/2/2020 16:14",
18 | "shouldBotAsked:answersSatisfy:" : "ct 3/7/2021 17:16",
19 | "someNumber" : "ct 9/21/2020 19:50",
20 | "someString" : "ct 9/21/2020 19:12",
21 | "tearDown" : "ct 9/22/2020 00:59",
22 | "testAnimation" : "ct 10/3/2020 18:50",
23 | "testDialog" : "ct 10/2/2020 14:51",
24 | "testDo" : "ct 9/21/2020 19:52",
25 | "testEditMessage" : "ct 10/2/2020 16:16",
26 | "testForm" : "ct 9/21/2020 21:45",
27 | "testHelp" : "ct 3/7/2021 17:20",
28 | "testInspect" : "ct 9/21/2020 20:09",
29 | "testInternalError" : "ct 3/6/2021 02:13",
30 | "testPrint" : "ct 9/21/2020 21:45",
31 | "testRuntimeError" : "ct 9/21/2020 22:48",
32 | "testSimple" : "ct 9/21/2020 19:49",
33 | "testSound" : "ct 9/21/2020 21:45",
34 | "testStart" : "ct 3/7/2021 17:18",
35 | "testSyntaxError" : "ct 9/21/2020 22:23",
36 | "testText" : "ct 9/21/2020 22:21",
37 | "testVariables" : "ct 10/2/2020 14:28" } }
38 |
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Tests.package/TelegramSmalltalkBotTest.class/properties.json:
--------------------------------------------------------------------------------
1 | {
2 | "category" : "TelegramSmalltalkBot-Tests",
3 | "classinstvars" : [
4 | ],
5 | "classvars" : [
6 | ],
7 | "commentStamp" : "ct 10/3/2020 21:57",
8 | "instvars" : [
9 | "bot",
10 | "lastMessageId",
11 | "receivedMessages",
12 | "editedMessages" ],
13 | "name" : "TelegramSmalltalkBotTest",
14 | "pools" : [
15 | ],
16 | "super" : "TestCase",
17 | "type" : "normal" }
18 |
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Tests.package/monticello.meta/categories.st:
--------------------------------------------------------------------------------
1 | SystemOrganization addCategory: #'TelegramSmalltalkBot-Tests'!
2 |
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Tests.package/monticello.meta/initializers.st:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LinqLover/TelegramSmalltalkBot/9ffd71a4b40aa175aa4e1ae33e42952c84598f9a/src/TelegramSmalltalkBot-Tests.package/monticello.meta/initializers.st
--------------------------------------------------------------------------------
/src/TelegramSmalltalkBot-Tests.package/properties.json:
--------------------------------------------------------------------------------
1 | {
2 | }
3 |
--------------------------------------------------------------------------------