Skip to content

Remove the CLI; ship an example script - #50

Merged
jerome-white merged 4 commits into
masterfrom
issue-49-remove-cli
Oct 22, 2026
Merged

jerome-white merged 4 commits into
masterfrom
issue-49-remove-cli

Conversation

@jerome-white

Copy link
Copy Markdown
Owner

Closes #49. Part of #38.

What this does

Removes the command-line interface and replaces it with a short example script, as decided on #49: Julia packages are libraries that users call from their own script, and the CLI had been shaping the library for a minority interface.

  • bin/ is deleted (rthsd.jl, its Project.toml): ArgParse, the second environment, and the Julia 1.11 requirement that came with it.
  • tidy_columns and incomplete_topics are deleted from src/input.jl, with their tests. Only the CLI used them. tidy_columns also held the topic/system/score fallback names, so this removes one of the IR-name surfaces Neutral vocabulary: blocks and treatments in docs and output #42 had still to decide. scores_matrix and wide_scores stay, since the table methods use them.
  • examples/run.jl (about ten lines plus comments) reads a tidy CSV with CSV.jl and DataFrames.jl, calls randomized_tukey_hsd on the DataFrame, and writes the results as CSV; it takes the path, the number of trials and an optional seed. It is an example to copy, not a supported tool. examples/Project.toml is its environment (Julia 1.11+, [sources], like benchmark/).
  • README: the CLI sections become "Reading a CSV", which says why there is no CLI. "Missing scores" keeps the explanation and replaces --missing drop with DataFrames recipes for complete cases (wide, and tidy including blocks with a missing row). "Threads and reproducibility" now shows the example script. Layout table and the benchmark README note updated.

