capitate 0.2.11 → 0.2.13

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 (52) hide show
  1. data/History.txt +9 -0
  2. data/Manifest.txt +11 -1
  3. data/lib/capitate/cap_ext/connections.rb +15 -8
  4. data/lib/capitate/cap_ext/run_via.rb +2 -0
  5. data/lib/capitate/cap_ext/variables.rb +9 -2
  6. data/lib/capitate/plugins/base.rb +17 -12
  7. data/lib/capitate/plugins/build.rb +14 -11
  8. data/lib/capitate/plugins/prompt.rb +6 -8
  9. data/lib/capitate/plugins/script.rb +6 -4
  10. data/lib/capitate/plugins/templates.rb +16 -7
  11. data/lib/capitate/plugins/upload.rb +2 -1
  12. data/lib/capitate/plugins/utils.rb +7 -5
  13. data/lib/capitate/task_node.rb +30 -32
  14. data/lib/capitate/version.rb +1 -1
  15. data/lib/recipes/backgroundrb.rb +18 -4
  16. data/lib/recipes/centos/backgroundrb.rb +10 -3
  17. data/lib/recipes/centos/centos.rb +21 -8
  18. data/lib/recipes/centos/imagemagick.rb +4 -1
  19. data/lib/recipes/centos/memcached.rb +26 -8
  20. data/lib/recipes/centos/mongrel_cluster.rb +33 -13
  21. data/lib/recipes/centos/monit.rb +32 -11
  22. data/lib/recipes/centos/mysql.rb +7 -2
  23. data/lib/recipes/centos/nginx.rb +29 -10
  24. data/lib/recipes/centos/ruby.rb +11 -2
  25. data/lib/recipes/centos/sphinx.rb +32 -10
  26. data/lib/recipes/docs.rb +12 -7
  27. data/lib/recipes/logrotate/backgroundrb.rb +25 -0
  28. data/lib/recipes/logrotated.rb +18 -12
  29. data/lib/recipes/memcached.rb +0 -25
  30. data/lib/recipes/monit/backgroundrb.rb +39 -0
  31. data/lib/recipes/monit/memcached.rb +22 -0
  32. data/lib/recipes/{mongrel_cluster.rb → monit/mongrel_cluster.rb} +22 -12
  33. data/lib/recipes/monit/mysql.rb +21 -0
  34. data/lib/recipes/monit/nginx.rb +34 -0
  35. data/lib/recipes/monit/sphinx.rb +29 -0
  36. data/lib/recipes/monit/sshd.rb +27 -0
  37. data/lib/recipes/monit.rb +18 -3
  38. data/lib/recipes/mysql.rb +22 -32
  39. data/lib/recipes/nginx.rb +15 -30
  40. data/lib/recipes/rails.rb +17 -6
  41. data/lib/recipes/sphinx.rb +11 -24
  42. data/lib/recipes/sshd.rb +4 -22
  43. data/lib/recipes/syslogd.rb +4 -0
  44. data/lib/templates/backgroundrb/backgroundrb.monitrc.erb +4 -0
  45. data/lib/templates/backgroundrb/backgroundrb.yml.erb +4 -0
  46. data/website/index.html +10 -2
  47. data/website/javascripts/code_highlighter.js +188 -0
  48. data/website/javascripts/ruby.js +18 -0
  49. data/website/stylesheets/screen.css +116 -23
  50. data/website/template.rhtml +9 -1
  51. data/website/template_recipe.rhtml +12 -1
  52. metadata +13 -3
