module Hyperstack class Operation class Railway def validations self.class.validations end def add_validation_error(i, e) @operation.add_error("param validation #{i+1}", :validation_error, e.to_s) end class << self def validations @validations ||= [] end def add_validation(*args, &block) block = args[0] if args[0] validations << block end def add_error(param, symbol, message, *args, &block) add_validation do begin add_error(param, symbol, message) if instance_eval(&block) true rescue Exit => e raise e unless e.state == :failed add_error(param, symbol, message) # use a bogus exit state which will skip adding # a validation error (see catch block in process_validations method) raise Exit.new(:abort_from_add_error, e.result) end end end end def process_validations validations.each_with_index do |validator, i| begin validator = @operation.method(validator) if validator.is_a? Symbol next if @operation.instance_exec(&validator) add_validation_error(i, "param validation #{i+1} failed") rescue Exit => e case e.state when :success add_validation_error(i, "illegal use of succeed! in validation") when :failed add_validation_error(i, "param validation #{i+1} aborted") end @state = :abort return # break does not work in Opal rescue AccessViolation => e add_validation_error(i, e) @state = :abort @last_result = e return # break does not work in Opal rescue Exception => e add_validation_error(i, e) end end ensure if @operation.has_errors? @last_result ||= ValidationException.new(@operation.instance_variable_get('@errors')) @state ||= :failed end end end end end