{"id":49791986,"url":"https://github.com/ljrobinson/unitmath","last_synced_at":"2026-05-12T06:00:43.836Z","repository":{"id":357266369,"uuid":"1236155054","full_name":"LJrobinson/UnitMath","owner":"LJrobinson","description":"Pure Rust unit conversion engine and CLI for weight, volume, potency, package math, and batch CSV/JSON workflows.","archived":false,"fork":false,"pushed_at":"2026-05-12T04:01:59.000Z","size":38,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-12T06:00:20.122Z","etag":null,"topics":["batch-processing","cli","command-line-tool","conversion","csv","data-cleaning","json","jsonl","math","rust","unit-conversion","units"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/LJrobinson.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-12T02:03:45.000Z","updated_at":"2026-05-12T04:01:56.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/LJrobinson/UnitMath","commit_stats":null,"previous_names":["ljrobinson/unitmath"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/LJrobinson/UnitMath","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LJrobinson%2FUnitMath","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LJrobinson%2FUnitMath/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LJrobinson%2FUnitMath/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LJrobinson%2FUnitMath/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/LJrobinson","download_url":"https://codeload.github.com/LJrobinson/UnitMath/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LJrobinson%2FUnitMath/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32926039,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-11T17:09:15.040Z","status":"online","status_checked_at":"2026-05-12T02:00:06.338Z","response_time":102,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["batch-processing","cli","command-line-tool","conversion","csv","data-cleaning","json","jsonl","math","rust","unit-conversion","units"],"created_at":"2026-05-12T06:00:25.709Z","updated_at":"2026-05-12T06:00:43.827Z","avatar_url":"https://github.com/LJrobinson.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# UnitMath\n\nUnitMath is a small Rust library and dependency-free CLI for unit conversions, parsing, and package math. The library focuses on core typed conversions and parsers; the CLI adds convenient one-shot commands, package math commands, and batch processing for CSV and JSON Lines data.\n\n## Current Scope\n\nUnitMath currently supports:\n\n- Weight conversions and parsing\n- US liquid volume conversions and parsing\n- Potency conversions and parsing\n- Simple package math helpers\n- One-shot CLI conversion commands\n- Batch CLI processing from CSV, JSON Lines, files, and stdin\n- Machine-readable CLI output as JSON, CSV-style rows, JSON Lines, or JSON arrays\n\nUnitMath intentionally keeps the public library API focused and lightweight. Higher-level features such as universal conversion, package expression parsing, batch processing, CSV/JSON formatting, and input-format handling are currently CLI-layer features, while trait-based quantity abstractions are intentionally deferred.\n\n## Supported Units\n\n### Weight\n\n- Milligram: `mg`\n- Gram: `g`, `gram`, `grams`\n- Kilogram: `kg`\n- Ounce: `oz`, `ounce`, `ounces`\n- Pound: `lb`, `lbs`, `pound`, `pounds`\n\nWeight conversions use grams as the canonical base unit internally.\n\n### Volume\n\n- Milliliter: `ml`, `milliliter`, `milliliters`\n- Liter: `l`, `liter`, `liters`\n- US fluid ounce: `fl oz`, `floz`, `fluid ounce`, `fluid ounces`\n- US cup: `cup`, `cups`\n- US pint: `pint`, `pints`\n- US quart: `quart`, `quarts`\n- US gallon: `gallon`, `gallons`\n\nVolume conversions use milliliters as the canonical base unit internally.\n\n### Potency\n\n- Percent: `%`, `percent`, `percentage`\n- Milligrams per gram: `mg/g`, `mgg`, `mg per g`, `mg/g dry weight`, `milligrams per gram`\n\nPotency conversions use milligrams per gram as the canonical base unit internally.\n\n## Library Usage\n\n```rust\nuse unitmath::{\n    calculate_total_quantity, calculate_total_units, convert_parsed_potency,\n    convert_parsed_volume, convert_parsed_weight, convert_potency, convert_volume,\n    convert_weight, parse_potency, parse_volume, parse_weight, PotencyUnit, VolumeUnit,\n    WeightUnit,\n};\n\nlet grams = convert_weight(1000.0, WeightUnit::Milligram, WeightUnit::Gram);\nassert_eq!(grams, 1.0);\n\nlet liters = convert_volume(1000.0, VolumeUnit::Milliliter, VolumeUnit::Liter);\nassert_eq!(liters, 1.0);\n\nlet milligrams_per_gram =\n    convert_potency(22.4, PotencyUnit::Percent, PotencyUnit::MilligramsPerGram);\nassert_eq!(milligrams_per_gram, 224.0);\n\nlet units = calculate_total_units(2.0, 12.0);\nassert_eq!(units, 24.0);\n\nlet total_milligrams = calculate_total_quantity(24.0, 100.0);\nassert_eq!(total_milligrams, 2400.0);\n\nlet parsed_weight = parse_weight(\"  3.5G  \")?;\nassert_eq!(parsed_weight.value, 3.5);\nassert_eq!(parsed_weight.unit, WeightUnit::Gram);\n\nlet parsed_volume = parse_volume(\"8 fl oz\")?;\nassert_eq!(parsed_volume.unit, VolumeUnit::FluidOunce);\n\nlet parsed_potency = parse_potency(\"22.4%\")?;\nassert_eq!(parsed_potency.unit, PotencyUnit::Percent);\n\nlet ounces = convert_parsed_weight(\"3.5g\", WeightUnit::Ounce)?;\nlet cups = convert_parsed_volume(\"8 fl oz\", VolumeUnit::Cup)?;\nlet percent = convert_parsed_potency(\"224mg/g\", PotencyUnit::Percent)?;\n\nassert!(ounces \u003e 0.0);\nassert_eq!(cups, 1.0);\nassert_eq!(percent, 22.4);\n\n# Ok::\u003c(), unitmath::UnitMathError\u003e(())\n```\n\nParsing trims whitespace, is case-insensitive, and returns `UnitMathError` for empty input, missing numbers, invalid numbers, missing units, and unknown units.\n\n## CLI Examples\n\nDefault CLI output is numeric-only:\n\n```sh\nunitmath weight \"1000mg\" g\nunitmath weight \"1 lb\" oz\nunitmath volume \"8 fl oz\" cup\nunitmath volume \"1 gallon\" ml\nunitmath potency \"22.4%\" mg/g\nunitmath potency \"224mg/g\" percent\nunitmath convert \"3.5g\" oz\nunitmath convert \"1 gallon\" ml\nunitmath convert \"22.4%\" mg/g\n```\n\nPackage CLI commands perform simple multiplication without unit conversion:\n\n```sh\nunitmath package total-units \"2 x 12\"\nunitmath package total-units \"2,12\"\nunitmath package total-quantity \"10 x 3.5\"\nunitmath package total-quantity \"24 * 100\" mg\n```\n\nAdd `--precision \u003cdigits\u003e` to format output values with exactly that many digits after the decimal point. Precision supports values from `0` through `12` and affects output formatting only:\n\n```sh\nunitmath convert \"3.5g\" oz --precision 4\nunitmath convert \"3.5g\" oz --json --precision 4\nunitmath convert \"3.5g\" oz --csv --precision 4\nunitmath package total-units \"2 x 12\" --precision 2\n```\n\n## Machine-Readable Output\n\nOne-shot commands support JSON and CSV-style output:\n\n```sh\nunitmath convert \"3.5g\" oz --json\nunitmath convert \"3.5g\" oz --csv\nunitmath convert \"3.5g\" oz --csv --no-header\nunitmath convert \"3.5g\" oz --csv --include-header\nunitmath convert \"3.5g\" oz --csv --delimiter tab\n```\n\nOne-shot JSON output is a single object:\n\n```json\n{\"category\":\"weight\",\"input\":\"3.5g\",\"target_unit\":\"oz\",\"value\":0.12345886682353144}\n```\n\nOne-shot CSV output includes headers by default:\n\n```csv\ncategory,input,target_unit,value\nweight,3.5g,oz,0.12345886682353144\n```\n\nBatch commands support CSV-style rows, JSON Lines, and JSON arrays:\n\n```sh\nunitmath batch examples/conversions.csv --csv\nunitmath batch examples/conversions.csv --json\nunitmath batch examples/conversions.csv --json --json-array\nunitmath batch examples/conversions.csv --csv --delimiter tab\nunitmath batch examples/conversions.csv --csv --delimiter pipe\n```\n\nBatch JSON output is JSON Lines by default:\n\n```jsonl\n{\"category\":\"weight\",\"input\":\"1000mg\",\"target_unit\":\"g\",\"value\":1,\"status\":\"ok\",\"error\":null}\n{\"category\":\"volume\",\"input\":\"1 gallon\",\"target_unit\":\"ml\",\"value\":3785.411784,\"status\":\"ok\",\"error\":null}\n```\n\nAdd `--json-array` with batch `--json` to emit one JSON array instead of JSON Lines:\n\n```json\n[{\"category\":\"weight\",\"input\":\"1000mg\",\"target_unit\":\"g\",\"value\":1,\"status\":\"ok\",\"error\":null},{\"category\":\"volume\",\"input\":\"1 gallon\",\"target_unit\":\"ml\",\"value\":3785.411784,\"status\":\"ok\",\"error\":null}]\n```\n\nCSV-style output uses commas by default. Use `--delimiter comma`, `--delimiter tab`, or `--delimiter pipe` with `--csv` to choose the output separator. Delimiter control affects output only; batch CSV input remains comma-separated.\n\n## Batch Examples\n\nBatch CSV input uses these headers:\n\n```csv\ncategory,input,target_unit\nweight,1000mg,g\nvolume,1 gallon,ml\npotency,22.4%,mg/g\nconvert,8 fl oz,cup\ntotal_units,2 x 12,units\ntotal_quantity,24 * 100,mg\n```\n\nSupported batch categories are `weight`, `volume`, `potency`, `convert`, `total_units`, and `total_quantity`. Surrounding whitespace in header names and category values is ignored. Package rows do simple multiplication without unit conversion; `target_unit` is preserved as an output label.\n\nJSON Lines batch input uses one flat object per non-empty line with string fields for `category`, `input`, and `target_unit`:\n\n```jsonl\n{\"category\":\"weight\",\"input\":\"1000mg\",\"target_unit\":\"g\"}\n{\"category\":\"volume\",\"input\":\"1 gallon\",\"target_unit\":\"ml\"}\n{\"category\":\"potency\",\"input\":\"22.4%\",\"target_unit\":\"mg/g\"}\n{\"category\":\"convert\",\"input\":\"8 fl oz\",\"target_unit\":\"cup\"}\n{\"category\":\"total_units\",\"input\":\"2 x 12\",\"target_unit\":\"units\"}\n{\"category\":\"total_quantity\",\"input\":\"24 * 100\",\"target_unit\":\"mg\"}\n```\n\nCopy-paste batch commands:\n\n```sh\nunitmath batch examples/conversions.csv --csv\nunitmath batch examples/conversions.csv --json\nunitmath batch examples/conversions.csv --json --json-array\nunitmath batch examples/conversions.jsonl --json\nunitmath batch examples/conversions.jsonl --csv\nunitmath batch examples/conversions.csv --csv --precision 2\n```\n\nOmit the file path to read from stdin. Stdin defaults to CSV unless `--input-format jsonl` or `--input-json` is provided:\n\n```sh\ncat examples/conversions.csv | unitmath batch --csv\ncat examples/conversions.csv | unitmath batch --json\ncat examples/conversions.jsonl | unitmath batch --input-format jsonl --csv\ncat examples/conversions.jsonl | unitmath batch --input-format jsonl --json\n```\n\nBatch file input is auto-detected from the file extension:\n\n- `.csv` reads CSV input\n- `.jsonl` reads JSON Lines input\n- `.ndjson` reads JSON Lines input\n\nExtension matching is case-insensitive. Files with unknown or missing extensions require `--input-format csv` or `--input-format jsonl`:\n\n```sh\nunitmath batch examples/conversions.csv --input-format csv --csv\nunitmath batch examples/conversions.jsonl --input-format jsonl --json\nunitmath batch examples/conversions.jsonl --input-format jsonl --json --json-array\n```\n\nThe older `--input-json` flag remains available as a compatibility alias for `--input-format jsonl`:\n\n```sh\nunitmath batch examples/conversions.jsonl --input-json --json\ncat examples/conversions.jsonl | unitmath batch --input-json --json\n```\n\nUse `--out \u003cpath\u003e` to write batch results to a file instead of stdout:\n\n```sh\nunitmath batch examples/conversions.csv --csv --out results.csv\nunitmath batch examples/conversions.csv --json --out results.jsonl\nunitmath batch examples/conversions.csv --json --json-array --out results.json\nunitmath batch examples/conversions.csv --csv --delimiter tab --out results.tsv\ncat examples/conversions.csv | unitmath batch --csv --out results.csv\n```\n\n## Dirty Data Workflows\n\nRows with conversion errors are included in batch output with `status` set to `error`; batch processing continues after row-level failures. Use filters and summaries to triage mixed-quality files:\n\n```sh\nunitmath batch examples/conversions.csv --csv --errors-only\nunitmath batch examples/conversions.csv --json --errors-only\nunitmath batch examples/conversions.csv --csv --ok-only\nunitmath batch examples/conversions.csv --csv --summary\nunitmath batch examples/conversions.csv --csv --errors-only --summary\nunitmath batch examples/conversions.csv --csv --errors-only --out errors.csv\nunitmath batch examples/conversions.csv --json --ok-only --out clean.jsonl\n```\n\n`--summary` writes counts to stderr and never changes stdout or output file schemas:\n\n```text\nsummary: processed=6 ok=6 errors=0 emitted=6\nsummary: processed=6 ok=5 errors=1 emitted=1 output=errors.csv\n```\n\nSummary counts are:\n\n- `processed`: all parsed batch result rows before filtering\n- `ok`: successful rows before filtering\n- `errors`: error rows before filtering\n- `emitted`: rows emitted after `--errors-only` or `--ok-only`\n\n## Examples\n\nLibrary examples:\n\n```sh\ncargo run --example basic_weight\ncargo run --example basic_volume\ncargo run --example basic_potency\n```\n\nBatch sample files:\n\n- `examples/conversions.csv`\n- `examples/conversions.jsonl`\n\n## Roadmap\n\n- Additional parsers\n- More unit families\n- Richer package parsing as a library API\n- Broader CLI ergonomics\n- Trait-based quantity abstractions when the core API shape is clear\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fljrobinson%2Funitmath","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fljrobinson%2Funitmath","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fljrobinson%2Funitmath/lists"}