git.nmyk.io / cowsay

@ v1.1.0

refs | commits



README.md


# [cowsay](https://nmyk.io/cowsay)

```
% figlet "Cowsay" | ~/go/bin/cowsay -f gopher -n
 ______________________________________
/   ____                               \
|  / ___|_____      _____  __ _ _   _  |
| | |   / _ \ \ /\ / / __|/ _` | | | | |
| | |__| (_) \ V  V /\__ \ (_| | |_| | |
|  \____\___/ \_/\_/ |___/\__,_|\__, | |
\                               |___/  /
 --------------------------------------
      \
       \
      ยด.-::::::-.ยด
  .:-::::::::::::::-:.
  ยด_:::    ::    :::_ยด
   .:( o   :: o   ):.
   ยด:::   (..)   :::.
   ยด:::::::UU:::::::ยด
   .::::::::::::::::.
   O::::::::::::::::O
   -::::::::::::::::-
   ยด::::::::::::::::ยด
    .::::::::::::::.
      oO:::::::Oo
```

`nmyk.io/cowsay` 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.

It is:

* Lightweight: Has no dependencies; easy to justify adding to your
  project.

* Ergonomic: Uses similar "zero as default" semantics to types like
  `sync.Mutex`; `cowsay.Cow` is ready to `Say` without initialization.

* 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`.


## 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.


## 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.


## Version History


* 1.0.0: initial release
    * 1.0.1: fixes formatting error in CLI usage string
    * 1.0.2: updates `README.md`; adds version history
    * 1.1.0: relicense under MIT (previously GPLv3)


## 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).