module LolcatRunner
LolcatRunner — run lolcat safely via argv arrays (no shell interpolation). Public: run, build_argv, available?, default_argv Depends: (none) Tests: test/lib/lolcat_runner_test.rb
Constants
- ALLOWED_FLAGS
- BIN
- DEFAULT_ARGV
- DEFAULT_TIMEOUT
Public Instance Methods
Source
# File lib/lolcat_runner.rb, line 29 def available?(executable: default_executable) executable.call(BIN) end
Source
# File lib/lolcat_runner.rb, line 37 def build_argv(tokens) argv = [BIN] tokens = Array(tokens).map(&:to_s) index = 0 while index < tokens.length token = tokens[index] spec = ALLOWED_FLAGS[token] return { error: "Unknown lolcat option #{token.inspect}." } unless spec argv << token index += 1 next if spec == :flag value = tokens[index] return { error: "Missing value for #{token}." } if value.nil? || value.empty? case spec when :numeric return { error: "Invalid number for #{token}." } unless value.match?(/\A-?\d+(?:\.\d+)?\z/) argv << value when :integer return { error: "Invalid integer for #{token}." } unless value.match?(/\A-?\d+\z/) argv << value end index += 1 end argv << "-f" unless argv.include?("-f") || argv.include?("--force") { argv: argv } end
Source
# File lib/lolcat_runner.rb, line 95 def default_executable lambda do |bin| ENV.fetch("PATH", "").split(File::PATH_SEPARATOR).any? do |dir| path = File.join(dir, bin) File.file?(path) && File.executable?(path) end end end
Source
# File lib/lolcat_runner.rb, line 89 def default_run lambda do |argv, stdin_data:| Open3.capture3(*argv, stdin_data: stdin_data) end end
Source
# File lib/lolcat_runner.rb, line 70 def run(text, argv: default_argv, timeout: DEFAULT_TIMEOUT, run: default_run) return { error: "lolcat not installed." } unless available? stdout, _stderr, status = run_with_timeout(run, argv, text.to_s, timeout: timeout) return { error: "lolcat failed." } unless status.success? { output: stdout } rescue Timeout::Error { error: "lolcat timed out." } rescue StandardError { error: "lolcat failed." } end
Source
# File lib/lolcat_runner.rb, line 83 def run_with_timeout(run, argv, stdin_data, timeout:) Timeout.timeout(timeout) do run.call(argv, stdin_data: stdin_data) end end