@@ -0,0 +1,27 @@
1
+ namespace :sshd do
2
+
3
+ namespace :monit do
4
+
5
+ desc <<-DESC
6
+ Install sshd monit hooks.
7
+
8
+ *sshd_port*: SSH daemon port. _Defaults to 22_\n
9
+ *sshd_pid_path*: Path to mysql pid file. _Defaults to /var/run/sshd.pid_\n
10
+ *monit_conf_dir*: Destination for monitrc. _Defaults to "/etc/monit"_\n
11
+
12
+ "Source":#{link_to_source(__FILE__)}
13
+ DESC
14
+ task :install do
15
+
16
+ # Settings
17
+ fetch_or_default(:sshd_port, 3306)
18
+ fetch_or_default(:sshd_pid_path, "/var/run/sshd.pid")
19
+ fetch_or_default(:monit_conf_dir, "/etc/monit")
20
+
21
+ put template.load("sshd/sshd.monitrc.erb", binding), "/tmp/sshd.monitrc"
22
+ run_via "install -o root /tmp/sshd.monitrc #{monit_conf_dir}/sshd.monitrc"
23
+ end
24
+
25
+ end
26
+
27
+ end
data/lib/recipes/monit.rb CHANGED
@@ -5,7 +5,12 @@ namespace :monit do
5
5
 
6
6
  HUP's the process from the pid file, if it exists.
7
7
 
8
- *monit_pid_path*: Path to monit pid file. _Defaults to <tt>/var/run/monit.pid</tt>_
8
+ <dl>
9
+ <dt>monit_pid_path</dt>
10
+ <dd>Path to monit pid file</dd>
11
+ <dd class="default">Defaults to @/var/run/monit.pid@</dd>
12
+ </dl>
13
+ "Source":#{link_to_source(__FILE__)}
9
14
  DESC
10
15
  task :restart do
11
16
  fetch_or_default(:monit_pid_path, "/var/run/monit.pid")
@@ -17,7 +22,12 @@ namespace :monit do
17
22
  desc <<-DESC
18
23
  Unmonitor all.
19
24
 
20
- *monit_bin_path*: Path to monit bin. _Defaults to <tt>monit</tt>_
25
+ <dl>
26
+ <dt>monit_bin_path</dt>
27
+ <dd>Path to monit bin.</dd>
28
+ <dd>Defaults to @monit@</dd>
29
+ </dl>
30
+ "Source":#{link_to_source(__FILE__)}
21
31
  DESC
22
32
  task :unmonitor_all do
23
33
  fetch_or_default(:monit_bin_path, "monit")
@@ -28,7 +38,12 @@ namespace :monit do
28
38
  desc <<-DESC
29
39
  Monitor all.
30
40
 
31
- *monit_bin_path*: Path to monit bin. _Defaults to <tt>monit</tt>_
41
+ <dl>
42
+ <dt>monit_bin_path</dt>
43
+ <dd>Path to monit bin.</dd>
44
+ <dd>Defaults to @monit@</dd>
45
+ </dl>
46
+ "Source":#{link_to_source(__FILE__)}
32
47
  DESC
33
48
  task :monitor_all do
34
49
  fetch_or_default(:monit_bin_path, "monit")
data/lib/recipes/mysql.rb CHANGED
@@ -1,42 +1,32 @@
1
1
  # Mysql recipes
2
2
  namespace :mysql do
3
3
 
4
- namespace :monit do
4
+ desc <<-DESC
5
+ Create database, database user, and set grant permissions.
5
6
 
6
- desc <<-DESC
7
- Install mysql monit hooks.
7
+ <dl>
8
+ <dt>db_name</dt>
9
+ <dd>Database name (application).</dd>
8
10
 
9
- *mysql_port*: Mysql port. _Defaults to 3306_\n
10
- *mysql_pid_path*: Path to mysql pid file. _Defaults to /var/run/mysqld/mysqld.pid_\n
11
- @set :mysql_pid_path, "/var/run/mysqld/mysqld.pid"@\n
12
- *monit_conf_dir*: Destination for monitrc. _Defaults to "/etc/monit"_\n
13
- @set :monit_conf_dir, "/etc/monit"@\n
14
- DESC
15
- task :install do
16
-
17
- # Settings
18
- fetch_or_default(:mysql_pid_path, "/var/run/mysqld/mysqld.pid")
19
- fetch_or_default(:mysql_port, 3306)
20
- fetch_or_default(:monit_conf_dir, "/etc/monit")
21
-
22
- put template.load("mysql/mysql.monitrc.erb", binding), "/tmp/mysql.monitrc"
23
- run_via "install -o root /tmp/mysql.monitrc #{monit_conf_dir}/mysql.monitrc"
24
- end
25
-
26
- end
11
+ <dt>db_user</dt>
12
+ <dd>Database user (application).</dd>
27
13
 
28
- desc <<-DESC
29
- Create database, database user, and set grant permissions.
14
+ <dt>db_pass</dt>
15
+ <dd>Database password (application).</dd>
16
+
17
+ <dt>mysql_grant_locations</dt>
18
+ <dd>Grant locations. </dd>
19
+ <dd>Defaults to @[ "localhost" ]@</dd>
20
+
21
+ <dt>mysql_grant_priv_type</dt>
22
+ <dd>Grant privilege types.</dd>
23
+ <dd>Defaults to @ALL@</dd>
30
24
 
31
- *db_name*: Database name (application).\n
32
- *db_user*: Database user (application).\n
33
- *db_pass*: Database password (application).\n
34
- *mysql_grant_locations*: Grant locations. _Defaults to localhost_\n
35
- @set :mysql_grant_locations, [ "localhost", "192.168.1.111" ]@\n
36
- *mysql_grant_priv_type*: Grant privilege types. _Defaults to ALL_\n
37
- @set :mysql_grant_priv_type, "ALL"@\n
38
- *mysql_admin_password*: Mysql admin password (to use to connect). Defaults to password prompt.\n
39
- @set :mysql_admin_password, prompt.password('Mysql admin password: '))@
25
+ <dt>mysql_admin_password</dt>
26
+ <dd>Mysql admin password (to use to connect).</dd>
27
+ <dd>Defaults to password prompt.</dd>
28
+ </dl>
29
+ "Source":#{link_to_source(__FILE__)}
40
30
  DESC
41
31
  task :setup, :roles => :db do
42
32
 
data/lib/recipes/nginx.rb CHANGED
@@ -1,40 +1,25 @@
1
1
  # Nginx recipes
2
2
  namespace :nginx do
3
3
 
4
- namespace :monit do
5
-
6
- desc <<-DESC
7
- Install nginx monit hooks.
8
-
9
- *nginx_pid_path*: Path to nginx pid file. _Defaults to /var/run/nginx.pid_\n
10
- @set :nginx_pid_path, "/var/run/nginx.pid"@\n
11
- *monit_conf_dir*: Destination for monitrc. _Defaults to "/etc/monit"_\n
12
- @set :monit_conf_dir, "/etc/monit"@\n
13
- DESC
14
- task :install do
15
-
16
- # Settings
17
- fetch_or_default(:nginx_pid_path, "/var/run/nginx.pid")
18
- fetch_or_default(:monit_conf_dir, "/etc/monit")
19
-
20
- put template.load("nginx/nginx.monitrc.erb", binding), "/tmp/nginx.monitrc"
21
- run_via "install -o root /tmp/nginx.monitrc #{monit_conf_dir}/nginx.monitrc"
22
- end
23
-
24
- end
25
-
26
4
  namespace :mongrel do
27
5
  desc <<-DESC
28
6
  Generate the nginx vhost include (for a mongrel setup).
29
7
 
30
- *mongrel_application*: Mongrel application. _Defaults to <tt>:application</tt>_
31
- *mongrel_size*: Number of mongrels.\n
32
- @set :mongrel_size, 3@\n
33
- *mongrel_port*: Starting port for mongrels.\n
34
- If there are 3 mongrels with port 9000, then instances will be at 9000, 9001, and 9002\n
35
- @set :mongrel_port, 9000@\n
36
- *domain_name*: Domain name for nginx virtual host, (without www prefix).\n
37
- @set :domain_name, "foo.com"@
8
+ <dl>
9
+ <dt>mongrel_application</dt>
10
+ <dd>Mongrel application. _Defaults to <tt>:application</tt>_
11
+
12
+ <dt>mongrel_size</dt>: Number of mongrels.\n
13
+ <dd>@set :mongrel_size, 3@\n
14
+
15
+ <dt>*mongrel_port</dt>
16
+ <dd>Starting port for mongrels. If there are 3 mongrels with port 9000, then instances will be at 9000, 9001, and 9002</dd>
17
+ <dd>@set :mongrel_port, 9000@</dd>
18
+
19
+ <dt>domain_name</dt>: Domain name for nginx virtual host, (without www prefix).</dd>
20
+ <dd>@set :domain_name, "foo.com"@</dd>
21
+ </dl>
22
+ "Source":#{link_to_source(__FILE__)}
38
23
  DESC
39
24
  task :setup do
40
25
 
data/lib/recipes/rails.rb CHANGED
@@ -15,6 +15,8 @@ namespace :rails do
15
15
  *db_socket*: Database socket (can be nil, if you are using host). _Defaults to nil_\n
16
16
  @set :db_socket, "/var/lib/mysql/mysql.sock"@\n
17
17
  *database_yml_template*: Path to database yml erb template. _Defaults to <tt>rails/database.yml.erb</tt>_ (in this GEM)\n
18
+
19
+ "Source":#{link_to_source(__FILE__)}
18
20
  DESC
19
21
  task :setup, :roles => :app do
20
22
 
@@ -49,8 +51,11 @@ namespace :rails do
49
51
  namespace :logs do
50
52
 
51
53
  desc <<-DESC
52
- Tail production log files.\n
53
- http://errtheblog.com/posts/19-streaming-capistrano
54
+ Tail production log files.
55
+
56
+ "From errtheblog":http://errtheblog.com/posts/19-streaming-capistrano
57
+
58
+ "Source":#{link_to_source(__FILE__)}
54
59
  DESC
55
60
  task :tail, :roles => :web do
56
61
  run "tail -f #{shared_path}/log/production.log" do |channel, stream, data|
@@ -62,8 +67,11 @@ namespace :rails do
62
67
 
63
68
 
64
69
  desc <<-DESC
65
- Check production log files in TextMate.\n
66
- See http://errtheblog.com/posts/19-streaming-capistrano
70
+ Check production log files in TextMate.
71
+
72
+ "From errtheblog":http://errtheblog.com/posts/19-streaming-capistrano
73
+
74
+ "Source":#{link_to_source(__FILE__)}
67
75
  DESC
68
76
  task :mate, :roles => :app do
69
77
 
@@ -87,8 +95,11 @@ namespace :rails do
87
95
  end
88
96
 
89
97
  desc <<-DESC
90
- Remotely console.\n
91
- See http://errtheblog.com/posts/19-streaming-capistrano
98
+ Remotely console.
99
+
100
+ "From errtheblog":http://errtheblog.com/posts/19-streaming-capistrano
101
+
102
+ "Source":#{link_to_source(__FILE__)}
92
103
  DESC
93
104
  task :console, :roles => :app do
94
105
  input = ''
@@ -1,25 +1,6 @@
1
1
  # Sphinx recipes
2
2
  namespace :sphinx do
3
3
 
4
- namespace :monit do
5
-
6
- desc <<-DESC
7
- Create monit configuration for sphinx.\n
8
- *monit_conf_dir*: Destination for monitrc. _Defaults to "/etc/monit"_\n
9
- *sphinx_pid_path*: Location for sphinx pid. _Defaults to "[shared_path]/pids/searchd.pid"_\n
10
- DESC
11
- task :setup do
12
-
13
- # Settings
14
- fetch_or_default(:monit_conf_dir, "/etc/monit")
15
- fetch_or_default(:sphinx_pid_path, "#{shared_path}/pids/searchd.pid")
16
-
17
- put template.load("sphinx/sphinx.monitrc.erb"), "/tmp/sphinx_#{application}.monitrc"
18
- sudo "install -o root /tmp/sphinx_#{application}.monitrc #{monit_conf_dir}/sphinx_#{application}.monitrc"
19
- end
20
-
21
- end
22
-
23
4
  desc <<-DESC
24
5
  Update sphinx for application.
25
6
 
@@ -39,6 +20,7 @@ namespace :sphinx do
39
20
  *sphinx_db_host*: Sphinx DB host. _Defaults to db_host_\n
40
21
  *sphinx_conf_host*: Sphinx DB host to listen on. _Defaults to 127.0.0.1_\n
41
22
 
23
+ "Source":#{link_to_source(__FILE__)}
42
24
  DESC
43
25
  task :update_conf do
44
26
 
@@ -60,11 +42,18 @@ namespace :sphinx do
60
42
  put template.load(sphinx_conf_template), sphinx_conf_path
61
43
  end
62
44
 
45
+ desc "Make symlink for sphinx conf"
46
+ task :update_code do
47
+ run "ln -nfs #{shared_path}/config/sphinx.conf #{release_path}/config/sphinx.conf"
48
+ end
49
+
63
50
  desc <<-DESC
64
51
  Rotate sphinx index for application.
65
52
 
66
53
  *sphinx_prefix*: Location to sphinx install. _Defaults to nil_\n
67
54
  *sphinx_conf*: Location to sphinx conf. _Defaults to "[shared_path]/config/sphinx.conf"_\n
55
+
56
+ "Source":#{link_to_source(__FILE__)}
68
57
  DESC
69
58
  task :rotate_all do
70
59
  fetch_or_default(:sphinx_prefix, nil)
@@ -80,6 +69,8 @@ namespace :sphinx do
80
69
 
81
70
  *sphinx_prefix*: Location to sphinx install. _Defaults to nil_\n
82
71
  *sphinx_conf*: Location to sphinx conf. _Defaults to "[shared_path]/config/sphinx.conf"_\n
72
+
73
+ "Source":#{link_to_source(__FILE__)}
83
74
  DESC
84
75
  task :index_all do
85
76
  fetch_or_default(:sphinx_prefix, nil)
@@ -89,9 +80,5 @@ namespace :sphinx do
89
80
 
90
81
  run "#{indexer_path} --config #{sphinx_conf} --all"
91
82
  end
92
-
93
- desc "Restart sphinx"
94
- task :restart do
95
- sudo "/sbin/service monit restart sphinx_#{application}"
96
- end
83
+
97
84
  end
data/lib/recipes/sshd.rb CHANGED
@@ -1,32 +1,12 @@
1
1
  namespace :sshd do
2
2
 
3
- namespace :monit do
4
-
5
- desc <<-DESC
6
- Install sshd monit hooks.
7
-
8
- *sshd_port*: SSH daemon port. _Defaults to 22_\n
9
- *sshd_pid_path*: Path to mysql pid file. _Defaults to /var/run/sshd.pid_\n
10
- *monit_conf_dir*: Destination for monitrc. _Defaults to "/etc/monit"_\n
11
- DESC
12
- task :install do
13
-
14
- # Settings
15
- fetch_or_default(:sshd_port, 3306)
16
- fetch_or_default(:sshd_pid_path, "/var/run/sshd.pid")
17
- fetch_or_default(:monit_conf_dir, "/etc/monit")
18
-
19
- put template.load("sshd/sshd.monitrc.erb", binding), "/tmp/sshd.monitrc"
20
- run_via "install -o root /tmp/sshd.monitrc #{monit_conf_dir}/sshd.monitrc"
21
- end
22
-
23
- end
24
-
25
3
  desc <<-DESC
26
4
  Create public and private keys for ssh.
27
5
 
28
6
  *ssh_keygen_type*: SSH keygen type. _Defaults to rsa_\n
29
7
  *ssh_keygen_bits*: SSH keygen bits. _Defaults to 2048_\n
8
+
9
+ "Source":#{link_to_source(__FILE__)}
30
10
  DESC
31
11
  task :keygen do
32
12
  # Settings
@@ -56,6 +36,8 @@ namespace :sshd do
56
36
  Add to authorized keys. Uses <tt>.ssh/authorized_keys</tt>.
57
37
 
58
38
  *ssh_public_key*: The public key from ssh:keygen.
39
+
40
+ "Source":#{link_to_source(__FILE__)}
59
41
  DESC
60
42
  task :authorize_key do
61
43
 
@@ -6,6 +6,8 @@ namespace :syslogd do
6
6
  *syslog_program_name*: syslog program name. What you used for <tt>SyslogLogger.new("program_name_here")</tt>\n
7
7
  *syslog_log_path*: Path to log.\n
8
8
  *syslog_conf_path*: Path to syslog conf. _Defaults to <tt>/etc/syslog.conf</tt>_\n
9
+
10
+ "Source":#{link_to_source(__FILE__)}
9
11
  DESC
10
12
  task :setup_conf do
11
13
 
@@ -37,6 +39,8 @@ namespace :syslogd do
37
39
  *newsyslog_size*: Max size. _Defaults to *_\n
38
40
  *newsyslog_when*: When to rotate. _Defaults to @T00_\n
39
41
  *newsyslog_zb*: Whether to gzip or tarball. _Defaults to Z_\n
42
+
43
+ "Source":#{link_to_source(__FILE__)}
40
44
  DESC
41
45
  task :setup_newsyslog_conf do
42
46
 
@@ -0,0 +1,4 @@
1
+ check process backgroundrb_<%= application %> with pidfile <%= backgroundrb_pid_path %>
2
+ start program = "/sbin/service backgroundrb_<%= application %> start"
3
+ stop program = "/sbin/service backgroundrb_<%= application %> stop"
4
+ if failed host 127.0.0.1 port <%= backgroundrb_port %> then restart
@@ -8,3 +8,7 @@
8
8
  :development:
9
9
  :backgroundrb:
10
10
  :log: foreground
11
+
12
+ :production:
13
+ :backgroundrb:
14
+ :lazy_load: true
data/website/index.html CHANGED
@@ -38,7 +38,7 @@
38
38
 
39
39
  <div id="version" class="clickable box" onclick='document.location = "http://rubyforge.org/projects/capitate"; return false'>
40
40
  <p>Get Version</p>
41
- <a href="http://rubyforge.org/projects/capitate" class="numbers">0.2.11</a>
41
+ <a href="http://rubyforge.org/projects/capitate" class="numbers">0.2.13</a>
42
42
  </div>
43
43
 
44
44
  <div id="recipes">
@@ -143,7 +143,15 @@
143
143
  </p>
144
144
  </div>
145
145
 
146
- <!-- insert site tracking codes here, like Google Urchin -->
146
+ <script type="text/javascript">
147
+ var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
148
+ document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
149
+ </script>
150
+ <script type="text/javascript">
151
+ var pageTracker = _gat._getTracker("UA-1286493-6");
152
+ pageTracker._initData();
153
+ pageTracker._trackPageview();
154
+ </script>
147
155
 
148
156
  </body>
149
157
  </html>
