Created
September 22, 2022 22:52
-
-
Save estum/80754559a82987fb29b9f2d908e672c3 to your computer and use it in GitHub Desktop.
Ruby Osascript runner
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# @example Simple | |
# Osascript.new(<<~SCPT.freeze).() | |
# activate application "Finder" | |
# SCPT | |
# | |
# @example JSC with args | |
# # The script takes 2 arguments: directory path & image path | |
# # to set a folder icon to the given directory. | |
# script = Osascript.new(<<-JS.freeze, lang: 'JavaScript') | |
# ObjC.import("Cocoa"); | |
# function run(input) { | |
# var target_path = input[0].toString(); | |
# var source_image = $.NSImage.alloc.initWithContentsOfFile(input[1].toString()); | |
# var result = $.NSWorkspace.sharedWorkspace.setIconForFileOptions(source_image, target_path, 0); | |
# return target_path; | |
# } | |
# JS | |
# script.(target_dir, folder_icon) | |
class Osascript | |
attr_accessor :script | |
def initialize(script = nil, lang: "AppleScript") | |
@script = block_given? ? yield : script | |
@lang = lang | |
end | |
def call(*other) | |
handle_errors do | |
cmd = ["/usr/bin/env", "osascript", *params(*other)] | |
IO.popen cmd, "r+", 2 => %i(child out) do |io| | |
io.write script | |
io.close_write | |
io.readlines | |
end | |
end | |
end | |
def params(*args) | |
["-l", @lang].tap { |e| e.concat(args.unshift(?-)) unless args.empty? } | |
end | |
ERROR_PATTERN = /(?<=execution error: )(.+?)(?=$)/ | |
USER_CANCELLED_PATTERN = /user canceled/i | |
NL = "\n" | |
private | |
def handle_errors | |
yield().each_with_object([]) do |line, buf| | |
line.match(ERROR_PATTERN) { |m| raise error_for(m[0]), m[0], caller(4) } | |
buf << line.strip | |
end.join(NL) | |
end | |
def error_for(msg) | |
USER_CANCELLED_PATTERN.test?(msg) ? UserCanceled : ExecutionError | |
end | |
class ExecutionError < RuntimeError | |
CAPTURE_MSG_AND_CODE = /(.+?) \((-?\d+?)\)$/ | |
attr_reader :code | |
def initialize(msg) | |
msg.match(CAPTURE_MSG_AND_CODE) { |m| msg, @code, * = m.captures } | |
super(msg) | |
end | |
end | |
UserCanceled = Class.new(ExecutionError) | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment