diff options
author | Rémy Coutable <remy@rymai.me> | 2016-08-11 18:51:37 +0200 |
---|---|---|
committer | Rémy Coutable <remy@rymai.me> | 2016-08-13 00:06:12 +0200 |
commit | 42e30a5012bb3384ee6f275ff058d4c0841776cd (patch) | |
tree | d38e8a2736eb6e73559a0d90390722b463c702cd /lib | |
parent | 65349c22129fcdf2ae0c7103094bbf50ae73db61 (diff) | |
download | gitlab-ce-42e30a5012bb3384ee6f275ff058d4c0841776cd.tar.gz |
Accept blocks for `.desc` and `.condition` slash commands DSL
Also, pass options as instance variables, making the DSL more
user-friendly / natural.
Signed-off-by: Rémy Coutable <remy@rymai.me>
Diffstat (limited to 'lib')
-rw-r--r-- | lib/gitlab/slash_commands/dsl.rb | 111 |
1 files changed, 73 insertions, 38 deletions
diff --git a/lib/gitlab/slash_commands/dsl.rb b/lib/gitlab/slash_commands/dsl.rb index 20e1d071d06..3affd6253e9 100644 --- a/lib/gitlab/slash_commands/dsl.rb +++ b/lib/gitlab/slash_commands/dsl.rb @@ -8,20 +8,27 @@ module Gitlab end module ClassMethods + # This method is used to generate the autocompletion menu + # It returns no-op slash commands (such as `/cc`) def command_definitions(opts = {}) @command_definitions.map do |cmd_def| - next if cmd_def[:cond_lambda] && !cmd_def[:cond_lambda].call(opts) + context = OpenStruct.new(opts) + next if cmd_def[:cond_block] && !context.instance_exec(&cmd_def[:cond_block]) cmd_def = cmd_def.dup if cmd_def[:description].present? && cmd_def[:description].respond_to?(:call) - cmd_def[:description] = cmd_def[:description].call(opts) rescue '' + cmd_def[:description] = context.instance_exec(&cmd_def[:description]) rescue '' end cmd_def end.compact end + # This method is used to generate a list of valid commands in the current + # context of `opts`. + # It excludes no-op slash commands (such as `/cc`). + # This list can then be given to `Gitlab::SlashCommands::Extractor`. def command_names(opts = {}) command_definitions(opts).flat_map do |command_definition| next if command_definition[:noop] @@ -30,59 +37,88 @@ module Gitlab end.compact end - # Allows to give a description to the next slash command - def desc(text) - @description = text + # Allows to give a description to the next slash command. + # This description is shown in the autocomplete menu. + # It accepts a block that will be evaluated with the context given to + # `.command_definitions` or `.command_names`. + # + # Example: + # + # desc do + # "This is a dynamic description for #{noteable.to_ability_name}" + # end + # command :command_key do |arguments| + # # Awesome code block + # end + def desc(text = '', &block) + @description = block_given? ? block : text end - # Allows to define params for the next slash command + # Allows to define params for the next slash command. + # These params are shown in the autocomplete menu. + # + # Example: + # + # params "~label ~label2" + # command :command_key do |arguments| + # # Awesome code block + # end def params(*params) @params = params end - # Allows to define if a command is a no-op, but should appear in autocomplete - def noop(noop) - @noop = noop - end - - # Allows to define if a lambda to conditionally return an action - def condition(cond_lambda) - @cond_lambda = cond_lambda - end - - # Registers a new command which is recognizeable - # from body of email or comment. + # Allows to define conditions that must be met in order for the command + # to be returned by `.command_names` & `.command_definitions`. + # It accepts a block that will be evaluated with the context given to + # `.command_definitions`, `.command_names`, and the actual command method. + # # Example: # + # condition do + # project.public? + # end # command :command_key do |arguments| # # Awesome code block # end + def condition(&block) + @cond_block = block + end + + # Registers a new command which is recognizeable from body of email or + # comment. + # It accepts aliases and takes a block. # + # Example: + # + # command :my_command, :alias_for_my_command do |arguments| + # # Awesome code block + # end def command(*command_names, &block) + opts = command_names.extract_options! command_name, *aliases = command_names proxy_method_name = "__#{command_name}__" - # This proxy method is needed because calling `return` from inside a - # block/proc, causes a `return` from the enclosing method or lambda, - # otherwise a LocalJumpError error is raised. - define_method(proxy_method_name, &block) + if block_given? + # This proxy method is needed because calling `return` from inside a + # block/proc, causes a `return` from the enclosing method or lambda, + # otherwise a LocalJumpError error is raised. + define_method(proxy_method_name, &block) - define_method(command_name) do |*args| - unless @cond_lambda.nil? || @cond_lambda.call(project: project, current_user: current_user, noteable: noteable) - return - end + define_method(command_name) do |*args| + return if @cond_block && !instance_exec(&@cond_block) - proxy_method = method(proxy_method_name) + proxy_method = method(proxy_method_name) - if proxy_method.arity == -1 || proxy_method.arity == args.size - instance_exec(*args, &proxy_method) + if proxy_method.arity == -1 || proxy_method.arity == args.size + instance_exec(*args, &proxy_method) + end end - end - private command_name - aliases.each do |alias_command| - alias_method alias_command, command_name - private alias_command + private command_name + aliases.each do |alias_command| + alias_method alias_command, command_name + private alias_command + end end command_definition = { @@ -91,14 +127,13 @@ module Gitlab description: @description || '', params: @params || [] } - command_definition[:noop] = @noop unless @noop.nil? - command_definition[:cond_lambda] = @cond_lambda unless @cond_lambda.nil? + command_definition[:noop] = opts[:noop] || false + command_definition[:cond_block] = @cond_block @command_definitions << command_definition @description = nil @params = nil - @noop = nil - @cond_lambda = nil + @cond_block = nil end end end |