Class: Mailmate::AppleScriptDriver
- Inherits:
-
Object
- Object
- Mailmate::AppleScriptDriver
- Defined in:
- lib/mailmate/applescript_driver.rb
Overview
Build and run AppleScript calls against MailMate. macOS-only.
A class (not a module like the stateless utilities HeaderReader,
MidUrl, Identity, etc.) because each driver carries per-invocation
state — dry_run, output, errput. The rule throughout the gem:
stateless surface → module with extend self; state-bearing → class.
Defined Under Namespace
Classes: Error
Instance Attribute Summary collapse
- #dry_run ⇒ Object readonly
Instance Method Summary collapse
-
#applescript_escape(s, allow_controls: false) ⇒ Object
Escape a Ruby string for inclusion inside an AppleScript double-quoted string literal.
-
#build_perform_script(selector, args) ⇒ Object
Internal — build the
tell application "MailMate" to perform { ... }script with proper quoting. -
#close_windows(ids) ⇒ Object
Close every window in
ids. -
#initialize(dry_run: false, output: $stdout, errput: $stderr) ⇒ AppleScriptDriver
constructor
A new instance of AppleScriptDriver.
-
#open_url(url) ⇒ Object
Open a URL in MailMate (used for
mid:URLs to select a message). -
#perform(selector, *args) ⇒ Object
Drive a MailMate selector against the current selection.
-
#window_ids ⇒ Object
Return the array of MailMate's current window IDs (integers).
Constructor Details
#initialize(dry_run: false, output: $stdout, errput: $stderr) ⇒ AppleScriptDriver
Returns a new instance of AppleScriptDriver.
19 20 21 22 23 |
# File 'lib/mailmate/applescript_driver.rb', line 19 def initialize(dry_run: false, output: $stdout, errput: $stderr) @dry_run = dry_run @output = output @errput = errput end |
Instance Attribute Details
#dry_run ⇒ Object (readonly)
17 18 19 |
# File 'lib/mailmate/applescript_driver.rb', line 17 def dry_run @dry_run end |
Instance Method Details
#applescript_escape(s, allow_controls: false) ⇒ Object
Escape a Ruby string for inclusion inside an AppleScript double-quoted
string literal. Order matters: backslash first, then quote. Newlines/
tabs are rejected unless allow_controls: true.
90 91 92 93 94 95 |
# File 'lib/mailmate/applescript_driver.rb', line 90 def applescript_escape(s, allow_controls: false) if !allow_controls && s.match?(/[\r\n\t]/) raise Error, "AppleScript arg contains control character (\\r/\\n/\\t): #{s.inspect}" end s.gsub("\\", "\\\\\\\\").gsub('"', '\\"') end |
#build_perform_script(selector, args) ⇒ Object
Internal — build the tell application "MailMate" to perform { ... }
script with proper quoting. AppleScript string literals require:
\ → \\ (single backslash becomes \\, otherwise it interprets
\b / \n / \t / etc. as control-character escapes)
" → \" (terminates the string otherwise)
Newlines and tabs in args are rejected — they have no defensible meaning inside an AppleScript single-line script and almost certainly indicate data the caller doesn't want injected.
77 78 79 80 81 82 83 84 85 |
# File 'lib/mailmate/applescript_driver.rb', line 77 def build_perform_script(selector, args) escaped_selector = applescript_escape(selector.to_s, allow_controls: false) if args.empty? %(tell application "MailMate" to perform {"#{escaped_selector}"}) else list = args.map { |a| %("#{applescript_escape(a.to_s)}") }.join(", ") %(tell application "MailMate" to perform {"#{escaped_selector}", #{list}}) end end |
#close_windows(ids) ⇒ Object
Close every window in ids. No-op for IDs that no longer exist.
62 63 64 65 66 67 |
# File 'lib/mailmate/applescript_driver.rb', line 62 def close_windows(ids) return if dry_run Array(ids).each do |id| `osascript -e 'tell application "MailMate" to close window id #{id}' >/dev/null 2>&1` end end |
#open_url(url) ⇒ Object
Open a URL in MailMate (used for mid: URLs to select a message).
Uses open -g -a MailMate so the URL is dispatched to MailMate's URL
handler without bringing MailMate to the foreground — keeping the
user's keyboard focus where it was. The viewer window is still spawned
for mid: URLs. The AppleScript-native alternative
(tell application "MailMate" to open location) was tried but is
synchronous and can hang on mid: URLs while MailMate processes the
spawn — open -g is asynchronous and avoids the wait.
42 43 44 45 46 47 48 49 50 |
# File 'lib/mailmate/applescript_driver.rb', line 42 def open_url(url) Mailmate::PlatformError.check_darwin!(component: "AppleScriptDriver") unless dry_run if dry_run @output.puts "DRY: open -g -a MailMate #{url.inspect}" return end success = system("/usr/bin/open", "-g", "-a", "MailMate", url) raise Error, "open command failed for #{url}" unless success end |
#perform(selector, *args) ⇒ Object
Drive a MailMate selector against the current selection.
selector is the key-binding selector name ("markAsRead:",
"setTag:", etc.). args are positional arguments passed alongside.
28 29 30 31 32 |
# File 'lib/mailmate/applescript_driver.rb', line 28 def perform(selector, *args) Mailmate::PlatformError.check_darwin!(component: "AppleScriptDriver") unless dry_run script = build_perform_script(selector, args) run_apple_script(script) end |
#window_ids ⇒ Object
Return the array of MailMate's current window IDs (integers). Empty
array if MailMate isn't running or osascript errors.
54 55 56 57 58 59 |
# File 'lib/mailmate/applescript_driver.rb', line 54 def window_ids return [] if dry_run out = `osascript -e 'tell application "MailMate" to get id of every window' 2>&1` return [] unless $?.success? out.strip.split(",").map { |s| s.strip.to_i } end |