Why (the full reasoning is on #49)

  • Not how Julia packages are used (Turing, SciML, JuMP, Distributions, DataFrames are all libraries; CLIs such as Runic are the exception), and the compile/load cost makes it a poor fit: on a 4 × 3 file the CLI took about 3.7 s per run against about 0.8 s for the library alone (one machine, one file).
  • It had cost a lot for the minority interface: 122 lines, a second environment, helpers living in src/ only to serve it, and a design choice (String names) that was reversed on Accept Tables.jl tables in randomized_tukey_hsd #48 because it followed the CLI.
  • Since Accept Tables.jl tables in the library #41 the library accepts a matrix, or a wide or tidy Tables.jl table with the names carried by the data, so getting data in is a line or two in the user's own script.

What it costs

  • Non-Julia users need a few lines of Julia.
  • --missing drop is a recipe, not a flag.
  • Running on a file is julia --project=examples examples/run.jl scores.csv 100000, not a command.

The CLI remains in git history (the parent of the first commit here), described by the README there.

Commits

  1. Remove the command-line interface (bin/, only the deletion)
  2. Remove the helpers that only the CLI used
  3. Add an example script for reading a CSV
  4. README: no CLI; read a CSV from a script, and drop incomplete blocks

Verification

  • ] test: 136 pass + 1 deliberately broken at 1 and at 4 threads. It was 151 before; the 15 fewer are the tests of the two deleted helpers (and one assertion in the wide_scores test that used incomplete_topics); no other test changed.
  • benchmark/snapshot.jl output is byte-identical to before (the library's computation is untouched).
  • The example script run on test/data/tiny.csv with 500 trials and seed 1 gives p-values 0.386, 0.0, 0.38, the same as the removed CLI gave for the same input and seed.
  • The README recipes were run, not just written: the tidy one on the old test inputs (a NaN, an absent row, an empty cell) keeps 3 of 4 blocks and gives first p-value 0.606, which is what --missing drop gave; the wide one dropped an empty cell and a NaN row (4 rows to 2). The recipes use generic column names in the README; I ran them with the file's own names.
  • 80 columns checked.

Follow-ups (outside this diff)

🤖 Generated with Claude Code

jerome-white and others added 4 commits October 22, 2026 09:24
Deletes bin/rthsd.jl and bin/Project.toml (the CLI and its separate
environment: ArgParse, CSV, DataFrames and a [sources] entry that needed
Julia 1.11).

Julia packages are libraries that users import from their own script or
notebook, not programs run from a shell (Turing, SciML, JuMP, Distributions
and DataFrames are all used that way), and the language's start-up and
compile cost makes a CLI a poor fit: on a 4 x 3 file the CLI took about
3.7 s per run against about 0.8 s for the library alone. The CLI was also
shaping the library (helpers placed in src/ only to serve it, a String
conversion adopted to match it) when the library should be designed
Julia-first and anything else built on it. Since the table methods of #41
the library already takes a matrix, or a wide or tidy Tables.jl table, so
getting data in is a line or two of CSV.jl and DataFrames.jl in the user's
own script. The README and a short example script follow in later commits.

The removed code is in git history: it is the tree of the parent of this
commit, and described by the README there.

The helpers only the CLI used (tidy_columns, incomplete_topics) are removed
in the next commit, so that this one is only the deletion of bin/.

Refs #49
Part of #38

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
tidy_columns decided which CSV columns held the block, treatment and score,
with a fallback to the IR names topic, system and score; incomplete_topics
flagged blocks with a NaN for the CLI's --missing drop. With the CLI gone
(previous commit) nothing calls either, and the table methods of #41
ask for the columns explicitly, so they are deleted with their tests
(tidy_columns: 7 groups of checks; incomplete_topics: the flags and the
"dropping them leaves a matrix the test accepts" check; one assertion in
the wide_scores test that used incomplete_topics).

scores_matrix and wide_scores stay: the table methods use them, and their
tests are unchanged. The two docstrings that pointed at incomplete_topics
now say that a missing score becomes NaN, which the test rejects. A header
comment in test/input.jl no longer mentions the CLI.

The test suite goes from 151 to 136 passing (plus the 1 deliberately
broken), all removed tests being of the deleted functions.

This also removes the second IR-fallback surface noted in the review of
#48 (the topic/system/score names in tidy_columns), which #42 had still
to decide.

Refs #49
Part of #38

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
examples/run.jl reads a tidy CSV, calls randomized_tukey_hsd on the
DataFrame with block, treatment and value named, and writes the results as
CSV to stdout. It takes the path, the number of trials and an optional seed
from ARGS:

    julia --project=examples examples/run.jl scores.csv 100000 [seed]

It stands in for what the removed CLI did for the common case, in about
ten lines of ordinary Julia that a user can copy and change, and is
documented as an example, not a supported tool. examples/Project.toml has
the environment (CSV, DataFrames, Random and the library through a
[sources] path entry, so Julia 1.11 or newer, like benchmark/).

Checked on test/data/tiny.csv with 500 trials and seed 1: the p-values
(0.386, 0.0, 0.38) are the ones the removed CLI gave for the same input and
seed, since both call the same library method.

Refs #49
Part of #38

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Replaces the "Running the CLI" section with "Reading a CSV", which points
at examples/run.jl and says why there is no command-line tool (you call
the function from your own script, as with other Julia packages) and that
the examples environment needs Julia 1.11 (its [sources] entry).

"Missing scores" keeps the explanation (a NaN poisons every p-value; the
sound option is complete cases; why nanmean is not offered) and replaces
the --missing flag with DataFrames recipes: dropmissing and a NaN filter
for a wide table, and a groupby filter for a tidy one that also drops
blocks with a missing row. The tidy recipe was run on the old test inputs
(NaN, absent row, empty cell) and keeps 3 of 4 blocks with the same first
p-value (0.606) the old --missing drop gave; the wide one drops the
missing and the NaN row (4 rows to 2 in the check).

"Threads and reproducibility" now shows the example script with -t auto
and says the script takes the seed as its third argument; nothing else in
it changes. The layout table lists examples/ instead of bin/, and the
benchmark README no longer says "like bin/" about the Julia 1.11
requirement.

Refs #49
Part of #38

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@jerome-white jerome-white self-assigned this Oct 22, 2026
@jerome-white
jerome-white merged commit c2cf9be into master Oct 22, 2026
4 checks passed
@jerome-white
jerome-white deleted the issue-49-remove-cli branch October 22, 2026 04:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Remove the CLI; ship a short example script instead

1 participant