Class: CommandKit::Completion::Task

Inherits:
Rake::TaskLib
  • Object
show all
Defined in:
lib/command_kit/completion/task.rb

Overview

command_kit-completion rake task.

Example

require 'command_kit/completion/task'
CommandKit::Completion::Task.new(
  class_file:  './examples/cli',
  class_name:  'Foo::CLI',
  output_file: 'completion.sh'
)

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(class_file:, class_name:, output_file:, input_file: nil, wrap_function: false, function_name: nil) ⇒ Task

Initializes the command_kit:completion task.

Parameters:

  • class_file (String)

    The file that contains the comand_kit CLI.

  • class_name (String)

    The class name of the command_kit CLI.

  • output_file (String)

    The output file to write the completions rules to.

  • input_file (String, nil) (defaults to: nil)

    The optional YAML input file of additional completion rules. See completely examples for YAML syntax.



90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/command_kit/completion/task.rb', line 90

def initialize(class_file: ,
               class_name: ,
               output_file: ,
               input_file:    nil,
               wrap_function: false,
               function_name: nil)
  @class_file  = class_file
  @class_name  = class_name
  @output_file = output_file

  @input_file    = input_file
  @wrap_function = wrap_function
  @function_name = function_name

  define
end

Instance Attribute Details

#class_fileString (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

The file that the command_kit CLI is defined in.

Returns:

  • (String)


32
33
34
# File 'lib/command_kit/completion/task.rb', line 32

def class_file
  @class_file
end

#class_nameString (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

The class name of the command_kit CLI.

Returns:

  • (String)


39
40
41
# File 'lib/command_kit/completion/task.rb', line 39

def class_name
  @class_name
end

#function_nameString? (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Optional function name to wrap the shell completions within.

Returns:

  • (String, nil)


68
69
70
# File 'lib/command_kit/completion/task.rb', line 68

def function_name
  @function_name
end

#input_fileString? (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Optional input YAML file to read additional shell completions from.

Returns:

  • (String, nil)


53
54
55
# File 'lib/command_kit/completion/task.rb', line 53

def input_file
  @input_file
end

#output_fileString (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

The output file to write the shell completions to.

Returns:

  • (String)


46
47
48
# File 'lib/command_kit/completion/task.rb', line 46

def output_file
  @output_file
end

#wrap_functionBoolean (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Specifies whether the shell completion logic should be wrapped in a function.

Returns:

  • (Boolean)


61
62
63
# File 'lib/command_kit/completion/task.rb', line 61

def wrap_function
  @wrap_function
end

Instance Method Details

#completion_rulesHash{String => Array<String>}

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Builds the completion rules for the command_kit CLI command, and merges in any additional completion rules from the input file.

Returns:

  • (Hash{String => Array<String>})


258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
# File 'lib/command_kit/completion/task.rb', line 258

def completion_rules
  completion_rules = completion_rules_for(load_class)

  if @input_file
    # load the additional rules from the input file
    additional_completion_rules = load_input_file

    # merge the additional completion rules
    additional_completion_rules.each do |command_string,completions|
      if completion_rules[command_string]
        completion_rules[command_string].concat(completions)
      else
        completion_rules[command_string] = completions
      end
    end
  end

  return completion_rules
end

#completion_rules_for(command_class) ⇒ Hash{String => Array<String>}

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Generates the completion rules for the given command_kit command class.

Parameters:

  • command_class (Class)

    The command class.

Returns:

  • (Hash{String => Array<String>})

    The completion rules for the command class and any sub-commands.



192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
# File 'lib/command_kit/completion/task.rb', line 192

def completion_rules_for(command_class)
  command_name = command_class.command_name
  completions  = {command_name => []}

  # options
  if command_class.include?(CommandKit::Options)
    # add all long option flags
    command_class.options.each_value do |option|
      completions[command_name] << option.long
      completions[command_name] << option.short if option.short

      if option.value
        if (suggestions = suggestions_for_argument(option.value.usage))
          command_pattern = "#{command_name}*#{option.long}"

          # add a special rule if the option's value USAGE maps to a
          # 'completely' completion keyword (ex: `FILE` -> `<file>`).
          completions[command_pattern] = suggestions

          if option.short
            # also add another rule with the option's short flag
            completions["#{command_name}*#{option.short}"] = suggestions
          end
        end
      end
    end
  end

  # sub-commands / first argument
  if command_class.include?(CommandKit::Commands)
    command_class.commands.each do |subcommand_name,subcommand|
      # add all sub-command names
      completions[command_name] << subcommand_name

      # generate completions for the sub-command and merge them in
      completion_rules_for(subcommand.command).each do |subcommand_string,subcommand_completions|
        completions["#{command_name} #{subcommand_string}"] = subcommand_completions
      end
    end

    completions[command_name].concat(command_class.command_aliases.keys)
  elsif command_class.include?(CommandKit::Arguments)
    if (argument = command_class.arguments.values.first)
      if (suggestions = suggestions_for_argument(argument.usage))
        # add a suggestion for the first argument
        completions[command_name].concat(suggestions)
      end
    end
  end

  # filter out any command's that have no options/sub-commands
  completions.reject! do |command_string,command_completions|
    command_completions.empty?
  end

  return completions
end

#defineObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Defines the command_kit:completion task.



112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# File 'lib/command_kit/completion/task.rb', line 112

def define
  task(@output_file) do
    completions  = Completely::Completions.new(completion_rules)
    shell_script = if @wrap_function
                     completions.wrap_function(*@function_name)
                   else
                     completions.script
                   end

    ::FileUtils.mkdir_p(File.dirname(@output_file))
    File.write(@output_file,shell_script)
  end

  desc 'Generates the shell completions'
  task 'command_kit:completion' => @output_file

  task :completion => 'command_kit:completion'
end

#load_classClass

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Loads the #class_name from the #class_file.

Returns:

  • (Class)


138
139
140
141
# File 'lib/command_kit/completion/task.rb', line 138

def load_class
  require(@class_file)
  Object.const_get(@class_name)
end

#load_input_fileHash

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Loads the completion rules from the #input_file.

Returns:

  • (Hash)

    The completion rules from the #input_file.



151
152
153
# File 'lib/command_kit/completion/task.rb', line 151

def load_input_file
  YAML.load_file(@input_file, aliases: true)
end

#suggestions_for_argument(arg) ⇒ Array<String>?

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Maps the argument name strings to completely suggestion <keyword>s.

Parameters:

  • arg (String)

    The argument name.

Returns:

  • (Array<String>, nil)

    The suggestion keyword for the argument name.

Since:

  • 0.3.0



168
169
170
171
172
173
174
175
176
# File 'lib/command_kit/completion/task.rb', line 168

def suggestions_for_argument(arg)
  case arg
  when /\AFILE\z|_FILE\z/ then %w[<file>]
  when /\ADIR\z|_DIR\z/   then %w[<directory>]
  when /\APATH\z|_PATH\z/ then %w[<file> <directory>]
  when /\AHOST\z|_HOST\z/ then %w[<hostname>]
  when /\AUSER\z|_USER\z/ then %w[<user>]
  end
end