olelo 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (282) hide show
  1. data/.gitignore +10 -0
  2. data/.gitmodules +3 -0
  3. data/Gemfile +3 -0
  4. data/README.markdown +104 -0
  5. data/Rakefile +92 -0
  6. data/bin/olelo +5 -0
  7. data/config.ru +86 -0
  8. data/config/aspects.rb +256 -0
  9. data/config/config.yml.default +154 -0
  10. data/config/initializers/00-mime_types.rb +29 -0
  11. data/config/initializers/01-slim.rb +2 -0
  12. data/config/interwiki.yml +11 -0
  13. data/doc/AUTHORS +7 -0
  14. data/doc/LICENSE +22 -0
  15. data/lib/olelo.rb +39 -0
  16. data/lib/olelo/application.rb +294 -0
  17. data/lib/olelo/attributes.rb +285 -0
  18. data/lib/olelo/config.rb +88 -0
  19. data/lib/olelo/extensions.rb +252 -0
  20. data/lib/olelo/helper.rb +290 -0
  21. data/lib/olelo/hooks.rb +142 -0
  22. data/lib/olelo/html_safe.rb +29 -0
  23. data/lib/olelo/initializer.rb +76 -0
  24. data/lib/olelo/locale.rb +63 -0
  25. data/lib/olelo/locale.yml +284 -0
  26. data/lib/olelo/menu.rb +101 -0
  27. data/lib/olelo/middleware/blacklist.rb +25 -0
  28. data/lib/olelo/middleware/degrade_mime_type.rb +19 -0
  29. data/lib/olelo/middleware/flash.rb +97 -0
  30. data/lib/olelo/middleware/force_encoding.rb +41 -0
  31. data/lib/olelo/page.rb +266 -0
  32. data/lib/olelo/patch.rb +311 -0
  33. data/lib/olelo/plugin.rb +188 -0
  34. data/lib/olelo/repository.rb +225 -0
  35. data/lib/olelo/routing.rb +223 -0
  36. data/lib/olelo/templates.rb +30 -0
  37. data/lib/olelo/user.rb +132 -0
  38. data/lib/olelo/util.rb +233 -0
  39. data/lib/olelo/version.rb +3 -0
  40. data/lib/olelo/virtualfs.rb +161 -0
  41. data/lib/rack/olelo_patches.rb +33 -0
  42. data/lib/rack/relative_redirect.rb +44 -0
  43. data/lib/rack/static_cache.rb +93 -0
  44. data/lib/yard/addons.rb +1 -0
  45. data/lib/yard/addons/hook_handler.rb +25 -0
  46. data/lib/yard/addons/override_tag.rb +14 -0
  47. data/lib/yard/addons/route_handler.rb +33 -0
  48. data/lib/yard/addons/sanitize_anchor.rb +16 -0
  49. data/olelo.gemspec +31 -0
  50. data/plugins/aspects/changelog.rb +45 -0
  51. data/plugins/aspects/documentbrowser.rb +57 -0
  52. data/plugins/aspects/download.rb +11 -0
  53. data/plugins/aspects/highlight.rb +8 -0
  54. data/plugins/aspects/image.rb +41 -0
  55. data/plugins/aspects/imageinfo.rb +64 -0
  56. data/plugins/aspects/locale.yml +60 -0
  57. data/plugins/aspects/main.rb +199 -0
  58. data/plugins/aspects/pageinfo.rb +37 -0
  59. data/plugins/aspects/source.rb +6 -0
  60. data/plugins/aspects/subpages.rb +44 -0
  61. data/plugins/aspects/text.rb +9 -0
  62. data/plugins/blog/blog.css +1 -0
  63. data/plugins/blog/blog.scss +37 -0
  64. data/plugins/blog/locale.yml +12 -0
  65. data/plugins/blog/main.rb +85 -0
  66. data/plugins/editor/locale.yml +18 -0
  67. data/plugins/editor/markup/main.rb +3 -0
  68. data/plugins/editor/markup/script.js +10 -0
  69. data/plugins/editor/markup/script/00-jquery.textselection.js +267 -0
  70. data/plugins/editor/markup/script/01-olelo.markupeditor.js +116 -0
  71. data/plugins/editor/markup/script/init.js +10 -0
  72. data/plugins/editor/preview.rb +52 -0
  73. data/plugins/editor/recaptcha.rb +56 -0
  74. data/plugins/filters/creole.rb +37 -0
  75. data/plugins/filters/disposition.rb +9 -0
  76. data/plugins/filters/editsection.rb +67 -0
  77. data/plugins/filters/fix_img_tag.rb +16 -0
  78. data/plugins/filters/html_wrapper.rb +12 -0
  79. data/plugins/filters/interwiki.rb +19 -0
  80. data/plugins/filters/link_classifier.rb +26 -0
  81. data/plugins/filters/locale.yml +15 -0
  82. data/plugins/filters/main.rb +202 -0
  83. data/plugins/filters/markdown_nowiki.rb +15 -0
  84. data/plugins/filters/numbering.xsl +93 -0
  85. data/plugins/filters/orgmode.rb +6 -0
  86. data/plugins/filters/rubypants.rb +6 -0
  87. data/plugins/filters/s5/main.rb +32 -0
  88. data/plugins/filters/s5/s5.xsl +118 -0
  89. data/plugins/filters/tilt.rb +17 -0
  90. data/plugins/filters/toc.rb +50 -0
  91. data/plugins/filters/xhtml2latex.xsl +232 -0
  92. data/plugins/filters/xslt.rb +22 -0
  93. data/plugins/gallery/gallery.css +1 -0
  94. data/plugins/gallery/gallery.scss +28 -0
  95. data/plugins/gallery/main.rb +34 -0
  96. data/plugins/misc/fancybox/images/blank.gif +0 -0
  97. data/plugins/misc/fancybox/images/fancy_close.png +0 -0
  98. data/plugins/misc/fancybox/images/fancy_loading.png +0 -0
  99. data/plugins/misc/fancybox/images/fancy_nav_left.png +0 -0
  100. data/plugins/misc/fancybox/images/fancy_nav_right.png +0 -0
  101. data/plugins/misc/fancybox/images/fancy_shadow_e.png +0 -0
  102. data/plugins/misc/fancybox/images/fancy_shadow_n.png +0 -0
  103. data/plugins/misc/fancybox/images/fancy_shadow_ne.png +0 -0
  104. data/plugins/misc/fancybox/images/fancy_shadow_nw.png +0 -0
  105. data/plugins/misc/fancybox/images/fancy_shadow_s.png +0 -0
  106. data/plugins/misc/fancybox/images/fancy_shadow_se.png +0 -0
  107. data/plugins/misc/fancybox/images/fancy_shadow_sw.png +0 -0
  108. data/plugins/misc/fancybox/images/fancy_shadow_w.png +0 -0
  109. data/plugins/misc/fancybox/images/fancy_title_left.png +0 -0
  110. data/plugins/misc/fancybox/images/fancy_title_main.png +0 -0
  111. data/plugins/misc/fancybox/images/fancy_title_over.png +0 -0
  112. data/plugins/misc/fancybox/images/fancy_title_right.png +0 -0
  113. data/plugins/misc/fancybox/images/fancybox-x.png +0 -0
  114. data/plugins/misc/fancybox/images/fancybox-y.png +0 -0
  115. data/plugins/misc/fancybox/images/fancybox.png +0 -0
  116. data/plugins/misc/fancybox/jquery.fancybox.css +1 -0
  117. data/plugins/misc/fancybox/jquery.fancybox.scss +323 -0
  118. data/plugins/misc/fancybox/main.rb +4 -0
  119. data/plugins/misc/fancybox/script.js +37 -0
  120. data/plugins/misc/fancybox/script/00-jquery.mousewheel.js +84 -0
  121. data/plugins/misc/fancybox/script/01-jquery.easing.js +205 -0
  122. data/plugins/misc/fancybox/script/02-jquery.fancybox.js +1156 -0
  123. data/plugins/misc/fancybox/script/init.js +18 -0
  124. data/plugins/misc/system.rb +192 -0
  125. data/plugins/misc/variables.rb +29 -0
  126. data/plugins/misc/webdav.rb +45 -0
  127. data/plugins/repositories/git_grep.rb +69 -0
  128. data/plugins/repositories/gitrb_repository.rb +204 -0
  129. data/plugins/repositories/locale.yml +12 -0
  130. data/plugins/repositories/rugged_repository.rb +454 -0
  131. data/plugins/security/acl.rb +57 -0
  132. data/plugins/security/basic_auth.rb +21 -0
  133. data/plugins/security/locale.yml +21 -0
  134. data/plugins/security/persistent_login.rb +32 -0
  135. data/plugins/security/portal.rb +28 -0
  136. data/plugins/security/private_wiki.rb +24 -0
  137. data/plugins/security/readonly_wiki.rb +25 -0
  138. data/plugins/security/stack.rb +20 -0
  139. data/plugins/security/yamlfile.rb +66 -0
  140. data/plugins/tags/code.rb +6 -0
  141. data/plugins/tags/footnotes.rb +35 -0
  142. data/plugins/tags/gist-embed.css +123 -0
  143. data/plugins/tags/gist.rb +13 -0
  144. data/plugins/tags/html.rb +57 -0
  145. data/plugins/tags/include.rb +20 -0
  146. data/plugins/tags/main.rb +353 -0
  147. data/plugins/tags/math.rb +117 -0
  148. data/plugins/tags/scripting.rb +64 -0
  149. data/plugins/tags/sort.rb +7 -0
  150. data/plugins/tags/tabs.rb +20 -0
  151. data/plugins/treeview/images/collapsed.png +0 -0
  152. data/plugins/treeview/images/expanded.png +0 -0
  153. data/plugins/treeview/images/menu.png +0 -0
  154. data/plugins/treeview/images/tree.png +0 -0
  155. data/plugins/treeview/images/wait.gif +0 -0
  156. data/plugins/treeview/main.rb +16 -0
  157. data/plugins/treeview/script.js +5 -0
  158. data/plugins/treeview/script/00-jquery.treeview.js +164 -0
  159. data/plugins/treeview/script/init.js +25 -0
  160. data/plugins/treeview/treeview.css +1 -0
  161. data/plugins/treeview/treeview.scss +113 -0
  162. data/plugins/utils/assets.rb +74 -0
  163. data/plugins/utils/cache.rb +53 -0
  164. data/plugins/utils/image_magick.rb +34 -0
  165. data/plugins/utils/pygments.css +1 -0
  166. data/plugins/utils/pygments.rb +50 -0
  167. data/plugins/utils/pygments.scss +83 -0
  168. data/plugins/utils/semaphore.rb +50 -0
  169. data/plugins/utils/shell.rb +45 -0
  170. data/plugins/utils/store.rb +315 -0
  171. data/plugins/utils/worker.rb +36 -0
  172. data/plugins/utils/xml.rb +29 -0
  173. data/static/images/favicon.png +0 -0
  174. data/static/script.js +267 -0
  175. data/static/script/00-json2.js +486 -0
  176. data/static/script/01-jstorage.js +217 -0
  177. data/static/script/02-jquery.js +9440 -0
  178. data/static/script/03-jquery.ui.core.js +337 -0
  179. data/static/script/04-jquery.ui.widget.js +502 -0
  180. data/static/script/05-jquery.ui.position.js +517 -0
  181. data/static/script/06-jquery.ui.menu.js +609 -0
  182. data/static/script/07-jquery.ui.autocomplete.js +601 -0
  183. data/static/script/08-olelo.i18n.js +37 -0
  184. data/static/script/09-olelo.unsaved.js +68 -0
  185. data/static/script/10-olelo.historytable.js +40 -0
  186. data/static/script/11-olelo.pagination.js +18 -0
  187. data/static/script/13-olelo.tabwidget.js +57 -0
  188. data/static/script/14-olelo.timeago.js +70 -0
  189. data/static/script/15-olelo.underliner.js +31 -0
  190. data/static/script/16-olelo.ui.combobox.js +32 -0
  191. data/static/script/init.js +48 -0
  192. data/static/themes/atlantis/constants.scss +15 -0
  193. data/static/themes/atlantis/iehacks.scss +38 -0
  194. data/static/themes/atlantis/images/actions/delete.png +0 -0
  195. data/static/themes/atlantis/images/actions/edit.png +0 -0
  196. data/static/themes/atlantis/images/actions/history.png +0 -0
  197. data/static/themes/atlantis/images/actions/home.png +0 -0
  198. data/static/themes/atlantis/images/actions/move.png +0 -0
  199. data/static/themes/atlantis/images/actions/new.png +0 -0
  200. data/static/themes/atlantis/images/actions/page.png +0 -0
  201. data/static/themes/atlantis/images/bg/button.png +0 -0
  202. data/static/themes/atlantis/images/bg/container.png +0 -0
  203. data/static/themes/atlantis/images/bg/content.png +0 -0
  204. data/static/themes/atlantis/images/bg/footer.png +0 -0
  205. data/static/themes/atlantis/images/bg/header.jpg +0 -0
  206. data/static/themes/atlantis/images/bg/header.orig.jpg +0 -0
  207. data/static/themes/atlantis/images/bg/header_gray.jpg +0 -0
  208. data/static/themes/atlantis/images/bug.png +0 -0
  209. data/static/themes/atlantis/images/filetypes/7z.png +0 -0
  210. data/static/themes/atlantis/images/filetypes/_archive.png +0 -0
  211. data/static/themes/atlantis/images/filetypes/_audio.png +0 -0
  212. data/static/themes/atlantis/images/filetypes/_code.png +0 -0
  213. data/static/themes/atlantis/images/filetypes/_linux.png +0 -0
  214. data/static/themes/atlantis/images/filetypes/_picture.png +0 -0
  215. data/static/themes/atlantis/images/filetypes/_video.png +0 -0
  216. data/static/themes/atlantis/images/filetypes/bz2.png +0 -0
  217. data/static/themes/atlantis/images/filetypes/doc.png +0 -0
  218. data/static/themes/atlantis/images/filetypes/flac.png +0 -0
  219. data/static/themes/atlantis/images/filetypes/gz.png +0 -0
  220. data/static/themes/atlantis/images/filetypes/html.png +0 -0
  221. data/static/themes/atlantis/images/filetypes/java.png +0 -0
  222. data/static/themes/atlantis/images/filetypes/jpg.png +0 -0
  223. data/static/themes/atlantis/images/filetypes/midi.png +0 -0
  224. data/static/themes/atlantis/images/filetypes/mp3.png +0 -0
  225. data/static/themes/atlantis/images/filetypes/ogg.png +0 -0
  226. data/static/themes/atlantis/images/filetypes/pdf.png +0 -0
  227. data/static/themes/atlantis/images/filetypes/php.png +0 -0
  228. data/static/themes/atlantis/images/filetypes/png.png +0 -0
  229. data/static/themes/atlantis/images/filetypes/ppt.png +0 -0
  230. data/static/themes/atlantis/images/filetypes/psd.png +0 -0
  231. data/static/themes/atlantis/images/filetypes/rar.png +0 -0
  232. data/static/themes/atlantis/images/filetypes/rb.png +0 -0
  233. data/static/themes/atlantis/images/filetypes/sh.png +0 -0
  234. data/static/themes/atlantis/images/filetypes/tar.png +0 -0
  235. data/static/themes/atlantis/images/filetypes/txt.png +0 -0
  236. data/static/themes/atlantis/images/filetypes/wma.png +0 -0
  237. data/static/themes/atlantis/images/filetypes/xls.png +0 -0
  238. data/static/themes/atlantis/images/filetypes/zip.png +0 -0
  239. data/static/themes/atlantis/images/folder.png +0 -0
  240. data/static/themes/atlantis/images/folder_open.png +0 -0
  241. data/static/themes/atlantis/images/loading.gif +0 -0
  242. data/static/themes/atlantis/images/loading.xcf +0 -0
  243. data/static/themes/atlantis/images/not_found.png +0 -0
  244. data/static/themes/atlantis/images/page.png +0 -0
  245. data/static/themes/atlantis/images/search.png +0 -0
  246. data/static/themes/atlantis/layout.scss +115 -0
  247. data/static/themes/atlantis/menu.scss +99 -0
  248. data/static/themes/atlantis/print.scss +129 -0
  249. data/static/themes/atlantis/screen.scss +495 -0
  250. data/static/themes/atlantis/style.css +3 -0
  251. data/static/themes/lib/autocomplete.scss +39 -0
  252. data/static/themes/lib/headlines.scss +10 -0
  253. data/static/themes/lib/horizontal-list.scss +31 -0
  254. data/static/themes/lib/patch.scss +88 -0
  255. data/static/themes/lib/reset.scss +114 -0
  256. data/static/themes/lib/rounded.scss +46 -0
  257. data/static/themes/lib/shadow.scss +14 -0
  258. data/test/config_test.rb +28 -0
  259. data/test/factory_test.rb +29 -0
  260. data/test/hash_extensions_test.rb +16 -0
  261. data/test/helper.rb +38 -0
  262. data/test/hooks_test.rb +85 -0
  263. data/test/object_extensions_test.rb +20 -0
  264. data/test/page_test.rb +168 -0
  265. data/test/request_test.rb +166 -0
  266. data/test/string_extensions_test.rb +32 -0
  267. data/test/templates_test.rb +39 -0
  268. data/test/util_test.rb +71 -0
  269. data/views/changes.slim +22 -0
  270. data/views/compare.slim +8 -0
  271. data/views/delete.slim +9 -0
  272. data/views/deleted.slim +2 -0
  273. data/views/edit.slim +65 -0
  274. data/views/error.slim +6 -0
  275. data/views/history.slim +20 -0
  276. data/views/layout.slim +38 -0
  277. data/views/login.slim +37 -0
  278. data/views/move.slim +10 -0
  279. data/views/not_found.slim +6 -0
  280. data/views/profile.slim +26 -0
  281. data/views/show.slim +9 -0
  282. metadata +488 -0
