experiment 0.0.1 → 0.2.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/Manifest.txt +5 -1
- data/README.rdoc +12 -3
- data/Rakefile +1 -1
- data/bin/experiment +62 -186
- data/bin/growl.sh +241 -0
- data/lib/experiment.rb +1 -1
- data/lib/experiment/base.rb +51 -13
- data/lib/experiment/config.rb +32 -3
- data/lib/experiment/distributed.rb +67 -0
- data/lib/experiment/notify.rb +177 -3
- data/lib/experiment/runner.rb +208 -0
- data/lib/experiment/work_server.rb +58 -0
- data/test/test_base.rb +5 -0
- data/test/test_config.rb +11 -0
- data/test/test_experiment.rb +1 -1
- data/test/test_stats.rb +34 -0
- metadata +14 -3
data/Manifest.txt
CHANGED
@@ -5,11 +5,15 @@ Rakefile
|
|
5
5
|
lib/experiment.rb
|
6
6
|
lib/experiment/config.rb
|
7
7
|
lib/experiment/stats.rb
|
8
|
+
lib/experiment/runner.rb
|
8
9
|
lib/experiment/generator/readme_template.txt
|
9
10
|
lib/experiment/generator/experiment_template.rb
|
10
11
|
lib/experiment/generator/Rakefile
|
11
12
|
lib/experiment/base.rb
|
12
13
|
lib/experiment/notify.rb
|
14
|
+
lib/experiment/work_server.rb
|
15
|
+
lib/experiment/distributed.rb
|
13
16
|
test/test_experiment.rb
|
14
17
|
test/test_helper.rb
|
15
|
-
bin/experiment
|
18
|
+
bin/experiment
|
19
|
+
bin/growl.sh
|
data/README.rdoc
CHANGED
@@ -27,7 +27,7 @@ Experiments are set up in the experiments directory. The first thing you need to
|
|
27
27
|
|
28
28
|
For a typical experiment you will need to do some setup work (eg. initialize your classes, calculate parametres, etc.), run the experiment and maybe do cleanup (remove temp. files).
|
29
29
|
|
30
|
-
You do all this work in the `run_the_experiment` method.
|
30
|
+
You do all this work in the `run_the_experiment` method. Use the `measure` method to wrap your measurements. These will be autmatically benchmarked and their ouput will be automatically saved to the results directory for further analysis.
|
31
31
|
|
32
32
|
The `test_data` method lets you specify an array of data points that you want split for cross-validation (see below). This will be passed to in `run_the_experiment` in the input variable.
|
33
33
|
|
@@ -102,7 +102,7 @@ Then your final config will look like this:
|
|
102
102
|
:master_dir => "/Users/kubowo/Desktop/points-vals/s015",
|
103
103
|
:alpha => 0.6 }
|
104
104
|
|
105
|
-
Flexible, eh?
|
105
|
+
Flexible, eh? **NEW** Check out the *get* method. It has features like interpolation and defaults.
|
106
106
|
|
107
107
|
== Cross Validation
|
108
108
|
|
@@ -116,8 +116,17 @@ Surprise, surprise. This will create two files in your `report` directory (BTW,
|
|
116
116
|
|
117
117
|
The second file created is the `data.csv` file which contains the data from all your experiments. It should be importable to Numbers, Excel even Matlab for further analysis and charting.
|
118
118
|
|
119
|
+
|
120
|
+
== Distributed computing support
|
121
|
+
|
122
|
+
Newly this library supports a simple distributed model of running experiments. Setup worker computers with the
|
123
|
+
|
124
|
+
$ experiment worker --address IP_OF_COMPUTER_WHERE_YOU_RUN_EXPERIMENTS
|
125
|
+
|
126
|
+
and then run experiments with --distributed flag.
|
127
|
+
|
119
128
|
== Misc
|
120
129
|
|
121
|
-
So that's pretty much the gist of experiment. There's a few other features (and a few soon to come to a gem near you ;-)
|
130
|
+
So that's pretty much the gist of experiment. There's a few other features (and a few soon to come to a gem near you ;-) Growl notifications are now supported. Turn them of by setting growl_notifications to false in your config file.
|
122
131
|
|
123
132
|
Also check out the RDocs: http://rdoc.info/github/gampleman/Experiment/master/frames
|
data/Rakefile
CHANGED
@@ -14,7 +14,7 @@ $hoe = Hoe.spec 'experiment' do
|
|
14
14
|
self.developer 'Jakub Hampl', 'honitom@seznam.cz'
|
15
15
|
#self.post_install_message = 'PostInstall.txt' # TODO remove if post-install message not required
|
16
16
|
self.rubyforge_name = self.name # TODO this is default value
|
17
|
-
#
|
17
|
+
#self.extra_deps = [['ruby-growl','>= 1.0']]
|
18
18
|
|
19
19
|
end
|
20
20
|
|
data/bin/experiment
CHANGED
@@ -1,47 +1,14 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
# == Synopsis
|
4
|
-
# This program will run an experimental batch or generate files
|
5
|
-
# for a new experiment
|
6
|
-
#
|
7
|
-
# == Examples
|
8
|
-
# Running an experiment
|
9
|
-
# experiment --env dice experiment1 experiment2 ...
|
10
|
-
#
|
11
|
-
# Generating a new experiment with 2 cross validations
|
12
|
-
# experiment new experiment_name --cv 2
|
13
|
-
#
|
14
|
-
# List all available experiments
|
15
|
-
# experiment list
|
16
|
-
#
|
17
|
-
#
|
18
|
-
# == Usage
|
19
|
-
# experiment command [options]
|
20
|
-
#
|
21
|
-
# For help use: experiment -h
|
22
|
-
#
|
23
|
-
# == Options
|
24
|
-
# -h, --help Displays help message
|
25
|
-
# -v, --version Display the version, then exit
|
26
|
-
# -q, --quiet Output as little as possible, overrides verbose
|
27
|
-
# -V, --verbose Verbose output
|
28
|
-
# -e, --env Sets the environment to run in
|
29
|
-
# Defaults to development
|
30
|
-
# -c, --cv Number of Cross validations to run
|
31
|
-
# -m, --description A description of the current experiment
|
32
|
-
#
|
33
|
-
# == Author
|
34
|
-
# Jakub Hampl
|
35
|
-
#
|
36
|
-
|
37
|
-
#require "rubygems"
|
38
3
|
require 'optparse'
|
39
|
-
#require 'rdoc/usage'
|
40
4
|
require 'ostruct'
|
41
|
-
|
5
|
+
require "rdoc"
|
6
|
+
require "rdoc/rdoc"
|
7
|
+
|
8
|
+
require File.dirname(__FILE__) + "/../lib/experiment/runner"
|
42
9
|
|
43
10
|
class App
|
44
|
-
VERSION = '
|
11
|
+
VERSION = '0.2.0'
|
45
12
|
|
46
13
|
attr_reader :options
|
47
14
|
|
@@ -55,11 +22,10 @@ class App
|
|
55
22
|
@options.quiet = false
|
56
23
|
@options.env = :development
|
57
24
|
@options.cv = 5
|
58
|
-
@options.n_classes = 10
|
59
|
-
@options.kind = "d"
|
60
25
|
@options.description = ""
|
61
|
-
@options.opts =
|
62
|
-
|
26
|
+
@options.opts = ""
|
27
|
+
@options.distributed = false
|
28
|
+
@options.master = "localhost"
|
63
29
|
end
|
64
30
|
|
65
31
|
# Parse options, check arguments, then process the command
|
@@ -69,10 +35,7 @@ class App
|
|
69
35
|
|
70
36
|
puts "Start at #{DateTime.now}\n\n" if @options.verbose
|
71
37
|
|
72
|
-
output_options if @options.verbose # [Optional]
|
73
|
-
require File.dirname(__FILE__) + "/vendor/backports/backports" if @options.env == :dice
|
74
|
-
|
75
|
-
process_arguments
|
38
|
+
output_options if @options.verbose # [Optional]
|
76
39
|
process_command
|
77
40
|
|
78
41
|
puts "\nFinished at #{DateTime.now}" if @options.verbose
|
@@ -88,20 +51,20 @@ class App
|
|
88
51
|
def parsed_options?
|
89
52
|
|
90
53
|
# Specify options
|
91
|
-
opts = OptionParser.new
|
92
|
-
opts.on('-v', '--version') { output_version ; exit 0 }
|
93
|
-
opts.on('-h', '--help') { output_help }
|
94
|
-
opts.on('-V', '--verbose') { @options.verbose = true }
|
95
|
-
opts.on('-q', '--quiet') { @options.quiet = true }
|
96
|
-
opts.on('-e', '--env [ENV]', [:development, :
|
97
|
-
opts.on('-c', '--cv CV', Integer) { |v| @options.cv = v }
|
98
|
-
opts.on('-
|
99
|
-
opts.on('-
|
100
|
-
opts.on('-m', '--description M', String) { |v| @options.description = v }
|
101
|
-
opts.on('-o', '--options OPTSTRING', String) do |v|
|
54
|
+
@opts = OptionParser.new
|
55
|
+
@opts.on('-v', '--version') { output_version ; exit 0 }
|
56
|
+
@opts.on('-h', '--help') { output_help }
|
57
|
+
@opts.on('-V', '--verbose') { @options.verbose = true }
|
58
|
+
@opts.on('-q', '--quiet') { @options.quiet = true }
|
59
|
+
@opts.on('-e', '--env [ENV]', [:development, :compute], "Sets the environment to run in.") { |v| @options.env = v }
|
60
|
+
@opts.on('-c', '--cv CV', Integer, "The number of cross validations to run.") { |v| @options.cv = v }
|
61
|
+
@opts.on('-m', '--description M', String, "Description or hypothesis for the condition being generated.") { |v| @options.description = v }
|
62
|
+
@opts.on('-o', '--options OPTSTRING', String, "Options to override config with. key1:val1,key2:val2") do |v|
|
102
63
|
@options.opts = v
|
103
64
|
end
|
104
|
-
opts.
|
65
|
+
@opts.on('-D', '--distributed', "Run with a distributed computing mode. This will be the master server/work cue.") { @options.distributed = true }
|
66
|
+
@opts.on('-a', '--address MODE', String, "Address to the master machine.") { |v| @options.master = v }
|
67
|
+
@opts.parse!(@arguments) #rescue return false
|
105
68
|
|
106
69
|
process_options
|
107
70
|
true
|
@@ -122,21 +85,45 @@ class App
|
|
122
85
|
|
123
86
|
# True if required arguments were provided
|
124
87
|
def arguments_valid?
|
125
|
-
true if @arguments.length > 0
|
126
|
-
end
|
127
|
-
|
128
|
-
# Setup the arguments
|
129
|
-
def process_arguments
|
130
|
-
# TO DO - place in local vars, etc
|
88
|
+
true #if @arguments.length > 0
|
131
89
|
end
|
132
90
|
|
133
91
|
def output_help
|
134
92
|
output_version
|
135
|
-
|
93
|
+
puts "= Synopsis
|
94
|
+
This program will run an experimental batch or generate files
|
95
|
+
for a new experiment"
|
96
|
+
puts
|
97
|
+
output_usage
|
98
|
+
puts
|
99
|
+
puts "= Options"
|
100
|
+
puts @opts.help
|
101
|
+
puts
|
102
|
+
puts "= Commands"
|
103
|
+
# Bizzare hax to make RDoc parse the files
|
104
|
+
top_level = RDoc::TopLevel.new File.dirname(__FILE__) + "/../lib/experiment/runner.rb"
|
105
|
+
opts = RDoc::Options.new
|
106
|
+
stats = RDoc::Stats.new 1
|
107
|
+
parser = RDoc::Parser.for top_level, File.dirname(__FILE__) + "/../lib/experiment/runner.rb", File.read(File.dirname(__FILE__) + "/../lib/experiment/runner.rb"), opts, stats
|
108
|
+
d = parser.scan
|
109
|
+
d.modules.first.classes.first.method_list.each do |m|
|
110
|
+
if m.comment != ""
|
111
|
+
puts "== #{m.name == 'new_project' ? 'new' : m.name}"
|
112
|
+
puts m.comment
|
113
|
+
puts
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
puts "----"
|
118
|
+
exit 0
|
136
119
|
end
|
137
120
|
|
138
121
|
def output_usage
|
139
|
-
|
122
|
+
puts "= Usage
|
123
|
+
experiment command [options]
|
124
|
+
|
125
|
+
For help use: experiment -h"
|
126
|
+
|
140
127
|
end
|
141
128
|
|
142
129
|
def output_version
|
@@ -144,130 +131,19 @@ class App
|
|
144
131
|
end
|
145
132
|
|
146
133
|
def process_command
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
req_file.puts "# This includes the reference implementation."
|
157
|
-
req_file.puts "# Override any desired files in this directory."
|
158
|
-
Dir["./app/**/*.rb"].each do |f|
|
159
|
-
p = f.split("/") - File.expand_path(".").split("/")
|
160
|
-
req_file.puts "require File.dirname(__FILE__) + \"/../../#{p.join("/")}\""
|
161
|
-
end
|
162
|
-
req_file.puts "\nclass #{as_class_name @arguments[1]} < MyExperiment\n\t\nend"
|
163
|
-
end
|
164
|
-
File.open(dir + "/config.yaml", "w") do |f|
|
165
|
-
f << "---\nexperiment:\n development:\n compute:\n"
|
166
|
-
end
|
167
|
-
|
168
|
-
elsif @arguments.first == "new" # generate a new project
|
169
|
-
require 'fileutils'
|
170
|
-
dir = "./" + @arguments[1]
|
171
|
-
Dir.mkdir(dir)
|
172
|
-
%w[app config experiments report results test tmp vendor].each do |d|
|
173
|
-
Dir.mkdir(dir + "/" + d)
|
174
|
-
end
|
175
|
-
basedir = File.dirname(__FILE__) + "/.."
|
176
|
-
File.open(File.join(dir, "config", "config.yaml"), "w") do |f|
|
177
|
-
f << "---\nenvironments:\n development:\n compute:\n"
|
178
|
-
end
|
179
|
-
File.open(File.join(dir, ".gitignore"), "w") do |f|
|
180
|
-
f << "tmp/*"
|
181
|
-
end
|
182
|
-
FileUtils::cp File.join(basedir, "lib/experiment/generator/readme_template.txt"), File.join(dir, "README")
|
183
|
-
FileUtils::cp File.join(basedir, "lib/experiment/generator/Rakefile"), File.join(dir, "Rakefile")
|
184
|
-
FileUtils::cp File.join(basedir, "lib/experiment/generator/experiment_template.rb"), File.join(dir, "experiments", "experiment.rb")
|
185
|
-
elsif @arguments.first == "list"
|
186
|
-
puts "Available experiments:"
|
187
|
-
puts " " + Dir["./experiments/*"].map{|a| File.basename(a) }.join(", ")
|
188
|
-
elsif @arguments.first == "report"
|
189
|
-
dir = "./report/"
|
190
|
-
File.open(dir + "method.mmd", "w") do |f|
|
191
|
-
f.puts "# Methods #"
|
192
|
-
Dir["./experiments/*/*.rb"].each do |desc|
|
193
|
-
if File.basename(desc) == File.basename(File.dirname(desc)) + ".rb"
|
194
|
-
File.read(desc).split("\n").each do |line|
|
195
|
-
if m = line.match(/^\# (.+)/)
|
196
|
-
f.puts m[1]
|
197
|
-
else
|
198
|
-
break
|
199
|
-
end
|
200
|
-
end
|
201
|
-
f.puts
|
202
|
-
f.puts
|
203
|
-
end
|
204
|
-
end
|
205
|
-
end
|
206
|
-
require 'csv'
|
207
|
-
require "yaml"
|
208
|
-
require File.dirname(__FILE__)+"/../lib/experiment/stats"
|
209
|
-
CSV.open(dir + "/data.csv", "w") do |csv|
|
210
|
-
data = {}
|
211
|
-
Dir["./results/*/results.yaml"].each do |res|
|
212
|
-
d = YAML::load_file(res)
|
213
|
-
da = {}
|
214
|
-
d.each do |k, vals|
|
215
|
-
da[k.to_s + " mean"], da[k.to_s + " sd"] = Stats::mean(vals), Stats::standard_deviation(vals)
|
216
|
-
vals.each_with_index do |v, i|
|
217
|
-
da[k.to_s + " cv:" + i.to_s] = v
|
218
|
-
end
|
219
|
-
end
|
220
|
-
array_merge(data, da)
|
221
|
-
end
|
222
|
-
data.keys.map do |key|
|
223
|
-
# calculate stats
|
224
|
-
a = data[key]
|
225
|
-
[key] + a
|
226
|
-
end.transpose.each do |row|
|
227
|
-
csv << row
|
228
|
-
end
|
229
|
-
end
|
230
|
-
elsif @arguments.shift == "run"
|
231
|
-
require File.dirname(__FILE__) + "/../lib/experiment/base"
|
232
|
-
require "experiments/experiment"
|
233
|
-
@arguments.each do |exp|
|
234
|
-
require "./experiments/#{exp}/#{exp}"
|
235
|
-
cla = eval(as_class_name(exp))
|
236
|
-
experiment = cla.new exp, @options.opts, @options.env
|
237
|
-
experiment.run! @options.cv
|
238
|
-
end
|
239
|
-
else
|
240
|
-
output_usage
|
241
|
-
end
|
242
|
-
|
243
|
-
end
|
244
|
-
|
245
|
-
|
246
|
-
private
|
247
|
-
def array_merge(h1, h2)
|
248
|
-
h2.each do |key, value|
|
249
|
-
h1[key] ||= []
|
250
|
-
h1[key] << value
|
251
|
-
end
|
252
|
-
end
|
253
|
-
|
254
|
-
def as_class_name(str)
|
255
|
-
str.split(/[\_\-]+/).map(&:capitalize).join
|
256
|
-
end
|
257
|
-
|
258
|
-
def as_human_name(str)
|
259
|
-
str.split(/[\_\-]+/).map(&:capitalize).join(" ")
|
134
|
+
command = @arguments.shift
|
135
|
+
runner = Experiment::Runner.new @arguments, options
|
136
|
+
command = "new_project" if command == 'new'
|
137
|
+
#begin
|
138
|
+
runner.send command.to_sym
|
139
|
+
#rescue NoMethodError => e
|
140
|
+
# puts "Wrong input #{e.inspect}"
|
141
|
+
# output_usage
|
142
|
+
#end
|
260
143
|
end
|
261
144
|
|
262
145
|
def process_standard_input
|
263
146
|
input = @stdin.read
|
264
|
-
# TO DO - process input
|
265
|
-
|
266
|
-
# [Optional]
|
267
|
-
# @stdin.each do |line|
|
268
|
-
# # TO DO - process each line
|
269
|
-
#end
|
270
|
-
|
271
147
|
end
|
272
148
|
end
|
273
149
|
|
data/bin/growl.sh
ADDED
@@ -0,0 +1,241 @@
|
|
1
|
+
#!/bin/sh
|
2
|
+
#-----------------------------------------------------------------------------
|
3
|
+
# growl - Send the a message to Mac OS X Growl <http://growl.info> via a
|
4
|
+
# Unix shell script.
|
5
|
+
#
|
6
|
+
# And if this is a Linux or Windows_NT box, use ssh to forward the
|
7
|
+
# growl notice to my Mac OS X workstation (taking advantage of
|
8
|
+
# previously exchanged ssh so no additional authentication is
|
9
|
+
# needed).
|
10
|
+
#
|
11
|
+
# This script should be somewhere in your PATH. I like to use
|
12
|
+
# $HOME/bin for personal scripts, and /usr/local/bin for system
|
13
|
+
# wide scripts, with appropriate entries added to PATH. The script
|
14
|
+
# needs to be executable:
|
15
|
+
#
|
16
|
+
# chmod +x $HOME/bin/growl
|
17
|
+
#
|
18
|
+
# The basics for the Growl Applescript came from the Growl
|
19
|
+
# documentation at:
|
20
|
+
# <http://growl.info/documentation/applescript-support.php>
|
21
|
+
#-----------------------------------------------------------------------------
|
22
|
+
# Bob Harris - 2-Jun-2007
|
23
|
+
#-----------------------------------------------------------------------------
|
24
|
+
|
25
|
+
|
26
|
+
#--- usage -------------------------------------------------------------------
|
27
|
+
usage()
|
28
|
+
{
|
29
|
+
echo 1>&2 ""
|
30
|
+
echo 1>&2 "Usage: growl [options] \"message to display\""
|
31
|
+
echo 1>&2 ""
|
32
|
+
echo 1>&2 " -sticky - Stays on screen until dismissed [Default]."
|
33
|
+
echo 1>&2 " -nosticky - Goes away after several seconds."
|
34
|
+
echo 1>&2 " -priority n - Priority -2,-1,0,1,2 [Default: 0]"
|
35
|
+
echo 1>&2 " -verylow - priority [-2]"
|
36
|
+
echo 1>&2 " -moderate - priority [-1]"
|
37
|
+
echo 1>&2 " -normal - priority [0] [Default]"
|
38
|
+
echo 1>&2 " -high - priority [1]"
|
39
|
+
echo 1>&2 " -emergency - priority [2]"
|
40
|
+
echo 1>&2 ""
|
41
|
+
echo 1>&2 " Interesting environment variables:"
|
42
|
+
echo 1>&2 " G_TITLE - Used as the Growl message title."
|
43
|
+
echo 1>&2 " G_APPLICATION_NAME - Used by Growl to manage a set of"
|
44
|
+
echo 1>&2 " G_WITH_NAME message configurations."
|
45
|
+
echo 1>&2 " See System Preferences -> Growl"
|
46
|
+
echo 1>&2 " G_ALL_NAMES - Used to specify 'ALL' the possible"
|
47
|
+
echo 1>&2 " G_WITH_NAME values this"
|
48
|
+
echo 1>&2 " G_APPLICATION_NAME will ever use."
|
49
|
+
echo 1>&2 " Specify something like:"
|
50
|
+
echo 1>&2 " G_ALL_NAMES='\"class1\",\"class2\"'"
|
51
|
+
echo 1>&2 " export G_ALL_NAMES"
|
52
|
+
echo 1>&2 " G_WITH_NAME - Used by Growl to associate a"
|
53
|
+
echo 1>&2 " message with a set of Growl"
|
54
|
+
echo 1>&2 " notification settings, such as"
|
55
|
+
echo 1>&2 " message style and colors associated"
|
56
|
+
echo 1>&2 " with different priorities. See"
|
57
|
+
echo 1>&2 " System preferences -> Growl"
|
58
|
+
echo 1>&2 " Specify something like:"
|
59
|
+
echo 1>&2 " G_WITH_NAME='class2'"
|
60
|
+
echo 1>&2 " export G_WITH_NAME"
|
61
|
+
echo 1>&2 " If G_WITH_NAME is not in"
|
62
|
+
echo 1>&2 " G_ALL_NAMES, nothing will be"
|
63
|
+
echo 1>&2 " displayed"
|
64
|
+
echo 1>&2 " G_APPLICATION_ICON - Display this application's icon in"
|
65
|
+
echo 1>&2 " the Growl message (default is"
|
66
|
+
echo 1>&2 " Terminal.app, as this is a shell"
|
67
|
+
echo 1>&2 " script generated Growl notice)."
|
68
|
+
echo 1>&2 ""
|
69
|
+
exit 1
|
70
|
+
}
|
71
|
+
|
72
|
+
|
73
|
+
#--- defaults ----------------------------------------------------------------
|
74
|
+
defaults()
|
75
|
+
{
|
76
|
+
#
|
77
|
+
# These 2 variables are used when this script notices that it is on a Linux
|
78
|
+
# or Windows_NT system, then this script uses ssh to forward the request to
|
79
|
+
# my Mac OS X workstation. This assumes that ssh keys have been exchanged
|
80
|
+
# between the systems so that no passwords are needed. If you don't know
|
81
|
+
# what this means, then do a Google search for something like
|
82
|
+
# "ssh nopassword key" and you should turn up a number of guides for
|
83
|
+
# configuring ssh.
|
84
|
+
#
|
85
|
+
G_REMOTE="${G_REMOTE:-juggle-mac.us.oracle.com}" # assumes ssh exchanged keys
|
86
|
+
G_REMOTE_GROWL="${G_REMOTE_GROWL:-bin/growl}" # growl script remote location
|
87
|
+
|
88
|
+
#
|
89
|
+
# G_APPLICATION_NAME is the name Growl will use in the Growl System
|
90
|
+
# Preferences to provide defaults for Display, and to collect each of your
|
91
|
+
# notification classes (See G_ALL_NAMES below).
|
92
|
+
#
|
93
|
+
G_APPLICATION_NAME="${G_APPLICATION_NAME:-Shell Script Growl Message}"
|
94
|
+
#
|
95
|
+
# G_ALL_NAMES contains a list of all the notification classes to be
|
96
|
+
# associated with the G_APPLICATION_NAME. Each notification class can have
|
97
|
+
# its own default Display, Priority, and Stickness settings in the Growl
|
98
|
+
# System Preferences.
|
99
|
+
#
|
100
|
+
G_ALL_NAMES="${G_ALL_NAMES:-\"Shell Script Growl Message\",\"Growl Message\"}"
|
101
|
+
#
|
102
|
+
# The default notification class this message should use, must be in the
|
103
|
+
# G_ALL_NAMES list above.
|
104
|
+
#
|
105
|
+
G_WITH_NAME="${G_WITH_NAME:-Shell Script Growl Message}" # default notification
|
106
|
+
#
|
107
|
+
G_TITLE="${G_TITLE:-Shell Script Growl Message}" # default title
|
108
|
+
G_APPLICATION_ICON="${G_APPLICATION_ICON:-Terminal.app}" # default icon to use
|
109
|
+
G_STICKY="${G_STICKY:-yes}" # default sticky setting
|
110
|
+
G_PRIORITY="${G_PRIORITY:-0}" # default priority (normal)
|
111
|
+
}
|
112
|
+
|
113
|
+
|
114
|
+
#--- growl -------------------------------------------------------------------
|
115
|
+
# notify v : Post a notification to be displayed via Growl
|
116
|
+
# notify
|
117
|
+
# with name string : name of the notification to display
|
118
|
+
# title string : title of the notification to display
|
119
|
+
# description string : full text of the notification to display
|
120
|
+
# application name string : name of the application posting the
|
121
|
+
# notification.
|
122
|
+
# [image from location location_reference]
|
123
|
+
# : Location of the image file to use for this
|
124
|
+
# notification. Accepts aliases, paths and
|
125
|
+
# file:/// URLs.
|
126
|
+
# [icon of file location_reference]
|
127
|
+
# : Location of the file whose icon should be
|
128
|
+
# used as the image for this notification.
|
129
|
+
# Accepts aliases, paths and file:/// URLs.
|
130
|
+
# e.g. 'file:///Applications'.
|
131
|
+
# [icon of application string]
|
132
|
+
# : Name of the application whose icon should
|
133
|
+
# be used for this notification. For
|
134
|
+
# example, 'Mail.app'.
|
135
|
+
# [image Image] : TIFF Image to be used for the
|
136
|
+
# notification.
|
137
|
+
# [pictImage Picture] : PICT Image to be used for the
|
138
|
+
# notification.
|
139
|
+
# [sticky boolean] : whether or not the notification displayed
|
140
|
+
# should time out. Defaults to 'no'.
|
141
|
+
# [priority integer] : The priority of the notification, from -2
|
142
|
+
# (low) to 0 (normal) to 2 (emergency).
|
143
|
+
#
|
144
|
+
growl()
|
145
|
+
{
|
146
|
+
typeset description="$*"
|
147
|
+
|
148
|
+
osascript <<EOD
|
149
|
+
-- From <http://growl.info/documentation/applescript-support.php>
|
150
|
+
--
|
151
|
+
tell application "GrowlHelperApp"
|
152
|
+
-- Make a list of all the notification types that this script will ever send:
|
153
|
+
set the allNotificationsList to {${G_ALL_NAMES}}
|
154
|
+
|
155
|
+
-- Make a list of the notifications that will be enabled by default.
|
156
|
+
-- Those not enabled by default can be enabled later in the 'Applications'
|
157
|
+
-- tab of the growl prefpane.
|
158
|
+
set the enabledNotificationsList to {"${G_WITH_NAME}"}
|
159
|
+
|
160
|
+
-- Register our script with growl. You can optionally (as here) set a
|
161
|
+
-- default icon for this script's notifications.
|
162
|
+
register as application "${G_APPLICATION_NAME}" all notifications allNotificationsList default notifications enabledNotificationsList icon of application "${G_APPLICATION_ICON}"
|
163
|
+
|
164
|
+
-- Send a Notification...
|
165
|
+
notify with name "${G_WITH_NAME}" title "${G_TITLE}" description "${description}" application name "${G_APPLICATION_NAME}" sticky ${G_STICKY} priority ${G_PRIORITY}
|
166
|
+
|
167
|
+
end tell
|
168
|
+
EOD
|
169
|
+
}
|
170
|
+
|
171
|
+
|
172
|
+
#--- main --------------------------------------------------------------------
|
173
|
+
#{
|
174
|
+
if [[ $# = 0 ]]; then
|
175
|
+
#
|
176
|
+
# No arguments, so give the usage message.
|
177
|
+
#
|
178
|
+
usage
|
179
|
+
exit 1
|
180
|
+
fi
|
181
|
+
while [[ "X$1" = X-* ]]
|
182
|
+
do
|
183
|
+
if [[ "X$1" = X-nos* ]]; then
|
184
|
+
G_STICKY=no
|
185
|
+
elif [[ "X$1" = X-s* ]]; then
|
186
|
+
G_STICKY=yes
|
187
|
+
elif [[ "X$1" = X-p* ]]; then
|
188
|
+
G_PRIORITY="$2"
|
189
|
+
G_TITLE="${G_TITLE:-Priority $2}"
|
190
|
+
OPTIONS="$OPTIONS $1"
|
191
|
+
shift
|
192
|
+
elif [[ "X$1" = X-v* ]]; then
|
193
|
+
G_PRIORITY="-2"
|
194
|
+
G_TITLE="${G_TITLE:-Very Low Priority}"
|
195
|
+
elif [[ "X$1" = X-m* ]]; then
|
196
|
+
G_PRIORITY="-1"
|
197
|
+
G_TITLE="${G_TITLE:-Moderate Priority}"
|
198
|
+
elif [[ "X$1" = X-n* ]]; then
|
199
|
+
G_PRIORITY="0"
|
200
|
+
G_TITLE="${G_TITLE:-Normal Priority}"
|
201
|
+
elif [[ "X$1" = X-h* ]]; then
|
202
|
+
G_PRIORITY="1"
|
203
|
+
G_TITLE="${G_TITLE:-High Priority}"
|
204
|
+
elif [[ "X$1" = X-e* ]]; then
|
205
|
+
G_PRIORITY="2"
|
206
|
+
G_TITLE="${G_TITLE:-Emergency Priority}"
|
207
|
+
else
|
208
|
+
break;
|
209
|
+
fi
|
210
|
+
OPTIONS="$OPTIONS $1"
|
211
|
+
shift
|
212
|
+
done
|
213
|
+
|
214
|
+
#
|
215
|
+
# If any of the option variables have not been set yet, then apply the
|
216
|
+
# default values now.
|
217
|
+
#
|
218
|
+
defaults
|
219
|
+
|
220
|
+
UNAME=$(uname)
|
221
|
+
if [[ "$UNAME" = Darwin ]]; then
|
222
|
+
#
|
223
|
+
# I'm assuming this is one of my systems where I have Growl
|
224
|
+
# installed.
|
225
|
+
#
|
226
|
+
growl "$*"
|
227
|
+
elif [[ "$UNAME" = *Linux* || "$UNAME" = *Windows_NT* ]]; then
|
228
|
+
#
|
229
|
+
# Must be one of the development systems I work on, so lets ship
|
230
|
+
# this request to my Mac OS X workstation.
|
231
|
+
#
|
232
|
+
ssh ${G_REMOTE} ${G_REMOTE_GROWL} $OPTIONS "$*"
|
233
|
+
else
|
234
|
+
#
|
235
|
+
# I don't know what this is, so I'll just try to Growl anyway. It
|
236
|
+
# will most likely fail (no osascript would be my guess), but what
|
237
|
+
# do I have to loose at this point!
|
238
|
+
#
|
239
|
+
growl "$*"
|
240
|
+
fi
|
241
|
+
#}
|