osaka 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README +0 -0
- data/Rakefile +6 -0
- data/lib/osaka/applicationwrapper.rb +112 -0
- data/lib/osaka/keynote.rb +18 -0
- data/lib/osaka/numbers.rb +13 -0
- data/lib/osaka/pages.rb +38 -0
- data/lib/osaka/scriptrunner.rb +38 -0
- data/lib/osaka/typicalapplication.rb +91 -0
- data/lib/osaka/version.rb +4 -0
- data/lib/osaka.rb +7 -0
- data/osaka.gemfile +20 -0
- data/spec/applicationwrapper_spec.rb +144 -0
- data/spec/keynote_spec.rb +11 -0
- data/spec/numbers_spec.rb +17 -0
- data/spec/pages_spec.rb +37 -0
- data/spec/scriptrunner_spec.rb +50 -0
- data/spec/typicalapplication_spec.rb +95 -0
- metadata +93 -0
data/README
ADDED
File without changes
|
data/Rakefile
ADDED
@@ -0,0 +1,112 @@
|
|
1
|
+
|
2
|
+
module Osaka
|
3
|
+
|
4
|
+
class ApplicationWrapper
|
5
|
+
|
6
|
+
def initialize(name)
|
7
|
+
@name = name
|
8
|
+
end
|
9
|
+
|
10
|
+
def activate
|
11
|
+
tell("activate")
|
12
|
+
end
|
13
|
+
|
14
|
+
def quit
|
15
|
+
tell("quit")
|
16
|
+
end
|
17
|
+
|
18
|
+
def tell(command)
|
19
|
+
ScriptRunner::execute("tell application \"#{@name}\"; #{command}; end tell")
|
20
|
+
end
|
21
|
+
|
22
|
+
def system_event!(event)
|
23
|
+
ScriptRunner::execute("tell application \"System Events\"; tell process \"#{@name}\"; #{event}; end tell; end tell")
|
24
|
+
end
|
25
|
+
|
26
|
+
def system_event(event)
|
27
|
+
activate
|
28
|
+
system_event!(event)
|
29
|
+
end
|
30
|
+
|
31
|
+
def wait_until_exists!(element_to_wait_for)
|
32
|
+
system_event!("repeat until exists #{element_to_wait_for}; end repeat")
|
33
|
+
end
|
34
|
+
|
35
|
+
def wait_until_exists(element_to_wait_for)
|
36
|
+
activate
|
37
|
+
wait_until_exists!(element_to_wait_for)
|
38
|
+
end
|
39
|
+
|
40
|
+
def wait_until_not_exists!(element_to_wait_for)
|
41
|
+
system_event!("repeat until not exists #{element_to_wait_for}; end repeat")
|
42
|
+
end
|
43
|
+
|
44
|
+
def wait_until_not_exists(element_to_wait_for)
|
45
|
+
activate
|
46
|
+
wait_until_not_exists!(element_to_wait_for)
|
47
|
+
end
|
48
|
+
|
49
|
+
def construct_modifier_statement(modifier_keys)
|
50
|
+
modified_key_string = [ modifier_keys ].flatten.collect! { |mod_key| mod_key.to_s + " down"}.join(", ")
|
51
|
+
modifier_command = " using {#{modified_key_string}}" unless modifier_keys.empty?
|
52
|
+
modifier_command
|
53
|
+
end
|
54
|
+
|
55
|
+
def keystroke!(key, modifier_keys = [])
|
56
|
+
system_event!("keystroke \"#{key}\"#{construct_modifier_statement(modifier_keys)}")
|
57
|
+
end
|
58
|
+
|
59
|
+
def keystroke(key, modifier_keys = [])
|
60
|
+
activate
|
61
|
+
keystroke!(key, modifier_keys)
|
62
|
+
end
|
63
|
+
|
64
|
+
def keystroke_and_wait_until_exists!(key, modifier_keys, element)
|
65
|
+
keystroke!(key, modifier_keys)
|
66
|
+
wait_until_exists!(element)
|
67
|
+
end
|
68
|
+
|
69
|
+
def keystroke_and_wait_until_exists(key, modifier_keys, element)
|
70
|
+
activate
|
71
|
+
keystroke_and_wait_until_exists!(key, modifier_keys, element)
|
72
|
+
end
|
73
|
+
|
74
|
+
def click!(element)
|
75
|
+
system_event!("click #{element}")
|
76
|
+
end
|
77
|
+
|
78
|
+
def click(element)
|
79
|
+
activate
|
80
|
+
click!(element)
|
81
|
+
end
|
82
|
+
|
83
|
+
def click_and_wait_until_exists!(element, wait_condition)
|
84
|
+
click!(element)
|
85
|
+
wait_until_exists!(wait_condition)
|
86
|
+
end
|
87
|
+
|
88
|
+
def click_and_wait_until_exists(element, wait_condition)
|
89
|
+
activate
|
90
|
+
click_and_wait_until_exists!(element, wait_condition)
|
91
|
+
end
|
92
|
+
|
93
|
+
def click_and_wait_until_not_exists!(element, wait_condition)
|
94
|
+
click!(element)
|
95
|
+
wait_until_not_exists!(wait_condition)
|
96
|
+
end
|
97
|
+
|
98
|
+
def click_and_wait_until_not_exists(element, wait_condition)
|
99
|
+
activate
|
100
|
+
click_and_wait_until_not_exists!(element, wait_condition)
|
101
|
+
end
|
102
|
+
|
103
|
+
def set!(element, value)
|
104
|
+
system_event!("set #{element} to \"#{value}\"")
|
105
|
+
end
|
106
|
+
|
107
|
+
def set(element, value)
|
108
|
+
activate
|
109
|
+
set!(element, value)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
|
2
|
+
module Osaka
|
3
|
+
|
4
|
+
class KeynotePrintDialog < TypicalPrintDialog
|
5
|
+
|
6
|
+
end
|
7
|
+
|
8
|
+
class Keynote < TypicalApplication
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
super "Keynote"
|
12
|
+
end
|
13
|
+
|
14
|
+
def create_print_dialog(location)
|
15
|
+
KeynotePrintDialog.new(location, app)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
|
2
|
+
module Osaka
|
3
|
+
class Numbers < TypicalApplication
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
super "Numbers"
|
7
|
+
end
|
8
|
+
|
9
|
+
def fill_cell(row, column, value)
|
10
|
+
@wrapper.tell("tell document 1; tell sheet 1; tell table 1; set value of cell #{column} of row #{row} to \"#{value}\"; end tell; end tell; end tell")
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
data/lib/osaka/pages.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
|
2
|
+
module Osaka
|
3
|
+
class PagesMailMergeDialog
|
4
|
+
attr_accessor :wrapper
|
5
|
+
|
6
|
+
def initialize(wrapper)
|
7
|
+
@wrapper = wrapper
|
8
|
+
end
|
9
|
+
|
10
|
+
def merge
|
11
|
+
@wrapper.click!('button "Merge" of sheet 1 of window 1')
|
12
|
+
print_dialog_location = 'window "Print"'
|
13
|
+
@wrapper.wait_until_exists!("menu button \"PDF\" of #{print_dialog_location}")
|
14
|
+
TypicalPrintDialog.new(print_dialog_location, @wrapper)
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
class Pages < TypicalApplication
|
20
|
+
|
21
|
+
def initialize
|
22
|
+
super "Pages"
|
23
|
+
end
|
24
|
+
|
25
|
+
def mail_merge
|
26
|
+
@wrapper.systemEvent("tell menu bar 1; tell menu \"Edit\"; click menu item 20; end tell; end tell")
|
27
|
+
@wrapper.wait_until_exists('button "Merge" of sheet 1 of window 1')
|
28
|
+
PagesMailMergeDialog.new(@wrapper)
|
29
|
+
end
|
30
|
+
|
31
|
+
def mail_merge_to_pdf(filename)
|
32
|
+
mail_merge_dialog = mail_merge
|
33
|
+
print_dialog = mail_merge_dialog.merge
|
34
|
+
print_dialog.save_as_pdf(filename)
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
|
2
|
+
module Osaka
|
3
|
+
|
4
|
+
class ScriptRunnerError < RuntimeError
|
5
|
+
end
|
6
|
+
|
7
|
+
module ScriptRunner
|
8
|
+
|
9
|
+
@@debug_info_enabled = false
|
10
|
+
|
11
|
+
def self.enabled_debug_prints
|
12
|
+
@@debug_info_enabled = true
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.disable_debug_prints
|
16
|
+
@@debug_info_enabled = false
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.debug_prints?
|
20
|
+
@@debug_info_enabled
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.execute(applescript)
|
24
|
+
script_commands = applescript.gsub('"', '\\"').split(';')
|
25
|
+
escaped_commands = ""
|
26
|
+
script_commands.each { |l|
|
27
|
+
escaped_commands += " -e \"#{l.strip}\""
|
28
|
+
}
|
29
|
+
puts "Executing: osascript#{escaped_commands}" if debug_prints?
|
30
|
+
|
31
|
+
raise(Osaka::ScriptRunnerError, "Error received while executing: #{applescript}") unless system("osascript#{escaped_commands}")
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.execute_file(scriptName, parameters = "")
|
35
|
+
system("osascript #{scriptName} #{parameters}".strip)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
|
2
|
+
module Osaka
|
3
|
+
|
4
|
+
class TypicalSaveDialog
|
5
|
+
attr_accessor :wrapper
|
6
|
+
|
7
|
+
def initialize(location, wrapper)
|
8
|
+
@location = location
|
9
|
+
@wrapper = wrapper
|
10
|
+
end
|
11
|
+
|
12
|
+
def set_filename(filename)
|
13
|
+
@wrapper.set("value of text field 1 of #{@location}", filename)
|
14
|
+
end
|
15
|
+
|
16
|
+
def set_folder(pathname)
|
17
|
+
@wrapper.keystroke_and_wait_until_exists("g", [ :command, :shift ], "sheet 1 of #{@location}")
|
18
|
+
@wrapper.set("value of text field 1 of sheet 1 of #{@location}", pathname)
|
19
|
+
@wrapper.click_and_wait_until_not_exists("button \"Go\" of sheet 1 of #{@location}", "sheet 1 of #{@location}")
|
20
|
+
end
|
21
|
+
|
22
|
+
def click_save
|
23
|
+
@wrapper.click_and_wait_until_not_exists("button \"Save\" of #{@location}", "#{@location}")
|
24
|
+
end
|
25
|
+
|
26
|
+
def save(filename)
|
27
|
+
set_filename(File.basename(filename))
|
28
|
+
set_folder(File.dirname(filename)) unless File.dirname(filename) == "."
|
29
|
+
click_save
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
class TypicalPrintDialog
|
35
|
+
attr_accessor :wrapper
|
36
|
+
|
37
|
+
def initialize(location, wrapper)
|
38
|
+
@location = location
|
39
|
+
@wrapper = wrapper
|
40
|
+
end
|
41
|
+
|
42
|
+
def create_save_dialog(location, app)
|
43
|
+
GenericSaveDialog.new(location, app)
|
44
|
+
end
|
45
|
+
|
46
|
+
def save_as_pdf(filename)
|
47
|
+
@wrapper.click_and_wait_until_exists!("menu button \"PDF\" of #{@location}", "menu 1 of menu button \"PDF\" of #{@location}")
|
48
|
+
@wrapper.click_and_wait_until_exists!("menu item 2 of menu 1 of menu button \"PDF\" of #{@location}", 'window "Save"')
|
49
|
+
save_dialog = create_save_dialog("window \"Save\"", @wrapper)
|
50
|
+
save_dialog.save(filename)
|
51
|
+
@wrapper.wait_until_not_exists(@location)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
class TypicalApplication
|
56
|
+
|
57
|
+
attr_accessor :wrapper
|
58
|
+
|
59
|
+
def initialize(name)
|
60
|
+
@wrapper = ApplicationWrapper.new(name)
|
61
|
+
end
|
62
|
+
|
63
|
+
def open (filename)
|
64
|
+
abolutePathFileName = File.absolute_path(filename)
|
65
|
+
@wrapper.tell("open \"#{abolutePathFileName}\"")
|
66
|
+
end
|
67
|
+
|
68
|
+
def quit
|
69
|
+
@wrapper.quit
|
70
|
+
end
|
71
|
+
|
72
|
+
def save
|
73
|
+
@wrapper.keystroke("s", :command)
|
74
|
+
end
|
75
|
+
|
76
|
+
def activate
|
77
|
+
@wrapper.activate
|
78
|
+
end
|
79
|
+
|
80
|
+
def create_print_dialog(location)
|
81
|
+
TypicalPrintDialog.new(location, @wrapper)
|
82
|
+
end
|
83
|
+
|
84
|
+
def print_dialog
|
85
|
+
location = "sheet 1 of window 1"
|
86
|
+
@wrapper.keystroke_and_wait_until_exists("p", :command, location)
|
87
|
+
create_print_dialog(location)
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
end
|
data/lib/osaka.rb
ADDED
data/osaka.gemfile
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require File.expand_path('../lib/osaka/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.name = 'osaka'
|
6
|
+
gem.version = Osaka::VERSION
|
7
|
+
gem.date = Date.today.to_s
|
8
|
+
|
9
|
+
gem.summary = "Osaka is an Mac GUI automation library"
|
10
|
+
gem.description = "Osaka wraps osascript (Applescript) and provides a ruby interface for automating tasks through the GUI on Mac"
|
11
|
+
|
12
|
+
gem.authors = ['Bas Vodde']
|
13
|
+
gem.email = 'basv@odd-e.com'
|
14
|
+
gem.homepage = 'https://github.com/basvodde/osaka'
|
15
|
+
|
16
|
+
gem.add_dependency('rake')
|
17
|
+
gem.add_development_dependency('rspec', [">= 2.0.0"])
|
18
|
+
|
19
|
+
gem.files = `git ls-files -- {.,test,spec,lib}/*`.split("\n")
|
20
|
+
end
|
@@ -0,0 +1,144 @@
|
|
1
|
+
|
2
|
+
require 'osaka'
|
3
|
+
|
4
|
+
describe "Osaka::ApplicationWrapper" do
|
5
|
+
|
6
|
+
name = "ApplicationName"
|
7
|
+
quoted_name = "\"#{name}\""
|
8
|
+
subject { Osaka::ApplicationWrapper.new(name) }
|
9
|
+
|
10
|
+
it "Should be able to tell applications to do something" do
|
11
|
+
Osaka::ScriptRunner.should_receive(:execute).with("tell application #{quoted_name}; command; end tell")
|
12
|
+
subject.tell("command")
|
13
|
+
end
|
14
|
+
|
15
|
+
it "Can also pass multi-line commands to telling an application what to do" do
|
16
|
+
Osaka::ScriptRunner.should_receive(:execute).with("tell application #{quoted_name}; activate; quit; end tell")
|
17
|
+
subject.tell("activate; quit")
|
18
|
+
end
|
19
|
+
|
20
|
+
it "Has a short-cut method for activation" do
|
21
|
+
Osaka::ScriptRunner.should_receive(:execute).with(/activate/)
|
22
|
+
subject.activate
|
23
|
+
end
|
24
|
+
|
25
|
+
it "Has a short-cut method for quitting" do
|
26
|
+
Osaka::ScriptRunner.should_receive(:execute).with(/quit/)
|
27
|
+
subject.quit
|
28
|
+
end
|
29
|
+
|
30
|
+
it "Should be able to generate events via the Systems Events" do
|
31
|
+
Osaka::ScriptRunner.should_receive(:execute).with(/tell application "System Events"; tell process #{quoted_name}; quit; end tell; end tell/)
|
32
|
+
subject.system_event!("quit")
|
33
|
+
end
|
34
|
+
|
35
|
+
it "Should be able to generate events via the Systems Events and activate the application first" do
|
36
|
+
subject.should_receive(:activate)
|
37
|
+
subject.should_receive(:system_event!).with("quit")
|
38
|
+
subject.system_event("quit")
|
39
|
+
end
|
40
|
+
|
41
|
+
it "Should be able to wait for for a specific element existing" do
|
42
|
+
Osaka::ScriptRunner.should_receive(:execute).with(/repeat until exists window 1; end repeat/)
|
43
|
+
subject.wait_until_exists!("window 1")
|
44
|
+
end
|
45
|
+
|
46
|
+
it "Should be able to wait until exists and activate the application first" do
|
47
|
+
subject.should_receive(:activate)
|
48
|
+
subject.should_receive(:wait_until_exists!).with("window 1")
|
49
|
+
subject.wait_until_exists("window 1")
|
50
|
+
end
|
51
|
+
|
52
|
+
it "Should be able to wait for a specific element to not exist anymore" do
|
53
|
+
Osaka::ScriptRunner.should_receive(:execute).with(/repeat until not exists window 1; end repeat/)
|
54
|
+
subject.wait_until_not_exists!("window 1")
|
55
|
+
end
|
56
|
+
|
57
|
+
it "Should be able to wait_until_not_exists and activate" do
|
58
|
+
subject.should_receive(:activate)
|
59
|
+
subject.should_receive(:wait_until_not_exists!).with("window 1")
|
60
|
+
subject.wait_until_not_exists("window 1")
|
61
|
+
end
|
62
|
+
|
63
|
+
it "Should be able to generate keystroke events" do
|
64
|
+
Osaka::ScriptRunner.should_receive(:execute).with(/keystroke "p"/)
|
65
|
+
subject.keystroke!("p")
|
66
|
+
end
|
67
|
+
|
68
|
+
it "Should be able to keystroke and activate" do
|
69
|
+
subject.should_receive(:activate)
|
70
|
+
subject.should_receive(:keystroke!).with("a", [])
|
71
|
+
subject.keystroke("a", [])
|
72
|
+
end
|
73
|
+
|
74
|
+
it "Should be able to do keystrokes with command down" do
|
75
|
+
Osaka::ScriptRunner.should_receive(:execute).with(/keystroke "p" using {command down}/)
|
76
|
+
subject.keystroke!("p", :command)
|
77
|
+
end
|
78
|
+
|
79
|
+
it "Should be able to do keystrokes with option and command down" do
|
80
|
+
Osaka::ScriptRunner.should_receive(:execute).with(/keystroke "p" using {option down, command down}/)
|
81
|
+
subject.keystroke!("p", [ :option, :command ])
|
82
|
+
end
|
83
|
+
|
84
|
+
it "Should be able to do a keystroke and wait until something happen in one easy command" do
|
85
|
+
subject.should_receive(:keystroke!).with("p", [])
|
86
|
+
subject.should_receive(:wait_until_exists!).with("window 1")
|
87
|
+
subject.keystroke_and_wait_until_exists!("p", [], "window 1")
|
88
|
+
end
|
89
|
+
|
90
|
+
it "Should be able to keystroke_and_wait_until_exists and activate" do
|
91
|
+
subject.should_receive(:activate)
|
92
|
+
subject.should_receive(:keystroke_and_wait_until_exists!).with("p", [], "window 1")
|
93
|
+
subject.keystroke_and_wait_until_exists("p", [], "window 1")
|
94
|
+
end
|
95
|
+
|
96
|
+
it "Should be able to do clicks" do
|
97
|
+
Osaka::ScriptRunner.should_receive(:execute).with(/click menu button "PDF"/)
|
98
|
+
subject.click!('menu button "PDF"')
|
99
|
+
end
|
100
|
+
|
101
|
+
it "Should be able to do click and activate" do
|
102
|
+
subject.should_receive(:activate)
|
103
|
+
subject.should_receive(:click!).with("button")
|
104
|
+
subject.click("button")
|
105
|
+
end
|
106
|
+
|
107
|
+
it "Should be able to do clicks and wait until something happened in one easy command" do
|
108
|
+
subject.should_receive(:click!).with("button")
|
109
|
+
subject.should_receive(:wait_until_exists!).with("window")
|
110
|
+
subject.click_and_wait_until_exists!("button", "window")
|
111
|
+
end
|
112
|
+
|
113
|
+
it "Should be able to click_and_wait_until_exists and activate" do
|
114
|
+
subject.should_receive(:activate)
|
115
|
+
subject.should_receive(:click_and_wait_until_exists!).with("button", "window")
|
116
|
+
subject.click_and_wait_until_exists("button", "window")
|
117
|
+
end
|
118
|
+
|
119
|
+
it "Should be able to click and wait until something doesn't exist anymore" do
|
120
|
+
subject.should_receive(:click!).with("button1")
|
121
|
+
subject.should_receive(:wait_until_not_exists!).with("window 1")
|
122
|
+
subject.click_and_wait_until_not_exists!('button1', 'window 1')
|
123
|
+
end
|
124
|
+
|
125
|
+
it "Should be able to click_and_wait_until_not_exists and activate" do
|
126
|
+
subject.should_receive(:activate)
|
127
|
+
subject.should_receive(:click_and_wait_until_not_exists!).with("button", "window")
|
128
|
+
subject.click_and_wait_until_not_exists('button', 'window')
|
129
|
+
end
|
130
|
+
|
131
|
+
it "Should be able to set a value to an element" do
|
132
|
+
subject.should_receive(:system_event!).with(/set value of window to "newvalue"/)
|
133
|
+
subject.set!("value of window", "newvalue")
|
134
|
+
end
|
135
|
+
|
136
|
+
it "Should be able to set a value and activate" do
|
137
|
+
subject.should_receive(:activate)
|
138
|
+
subject.should_receive(:set!).with("value of window", "newvalue")
|
139
|
+
subject.set("value of window", "newvalue")
|
140
|
+
end
|
141
|
+
|
142
|
+
|
143
|
+
|
144
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
|
2
|
+
require 'osaka'
|
3
|
+
|
4
|
+
describe "Osaka::Numbers" do
|
5
|
+
|
6
|
+
subject { Osaka::Numbers.new }
|
7
|
+
|
8
|
+
before (:each) do
|
9
|
+
subject.wrapper = double("Osaka::Number").as_null_object
|
10
|
+
end
|
11
|
+
|
12
|
+
it "Should be able to fill in data in cells" do
|
13
|
+
subject.wrapper.should_receive(:tell).with('tell document 1; tell sheet 1; tell table 1; set value of cell 2 of row 1 to "30"; end tell; end tell; end tell')
|
14
|
+
subject.fill_cell(1, 2, "30")
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
data/spec/pages_spec.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
|
2
|
+
require 'osaka'
|
3
|
+
|
4
|
+
describe "Osaka::Pages" do
|
5
|
+
|
6
|
+
subject { Osaka::Pages.new }
|
7
|
+
|
8
|
+
before (:each) do
|
9
|
+
subject.wrapper = double("Osaka::ApplicationWrapper").as_null_object
|
10
|
+
end
|
11
|
+
|
12
|
+
it "Should be able to do mail merge to a PDF flow" do
|
13
|
+
|
14
|
+
mail_merge_dialog = double(:PagesMailMergeDialog)
|
15
|
+
print_dialog = double(:GenericPrintDialog)
|
16
|
+
|
17
|
+
subject.should_receive(:mail_merge).and_return(mail_merge_dialog)
|
18
|
+
mail_merge_dialog.should_receive(:merge).and_return(print_dialog)
|
19
|
+
print_dialog.should_receive(:save_as_pdf).with("filename")
|
20
|
+
|
21
|
+
subject.mail_merge_to_pdf("filename")
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
it "Should be able to select the Mail Merge" do
|
26
|
+
subject.wrapper.should_receive(:systemEvent).with("tell menu bar 1; tell menu \"Edit\"; click menu item 20; end tell; end tell")
|
27
|
+
subject.wrapper.should_receive(:wait_until_exists).with('button "Merge" of sheet 1 of window 1')
|
28
|
+
subject.mail_merge
|
29
|
+
end
|
30
|
+
|
31
|
+
it "Should click the merge button of the mail merge dialog" do
|
32
|
+
subject.wrapper.should_receive(:click!).with('button "Merge" of sheet 1 of window 1')
|
33
|
+
subject.wrapper.should_receive(:wait_until_exists!).with('menu button "PDF" of window "Print"')
|
34
|
+
subject.mail_merge.merge
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'osaka'
|
2
|
+
|
3
|
+
describe "Osaka::ScriptRunner" do
|
4
|
+
|
5
|
+
subject { Osaka::ScriptRunner }
|
6
|
+
|
7
|
+
it "Should be able to run single-line text as osascript" do
|
8
|
+
subject.should_receive(:system).with('osascript -e "random number"').and_return(true)
|
9
|
+
subject.execute("random number")
|
10
|
+
end
|
11
|
+
|
12
|
+
it "Should escape quotes when passing text" do
|
13
|
+
subject.should_receive(:system).with('osascript -e "say \\"hello\\""').and_return(true)
|
14
|
+
subject.execute('say "hello"')
|
15
|
+
end
|
16
|
+
|
17
|
+
it "Should be able to run on debug printing" do
|
18
|
+
subject.should_receive(:system).and_return(true)
|
19
|
+
subject.should_receive(:puts).with('Executing: osascript -e "random number"')
|
20
|
+
Osaka::ScriptRunner::enabled_debug_prints
|
21
|
+
subject.execute("random number")
|
22
|
+
Osaka::ScriptRunner::disable_debug_prints
|
23
|
+
end
|
24
|
+
|
25
|
+
it "Should not print any debugging information by default " do
|
26
|
+
subject.should_receive(:system).and_return(true)
|
27
|
+
subject.should_not_receive(:puts)
|
28
|
+
subject.execute("random number")
|
29
|
+
end
|
30
|
+
|
31
|
+
it "Should be able to define multi-line statements using ; as a separator" do
|
32
|
+
subject.should_receive(:system).with('osascript -e "tell application \\"Calculator\\"" -e "activate" -e "end tell"').and_return(true)
|
33
|
+
subject.execute('tell application "Calculator"; activate; end tell')
|
34
|
+
end
|
35
|
+
|
36
|
+
it "Should raise an exception witha proper error message when the applescript fails" do
|
37
|
+
subject.should_receive(:system).and_return(false)
|
38
|
+
lambda {subject.execute("Fuck off!")}.should raise_error(Osaka::ScriptRunnerError, "Error received while executing: Fuck off!")
|
39
|
+
end
|
40
|
+
|
41
|
+
it "Should be able to execute an file containing applescript" do
|
42
|
+
subject.should_receive(:system).with('osascript script.scpt').and_return(true)
|
43
|
+
subject.execute_file("script.scpt")
|
44
|
+
end
|
45
|
+
|
46
|
+
it "Should be able to pass parameters to an applescript" do
|
47
|
+
subject.should_receive(:system).with('osascript script.scpt a b c').and_return(true)
|
48
|
+
subject.execute_file("script.scpt", "a b c")
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
|
2
|
+
require 'osaka'
|
3
|
+
|
4
|
+
describe "Osaka::TypicalApplication" do
|
5
|
+
|
6
|
+
subject { Osaka::TypicalApplication.new("ApplicationName") }
|
7
|
+
|
8
|
+
before (:each) do
|
9
|
+
subject.wrapper = double("Osaka::ApplicationWrapper").as_null_object
|
10
|
+
end
|
11
|
+
|
12
|
+
it "Should pass the right open string to the Keynote application osascript" do
|
13
|
+
filename = "filename.key"
|
14
|
+
subject.wrapper.should_receive(:tell).with("open \"#{File.absolute_path(filename)}\"")
|
15
|
+
subject.open(filename)
|
16
|
+
end
|
17
|
+
|
18
|
+
it "Should be able to quit" do
|
19
|
+
subject.wrapper.should_receive(:quit)
|
20
|
+
subject.quit
|
21
|
+
end
|
22
|
+
|
23
|
+
it "Should be able to save" do
|
24
|
+
subject.wrapper.should_receive(:keystroke).with("s", :command)
|
25
|
+
subject.save
|
26
|
+
end
|
27
|
+
|
28
|
+
it "Should be able to activate keynote" do
|
29
|
+
subject.wrapper.should_receive(:activate)
|
30
|
+
subject.activate
|
31
|
+
end
|
32
|
+
|
33
|
+
it "Should be able to retrieve a print dialog" do
|
34
|
+
subject.wrapper.should_receive(:keystroke_and_wait_until_exists).with("p", :command, "sheet 1 of window 1")
|
35
|
+
subject.print_dialog
|
36
|
+
end
|
37
|
+
|
38
|
+
describe "Generic Print Dialog" do
|
39
|
+
|
40
|
+
location = "window 1"
|
41
|
+
subject { Osaka::TypicalPrintDialog.new("window 1", double(:OSAApp).as_null_object) }
|
42
|
+
|
43
|
+
it "Should be able to save the PDF in a print dialog" do
|
44
|
+
save_dialog_mock = double(:GenericSaveDialog)
|
45
|
+
subject.wrapper.should_receive(:click_and_wait_until_exists!).with('menu button "PDF" of window 1', 'menu 1 of menu button "PDF" of window 1')
|
46
|
+
subject.wrapper.should_receive(:click_and_wait_until_exists!).with('menu item 2 of menu 1 of menu button "PDF" of window 1', 'window "Save"')
|
47
|
+
subject.should_receive(:create_save_dialog).with("window \"Save\"", subject.wrapper).and_return(save_dialog_mock)
|
48
|
+
save_dialog_mock.should_receive(:save).with("filename")
|
49
|
+
subject.wrapper.should_receive(:wait_until_not_exists).with('window 1')
|
50
|
+
subject.save_as_pdf("filename")
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe "Generic Save Dialog" do
|
55
|
+
|
56
|
+
subject { Osaka::TypicalSaveDialog.new("window 1", double("Osaka::ApplicationWrapper").as_null_object)}
|
57
|
+
|
58
|
+
it "Should set the filename in the test field" do
|
59
|
+
subject.should_receive(:set_filename).with("filename")
|
60
|
+
subject.should_receive(:click_save)
|
61
|
+
subject.should_not_receive(:set_folder)
|
62
|
+
subject.save("filename")
|
63
|
+
end
|
64
|
+
|
65
|
+
it "Should pick only the base filename when a path is given" do
|
66
|
+
subject.should_receive(:set_filename).with("filename")
|
67
|
+
subject.should_receive(:set_folder)
|
68
|
+
subject.should_receive(:click_save)
|
69
|
+
subject.save("/path/filename")
|
70
|
+
end
|
71
|
+
|
72
|
+
it "Should set the path when a full path is given" do
|
73
|
+
subject.should_receive(:set_filename)
|
74
|
+
subject.should_receive(:set_folder).with("/path/second")
|
75
|
+
subject.save("/path/second/name")
|
76
|
+
end
|
77
|
+
|
78
|
+
it "Should be able to click save" do
|
79
|
+
subject.wrapper.should_receive(:click_and_wait_until_not_exists).with('button "Save" of window 1', 'window 1')
|
80
|
+
subject.click_save
|
81
|
+
end
|
82
|
+
|
83
|
+
it "Should be able to set the filename" do
|
84
|
+
subject.wrapper.should_receive(:set).with('value of text field 1 of window 1', "filename")
|
85
|
+
subject.set_filename("filename")
|
86
|
+
end
|
87
|
+
|
88
|
+
it "Should be able to set the path" do
|
89
|
+
subject.wrapper.should_receive(:keystroke_and_wait_until_exists).with("g", [ :command, :shift ], "sheet 1 of window 1")
|
90
|
+
subject.wrapper.should_receive(:set).with("value of text field 1 of sheet 1 of window 1", "path")
|
91
|
+
subject.wrapper.should_receive(:click_and_wait_until_not_exists).with('button "Go" of sheet 1 of window 1', "sheet 1 of window 1")
|
92
|
+
subject.set_folder("path")
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
metadata
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: osaka
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 0.1.0
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Bas Vodde
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2012-02-10 00:00:00 +08:00
|
14
|
+
default_executable:
|
15
|
+
dependencies:
|
16
|
+
- !ruby/object:Gem::Dependency
|
17
|
+
name: rake
|
18
|
+
prerelease: false
|
19
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
20
|
+
none: false
|
21
|
+
requirements:
|
22
|
+
- - ">="
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: "0"
|
25
|
+
type: :runtime
|
26
|
+
version_requirements: *id001
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rspec
|
29
|
+
prerelease: false
|
30
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
31
|
+
none: false
|
32
|
+
requirements:
|
33
|
+
- - ">="
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: 2.0.0
|
36
|
+
type: :development
|
37
|
+
version_requirements: *id002
|
38
|
+
description: Osaka wraps osascript (Applescript) and provides a ruby interface for automating tasks through the GUI on Mac
|
39
|
+
email: basv@odd-e.com
|
40
|
+
executables: []
|
41
|
+
|
42
|
+
extensions: []
|
43
|
+
|
44
|
+
extra_rdoc_files: []
|
45
|
+
|
46
|
+
files:
|
47
|
+
- README
|
48
|
+
- Rakefile
|
49
|
+
- lib/osaka.rb
|
50
|
+
- lib/osaka/applicationwrapper.rb
|
51
|
+
- lib/osaka/keynote.rb
|
52
|
+
- lib/osaka/numbers.rb
|
53
|
+
- lib/osaka/pages.rb
|
54
|
+
- lib/osaka/scriptrunner.rb
|
55
|
+
- lib/osaka/typicalapplication.rb
|
56
|
+
- lib/osaka/version.rb
|
57
|
+
- osaka.gemfile
|
58
|
+
- spec/applicationwrapper_spec.rb
|
59
|
+
- spec/keynote_spec.rb
|
60
|
+
- spec/numbers_spec.rb
|
61
|
+
- spec/pages_spec.rb
|
62
|
+
- spec/scriptrunner_spec.rb
|
63
|
+
- spec/typicalapplication_spec.rb
|
64
|
+
has_rdoc: true
|
65
|
+
homepage: https://github.com/basvodde/osaka
|
66
|
+
licenses: []
|
67
|
+
|
68
|
+
post_install_message:
|
69
|
+
rdoc_options: []
|
70
|
+
|
71
|
+
require_paths:
|
72
|
+
- lib
|
73
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
74
|
+
none: false
|
75
|
+
requirements:
|
76
|
+
- - ">="
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: "0"
|
79
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
80
|
+
none: false
|
81
|
+
requirements:
|
82
|
+
- - ">="
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
version: "0"
|
85
|
+
requirements: []
|
86
|
+
|
87
|
+
rubyforge_project:
|
88
|
+
rubygems_version: 1.6.2
|
89
|
+
signing_key:
|
90
|
+
specification_version: 3
|
91
|
+
summary: Osaka is an Mac GUI automation library
|
92
|
+
test_files: []
|
93
|
+
|