@@ -0,0 +1,53 @@
1
+ description 'Caching support'
2
+ dependencies 'utils/worker', 'utils/store'
3
+
4
+ class Cache
5
+ def initialize(store)
6
+ @store = store
7
+ @disabled = false
8
+ end
9
+
10
+ def disable!
11
+ @disabled = true
12
+ end
13
+
14
+ # Block around cacheable return value identified by a <i>key</i>.
15
+ # The following options can be specified:
16
+ # * :disable Disable caching
17
+ # * :update Force cache update
18
+ # * :defer Deferred cache update
19
+ def cache(key, options = {}, &block)
20
+ if options[:disable] || !Config['production']
21
+ yield(self)
22
+ elsif @store.key?(key) && (!options[:update] || options[:defer])
23
+ Worker.defer { update(key, options, &block) } if options[:update]
24
+ @store[key]
25
+ else
26
+ update(key, options, &block)
27
+ end
28
+ end
29
+
30
+ def clear
31
+ @store.clear
32
+ end
33
+
34
+ private
35
+
36
+ def update(key, options = {}, &block)
37
+ content = block.call(self)
38
+ @store[key] = content if !@disabled
39
+ content
40
+ end
41
+
42
+ class<< self
43
+ def store
44
+ @store ||= Store.create(Config['cache_store'])
45
+ end
46
+
47
+ def cache(*args, &block)
48
+ Cache.new(store).cache(*args, &block)
49
+ end
50
+ end
51
+ end
52
+
53
+ Olelo::Cache = Cache
@@ -0,0 +1,34 @@
1
+ description 'ImageMagick'
2
+ dependencies 'utils/shell', 'utils/semaphore'
3
+
4
+ class ImageMagick < Shell
5
+ def self.semaphore
6
+ @semaphore ||= Semaphore.new
7
+ end
8
+
9
+ def initialize
10
+ if (`gm -version` rescue '').include?('GraphicsMagick')
11
+ @prefix = 'gm'
12
+ elsif !(`convert -version` rescue '').include?('ImageMagick')
13
+ raise 'GraphicsMagick or ImageMagick not found'
14
+ end
15
+ end
16
+
17
+ def label(text)
18
+ convert('-pointsize', 16, '-background', 'transparent', "label:#{text}", 'PNG:-').run rescue nil
19
+ end
20
+
21
+ def method_missing(name, *args, &block)
22
+ if %w(convert identify).include?(name.to_s)
23
+ super(@prefix, name, *args, &block)
24
+ else
25
+ super
26
+ end
27
+ end
28
+
29
+ def self.run(cmd, data)
30
+ semaphore.synchronize { super }
31
+ end
32
+ end
33
+
34
+ Olelo::ImageMagick = ImageMagick
@@ -0,0 +1 @@
1
+ .pygmentstable{background:transparent;width:100%}.pygmentstable td{background-color:#f8f8ff;padding:0.3em;vertical-align:top}.pygmentstable .linenos{width:0px;color:#555555}.pygmentstable .code{width:100%}.pygmentstable pre{padding:0;border:none}.pygments{background-color:#f8f8ff}.pygments .c{color:#999988;font-style:italic}.pygments .err{color:#a61717;background-color:#e3d2d2}.pygments .k{color:#000000;font-weight:bold}.pygments .o{color:#000000;font-weight:bold}.pygments .cm{color:#999988;font-style:italic}.pygments .cp{color:#999999;font-weight:bold}.pygments .c1{color:#999988;font-style:italic}.pygments .cs{color:#999999;font-weight:bold;font-style:italic}.pygments .gd{color:#000000;background-color:#ffdddd}.pygments .gd .x{color:#000000;background-color:#ffaaaa}.pygments .ge{color:#000000;font-style:italic}.pygments .gr{color:#aa0000}.pygments .gh{color:#999999}.pygments .gi{color:#000000;background-color:#ddffdd}.pygments .gi .x{color:#000000;background-color:#aaffaa}.pygments .go{color:#888888}.pygments .gp{color:#555555}.pygments .gs{font-weight:bold}.pygments .gu{color:#aaaaaa}.pygments .gt{color:#aa0000}.pygments .kc{color:#000000;font-weight:bold}.pygments .kd{color:#000000;font-weight:bold}.pygments .kp{color:#000000;font-weight:bold}.pygments .kr{color:#000000;font-weight:bold}.pygments .kt{color:#445588;font-weight:bold}.pygments .m{color:#009999}.pygments .s{color:#d14}.pygments .na{color:#008080}.pygments .nb{color:#0086B3}.pygments .nc{color:#445588;font-weight:bold}.pygments .no{color:#008080}.pygments .ni{color:#800080}.pygments .ne{color:#990000;font-weight:bold}.pygments .nf{color:#990000;font-weight:bold}.pygments .nn{color:#555555}.pygments .nt{color:#000080}.pygments .nv{color:#008080}.pygments .ow{color:#000000;font-weight:bold}.pygments .w{color:#bbbbbb}.pygments .mf{color:#009999}.pygments .mh{color:#009999}.pygments .mi{color:#009999}.pygments .mo{color:#009999}.pygments .sb{color:#d14}.pygments .sc{color:#d14}.pygments .sd{color:#d14}.pygments .s2{color:#d14}.pygments .se{color:#d14}.pygments .sh{color:#d14}.pygments .si{color:#d14}.pygments .sx{color:#d14}.pygments .sr{color:#009926}.pygments .s1{color:#d14}.pygments .ss{color:#990073}.pygments .bp{color:#999999}.pygments .vc{color:#008080}.pygments .vg{color:#008080}.pygments .vi{color:#008080}.pygments .il{color:#009999}
@@ -0,0 +1,50 @@
1
+ description 'Pygments syntax highlighter'
2
+ dependencies 'utils/assets', 'utils/shell'
3
+ export_scripts 'pygments.css'
4
+
5
+ module Pygments
6
+ FORMAT_OPTIONS = %w(-O encoding=utf8 -O linenos=table -O cssclass=pygments -f html -l)
7
+ @patterns = {}
8
+ @formats = []
9
+
10
+ include Util
11
+
12
+ def self.pre(text)
13
+ "<pre>#{escape_html(text.strip)}</pre>"
14
+ end
15
+
16
+ private_class_method :pre
17
+
18
+ def self.pygmentize(text, format)
19
+ return pre(text) if !@formats.include?(format)
20
+ options = FORMAT_OPTIONS + [format]
21
+ content = Shell.pygmentize(*options).run(text)
22
+ content.blank? ? pre(text) : content
23
+ end
24
+
25
+ def self.file_format(name)
26
+ pattern = @patterns.keys.find {|p| File.fnmatch(p, name)}
27
+ pattern && @patterns[pattern]
28
+ end
29
+
30
+ def self.setup
31
+ format = ''
32
+ output = `pygmentize -L lexer`
33
+ output.split("\n").each do |line|
34
+ if line =~ /^\* ([^:]+):$/
35
+ format = $1.split(', ')
36
+ @formats += format
37
+ elsif line =~ /^ [^(]+ \(filenames ([^)]+)/
38
+ $1.split(', ').each {|s| @patterns[s] = format.first }
39
+ end
40
+ end
41
+ rescue Errno::ENOENT => ex
42
+ Olelo.logger.warn 'pygmentize not found'
43
+ end
44
+ end
45
+
46
+ setup do
47
+ Pygments.setup
48
+ end
49
+
50
+ Olelo::Pygments = Pygments
@@ -0,0 +1,83 @@
1
+ .pygmentstable {
2
+ background: transparent;
3
+ width: 100%;
4
+ td {
5
+ background-color: #f8f8ff;
6
+ padding: 0.3em;
7
+ vertical-align: top;
8
+ }
9
+ .linenos {
10
+ width: 0px;
11
+ color: #555555;
12
+ }
13
+ .code {
14
+ width: 100%;
15
+ }
16
+ pre {
17
+ padding: 0;
18
+ border: none;
19
+ }
20
+ }
21
+
22
+ .pygments {
23
+ background-color: #f8f8ff;
24
+ .c { color: #999988; font-style: italic } /* Comment */
25
+ .err { color: #a61717; background-color: #e3d2d2 } /* Error */
26
+ .k { color: #000000; font-weight: bold } /* Keyword */
27
+ .o { color: #000000; font-weight: bold } /* Operator */
28
+ .cm { color: #999988; font-style: italic } /* Comment.Multiline */
29
+ .cp { color: #999999; font-weight: bold } /* Comment.Preproc */
30
+ .c1 { color: #999988; font-style: italic } /* Comment.Single */
31
+ .cs { color: #999999; font-weight: bold; font-style: italic } /* Comment.Special */
32
+ .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
33
+ .gd .x { color: #000000; background-color: #ffaaaa } /* Generic.Deleted.Specific */
34
+ .ge { color: #000000; font-style: italic } /* Generic.Emph */
35
+ .gr { color: #aa0000 } /* Generic.Error */
36
+ .gh { color: #999999 } /* Generic.Heading */
37
+ .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
38
+ .gi .x { color: #000000; background-color: #aaffaa } /* Generic.Inserted.Specific */
39
+ .go { color: #888888 } /* Generic.Output */
40
+ .gp { color: #555555 } /* Generic.Prompt */
41
+ .gs { font-weight: bold } /* Generic.Strong */
42
+ .gu { color: #aaaaaa } /* Generic.Subheading */
43
+ .gt { color: #aa0000 } /* Generic.Traceback */
44
+ .kc { color: #000000; font-weight: bold } /* Keyword.Constant */
45
+ .kd { color: #000000; font-weight: bold } /* Keyword.Declaration */
46
+ .kp { color: #000000; font-weight: bold } /* Keyword.Pseudo */
47
+ .kr { color: #000000; font-weight: bold } /* Keyword.Reserved */
48
+ .kt { color: #445588; font-weight: bold } /* Keyword.Type */
49
+ .m { color: #009999 } /* Literal.Number */
50
+ .s { color: #d14 } /* Literal.String */
51
+ .na { color: #008080 } /* Name.Attribute */
52
+ .nb { color: #0086B3 } /* Name.Builtin */
53
+ .nc { color: #445588; font-weight: bold } /* Name.Class */
54
+ .no { color: #008080 } /* Name.Constant */
55
+ .ni { color: #800080 } /* Name.Entity */
56
+ .ne { color: #990000; font-weight: bold } /* Name.Exception */
57
+ .nf { color: #990000; font-weight: bold } /* Name.Function */
58
+ .nn { color: #555555 } /* Name.Namespace */
59
+ .nt { color: #000080 } /* Name.Tag */
60
+ .nv { color: #008080 } /* Name.Variable */
61
+ .ow { color: #000000; font-weight: bold } /* Operator.Word */
62
+ .w { color: #bbbbbb } /* Text.Whitespace */
63
+ .mf { color: #009999 } /* Literal.Number.Float */
64
+ .mh { color: #009999 } /* Literal.Number.Hex */
65
+ .mi { color: #009999 } /* Literal.Number.Integer */
66
+ .mo { color: #009999 } /* Literal.Number.Oct */
67
+ .sb { color: #d14 } /* Literal.String.Backtick */
68
+ .sc { color: #d14 } /* Literal.String.Char */
69
+ .sd { color: #d14 } /* Literal.String.Doc */
70
+ .s2 { color: #d14 } /* Literal.String.Double */
71
+ .se { color: #d14 } /* Literal.String.Escape */
72
+ .sh { color: #d14 } /* Literal.String.Heredoc */
73
+ .si { color: #d14 } /* Literal.String.Interpol */
74
+ .sx { color: #d14 } /* Literal.String.Other */
75
+ .sr { color: #009926 } /* Literal.String.Regex */
76
+ .s1 { color: #d14 } /* Literal.String.Single */
77
+ .ss { color: #990073 } /* Literal.String.Symbol */
78
+ .bp { color: #999999 } /* Name.Builtin.Pseudo */
79
+ .vc { color: #008080 } /* Name.Variable.Class */
80
+ .vg { color: #008080 } /* Name.Variable.Global */
81
+ .vi { color: #008080 } /* Name.Variable.Instance */
82
+ .il { color: #009999 } /* Literal.Number.Integer.Long */
83
+ }
@@ -0,0 +1,50 @@
1
+ description 'Semaphore class'
2
+
3
+ # Semaphore implementation based on {Mutex} and {ConditionVariable}.
4
+ # A mutex allows a number of threads to enter a synchronized section in parallel.
5
+ class Semaphore
6
+ # @param [Integer] counter Number of threads which can enter the section in parallel
7
+ def initialize(counter = 1)
8
+ @mutex = Mutex.new
9
+ @cond = ConditionVariable.new
10
+ @counter = counter
11
+ end
12
+
13
+ # Enter synchronized section
14
+ #
15
+ # Decrements the semaphore counter
16
+ #
17
+ # @api public
18
+ # @return [void]
19
+ def enter
20
+ @mutex.synchronize do
21
+ @cond.wait(@mutex) if (@counter -= 1) < 0
22
+ end
23
+ end
24
+
25
+ # Leave synchronized section
26
+ #
27
+ # Increments the semaphore counter
28
+ #
29
+ # @api public
30
+ # @return [void]
31
+ def leave
32
+ @mutex.synchronize do
33
+ @cond.signal if (@counter += 1) <= 0
34
+ end
35
+ end
36
+
37
+ # Synchronize block with this semaphore
38
+ #
39
+ # @api public
40
+ # @yield Block to synchronize
41
+ # @return [void]
42
+ def synchronize
43
+ enter
44
+ yield
45
+ ensure
46
+ leave
47
+ end
48
+ end
49
+
50
+ Olelo::Semaphore = Semaphore
@@ -0,0 +1,45 @@
1
+ description 'Shell utility'
2
+ require 'shellwords'
3
+
4
+ class Shell
5
+ def run(data = nil)
6
+ cmd = @cmd.join(' | ')
7
+ return `#{cmd}` if !data
8
+ Open3.popen3(cmd) do |stdin, stdout, stderr|
9
+ output = ''
10
+ len = 0
11
+ begin
12
+ while len < data.length
13
+ if found = IO.select([stdout], [stdin], nil, 0)
14
+ len += stdin.write_nonblock(data[len..-1]) if found[1].first
15
+ output << stdout.read_nonblock(1048576) if found[0].first && !stdout.eof?
16
+ end
17
+ end
18
+ rescue Errno::EPIPE
19
+ end
20
+ stdin.close
21
+ begin
22
+ output << stdout.read
23
+ rescue Errno::EAGAIN
24
+ retry
25
+ end
26
+ output
27
+ end
28
+ end
29
+
30
+ def cmd(*args)
31
+ yield(args) if block_given?
32
+ (@cmd ||= []) << args.compact.map(&:to_s).shelljoin
33
+ self
34
+ end
35
+
36
+ def method_missing(*args, &block)
37
+ cmd(*args, &block)
38
+ end
39
+
40
+ def self.method_missing(*args, &block)
41
+ new.send(*args, &block)
42
+ end
43
+ end
44
+
45
+ Olelo::Shell = Shell
@@ -0,0 +1,315 @@
1
+ description 'Key/value store'
2
+ require 'delegate'
3
+
4
+ # Simple interface to key/value stores with Hash-like interface.
5
+ #
6
+ # Store supports a subset of the Moneta interface,
7
+ # Moneta can be used as a drop-in replacement.
8
+ # It is recommended to wrap the moneta store in a Store::Delegated
9
+ # to only expose the Store interface.
10
+ #
11
+ # @abstract
12
+ class Store
13
+ extend Factory
14
+
15
+ # Exists the value with key
16
+ #
17
+ # @param [String] key
18
+ # @return [Boolean]
19
+ # @api public
20
+ # @abstract
21
+ def key?(key)
22
+ raise NotImplementedError
23
+ end
24
+
25
+ # Read value with key. Return nil if the key doesn't exist
26
+ #
27
+ # @param [String] key
28
+ # @return [Object] value
29
+ # @api public
30
+ # @abstract
31
+ def [](key)
32
+ raise NotImplementedError
33
+ end
34
+
35
+ # Write value with key
36
+ #
37
+ # @param [String] key
38
+ # @param [Object] value
39
+ # @return value
40
+ # @api public
41
+ # @abstract
42
+ def []=(key, value)
43
+ raise NotImplementedError
44
+ end
45
+
46
+ # Delete the key from the store and return the current value
47
+ #
48
+ # @param [String] key
49
+ # @return [Object] current value
50
+ # @api public
51
+ # @abstract
52
+ def delete(key)
53
+ raise NotImplementedError
54
+ end
55
+
56
+ # Clear all keys in this store
57
+ #
58
+ # @return [void]
59
+ # @api public
60
+ # @abstract
61
+ def clear
62
+ raise NotImplementedError
63
+ end
64
+
65
+ protected
66
+
67
+ # Serialize value
68
+ #
69
+ # @param [Object] value Serializable object
70
+ # @return [String] serialized object
71
+ # @api private
72
+ def serialize(value)
73
+ Marshal.dump(value)
74
+ end
75
+
76
+ # Deserialize value
77
+ #
78
+ # @param [String] value Serialized object
79
+ # @return [Object] Deserialized object
80
+ # @api private
81
+ def deserialize(value)
82
+ value && Marshal.load(value)
83
+ end
84
+
85
+ # Create store instance
86
+ #
87
+ # @param [Config] Store configuration
88
+ # @return [Store]
89
+ # @api public
90
+ def self.create(config)
91
+ self[config[:type]].new(config[config[:type]])
92
+ end
93
+
94
+ # Delegated store
95
+ Delegated = DelegateClass(Store)
96
+
97
+ # Synchronized store
98
+ def self.Synchronized(type)
99
+ klass = Class.new
100
+ klass.class_eval %{
101
+ def initialize(config)
102
+ @store = #{type.name}.new(config)
103
+ @lock = Mutex.new
104
+ end
105
+
106
+ def method_missing(*args)
107
+ @lock.synchronize { @store.send(*args) }
108
+ end
109
+ }
110
+ klass
111
+ end
112
+
113
+ # Memory based store (uses hash)
114
+ class Memory < Delegated
115
+ def initialize(config)
116
+ super({})
117
+ end
118
+ end
119
+
120
+ register :memory, Memory
121
+
122
+ # Memcached client
123
+ class Memcached < Delegated
124
+ def initialize(config)
125
+ super(Store::Synchronized(Native).new(config))
126
+ rescue LoadError
127
+ super(Ruby.new(config))
128
+ end
129
+
130
+ # Uses the memcached gem
131
+ class Native < Store
132
+ include Util
133
+
134
+ def initialize(config)
135
+ require 'memcached'
136
+ @server = ::Memcached.new(config[:server], :prefix_key => (config[:prefix] rescue nil))
137
+ end
138
+
139
+ # @override
140
+ def key?(key)
141
+ @server.get(md5(key), false)
142
+ true
143
+ rescue ::Memcached::NotFound
144
+ false
145
+ end
146
+
147
+ # @override
148
+ def [](key)
149
+ @server.get(md5(key))
150
+ rescue ::Memcached::NotFound
151
+ end
152
+
153
+ # @override
154
+ def []=(key, value)
155
+ @server.set(md5(key), value)
156
+ value
157
+ end
158
+
159
+ # @override
160
+ def delete(key)
161
+ key = md5(key)
162
+ value = @server.get(key)
163
+ @server.delete(key)
164
+ value
165
+ rescue ::Memcached::NotFound
166
+ end
167
+
168
+ # @override
169
+ def clear
170
+ @server.flush
171
+ end
172
+ end
173
+
174
+ # Uses the dalli gem (memcache-client successor)
175
+ class Ruby < Store
176
+ include Util
177
+
178
+ def initialize(config)
179
+ require 'dalli'
180
+ @server = ::Dalli::Client.new(config[:server], :namespace => (config[:prefix] rescue nil))
181
+ end
182
+
183
+ # @override
184
+ def key?(key)
185
+ !@server.get(md5(key)).nil?
186
+ end
187
+
188
+ # @override
189
+ def [](key)
190
+ deserialize(@server.get(md5(key)))
191
+ end
192
+
193
+ # @override
194
+ def []=(key, value)
195
+ @server.set(md5(key), serialize(value))
196
+ value
197
+ end
198
+
199
+ # @override
200
+ def delete(key)
201
+ key = md5(key)
202
+ value = deserialize(@server.get(key))
203
+ @server.delete(key)
204
+ value
205
+ end
206
+
207
+ # @override
208
+ def clear
209
+ @server.flush_all
210
+ end
211
+ end
212
+ end
213
+
214
+ register :memcached, Memcached
215
+
216
+ # PStore based store
217
+ class PStore < Store
218
+ def initialize(config)
219
+ require 'pstore'
220
+ FileUtils.mkpath(::File.dirname(config[:file]))
221
+ @store = ::PStore.new(config[:file])
222
+ end
223
+
224
+ # @override
225
+ def key?(key)
226
+ @store.transaction(true) { @store.root?(key) }
227
+ end
228
+
229
+ # @override
230
+ def [](key)
231
+ @store.transaction(true) { @store[key] }
232
+ end
233
+
234
+ # @override
235
+ def []=(key, value)
236
+ @store.transaction { @store[key] = value }
237
+ end
238
+
239
+ # @override
240
+ def delete(key)
241
+ @store.transaction { @store.delete(key) }
242
+ end
243
+
244
+ # @override
245
+ def clear
246
+ @store.transaction do
247
+ @store.roots.each do |key|
248
+ @store.delete(key)
249
+ end
250
+ end
251
+ end
252
+ end
253
+
254
+ register :pstore, Synchronized(PStore)
255
+
256
+ # File based store
257
+ class File < Store
258
+ def initialize(config)
259
+ @root = config[:root]
260
+ end
261
+
262
+ # @override
263
+ def key?(key)
264
+ ::File.exist?(store_path(key))
265
+ end
266
+
267
+ # @override
268
+ def [](key)
269
+ deserialize(::File.read(store_path(key)))
270
+ rescue Errno::ENOENT
271
+ end
272
+
273
+ # @override
274
+ def []=(key, value)
275
+ temp_file = ::File.join(@root, "value-#{$$}-#{Thread.current.object_id}")
276
+ FileUtils.mkpath(@root)
277
+ ::File.open(temp_file, 'wb') {|file| file.write(serialize(value)) }
278
+ path = store_path(key)
279
+ FileUtils.mkpath(::File.dirname(path))
280
+ ::File.unlink(path) if ::File.exist?(path)
281
+ FileUtils.mv(temp_file, path)
282
+ rescue
283
+ ::File.unlink(temp_file) rescue nil
284
+ ensure
285
+ value
286
+ end
287
+
288
+ # @override
289
+ def delete(key)
290
+ value = self[key]
291
+ ::File.unlink(store_path(key))
292
+ value
293
+ rescue Errno::ENOENT
294
+ end
295
+
296
+ # @override
297
+ def clear
298
+ temp_dir = "#{@root}-#{$$}-#{Thread.current.object_id}"
299
+ FileUtils.mv(@root, temp_dir)
300
+ FileUtils.rm_rf(temp_dir)
301
+ rescue Errno::ENOENT
302
+ end
303
+
304
+ protected
305
+
306
+ def store_path(key)
307
+ key = Util.md5(key)
308
+ ::File.join(@root, key[0..1], key[2..-1])
309
+ end
310
+ end
311
+
312
+ register :file, File
313
+ end
314
+
315
+ Olelo::Store = Store