rubyserv-iirc/eval.rb

118 lines
3.2 KiB
Ruby

# Copyright (C) 2021 Checks Out ✔ <noc@piss.guru>
# Copyright (C) 2022, 2023 Noisytoot <ron@noisytoot.org>
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
require "timeout"
module Eval
def configure_eval
on :privmsg, :do_eval
end
private def do_eval evt
target, msg = evt.args
if msg.start_with?(eval_prefix) and target.start_with? '#' and evt.from_oper?
begin
result = Timeout.timeout(eval_timeout) do
@locals ||= {}
code = msg[eval_prefix.length..]
local_variables.each do |name|
@locals[name] = binding.local_variable_get(name)
end
binding.eval <<~RUBY
#{
@locals.keys.map { |name|
"#{name} = @locals[:#{name}]"
}.join "\n"
}
begin
_ = begin
#{code}
end
ensure
local_variables.each do |name|
@locals[name] = binding.local_variable_get(name)
end
end
RUBY
end
rescue Exception => e
first_line, second_line = e.message.lines.map(&:strip)
say "Fuck, #{e.class.name}: #{first_line[..400]}"
say "#{second_line[..400]}" if second_line
return
end
@last_eval_result = result
header = result.class.name
case result
when String
header = nil
formatted = result
when Array
formatted = result.inspect
when FalseClass, TrueClass
header = result.inspect
formatted = false
when NilClass
header = "-"
formatted = false
when Numeric
header = result.inspect
formatted = false
when Symbol
header = result.inspect
when Hash
keys = []
for key, value in result
keys.push "#{bold key} #{value.inspect}"
end
formatted = keys.join " "
formatted = nil if formatted.empty?
else
formatted = (result.to_s || '')
end
if header
size = " (#{result.size})" rescue nil unless result.is_a? Numeric or result.is_a? Symbol
header = "#{underline header}#{size}"
end
unless formatted
say header if header
return
end
lines = formatted.split("\n").reject(&:empty?)
if lines.empty?
say "-"
else
if header
say "#{header}: #{lines[0][..400]}"
lines = lines[1..]
end
for line in lines
say "#{line[..400]}"
end
end
end
end
def _
@last_eval_result
end
end