feat(page): normalize the authoring API — positional Header title, no more parens gotcha - #27
Merged
Merged
Conversation
…ose/example helpers
## Summary
One consistent convention across the kit: the primary argument is positional,
modifiers are keyword arguments — and the everyday authoring path no longer hits
the Ruby parens-with-blocks SyntaxError.
- `DocsUI::Header` takes the title positionally (`Header("Installation")`),
matching Section/Code. The legacy `title:` kwarg still works (silent compat,
no deprecation); the positional wins if both are given.
- New lowercase, block-friendly page helpers `prose { … }` and `example { |ex| … }`
(alongside the existing `md`), extracted into `DocsUI::PageHelpers` and mixed
into `DocsUI::Page`. A lowercase method takes a block without parens, so the
gotcha structurally cannot occur. The kit forms `DocsUI::Prose()` /
`DocsUI::Example()` stay valid forever.
- The gem's own docs pages adopt the helpers; the dedicated "parens gotcha"
section shrinks to a footnote. README documents the convention.
`PageHelpers` is a module (not methods inline on Page) so the helpers are
unit-testable against a bare Phlex host — `DocsUI::Page` includes
Phlex::Rails::Helpers::Routes and cannot load in the standalone suite.
## Test Coverage
- spec/docs_ui/header_spec.rb: positional title, eyebrow, lead block; legacy
`title:` kwarg renders identically (backwards-compat proof); positional wins
when both given.
- spec/docs_ui/page_helpers_spec.rb: `prose`/`example`/`md` render the expected
Prose wrapper / Example tabs / Markdown against a bare Phlex host exercising the
REAL PageHelpers module.
- spec/docs_ui/markdown_spec.rb: the `md` delegation test now includes the real
PageHelpers module instead of re-implementing `md`.
## Verification
- [x] bundle exec rake (rspec 103 examples, 0 failures; rubocop 42 files clean)
- [x] header.rb + page_helpers.rb: 100% line coverage
- [x] grep gate: no live DocsUI::Prose()/Example() in gem docs (only code{} API references remain)
- [x] backwards compatible: `Header(title:)` covered by spec; existing consumer sites unchanged
Refs #10
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #10. Part of #8 (Phase 1).
Problem
The kit's constructor conventions were inconsistent and the inconsistency was user-facing:
Section.new(title, …)/Code.new(source, …)took their main argument positionally, butHeader.new(title:, …)required a kwarg —DocsUI::Header("My guide")raisedArgumentError.Prose/Exampletake no positional args, soDocsUI::Prose do … endis a RubySyntaxError(it parses as a constant reference). The gem papered over this with a whole "the one syntax rule that bites everyone" docs section.What changed
One convention: the primary argument is positional; modifiers are keyword arguments.
DocsUI::Header(title: "T", eyebrow: "E")DocsUI::Header("T", eyebrow: "E")DocsUI::Prose() do … endprose do … end(page helper)DocsUI::Example() do |ex| … endexample do |ex| … end(page helper)Headertakes a positional title —initialize(title = nil, eyebrow: nil, **opts). The legacytitle:kwarg still works (silent compat, no deprecation warning); the positional wins if both are given. Existing consumer sites that callHeader(title:)keep rendering verbatim.prose/example(alongside the existingmd). A lowercase method takes a block without parens, so the parens-with-blocks trap structurally cannot occur. The kit formsDocsUI::Prose()/DocsUI::Example()stay valid forever — nothing is removed.DocsUI::PageHelpersmodule mixed intoDocsUI::Page. Extracting them into a module (rather than defining them inline onPage) makes them unit-testable against a bare Phlex host —DocsUI::PageincludesPhlex::Rails::Helpers::Routesand cannot load in the standalone suite.Why a module instead of inline methods
DocsUI::PagereferencesRails.application.routesat class-load time (via the Routes helper), so it cannot be loaded in the gem's Rails-free spec suite. A globalRailsstub was ruled out — two code paths (icon.rband the install generator) branch ondefined?(Rails)and specs depend onRailsbeing absent under the random-ordered suite. Extracting the helpers into a module tests the real helper bodies without loadingPageand without global-state pollution. (It also fixed a latent weakness inmarkdown_specthat was re-implementingmdrather than exercising it.)Test coverage
spec/docs_ui/header_spec.rb— positional title, eyebrow, lead block; legacytitle:kwarg renders identically to the positional form (backwards-compat proof); positional wins when both are given.spec/docs_ui/page_helpers_spec.rb—prose/example/mdrender the Prose wrapper / Example tabs / Markdown, exercising the realPageHelpersmodule through a bare Phlex host.spec/docs_ui/markdown_spec.rb— themddelegation test now includes the real module.header.rbandpage_helpers.rbare at 100% line coverage.Verification
bundle exec rake— rspec 103 examples, 0 failures; rubocop 42 files, no offensesDocsUI::Prose()/DocsUI::Example()in the gem's docs pages (onlycode { "…" }API references remain, which document that the kit form stays valid)Header(title:)covered by spec; no consumer-site call site changes required@sourcechange neededOut of scope (per the issue)
DocsUI::Prose()stays valid).Callout/OnThisPagesignature changes.