{"action":"created","issue":{"url":"https://api.github.com/repos/Gabriel439/Haskell-Turtle-Library/issues/192","repository_url":"https://api.github.com/repos/Gabriel439/Haskell-Turtle-Library","labels_url":"https://api.github.com/repos/Gabriel439/Haskell-Turtle-Library/issues/192/labels{/name}","comments_url":"https://api.github.com/repos/Gabriel439/Haskell-Turtle-Library/issues/192/comments","events_url":"https://api.github.com/repos/Gabriel439/Haskell-Turtle-Library/issues/192/events","html_url":"https://github.com/Gabriel439/Haskell-Turtle-Library/pull/192","id":189947937,"number":192,"title":"More flexible command line flags","user":{"login":"maoe","id":105151,"avatar_url":"https://avatars.githubusercontent.com/u/105151?v=3","gravatar_id":"","url":"https://api.github.com/users/maoe","html_url":"https://github.com/maoe","followers_url":"https://api.github.com/users/maoe/followers","following_url":"https://api.github.com/users/maoe/following{/other_user}","gists_url":"https://api.github.com/users/maoe/gists{/gist_id}","starred_url":"https://api.github.com/users/maoe/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/maoe/subscriptions","organizations_url":"https://api.github.com/users/maoe/orgs","repos_url":"https://api.github.com/users/maoe/repos","events_url":"https://api.github.com/users/maoe/events{/privacy}","received_events_url":"https://api.github.com/users/maoe/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":2,"created_at":"2016-11-17T06:06:59Z","updated_at":"2016-11-20T07:57:30Z","closed_at":null,"pull_request":{"url":"https://api.github.com/repos/Gabriel439/Haskell-Turtle-Library/pulls/192","html_url":"https://github.com/Gabriel439/Haskell-Turtle-Library/pull/192","diff_url":"https://github.com/Gabriel439/Haskell-Turtle-Library/pull/192.diff","patch_url":"https://github.com/Gabriel439/Haskell-Turtle-Library/pull/192.patch"},"body":"This PR changes the way to define command line flags to get more flexibility. Specifically the option parsing library now:\r\n\r\n* requires only one flag name which can be a short name or a long name\r\n* is able to define multiple long/short names for a flag e.g. `switch (\"dry\" <> \"dry-run\" <> shortFlag 'n')` accepts `--dry`, `--dry-run`, and `-n`\r\n* requires a separate metavariable name. This is necessary because there can be no long flag name which can be used as the metavariable. This is sometimes useful even with a long flag for clarity of the help message.\r\n\r\n## Motivation\r\n\r\nThere are three reasons why I want this change.\r\n\r\n1. I often would like to omit short flags for rarely-used options. This is currently impossible because all `optXXX` parsers always take an `ArgName` and a `ShortName`.\r\n2. I sometimes would like to define a synonym for a flag so I can change a flag name without breaking existing systems.\r\n3. I'd like to specify a custom metavariable if the flag takes some complex format.\r\n\r\n## Implementation notes\r\n\r\n`FlagName` is an abstract data type accompanied by smart constructors to keep an invariant: every option should at least have either a long name or a short name. It has an instance of `Semigroup` so we can add more names without introducing `mempty` which breaks the invariant.\r\n\r\n## Migration notes\r\n\r\nThis is a breaking change. All existing code that use `optXXX` break. Fortunately, it's straightforward to fix the breakage:\r\n\r\n* `ArgName` is a long option. If it's a string literal, it works as it is. Otherwise you can use `longFlag`.\r\n* `shortFlag` is necessary to turn a `ShortName` to a `FlagName`. You can compose it with other flag names using `(Data.Semigroup.<>)`, which is re-exported from `Turtle`.\r\n* `ArgName` now means the metavariable for the flag.\r\n\r\nLook at the documentation changes in this PR for example.\r\n\r\nAnother type of breakage is the reexport of `Semigroup`'s `(<>)` from `Turtle`. It fails to compile if a module imports `(<>)` from `Data.Monoid`. I suspect it would become less problematic as `Data.Semigroup` gets popular."},"comment":{"url":"https://api.github.com/repos/Gabriel439/Haskell-Turtle-Library/issues/comments/261764539","html_url":"https://github.com/Gabriel439/Haskell-Turtle-Library/pull/192#issuecomment-261764539","issue_url":"https://api.github.com/repos/Gabriel439/Haskell-Turtle-Library/issues/192","id":261764539,"user":{"login":"maoe","id":105151,"avatar_url":"https://avatars.githubusercontent.com/u/105151?v=3","gravatar_id":"","url":"https://api.github.com/users/maoe","html_url":"https://github.com/maoe","followers_url":"https://api.github.com/users/maoe/followers","following_url":"https://api.github.com/users/maoe/following{/other_user}","gists_url":"https://api.github.com/users/maoe/gists{/gist_id}","starred_url":"https://api.github.com/users/maoe/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/maoe/subscriptions","organizations_url":"https://api.github.com/users/maoe/orgs","repos_url":"https://api.github.com/users/maoe/repos","events_url":"https://api.github.com/users/maoe/events{/privacy}","received_events_url":"https://api.github.com/users/maoe/received_events","type":"User","site_admin":false},"created_at":"2016-11-20T07:57:30Z","updated_at":"2016-11-20T07:57:30Z","body":"I'm fine to drop the `IsString` instance for `FlagName` if that's better.\r\n\r\nI think there are some design choices here.\r\n\r\nMy implementation ensures there is at least one name for an option. This is hard to guarantee if we just make `LongName` and `ShortName` into `Optional` arguments in `optXXX` and `switch` because it's possible that both names are empty. In that case, we could make the `ArgName` the default option name. It forces users to make at least one long name for an option, which is, I feel, an unnecessary constraint.\r\n\r\nAlternatively we could use `NonEmpty FlagName`  where `data FlagName = ShortName Char | LongName Text`. This satisfies the same requirement (where every option has at least one name, either long one or short one) but with a different syntax. I chose `Semigroup` because `Data.List.NonEmpty` is a bit tedious to use.\r\n\r\nLastly, I agree that `OverloadedCharacters` would be nice.\r\n\r\n"}}
{"actor":{"display_login":"maoe"}}