From 89b5668d48229c18f89a7e34b814ea2cb0231422 Mon Sep 17 00:00:00 2001 From: Fire Demon Date: Mon, 27 Jul 2020 15:29:34 -0500 Subject: [Command Tags] Simplify tag processing and add support for return value templates --- app/lib/command_tag/commands/hello_world.rb | 4 +- app/lib/command_tag/commands/variables.rb | 2 - app/lib/command_tag/processor.rb | 71 ++++++++++++++++++----------- 3 files changed, 47 insertions(+), 30 deletions(-) (limited to 'app/lib') diff --git a/app/lib/command_tag/commands/hello_world.rb b/app/lib/command_tag/commands/hello_world.rb index 2341d22e2..d67f65333 100644 --- a/app/lib/command_tag/commands/hello_world.rb +++ b/app/lib/command_tag/commands/hello_world.rb @@ -5,7 +5,7 @@ module CommandTag::Commands::HelloWorld @vars['hello_world'] = ['Hello, world!'] end - def handle_hello_world_at_start(_) - @text << "\nHello, world!" + def handle_hello_world_with_return(_) + 'Hello, world!' end end diff --git a/app/lib/command_tag/commands/variables.rb b/app/lib/command_tag/commands/variables.rb index ab90ca13b..997131cd9 100644 --- a/app/lib/command_tag/commands/variables.rb +++ b/app/lib/command_tag/commands/variables.rb @@ -9,8 +9,6 @@ module CommandTag::Commands::Variables case args.count when 1 @vars.delete(args[0]) - when 2 - @vars[args[0]] = [args.last] else @vars[args[0]] = args[1..-1] end diff --git a/app/lib/command_tag/processor.rb b/app/lib/command_tag/processor.rb index 6ca355687..74fe30509 100644 --- a/app/lib/command_tag/processor.rb +++ b/app/lib/command_tag/processor.rb @@ -15,9 +15,10 @@ class CommandTag::Processor include ImgProxyHelper include CommandTag::Commands - STATEMENT_RE = /^\s*#!\s*([^\n]+ (?:start|begin|do)$.*?)\n\s*#!\s*(?:end|stop|done)\s*$|^\s*#!\s*(.*?)\s*$/im.freeze - TEMPLATE_RE = /%%\s*(.*?)\s*%%/.freeze MENTIONS_OR_HASHTAGS_RE = /(?:(?:#{Account::MENTION_RE}|#{Tag::HASHTAG_RE})\s*)+/.freeze + PARSEABLE_RE = /^\s*(?:#{MENTIONS_OR_HASHTAGS_RE})?#!|%%.+?%%/.freeze + STATEMENT_RE = /^\s*#!\s*[^\n]+ (?:start|begin|do)$.*?\n\s*#!\s*(?:end|stop|done)\s*$|^\s*#!\s*.*?\s*$/im.freeze + TEMPLATE_RE = /%%\s*(.*?)\s*%%/.freeze ESCAPE_MAP = { '\n' => "\n", '\r' => "\r", @@ -31,15 +32,15 @@ class CommandTag::Processor @parent = status.thread @conversation = status.conversation @run_once = Set[] - @vars = {} + @vars = { 'statement_uuid' => [nil] } @text = prepare_input(status.text) - @statements = [] + @statements = {} return unless @account.present? && @account.local? && @status.present? end def process! - unless @text.include?('#!') && @text.match?(/^\s*(?:#{MENTIONS_OR_HASHTAGS_RE})?#!/) + unless @text.match?(PARSEABLE_RE) process_inline_images! @status.save! return @@ -51,31 +52,32 @@ class CommandTag::Processor parse_statements - %w(at_start once_at_start).each { |suffix| execute_statements(suffix) } + execute_statements(:at_start) + execute_statements(:with_return, true) @text = parse_templates(@text).rstrip - %w(before_save once_before_save).each { |suffix| execute_statements(suffix) } + execute_statements(:before_save) if @text.blank? || @text.gsub(MENTIONS_OR_HASHTAGS_RE, '').strip.blank? - %w(when_blank once_when_blank).each { |suffix| execute_statements(suffix) } + execute_statements(:when_blank) unless (@status.published? && !@status.edited.zero?) || @text.present? - %w(before_destroy once_before_destroy).each { |suffix| execute_statements(suffix) } + execute_statements(:before_destroy) @status.destroy - %w(after_destroy once_after_destroy).each { |suffix| execute_statements(suffix) } + execute_statements(:after_destroy) end elsif @status.destroyed? - %w(after_destroy once_after_destroy).each { |suffix| execute_statements(suffix) } + execute_statements(:after_destroy) else @status.text = @text process_inline_images! if @status.save - %w(after_save once_after_save).each { |suffix| execute_statements(suffix) } + execute_statements(:after_save) else - %w(after_save_fail once_after_save_fail).each { |suffix| execute_statements(suffix) } + execute_statements(:after_save_fail) end end - %w(at_end once_at_end).each { |suffix| execute_statements(suffix) } + execute_statements(:at_end) reset_status_caches end @@ -126,12 +128,12 @@ class CommandTag::Processor def parse_statements @text.gsub!(STATEMENT_RE) do - statement = Regexp.last_match[1..-1].flatten.compact + statement = Regexp.last_match(0).strip[2..-1] next if statement.blank? statement_array = statement.scan(/'([^']*)'|"([^"]*)"|(\S+)|\s+(?:start|begin|do)\s*$\n+(.*)/im).flatten.compact statement_array[0] = statement_array[0].strip.tr(':.\- ', '_').gsub(/__+/, '_').downcase - next unless statement_array[0].match?(/\A\w+\z/) + next unless statement_array[0].match?(/\A[\w_]+\z/) statement_array[-1].rstrip! if statement_array.count > 1 add_statement_handlers_for(statement_array) @@ -140,28 +142,45 @@ class CommandTag::Processor def potential_handlers_for(name) ['_once', ''].each_with_index do |count_affix, index| - %w(at_start when_blank at_end).each do |when_affix| - yield ["handle_#{name}#{count_affix}_#{when_affix}", index.zero?] + %w(at_start with_return when_blank at_end).each do |when_affix| + yield ["#{count_affix}_#{when_affix}", "handle_#{name}#{count_affix}_#{when_affix}", index.zero?] end %w(destroy save postprocess save_fail).each do |event_affix| %w(before after).each do |when_affix| - yield ["handle_#{name}#{count_affix}_#{when_affix}_#{event_affix}", index.zero?] + yield ["#{count_affix}_#{when_affix}_#{event_affix}", "handle_#{name}#{count_affix}_#{when_affix}_#{event_affix}", index.zero?] end end end end - def add_statement_handlers_for(statement_array, _index) - potential_handlers_for(statement_array[0]) do |handler, once| - (@statements << [handler, statement_array[1..-1]]) if respond_to?(handler) && !(once && @run_once.include?(handler)) - @run_once << handler if once + def add_statement_handlers_for(statement_array) + statement_uuid = SecureRandom.uuid + + potential_handlers_for(statement_array[0]) do |when_affix, handler, once| + if !(once && @run_once.include?(handler)) && respond_to?(handler) + @statements[when_affix] ||= [] + @statements[when_affix] << [handler, statement_array[1..-1], statement_uuid] + @run_once << handler if once + end end + + # Template for statement return value. + "%% statement:#{statement_uuid} %%" end - def execute_statements(event) - @statements.each do |handler, arguments| - public_send(handler, arguments) if handler.end_with?("_#{event}") + def execute_statements(event, with_return = false) + ["_#{event}", "_once_#{event}"].each do |when_affix| + next if @statements[when_affix].blank? + + @statements[when_affix].each do |handler, arguments, uuid| + @vars['statement_uuid'][0] = uuid + if with_return + @vars["statement:#{uuid}"] = [public_send(handler, arguments)] + else + public_send(handler, arguments) + end + end end end -- cgit