{"id":37019571,"url":"https://github.com/piotrkot/simple-cli","last_synced_at":"2026-01-14T02:10:48.730Z","repository":{"id":35018388,"uuid":"39120524","full_name":"piotrkot/simple-cli","owner":"piotrkot","description":"Simple Object-oriented Command Line Interface","archived":false,"fork":false,"pushed_at":"2021-04-19T17:20:41.000Z","size":38,"stargazers_count":4,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-07-19T14:57:59.387Z","etag":null,"topics":["cli","oop"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":"JetBrains/swot","license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/piotrkot.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-07-15T06:33:59.000Z","updated_at":"2021-04-19T17:20:43.000Z","dependencies_parsed_at":"2022-07-15T14:47:23.685Z","dependency_job_id":null,"html_url":"https://github.com/piotrkot/simple-cli","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/piotrkot/simple-cli","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/piotrkot%2Fsimple-cli","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/piotrkot%2Fsimple-cli/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/piotrkot%2Fsimple-cli/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/piotrkot%2Fsimple-cli/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/piotrkot","download_url":"https://codeload.github.com/piotrkot/simple-cli/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/piotrkot%2Fsimple-cli/sbom","scorecard":{"id":734775,"data":{"date":"2025-08-11","repo":{"name":"github.com/piotrkot/simple-cli","commit":"c2424f8debdfe22a52f8bf69b762556ca06d8031"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3,"checks":[{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Code-Review","score":0,"reason":"Found 0/30 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-22T15:27:39.061Z","repository_id":35018388,"created_at":"2025-08-22T15:27:39.061Z","updated_at":"2025-08-22T15:27:39.061Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28408711,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-14T01:52:23.358Z","status":"online","status_checked_at":"2026-01-14T02:00:06.678Z","response_time":107,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cli","oop"],"created_at":"2026-01-14T02:10:48.142Z","updated_at":"2026-01-14T02:10:48.718Z","avatar_url":"https://github.com/piotrkot.png","language":"Java","readme":"[![Build Status](https://travis-ci.org/piotrkot/simple-cli.svg?branch=master)](https://travis-ci.org/piotrkot/simple-cli)\n[![Build status](https://ci.appveyor.com/api/projects/status/eudv3qsoogrd1h6k?svg=true)](https://ci.appveyor.com/project/piotrkot/simple-cli)\n[![Coverage Status](https://coveralls.io/repos/piotrkot/simple-cli/badge.svg?branch=master\u0026service=github)](https://coveralls.io/github/piotrkot/simple-cli?branch=master)\n\n# Inspiration\n\n[Object thinking by David West](http://www.amazon.com/Object-Thinking-Developer-Reference-David/dp/0735619654) is an amazing read.\nAuthor convinces that proper object-oriented design, fundamentally different\nfrom structured design, can leverage communication among all team members\n(with users included), contribute to vast product simplicity, and even produce\nbetter developers.\n\nWhile soft advantages are hard to question and prove, West also mentions\npublished empirical metrics of Mark Lorenz and\nJeff Kidd\u003csup\u003e[1](#MarkKidd)\u003c/sup\u003e which he interprets as\n\u003e Lines of code, for example, in a well-thought-out object application will be\nat least an order of magnitude fewer (sometimes two orders of magnitude).\n\nWell, that's impressive. Let's check that.\n\n# Experiment\n\nFor the purpose of verifying the claim, we will try to come up with a new\nidea for Command Line Interface (CLI) in Java language.\n\nThere is already a number of Java tools for recognizing command line options\npassed to programs. And they all vary in size, complexity, and, sadly,\nspecification.\n\nProgram | Version | Size\u003csup\u003e[2](#LoC)\u003c/sup\u003e\n--------|---------|-------------------------\nhttps://commons.apache.org/proper/commons-cli/ | (version 1.4-SNAPSHOT) | 23 files (2665 loc)\nhttp://args4j.kohsuke.org/ | (latest commit 00c192c445) | 63 files (2379 loc)\nhttp://jewelcli.lexicalscope.com/usage.html | (latest commit d282f87b93) | 90 files (2825 loc)\nhttp://www.cs.ubc.ca/~lloyd/java/argparser.html | n/a | 14 files (3348 loc)\nhttp://www.urbanophile.com/arenn/hacking/download.html | (latest commit 97d3ac8d79) | 3 files (634 loc)\nhttp://www.martiansoftware.com/jsap/ | (version 2.1) | 94 files (4888 loc)\nhttp://pholser.github.io/jopt-simple/ |(version 4.9) | 45 files (2053 loc)\nhttp://ostermiller.org/utils/CmdLn.html | (version 1.08.02) | 6 files (730 loc)\nhttps://code.google.com/p/parse-cmd/ | (version 0.0.93) | 1 file (238 loc)\nhttp://jcommander.org/ | (latest commit b02e9dee4e) | 49 files (2226 loc)\n\nLooking closer into their documentation and test cases reveals there are\nmany parsers recognizing different options, among which are POSIX, GNU,\nlong options, short options, multivalued options and group options. As the\ngeneral purpose is to outperform others we must support all the possible ones.\n\nAs perhaps it is safe to assume the most popular tool is the Apache Commons CLI,\nthis will be the benchmark for supported options and test cases. This will not\nhowever be the benchmark for the source code complexity, the smallest from\nthe non Object-oriented sources will be.\n\nYou can notice that some existing solutions are already a magnitude smaller in\nlines of code from others. Can we get any better and still be object-oriented?\n\nWhen making contrasting approach one should not look at the current\nimplementations. Thus, let think over the basic principles and responsibilities\nof the CLI objects.\n\nFirst, we must be able to **find options given list of arguments**. And we don't\ncare what kind of options, just options objects. After that\nan **option must provide us with its _values_**. From experience on Unix\nsystems we know that option might be composed of a key with value\n(i.e. `du --max-depth=1`), a value (i.e. `df -H`), or even an\nargument (i.e. `cut -f 1,3`). Apache Commons CLI discloses POSIX options\n(i.e. `tar -cf archive.tar foo bar`), GNU options (i.e. `du --human-readable`),\nshort options with value (i.e. `gcc -O2 foo.c`), long options with single hyphen\n(i.e. `ant -projecthelp`), and alike variations. But it all should not matter as\nthe Option object should be concerned about the details.\n\nOne may notice it is all not that simple. Given argument of `-Dparam2` we don't\nknow whether it is:\n* option `-D` with `param2` value or\n* option `-D` with `param` key and `2` value or\n* option value `-Dparam2`.\n\nIndeed, there is ambiguity of interpretation. However, this is irrelevant as\nthey are different views of the same argument. And whichever form you choose\nthe result is positive.\n\nOften CLI tools provide a bonus feature - generating help information. Help\ninformation is the message displayed when user asks for help explicitly or\nwhen given arguments are not expected for the application.\nRight. How does it fit into the objects model?\n\nCreated CLI object with given command line arguments has the responsibility to\nanswer when asked for an option. It may return an option if it finds one,\nperhaps many options if my request is too general or none if not satisfied.\nHowever, reacting on the options found is the sole purpose of the application,\nso why reacting on the error should be the responsibility of the command\nline parser? And is this help flexible enough to print into different\nsystem streams, with special formatting? And if so, is it really the right\nplace to put logic into?\n\nIn my opinion, it is not.\n\n# Result\n\nWith simple, yet object-oriented design, there are **3 files with total of 134\nloc (which is the smallest code base size!)** with no additional dependency.\nThe code follows strict quality rules\nof [qulice](http://www.qulice.com/) with full test coverage\nof [mutation tests](http://pitest.org/).\n\nApplication supports various options like:\n* POSIX like options (i.e. `tar -zxvf foo.tar.gz`)\n* GNU like long options (i.e. `du --human-readable --max-depth=1`)\n* Java like properties (i.e. `java -Djava.awt.headless=true -Djava.net.useSystemProxies=true Foo`)\n* Short options with value attached (i.e. `gcc -O2 foo.c`)\n* Long options with single hyphen (i.e. `ant -projecthelp`)\n* Multivalued options (i.e. `-file input1.txt input2.txt`)\n* Properties with long format (i.e. `--property foo=bar`)\n* Group options (i.e. `-Xmx2048m -Xms256m -Xdebug`) even all [JVM parameters](http://javarevisited.blogspot.com/2011/11/hotspot-jvm-options-java-examples.html)\n\nHow about the simplicity of use? Here are some examples.\n\n```java\nCommandLineArgs cli = new CommandLineArgs(\"--human-readable\");\ncli.findOption(\"human-readable\").iterator().hasNext(); // returns true\n```\n```java\nCommandLineArgs cli = new CommandLineArgs(\"--max-depth=1\");\ncli.findFirstOption(\"max-depth\").value(); // returns \"1\"\n```\nFor ambiguous options we have an interpretation choice.\n```java\nCommandLineArgs cli = new CommandLineArgs(\"-Xmx2048m\", \"-Xms256m\");\nIterator\u003cOption\u003e iter = cli.findOption(\"X\").iterator();\niter.next().value(); // returns \"mx2048m\"\niter.next().value(); // returns \"ms256m\"\n```\nor\n```java\nCommandLineArgs cli = new CommandLineArgs(\"-Xmx2048m\", \"-Xms256m\");\ncli.findOption(\"Xmx\").iterator().next().value(); // returns \"2048m\"\ncli.findOption(\"Xms\").iterator().next().value(); // returns \"256m\"\n```\ndepending what is more preferable for the user.\n\nIn case we don't exactly know what option name to search for we may find\nthem all by `getOptions` with:\n```java\nOption option = new CommandLineArgs(\"-zxvf\", \"foo.tar.gz\")\n    .getOptions().iterator().next();\noption.value(); // returns \"zxvf\"\noption.arguments().iterator().next(); // returns \"foo.tar.gz\"\n```\n\nIt is quite natural to inform the users how to use the command line program.\nFor we show a special help message when user requests for it, e.g.\nproviding `--help` parameter or when makes a mistake using the program.\n\nThe latter case can be automatically handled with:\n```java\nCommandLineArgs cli = new CommandLineArgs(\n    new HelpException(\"Allowed param is 'abc'\"),\n    \"-abc\"\n);\ncli.findFirstOption(\"bcd\"); // prints \"Allowed param is 'abc'\" as an exception\n```\n\nTo get started, add dependency to your project:\n```xml\n        \u003cdependency\u003e\n            \u003cgroupId\u003ecom.github.piotrkot\u003c/groupId\u003e\n            \u003cartifactId\u003ecli\u003c/artifactId\u003e\n            \u003cversion\u003e1.3.0\u003c/version\u003e\n        \u003c/dependency\u003e\n```\n\nFeel free to fork me on GitHub, report bugs or post comments.\n\nFor Pull Requests, please run `mvn clean package -Pqulice`, first.\n\n\u003ca name=\"MarkKidd\"\u003e\u003csup\u003e1\u003c/sup\u003e\u003c/a\u003e Lorenz, Mark, and Jeff Kidd. Object-Oriented\nSoftware Metrics. Englewood Cliffs, NJ: Prentice Hall. 1994. ISBN 0-13-179292-X\n\n\u003ca name=\"LoC\"\u003e\u003csup\u003e2\u003c/sup\u003e\u003c/a\u003e Lines of code are calculated with\n[cloc](http://cloc.sourceforge.net).\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpiotrkot%2Fsimple-cli","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpiotrkot%2Fsimple-cli","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpiotrkot%2Fsimple-cli/lists"}