Skip to content

Commit

Permalink
Update docs, add classification diagram (#57)
Browse files Browse the repository at this point in the history
* Convert classification table to Mermaid diagram
* Generate PyPI-compatible README
* Update docs
  • Loading branch information
makukha authored Dec 20, 2024
1 parent 7c914b4 commit 255ba9d
Show file tree
Hide file tree
Showing 12 changed files with 163 additions and 74 deletions.
32 changes: 22 additions & 10 deletions .dev/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,21 +1,33 @@
FROM makukha/multipython:latest

RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
--mount=type=cache,target=/var/lib/apt,sharing=locked \
--mount=type=bind,from=dattached/bootstrap,dst=/b \
<<EOT
RUN --mount=type=bind,from=dattached/bootstrap,dst=/b <<EOT
apt-get update
bash /b/debian-apt-install-devtools.sh
rm -rf /tmp/* /var/tmp/*
rm -rf /var/lib/apt/lists/*
EOT

RUN --mount=type=cache,dst=/root/.cache/pip \
pip install uv
RUN <<EOT
apt-get update
apt-get install -y --no-install-recommends \
chromium \
nodejs \
npm
rm -rf /var/lib/apt/lists/*
npm install -g @mermaid-js/mermaid-cli
EOT

COPY .dev/requirements.*.txt /tmp/
COPY <<EOF /root/puppeteer-config.json
{
"executablePath": "/usr/bin/chromium",
"args": [
"--no-sandbox"
]
}
EOF

RUN --mount=type=cache,dst=/root/.cache/uv \
uv pip install --system -r /tmp/requirements.dev.txt -r /tmp/requirements.doc.txt
COPY --from=ghcr.io/astral-sh/uv /uv /uvx /bin/
COPY .dev/requirements.*.txt /tmp/
RUN uv pip install --system -r /tmp/requirements.dev.txt -r /tmp/requirements.doc.txt

WORKDIR /project
EXPOSE 8000
35 changes: 22 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
> Case conversion and verification for Python: snake_case, camelCase, kebab-case, etc.
[![versions](https://img.shields.io/pypi/pyversions/caseutil.svg)](https://pypi.org/project/caseutil)
[![pypi](https://img.shields.io/pypi/v/caseutil.svg#v0.7.0)](https://pypi.python.org/pypi/caseutil)
[![Tests](https://raw.githubusercontent.com/makukha/caseutil/v0.7.0/docs/badge/tests.svg)](https://github.com/makukha/caseutil)
[![Coverage](https://raw.githubusercontent.com/makukha/caseutil/v0.7.0/docs/badge/coverage.svg)](https://github.com/makukha/caseutil)
[![pypi](https://img.shields.io/pypi/v/caseutil.svg#v0.7.1)](https://pypi.python.org/pypi/caseutil)
[![Tests](https://raw.githubusercontent.com/makukha/caseutil/v0.7.1/docs/badge/tests.svg)](https://github.com/makukha/caseutil)
[![Coverage](https://raw.githubusercontent.com/makukha/caseutil/v0.7.1/docs/badge/coverage.svg)](https://github.com/makukha/caseutil)
[![PyPI - Downloads](https://img.shields.io/pypi/dw/caseutil)](https://pypistats.org/packages/caseutil)
[![license](https://img.shields.io/github/license/makukha/caseutil.svg)](https://github.com/makukha/caseutil/blob/main/LICENSE)
[![Documentation Status](https://readthedocs.org/projects/caseutil/badge/?version=latest)](https://caseutil.readthedocs.io/en/latest/?badge=latest)
Expand All @@ -20,7 +20,14 @@
* No dependencies
* 100% test coverage

### Supported cases
## Supported cases

### [Classification](https://caseutil.readthedocs.io/en/latest/classification/)

![Cases classification](docs/img/classification-dark.svg#gh-dark-mode-only)
![Cases classification](docs/img/classification-light.svg#gh-light-mode-only)

### Simple functions

| Case | Verify | Convert |
|---------------|---------------|---------------|
Expand All @@ -37,8 +44,6 @@
| Title Case | `is_title` | `to_title` |
| Sentence case | `is_sentence` | `to_sentence` |

For more details about cases and their relations, see [Cases classification](https://caseutil.readthedocs.io/en/latest/classification/).

## Installation

```shell
Expand All @@ -65,7 +70,7 @@ hiThere
seeYou
```

## Simple usage
## Basic usage

```doctest
>>> from caseutil import *
Expand Down Expand Up @@ -151,15 +156,19 @@ Only ASCII names are supported. Unicode support is planned.
This project requires [Docker](https://www.docker.com).

```shell
git clone https://github.com/makukha/caseutil.git
cd caseutil
task dev
$ git clone https://github.com/makukha/caseutil.git
$ cd caseutil
$ task dev
```

In dev environment:

```shell
root@caseutil:/project# task lint
root@caseutil:/project# task format
root@caseutil:/project# task test
$ task version -- minor
$ task build
$ task lint
$ task format
$ task test
```

## Alternatives
Expand Down
26 changes: 24 additions & 2 deletions Taskfile.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,29 @@ tasks:
cmds:
- uv pip install --system -e .

build:
desc: Build artefacts
cmds:
- task: build:classification
- rm -rf dist
- mv README.md README.md.backup
- sed -e'{/#gh-dark-mode-only/ d; s|(docs/\(img/.*\)#gh-light-mode-only|(https://caseutil.readthedocs.io/en/latest/\1|;}'
README.md.backup > README.md
- uv build
- rm README.md
- mv README.md.backup README.md

build:classification:
internal: true
sources: [docs/classification.md]
generates:
- docs/img/classification-dark.svg
- docs/img/classification-light.svg
cmds:
- sed -ne '/^```mermaid/,/^```/{/^```mermaid/d; s/^```//; p;}' docs/classification.md > /tmp/classification.mmd
- mmdc -p /root/puppeteer-config.json -i /tmp/classification.mmd -o docs/img/classification-dark.svg -t dark -b transparent 2>/dev/null
- mmdc -p /root/puppeteer-config.json -i /tmp/classification.mmd -o docs/img/classification-light.svg -t default -b transparent 2>/dev/null

docs:
desc: Serve local MkDocs.
cmds:
Expand All @@ -51,8 +74,7 @@ tasks:
preconditions:
- test $(git rev-parse --abbrev-ref HEAD) = main
cmds:
- rm -rf dist
- uv build
- task: build
- uv publish

# dev testing
Expand Down
18 changes: 9 additions & 9 deletions docs/badge/coverage.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
66 changes: 50 additions & 16 deletions docs/classification.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,58 @@

The two properties bellow let us classify all widely used cases: *word separator* (underscore, hyphen, space, letter case change), and *word case rule*:

## Table

| Words case rule | Underscore | Hyphen | Space | Case change |
|--------------------------|---------------|--------------|-----------------|---------------|
| all words are `lower` | `snake_case` | `kebab-case` | `lower case` | ∅<sup>2</sup> |
| 1st `lower` rest `Title` | —<sup>1</sup> ||| `camelCase` |
| all words are `Title` | `Ada_Case` | `Train-Case` | `Title Case` | `PascalCase` |
| 1st `Title` rest `lower` ||| `Sentence case` ||
| all words are `UPPER` | `CONST_CASE` | `COBOL-CASE` | `UPPER CASE` ||

<sup>1</sup> not widely used, <sup>2</sup> not possible
```mermaid
block-beta
columns 6
W["Word case"]:2
D["Delimiter"]:4
FW["First word"] RW["Other words"]
UD["underscore"] HD["hyphen"] SD["space"] CD["case change"]
FW1["lower"] RW1["lower"]
snake(["snake_case"]) kebab(["kebab-case"]) lower(["lower case"]) llc("∅")
FW2["lower"] RW2["Title"]
ltu("—") lth("—") lts("—") camel(["camelCase"])
FW3["Title"] RW3["Title"]
ada(["Ada_Case"]) train(["Train-Case"]) title(["Title Case"]) pascal(["PascalCase"])
FW4["Title"] RW4["lower"]
tlu("—") tlh("—") sentence(["Sentence case"]) tlc("∅")
FW5["UPPER"] RW5["UPPER"]
const(["CONST_CASE"]) cobol(["COBOL-CASE"]) upper(["UPPER CASE"]) uuc("∅")
classDef Head1 fill:#006400,fill-opacity:0.9,color:white,stroke:white,stroke-width:1px;
classDef Head2 fill:#228B22,fill-opacity:0.9,color:white,stroke:white,stroke-width:1px;
classDef Empty fill-opacity:0,stroke-width:0px;
classDef CaseL padding-left:8px,padding-right:8px,fill:#FFB6C1,fill-opacity:0.2,stroke-width:0px,font-weight:bold;
classDef CaseT padding-left:8px,padding-right:8px,fill:#00BFFF,fill-opacity:0.2,stroke-width:0px,font-weight:bold;
classDef CaseU padding-left:8px,padding-right:8px,fill:#00FFFF,fill-opacity:0.2,stroke-width:0px,font-weight:bold;
class W,FW,RW,D Head1
class FW1,RW1,FW2,RW2,FW3,RW3,FW4,RW4,FW5,RW5,UD,HD,SD,CD Head2
class snake,kebab,lower,camel CaseL
class ada,train,title,pascal,sentence CaseT
class const,cobol,upper CaseU
class llc,ltu,lth,lts,tlu,tlh,tlc,uuc Empty
```

* `` not widely used
* `` not possible

## Ambiguity

It is easy to observe that when there is a single word (no separators possible), all 12 cases are reduced to 3 classes:
1. When there is a single word (no separators possible), all 12 cases reduce to 3 classes:
* `lower` = `camel` = `kebab` = `snake`
* `Title` = `Ada` = `Pascal` = `Sentence` = `Train`
* `UPPER` = `COBOL` = `CONST`

* `lower` = `camel` = `kebab` = `snake`
* `Title` = `Ada` = `Pascal` = `Sentence` = `Train`
* `UPPER` = `COBOL` = `CONST`
2. When there is a single character (Title and UPPER match), all 12 cases reduce to 2 classes:
* `lower` = `camel` = `kebab` = `snake`
* `Title` = `Ada` = `Pascal` = `Sentence` = `Train` = `UPPER` = `COBOL` = `CONST`

This makes case detection multivalued when there is more than one word.
This makes case detection multivalued when there is a single word or single character.
1 change: 1 addition & 0 deletions docs/img/classification-dark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions docs/img/classification-light.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
41 changes: 23 additions & 18 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
> Case conversion and verification for Python: snake_case, camelCase, kebab-case, etc.
[![versions](https://img.shields.io/pypi/pyversions/caseutil.svg)](https://pypi.org/project/caseutil)
[![pypi](https://img.shields.io/pypi/v/caseutil.svg#v0.7.0)](https://pypi.python.org/pypi/caseutil)
[![Tests](https://raw.githubusercontent.com/makukha/caseutil/v0.7.0/docs/badge/tests.svg)](https://github.com/makukha/caseutil)
[![Coverage](https://raw.githubusercontent.com/makukha/caseutil/v0.7.0/docs/badge/coverage.svg)](https://github.com/makukha/caseutil)
[![pypi](https://img.shields.io/pypi/v/caseutil.svg#v0.7.1)](https://pypi.python.org/pypi/caseutil)
[![Tests](https://raw.githubusercontent.com/makukha/caseutil/v0.7.1/docs/badge/tests.svg)](https://github.com/makukha/caseutil)
[![Coverage](https://raw.githubusercontent.com/makukha/caseutil/v0.7.1/docs/badge/coverage.svg)](https://github.com/makukha/caseutil)
[![PyPI - Downloads](https://img.shields.io/pypi/dw/caseutil)](https://pypistats.org/packages/caseutil)
[![license](https://img.shields.io/github/license/makukha/caseutil.svg)](https://github.com/makukha/caseutil/blob/main/LICENSE)
[![Documentation Status](https://readthedocs.org/projects/caseutil/badge/?version=latest)](https://caseutil.readthedocs.io/en/latest/?badge=latest)
Expand All @@ -20,7 +20,14 @@
* No dependencies
* 100% test coverage

### Supported cases
## Supported cases

![Cases classification](img/classification-dark.svg#only-dark)
![Cases classification](img/classification-light.svg#only-light)

See [classification details](classification.md).

### Simple functions

| Case | Verify | Convert |
|---------------|---------------|---------------|
Expand All @@ -37,26 +44,12 @@
| Title Case | `is_title` | `to_title` |
| Sentence case | `is_sentence` | `to_sentence` |

For more details about cases and their relations, see [Cases classification](classification.md).

## Installation

```shell
$ pip install caseutil
```

## Simple usage

```doctest
>>> from caseutil import *
>>> is_snake('Foo bar-baz')
False
>>> to_snake('Foo bar-baz')
'foo_bar_baz'
```

## Command line

```shell
Expand All @@ -77,6 +70,18 @@ hiThere
seeYou
```

## Basic usage

```doctest
>>> from caseutil import *
>>> is_snake('Foo bar-baz')
False
>>> to_snake('Foo bar-baz')
'foo_bar_baz'
```

## Advanced usage

### Cases enum
Expand Down
6 changes: 5 additions & 1 deletion mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,11 @@ extra_css:
markdown_extensions:
- admonition
- pymdownx.details
- pymdownx.superfences
- pymdownx.superfences:
custom_fences:
- name: mermaid
class: mermaid
format: !!python/name:pymdownx.superfences.fence_code_format

theme:
name: material
Expand Down
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# NOTE: Keep in sync with setup.cfg

name = "caseutil"
version = "0.7.0"
version = "0.7.1"
description = "Case convert and verify for Python: snake_case, camelCase, kebab-case, and more."
authors = [{name = "Michael Makukha", email = "m.makukha@gmail.com"}]
readme = "README.md"
Expand Down Expand Up @@ -55,7 +55,7 @@ Changelog = "https://github.com/makukha/caseutil/releases"
# bump-my-version

[tool.bumpversion]
current_version = "0.7.0"
current_version = "0.7.1"
allow_dirty = true
files = [
{filename = "docs/index.md"},
Expand Down
5 changes: 3 additions & 2 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
# NOTE: Keep in sync with pyproject.toml (version is updated automatically)

name = caseutil
version = 0.7.0
description = Case convert and verify for Python: snake_case, camelCase, kebab-case, and more.
version = 0.7.1
description = Case conversion and verification for Python: snake_case, camelCase, kebab-case, etc.
long_description = file: README.md, LICENSE
author = Michael Makukha
author_email = m.makukha@gmail.com

Expand Down
2 changes: 1 addition & 1 deletion src/caseutil/__version__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = '0.7.0'
__version__ = '0.7.1'

0 comments on commit 255ba9d

Please sign in to comment.