rum 0.0.1-universal-darwin-10

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.
Files changed (99) hide show
  1. data/CHANGELOG +3 -0
  2. data/README +30 -0
  3. data/Rakefile +134 -0
  4. data/bin/rum-client +124 -0
  5. data/doc/basic.rb +10 -0
  6. data/doc/doc.html +602 -0
  7. data/doc/example.rb +59 -0
  8. data/doc/reference.rb +415 -0
  9. data/doc/resources/bg.png +0 -0
  10. data/doc/resources/bottom.png +0 -0
  11. data/doc/resources/build.rb +235 -0
  12. data/doc/resources/doc.haml +167 -0
  13. data/doc/resources/emacs-auto-completion.png +0 -0
  14. data/doc/resources/flash.png +0 -0
  15. data/doc/resources/highlight.css +94 -0
  16. data/doc/resources/intro.rb +17 -0
  17. data/doc/resources/left.png +0 -0
  18. data/doc/resources/logo.png +0 -0
  19. data/doc/resources/screen.css +420 -0
  20. data/doc/resources/screenshot.png +0 -0
  21. data/doc/resources/top.png +0 -0
  22. data/ext/mac/keyboard_hook/English.lproj/InfoPlist.strings +0 -0
  23. data/ext/mac/keyboard_hook/Event.h +17 -0
  24. data/ext/mac/keyboard_hook/Event.m +18 -0
  25. data/ext/mac/keyboard_hook/EventTap.h +11 -0
  26. data/ext/mac/keyboard_hook/EventTap.m +77 -0
  27. data/ext/mac/keyboard_hook/Info.plist +26 -0
  28. data/ext/mac/keyboard_hook/KeyboardHook.xcodeproj/TemplateIcon.icns +0 -0
  29. data/ext/mac/keyboard_hook/KeyboardHook.xcodeproj/project.pbxproj +323 -0
  30. data/ext/mac/keyboard_hook/KeyboardHook_Prefix.pch +7 -0
  31. data/ext/mac/keyboard_hook/version.plist +16 -0
  32. data/ext/windows/keyboard_hook/extconf.rb +2 -0
  33. data/ext/windows/keyboard_hook/keyboard_hook.c +126 -0
  34. data/ext/windows/system/autohotkey_stuff.c +255 -0
  35. data/ext/windows/system/autohotkey_stuff.h +2 -0
  36. data/ext/windows/system/clipboard_watcher.c +58 -0
  37. data/ext/windows/system/clipboard_watcher.h +2 -0
  38. data/ext/windows/system/extconf.rb +3 -0
  39. data/ext/windows/system/input_box.c +239 -0
  40. data/ext/windows/system/input_box.h +4 -0
  41. data/ext/windows/system/system.c +273 -0
  42. data/lib/rum.rb +4 -0
  43. data/lib/rum/apps.rb +4 -0
  44. data/lib/rum/barrel.rb +157 -0
  45. data/lib/rum/barrel/emacs.rb +44 -0
  46. data/lib/rum/barrel/emacs_client.rb +74 -0
  47. data/lib/rum/core.rb +125 -0
  48. data/lib/rum/dsl.rb +109 -0
  49. data/lib/rum/gui.rb +93 -0
  50. data/lib/rum/help.rb +128 -0
  51. data/lib/rum/hotkey_core.rb +479 -0
  52. data/lib/rum/mac.rb +18 -0
  53. data/lib/rum/mac/app.rb +4 -0
  54. data/lib/rum/mac/apps.rb +19 -0
  55. data/lib/rum/mac/gui.rb +26 -0
  56. data/lib/rum/mac/gui/CocoaDialog.app/Contents/Info.plist +28 -0
  57. data/lib/rum/mac/gui/CocoaDialog.app/Contents/MacOS/CocoaDialog +0 -0
  58. data/lib/rum/mac/gui/CocoaDialog.app/Contents/Resources/Info.plist +28 -0
  59. data/lib/rum/mac/gui/CocoaDialog.app/Contents/Resources/InfoPlist.strings +0 -0
  60. data/lib/rum/mac/gui/CocoaDialog.app/Contents/Resources/Inputbox.nib/classes.nib +51 -0
  61. data/lib/rum/mac/gui/CocoaDialog.app/Contents/Resources/Inputbox.nib/info.nib +16 -0
  62. data/lib/rum/mac/gui/CocoaDialog.app/Contents/Resources/Inputbox.nib/keyedobjects.nib +0 -0
  63. data/lib/rum/mac/gui/CocoaDialog.app/Contents/Resources/MainMenu.nib/classes.nib +7 -0
  64. data/lib/rum/mac/gui/CocoaDialog.app/Contents/Resources/MainMenu.nib/info.nib +21 -0
  65. data/lib/rum/mac/gui/CocoaDialog.app/Contents/Resources/MainMenu.nib/info.nib.orig +21 -0
  66. data/lib/rum/mac/gui/CocoaDialog.app/Contents/Resources/MainMenu.nib/objects.nib +0 -0
  67. data/lib/rum/mac/gui/CocoaDialog.app/Contents/Resources/MainMenu.nib/objects.nib.orig +0 -0
  68. data/lib/rum/mac/gui/CocoaDialog.app/Contents/Resources/Msgbox.nib/classes.nib +27 -0
  69. data/lib/rum/mac/gui/CocoaDialog.app/Contents/Resources/Msgbox.nib/info.nib +16 -0
  70. data/lib/rum/mac/gui/CocoaDialog.app/Contents/Resources/Msgbox.nib/keyedobjects.nib +0 -0
  71. data/lib/rum/mac/gui/Growl.framework/Growl +0 -0
  72. data/lib/rum/mac/gui/Growl.framework/Versions/A/Growl +0 -0
  73. data/lib/rum/mac/gui/Growl.framework/Versions/A/Headers/Growl.h +6 -0
  74. data/lib/rum/mac/gui/Growl.framework/Versions/A/Headers/GrowlApplicationBridge-Carbon.h +780 -0
  75. data/lib/rum/mac/gui/Growl.framework/Versions/A/Headers/GrowlApplicationBridge.h +575 -0
  76. data/lib/rum/mac/gui/Growl.framework/Versions/A/Headers/GrowlDefines.h +348 -0
  77. data/lib/rum/mac/gui/Growl.framework/Versions/A/Resources/Info.plist +24 -0
  78. data/lib/rum/mac/gui/growl.rb +54 -0
  79. data/lib/rum/mac/irb/completion.rb +207 -0
  80. data/lib/rum/mac/keyboard_hook.rb +73 -0
  81. data/lib/rum/mac/keyboard_hook/KeyboardHook.framework/KeyboardHook +0 -0
  82. data/lib/rum/mac/keyboard_hook/KeyboardHook.framework/Versions/A/KeyboardHook +0 -0
  83. data/lib/rum/mac/keyboard_hook/KeyboardHook.framework/Versions/A/Resources/English.lproj/InfoPlist.strings +0 -0
  84. data/lib/rum/mac/keyboard_hook/KeyboardHook.framework/Versions/A/Resources/Info.plist +22 -0
  85. data/lib/rum/mac/layouts.rb +146 -0
  86. data/lib/rum/mac/system.rb +45 -0
  87. data/lib/rum/remote.rb +48 -0
  88. data/lib/rum/server.rb +92 -0
  89. data/lib/rum/windows.rb +23 -0
  90. data/lib/rum/windows/app.rb +72 -0
  91. data/lib/rum/windows/apps.rb +25 -0
  92. data/lib/rum/windows/gui.rb +116 -0
  93. data/lib/rum/windows/keyboard.rb +80 -0
  94. data/lib/rum/windows/keyboard_hook.rb +20 -0
  95. data/lib/rum/windows/layouts.rb +232 -0
  96. data/lib/rum/windows/system.rb +310 -0
  97. data/lib/rum/windows/system_foreign_functions.rb +129 -0
  98. data/rum.gemspec +14 -0
  99. metadata +166 -0
