tty
tty copied to clipboard
Teletype subcommand creation causes nil reference error
Reposted from tty-file, by request.
Thanks, John for reporting!
Does the contacts command already exist when you're trying to create contacts phonelist subcommand? Would it be possible for you to report this issue at https://github.com/piotrmurach/tty since that's where the teletype tool is developed?
I cannot use teletype to create a subcommand of a command. When I do I get an exception
> teletype add contacts phonelist --force 136ms
create spec/integration/contacts/phonelist_spec.rb
create spec/unit/contacts/phonelist_spec.rb
create lib/ddca/commands/contacts/phonelist.rb
create lib/ddca/templates/contacts/phonelist/.gitkeep
Traceback (most recent call last):
10: from /Users/jschank/.asdf/installs/ruby/2.5.1/bin/teletype:23:in `<main>'
9: from /Users/jschank/.asdf/installs/ruby/2.5.1/bin/teletype:23:in `load'
8: from /Users/jschank/.asdf/installs/ruby/2.5.1/lib/ruby/gems/2.5.0/gems/tty-0.8.1/exe/teletype:14:in `<top (required)>'
7: from /Users/jschank/.asdf/installs/ruby/2.5.1/lib/ruby/gems/2.5.0/gems/thor-0.20.0/lib/thor/base.rb:466:in `start'
6: from /Users/jschank/.asdf/installs/ruby/2.5.1/lib/ruby/gems/2.5.0/gems/thor-0.20.0/lib/thor.rb:387:in `dispatch'
5: from /Users/jschank/.asdf/installs/ruby/2.5.1/lib/ruby/gems/2.5.0/gems/thor-0.20.0/lib/thor/invocation.rb:126:in `invoke_command'
4: from /Users/jschank/.asdf/installs/ruby/2.5.1/lib/ruby/gems/2.5.0/gems/thor-0.20.0/lib/thor/command.rb:27:in `run'
3: from /Users/jschank/.asdf/installs/ruby/2.5.1/lib/ruby/gems/2.5.0/gems/tty-0.8.1/lib/tty/cli.rb:88:in `add'
2: from /Users/jschank/.asdf/installs/ruby/2.5.1/lib/ruby/gems/2.5.0/gems/tty-0.8.1/lib/tty/commands/add.rb:131:in `execute'
1: from /Users/jschank/.asdf/installs/ruby/2.5.1/lib/ruby/gems/2.5.0/gems/tty-file-0.6.0/lib/tty/file.rb:512:in `inject_into_file'
/Users/jschank/.asdf/installs/ruby/2.5.1/lib/ruby/gems/2.5.0/gems/tty-file-0.6.0/lib/tty/file.rb:512:in `escape': no implicit conversion of nil into String (TypeError)
It doesn't matter if I try to define parameters or not. I met this problem when I tried a more complex call:
> teletype add contacts phone_list --desc "Color code the phone extension list" --args contacts_file extension_xslx
Ultimately resulted in the same exception, from the same place
Answer - from tty-file:
Yep, contacts already existed. Created with add command earlier.
What might not be clear is - are we permitted to add a sub command to an existing command? It does not appear this is supported:
teletype add main
teletype add main sub
I made a small script to show the issue:
#!/bin/bash
VER=2.5.1
rm -rf works || true
rm -rf issue || true
echo $VER > .ruby-version
echo "**** NEW PROJECT works ****"
teletype new works
cd works
echo $VER > .ruby-version
echo "**** ADD main sub ****"
teletype add main sub
cd ..
echo "**** NEW PROJECT issue ****"
teletype new issue
cd issue
echo $VER > .ruby-version
echo "**** ADD main ****"
teletype add main
echo "**** ADD sub ****"
teletype add main sub
I using the latest tty gem this is what I see for output:
**** NEW PROJECT works ****
Creating gem 'works'...
Code of conduct enabled in config
create works/Gemfile
create works/lib/works.rb
create works/lib/works/version.rb
create works/works.gemspec
create works/Rakefile
create works/README.md
create works/bin/console
create works/bin/setup
create works/.gitignore
create works/.travis.yml
create works/.rspec
create works/spec/spec_helper.rb
create works/spec/works_spec.rb
create works/CODE_OF_CONDUCT.md
append works/README.md
inject works/works.gemspec
create works/lib/works/cli.rb
create works/lib/works/command.rb
create works/exe/works
create works/LICENSE.txt
create works/lib/works/commands/.gitkeep
create works/lib/works/templates/.gitkeep
create works/spec/integration/.gitkeep
create works/spec/support/.gitkeep
create works/spec/unit/.gitkeep
Initializing git repo in /Users/jaylawrence/Projects/PwCmd/TTYissue/works
Your teletype project has been created successfully.
Run "teletype help" for more commands.
**** ADD main sub ****
create spec/integration/main_spec.rb
create spec/integration/main/sub_spec.rb
create spec/unit/main/sub_spec.rb
create lib/works/commands/main.rb
create lib/works/commands/main/sub.rb
create lib/works/templates/main/sub/.gitkeep
inject lib/works/cli.rb
inject lib/works/commands/main.rb
**** NEW PROJECT issue ****
Creating gem 'issue'...
Code of conduct enabled in config
create issue/Gemfile
create issue/lib/issue.rb
create issue/lib/issue/version.rb
create issue/issue.gemspec
create issue/Rakefile
create issue/README.md
create issue/bin/console
create issue/bin/setup
create issue/.gitignore
create issue/.travis.yml
create issue/.rspec
create issue/spec/spec_helper.rb
create issue/spec/issue_spec.rb
create issue/CODE_OF_CONDUCT.md
append issue/README.md
inject issue/issue.gemspec
create issue/lib/issue/cli.rb
create issue/lib/issue/command.rb
create issue/exe/issue
create issue/LICENSE.txt
create issue/lib/issue/commands/.gitkeep
create issue/lib/issue/templates/.gitkeep
create issue/spec/integration/.gitkeep
create issue/spec/support/.gitkeep
create issue/spec/unit/.gitkeep
Initializing git repo in /Users/jaylawrence/Projects/PwCmd/TTYissue/issue
Your teletype project has been created successfully.
Run "teletype help" for more commands.
**** ADD main ****
create spec/integration/main_spec.rb
create spec/unit/main_spec.rb
create lib/issue/commands/main.rb
create lib/issue/templates/main/.gitkeep
inject lib/issue/cli.rb
**** ADD sub ****
create spec/integration/main/sub_spec.rb
create spec/unit/main/sub_spec.rb
create lib/issue/commands/main/sub.rb
create lib/issue/templates/main/sub/.gitkeep
/Users/jaylawrence/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/tty-file-0.6.0/lib/tty/file.rb:512:in `escape': no implicit conversion of nil into String (TypeError)
from /Users/jaylawrence/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/tty-file-0.6.0/lib/tty/file.rb:512:in `inject_into_file'
from /Users/jaylawrence/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/tty-0.8.1/lib/tty/commands/add.rb:131:in `execute'
from /Users/jaylawrence/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/tty-0.8.1/lib/tty/cli.rb:88:in `add'
from /Users/jaylawrence/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/thor-0.20.3/lib/thor/command.rb:27:in `run'
from /Users/jaylawrence/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/thor-0.20.3/lib/thor/invocation.rb:126:in `invoke_command'
from /Users/jaylawrence/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/thor-0.20.3/lib/thor.rb:387:in `dispatch'
from /Users/jaylawrence/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/thor-0.20.3/lib/thor/base.rb:466:in `start'
from /Users/jaylawrence/.rbenv/versions/2.5.1/lib/ruby/gems/2.5.0/gems/tty-0.8.1/exe/teletype:14:in `<top (required)>'
from /Users/jaylawrence/.rbenv/versions/2.5.1/bin/teletype:23:in `load'
from /Users/jaylawrence/.rbenv/versions/2.5.1/bin/teletype:23:in `<main>'
This is not supported. Why is that? It is impossible to distinguish between command argument and subcommand name. To make it more concrete:
mytool main arg # the arg is the argument to command main
mytool main subcmd # the subcmd is a sub command name
How would mytool reconcile this situation? The answer is it cannot. Basically when you run:
tty add main
This will genearte a command main. When you run mytool main it will call method called main with everything else passed as arguments or options. Then if you wished your command main to provide meaning for your arguments, you would need specify logic yourself like so:
def main(arg1)
if arg1 == 'subcmd'
# invoke subcmd
end
end
The teleteype executable cannot do this for you because your main can have plenty of logic already and figuring out arguments maybe hard or impossible to automate. The one thing teletype could do is to create these commands but hooking them up with your main command would be a rather hard thing to do elegantly.
On the other hand if you wish main to support subcommands you wouldn't actually need to generate the main command first. The act of generating subcommand creates the main command as well as a namespace for all the other subcommands. The main itself would become the list of all subcommands:
tty add main subcmd1
tty add main subcmd2
...
Then you can run:
mytool main # lists all subcommands
mytool main subcmd1
mytool main subcmd2
Does that make sense? It probably would be beneficial to provide automatic explanation for this when generating commands or improve documentation?
As I get to know the toolkit better I see what you mean. It might be helpful in section 2.8 to specifically address this point. The way it flows is here's how to do a command called "config" and how it can do a few things, then let's (also) add a subcommand called "config set".
If you would like I could make a PR with some documentation edits that might help the new user. (because I am one right now so I know what's got me puzzled here and there).
I think that there's a case that could be made for section 2.9 which would be the kitchen sink example. In fact It think I'll build one now for myself and would be happy to add to the above edit.
I would recommend that if a command is detected when adding a subcommand that it fail and advise the user as such.
I view documentation as essential to tty adoption. So I'm always happy to receive PRs improving the docs! If you can chunk your changes into smaller PRs that will be even better so I can review them quicker and merge. Thanks!
I will have to see what is the best approach in handling the subcommand generation when the command is already present, whether an error message gets displayed or the teletype will figure out how to and generate additional commands and let the user to manually wire them into their command.