about summary refs log tree commit diff
path: root/app/lib/command_tag/processor.rb
diff options
context:
space:
mode:
Diffstat (limited to 'app/lib/command_tag/processor.rb')
-rw-r--r--app/lib/command_tag/processor.rb60
1 files changed, 47 insertions, 13 deletions
diff --git a/app/lib/command_tag/processor.rb b/app/lib/command_tag/processor.rb
index 66a507f23..864da6c59 100644
--- a/app/lib/command_tag/processor.rb
+++ b/app/lib/command_tag/processor.rb
@@ -1,7 +1,18 @@
 # frozen_string_literal: true
 
+#                  .~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~.                  #
+###################              Cthulhu Code!              ###################
+#                  `~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~`                  #
+# - Interprets and executes user input.  THIS CAN BE VERY DANGEROUS!          #
+# - Has a high complexity level and needs tests.                              #
+# - May destroy objects passed to it.                                         #
+# - Incurs a high performance penalty.                                        #
+#                                                                             #
+###############################################################################
+
 class CommandTag::Processor
   include Redisable
+  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
@@ -15,6 +26,7 @@ class CommandTag::Processor
     @run_once     = Set[]
     @vars         = {}
     @text         = prepare_input(status.text)
+    @statements   = []
 
     return unless @account.present? && @account.local? && @status.present?
   end
@@ -22,7 +34,7 @@ class CommandTag::Processor
   def process!
     reset_status_caches
 
-    @statements = parse_statements
+    parse_statements
     @text = @text.gsub(STATEMENT_STRIP_RE, '').split("\n")
 
     %w(at_start once_at_start).each { |suffix| execute_statements(suffix) }
@@ -39,10 +51,14 @@ class CommandTag::Processor
       end
     elsif @status.destroyed?
       %w(after_destroy once_after_destroy).each { |suffix| execute_statements(suffix) }
-    elsif @status.update(text: process_inline_images(@text))
-      %w(after_save once_after_save).each { |suffix| execute_statements(suffix) }
     else
-      %w(after_save_fail once_after_save_fail).each { |suffix| execute_statements(suffix) }
+      @status.text = @text
+      process_inline_images!
+      if @status.save
+        %w(after_save once_after_save).each { |suffix| execute_statements(suffix) }
+      else
+        %w(after_save_fail once_after_save_fail).each { |suffix| execute_statements(suffix) }
+      end
     end
 
     %w(at_end once_at_end).each { |suffix| execute_statements(suffix) }
@@ -57,21 +73,39 @@ class CommandTag::Processor
   end
 
   def parse_statements
-    @text.scan(STATEMENT_RE).flatten.map do |statement|
+    @text.scan(STATEMENT_RE).flatten.each do |statement|
       next if statement.blank? || statement[0]&.strip.blank?
 
       statement = statement.scan(/^(.*) (?:start|begin|do)$(.*)|'([^']*)'|"([^"]*)"|(\S+)/im).flatten.compact
       statement[0] = statement[0].strip.tr(':.\- ', '_').gsub(/__+/, '_').downcase
-      statement
-    end.compact
+      add_statement_handlers_for(statement)
+    end
+  end
+
+  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?]
+      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?]
+        end
+      end
+    end
+  end
+
+  def add_statement_handlers_for(statement_array)
+    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
+    end
   end
 
-  def execute_statements(suffix)
-    @statements.each do |statement|
-      name = "handle_#{statement[0]}_#{suffix}"
-      is_run_once = suffix.start_with?('once_')
-      public_send(name, statement[1..-1]) if respond_to?(name) && !(is_run_once && @run_once.include?(name))
-      @run_once << name if is_run_once
+  def execute_statements(event)
+    @statements.select { |handler, _| handler.end_with?("_#{event}") }.each do |handler, arguments|
+      public_send(handler, arguments)
     end
   end