@@ -0,0 +1,3 @@
1
+ = 0.0.1
2
+ === 2011/06/4
3
+ * Hello World!
data/README ADDED
@@ -0,0 +1,30 @@
1
+ = Description
2
+ A cross-platform Hotkey and Macro utility, running on Windows and Mac OS.
3
+
4
+ = Synopsis
5
+ require 'rum'
6
+ Rum.layout.modifier 'caps'
7
+ 'caps f1'.do { message 'hi' }
8
+ Rum.start
9
+
10
+ = Documentation
11
+ Visit http://nonsequitur.github.com/rum for examples and a detailed reference.
12
+
13
+ = License
14
+ Rum is available under the MIT license (http://www.opensource.org/licenses/mit-license.php)
15
+ Copyright 2010-2011, The Rum Project
16
+
17
+ = Licenses of software that is bundled with some Rum distributions
18
+ == CocoaDialog
19
+ CocoaDialog is Copyright © 2004, Mark A. Stratman <mark@sporkstorms.org>
20
+ It is licensed under the GNU General Public License.
21
+ http://cocoadialog.sourceforge.net/
22
+
23
+ == Growl
24
+ Copyright (c) The Growl Project, 2004
25
+ All rights reserved.
26
+ http://growl.info/documentation/developer/bsd-license.txt
27
+
28
+ == AutoHotkey
29
+ GNU General Public License
30
+ http://www.autohotkey.com/docs/license.htm
@@ -0,0 +1,134 @@
1
+ require 'rake/clean'
2
+
3
+ CLEAN.include('ext/windows/keyboard_hook/*',
4
+ 'ext/windows/system/*',
5
+ 'ext/mac/keyboard_hook/build',
6
+ '*.gem',
7
+ '**/.DS_Store')
8
+ CLEAN.exclude('.c', '.h', 'extconf.rb')
9
+
10
+ CLOBBER.include('lib/rum/windows/keyboard_hook.so',
11
+ 'lib/rum/windows/system.so',
12
+ 'lib/rum/mac/keyboard_hook/KeyboardHook.framework',
13
+ 'doc/doc.html')
14
+
15
+ MAC_BINARIES = ['lib/rum/mac/keyboard_hook/KeyboardHook.framework',
16
+ 'lib/rum/mac/gui/Growl.framework',
17
+ 'lib/rum/mac/gui/CocoaDialog.app']
18
+
19
+ WINDOWS_BINARIES = ['lib/rum/windows/keyboard_hook.so',
20
+ 'lib/rum/windows/system.so']
21
+
22
+ namespace :ext do
23
+ namespace :windows do
24
+ InstallDir = 'lib/rum/windows'
25
+
26
+ extensions = [['ext/windows/keyboard_hook', 'keyboard_hook'],
27
+ ['ext/windows/system', 'system', 'input_box',
28
+ 'autohotkey_stuff', 'clipboard_watcher']]
29
+
30
+ extensions.each do |dir, ext, *deps|
31
+
32
+ extconf = "#{dir}/extconf.rb"
33
+
34
+ deps.map! do |dependency|
35
+ source = "#{dir}/#{dependency}.c"
36
+ obj = "#{dir}/#{dependency}.obj"
37
+ file source do
38
+ # Trigger automatic compiling of source in make
39
+ rm obj if File.exists? obj
40
+ end
41
+ source
42
+ end
43
+
44
+ file "#{InstallDir}/#{ext}.so" => ["#{dir}/#{ext}.c", extconf, *deps] do
45
+ Dir.chdir(dir) do
46
+ ruby 'extconf.rb'
47
+ system 'nmake'
48
+ system "mt -manifest #{ext}.so.manifest -outputresource:#{ext}.so;2"
49
+ end
50
+ mv "#{dir}/#{ext}.so", InstallDir
51
+ end
52
+ end
53
+
54
+ task :keyboard_hook => 'lib/rum/windows/keyboard_hook.so'
55
+ task :system => 'lib/rum/windows/system.so'
56
+ end
57
+ task :windows => ['windows:keyboard_hook', 'windows:system']
58
+
59
+ namespace :mac do
60
+ keyboard_hook = 'lib/rum/mac/keyboard_hook/KeyboardHook.framework'
61
+ xcode_output = 'ext/mac/keyboard_hook/build/release/KeyboardHook.framework'
62
+
63
+ file keyboard_hook => xcode_output do
64
+ rm_r keyboard_hook if File.exists? keyboard_hook
65
+ cp_r xcode_output, keyboard_hook
66
+ end
67
+
68
+ file xcode_output => FileList['ext/mac/keyboard_hook/*.m'] do
69
+ Dir.chdir('ext/mac/keyboard_hook') { system 'xcodebuild' }
70
+ end
71
+
72
+ task :keyboard_hook => keyboard_hook
73
+ end
74
+ task :mac => 'mac:keyboard_hook'
75
+ end
76
+
77
+ namespace :gem do
78
+ def common_spec
79
+ spec = eval(IO.read('rum.gemspec'))
80
+ yield spec
81
+ end
82
+
83
+ def build(spec)
84
+ Gem::Builder.new(spec).build
85
+ end
86
+
87
+ task :windows do
88
+ common_spec do |spec|
89
+ spec.files = FileList['**/*'].exclude(*CLEAN.to_a, *MAC_BINARIES)
90
+ spec.add_dependency('ruby_gntp', '>= 0.3.4')
91
+ spec.add_dependency('win32-api', '>= 1.4.8')
92
+ spec.add_dependency('win32-clipboard', '>= 0.5.2')
93
+ # mingw32 and mswin32 binaries can be used interchangeably
94
+ spec.platform = 'x86-mingw32'
95
+ build(spec)
96
+ spec.platform = 'x86-mswin32-60'
97
+ build(spec)
98
+ end
99
+ end
100
+
101
+ task :mac do
102
+ common_spec do |spec|
103
+ spec.platform = 'universal-darwin-10'
104
+ spec.files = FileList['**/*'].exclude(*CLEAN.to_a, *WINDOWS_BINARIES)
105
+ build(spec)
106
+ end
107
+ end
108
+
109
+ task :publish do
110
+
111
+ end
112
+ end
113
+ task :gem => ['gem:windows', 'gem:mac']
114
+
115
+ namespace :doc do
116
+ doc = 'doc/doc.html'
117
+ doc_files = ['doc/resources/doc.haml', 'doc/resources/intro.rb', 'doc/basic.rb',
118
+ 'doc/example.rb','doc/reference.rb']
119
+ task :build => doc
120
+
121
+ build_script = 'doc/resources/build.rb'
122
+ file doc => [*doc_files, build_script] do
123
+ require_relative build_script
124
+ Doc.new(*doc_files, dir: File.dirname(__FILE__), output: doc).build
125
+ end
126
+ end
127
+ task :doc => 'doc:build'
128
+
129
+ case RUBY_PLATFORM
130
+ when /mswin|mingw/ then task :ext => 'ext:windows'
131
+ when /darwin/ then task :ext => 'ext:mac'
132
+ else raise 'Platform not supported.'
133
+ end
134
+ task :build => [:ext, :doc]
@@ -0,0 +1,124 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ module Client
4
+ module_function
5
+
6
+ def connect
7
+ @remote = Rum::Remote.new
8
+ rescue SystemCallError
9
+ puts "Rum Client: Connecting failed. Rum Server not responding."
10
+ end
11
+
12
+ class NilResponse < StandardError; end
13
+
14
+ def eval(code)
15
+ if connect
16
+ result = @remote.eval(code) or raise NilResponse
17
+ @remote.disconnect
18
+ result
19
+ end
20
+ rescue SystemCallError, NilResponse # Connection Error
21
+ @remote.disconnect
22
+ puts "Rum Client: Connection to Rum Server lost."
23
+ end
24
+ end
25
+
26
+ module RemoteIRB
27
+ module Completion
28
+ def Completion.candidates(completor_call)
29
+ eval(Client.eval(completor_call))
30
+ rescue Exception # Explicitly rescue Exception to catch eval errors.
31
+ end
32
+
33
+ def Completion.setup
34
+ Readline.completion_proc = lambda do |input|
35
+ candidates("IRB::InputCompletor::CompletionProc.call(#{input.dump})")
36
+ end
37
+ end
38
+ end
39
+
40
+ def self.load_irb
41
+ require 'irb'
42
+
43
+ # Borrowed from Hijack
44
+ const_set 'Workspace', Class.new(IRB::WorkSpace)
45
+ Workspace.class_eval do
46
+ def evaluate(context, statements, file = __FILE__, line = __LINE__)
47
+ if completor_call = statements[/^puts (IRB::InputCompletor.*)/, 1]
48
+ puts Completion.candidates(completor_call)
49
+ elsif statements.strip =~ /^exit/
50
+ exit
51
+ else
52
+ Client.eval(statements)
53
+ end
54
+ end
55
+ end
56
+
57
+ IRB::Context.class_eval do
58
+ def set_last_value value
59
+ @last_value = value
60
+ # Setting the last value variable '_' on the server is
61
+ # pointless. So skip it.
62
+ end
63
+ end
64
+ end
65
+
66
+ def self.start
67
+ load_irb
68
+ ARGV.replace ["--simple-prompt"] if ARGV.empty? # todo
69
+ IRB.setup(nil)
70
+ workspace = Workspace.new
71
+ @CONF = IRB.instance_variable_get(:@CONF)
72
+ @CONF[:INSPECT_MODE] = false
73
+ irb = IRB::Irb.new(workspace)
74
+ Completion.setup
75
+ @CONF[:IRB_RC].call irb.context if @CONF[:IRB_RC]
76
+ @CONF[:MAIN_CONTEXT] = irb.context
77
+ @CONF[:PROMPT_MODE] = :SIMPLE
78
+ trap('SIGINT') { irb.signal_handle }
79
+ catch(:IRB_EXIT) { irb.eval_input }
80
+ end
81
+ end
82
+
83
+ def evaluate code
84
+ # require_relative is missing on MacRuby
85
+ require File.join(File.dirname(__FILE__), '..', 'lib/rum/remote')
86
+ if code and not code.empty?
87
+ if (result = Client.eval(code))
88
+ puts result
89
+ else
90
+ exit 1
91
+ end
92
+ end
93
+ end
94
+
95
+ def switch_to_mri_ruby
96
+ puts "The Rum REPL doesn't yet work with MacIrb. Switching to default Ruby."
97
+ exec('ruby', __FILE__, *ARGV)
98
+ end
99
+
100
+ case not ARGV.empty? and ARGV.first.chomp
101
+ when '-h', '--help'
102
+ puts 'Usage:
103
+ -i, --interactive start a Rum IRB session
104
+ -e, --evaluate CODE evaluate CODE
105
+ CODE evaluate CODE
106
+
107
+ Evaluates code from standard input if arguments are omitted.
108
+
109
+ You can set the environment variable RUM_PORT to change the
110
+ port that is used by Rum-Client and Rum-Server.'
111
+
112
+ when '-i', '--interactive'
113
+ switch_to_mri_ruby if RUBY_DESCRIPTION =~ /MacRuby/
114
+ require_relative '../lib/rum/remote'
115
+ ARGV.shift
116
+ RemoteIRB.start
117
+ when '-e', '--evaluate'
118
+ ARGV.shift
119
+ evaluate ARGV.join(' ')
120
+ when /\S+/
121
+ evaluate ARGV.join(' ')
122
+ else
123
+ evaluate gets(nil)
124
+ end
@@ -0,0 +1,10 @@
1
+ require 'rum'
2
+
3
+ 'shift f1'.do { Rum.restart }
4
+
5
+ # If you use Emacs
6
+ require 'rum/apps'
7
+ 'shift f2'.do { Emacs.eval '(rum-client)'; Emacs.activate }
8
+
9
+ Rum::Server.start
10
+ Rum.start
@@ -0,0 +1,602 @@
1
+ <html lang='en' xml:lang='en' xmlns='http://www.w3.org/1999/xhtml'>
2
+ <head>
3
+ <title>Rum</title>
4
+ <meta content='text/html;charset=utf-8' http-equiv='Content-Type' />
5
+ <link href='resources/screen.css' media='screen' rel='stylesheet' type='text/css' />
6
+ <link href='resources/highlight.css' media='screen' rel='stylesheet' type='text/css' />
7
+ </head>
8
+ <body>
9
+ <img id='logo' src='resources/logo.png' />
10
+ <div id='nav'>
11
+ <ul>
12
+ <li>
13
+ <a href='#'>Intro</a>
14
+ </li>
15
+ <li>
16
+ <a href='#installation'>Installation</a>
17
+ </li>
18
+ <li>
19
+ <a href='#coding'>Coding</a>
20
+ </li>
21
+ <li>
22
+ <a href='#example'>Example</a>
23
+ </li>
24
+ <li>
25
+ <a href='#reference'>Reference</a>
26
+ </li>
27
+ <li>
28
+ <a href='#development'>Development</a>
29
+ </li>
30
+ </ul>
31
+ </div>
32
+ <div id='wrapper'>
33
+ <div id='intro'>Rum is a cross-platform Hotkey and Macro utility, built in Ruby.<br />Not yet running on Linux, it’s progressing steadily on the Mac (MacRuby) and is fully supported on Windows.</div>
34
+ <img src='resources/screenshot.png' />
35
+ <div id='screenshot-sub'></div>
36
+ <div id='intro-code'>
37
+ <div id='top'></div>
38
+ <div id='content'>
39
+ <img id='flash' src='resources/flash.png' />
40
+ <div id='sshot-sub'>This snippet powers the above screenshot.</div>
41
+ <div class="highlight"><pre>require <span class="s1">&#39;rum&#39;</span>
42
+
43
+ <span class="no">Rum</span><span class="o">.</span><span class="n">layout</span><span class="o">.</span><span class="n">modifier</span> <span class="s1">&#39;caps&#39;</span>
44
+ <span class="s1">&#39;caps&#39;</span><span class="o">.</span><span class="n">do</span> <span class="s1">&#39;(cmd (tab))&#39;</span>
45
+ <span class="s1">&#39;caps shift&#39;</span><span class="o">.</span><span class="n">do</span> <span class="p">{</span> <span class="n">active_window</span><span class="o">.</span><span class="n">close</span> <span class="p">}</span>
46
+
47
+ require <span class="s1">&#39;rum/apps&#39;</span>
48
+ <span class="s1">&#39;caps h&#39;</span><span class="o">.</span><span class="n">do</span> <span class="p">{</span> <span class="nb">puts</span> <span class="s1">&#39;Hello from Rum!&#39;</span> <span class="p">}</span>
49
+ <span class="s1">&#39;caps p&#39;</span><span class="o">.</span><span class="n">do</span> <span class="p">{</span> <span class="no">Photoshop</span><span class="o">.</span><span class="n">activate</span> <span class="p">}</span>
50
+ <span class="s1">&#39;caps down&#39;</span><span class="o">.</span><span class="n">do</span><span class="p">(</span><span class="no">Photoshop</span><span class="p">)</span> <span class="p">{</span> <span class="no">Photoshop</span><span class="o">.</span><span class="n">next_blend_mode</span> <span class="p">}</span>
51
+ <span class="s1">&#39;caps b&#39;</span><span class="o">.</span><span class="n">do</span> <span class="p">{</span> <span class="no">Chrome</span><span class="o">.</span><span class="n">activate_and_focus_address_bar</span> <span class="p">}</span>
52
+ <span class="s1">&#39;caps s&#39;</span><span class="o">.</span><span class="n">do</span> <span class="p">{</span> <span class="no">Emacs</span><span class="o">.</span><span class="n">eval</span> <span class="s1">&#39;(slime-repl)&#39;</span><span class="p">;</span> <span class="no">Emacs</span><span class="o">.</span><span class="n">activate</span> <span class="p">}</span>
53
+ <span class="s1">&#39;caps c&#39;</span><span class="o">.</span><span class="n">do</span> <span class="p">{</span> <span class="no">Clipboard</span><span class="o">.</span><span class="n">append</span> <span class="p">}</span>
54
+ <span class="s1">&#39;ctrl shift h&#39;</span><span class="o">.</span><span class="n">do</span> <span class="p">{</span> type <span class="s1">&#39;hi&#39;</span> <span class="p">}</span>
55
+ <span class="c1"># Caveat: Some hotkey actions are not yet available on the Mac.</span>
56
+
57
+ <span class="no">Rum</span><span class="o">.</span><span class="n">start</span>
58
+ </pre></div>
59
+
60
+ </div>
61
+ <div id='bottom'></div>
62
+ <div id='intro-code-sub'>Rum configuration files are regular Ruby scripts, like the above.<br /> Running Rum is as easy as calling <span class="code">ruby my_rum_config_file.rb</span> from the command line.<br />(Or <span class="code">macruby -rubygems my_rum_config_file.rb</span> on the Mac.)</div>
63
+ </div>
64
+ <div id='guide'>
65
+ <div id='installation'>
66
+ <a name='installation'>
67
+ <h1>Installation</h1>
68
+ </a>
69
+ <div id='gem'>
70
+ <div id='regulargem'>
71
+ <span class='code'>gem install rum</span>
72
+ </div>
73
+ <div id='macgem'>
74
+ <span class='code'>macgem install rum</span>
75
+ <div>
76
+ </div>
77
+ </div>
78
+ <div class='clear'></div>
79
+ </div>
80
+ <p id='current_version'>
81
+ Current version:
82
+ 0.0.1
83
+ <span id='changelog'>(<a href="https://github.com/nonsequitur/rum/blob/master/CHANGELOG">Changelog</a>)</span>
84
+ </p>
85
+ <div id='platforms'>
86
+ <h3>Supported platforms</h3>
87
+ <ul>
88
+ <li>Mac OS X – MacRuby >=0.10</li>
89
+ <li>
90
+ 32-bit Windows XP/Vista/7 – Ruby >=1.9.1p378.<br />
91
+ </li>
92
+ </ul>
93
+ </div>
94
+ <div id='growl'>
95
+ <h2>Recommended: Growl</h2>
96
+ <ul>
97
+ <li>Get Growl: <a href="http://growl.info/">Mac</a>, <a href="http://www.growlforwindows.com/gfw/">Windows</a></li>
98
+ <li>To use Growl in Rum: Add <span class="code">Gui.use Gui::Growl</span> to your Rum config.</li>
99
+ </ul>
100
+ <div id='growl-explanation'>
101
+ <h3>Why Growl?</h3>
102
+ Notification bubbles are a convenient alternative to focus-stealing message boxes.
103
+ Some higher level Rum methods only work smoothly with Growl-style notifications.
104
+ Currently, Growl is the only notification system supported by Rum.
105
+ </div>
106
+ </div>
107
+ </div>
108
+ <div id='coding'>
109
+ <a name='coding'>
110
+ <h1>Coding in Rum</h1>
111
+ </a>
112
+ Rum encourages an interactive approach to coding and a fast code-and-feedback cycle.
113
+ <h2>Core techniques</h2>
114
+ <ul id='core-techniques'>
115
+ <li>
116
+ <h3>rum-client REPL</h3>
117
+ <p>Add <span class="code">Rum::Server.start</span> to your Rum config.</p>
118
+ <p>Call <span class="code">rum-client -i</span> from the command line to start an IRB-session inside a running Rum instance. IRB Completion is fully supported.</p>
119
+ <p>Nearly all snippets in this guide can be evaluated interactively.</p>
120
+ <p>Set the environment variable <span class="code">RUM_PORT</span> to change the port on which client and server connect.</p>
121
+ <p>
122
+ <h3>rum-client in emacs:</h3>
123
+ <ul>
124
+ <li>Get the latest Inf-Ruby via <a href="http://marmalade-repo.org/packages/inf-ruby">ELPA</a></li>
125
+ <li>
126
+ Add the following to your Emacs config:
127
+ <pre id='inf_ruby_setup'>(add-to-list 'inf-ruby-implementations
128
+ '("rum-client" . "rum-client -i --inf-ruby-mode")
129
+ (defun rum-client ()
130
+ (interactive)
131
+ (inf-ruby "rum-client")))
132
+ </pre>
133
+ </li>
134
+ <li>
135
+ Run <span class="code">M-x rum-client</span>
136
+ </li>
137
+ </ul>
138
+ <div id='auto-completion'>
139
+ <h4>Auto-completion</h4>
140
+ <img id='auto-completion' src='resources/emacs-auto-completion.png' />
141
+ <p>
142
+ Company-Mode features auto-completion for IRB sessions.<br />
143
+ <a href="http://www.emacswiki.org/emacs/InfRubyCompany">See here for installation instructions</a>.
144
+ </p>
145
+ </div>
146
+ </p>
147
+ </li>
148
+ <li>
149
+ <h3>Rum.restart</h3>
150
+ Restarts Rum.
151
+ Bind it to a key, like <span class="code">'shift f1'.do { Rum.restart }</span>
152
+ </li>
153
+ </ul>
154
+ Run Rum with this basic, REPL-enabled setup to get started:
155
+ <div id='basic'><div class="highlight"><pre>require <span class="s1">&#39;rum&#39;</span>
156
+
157
+ <span class="s1">&#39;shift f1&#39;</span><span class="o">.</span><span class="n">do</span> <span class="p">{</span> <span class="no">Rum</span><span class="o">.</span><span class="n">restart</span> <span class="p">}</span>
158
+
159
+ <span class="c1"># If you use Emacs</span>
160
+ require <span class="s1">&#39;rum/apps&#39;</span>
161
+ <span class="s1">&#39;shift f2&#39;</span><span class="o">.</span><span class="n">do</span> <span class="p">{</span> <span class="no">Emacs</span><span class="o">.</span><span class="n">eval</span> <span class="s1">&#39;(rum-client)&#39;</span><span class="p">;</span> <span class="no">Emacs</span><span class="o">.</span><span class="n">activate</span> <span class="p">}</span>
162
+
163
+ <span class="no">Rum</span><span class="o">::</span><span class="no">Server</span><span class="o">.</span><span class="n">start</span>
164
+ <span class="no">Rum</span><span class="o">.</span><span class="n">start</span>
165
+ </pre></div>
166
+ </div>
167
+ <div id='example'>
168
+ <a name='example'>
169
+ <h1>Extended Example</h1>
170
+ </a>
171
+ <div class="highlight"><pre><span class="c1">## A short survey of the main features</span>
172
+ <span class="c1">## This file can be found at rum_dir/doc/example.rb</span>
173
+
174
+ require <span class="s1">&#39;rum&#39;</span>
175
+
176
+ <span class="c1"># 1. Set up additional modifiers that can then</span>
177
+ <span class="c1"># be used in hotkey definitions.</span>
178
+ <span class="c1"># Any key can be a modifier</span>
179
+ <span class="no">Rum</span><span class="o">.</span><span class="n">layout</span><span class="o">.</span><span class="n">modifier</span> <span class="s1">&#39;caps&#39;</span>
180
+ <span class="no">Rum</span><span class="o">.</span><span class="n">layout</span><span class="o">.</span><span class="n">modifier</span> <span class="s1">&#39;escape&#39;</span>
181
+
182
+ <span class="c1"># 2. Hotkey definitions</span>
183
+ <span class="s1">&#39;ctrl a&#39;</span><span class="o">.</span><span class="n">do</span> <span class="p">{</span> <span class="nb">puts</span> <span class="s1">&#39;foo&#39;</span> <span class="p">}</span>
184
+ <span class="c1"># Hotkeys may consist solely of modifiers</span>
185
+ <span class="s1">&#39;caps&#39;</span><span class="o">.</span><span class="n">do</span> <span class="p">{</span> <span class="nb">puts</span> <span class="s1">&#39;bar&#39;</span> <span class="p">}</span>
186
+ <span class="s1">&#39;caps ctrl&#39;</span><span class="o">.</span><span class="n">do</span> <span class="p">{</span> <span class="nb">puts</span> <span class="s1">&#39;bar&#39;</span> <span class="p">}</span>
187
+ <span class="c1"># Hotkey conditions</span>
188
+ <span class="s1">&#39;f1&#39;</span><span class="o">.</span><span class="n">do</span><span class="p">(</span> <span class="nb">lambda</span> <span class="p">{</span> <span class="nb">rand</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span> <span class="o">==</span> <span class="mi">1</span> <span class="p">}</span> <span class="p">)</span> <span class="p">{</span> <span class="nb">puts</span> <span class="s1">&#39;win!&#39;</span> <span class="p">}</span>
189
+ <span class="c1"># Fuzzy hotkeys, trigger regardless of other modifiers being pressed</span>
190
+ <span class="s1">&#39;* ctrl b&#39;</span><span class="o">.</span><span class="n">do</span> <span class="p">{</span> <span class="nb">puts</span> <span class="s1">&#39;hi&#39;</span> <span class="p">}</span>
191
+ <span class="c1"># Translations</span>
192
+ <span class="s1">&#39;* caps j&#39;</span><span class="o">.</span><span class="n">translate</span> <span class="s1">&#39;down&#39;</span>
193
+
194
+ <span class="c1"># 3. Gui</span>
195
+ <span class="n">message</span> <span class="s1">&#39;message&#39;</span>
196
+ <span class="n">read</span> <span class="s1">&#39;hi, how are you?&#39;</span> <span class="c1"># Input box</span>
197
+
198
+ <span class="c1"># 4. Keyboard, send keypresses</span>
199
+ type <span class="s1">&#39;hello&#39;</span>
200
+ type <span class="s1">&#39;(ctrl (shift a))&#39;</span> <span class="c1"># Key combinations</span>
201
+
202
+ <span class="c1"># 5. Help and introspection</span>
203
+ <span class="c1"># Prompts you to enter a hotkey and then jumps to its</span>
204
+ <span class="c1"># definition in your text editor.</span>
205
+ <span class="s1">&#39;shift f2&#39;</span><span class="o">.</span><span class="n">do</span> <span class="p">{</span> <span class="no">Rum</span><span class="o">.</span><span class="n">show_hotkey</span> <span class="p">}</span>
206
+
207
+ <span class="c1"># Asks you to enter an arbitrary hotkey and inserts a hotkey</span>
208
+ <span class="c1"># definition snippet.</span>
209
+ <span class="s1">&#39;shift f3&#39;</span><span class="o">.</span><span class="n">do</span> <span class="p">{</span> <span class="no">Rum</span><span class="o">.</span><span class="n">snippet</span> <span class="p">}</span>
210
+
211
+ <span class="c1"># Restarts Rum.</span>
212
+ <span class="s1">&#39;shift f1&#39;</span><span class="o">.</span><span class="n">do</span> <span class="p">{</span> <span class="no">Rum</span><span class="o">.</span><span class="n">restart</span> <span class="p">}</span>
213
+
214
+
215
+ <span class="c1"># 6. Integrate external features</span>
216
+ <span class="no">Gui</span><span class="o">.</span><span class="n">use</span> <span class="no">Gui</span><span class="o">::</span><span class="no">Growl</span>
217
+
218
+ <span class="c1"># Set up a text-editor for opening files</span>
219
+ require <span class="s1">&#39;rum/apps&#39;</span>
220
+ <span class="no">Gui</span><span class="o">.</span><span class="n">use</span> <span class="no">Textmate</span><span class="p">,</span> <span class="ss">:open_file</span>
221
+ <span class="c1"># Or</span>
222
+ <span class="no">Gui</span><span class="o">.</span><span class="n">use</span> <span class="no">Emacs</span><span class="p">,</span> <span class="ss">:open_file</span>
223
+
224
+ <span class="c1"># 7. Start the server. You can now connect to the</span>
225
+ <span class="c1"># Rum process via rum-client.</span>
226
+ <span class="no">Rum</span><span class="o">::</span><span class="no">Server</span><span class="o">.</span><span class="n">start</span>
227
+
228
+ <span class="c1"># 8. Start rum</span>
229
+ <span class="no">Rum</span><span class="o">.</span><span class="n">start</span>
230
+ </pre></div>
231
+
232
+ </div>
233
+ <a name='reference'>
234
+ <h1>Reference</h1>
235
+ </a>
236
+ <p>
237
+ This section is also available as a Ruby source file and can be
238
+ conveniently viewed in a text editor.<br />
239
+ Call <span class="code">Rum.reference</span> or manually open
240
+ <span class="code">rum_dir/doc/reference.rb</span>.
241
+ </p>
242
+ </div>
243
+ </div>
244
+ <div id='reference_wrapper'><div id="table_of_contents"><h1>Chapters</h1><ul><li><a href="#chapter_1">1. Unicode</a></li><li><a href="#chapter_2">2. Layouts</a></li><li><a href="#chapter_3">2. Hotkeys</a></li><li><a href="#chapter_4">3. Keyboard</a></li><li><a href="#chapter_5">3. Gui</a></li><li><a href="#chapter_6">4. Get selected text</a></li><li><a href="#chapter_7">5. Clipboard</a></li><li><a href="#chapter_8">6. More methods</a></li><li><a href="#chapter_9">6. Rum's threading model</a></li><li><a href="#chapter_10">5. Help, introspection</a></li><li><a href="#chapter_11">5. Restarting, server</a></li><li><a href="#chapter_12">6. Windows</a></li><li><a href="#chapter_13">7. Apps</a></li></ul></div>
245
+ <div class="chapter">
246
+ <a name="chapter_1"><h1>1. Unicode</h1></a>
247
+
248
+ <p>Rum is unicode-compatible. The default encoding is UTF-8.</p>
249
+ </div>
250
+ <div class="chapter">
251
+ <a name="chapter_2"><h1>2. Layouts</h1></a>
252
+
253
+ <p>Keyboard layout changes must take place before any hotkey definitions.<br /><br />Rum starts with a default QWERTY layout</p>
254
+ <pre class="highlight"><span class="no">Rum</span><span class="o">.</span><span class="n">layout</span> <span class="c1">#=&gt; #&lt;Rum::Layout:0xb99634 ... &gt;</span></pre>
255
+ <p>Changing the layout</p>
256
+ <pre class="highlight"><span class="no">Rum</span><span class="o">.</span><span class="n">layout</span> <span class="o">=</span> <span class="no">Layouts</span><span class="o">.</span><span class="n">german</span></pre>
257
+ <p>Listing available layouts</p>
258
+ <pre class="highlight"><span class="no">Layouts</span><span class="o">.</span><span class="n">list</span></pre>
259
+ <h2>Editing a layout</h2>
260
+ <pre class="highlight"><span class="n">layout</span> <span class="o">=</span> <span class="no">Rum</span><span class="o">.</span><span class="n">layout</span></pre>
261
+ <h3>Adding a modifier.</h3>
262
+ <p>Any key can be a modifier.</p>
263
+ <pre class="highlight"><span class="n">layout</span><span class="o">.</span><span class="n">modifier</span> <span class="s1">&#39;escape&#39;</span></pre>
264
+ <h3>Aliasing</h3>
265
+ <pre class="highlight"><span class="n">layout</span><span class="o">.</span><span class="n">alias</span> <span class="s1">&#39;escape&#39;</span><span class="p">,</span> <span class="s1">&#39;esc&#39;</span></pre>
266
+ <p>The original key...</p>
267
+ <pre class="highlight"><span class="n">layout</span><span class="o">[</span><span class="s1">&#39;escape&#39;</span><span class="o">]</span> <span class="c1">#=&gt; #&lt;Key:escape&gt;</span></pre>
268
+ <p>...can now be referenced by the alias</p>
269
+ <pre class="highlight"><span class="n">layout</span><span class="o">[</span><span class="s1">&#39;esc&#39;</span><span class="o">]</span> <span class="c1">#=&gt; #&lt;Key:escape&gt;</span></pre>
270
+ <h3>Renaming</h3>
271
+ <pre class="highlight"><span class="n">layout</span><span class="o">.</span><span class="n">rename</span> <span class="s1">&#39;escape&#39;</span><span class="p">,</span> <span class="s1">&#39;foo&#39;</span>
272
+ <span class="n">layout</span><span class="o">[</span><span class="s1">&#39;foo&#39;</span><span class="o">]</span> <span class="c1">#=&gt; #&lt;Key:foo&gt;</span></pre>
273
+ <h3>Finding out the name of a key</h3>
274
+ <p>All keyboard activity is reported at the terminal.<br />Switch to the Rum terminal window and press a key.</p>
275
+ <h2>Advanced</h2>
276
+ <h3>Adding a key</h3>
277
+ <p>add name, *aliases, id</p>
278
+ <pre class="highlight"><span class="n">layout</span><span class="o">.</span><span class="n">add</span> <span class="s1">&#39;my-key&#39;</span><span class="p">,</span> <span class="mi">125</span>
279
+ <span class="n">layout</span><span class="o">.</span><span class="n">add</span> <span class="s1">&#39;my-other-key&#39;</span><span class="p">,</span> <span class="s1">&#39;my-alias&#39;</span><span class="p">,</span> <span class="mi">126</span></pre>
280
+ <h3>Remapping</h3>
281
+ <p>Maps multiple key ids to a single key.</p>
282
+ <pre class="highlight"><span class="n">layout</span><span class="o">[</span><span class="s1">&#39;lctrl&#39;</span><span class="o">].</span><span class="n">id</span> <span class="c1">#=&gt; 39</span>
283
+ <span class="n">layout</span><span class="o">[</span><span class="mi">39</span><span class="o">]</span> <span class="c1">#=&gt; #&lt;Key:lctrl&gt;</span></pre>
284
+ <p>remap from*, to</p>
285
+ <pre class="highlight"><span class="n">layout</span><span class="o">.</span><span class="n">remap</span> <span class="s1">&#39;lctrl&#39;</span><span class="p">,</span> <span class="s1">&#39;ctrl&#39;</span>
286
+ <span class="n">layout</span><span class="o">[</span><span class="mi">39</span><span class="o">]</span> <span class="c1">#=&gt; #&lt;Key:ctrl&gt;</span></pre>
287
+ <h3>Core modifiers</h3>
288
+ <p>Core modifiers, unlike standard modifiers, are always passed on to the Operating System.<br />Shift, Ctrl, etc. are core modifiers.</p>
289
+ <pre class="highlight"><span class="n">layout</span><span class="o">.</span><span class="n">core_modifier</span> <span class="s1">&#39;escape&#39;</span> <span class="c1"># Sets a core modifier.</span></pre>
290
+ </div>
291
+ <div class="chapter">
292
+ <a name="chapter_3"><h1>2. Hotkeys</h1></a>
293
+
294
+ <h3>The basics</h3>
295
+ <pre class="highlight"><span class="s1">&#39;modifiers hotkey&#39;</span><span class="o">.</span><span class="n">do</span> <span class="p">{</span> <span class="n">action</span> <span class="p">}</span>
296
+ <span class="s1">&#39;ctrl shift w&#39;</span><span class="o">.</span><span class="n">do</span> <span class="p">{</span> <span class="n">active_window</span><span class="o">.</span><span class="n">close</span> <span class="p">}</span>
297
+ <span class="s1">&#39;f1&#39;</span><span class="o">.</span><span class="n">do</span> <span class="p">{</span> type <span class="s1">&#39;hello&#39;</span> <span class="p">}</span></pre>
298
+ <p>The last statement can be abbreviated:</p>
299
+ <pre class="highlight"><span class="s1">&#39;f1&#39;</span><span class="o">.</span><span class="n">do</span> <span class="s1">&#39;hello&#39;</span></pre>
300
+ <h3>Hotkey conditions</h3>
301
+ <p>Restrict hotkeys to trigger only when certain conditions are met.</p>
302
+ <pre class="highlight"><span class="s1">&#39;hotkey&#39;</span><span class="o">.</span><span class="n">do</span><span class="p">(</span><span class="n">condition</span><span class="p">)</span> <span class="p">{</span> <span class="n">action</span> <span class="p">}</span>
303
+ <span class="s1">&#39;f1&#39;</span><span class="o">.</span><span class="n">do</span><span class="p">(</span> <span class="nb">lambda</span> <span class="p">{</span> <span class="nb">rand</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span> <span class="o">==</span> <span class="mi">1</span> <span class="p">}</span> <span class="p">)</span> <span class="p">{</span> <span class="nb">puts</span> <span class="s1">&#39;win!&#39;</span> <span class="p">}</span></pre>
304
+ <h3>Fuzzy hotkeys</h3>
305
+ <p>The wildcard '*' forces a hotkey to trigger regardless of other modifiers being pressed.</p>
306
+ <pre class="highlight"><span class="s1">&#39;* shift a&#39;</span><span class="o">.</span><span class="n">do</span> <span class="p">{</span> <span class="n">action</span> <span class="p">}</span> <span class="c1"># would be triggered by &#39;ctrl shift option a&#39;</span></pre>
307
+ <p>Normal, non-fuzzy hotkeys take precedence over fuzzy hotkeys.</p>
308
+ <h3>No-Repeat</h3>
309
+ <p>Don't trigger on repetitive key-down events that are spawned when a key is held down for a certain time:</p>
310
+ <pre class="highlight"><span class="s1">&#39;f1&#39;</span><span class="o">.</span><span class="n">do</span><span class="p">(</span><span class="ss">:no_repeat</span><span class="p">)</span> <span class="p">{</span> <span class="n">action</span> <span class="p">}</span></pre>
311
+ <h3>Modifier hotkeys</h3>
312
+ <p>Hotkeys that consist solely of modifiers.</p>
313
+ <pre class="highlight"><span class="s1">&#39;ctrl&#39;</span><span class="o">.</span><span class="n">do</span> <span class="p">{</span> <span class="n">action</span> <span class="p">}</span>
314
+ <span class="s1">&#39;ctrl shift&#39;</span><span class="o">.</span><span class="n">do</span> <span class="p">{</span> <span class="n">action</span> <span class="p">}</span></pre>
315
+ <p>The modifiers used in modifier-only hotkeys can be part of another hotkey.<br />In this case, modifier hotkeys trigger on key-up and only when no other key has been pressed in the meantime.<br />Otherwise, they trigger instantly.<br /><br />Example, assuming 'caps' is a valid modifier:</p>
316
+ <pre class="highlight"><span class="s1">&#39;caps&#39;</span><span class="o">.</span><span class="n">do</span> <span class="p">{</span> <span class="n">action</span> <span class="p">}</span> <span class="c1"># Hotkey 1) - Triggers on key-down.</span>
317
+ <span class="s1">&#39;caps a&#39;</span><span class="o">.</span><span class="n">do</span> <span class="p">{</span> <span class="n">action</span><span class="p">}</span> <span class="c1"># Hotkey 2) - Conflicting hotkey.</span>
318
+ <span class="c1"># Forces hotkey 1) to now trigger on key-up.</span></pre>
319
+ <h3>Translations</h3>
320
+ <p>Translations allow keys or key combinations to act as another key.</p>
321
+ <pre class="highlight"><span class="s1">&#39;ctrl a&#39;</span><span class="o">.</span><span class="n">translate</span> <span class="s1">&#39;up&#39;</span> <span class="c1"># &#39;up&#39; is pressed as soon as &#39;ctrl a&#39; is pressed.</span>
322
+ <span class="c1"># &#39;up&#39; is released when either &#39;ctrl&#39; or &#39;a&#39; are released.</span></pre>
323
+ <p>Translations are usually combined with fuzzy hotkeys</p>
324
+ <pre class="highlight"><span class="s1">&#39;* ctrl a&#39;</span><span class="o">.</span><span class="n">translate</span> <span class="s1">&#39;up&#39;</span> <span class="c1"># would be triggered by e.g. &#39;ctrl shift a&#39;</span></pre>
325
+ <p>Example: Move the 'up' and 'down' cursor keys to the home row</p>
326
+ <pre class="highlight"><span class="s1">&#39;* caps j&#39;</span><span class="o">.</span><span class="n">translate</span> <span class="s1">&#39;down&#39;</span>
327
+ <span class="s1">&#39;* caps k&#39;</span><span class="o">.</span><span class="n">translate</span> <span class="s1">&#39;up&#39;</span></pre>
328
+ <h3>Unregistering and re-registering hotkeys</h3>
329
+ <p>All methods concerned with registering or unregistering hotkeys return actions that can be, again, registered or unregistered.</p>
330
+ <pre class="highlight"><span class="n">action</span> <span class="o">=</span> <span class="s1">&#39;ctrl a&#39;</span><span class="o">.</span><span class="n">do</span> <span class="p">{</span> <span class="n">do_stuff</span> <span class="p">}</span> <span class="c1">#=&gt; #&lt;Rum::Action...&gt;</span>
331
+ <span class="n">action</span><span class="o">.</span><span class="n">unregister</span> <span class="c1">#=&gt; #&lt;Rum::Action...&gt;</span>
332
+ <span class="n">action</span><span class="o">.</span><span class="n">register</span> <span class="c1">#=&gt; #&lt;Rum::Action...&gt;</span></pre>
333
+ <p>Unregistering the conditionless action of a hotkey</p>
334
+ <pre class="highlight"><span class="n">action</span> <span class="o">=</span> <span class="s1">&#39;ctrl a&#39;</span><span class="o">.</span><span class="n">unregister</span></pre>
335
+ <p>Actions with conditions...</p>
336
+ <pre class="highlight"><span class="s1">&#39;ctrl a&#39;</span><span class="o">.</span><span class="n">do</span><span class="p">(</span><span class="n">condition</span><span class="p">)</span> <span class="p">{</span> <span class="n">do_stuff</span> <span class="p">}</span></pre>
337
+ <p>... can't be unregistered this way</p>
338
+ </div>
339
+ <div class="chapter">
340
+ <a name="chapter_4"><h1>3. Keyboard</h1></a>
341
+
342
+ <h2>Caveat: Not yet available on the Mac.</h2>
343
+ <p>Generates keystrokes.</p>
344
+ <pre class="highlight"><span class="no">Keyboard</span><span class="o">.</span><span class="n">type</span> <span class="s1">&#39;hi&#39;</span></pre>
345
+ <p>The 'Keyboard.' prefix can be omitted.</p>
346
+ <pre class="highlight">type <span class="s1">&#39;hello world&#39;</span></pre>
347
+ <p>Some keys have multi-character names or aliases.<br />Wrap them in parentheses.</p>
348
+ <pre class="highlight">type <span class="s1">&#39;foo(tab)bar&#39;</span></pre>
349
+ <p>Pause for a short while between sending characters.</p>
350
+ <pre class="highlight">type <span class="s1">&#39;hello&#39;</span><span class="p">,</span> <span class="ss">:slow</span></pre>
351
+ <h3>Sending key combinations</h3>
352
+ <p>To send key combinations, enclose multiple keys within parentheses and nest them. (S-expressions!)</p>
353
+ <pre class="highlight">type <span class="s1">&#39;(ctrl (shift hi))&#39;</span> <span class="c1"># sends ctrl-down, shift-down, hi, shift-up, ctrl-up</span></pre>
354
+ <p>Backslash (\) acts as an escape character</p>
355
+ <pre class="highlight">type <span class="s1">&#39;\(&#39;</span> <span class="c1"># sends a (</span></pre>
356
+ <h3>Send string literally, without syntax interpretation</h3>
357
+ <pre class="highlight">type<span class="o">!</span> <span class="s1">&#39;(in brackets)&#39;</span></pre>
358
+ <h3>Translations</h3>
359
+ <p>Some keys are translated into key combinations.</p>
360
+ <pre class="highlight">type <span class="s1">&#39;A&#39;</span> <span class="c1"># sends &#39;(shift a)&#39;</span></pre>
361
+ <p>See Rum.layout.translations</p>
362
+ <h3>Sending single keyboard events</h3>
363
+ <pre class="highlight"><span class="no">System</span><span class="o">.</span><span class="n">keydown</span> <span class="s1">&#39;a&#39;</span>
364
+ <span class="no">System</span><span class="o">.</span><span class="n">keyup</span> <span class="s1">&#39;a&#39;</span></pre>
365
+ <p>In a future release, this might be integrated into the main keyboard syntax, like:</p>
366
+ <pre class="highlight">type <span class="s1">&#39;(keydown a)&#39;</span></pre>
367
+ <h3>Auto-release</h3>
368
+ <p>Pressed core modifiers are released before keyboard input is generated.<br />You can safely do the following:</p>
369
+ <pre class="highlight"><span class="s1">&#39;ctrl a&#39;</span><span class="o">.</span><span class="n">do</span> <span class="p">{</span> type <span class="s1">&#39;w&#39;</span> <span class="p">}</span> <span class="c1"># &#39;ctrl&#39; gets released before &#39;w&#39; is sent.</span></pre>
370
+ <p>Provide the :blind flag to bypass auto-releasing</p>
371
+ <pre class="highlight"><span class="s1">&#39;ctrl a&#39;</span><span class="o">.</span><span class="n">do</span> <span class="p">{</span> type <span class="s1">&#39;w&#39;</span><span class="p">,</span> <span class="ss">:blind</span> <span class="p">}</span> <span class="c1"># &#39;ctrl&#39; might still be pressed when &#39;w&#39; is sent.</span></pre>
372
+ <h3>Windows-specific: Extended keys</h3>
373
+ <p>Sends 'alt' with the 'extended' flag set.</p>
374
+ <pre class="highlight">type <span class="s1">&#39;(alt-extended)&#39;</span></pre>
375
+ </div>
376
+ <div class="chapter">
377
+ <a name="chapter_5"><h1>3. Gui</h1></a>
378
+
379
+ <h3>Messages</h3>
380
+ <p>Prints a non-disruptive notification when Growl is enabled, falls back to alert (see below) otherwise</p>
381
+ <pre class="highlight"><span class="n">message</span> <span class="s1">&#39;text&#39;</span>
382
+ <span class="n">message</span> <span class="s1">&#39;text&#39;</span><span class="p">,</span> <span class="s1">&#39;title&#39;</span></pre>
383
+ <p>Sticky: Keep the message from fading out after a few seconds</p>
384
+ <pre class="highlight"><span class="n">message</span> <span class="s1">&#39;hello&#39;</span><span class="p">,</span> <span class="ss">:sticky</span></pre>
385
+ <p>Callback: Do something when the user clicked on the message</p>
386
+ <pre class="highlight"><span class="n">message</span><span class="p">(</span><span class="s1">&#39;click me&#39;</span><span class="p">)</span> <span class="p">{</span> <span class="n">message</span> <span class="s1">&#39;clicked!&#39;</span> <span class="p">}</span></pre>
387
+ <h3>Alerts</h3>
388
+ <p>Shows a focus-stealing 'ok, cancel' message box, prompting for a response</p>
389
+ <pre class="highlight"><span class="n">alert</span> <span class="s1">&#39;message&#39;</span> <span class="c1"># returns true or false</span>
390
+ <span class="n">alert</span> <span class="s1">&#39;message&#39;</span><span class="p">,</span> <span class="s1">&#39;title&#39;</span></pre>
391
+ <h3>Input boxes</h3>
392
+ <pre class="highlight"><span class="n">read</span> <span class="c1"># returns the response or an empty string</span>
393
+ <span class="n">read</span> <span class="s1">&#39;hi, how are you?&#39;</span>
394
+ <span class="n">read</span> <span class="n">default</span><span class="p">:</span> <span class="s1">&#39;default input&#39;</span>
395
+ <span class="n">read</span> <span class="s1">&#39;hi, how are you?&#39;</span><span class="p">,</span> <span class="n">default</span><span class="p">:</span> <span class="s1">&#39;splendid&#39;</span><span class="p">,</span> <span class="n">title</span><span class="p">:</span> <span class="s1">&#39;greeting&#39;</span></pre>
396
+ <h3>Choose from candidates</h3>
397
+ <p>This one should launch a quicksilver-like fuzzy selection Gui.</p>
398
+ <pre class="highlight"><span class="n">choose</span> <span class="s1">&#39;choose one&#39;</span><span class="p">,</span> <span class="o">[</span><span class="s1">&#39;red&#39;</span><span class="p">,</span> <span class="s1">&#39;blue&#39;</span><span class="p">,</span> <span class="s1">&#39;yellow&#39;</span><span class="o">]</span></pre>
399
+ <p>TODO: Currently this is only supported via Emacs/Ido.<br />Falls back to an ugly combobox for non Emacs users.<br />Which selection GUIs are there already on the Mac and on Windows that could be harnessed?<br /><br />TODO: Emacs</p>
400
+ <pre class="highlight"><span class="no">Gui</span><span class="o">.</span><span class="n">use</span> <span class="no">Gui</span><span class="o">::</span><span class="no">EmacsInteraction</span></pre>
401
+ <h3>Open (text) files</h3>
402
+ <pre class="highlight"><span class="n">open_file</span> <span class="n">path</span></pre>
403
+ <p>Using a text editor ...</p>
404
+ <pre class="highlight"><span class="no">Gui</span><span class="o">.</span><span class="n">use</span> <span class="no">Textmate</span><span class="p">,</span> <span class="ss">:open_file</span>
405
+ <span class="no">Gui</span><span class="o">.</span><span class="n">use</span> <span class="no">Emacs</span><span class="p">,</span> <span class="ss">:open_file</span></pre>
406
+ <p>... enables jumping to a specific line</p>
407
+ <pre class="highlight"><span class="n">open_file</span> <span class="s1">&#39;foo.txt&#39;</span><span class="p">,</span> <span class="mi">24</span></pre>
408
+ <p>You may re-define open_file to fit your specific needs.</p>
409
+ <h3>Open URLs</h3>
410
+ <pre class="highlight"><span class="n">browse</span> <span class="s1">&#39;example.com&#39;</span> <span class="c1"># HTTP is implicit, unless another protocol is specified</span></pre>
411
+ <h3>Show directories or files in your file manager</h3>
412
+ <pre class="highlight"><span class="n">goto</span> <span class="s1">&#39;foo&#39;</span></pre>
413
+ <h3>Gui Module</h3>
414
+ <p>The above methods are part of the Gui module and may also be called explicitly:</p>
415
+ <pre class="highlight"><span class="no">Gui</span><span class="o">.</span><span class="n">message</span>
416
+ <span class="no">Gui</span><span class="o">.</span><span class="n">read</span>
417
+ <span class="o">.</span><span class="n">.</span><span class="o">.</span></pre>
418
+ </div>
419
+ <div class="chapter">
420
+ <a name="chapter_6"><h1>4. Get selected text</h1></a>
421
+
422
+ <h2>Caveat: Not yet available on the Mac.</h2>
423
+ <p>Grabs the currently selected text.</p>
424
+ <pre class="highlight"><span class="n">get_selection</span> <span class="c1"># returns the current selection or nil</span></pre>
425
+ </div>
426
+ <div class="chapter">
427
+ <a name="chapter_7"><h1>5. Clipboard</h1></a>
428
+
429
+ <h2>Caveat: Not yet available on the Mac.</h2>
430
+ <p>Retrieves the clipboard contents as text.</p>
431
+ <pre class="highlight"><span class="no">Clipboard</span><span class="o">.</span><span class="n">get</span> <span class="c1"># Always returns a string</span></pre>
432
+ <p>Sets the clipboard.</p>
433
+ <pre class="highlight"><span class="no">Clipboard</span><span class="o">.</span><span class="n">set</span> <span class="s1">&#39;hello&#39;</span></pre>
434
+ <p>Sends a 'copy to clipboard' keyboard shortcut and waits until the clipboard changes.</p>
435
+ <pre class="highlight"><span class="no">Clipboard</span><span class="o">.</span><span class="n">copy</span> <span class="c1"># returns true if successful</span></pre>
436
+ <p>Sends a 'paste' keyboard shortcut.</p>
437
+ <pre class="highlight"><span class="no">Clipboard</span><span class="o">.</span><span class="n">paste</span></pre>
438
+ <p>Append the result of get_selection as a new line to the current clipboard content.</p>
439
+ <pre class="highlight"><span class="no">Clipboard</span><span class="o">.</span><span class="n">get</span> <span class="c1">#=&gt; &quot;foo&quot;</span>
440
+ <span class="no">Clipboard</span><span class="o">.</span><span class="n">append</span>
441
+ <span class="no">Clipboard</span><span class="o">.</span><span class="n">get</span> <span class="c1">#=&gt; &quot;foo\nbar&quot;, assuming &#39;bar&#39; was selected.</span></pre>
442
+ <p>Run a block while preserving the clipboard contents.</p>
443
+ <pre class="highlight"><span class="no">Clipboard</span><span class="o">.</span><span class="n">set</span> <span class="s1">&#39;foo&#39;</span>
444
+ <span class="no">Clipboard</span><span class="o">.</span><span class="n">preserve</span> <span class="p">{</span> <span class="no">Clipboard</span><span class="o">.</span><span class="n">set</span> <span class="s1">&#39;bar&#39;</span> <span class="p">}</span>
445
+ <span class="no">Clipboard</span><span class="o">.</span><span class="n">get</span> <span class="c1">#=&gt; &quot;foo&quot;</span></pre>
446
+ </div>
447
+ <div class="chapter">
448
+ <a name="chapter_8"><h1>6. More methods</h1></a>
449
+
450
+ <h3>Waiting</h3>
451
+ <p>Wait until condition is true. Times out after 5 seconds, updates every 0.01 seconds.</p>
452
+ <pre class="highlight"><span class="n">wait</span> <span class="p">{</span> <span class="n">condition</span> <span class="p">}</span> <span class="c1">#=&gt; False when timed-out. Otherwise: true</span></pre>
453
+ <p>Set a 10 second timeout and a 0.5 second update interval.</p>
454
+ <pre class="highlight"><span class="n">wait</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="mi">0</span><span class="o">.</span><span class="mi">5</span><span class="p">)</span> <span class="p">{</span> <span class="n">my_window</span><span class="o">.</span><span class="n">active?</span> <span class="p">}</span></pre>
455
+ <h3>Run a command in a separate terminal window.</h3>
456
+ <pre class="highlight"><span class="n">spawn_in_terminal</span> <span class="n">command</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span>
457
+ <span class="n">spawn_in_terminal</span> <span class="s1">&#39;ruby&#39;</span><span class="p">,</span> <span class="s1">&#39;-e&#39;</span><span class="p">,</span> <span class="s1">&#39;puts Time.now&#39;</span></pre>
458
+ <p>Close the window if the command exits without errors.</p>
459
+ <pre class="highlight"><span class="n">spawn_in_terminal</span> <span class="s1">&#39;ruby&#39;</span><span class="p">,</span> <span class="s1">&#39;-e&#39;</span><span class="p">,</span> <span class="s1">&#39;puts &quot;Hello!&quot;; sleep 2&#39;</span><span class="p">,</span> <span class="ss">:close_if_successful</span></pre>
460
+ <h3>Open documents, run programs</h3>
461
+ <p>Wraps the 'open' command on the Mac and ShellExecute on Windows.</p>
462
+ <pre class="highlight"><span class="n">start</span> <span class="n">file</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span></pre>
463
+ <h3>Applescript</h3>
464
+ <pre class="highlight"><span class="n">applescript</span> <span class="s1">&#39;tell application &quot;System Events&quot;</span>
465
+ <span class="s1"> activate</span>
466
+ <span class="s1"> display dialog &quot;Hello!&quot;</span>
467
+ <span class="s1"> end tell&#39;</span></pre>
468
+ <p>The last three methods are part of the System module and may be called explicitly:</p>
469
+ <pre class="highlight"><span class="no">System</span><span class="o">.</span><span class="n">spawn_in_terminal</span>
470
+ <span class="no">System</span><span class="o">.</span><span class="n">start</span>
471
+ <span class="no">System</span><span class="o">.</span><span class="n">applescript</span></pre>
472
+ </div>
473
+ <div class="chapter">
474
+ <a name="chapter_9"><h1>6. Rum's threading model</h1></a>
475
+
476
+ <p>Rum employs one worker thread that executes all hotkey actions sequentially.<br />Errors during execution are automatically reported via Gui.message.<br /><br />If you have a long running action that may run in parallel with other actions call 'Rum.switch_worker_thread'. Action execution is then resumed on another thread.</p>
477
+ <pre class="highlight"><span class="s1">&#39;ctrl a&#39;</span><span class="o">.</span><span class="n">do</span> <span class="p">{</span> <span class="no">Rum</span><span class="o">.</span><span class="n">switch_worker_thread</span><span class="p">;</span> <span class="n">long_running_stuff</span> <span class="p">}</span></pre>
478
+ <p>The following is also possible...</p>
479
+ <pre class="highlight"><span class="s1">&#39;ctrl a&#39;</span><span class="o">.</span><span class="n">do</span> <span class="p">{</span> <span class="no">Thread</span><span class="o">.</span><span class="n">new</span> <span class="p">{</span> <span class="n">long_running_stuff</span> <span class="p">}</span> <span class="p">}</span></pre>
480
+ <p>... but errors in 'long_running_stuff' won't be implicitly caught and reported by Rum.<br /><br />When you call Gui.read, Gui.alert or Gui.print then Rum.switch_worker_thread is automatically run.</p>
481
+ </div>
482
+ <div class="chapter">
483
+ <a name="chapter_10"><h1>5. Help, introspection</h1></a>
484
+
485
+ <p>Prompts you to enter a hotkey and then jumps to its definition via Gui.open_file.</p>
486
+ <pre class="highlight"><span class="no">Rum</span><span class="o">.</span><span class="n">show_hotkey</span></pre>
487
+ <p>(Requires you to register your text-editor, see Gui.open_file above.)<br /><br />Asks you to enter an arbitrary hotkey and inserts a hotkey definition snippet via Keyboard.type.<br />When 'shift a' is pressed, 'shift a'.do { } is inserted.</p>
488
+ <pre class="highlight"><span class="no">Rum</span><span class="o">.</span><span class="n">snippet</span></pre>
489
+ <p>Reads a hotkey and passes it to the block.<br />(Internally used by Rum.snippet)</p>
490
+ <pre class="highlight"><span class="no">Rum</span><span class="o">.</span><span class="n">read_key</span> <span class="p">{</span> <span class="o">|</span><span class="n">hotkey</span><span class="o">|</span> <span class="n">do_stuff_with</span> <span class="n">hotkey</span> <span class="p">}</span></pre>
491
+ <p>Shows information about windows as they become active.</p>
492
+ <pre class="highlight"><span class="no">WindowInfo</span><span class="o">.</span><span class="n">start</span></pre>
493
+ <p>Opens this reference in a text editor</p>
494
+ <pre class="highlight"><span class="no">Rum</span><span class="o">.</span><span class="n">reference</span></pre>
495
+ </div>
496
+ <div class="chapter">
497
+ <a name="chapter_11"><h1>5. Restarting, server</h1></a>
498
+
499
+ <p>Restart the current Rum configuration.</p>
500
+ <pre class="highlight"><span class="no">Rum</span><span class="o">.</span><span class="n">restart</span></pre>
501
+ <p>Start the server. This allows for connections to the Rum process via rum-client.</p>
502
+ <pre class="highlight"><span class="no">Rum</span><span class="o">::</span><span class="no">Server</span><span class="o">.</span><span class="n">start</span></pre>
503
+ </div>
504
+ <div class="chapter">
505
+ <a name="chapter_12"><h1>6. Windows</h1></a>
506
+
507
+ <h2>Caveat: Not yet available on the Mac.</h2>
508
+ <h3>Retrieving windows</h3>
509
+ <pre class="highlight"><span class="n">active_window</span> <span class="c1">#=&gt; #&lt;Rum::System::Window...&gt;</span></pre>
510
+ <p>Traversing all active windows:</p>
511
+ <pre class="highlight"><span class="n">active_windows</span> <span class="c1">#=&gt; #&lt;Enumerator:...&gt;</span>
512
+ <span class="n">active_windows</span><span class="o">.</span><span class="n">each</span> <span class="p">{</span> <span class="o">|</span><span class="n">window</span><span class="o">|</span> <span class="n">window</span><span class="o">.</span><span class="n">close</span> <span class="k">if</span> <span class="n">window</span><span class="o">.</span><span class="n">title</span><span class="o">.</span><span class="n">empty?</span> <span class="p">}</span>
513
+ <span class="n">active_windows</span><span class="o">.</span><span class="n">map</span> <span class="o">&amp;</span><span class="ss">:title</span></pre>
514
+ <h3>Window Matchers</h3>
515
+ <p>WindowMatchers serve as a shorthand for using active_windows.find:</p>
516
+ <pre class="highlight"><span class="n">matcher</span> <span class="o">=</span> <span class="no">Window</span><span class="o">[</span><span class="n">title</span><span class="p">:</span><span class="sr"> /ruby/</span><span class="p">,</span> <span class="n">class_name</span><span class="p">:</span> <span class="s1">&#39;MozillaUIWindowClass&#39;</span><span class="o">]</span></pre>
517
+ <p>or shorter:</p>
518
+ <pre class="highlight"><span class="n">matcher</span> <span class="o">=</span> <span class="no">Window</span><span class="o">[/</span><span class="n">ruby</span><span class="o">/</span><span class="p">,</span> <span class="s1">&#39;MozillaUIWindowClass&#39;</span><span class="o">]</span>
519
+ <span class="n">matcher</span> <span class="c1">#=&gt; #&lt;Rum::System::WindowMatcher...&gt;</span>
520
+ <span class="n">matcher</span><span class="o">.</span><span class="n">find</span> <span class="c1">#=&gt; #&lt;Rum::System::Window...&gt;</span>
521
+ <span class="no">Window</span><span class="o">[</span><span class="n">class_name</span><span class="p">:</span> <span class="s1">&#39;Emacs&#39;</span><span class="o">].</span><span class="n">find</span></pre>
522
+ <p>The first matching window is returned.<br />WindowMatcher attributes differ between platforms.<br />The Windows version shown here supports 'title' and 'class_name'.<br />String arguments are checked for equality with the corresponding window attributes, Regex arguments require a match.</p>
523
+ <h3>Window objects</h3>
524
+ <pre class="highlight"><span class="n">w</span> <span class="o">=</span> <span class="n">active_window</span> <span class="c1">#=&gt; #&lt;Rum::System::Window:...&gt;</span>
525
+ <span class="n">w</span> <span class="o">==</span> <span class="n">active_window</span> <span class="c1">#=&gt; true</span>
526
+ <span class="n">w</span><span class="o">.</span><span class="n">show</span> <span class="c1"># returns true if successful</span>
527
+ <span class="n">w</span><span class="o">.</span><span class="n">minimize</span>
528
+ <span class="n">w</span><span class="o">.</span><span class="n">maximize</span>
529
+ <span class="n">w</span><span class="o">.</span><span class="n">toggle_always_on_top</span>
530
+ <span class="n">w</span><span class="o">.</span><span class="n">title</span> <span class="c1">#=&gt; &quot;A window title&quot;</span>
531
+ <span class="n">w</span><span class="o">.</span><span class="n">class_name</span> <span class="c1">#=&gt; &quot;Chrome_WidgetWin_0&quot;</span>
532
+ <span class="n">w</span><span class="o">.</span><span class="n">close</span>
533
+ <span class="n">w</span><span class="o">.</span><span class="n">kill_task</span> <span class="c1"># kills the task associated with the window</span></pre>
534
+ </div>
535
+ <div class="chapter">
536
+ <a name="chapter_13"><h1>7. Apps</h1></a>
537
+
538
+ <p>Integrates prominent applications into Rum.</p>
539
+ <pre class="highlight">require <span class="s1">&#39;rum/apps&#39;</span></pre>
540
+ <h3>App objects</h3>
541
+ <pre class="highlight"><span class="n">app</span> <span class="o">=</span> <span class="no">Emacs</span> <span class="c1">#=&gt; #&lt;Rum::App:...&gt;</span></pre>
542
+ <p>Start app or bring it to the front when it's already running.<br />This works for all apps.<br />Returns true when the app could be activated instantly.</p>
543
+ <pre class="highlight"><span class="n">app</span><span class="o">.</span><span class="n">activate</span> <span class="c1">#=&gt; true</span></pre>
544
+ <h3>Emacs</h3>
545
+ <pre class="highlight"><span class="no">Emacs</span><span class="o">.</span><span class="n">eval</span> <span class="s1">&#39;(message &quot;hi&quot;)&#39;</span> <span class="c1">#=&gt; &quot;\&quot;hi\&quot;&quot;</span>
546
+ <span class="no">Emacs</span><span class="o">.</span><span class="n">eval</span> <span class="s1">&#39;(* 3 3)&#39;</span> <span class="c1">#=&gt; &quot;9&quot;</span></pre>
547
+ <p>Eval in the current buffer context.</p>
548
+ <pre class="highlight"><span class="no">Emacs</span><span class="o">.</span><span class="n">eval_in_user_buffer</span> <span class="o">=</span> <span class="kp">true</span>
549
+ <span class="no">Emacs</span><span class="o">.</span><span class="n">eval</span> <span class="s1">&#39;default-directory&#39;</span> <span class="c1">#=&gt; &quot;~/current_buffer_dir/&quot;</span>
550
+ <span class="no">Emacs</span><span class="o">.</span><span class="n">eval</span> <span class="s1">&#39;(idle-highlight-mode t)&#39;</span> <span class="c1"># Turns on a minor mode in the current buffer.</span></pre>
551
+ <p>Set this on Windows to allow Emacs.activate to start Emacs when it's not running.</p>
552
+ <pre class="highlight"><span class="no">Emacs</span><span class="o">.</span><span class="n">path</span> <span class="o">=</span> <span class="s1">&#39;path/to/runemacs&#39;</span></pre>
553
+ </div>
554
+ </div>
555
+ <div id='development'>
556
+ <a name='development'>
557
+ <h1>Development</h1>
558
+ </a>
559
+ <p>
560
+ Patches and suggestions are most appreciated.
561
+ </p>
562
+ <p>
563
+ There's a <a href="https://github.com/nonsequitur/rum-dev/blob/master/rum-development.org">low-ceremony
564
+ to-do list</a> to coordinate the development
565
+ of larger-scale features.<br />
566
+ Feel free to have a look if you're interested in contributing.
567
+ </p>
568
+ <h2>Building</h2>
569
+ <p>
570
+ <span class='code'>rake build</span>
571
+ builds the extension and the document.
572
+ </p>
573
+ <p>
574
+ <span class='code'>rake ext</span>
575
+ builds just the extension.
576
+ </p>
577
+ <p>
578
+ <span class='code'>rake doc</span>
579
+ builds this document. Requires Pygments.
580
+ </p>
581
+ <h3>Mac specifics:</h3>
582
+ <p>
583
+ XCode required.
584
+ </p>
585
+ <h3>Windows specifics:</h3>
586
+ <p>
587
+ Visual Studio required. (Out-of-the-box MinGW support coming soon.)
588
+ </p>
589
+ <p>
590
+ You need to setup the Visual Studio build environment before running the rake commands.<br />Call <span class="code">"%programfiles%\Microsoft Visual Studio 9.0\VC\vcvarsall.bat" x86</span> from your Windows terminal.
591
+ </p>
592
+ <p>
593
+ You might have to delete the following lines from <span class="code">ruby_dir/include/ruby-1.9.x/i386-mswin32/ruby/config.h</span> to work around a compiler error:
594
+ <pre>#if _MSC_VER != 1200
595
+ #error MSC version unmatch: _MSC_VER: 1200 is expected.
596
+ #endif</pre>
597
+ </p>
598
+ <div id='footer'></div>
599
+ </div>
600
+ </div>
601
+ </body>
602
+ </html>