Repository: iqlusioninc/abscissa (language: rust)

Issue:
Unable to compile crate with dash in name
If I try to create an Abscissa crate that has a dash in the name, then it will create invalid code. Since in the code the crate name has to replace dashes with underscores.

How to reproduce:
```bash
$ abscissa new abscissa-test
...

$ cd abscissa-test/

$ cargo build
   Compiling abscissa-test v0.1.0 (/home/user/src/abscissa-test)
error: expected one of `::`, `;`, or `as`, found `-`
 --> src/bin/abscissa-test/main.rs:6:13
  |
6 | use abscissa-test::application::APPLICATION;
  |             ^ expected one of `::`, `;`, or `as` here
```


Discussion / hints:
The framework conventions are mostly around `_` in the name, but that said I would consider this a bug and it should probably replace all `-` with `_` before doing the rest of the conversions (ala crate names)

Fix patch:
diff --git a/Cargo.lock b/Cargo.lock
index 7f6af7d2..40c22e22 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -8,7 +8,7 @@ dependencies = [
  "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "gumdrop 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "handlebars 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "ident_case 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
@@ -41,7 +41,7 @@ name = "abscissa_derive"
 version = "0.3.0-rc.0"
 dependencies = [
  "darling 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "ident_case 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
  "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
  "syn 0.15.42 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -271,14 +271,6 @@ dependencies = [
  "serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
-[[package]]
-name = "heck"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "unicode-segmentation 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
 [[package]]
 name = "ident_case"
 version = "1.0.1"
@@ -597,11 +589,6 @@ name = "ucd-util"
 version = "0.1.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
-[[package]]
-name = "unicode-segmentation"
-version = "1.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-
 [[package]]
 name = "unicode-xid"
 version = "0.1.0"
@@ -699,7 +686,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum gumdrop_derive 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dae5488e2c090f7586e2027e4ea6fcf8c9d83e2ef64d623993a33a0fb811f1f7"
 "checksum handlebars 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "df044dd42cdb7e32f28557b661406fc0f2494be75199779998810dbc35030e0d"
 "checksum hashbrown 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e1de41fb8dba9714efd92241565cdff73f78508c95697dd56787d3cba27e2353"
-"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205"
 "checksum ident_case 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
 "checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f"
 "checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14"
@@ -742,7 +728,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169"
 "checksum ucd-trie 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8f00ed7be0c1ff1e24f46c3d2af4859f7e863672ba3a6e92e7cff702bf9f06c2"
 "checksum ucd-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fa9b3b49edd3468c0e6565d85783f51af95212b6fa3986a5500954f00b460874"
-"checksum unicode-segmentation 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1967f4cdfc355b37fd76d2a954fb2ed3871034eb4f26d60537d88795cfc332a9"
 "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
 "checksum utf8-ranges 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9d50aa7650df78abf942826607c62468ce18d9019673d4a2ebe1865dbb96ffde"
 "checksum wait-timeout 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6"
diff --git a/README.md b/README.md
index 9e1b406e..d989f15c 100644
--- a/README.md
+++ b/README.md
@@ -119,22 +119,26 @@ default set of features in the application:
 | 3  | [cc]              | [@alexcrichton]  | Apache-2.0/MIT | C/C++ compiler wrapper  |
 | 4  | [cfg-if]          | [@alexcrichton]  | Apache-2.0/MIT | If-like `#[cfg]` macros |
 | 5  | [darling]         | [@TedDriggs]     | MIT            | Nifty attribute parser  |
-| 6  | [failure_derive]  | [@withoutboats]  | Apache-2.0/MIT | failure custom derive   |
-| 7  | [gumdrop_derive]  | [@Murarth]       | Apache-2.0/MIT | Command-line options    |
-| 8  | [heck]            | [@withoutboats]  | Apache-2.0/MIT | Case conversion utils   |
-| 9  | [memchr]          | [@BurntSushi]    | MIT/Unlicense  | Optimize byte search    |
-| 10 | [proc-macro2]     | [@alexcrichton]  | Apache-2.0/MIT | Shim for Macros 2.0 API |
-| 11 | [quote]           | [@dtolnay]       | Apache-2.0/MIT | Rust AST to token macro |
-| 12 | [regex]           | [rust-lang]      | Apache-2.0/MIT | Regular expressions     |
-| 13 | [regex-syntax]    | [rust-lang]      | Apache-2.0/MIT | Regex syntax impl       |
-| 14 | [serde_derive]    | [serde-rs]       | Apache-2.0/MIT | `serde` custom derive   |
-| 15 | [syn]             | [@dtolnay]       | Apache-2.0/MIT | Rust source code parser |
-| 16 | [synstructure]    | [@mystor]        | Apache-2.0/MIT | `syn` structure macros  |
-| 17 | [thread_local]    | [@Amanieu]       | Apache-2.0/MIT | Per-object thread local |
-| 18 | [ucd-util]        | [@BurntSushi]    | Apache-2.0/MIT | Unicode utilities       |
-| 19 | [unicode-xid]     | [unicode-rs]     | Apache-2.0/MIT | Identify valid Unicode  |
-| 20 | [utf8-ranges]     | [@BurntSushi]    | MIT/Unlicense  | UTF-8 codepoint ranges  |
-| 21 | [wait-timeout]    | [@alexcrichton]  | Apache-2.0/MIT | Timeouts for waitpid    |
+| 6  | [darling_core]    | [@TedDriggs]     | MIT            | Attribute parser core   |
+| 7  | [darling_macro]   | [@TedDriggs]     | MIT            | Attribute parser macros |
+| 8  | [failure_derive]  | [@withoutboats]  | Apache-2.0/MIT | `failure` custom derive |
+| 9  | [fnv]             | [@alexcrichton]  | Apache-2.0/MIT | Fast hash function      |
+| 10 | [gumdrop_derive]  | [@Murarth]       | Apache-2.0/MIT | Command-line options    |
+| 11 | [ident_case]      | [@TedDriggs]     | Apache-2.0/MIT | Case conversion utils   |
+| 12 | [memchr]          | [@BurntSushi]    | MIT/Unlicense  | Optimized byte search   |
+| 13 | [proc-macro2]     | [@alexcrichton]  | Apache-2.0/MIT | Shim for Macros 2.0 API |
+| 14 | [quote]           | [@dtolnay]       | Apache-2.0/MIT | Rust AST to token macro |
+| 15 | [regex]           | [rust-lang]      | Apache-2.0/MIT | Regular expressions     |
+| 16 | [regex-syntax]    | [rust-lang]      | Apache-2.0/MIT | Regex syntax impl       |
+| 17 | [serde_derive]    | [serde-rs]       | Apache-2.0/MIT | `serde` custom derive   |
+| 18 | [strsim]          | [@dguo]          | MIT            | String similarity utils |
+| 19 | [syn]             | [@dtolnay]       | Apache-2.0/MIT | Rust source code parser |
+| 20 | [synstructure]    | [@mystor]        | Apache-2.0/MIT | `syn` structure macros  |
+| 21 | [thread_local]    | [@Amanieu]       | Apache-2.0/MIT | Per-object thread local |
+| 22 | [ucd-util]        | [@BurntSushi]    | Apache-2.0/MIT | Unicode utilities       |
+| 23 | [unicode-xid]     | [unicode-rs]     | Apache-2.0/MIT | Identify valid Unicode  |
+| 24 | [utf8-ranges]     | [@BurntSushi]    | MIT/Unlicense  | UTF-8 codepoint ranges  |
+| 25 | [wait-timeout]    | [@alexcrichton]  | Apache-2.0/MIT | Timeouts for waitpid    |
 
 ### Dependency Relationships
 
@@ -143,52 +147,59 @@ an Abscissa dependency and whether or not it is optional. Abscissa uses
 [cargo features] to allow parts of it you aren't using to be easily disabled,
 so you only compile the parts you need.
 
-| Crate Name             | [Cargo Features] | Required By     |
-|------------------------|------------------|-----------------|
-| [abscissa]             | -                | ⊤               |
-| [abscissa_derive]      | -                | [abscissa]      |
-| [aho-corasick]         | `testing`        | [regex]         |
+| Crate Name             | [Cargo Features] | Required By       |
+|------------------------|------------------|-------------------|
+| [abscissa]             | -                | ⊤                 |
+| [abscissa_derive]      | -                | [abscissa]        |
+| [aho-corasick]         | `testing`        | [regex]           |
 | [arc-swap]             | `signals`        | [signal-hook-registry] |
-| [autocfg]              | `time`           | [num-integer]   |
-| [backtrace]            | -                | [failure]       |
-| [backtrace-sys]        | -                | [backtrace]     |
-| [canonical-path]       | -                | [abscissa]      |
-| [cc]                   | -                | [backtrace-sys] |
+| [autocfg]              | `time`           | [num-integer]     |
+| [backtrace]            | -                | [failure]         |
+| [backtrace-sys]        | -                | [backtrace]       |
+| [canonical-path]       | -                | [abscissa]        |
+| [cc]                   | -                | [backtrace-sys]   |
 | [cfg-if]               | -                | [backtrace], [log] |
-| [chrono]               | `time`           | [abscissa]      |
-| [failure]              | -                | [abscissa]      |
-| [failure_derive]       | -                | [failure]       |
-| [generational-arena]   | `application`    | [abscissa]      |
-| [gumdrop]              | `options`        | [abscissa]      |
-| [gumdrop_derive]       | `options`        | [gumdrop]       |
-| [heck]                 | `inflector`      | [abscissa]      |
-| [lazy_static]          | -                | [abscissa]      |
-| [libc]                 | `signals`        | [abscissa]      |
-| [log]                  | `logging`        | [abscissa]      |
-| [memchr]               | `testing`        | [aho-corasick]  |
-| [num-integer]          | `time`           | [chrono]        |
+| [chrono]               | `time`           | [abscissa]        |
+| [darling]              | -                | [abscissa_derive] |
+| [darling_core]         | -                | [darling], [darling_macro] |
+| [darling_macro]        | -                | [darling]         |
+| [failure]              | -                | [abscissa]        |
+| [failure_derive]       | -                | [failure]         |
+| [fnv]                  | -                | [darling_core]    |
+| [generational-arena]   | `application`    | [abscissa]        |
+| [gumdrop]              | `options`        | [abscissa]        |
+| [gumdrop_derive]       | `options`        | [gumdrop]         |
+| [ident_case]           | -                | [abscissa_derive], [darling_core] |
+| [lazy_static]          | -                | [abscissa]        |
+| [libc]                 | `signals`        | [abscissa]        |
+| [log]                  | `logging`        | [abscissa]        |
+| [memchr]               | `testing`        | [aho-corasick]    |
+| [num-integer]          | `time`           | [chrono]          |
 | [num-traits]           | `time`           | [chrono], [num-integer] |
-| [proc-macro2]          | -                | [abscissa_derive], [failure_derive], [quote], [serde_derive] |
-| [redox_syscall]        | `time`           | [time]          |
-| [regex]                | `testing`        | [abscissa]      |
-| [rustc-demangle]       | -                | [backtrace]     |
-| [secrecy]              | `secrets`        | [abscissa]      |
-| [semver]               | `application`    | [abscissa]      |
-| [semver-parser]        | `application`    | [abscissa]      |
-| [serde]                | `config`         | [abscissa]      |
-| [serde_derive]         | `config`         | [serde]         |
-| [signal-hook]          | `signals`        | [abscissa]      |
-| [signal-hook-registry] | `signals`        | [signal-hook] |
-| [termcolor]            | `terminal`       | [abscissa]      |
-| [thread_local]         | `testing`        | [regex]         |
-| [time]                 | `logging`        | [chrono]        |
-| [ucd-util]             | `testing`        | [regex-syntax]  |
-| [unicode-xid]          | -                | [proc-macro2]   |
-| [utf8-ranges]          | `testing`        | [regex]         |
-| [wait-timeout]         | `testing`        | [abscissa]      |
+| [proc-macro2]          | -                | [abscissa_derive], [darling], [failure_derive], [quote], [serde_derive], [syn] |
+| [quote]                | -                | [abscissa_derive], [darling], [failure_derive], [gumdrop_derive], [serde_derive] |
+| [redox_syscall]        | `time`           | [time]            |
+| [regex]                | `testing`        | [abscissa]        |
+| [rustc-demangle]       | -                | [backtrace]       |
+| [secrecy]              | `secrets`        | [abscissa]        |
+| [semver]               | `application`    | [abscissa]        |
+| [semver-parser]        | `application`    | [abscissa]        |
+| [serde]                | `config`         | [abscissa]        |
+| [serde_derive]         | `config`         | [serde]           |
+| [signal-hook]          | `signals`        | [abscissa]        |
+| [signal-hook-registry] | `signals`        | [signal-hook]     |
+| [strsim]               | -                | [darling_core]    |
+| [syn]                  | -                | [abscissa_derive], [darling], [failure_derive], [gumdrop_derive], [serde_derive] |
+| [termcolor]            | `terminal`       | [abscissa]        |
+| [thread_local]         | `testing`        | [regex]           |
+| [time]                 | `logging`        | [chrono]          |
+| [ucd-util]             | `testing`        | [regex-syntax]    |
+| [unicode-xid]          | -                | [proc-macro2], [syn] |
+| [utf8-ranges]          | `testing`        | [regex]           |
+| [wait-timeout]         | `testing`        | [abscissa]        |
 | [winapi]§              | -                | [termcolor], [time], [winapi-util] |
-| [winapi-util]          | -                | [termcolor]     |
-| [zeroize]              | -                | [abscissa]      |
+| [winapi-util]          | -                | [termcolor]       |
+| [zeroize]              | -                | [abscissa]        |
 
 * § `winapi` is a facade for either [winapi-i686-pc-windows-gnu] or
     [winapi-x86_64-pc-windows-gnu] which aren't explicitly listed for brevity
@@ -320,13 +331,16 @@ read the [CONTRIBUTING.md] and [CODE_OF_CONDUCT.md] files first.
 [cc]: https://crates.io/crates/cc
 [cfg-if]: https://crates.io/crates/cfg-if
 [chrono]: https://crates.io/crates/chrono
-[darling]: https://github.com/TedDriggs/darling
+[darling]: https://crates.io/crates/darling
+[darling_core]: https://crates.io/crates/darling_core
+[darling_macro]: https://crates.io/crates/darling_macro
 [failure]: https://crates.io/crates/failure
 [failure_derive]: https://crates.io/crates/failure_derive
+[fnv]: https://crates.io/crates/fnv
 [generational-arena]: https://github.com/fitzgen/generational-arena
 [gumdrop]: https://crates.io/crates/gumdrop
 [gumdrop_derive]: https://crates.io/crates/gumdrop_derive
-[heck]: https://crates.io/crates/heck
+[ident_case]: https://crates.io/crates/ident_case
 [lazy_static]: https://crates.io/crates/lazy_static
 [libc]: https://crates.io/crates/libc
 [log]: https://crates.io/crates/log
@@ -346,6 +360,7 @@ read the [CONTRIBUTING.md] and [CODE_OF_CONDUCT.md] files first.
 [serde_derive]: https://crates.io/crates/serde_derive
 [signal-hook]: https://crates.io/crates/signal-hook
 [signal-hook-registry]: https://crates.io/crates/signal-hook
+[strsim]: https://crates.io/crates/darling
 [syn]: https://crates.io/crates/syn
 [synstructure]: https://crates.io/crates/
 [termcolor]: https://crates.io/crates/termcolor
@@ -369,6 +384,7 @@ read the [CONTRIBUTING.md] and [CODE_OF_CONDUCT.md] files first.
 [@Amanieu]: https://github.com/Amanieu
 [@BurntSushi]: https://github.com/BurntSushi
 [@cuviper]: https://github.com/cuviper
+[@dguo]: https://github.com/dtolnay
 [@dtolnay]: https://github.com/dtolnay
 [@fitzgen]: https://github.com/fitzgen
 [@Murarth]: https://github.com/Murarth
diff --git a/cli/Cargo.toml b/cli/Cargo.toml
index 947248ee..1290a818 100644
--- a/cli/Cargo.toml
+++ b/cli/Cargo.toml
@@ -23,7 +23,7 @@ maintenance = { status = "actively-developed" }
 failure = "0.1"
 gumdrop = "0.6"
 handlebars = "2"
-heck = "0.3"
+ident_case = "1"
 lazy_static = "1"
 serde = { version = "1", features = ["serde_derive"] }
 
diff --git a/cli/src/commands/new.rs b/cli/src/commands/new.rs
index 870734ca..d21c8a39 100644
--- a/cli/src/commands/new.rs
+++ b/cli/src/commands/new.rs
@@ -8,7 +8,7 @@ use crate::{
 };
 use abscissa_core::{status_err, status_info, status_ok, status_warn, Command, Options, Runnable};
 use failure::{bail, format_err, Error};
-use heck::TitleCase;
+use ident_case::RenameRule;
 use std::{
     fs, io,
     path::{Path, PathBuf},
@@ -186,12 +186,13 @@ impl NewCommand {
         let app_name = app_path
             .file_name()
             .expect("no filename?")
-            .to_string_lossy();
+            .to_string_lossy()
+            .replace("-", "_");
 
         let name: properties::name::App = app_name.parse().expect("no app name");
 
         // TODO(tarcieri): configurable title
-        let title = name.to_string().to_title_case();
+        let title = RenameRule::PascalCase.apply_to_field(&name);
 
         // TODO(tarcieri): configurable description
         let description = title.clone();
@@ -202,11 +203,10 @@ impl NewCommand {
         let patch_crates_io = self.patch_crates_io.clone();
 
         // TODO(tarcieri): configurable application type
-        let application_type =
-            properties::name::Type::from_snake_case(app_name.clone() + "_application");
+        let application_type = properties::name::Type::from_snake_case(app_name.clone() + "_app");
 
         // TODO(tarcieri): configurable command type
-        let command_type = properties::name::Type::from_snake_case(app_name.clone() + "_command");
+        let command_type = properties::name::Type::from_snake_case(app_name.clone() + "_cmd");
 
         // TODO(tarcieri): configurable config type
         let config_type = properties::name::Type::from_snake_case(app_name.clone() + "_config");
diff --git a/cli/src/properties/name.rs b/cli/src/properties/name.rs
index 3c4b0792..b35d9ddb 100644
--- a/cli/src/properties/name.rs
+++ b/cli/src/properties/name.rs
@@ -1,6 +1,6 @@
 //! Names used within an Abscissa application
 
-use heck::CamelCase;
+use ident_case::RenameRule;
 use serde::{Deserialize, Serialize};
 use std::{fmt, str};
 
@@ -68,6 +68,6 @@ impl Type {
     where
         S: AsRef<str>,
     {
-        Type(s.as_ref().to_camel_case())
+        Type(RenameRule::PascalCase.apply_to_field(s))
     }
 }
diff --git a/cli/template/Cargo.toml.hbs b/cli/template/Cargo.toml.hbs
index 2bc2617a..b56057ab 100644
--- a/cli/template/Cargo.toml.hbs
+++ b/cli/template/Cargo.toml.hbs
@@ -5,14 +5,12 @@ version = "{{version}}"
 edition = "{{edition}}"
 
 [dependencies]
+abscissa_core = "{{abscissa.version}}"
 failure = "0.1"
 gumdrop = "0.6"
 lazy_static = "1"
 serde = { version = "1", features = ["serde_derive"] }
 
-[dependencies.abscissa_core]
-version = "{{abscissa.version}}"
-
 [dev-dependencies.abscissa_core]
 version = "{{abscissa.version}}"
 features = ["testing"]
diff --git a/cli/template/src/commands.rs.hbs b/cli/template/src/commands.rs.hbs
index 4521bbf6..14113f29 100644
--- a/cli/template/src/commands.rs.hbs
+++ b/cli/template/src/commands.rs.hbs
@@ -13,7 +13,7 @@
 mod start;
 mod version;
 
-use self::{start::StartCommand, version::VersionCommand};
+use self::{start::StartCmd, version::VersionCmd};
 use crate::config::{{~config_type~}};
 use abscissa_core::{
     config::Override, Command, Configurable, FrameworkError, Help, Options, Runnable,
@@ -32,11 +32,11 @@ pub enum {{command_type}} {
 
     /// The `start` subcommand
     #[options(help = "start the application")]
-    Start(StartCommand),
+    Start(StartCmd),
 
     /// The `version` subcommand
     #[options(help = "display version information")]
-    Version(VersionCommand),
+    Version(VersionCmd),
 }
 
 /// This trait allows you to define how application configuration is loaded.
diff --git a/cli/template/src/commands/start.rs.hbs b/cli/template/src/commands/start.rs.hbs
index 63c26d5d..8da94385 100644
--- a/cli/template/src/commands/start.rs.hbs
+++ b/cli/template/src/commands/start.rs.hbs
@@ -15,13 +15,13 @@ use abscissa_core::{config, Command, FrameworkError, Options, Runnable};
 ///
 /// <https://docs.rs/gumdrop/>
 #[derive(Command, Debug, Options)]
-pub struct StartCommand {
+pub struct StartCmd {
     /// To whom are we saying hello?
     #[options(free)]
     recipient: Vec<String>,
 }
 
-impl Runnable for StartCommand {
+impl Runnable for StartCmd {
     /// Start the application.
     fn run(&self) {
         let config = app_config();
@@ -29,7 +29,7 @@ impl Runnable for StartCommand {
     }
 }
 
-impl config::Override<{{~config_type~}}> for StartCommand {
+impl config::Override<{{~config_type~}}> for StartCmd {
     // Process the given command line options, overriding settings from
     // a configuration file using explicit flags taken from command-line
     // arguments.
diff --git a/cli/template/src/commands/version.rs.hbs b/cli/template/src/commands/version.rs.hbs
index d6ed2b6e..4f2a4024 100644
--- a/cli/template/src/commands/version.rs.hbs
+++ b/cli/template/src/commands/version.rs.hbs
@@ -7,9 +7,9 @@ use abscissa_core::{Command, Options, Runnable};
 
 /// `version` subcommand
 #[derive(Command, Debug, Default, Options)]
-pub struct VersionCommand {}
+pub struct VersionCmd {}
 
-impl Runnable for VersionCommand {
+impl Runnable for VersionCmd {
     /// Print version message
     fn run(&self) {
         println!(
diff --git a/cli/template/src/lib.rs.hbs b/cli/template/src/lib.rs.hbs
index b3185a60..1cdef805 100644
--- a/cli/template/src/lib.rs.hbs
+++ b/cli/template/src/lib.rs.hbs
@@ -1,6 +1,8 @@
 //! {{title}}
 //!
-//! {{description}}
+//! Application based on the [Abscissa] framework.
+//!
+//! [Abscissa]: https://github.com/iqlusioninc/abscissa
 
 #![deny(warnings, missing_docs, trivial_casts, unused_qualifications)]
 #![forbid(unsafe_code)]
diff --git a/core/src/lib.rs b/core/src/lib.rs
index d558c870..afd0f333 100644
--- a/core/src/lib.rs
+++ b/core/src/lib.rs
@@ -158,8 +158,6 @@ pub use crate::{
 
 #[cfg(feature = "time")]
 pub use chrono as time;
-#[cfg(feature = "inflector")]
-pub use heck as inflector;
 #[cfg(feature = "secrets")]
 pub use secrecy as secret;
 #[cfg(feature = "secrets")]
diff --git a/derive/Cargo.toml b/derive/Cargo.toml
index 5b55895d..0404671b 100644
--- a/derive/Cargo.toml
+++ b/derive/Cargo.toml
@@ -18,7 +18,7 @@ proc-macro = true
 
 [dependencies]
 darling = "0.9"
-heck = "0.3"
+ident_case = "1"
 proc-macro2 = "0.4"
 quote = "0.6"
 syn = "0.15"
diff --git a/derive/src/command.rs b/derive/src/command.rs
index 328d5800..749d65af 100644
--- a/derive/src/command.rs
+++ b/derive/src/command.rs
@@ -1,6 +1,6 @@
 //! Custom derive support for `abscissa_core::command::Command`.
 
-use heck::KebabCase;
+use ident_case::RenameRule;
 use proc_macro2::TokenStream;
 use quote::quote;
 use synstructure::Structure;
@@ -44,7 +44,7 @@ pub fn derive_command(s: Structure) -> TokenStream {
 fn impl_subcommand_usage_for_enum(data: &syn::DataEnum) -> TokenStream {
     let match_arms = data.variants.iter().map(|variant| {
         // TODO(tarcieri): support `#[options(name = "...")]` attribute
-        let name = variant.ident.to_string().to_kebab_case();
+        let name = RenameRule::KebabCase.apply_to_variant(variant.ident.to_string());
 
         let subcommand = match &variant.fields {
             syn::Fields::Unnamed(fields) => {


Test patch: