backgroundrb-rails3 1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (126) hide show
  1. data/.autotest +17 -0
  2. data/ChangeLog +50 -0
  3. data/Gemfile +11 -0
  4. data/LICENSE +4 -0
  5. data/MIT-LICENSE +20 -0
  6. data/README +22 -0
  7. data/Rakefile +128 -0
  8. data/TODO.org +5 -0
  9. data/app/controller/backgroundrb_status_controller.rb +6 -0
  10. data/backgroundrb-rails3.gemspec +219 -0
  11. data/config/backgroundrb.yml +11 -0
  12. data/doc/Rakefile +5 -0
  13. data/doc/config.yaml +2 -0
  14. data/doc/content/advanced/advanced.txt +76 -0
  15. data/doc/content/advanced/advanced.yaml +4 -0
  16. data/doc/content/bugs/bugs.txt +20 -0
  17. data/doc/content/bugs/bugs.yaml +5 -0
  18. data/doc/content/community/community.txt +36 -0
  19. data/doc/content/community/community.yaml +5 -0
  20. data/doc/content/content.txt +168 -0
  21. data/doc/content/content.yaml +5 -0
  22. data/doc/content/faq/faq.txt +41 -0
  23. data/doc/content/faq/faq.yaml +5 -0
  24. data/doc/content/rails/rails.txt +182 -0
  25. data/doc/content/rails/rails.yaml +5 -0
  26. data/doc/content/scheduling/scheduling.txt +166 -0
  27. data/doc/content/scheduling/scheduling.yaml +5 -0
  28. data/doc/content/workers/workers.txt +178 -0
  29. data/doc/content/workers/workers.yaml +5 -0
  30. data/doc/layouts/default/default.erb +56 -0
  31. data/doc/layouts/default/default.yaml +4 -0
  32. data/doc/lib/default.rb +7 -0
  33. data/doc/output/Assets/BG-Ad-Top.png +0 -0
  34. data/doc/output/Assets/BG-Body.png +0 -0
  35. data/doc/output/Assets/BG-Feed.png +0 -0
  36. data/doc/output/Assets/BG-Menu-Hover.png +0 -0
  37. data/doc/output/Assets/BG-Menu.png +0 -0
  38. data/doc/output/Assets/BG-Sidebar-Bottom.png +0 -0
  39. data/doc/output/Assets/Button-Feed.png +0 -0
  40. data/doc/output/images/bg-ad-top.png +0 -0
  41. data/doc/output/images/bg-body.png +0 -0
  42. data/doc/output/images/bg-feed.gif +0 -0
  43. data/doc/output/images/bg-footer.jpg +0 -0
  44. data/doc/output/images/bg-header.jpg +0 -0
  45. data/doc/output/images/bg-menu-hover.png +0 -0
  46. data/doc/output/images/bg-menu.png +0 -0
  47. data/doc/output/images/bg-sidebar-bottom.gif +0 -0
  48. data/doc/output/images/button-feed.png +0 -0
  49. data/doc/output/images/icon-comment.png +0 -0
  50. data/doc/output/images/more_icon.gif +0 -0
  51. data/doc/output/style.css +299 -0
  52. data/doc/page_defaults.yaml +13 -0
  53. data/doc/tasks/default.rake +3 -0
  54. data/doc/templates/default/default.txt +1 -0
  55. data/doc/templates/default/default.yaml +4 -0
  56. data/examples/backgroundrb.yml +25 -0
  57. data/examples/foo_controller.rb +48 -0
  58. data/examples/god_worker.rb +7 -0
  59. data/examples/worker_tests/god_worker_test.rb +8 -0
  60. data/examples/workers/error_worker.rb +17 -0
  61. data/examples/workers/foo_worker.rb +38 -0
  62. data/examples/workers/god_worker.rb +7 -0
  63. data/examples/workers/model_worker.rb +13 -0
  64. data/examples/workers/renewal_worker.rb +11 -0
  65. data/examples/workers/rss_worker.rb +26 -0
  66. data/examples/workers/server_worker.rb +31 -0
  67. data/examples/workers/world_worker.rb +12 -0
  68. data/examples/workers/xmpp_worker.rb +7 -0
  69. data/init.rb +7 -0
  70. data/install.rb +1 -0
  71. data/know_issues.org +5 -0
  72. data/lib/backgroundrb.rb +1 -0
  73. data/lib/backgroundrb/bdrb_client_helper.rb +8 -0
  74. data/lib/backgroundrb/bdrb_cluster_connection.rb +156 -0
  75. data/lib/backgroundrb/bdrb_config.rb +43 -0
  76. data/lib/backgroundrb/bdrb_conn_error.rb +29 -0
  77. data/lib/backgroundrb/bdrb_connection.rb +179 -0
  78. data/lib/backgroundrb/bdrb_job_queue.rb +79 -0
  79. data/lib/backgroundrb/bdrb_result.rb +19 -0
  80. data/lib/backgroundrb/bdrb_start_stop.rb +146 -0
  81. data/lib/backgroundrb/rails_worker_proxy.rb +181 -0
  82. data/lib/backgroundrb/railtie.rb +48 -0
  83. data/lib/generators/backgroundrb/bdrb_migration/USAGE +12 -0
  84. data/lib/generators/backgroundrb/bdrb_migration/bdrb_migration_generator.rb +15 -0
  85. data/lib/generators/backgroundrb/bdrb_migration/templates/migration.rb +27 -0
  86. data/lib/generators/backgroundrb/worker/USAGE +16 -0
  87. data/lib/generators/backgroundrb/worker/templates/unit_test.rb +12 -0
  88. data/lib/generators/backgroundrb/worker/templates/worker.rb +7 -0
  89. data/lib/generators/backgroundrb/worker/worker_generator.rb +14 -0
  90. data/lib/tasks/backgroundrb_tasks.rake +103 -0
  91. data/release_notes.org +48 -0
  92. data/release_points.org +46 -0
  93. data/script/backgroundrb +52 -0
  94. data/script/bdrb_test_helper.rb +99 -0
  95. data/script/load_worker_env.rb +31 -0
  96. data/script/monitrc +25 -0
  97. data/server/backgroundrb_server.rb +12 -0
  98. data/server/lib/bdrb_result_storage.rb +62 -0
  99. data/server/lib/bdrb_server_helper.rb +24 -0
  100. data/server/lib/bdrb_thread_pool.rb +127 -0
  101. data/server/lib/cron_trigger.rb +197 -0
  102. data/server/lib/invalid_dump_error.rb +4 -0
  103. data/server/lib/log_worker.rb +25 -0
  104. data/server/lib/master_proxy.rb +140 -0
  105. data/server/lib/master_worker.rb +187 -0
  106. data/server/lib/meta_worker.rb +432 -0
  107. data/server/lib/trigger.rb +34 -0
  108. data/test/bdrb_client_test_helper.rb +5 -0
  109. data/test/bdrb_test_helper.rb +35 -0
  110. data/test/client/backgroundrb.yml +17 -0
  111. data/test/client/test_bdrb_client_helper.rb +13 -0
  112. data/test/client/test_bdrb_cluster_connection.rb +162 -0
  113. data/test/client/test_bdrb_config.rb +20 -0
  114. data/test/client/test_bdrb_connection.rb +29 -0
  115. data/test/client/test_bdrb_job_queue.rb +63 -0
  116. data/test/client/test_worker_proxy.rb +130 -0
  117. data/test/server/test_cron_trigger.rb +281 -0
  118. data/test/server/test_master_proxy.rb +54 -0
  119. data/test/server/test_master_worker.rb +157 -0
  120. data/test/server/test_meta_worker.rb +281 -0
  121. data/test/server/test_result_storage.rb +14 -0
  122. data/test/socket_mocker.rb +34 -0
  123. data/test/workers/bar_worker.rb +10 -0
  124. data/test/workers/foo_worker.rb +10 -0
  125. data/uninstall.rb +1 -0
  126. metadata +345 -0
@@ -0,0 +1,5 @@
1
+ # Built-in
2
+ filters_pre: [ "redcloth" ]
3
+ # Custom
4
+ title: "Rails Integration of BackgrounDRb"
5
+ sidebar_items: [["Introduction", "#introduction"], ["Async Task", "#async_task"], ["Sync Task", "#sync_task"], ["Worker Results", "#worker_results"], ["Persistent Tasks", "#persistent_task"], ["New Worker", "#new_worker"], ["Worker Info", "#worker_info"], ["Clustering", "#clustering"]]
@@ -0,0 +1,166 @@
1
+ <div id="content">
2
+
3
+ %(entry-title)<a name="timer_scheduling"> Timer Based Scheduling </a>%
4
+
5
+ Simple tasks in the workers can be scheduled using @add_timer@ or @add_periodic_timer@ methods.
6
+ For example:
7
+
8
+ <pre class="multiline">class HelloWorker < BackgrounDRb::MetaWorker
9
+ set_worker_name :hello_worker
10
+
11
+ def create(args = nil)
12
+ # time argument is in seconds
13
+ add_periodic_timer(10) { expire_sessions }
14
+ end
15
+
16
+ def expire_sessions
17
+ # expire user sessions
18
+ end
19
+ end </pre>
20
+
21
+ Similarly one can use @add_timer@ to fire oneshot task execution.
22
+
23
+ %(entry-title)<a name="unix_scheduling"> Unix Scheduler </a>%
24
+
25
+ _BackgrounDRb_ supports normal unix styled schedules which can be configured
26
+ from @backgroundrb.yml@ file. A sample configuration looks like:
27
+
28
+ <pre class="multiline">:backgroundrb:
29
+ :ip: 0.0.0.0
30
+ :port: 11006
31
+ :schedules:
32
+ :foo_worker:
33
+ :foobar:
34
+ :trigger_args:
35
+ :start: <%= Time.now + 5.seconds %>
36
+ :end: <%= Time.now + 10.minutes %>
37
+ :repeat_interval: <%= 1.minute %> </pre>
38
+
39
+ Above scheduler option schedules method @foobar@ defined inside @foo_worker@ to start
40
+ executing by 5 seconds delay and stop after 10 minutes. Method should periodically execute
41
+ every 1 minute between that time period. *Never in any scheduling option, you should schedule @create@
42
+ method/task*
43
+
44
+ %(entry-title)<a name="cron_scheduling"> Cron Scheduling </a>%
45
+
46
+ _BackgrounDRb_ also supports Cron based ccheduling.
47
+ You can use a configuration file for cron scheduling of workers. The method specified in the configuration
48
+ file would be called periodically. You should accommodate for the fact that the time gap between periodic
49
+ invocation of a method should be more than the time that is actually required to execute the method.
50
+ If a method takes longer time than the time window specified, your method invocations will lag
51
+ perpetually.
52
+
53
+ A Sample Configuration file for Cron based Scheduling looks like:
54
+
55
+ <pre class="multiline">
56
+ :backgroundrb:
57
+ :ip: 0.0.0.0
58
+ :port: 11006
59
+ :schedules:
60
+ :foo_worker:
61
+ :barbar:
62
+ :trigger_args: */10 * * * * *
63
+ :data: Hello World </pre>
64
+
65
+
66
+ Above scheduler will schedule invocation of @barbar@ method inside @foo_worker@ at every 10 seconds.
67
+ You can also schedule invocation of multiple methods in same worker at different intervals, just use
68
+ following as an example configuration file.
69
+
70
+ <pre class="multiline">
71
+ :backgroundrb:
72
+ :ip: 0.0.0.0
73
+ :port: 11006
74
+ :schedules:
75
+ :foo_worker:
76
+ :barbar:
77
+ :trigger_args: */10 * * * * *
78
+ :data: Hello World
79
+ :some_task: # execute some_method in foo_worker every 2nd hour
80
+ :trigger_args: 0 * */2 * * *
81
+ :data: Hello World </pre>
82
+
83
+
84
+ p(sub-title). A Word about Cron Scheduler
85
+
86
+ Note that the initial field in the BackgrounDRb cron trigger specifies
87
+ seconds, not minutes as with Unix-cron.
88
+
89
+ The fields (which can be an asterisk, meaning all valid patterns) are:
90
+
91
+ <pre class="boxed">sec[0,59] min[0,59], hour[0,23], day[1,31], month[1,12], weekday[0,6], year</pre>
92
+
93
+ The syntax pretty much follows Unix-cron. The following will trigger
94
+ on the first hour and the thirtieth minute every day:
95
+
96
+ <pre class="boxed">0 30 1 * * * *</pre>
97
+
98
+ The following will trigger the specified method every 10 seconds:
99
+
100
+ <pre class="boxed">*/10 * * * * * *</pre>
101
+
102
+ The following will trigger the specified method every 1 hour:
103
+
104
+ <pre class="boxed">0 0 * * * * *</pre>
105
+
106
+ For each field you can use a comma-separated list. The following would
107
+ trigger on the 5th, 16th and 23rd minute every hour:
108
+
109
+ <pre class="boxed"> 5,16,23 * * * * *</pre>
110
+
111
+ Fields also support ranges, using a dash between values. The following
112
+ triggers from 8th through the 17th hour, at five past the hour:
113
+
114
+ <pre class="boxed"> 5 8-17 * * * *</pre>
115
+
116
+ Finally, fields support repeat interval syntax. The following triggers
117
+ every five minutes, every other hour after the sixth hour:
118
+
119
+ <pre class="boxed"> */5 6/2 * * * *</pre>
120
+
121
+ Here is a more complex example: months 0,2,4,5,6,8,10,12, every day
122
+ and hour, minutes 1,2,3,4,6,20, seconds: every 5th second counting
123
+ from the 28th second plus the 59th second:
124
+
125
+
126
+ <pre class="boxed">28/5,59 1-4,6,20 */1 * 5,0/2 * *</pre>
127
+
128
+ Note that if you specify an asterisk in the first field (seconds)
129
+ it will trigger every second for the subsequent match.
130
+
131
+ %(entry-title)<a name="restart_on_schedule"> Restart worker on schedule </a>%
132
+
133
+ Usually when your worker is scheduled to execute at longer intervals, it
134
+ doesn't make sense to have worker around, when its doing nothing. Since, scheduling
135
+ via configuration file requires that your worker must be loaded when _BackgrounDRb_ starts,
136
+ your worker is always around, even when doing nothing.
137
+
138
+ You can reuse worker in processing requests from rails, but if its not possible
139
+ and you rather want worker to start afresh each time, scheduler detects a firetime, you can use
140
+ following syntax to autostart workers on scheduled time:
141
+
142
+ <pre class="multiline">class HelloWorker < BackgrounDRb::MetaWorker
143
+ set_worker_name :hello_worker
144
+ reload_on_schedule true
145
+
146
+ def create(args = nil)
147
+ # this method is called, when worker is loaded for the first time
148
+ end
149
+ end </pre>
150
+
151
+ In above worker @reload_on_schedule true@ makes sure that your worker is restarted on
152
+ scheduled time. This feature is only available in version 1.0.3 onwards.
153
+
154
+ %(entry-title)<a name="schedule_at"> Schedule one shot execution of task at specified time </a>%
155
+
156
+ <p><b> Only available for tasks persisted to database table </b></p>
157
+
158
+ If you are using job queue table and want one shot execution of a task scheduled at a particular time. You can use:
159
+
160
+ <pre class="multiline">MiddleMan(:hello_worker).enq_some_task(:arg => "hello_world",
161
+ :job_key => "boy",:scheduled_at => Time.now + 30.minutes)</pre>
162
+
163
+ Which will schedule specified task to be executed after 30 minutes from now.
164
+
165
+
166
+ </div>
@@ -0,0 +1,5 @@
1
+ # Built-in
2
+ filters_pre: [ "redcloth" ]
3
+ # Custom
4
+ title: "Scheduling Tasks using BackgrounDRb"
5
+ sidebar_items: [["Timers", "#timer_scheduling"], ["Unix Scheduler", "#unix_scheduling"], ["Cron Scheduler", "#cron_scheduling"], ["Restart on Schedule", "#restart_on_schedule"], ["Schedule At", "#schedule_at"]]
@@ -0,0 +1,178 @@
1
+ <div id="content">
2
+
3
+ %(entry-title)<a name="introduction"> Workers </a>%
4
+
5
+ Workers are your building blocks of Asynchronous Task Processing. An empty auto generated worker looks like this:
6
+
7
+ <pre class="multiline">class BillingWorker < BackgrounDRb::MetaWorker
8
+ set_worker_name :billing_worker
9
+ def create(args = nil)
10
+ # method gets called, when new instance of worker is created.
11
+ end
12
+ end </pre>
13
+
14
+ @set_worker_name@ will set the worker name which can be later used while invoking tasks on the worker.
15
+ @create@ method gets called when worker is loaded for the first time. If you are starting your worker
16
+ from rails, you can pass arguments to @create@ method using:
17
+
18
+ <pre class="multiline">MiddleMan.new_worker(:worker => :billing_worker,\
19
+ :worker_key => user_session,:data => current_user.id) </pre>
20
+
21
+ p(sub-title). Using Workers
22
+
23
+ You can invoke random tasks on workers from rails or you can schedule them using config file. Look into
24
+ "Scheduling":/scheduling/index.html section for scheduling and "Rails Integration":/rails/index.html section
25
+ for invoking worker tasks from rails.
26
+
27
+ p(sub-title). Inbuilt instance methods available in your workers:
28
+
29
+ *(content_list) @cache@ : Can be used to store random results from worker which can be later retrieved from rails. For example:
30
+ <pre class="boxed"> cache[key] = some_data </pre>
31
+ * @add_timer@ : Look in scheduler section
32
+ * @add_periodic_timer@ : Look in scheduler section
33
+ * @thread_pool@ : Look below
34
+ * @connect@: Look in "Advanced":/advanced/index.html section. Used to connect to external TCP/IP servers.
35
+ * @start_server@: Look in "Advanced":/advanced/index.html section. Used to start TCP/IP server from worker.
36
+ * @send_data@: Can be used to send objects to master process. You can ignore this method.
37
+ * @job_key@: When you invoke a task from rails by passing a job_key, that job_key can be accessed in workers with @job_key@. For example:
38
+ From rails:
39
+ <pre class="boxed"> MiddleMan.worker(:foo_worker).async_some_task(:arg => urls,
40
+ :job_key => current_user[:id])</pre>
41
+ Now this @job_key@ can be accessed inside workers with:
42
+ <pre class="multiline">class FooWorker < BackgrounDRb::MetaWorker
43
+ def some_task urls
44
+ .. do some work with urls ..
45
+ cache[job_key] = result
46
+ end
47
+ end</pre>
48
+
49
+ p(sub-title). Options via class methods :
50
+
51
+ Following class methods are available for further tuning of workers:
52
+
53
+ *(content_list) @pool_size@ : Can be used to control thread pool size. Accepts pool size as integer value.
54
+ * @set_no_auto_load@ : Can be used to disable auto loading of workers when _BackgrounDRb_ starts. Accepts true or false.
55
+ * @reload_on_schedule@ : Can be used to enable reloading of worker at scheduled execution time. Accepts true or false.
56
+ * @set_worker_name@ : Can be used to set worker name. Accepts symbol as worker name.
57
+
58
+ Following snippet demonstrates their usages:
59
+
60
+ <pre class="multiline">class HelloWorker < BackgrounDRb::MetaWorker
61
+ set_worker_name :hello_worker
62
+ reload_on_schedule true
63
+ pool_size 10
64
+ end</pre>
65
+
66
+ When @reload_on_schedule@ is true, worker won't be loaded while _BackgrounDRb_ starts and hence you don't need
67
+ @set_no_auto_load@ option there.
68
+
69
+ %(entry-title)<a name="thread_pool"> Using Thread Pool </a>%
70
+
71
+ Remember _BackgrounDRb_ follows event model of network programming, but sad truth of life is not all networking
72
+ libraries follow this model and hence they make use of blocking IO and threads. BackgrounDRb allows you to run
73
+ all such tasks concurrently in threads which are internally managed by BackgrounDRb thread pool.
74
+
75
+ Each worker has access to object @thread_pool@ which can be used to run task in a thread concurrently.
76
+
77
+ <pre class="boxed">thread_pool.defer(:scrap_wikipedia,scrap_url) </pre>
78
+
79
+ So whatever code you write within @scrap_wikipedia@ method is going to run concurrently.
80
+
81
+ *WARNING*: Many of the Ruby libraries out there aren't thread safe and they may not
82
+ work as advertised when used from threads(example: Mechanize,Scrubyt)
83
+
84
+ %(entry-title)<a name="result_caching"> Result Caching </a>%
85
+
86
+ <b>Update : </b> <em>Using MemCache to store result objects is strongly recommended. Inbuilt cache works, but may give
87
+ unpredictable results. Also, using Memcache serves as an out of process cache, which can be queried at any time.
88
+ If your worker is doing some processing, inbuilt cache may not return result until worker picks up that request.</em>
89
+
90
+
91
+ All workers can cache results using @cache@ attribute. This result object can be then
92
+ queried from rails using @ask_result@. For example:
93
+
94
+ <pre class="multiline">class ProgressWorker < BackgrounDRb::MetaWorker
95
+ set_worker_name :progress_worker
96
+ def create
97
+ @counter = 0
98
+ add_periodic_timer(2) { increment_counter }
99
+ end
100
+ def increment_counter
101
+ @counter += 1
102
+ cache[some_key] = counter
103
+ end
104
+ end</pre>
105
+
106
+ And using @MiddleMan@ proxy, you can keep querying the status of progress bar :
107
+
108
+ <pre class="boxed">MiddleMan.worker(:progress_worker).ask_result(some_key)</pre>
109
+
110
+ By default, @cache@ is a worker local hash like object, which is used for storing results.
111
+ But if you plan to store lots of objects in cache from your worker, it may not be an
112
+ optimal solution. You can easily replace in-worker cache with memcache.
113
+
114
+ You need to change @backgroundrb.yml@ file like this, for using memcache for object caching:
115
+
116
+ <pre class="multiline">:backgroundrb:
117
+ :ip: 0.0.0.0
118
+ :port: 11006
119
+ :result_storage: memcache
120
+
121
+ :memcache: "10.0.0.1:11211,10.0.0.2:11211" </pre>
122
+
123
+ Everything else remains the same.
124
+
125
+ %(entry-title)<a name="persistent_job">Persistent Task Queue </a>%
126
+
127
+ BackgrounDRb now have out of box support for persistent job queues which are persisted to the
128
+ database. API to add a task in the job_queue is pretty simple:
129
+
130
+ <pre class="boxed">MiddleMan(:hello_worker).enq_some_task(:arg => "hello_world",:job_key => "boy")</pre>
131
+
132
+ So in your hello worker:
133
+
134
+ <pre class="multiline">
135
+ class HelloWorker
136
+ def some_task args
137
+ .. do some work ..
138
+ persistent_job.finish! #=> marks the job as finished. totally thread safe
139
+ end
140
+ end</pre>
141
+
142
+ @persistent_job@ is a thread local variable and will refer to currently
143
+ running queued task can be used from thread pool as well. For example:
144
+
145
+ <pre class="multiline">
146
+ class HelloWorker
147
+ def some_task args
148
+ thread_pool.defer(:fetch_url,args)
149
+ end
150
+ def fetch_url tags
151
+ .. runs in thread ..
152
+ .. fetch tasks ..
153
+ persistent_job.finish!
154
+ end
155
+ end</pre>
156
+
157
+
158
+ %(entry-title)<a name="worker_testing">Testing Workers </a>%
159
+
160
+ _BackgrounDRb_ comes with a baked in mechanism to write test cases. First make sure that you
161
+ have bdrb_test_helper.rb in the test directory of your rails app (run @rake backgroundrb:setup@, if you dont have one).
162
+
163
+ Just put your worker test cases in test/unit directory of your rails application and require the helper. Now, you should be good to go.
164
+
165
+ <pre class="multiline">require File.join(File.dirname(__FILE__) + "/../bdrb_test_helper")
166
+ require "god_worker"
167
+ context "When god worker starts" do
168
+ setup do
169
+ god_worker = GodWorker.new
170
+ end
171
+ end </pre>
172
+
173
+ All above helper file does is that it stubs out, relevant worker methods, which really need network IO.
174
+ There can be methods added, which aren't stubbed, for all such methods you are encouraged to stub them and send
175
+ the patch to the backgroundrb mailing list.
176
+
177
+
178
+ </div>
@@ -0,0 +1,5 @@
1
+ # Built-in
2
+ filters_pre: [ "redcloth" ]
3
+ # Custom
4
+ title: "Using BackgrounDRb workers"
5
+ sidebar_items: [["Introduction", "#introduction"], ["Thread Pool", "#thread_pool"], ["Result Caching", "#result_caching"], ["Persistent Jobs", "#persistent_job"], ["Worker Testing", "#worker_testing"]]
@@ -0,0 +1,56 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
2
+ <html xmlns="http://www.w3.org/1999/xhtml">
3
+ <head>
4
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
5
+ <title>BackgrounDRb - <%= @page.title %></title>
6
+ <link rel="stylesheet" href="/style.css" type="text/css" media="screen" />
7
+ </head>
8
+
9
+ <body>
10
+
11
+ <div id="wrapper">
12
+ <div id="header">
13
+ <h1> BackgrounDRb </h1>
14
+ </div>
15
+
16
+ <div id="menu">
17
+ <ul>
18
+ <li><a href="/"> Intro </a></li>
19
+ <li><a href="/scheduling/"> Scheduling </a></li>
20
+ <li><a href="/workers/"> Workers </a></li>
21
+ <li><a href="/rails/"> Rails Integration </a></li>
22
+ <li><a href="/advanced/"> Advanced </a></li>
23
+ <li><a href="/manual/index.html"> Manual </a></li>
24
+ <li><a href="/community/"> Community </a></li>
25
+ <li><a href="/faq"> FAQs </a></li>
26
+ </ul>
27
+ </div>
28
+
29
+ <div id="sidebar">
30
+ <div id="feed">
31
+ <!-- <a class="feed-button" href="#">&nbsp;</a> -->
32
+ </div>
33
+ <ul>
34
+ <% if @page.sidebar_items %>
35
+ <% for menu_item in @page.sidebar_items %>
36
+ <li><a href="<%= menu_item[1] %>"> <%= menu_item[0] %> </a></li>
37
+ <% end %>
38
+ <% end %>
39
+ </ul>
40
+
41
+ <div id="sidebar-bottom"> &nbsp; </div>
42
+ </div>
43
+
44
+ <%= @page.content %>
45
+
46
+ <div id="footer">
47
+ <div id="footer-valid">
48
+ <a href="http://validator.w3.org/check/referer">xhtml</a> ::
49
+ <span align="right"> Created with <a href="http://nanoc.stoneship.org/"> Nanoc </a> </span>
50
+ </div>
51
+
52
+ </div>
53
+
54
+ </div> <!-- end of wrapper div tag -->
55
+ </body>
56
+ </html>
@@ -0,0 +1,4 @@
1
+ # Built-in
2
+
3
+ # Custom
4
+ filter: erb
@@ -0,0 +1,7 @@
1
+ # All files in the 'lib' directory will be loaded
2
+ # before nanoc starts compiling.
3
+
4
+ def html_escape(str)
5
+ str.gsub('&', '&amp;').str('<', '&lt;').str('>', '&gt;').str('"', '&quot;')
6
+ end
7
+ alias h html_escape
Binary file
Binary file
Binary file
Binary file