class ChefDK::CommandsMap
CommandsMap
maintains a mapping of subcommand names to the files where those commands are defined and the classes that implement the commands.
In ruby it's more typical to handle this sort of thing using conventions and metaprogramming. We've implemented this approach in the past and decided against it here:
-
Performance. As the
CLI
suite grows, you have to load more and more
code, including dependencies that are installed by rubygems, etc. This gets slow, and CLI
apps need to be fast.
-
You can workaround the above by having a convention mapping filename to
command name, but then you have to do a lot of work to list all of the commands, which is actually a common thing to do.
-
Other ways to mitigate the performance issue (loading deps lazily) have
their own complications and tradeoffs and don't fully solve the problem.
-
It's not actually that much work to maintain the mapping.
## Adding new commands globally:
A “singleton-ish” instance of this class is stored as ChefDK.commands_map
. You can configure a multiple commands at once in a block using ChefDK.commands
, like so:
ChefDK.commands do |c| # assigns `chef my-command` to the class ChefDK::Command::MyCommand. # The "require path" is inferred to be "chef-dk/command/my_command" c.builtin("my-command", :MyCommand) # Set the require path explicitly: c.builtin("weird-command", :WeirdoClass, require_path: "chef-dk/command/this_is_cray") # You can add a description that will show up in `chef -h` output (recommended): c.builtin("documented-cmd", :DocumentedCmd, desc: "A short description") end
Constants
- CommandSpec
- NULL_ARG
Attributes
Public Class Methods
# File lib/chef-dk/commands_map.rb, line 71 def initialize @command_specs = {} end
Public Instance Methods
# File lib/chef-dk/commands_map.rb, line 75 def builtin(name, constant_name, require_path: NULL_ARG, desc: "", hidden: false) if null?(require_path) snake_case_path = name.tr("-", "_") require_path = "chef-dk/command/#{snake_case_path}" end command_specs[name] = CommandSpec.new(name, constant_name, require_path, desc, hidden) end
# File lib/chef-dk/commands_map.rb, line 91 def command_names command_specs.keys end
# File lib/chef-dk/commands_map.rb, line 87 def have_command?(name) command_specs.key?(name) end
# File lib/chef-dk/commands_map.rb, line 83 def instantiate(name) spec_for(name).instantiate end
# File lib/chef-dk/commands_map.rb, line 95 def spec_for(name) command_specs[name] end
Private Instance Methods
# File lib/chef-dk/commands_map.rb, line 101 def null?(argument) argument.equal?(NULL_ARG) end