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,33 @@
1
+ require 'rack'
2
+ require 'socket'
3
+
4
+ class Rack::Request
5
+ # Remote host name
6
+ def remote_host
7
+ @remote_host ||= Socket.gethostbyaddr(ip.split('.').map(&:to_i).pack('C*')).first rescue nil
8
+ end
9
+
10
+ # No caching for this request?
11
+ def no_cache?
12
+ env['HTTP_PRAGMA'] == 'no-cache' || env['HTTP_CACHE_CONTROL'].to_s.include?('no-cache')
13
+ end
14
+ end
15
+
16
+ # Rack::Lint injector
17
+ class Rack::Builder
18
+ module UseLint
19
+ def use(middleware, *args, &block)
20
+ super Rack::Lint if middleware != Rack::Lint
21
+ super
22
+ end
23
+
24
+ def run(app)
25
+ use Rack::Lint
26
+ super
27
+ end
28
+ end
29
+
30
+ def use_lint
31
+ class << self; include UseLint; end
32
+ end
33
+ end
@@ -0,0 +1,44 @@
1
+ require 'rack'
2
+
3
+ # Rack::RelativeRedirect is a simple middleware that converts relative paths in
4
+ # redirects in absolute urls, so they conform to RFC2616. It allows the user to
5
+ # specify the absolute path to use (with a sensible default), and handles
6
+ # relative paths (those that don't start with a slash) as well.
7
+ class Rack::RelativeRedirect
8
+ SCHEME_MAP = {'http'=>'80', 'https'=>'443'}
9
+ # The default proc used if a block is not provided to .new
10
+ # Just uses the url scheme of the request and the server name.
11
+ DEFAULT_ABSOLUTE_PROC = proc do |env, res|
12
+ port = env['SERVER_PORT']
13
+ scheme = env['rack.url_scheme']
14
+ "#{scheme}://#{env['SERVER_NAME']}#{":#{port}" unless SCHEME_MAP[scheme] == port}"
15
+ end
16
+
17
+ # Initialize a new RelativeRedirect object with the given arguments. Arguments:
18
+ # * app : The next middleware in the chain. This is always called.
19
+ # * &block : If provided, it is called with the environment and the response
20
+ # from the next middleware. It should return a string representing the scheme
21
+ # and server name (such as 'http://example.org').
22
+ def initialize(app, &block)
23
+ @app = app
24
+ @absolute_proc = block || DEFAULT_ABSOLUTE_PROC
25
+ end
26
+
27
+ # Call the next middleware with the environment. If the request was a
28
+ # redirect (response status 301, 302, or 303), and the location header does
29
+ # not start with an http or https url scheme, call the block provided by new
30
+ # and use that to make the Location header an absolute url. If the Location
31
+ # does not start with a slash, make location relative to the path requested.
32
+ def call(env)
33
+ res = @app.call(env)
34
+ if [301,302,303].include?(res[0]) and loc = res[1]['Location'] and !%r{\Ahttps?://}o.match(loc)
35
+ absolute = @absolute_proc.call(env, res)
36
+ res[1]['Location'] = if %r{\A/}.match(loc)
37
+ "#{absolute}#{loc}"
38
+ else
39
+ "#{absolute}#{File.dirname(Rack::Utils.unescape(env['PATH_INFO']))}/#{loc}"
40
+ end
41
+ end
42
+ res
43
+ end
44
+ end
@@ -0,0 +1,93 @@
1
+ module Rack
2
+
3
+ #
4
+ # The Rack::StaticCache middleware automatically adds, removes and modifies
5
+ # stuffs in response headers to facilitiate client and proxy caching for static files
6
+ # that minimizes http requests and improves overall load times for second time visitors.
7
+ #
8
+ # Once a static content is stored in a client/proxy the only way to enforce the browser
9
+ # to fetch the latest content and ignore the cache is to rename the static file.
10
+ #
11
+ # Alternatively, we can add a version number into the URL to the content to bypass
12
+ # the caches. Rack::StaticCache by default handles version numbers in the filename.
13
+ # As an example,
14
+ # http://yoursite.com/images/test-1.0.0.png and http://yoursite.com/images/test-2.0.0.png
15
+ # both reffers to the same image file http://yoursite.com/images/test.png
16
+ #
17
+ # Another way to bypass the cache is adding the version number in a field-value pair in the
18
+ # URL query string. As an example, http://yoursite.com/images/test.png?v=1.0.0
19
+ # In that case, set the option :versioning to false to avoid unneccessary regexp calculations.
20
+ #
21
+ # It's better to keep the current version number in some config file and use it in every static
22
+ # content's URL. So each time we modify our static contents, we just have to change the version
23
+ # number to enforce the browser to fetch the latest content.
24
+ #
25
+ # You can use Rack::Deflater along with Rack::StaticCache for further improvements in page loading time.
26
+ #
27
+ # Examples:
28
+ # use Rack::StaticCache, :urls => ["/images", "/css", "/js", "/documents*"], :root => "statics"
29
+ # will serve all requests beginning with /images, /csss or /js from the
30
+ # directory "statics/images", "statics/css", "statics/js".
31
+ # All the files from these directories will have modified headers to enable client/proxy caching,
32
+ # except the files from the directory "documents". Append a * (star) at the end of the pattern
33
+ # if you want to disable caching for any pattern . In that case, plain static contents will be served with
34
+ # default headers.
35
+ #
36
+ # use Rack::StaticCache, :urls => ["/images"], :duration => 2, :versioning => false
37
+ # will serve all requests begining with /images under the current directory (default for the option :root
38
+ # is current directory). All the contents served will have cache expiration duration set to 2 years in headers
39
+ # (default for :duration is 1 year), and StaticCache will not compute any versioning logics (default for
40
+ # :versioning is true)
41
+ #
42
+
43
+
44
+ class StaticCache
45
+
46
+ def initialize(app, options={})
47
+ @app = app
48
+ @urls = options[:urls]
49
+ @no_cache = {}
50
+ @urls.collect! do |url|
51
+ if url =~ /\*$/
52
+ url.sub!(/\*$/, '')
53
+ @no_cache[url] = 1
54
+ end
55
+ url
56
+ end
57
+ root = options[:root] || Dir.pwd
58
+ @file_server = Rack::File.new(root)
59
+ @cache_duration = options[:duration] || 1
60
+ @versioning_enabled = true
61
+ @versioning_enabled = options[:versioning] unless options[:versioning].nil?
62
+ @duration_in_seconds = self.duration_in_seconds
63
+ @duration_in_words = self.duration_in_words
64
+ end
65
+
66
+ def call(env)
67
+ path = env["PATH_INFO"]
68
+ url = @urls.detect{ |u| path.index(u) == 0 }
69
+ unless url.nil?
70
+ path.sub!(/-[\d.]+([.][a-zA-Z][\w]+)?$/, '\1') if @versioning_enabled
71
+ status, headers, body = @file_server.call(env)
72
+ if @no_cache[url].nil?
73
+ headers['Cache-Control'] ="max-age=#{@duration_in_seconds}, public"
74
+ headers['Expires'] = @duration_in_words
75
+ headers.delete 'Etag'
76
+ headers.delete 'Pragma'
77
+ headers.delete 'Last-Modified'
78
+ end
79
+ [status, headers, body]
80
+ else
81
+ @app.call(env)
82
+ end
83
+ end
84
+
85
+ def duration_in_words
86
+ (Time.now + self.duration_in_seconds).strftime '%a, %d %b %Y %H:%M:%S GMT'
87
+ end
88
+
89
+ def duration_in_seconds
90
+ 60 * 60 * 24 * 365 * @cache_duration
91
+ end
92
+ end
93
+ end
@@ -0,0 +1 @@
1
+ Dir[File.dirname(__FILE__) + '/addons/*.rb'].each {|file| require file }
@@ -0,0 +1,25 @@
1
+ module YARD
2
+ module Handlers
3
+ class HookHandler < Ruby::Base
4
+ handles method_call(:hook)
5
+ handles method_call(:before)
6
+ handles method_call(:after)
7
+
8
+ def process
9
+ hook = statement.parameters.first.source
10
+ return if hook =~ /^"(BEFORE|AFTER)/
11
+ name = "#{statement.method_name(true).to_s.upcase} #{hook}"
12
+ route = register CodeObjects::MethodObject.new(namespace, name, :instance) do |o|
13
+ o.visibility = "public"
14
+ o.source = statement.source
15
+ o.signature = name
16
+ o.explicit = true
17
+ o.scope = scope
18
+ o.docstring = statement.comments
19
+ o.sanitize_anchor = true
20
+ o.add_file(parser.file, statement.line)
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,14 @@
1
+ module YARD::Tags
2
+ class OverrideTag < Tag
3
+ def initialize(tag_name, text)
4
+ super(tag_name, text)
5
+ end
6
+
7
+ def text
8
+ "{#{object.namespace.superclass}##{object.name(false)}}"
9
+ end
10
+ end
11
+
12
+ Library.define_tag "Override", :override, OverrideTag
13
+ Library.visible_tags.place(:override).before(:return)
14
+ end
@@ -0,0 +1,33 @@
1
+ module YARD
2
+ module Handlers
3
+ class RouteHandler < Ruby::Base
4
+ handles method_call(:get)
5
+ handles method_call(:post)
6
+ handles method_call(:put)
7
+ handles method_call(:delete)
8
+ handles method_call(:head)
9
+
10
+ def register_route(name, explicit)
11
+ register CodeObjects::MethodObject.new(namespace, name, :instance) do |o|
12
+ o.visibility = "public"
13
+ o.source = statement.source
14
+ o.signature = name
15
+ o.explicit = explicit
16
+ o.scope = scope
17
+ o.docstring = statement.comments
18
+ o.sanitize_anchor = true
19
+ o.add_file(parser.file, statement.line)
20
+ end
21
+ end
22
+
23
+ def process
24
+ path = statement.parameters.first.source
25
+ if path =~ /'(.*)'/
26
+ verb = statement.method_name(true).to_s.upcase
27
+ register_route("HEAD #{$1}", false) if verb == 'GET'
28
+ register_route("#{verb} #{$1}", true)
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,16 @@
1
+ module YARD
2
+ class CodeObjects::Base
3
+ attr_accessor :sanitize_anchor
4
+ end
5
+
6
+ module Templates::Helpers::HtmlHelper
7
+ alias anchor_for_without_sanitize anchor_for
8
+ def anchor_for(object)
9
+ if CodeObjects::Base === object && object.sanitize_anchor
10
+ anchor_for_without_sanitize(object).gsub(/[^\w_\-]/, '_')
11
+ else
12
+ anchor_for_without_sanitize(object)
13
+ end
14
+ end
15
+ end
16
+ end
data/olelo.gemspec ADDED
@@ -0,0 +1,31 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.dirname(__FILE__) + '/lib/olelo/version'
3
+ require 'date'
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = 'olelo'
7
+ s.version = Olelo::VERSION
8
+ s.date = Date.today.to_s
9
+ s.authors = ['Daniel Mendler']
10
+ s.email = ['mail@daniel-mendler.de']
11
+ s.summary = 'Olelo is a git-based wiki.'
12
+ s.summary = 'Olelo is a git-based wiki which supports many markup languages, tags, embedded TeX and much more. It can be extended through plugins.'
13
+ s.homepage = 'http://gitwiki.org/'
14
+ s.rubyforge_project = s.name
15
+
16
+ s.files = `git ls-files | grep -P -v '^tools/'`.split("\n")
17
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
18
+ s.require_paths = %w(lib)
19
+
20
+ s.add_runtime_dependency('tilt', ['~> 1.3.3'])
21
+ s.add_runtime_dependency('slim', ['~> 1.3.3'])
22
+ s.add_runtime_dependency('creole', ['~> 0.4.2'])
23
+ s.add_runtime_dependency('nokogiri', ['~> 1.5.5'])
24
+ s.add_runtime_dependency('mimemagic', ['~> 0.1.9'])
25
+ s.add_runtime_dependency('rack', ['~> 1.4.1'])
26
+ s.add_runtime_dependency('redcarpet', ['~> 2.1.1'])
27
+ s.add_runtime_dependency('rugged', ['~> 0.17.0b6'])
28
+
29
+ s.add_development_dependency('rake', ['>= 0.8.7'])
30
+ s.add_development_dependency('sass', ['>= 3.1.0'])
31
+ end
@@ -0,0 +1,45 @@
1
+ # -*- coding: utf-8 -*-
2
+ description 'Changelog Aspect'
3
+ require 'rss/maker'
4
+
5
+ Aspect.create(:changelog, :cacheable => true, :hidden => true) do
6
+ def call(context, page)
7
+ format = context.params[:format]
8
+
9
+ url = context.request.base_url
10
+ context.header['Content-Type'] = "application/#{format == 'rss' ? 'rss' : 'atom'}+xml; charset=utf-8"
11
+
12
+ content = RSS::Maker.make(format == 'rss' ? '2.0' : 'atom') do |feed|
13
+ feed.channel.generator = 'Ōlelo'
14
+ feed.channel.title = Config['title']
15
+ feed.channel.link = url + '/' + page.path
16
+ feed.channel.description = Config['title'] + ' Changelog'
17
+ feed.channel.id = url + page.path
18
+ feed.channel.updated = Time.now
19
+ feed.channel.author = Config['title']
20
+ feed.items.do_sort = true
21
+ page.history.each do |version|
22
+ i = feed.items.new_item
23
+ i.title = version.comment
24
+ i.link = url + '/changes'/version
25
+ i.date = version.date
26
+ i.dc_creator = version.author.name
27
+ end
28
+ end
29
+ content.to_s
30
+ end
31
+ end
32
+
33
+ Application.hook :head do
34
+ %{<link rel="alternate" type="application/atom+xml" title="Sitewide Atom Changelog"
35
+ href="#{escape_html build_path('/', :aspect => 'changelog', :format => 'atom')}"/>
36
+ <link rel="alternate" type="application/rss+xml" title="Sitewide RSS Changelog"
37
+ href="#{escape_html build_path('/', :aspect => 'changelog', :format => 'rss')}"/>}
38
+ end
39
+
40
+ Application.hook :head do
41
+ %{<link rel="alternate" type="application/atom+xml" title="#{escape_html page.path} Atom Changelog"
42
+ href="#{escape_html(build_path(page.path, :aspect => 'changelog', :format => 'atom'))}"/>
43
+ <link rel="alternate" type="application/rss+xml" title="#{escape_html page.path} RSS Changelog"
44
+ href="#{escape_html(build_path(page.path, :aspect => 'changelog', :format => 'rss'))}"/>} if page && !page.new? && !page.root?
45
+ end
@@ -0,0 +1,57 @@
1
+ description 'Document browser aspect'
2
+ dependencies 'utils/shell'
3
+
4
+ Aspect.create(:documentbrowser, :priority => 1, :layout => true, :cacheable => true, :accepts => %r{^application/pdf$|postscript$}) do
5
+ def count_pages
6
+ content = @page.content
7
+ page_count = 0
8
+ if @page.mime == 'application/pdf'
9
+ page_count = $1.to_i if Shell.pdfinfo('-').run(content) =~ /Pages:\s+(\d+)/
10
+ else
11
+ content = Shell.cmd($1 == 'gz' ? 'gunzip' : 'bunzip2').run(content) if @page.mime.to_s =~ /(gz|bz)/
12
+ page_count = $1.to_i if content =~ /^%%Pages:\s+(\d+)$/
13
+ end
14
+ page_count
15
+ end
16
+
17
+ def call(context, page)
18
+ @page = page
19
+ @page_nr = [context.params[:page].to_i, 1].max
20
+ @page_count = count_pages
21
+ render :browser
22
+ end
23
+ end
24
+
25
+ __END__
26
+
27
+ @@ browser.slim
28
+ = pagination(@page, @page_count, @page_nr, :aspect => 'documentbrowser')
29
+ p
30
+ img src=build_path(@page, :aspect => 'image', :geometry => '480x>', :trim => 1, :page => @page_nr)
31
+ = pagination(@page, @page_count, @page_nr, :aspect => 'documentbrowser')
32
+ h3= :information.t
33
+ table
34
+ tbody
35
+ tr
36
+ td= :name.t
37
+ td= @page.name
38
+ tr
39
+ td= :title.t
40
+ td= @page.title
41
+ tr
42
+ td= :description.t
43
+ td= @page.attributes['description']
44
+ - if @page.version
45
+ tr
46
+ td= :last_modified.t
47
+ td= date @page.version.date
48
+ tr
49
+ td= :version.t
50
+ td.version= @page.version
51
+ tr
52
+ td= :type.t
53
+ td= @page.mime.comment.blank? ? @page.mime : "#{@page.mime.comment} (#{@page.mime})"
54
+ tr
55
+ td= :download.t
56
+ td
57
+ a href=build_path(@page, :aspect => 'download') = :download.t
@@ -0,0 +1,11 @@
1
+ description 'Download aspect'
2
+
3
+ Aspect.create(:download) do
4
+ def accepts?(page); !page.content.empty?; end
5
+ def call(context, page)
6
+ name = page.root? ? :root.t : page.name.gsub(/[^\w.\-_]/, '_')
7
+ context.header['Content-Disposition'] = %{attachment; filename="#{name}"}
8
+ context.header['Content-Length'] = page.content.bytesize.to_s
9
+ page.content
10
+ end
11
+ end
@@ -0,0 +1,8 @@
1
+ description 'Source code highlighting aspect'
2
+ dependencies 'utils/pygments'
3
+
4
+ Aspect.create(:highlight, :priority => 2, :layout => true, :cacheable => true) do
5
+ def accepts?(page); !page.content.empty? && Pygments.file_format(page.name); end
6
+ def call(context, page); Pygments.pygmentize(page.content, Pygments.file_format(page.name)); end
7
+ end
8
+
@@ -0,0 +1,41 @@
1
+ description 'Image aspect'
2
+ dependencies 'utils/image_magick'
3
+
4
+ Aspect.create(:image, :priority => 5, :accepts => %r{^application/pdf$|postscript$|^image/}, :cacheable => true) do
5
+ def call(context, page)
6
+ geometry = context.params[:geometry]
7
+ trim = context.params[:trim]
8
+ ps = page.mime.to_s =~ /postscript/
9
+ if ps || page.mime == 'application/pdf'
10
+ page_nr = [context.params[:page].to_i, 1].max
11
+ cmd = ImageMagick.new
12
+ if ps
13
+ cmd.cmd($1 == 'gz' ? 'gunzip' : 'bunzip2') if page.mime.to_s =~ /(bz|gz)/
14
+ cmd.psselect "-p#{page_nr}"
15
+ cmd.gs('-sDEVICE=jpeg', '-sOutputFile=-', '-r144', '-dBATCH', '-dNOPAUSE', '-q', '-')
16
+ end
17
+ cmd.convert('-depth', 8, '-quality', 50) do |args|
18
+ args << '-trim' if trim
19
+ args << '-thumbnail' << geometry if geometry =~ /^(\d+)?x?(\d+)?[%!<>]*$/
20
+ if ps
21
+ args << '-'
22
+ else
23
+ args << '-density' << 144 << "-[#{page_nr - 1}]"
24
+ end
25
+ args << 'JPEG:-'
26
+ end
27
+ context.header['Content-Type'] = 'image/jpeg'
28
+ cmd.run(page.content)
29
+ elsif page.mime.to_s =~ /svg/ || geometry || trim
30
+ cmd = ImageMagick.convert do |args|
31
+ args << '-trim' if trim
32
+ args << '-thumbnail' << geometry if geometry =~ /^(\d+)?x?(\d+)?[%!<>]*$/
33
+ args << '-' << (page.mime.to_s == 'image/jpeg' ? 'JPEG:-' : 'PNG:-')
34
+ end
35
+ context.header['Content-Type'] = 'image/png'
36
+ cmd.run(page.content)
37
+ else
38
+ page.content
39
+ end
40
+ end
41
+ end