@ v1.0.0
# cowsay
```
% figlet "Cowsay" | ~/go/bin/cowsay -f gopher -n
______________________________________
/ ____ \
| / ___|_____ _____ __ _ _ _ |
| | | / _ \ \ /\ / / __|/ _` | | | | |
| | |__| (_) \ V V /\__ \ (_| | |_| | |
| \____\___/ \_/\_/ |___/\__,_|\__, | |
\ |___/ /
--------------------------------------
\
\
ยด.-::::::-.ยด
.:-::::::::::::::-:.
ยด_::: :: :::_ยด
.:( o :: o ):.
ยด::: (..) :::.
ยด:::::::UU:::::::ยด
.::::::::::::::::.
O::::::::::::::::O
-::::::::::::::::-
ยด::::::::::::::::ยด
.::::::::::::::.
oO:::::::Oo
```
This is a complete rewrite of [cowsay](https://en.wikipedia.org/wiki/Cowsay) in
Go, including translations of all the cowfiles that ship with version 3.x, plus
a few new ones.
## Installation
```shell
go install nmyk.io/cowsay/cmd/cow{say,think}@latest
```
## Usage
```go
package main
import (
"bytes"
"text/template"
log "github.com/sirupsen/logrus"
"nmyk.io/cowsay"
)
func main() {
// use it out of the box
cowsay.Cow{}.Say("mooo")
// for convenience; identical to above
cowsay.Cowsay("mooo")
/*
______
< mooo >
------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
*/
// customize mood and wrap width, use cowthink style
cowsay.Cow{Mood: cowsay.Wired, Width: 8}.Think("hmmmmmmmmmmmm!")
/*
_________
( hmmmmmm )
( mmmmmm! )
---------
o ^__^
o (OO)\_______
(__)\ )\/\
||----w |
|| ||
*/
// use a Mood literal instead of builtin Mood
cowsay.Cow{Mood: cowsay.Mood{"xx", "U "}}.Say("im ded")
/*
________
< im ded >
--------
\ ^__^
\ (xx)\_______
(__)\ )\/\
U ||----w |
|| ||
*/
// use one of the builtin cowfiles
cow, _ := cowsay.Load("eyes")
cow.Say("bufo is not in the sudoers file. This incident will be reported.")
/*
_______________________________________
/ bufo is not in the sudoers file. This \
\ incident will be reported. /
---------------------------------------
\
\
.::!!!!!!!:.
.!!!!!:. .:!!!!!!!!!!!!
~~~~!!!!!!. .:!!!!!!!!!UWWW$$$
:$$NWX!!: .:!!!!!!XUWW$$$$$$$$$P
$$$$$##WX!: .<!!!!UW$$$$" $$$$$$$$#
$$$$$ $$$UX :!!UW$$$$$$$$$ 4$$$$$*
^$$$B $$$$\ $$$$$$$$$$$$ d$$R"
"*$bd$$$$ '*$$$$$$$$$$$o+#"
"""" """""""
*/
// or bring your own!
cow, _ = cowsay.Load("/path/to/cowfile.cow")
cow.Say("you did this to me")
// no need for a file
cowperson := ` {{.Thoughts}}
{{.Thoughts}}
๐ง
๐๐โ๏ธ
๐
๐ ๐
`
template.Must(cowsay.Cowfiles.New("person").Parse(cowperson))
cow, _ := cowsay.Load("person")
cow.Say("enjoy your tea")
/*
________________
< enjoy your tea >
----------------
\
\
๐ง
๐๐โ๏ธ
๐
๐ ๐
*/
// cowsay all your logs
log.SetFormatter(CowFormatter{})
log.Info("mooo")
/*
__________________________________________________________________
/ {"level":"info","msg":"mooo","time":"2023-02-08T07:53:13-05:00"} \
\ /
------------------------------------------------------------------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
*/
}
// plays nicely with your favorite Go packages
func (f CowFormatter) Format(e *log.Entry) ([]byte, error) {
var b bytes.Buffer
ln, _ := (&log.JSONFormatter{}).Format(e)
// set Width < 0 to disable word wrap for log lines
cowsay.Cow{Width: -1}.Write(&b, ln, false)
b.WriteByte('\n')
return b.Bytes(), nil
}
type CowFormatter struct{}
```
### Cowfiles
There are many ports of `cowsay` to other languages that preserve the cowfiles
verbatim, but without access to a Perl interpreter, much of the fun is lost in
translation. For example, here is `three-eyes.cow`, which hacks `cowsay` into
printing a cow with three eyes instead of two:
```perl
##
## A cow with three eyes, brought to you by dpetrou@csua.berkeley.edu
##
$extra = chop($eyes);
$eyes .= ($extra x 2);
$the_cow = <<EOC;
$thoughts ^___^
$thoughts ($eyes)\\_______
(___)\\ )\\/\\
$tongue ||----w |
|| ||
EOC
```
Non-Perl `cowsay` implementations usually omit such cowfiles.
`nmyk.io/cowsay` includes them all, lovingly translated to Go's
`text/template` format:
```cow
{{.Thoughts}} ^___^
{{.Thoughts}} ({{.Eyes}}{{slice .Eyes 1 2}})\_______
(___)\ )\/\
{{.Tongue}} ||----w |
|| ||
{{- /* A cow with three eyes, brought to you by dpetrou@csua.berkeley.edu */ -}}
```
Cowfiles are UTF-8 encoded text files that use `text/template` syntax for
customization. `Eyes` and `Tongue` strings may be used to customize the cow's
moood, and `Thoughts` for the trail leading up to the cow's message balloon.
Now, we Gophers have a cowfile culture we can call our own.
A few more reasons to choose `nmyk.io/cowsay`:
* It's lightweight: Has no dependencies; easy to justify adding to your
project.
* It's ergonomic: Uses similar "zero as default" semantics to types like
`sync.Mutex`; `cowsay.Cow` is ready to `Say` without initialization.
* It's idiomatic: Access cowfiles in your Go program through the `Cowfiles`
`*template.Template`, which is associated with all the built-in cowfiles, in
order to inject ASCII art into your (company's) middleware. `Cow{}.Write` to
your favorite `io.Writer`.
## CLI
As a `cowsay`, it functions pretty similarly to the original program. Run
`$(go env GOPATH)/bin/cowsay` for usage information.
### Environment
The `COWPATH` environment variable, if present, will be used to search for
cowfiles. It contains a colon-separated list of directories, much like `PATH`
or `MANPATH`. Should always contain a file called `default.cow`. Files without
the `.cow` extension are ignored. Unset `COWPATH` to revert to the standard set
of cowfiles embedded in the `nmyk.io/cowsay` binary. (As long as you
have `nmyk.io/cowsay`, you have cowfiles <3)
### Comparison
As compared to the original Perl script:
*Pros*:
* Much faster
*Cons*:
* Much larger
There are also some behavioral differences which may be of interest to `cowsay`
aficionados. I believe these to be improvements.
The original script collapses single newlines (`"\n"`) into spaces:
`cowsay`:
```
% cowsay '
1
2
'
_______
< 1 2 >
-------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
```
Whereas we preserve them:
`nmyk.io/cowsay`:
```
% ~/go/bin/cowsay '
1
2
'
___
/ \
| 1 |
| 2 |
\ /
---
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
```
Additionally, the `-n` flag is usable when there are non-flag arguments, which
is not possible in the original program.
Finally, the `nmyk.io/cowsay` CLI prints a usage string when invoked
with no arguments, whereas the original requires `-h` for this behavior.
## Contributing
```shell
git clone https://git.nmyk.io/cowsay
```
Send a nice email containing a .tar.gz of your revision to cowsay@git.nmyk.io.
## Credits
This module only exists because some Perl hackers had a fun idea back in 1999-2000.
[Cowsay](https://linux.die.net/man/1/cowsay) was created by Tony Monroe
(tony@nog.net), with suggestions from Shannon Appel (appel@CSUA.Berkeley.EDU)
and contributions from Anthony Polito (aspolito@CSUA.Berkeley.EDU).