1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
//! A composed CLI's own identity: the package name, bin name and version
//! Cargo fixed when it was built.
//
// Neither `Identity` nor this module asserts anything at runtime. The only
// production caller is `identity!`'s expansion, which hands
// `from_macro_expansion` three `env!` results — Cargo guarantees each one is a
// non-empty string before the crate compiles at all, so a runtime check here
// would have nothing left to guard.
/// The identity of the composed command line a task is running inside — not
/// the task's own identity, and not a person's.
///
/// Carries the three facts Cargo fixes at compile time for a binary target:
/// its package name, its bin name, and its version. It is built with
/// [`macro@crate::identity`], which compiles only inside a binary target's
/// own source, because it reads `CARGO_BIN_NAME`, and Cargo defines that
/// variable nowhere else. That is deliberate: an `Identity` is only ever
/// meaningful as *the* identity of the command line currently running, and a
/// library crate — a task crate included — has no command line of its own to
/// be the identity of.
///
/// A task can opt in to being handed one of these at invocation time, with
/// [`crate::Task::receiving_command_line`].
///
/// # Examples
///
/// ```
/// use rituals::{CommandLine, Outcome, report};
///
/// fn run(command_line: &CommandLine) -> Outcome {
/// let identity = command_line.identity();
/// report(format!(
/// "{} {} (package {})",
/// identity.binary_name(),
/// identity.version(),
/// identity.package_name()
/// ));
/// Ok(())
/// }
/// # let identity = rituals::Identity::from_macro_expansion("acme-cli", "acme", "0.1.0");
/// # assert_eq!(identity.package_name(), "acme-cli");
/// # assert_eq!(identity.binary_name(), "acme");
/// # assert_eq!(identity.version(), "0.1.0");
/// # run(&rituals::CommandLine::from_dispatch(identity, [], ["about"]))?;
/// # Ok::<(), rituals::Failure>(())
/// ```
/// Builds the [`Identity`] of the command line this macro is invoked from.
///
/// Expands to `env!` on the three Cargo variables that name a binary
/// target — `CARGO_PKG_NAME`, `CARGO_BIN_NAME`, `CARGO_PKG_VERSION` — read in
/// whichever crate calls this macro, not the crate it is defined in. Cargo
/// only defines `CARGO_BIN_NAME` while compiling a binary target, so this
/// macro is a compile error anywhere else: inside a library, inside an
/// integration test, inside a doctest. That is not a limitation to work
/// around: the compiler checks that this macro is only ever used in a
/// binary, rather than leaving it to a convention someone has to remember.
/// It does not check the hidden constructor the expansion calls; see
/// `Identity::from_macro_expansion` for why that is left unchecked.
///
/// The one real call site is the generated file every composed CLI checks
/// in, where it appears once, as `rituals::identity!()`.
///
/// # Examples
///
/// ```ignore
/// // Not a compiled doctest: a doctest compiles as neither a binary
/// // target nor an integration test, so `CARGO_BIN_NAME` is undefined for
/// // it — the same reason this macro cannot appear inside a library or a
/// // test. Real coverage comes from `crates/rituals-cli` compiling at all,
/// // plus its integration tests that check `--version` and `Usage:`.
/// let identity = rituals::identity!();
/// assert_eq!(identity.binary_name(), "ritual");
/// ```