Age | Commit message (Collapse) | Author |
|
The `=` was previously aligned with the function definition below, but
since the pattern match of the lower function definition changed, the
`=`s were no longer aligned.
Seems like it would be weird to move the `=` out and create a bunch of
blank space to align the two `=`s, so moving the function body to the
next line.
|
|
|
|
It's duplicated so I figured I'd take it out.
|
|
Get rid of the `fail` and use an `Either` for error handling instead.
This allows us to send back the response string like before, but provide
an additional error message when no data comes back from the database
query.
Remove the old error handling code I had tried to set up previously.
|
|
This doesn't really work, but I wanted to hold onto this step. I've been
reading about error handling, notably this article:
http://www.randomhacks.net/2007/03/10/haskell-8-ways-to-report-errors/
I kind of like the idea of just using `fail`, and being able to have
that set up some polymorphism to handle `Maybe`, `Either`, and `IO`
situations, but today read some literature that discouraged using fail,
since not all monads implement it.
Anyway, this code doesn't print out the error string like I intended it
to, so I guess I'll have to use `Either` instead.
|
|
We don't need to select the channel because we don't do anything with
it. All we need is the repo URL.
Create a new data type for use with the database query that allows us to
select only the URL. Remove the `ChannelRepoUrl` type as it's no longer
needed.
|
|
Ask for the row corresponding to the channel received from the chat
message. This gets rid of the previously hard-coded SQL and allows us to
dynamically get the right URL value.
|
|
Added these while developing ff00355ade021d3e06d55017c5337f488474e5cb to
test out different theories while trying to get the project to compile.
These are no longer relevant any more, so delete them.
|
|
We're not using it, and originally I didn't even put it in my SELECT
query (which actually messed me up for a couple hours, as two columns in
the SELECT does not match three columns in the data type). Added it
later as a fix for that problem. But since I don't really want or need
to select the id, we shouldn't bother, and in order to do so, we need to
update the Haskell data type to only include two fields, so
sqlite-simple can correctly convert the data.
|
|
The GitHub Commit plugin needs access to the database in order to work
properly. Include 'sqlite-simple' to give us access to the database and
have it transform rows into Haskell objects.
This change has the unfortunate effect of forcing us to make
`PluginAction` an IO type. This means we'll need to make all our plugin
action functions use IO, even the pure ones. `PluginAction` now takes a
database connection as a second argument, and returns an `IO String`.
I don't like the fact that the database argument is effectively
hard-coded. Thus the TODO note to try to make a type class to replace it
so we can pass a null database connection when it isn't needed.
Eventually, if more things like this need to be passed into the
function, we might consider making a new struct type for the purpose.
In order to be able to use the `query_` function, which takes a
String-like `Query`, we have to declare `OverloadedStrings`. Now in
`gitHubCommitAction` we take the database connection as an argument,
select a row (for now it's always the first one to test this out), and
send back a GitHub commit URL (if a record matched, otherwise return an
empty string). Eventually we'll want to make this more real by selecting
the row corresponding to the channel in `message`. Also, instead of
returning an empty string, we should be returning an `Either`, so the
error state is clear.
Update the `ChannelRepoUrl` data constructor to use record syntax so we
can name its fields.
|
|
Instead of manually writing out the type of the action function returned
from `performPlugin`, use the consolidated `PluginAction` type.
This makes it easier for us to change the `PluginAction` type signature
if necessary.
|
|
Define some extra types in `ChannelRepoUrl` because I didn't like the
generic ones.
|
|
A type that will be used in conjunction with 'sqlite-simple' to read
values from the plugin's database table.
|
|
Have `PluginAction` functions take a Message type instead of a plain
string. This gives us access to additional fields on the message:
channel and nick.
sorbot.cabal:
Add `Message` to `exposed-modules` in order to be able to use it when
building.
Lib.hs:
Change our test message to be a `Message` data type to conform to the new
`PluginAction` interface.
Plugin.hs:
Use `Message` where appropriate. When calling `perform`, pass it a
`Message` instead of a `String`. This means we have to match the regex
within the plugin in order to get the match data. The benefit of that
change is that now we have access to the full message in the plugin if
we need it, not just the regex-filtered part.
GitHubCommit.hs:
Do a regex match against the Message text in order to get the SHA we
want from the message.
|
|
When I added the `Plugin(..)` export, I didn't think to remove the
exports for the functions created by the Plugin record data type. Didn't
see the warnings from the compiler when building until now.
|
|
We previously removed the call to `=~` that we needed this import for in
4bb65c50a2a85404af6d122acc53b6fb1739652b.
|
|
Add a few types to collect properties of a message, including message
body, channel posted to, and sender.
Need something like this for the GitHub Commit plugin, where we need
access to the message to get the SHA, and we need the channel to get the
repo URL from the database.
|
|
Write some short documentation above the function definitions to remind
myself later about what they're supposed to do.
|
|
Extract the GitHub commit plugin code from "Plugin.hs" into its own
module. Now that we have things more set up and working to a certain
degree, we can split the code out.
|
|
Move our base plugin types to a new module to enable us to use them in
both the plugin matching code (which we'll leave in "Plugin.hs") and in
specialised plugin modules.
This enables us to import and provide a list of plugins in `plugins` in
"Plugin.hs" and use these types in that file and in the plugin files
without any circular/recursive module dependencies.
|
|
Instead of implicitly using `String -> String` as the type for plugin
action/perform functions, create a real type to represent this.
|
|
I didn't even need the `matchPlugin` that took `plugins` as an argument,
I can just use the `plugins` function directly in `matchPlugin`. Get rid
of `realMatchPlugin` because that was just a temporary name until I got
things working.
Move `firstPlugin` into the definition of `matchPlugin` because it's not
needed anywhere else and is just used to pattern match for the first
matched plugin in the list.
|
|
I had been using the regex instead of the match result. Do another regex
match to correctly output our SHA instead of the match regex.
I had tried putting the `=~` match in another function and using it from
here and in the list comprehension in `matchPlugins`, but then found out
that, of course, the return types didn't agree (`matchPlugins` needs a
`Bool` and `performPlugin` needs a `String`). Ended up dispensing with
the extra function and doing the match both times instead.
|
|
Take our initial experiment on the regex matcher from before and expand
it into the beginnings of a plugin architecture.
Add a new `Plugin` module. This exports a `Plugin` data type that
collects a regex and a function together. The idea will be to create a
list of plugins, and chat messages will get matched against the regexes
in that list. If the regex matches, the associated function will be run.
If the function produces output, that output should eventually be sent
back to the chat as a message.
Implemented `Show` on `Plugin` manually because the `String -> String`
function can't be derived. Decided to forego that part in the output and
only show the regex when printing.
Ended up with a little redundancy here in the functions for matching
plugins. The `realMatchPlugin` function needs to be renamed, just called
it that for now because I had started with `matchPlugin`, and only later
realised that its interface wasn't what I needed when calling it from
the `Lib` module.
Need to add some doc comments, but figured I'd commit what I have now
since it sort of works.
The `firstPlugin` function is only used by `matchPlugin`, so now I
realise it should probably be a local `where`-defined function.
Also thought the `String -> String` wasn't very descriptive. We'll want
to make a type alias for that that tells people this is a plugin
function.
Added a test plugin inline in this file for now. Eventually our plugins
should be stored in separate files in a "Plugins" directory (or
"Plugin", depending on how the module system works, will have to look
into that). For now, the program outputs the correct string created by
`gitHubCommitAction`, which is actually pretty cool. It's not actually
the really correct string, as the `match` variable is the regex instead
of the matched part of the test string, but close enough for now. We'll
go back and correct that momentarily.
Needed to add `Plugin` to the `exposed-modules` section in the `library`
build metadata in order to properly build the code. Was getting this
error about it:
Warning: The following modules should be added to exposed-modules or other-modules in /Users/tw/Documents/Development/sorbot/sorbot/sorbot.cabal:
- In the library component:
Plugin
Missing modules in the cabal file are likely to cause undefined reference errors from the linker, along with other problems.
Really liking this so far!
|
|
Only match SHAs if they're the full 40 characters long. This will become
important later when we have an actual chat bot and we don't want to
match on partial SHAs.
|
|
* Add the 'regex-tdfa' library for RegEx handling
* Experiment with matching a Git SHA
|
|
$ stack new sorbot new-template
GHC v8.0.2
|