@@ -0,0 +1,188 @@
1
+ /* Unobtrustive Code Highlighter By Dan Webb 11/2005
2
+ Version: 0.4
3
+
4
+ Usage:
5
+ Add a script tag for this script and any stylesets you need to use
6
+ to the page in question, add correct class names to CODE elements,
7
+ define CSS styles for elements. That's it!
8
+
9
+ Known to work on:
10
+ IE 5.5+ PC
11
+ Firefox/Mozilla PC/Mac
12
+ Opera 7.23 + PC
13
+ Safari 2
14
+
15
+ Known to degrade gracefully on:
16
+ IE5.0 PC
17
+
18
+ Note: IE5.0 fails due to the use of lookahead in some stylesets. To avoid script errors
19
+ in older browsers use expressions that use lookahead in string format when defining stylesets.
20
+
21
+ This script is inspired by star-light by entirely cunning Dean Edwards
22
+ http://dean.edwards.name/star-light/.
23
+ */
24
+
25
+ // replace callback support for safari.
26
+ if ("a".replace(/a/, function() {return "b"}) != "b") (function(){
27
+ var default_replace = String.prototype.replace;
28
+ String.prototype.replace = function(search,replace){
29
+ // replace is not function
30
+ if(typeof replace != "function"){
31
+ return default_replace.apply(this,arguments)
32
+ }
33
+ var str = "" + this;
34
+ var callback = replace;
35
+ // search string is not RegExp
36
+ if(!(search instanceof RegExp)){
37
+ var idx = str.indexOf(search);
38
+ return (
39
+ idx == -1 ? str :
40
+ default_replace.apply(str,[search,callback(search, idx, str)])
41
+ )
42
+ }
43
+ var reg = search;
44
+ var result = [];
45
+ var lastidx = reg.lastIndex;
46
+ var re;
47
+ while((re = reg.exec(str)) != null){
48
+ var idx = re.index;
49
+ var args = re.concat(idx, str);
50
+ result.push(
51
+ str.slice(lastidx,idx),
52
+ callback.apply(null,args).toString()
53
+ );
54
+ if(!reg.global){
55
+ lastidx += RegExp.lastMatch.length;
56
+ break
57
+ }else{
58
+ lastidx = reg.lastIndex;
59
+ }
60
+ }
61
+ result.push(str.slice(lastidx));
62
+ return result.join("")
63
+ }
64
+ })();
65
+
66
+ var CodeHighlighter = { styleSets : new Array };
67
+
68
+ CodeHighlighter.addStyle = function(name, rules) {
69
+ // using push test to disallow older browsers from adding styleSets
70
+ if ([].push) this.styleSets.push({
71
+ name : name,
72
+ rules : rules,
73
+ ignoreCase : arguments[2] || false
74
+ })
75
+
76
+ function setEvent() {
77
+ // set highlighter to run on load (use LowPro if present)
78
+ if (typeof Event != 'undefined' && typeof Event.onReady == 'function')
79
+ return Event.onReady(CodeHighlighter.init.bind(CodeHighlighter));
80
+
81
+ var old = window.onload;
82
+
83
+ if (typeof window.onload != 'function') {
84
+ window.onload = function() { CodeHighlighter.init() };
85
+ } else {
86
+ window.onload = function() {
87
+ old();
88
+ CodeHighlighter.init();
89
+ }
90
+ }
91
+ }
92
+
93
+ // only set the event when the first style is added
94
+ if (this.styleSets.length==1) setEvent();
95
+ }
96
+
97
+ CodeHighlighter.init = function() {
98
+ if (!document.getElementsByTagName) return;
99
+ if ("a".replace(/a/, function() {return "b"}) != "b") return; // throw out Safari versions that don't support replace function
100
+ // throw out older browsers
101
+
102
+ var codeEls = document.getElementsByTagName("CODE");
103
+ // collect array of all pre elements
104
+ codeEls.filter = function(f) {
105
+ var a = new Array;
106
+ for (var i = 0; i < this.length; i++) if (f(this[i])) a[a.length] = this[i];
107
+ return a;
108
+ }
109
+
110
+ var rules = new Array;
111
+ rules.toString = function() {
112
+ // joins regexes into one big parallel regex
113
+ var exps = new Array;
114
+ for (var i = 0; i < this.length; i++) exps.push(this[i].exp);
115
+ return exps.join("|");
116
+ }
117
+
118
+ function addRule(className, rule) {
119
+ // add a replace rule
120
+ var exp = (typeof rule.exp != "string")?String(rule.exp).substr(1, String(rule.exp).length-2):rule.exp;
121
+ // converts regex rules to strings and chops of the slashes
122
+ rules.push({
123
+ className : className,
124
+ exp : "(" + exp + ")",
125
+ length : (exp.match(/(^|[^\\])\([^?]/g) || "").length + 1, // number of subexps in rule
126
+ replacement : rule.replacement || null
127
+ });
128
+ }
129
+
130
+ function parse(text, ignoreCase) {
131
+ // main text parsing and replacement
132
+ return text.replace(new RegExp(rules, (ignoreCase)?"gi":"g"), function() {
133
+ var i = 0, j = 1, rule;
134
+ while (rule = rules[i++]) {
135
+ if (arguments[j]) {
136
+ // if no custom replacement defined do the simple replacement
137
+ if (!rule.replacement) return "<span class=\"" + rule.className + "\">" + arguments[0] + "</span>";
138
+ else {
139
+ // replace $0 with the className then do normal replaces
140
+ var str = rule.replacement.replace("$0", rule.className);
141
+ for (var k = 1; k <= rule.length - 1; k++) str = str.replace("$" + k, arguments[j + k]);
142
+ return str;
143
+ }
144
+ } else j+= rule.length;
145
+ }
146
+ });
147
+ }
148
+
149
+ function highlightCode(styleSet) {
150
+ // clear rules array
151
+ var parsed, clsRx = new RegExp("(\\s|^)" + styleSet.name + "(\\s|$)");
152
+ rules.length = 0;
153
+
154
+ // get stylable elements by filtering out all code elements without the correct className
155
+ var stylableEls = codeEls.filter(function(item) { return clsRx.test(item.className) });
156
+
157
+ // add style rules to parser
158
+ for (var className in styleSet.rules) addRule(className, styleSet.rules[className]);
159
+
160
+
161
+ // replace for all elements
162
+ for (var i = 0; i < stylableEls.length; i++) {
163
+ // EVIL hack to fix IE whitespace badness if it's inside a <pre>
164
+ if (/MSIE/.test(navigator.appVersion) && stylableEls[i].parentNode.nodeName == 'PRE') {
165
+ stylableEls[i] = stylableEls[i].parentNode;
166
+
167
+ parsed = stylableEls[i].innerHTML.replace(/(<code[^>]*>)([^<]*)<\/code>/i, function() {
168
+ return arguments[1] + parse(arguments[2], styleSet.ignoreCase) + "</code>"
169
+ });
170
+ parsed = parsed.replace(/\n( *)/g, function() {
171
+ var spaces = "";
172
+ for (var i = 0; i < arguments[1].length; i++) spaces+= "&nbsp;";
173
+ return "\n" + spaces;
174
+ });
175
+ parsed = parsed.replace(/\t/g, "&nbsp;&nbsp;&nbsp;&nbsp;");
176
+ parsed = parsed.replace(/\n(<\/\w+>)?/g, "<br />$1").replace(/<br \/>[\n\r\s]*<br \/>/g, "<p><br></p>");
177
+
178
+ } else parsed = parse(stylableEls[i].innerHTML, styleSet.ignoreCase);
179
+
180
+ stylableEls[i].innerHTML = parsed;
181
+ }
182
+ }
183
+
184
+ // run highlighter on all stylesets
185
+ for (var i=0; i < this.styleSets.length; i++) {
186
+ highlightCode(this.styleSets[i]);
187
+ }
188
+ }
@@ -0,0 +1,18 @@
1
+ CodeHighlighter.addStyle("ruby",{
2
+ comment : {
3
+ exp : /#[^\n]+/
4
+ },
5
+ brackets : {
6
+ exp : /\(|\)/
7
+ },
8
+ string : {
9
+ exp : /'[^']*'|"[^"]*"/
10
+ },
11
+ keywords : {
12
+ exp : /\b(do|end|self|class|def|if|module|yield|then|else|for|until|unless|while|elsif|case|when|break|retry|redo|rescue|require|raise)\b/
13
+ },
14
+ /* Added by Shelly Fisher (shelly@agileevolved.com) */
15
+ symbol : {
16
+ exp : /([^:])(:[A-Za-z0-9_!?]+)/
17
+ }
18
+ });