Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Initial commit

  • Loading branch information...
commit 4d3e95dafe6c2068f038c41ee3f4ed9649fba15c 0 parents
@michaelklishin authored
Showing with 81,092 additions and 0 deletions.
  1. +33 −0 Rakefile
  2. +2 −0  app/controllers/application.rb
  3. +13 −0 app/controllers/exceptions.rb
  4. +22 −0 app/controllers/files.rb
  5. +5 −0 app/helpers/files_helper.rb
  6. +5 −0 app/helpers/global_helpers.rb
  7. +9 −0 app/models/merb/session.rb
  8. +216 −0 app/views/exceptions/internal_server_error.html.erb
  9. +63 −0 app/views/exceptions/not_acceptable.html.erb
  10. +47 −0 app/views/exceptions/not_found.html.erb
  11. +1 −0  app/views/files/index.html.erb
  12. +11 −0 app/views/layout/application.html.erb
  13. +1 −0  autotest/discover.rb
  14. +149 −0 autotest/merb.rb
  15. +165 −0 autotest/merb_rspec.rb
  16. +9 −0 config/environments/development.rb
  17. +7 −0 config/environments/production.rb
  18. +7 −0 config/environments/rake.rb
  19. +6 −0 config/environments/test.rb
  20. +192 −0 config/init.rb
  21. +35 −0 config/nginx.config.sample
  22. +12 −0 config/rack.rb
  23. +6 −0 config/router.rb
  24. +822 −0 merb.thor
  25. +23 −0 public/files/bin/merb
  26. +23 −0 public/files/bin/merb-gen
  27. +23 −0 public/files/bin/rake
  28. +23 −0 public/files/bin/rake2thor
  29. +23 −0 public/files/bin/spec
  30. +23 −0 public/files/bin/spec_translator
  31. +23 −0 public/files/bin/thor
  32. +19 −0 public/files/gems/bin/css2sass
  33. +19 −0 public/files/gems/bin/edit_json.rb
  34. +19 −0 public/files/gems/bin/erubis
  35. +19 −0 public/files/gems/bin/haml
  36. +19 −0 public/files/gems/bin/html2haml
  37. +19 −0 public/files/gems/bin/htmldiff
  38. +19 −0 public/files/gems/bin/ldiff
  39. +19 −0 public/files/gems/bin/merb
  40. +19 −0 public/files/gems/bin/merb-gen
  41. +19 −0 public/files/gems/bin/parse_tree_abc
  42. +19 −0 public/files/gems/bin/parse_tree_audit
  43. +19 −0 public/files/gems/bin/parse_tree_deps
  44. +19 −0 public/files/gems/bin/parse_tree_show
  45. +19 −0 public/files/gems/bin/r2r_show
  46. +19 −0 public/files/gems/bin/rackup
  47. +19 −0 public/files/gems/bin/rake
  48. +19 −0 public/files/gems/bin/rake2thor
  49. +19 −0 public/files/gems/bin/rubyforge
  50. +19 −0 public/files/gems/bin/sass
  51. +19 −0 public/files/gems/bin/sow
  52. +19 −0 public/files/gems/bin/spec
  53. +19 −0 public/files/gems/bin/spec_translator
  54. +19 −0 public/files/gems/bin/thor
  55. BIN  public/files/gems/cache/ParseTree-2.2.0.gem
  56. BIN  public/files/gems/cache/RubyInline-3.7.0.gem
  57. BIN  public/files/gems/cache/abstract-1.0.0.gem
  58. BIN  public/files/gems/cache/builder-2.1.2.gem
  59. BIN  public/files/gems/cache/diff-lcs-1.1.2.gem
  60. BIN  public/files/gems/cache/english-0.2.0.gem
  61. BIN  public/files/gems/cache/erubis-2.6.2.gem
  62. BIN  public/files/gems/cache/extlib-0.9.7.gem
  63. BIN  public/files/gems/cache/facets-2.4.4.gem
  64. BIN  public/files/gems/cache/haml-2.0.3.gem
  65. BIN  public/files/gems/cache/highline-1.4.0.gem
  66. BIN  public/files/gems/cache/hoe-1.7.0.gem
  67. BIN  public/files/gems/cache/hpricot-0.6.161.gem
  68. BIN  public/files/gems/cache/json_pure-1.1.3.gem
  69. BIN  public/files/gems/cache/mailfactory-1.4.0.gem
  70. BIN  public/files/gems/cache/merb-action-args-0.9.8.gem
  71. BIN  public/files/gems/cache/merb-assets-0.9.8.gem
  72. BIN  public/files/gems/cache/merb-builder-0.9.8.gem
  73. BIN  public/files/gems/cache/merb-cache-0.9.8.gem
  74. BIN  public/files/gems/cache/merb-core-0.9.8.gem
  75. BIN  public/files/gems/cache/merb-gen-0.9.8.gem
  76. BIN  public/files/gems/cache/merb-haml-0.9.8.gem
  77. BIN  public/files/gems/cache/merb-jquery-0.9.8.gem
  78. BIN  public/files/gems/cache/merb-mailer-0.9.8.gem
  79. BIN  public/files/gems/cache/merb-more-0.9.8.gem
  80. BIN  public/files/gems/cache/merb-parts-0.9.8.gem
  81. BIN  public/files/gems/cache/merb-slices-0.9.8.gem
  82. BIN  public/files/gems/cache/mime-types-1.15.gem
  83. BIN  public/files/gems/cache/rack-0.4.0.gem
  84. BIN  public/files/gems/cache/rake-0.8.1.gem
  85. BIN  public/files/gems/cache/rspec-1.1.4.gem
  86. BIN  public/files/gems/cache/ruby2ruby-1.1.9.gem
  87. BIN  public/files/gems/cache/rubyforge-1.0.0.gem
  88. BIN  public/files/gems/cache/templater-0.2.gem
  89. BIN  public/files/gems/cache/thor-0.9.6.gem
  90. +3 −0  public/files/gems/gems/ParseTree-2.2.0/.require_paths
  91. +346 −0 public/files/gems/gems/ParseTree-2.2.0/History.txt
  92. +24 −0 public/files/gems/gems/ParseTree-2.2.0/Manifest.txt
  93. +115 −0 public/files/gems/gems/ParseTree-2.2.0/README.txt
  94. +32 −0 public/files/gems/gems/ParseTree-2.2.0/Rakefile
  95. +89 −0 public/files/gems/gems/ParseTree-2.2.0/bin/parse_tree_abc
  96. +28 −0 public/files/gems/gems/ParseTree-2.2.0/bin/parse_tree_audit
  97. +62 −0 public/files/gems/gems/ParseTree-2.2.0/bin/parse_tree_deps
  98. +60 −0 public/files/gems/gems/ParseTree-2.2.0/bin/parse_tree_show
  99. +20 −0 public/files/gems/gems/ParseTree-2.2.0/demo/printer.rb
  100. +49 −0 public/files/gems/gems/ParseTree-2.2.0/lib/composite_sexp_processor.rb
  101. +1,097 −0 public/files/gems/gems/ParseTree-2.2.0/lib/parse_tree.rb
  102. +282 −0 public/files/gems/gems/ParseTree-2.2.0/lib/sexp.rb
  103. +336 −0 public/files/gems/gems/ParseTree-2.2.0/lib/sexp_processor.rb
  104. +187 −0 public/files/gems/gems/ParseTree-2.2.0/lib/unified_ruby.rb
  105. +15 −0 public/files/gems/gems/ParseTree-2.2.0/lib/unique.rb
  106. +2,471 −0 public/files/gems/gems/ParseTree-2.2.0/test/pt_testcase.rb
  107. +53 −0 public/files/gems/gems/ParseTree-2.2.0/test/something.rb
  108. +13 −0 public/files/gems/gems/ParseTree-2.2.0/test/test_all.rb
  109. +70 −0 public/files/gems/gems/ParseTree-2.2.0/test/test_composite_sexp_processor.rb
  110. +227 −0 public/files/gems/gems/ParseTree-2.2.0/test/test_parse_tree.rb
  111. +313 −0 public/files/gems/gems/ParseTree-2.2.0/test/test_sexp.rb
  112. +297 −0 public/files/gems/gems/ParseTree-2.2.0/test/test_sexp_processor.rb
  113. +257 −0 public/files/gems/gems/ParseTree-2.2.0/test/test_unified_ruby.rb
  114. +31 −0 public/files/gems/gems/ParseTree-2.2.0/validate.sh
  115. +338 −0 public/files/gems/gems/RubyInline-3.7.0/History.txt
  116. +12 −0 public/files/gems/gems/RubyInline-3.7.0/Manifest.txt
  117. +139 −0 public/files/gems/gems/RubyInline-3.7.0/README.txt
  118. +34 −0 public/files/gems/gems/RubyInline-3.7.0/Rakefile
  119. +27 −0 public/files/gems/gems/RubyInline-3.7.0/demo/fastmath.rb
  120. +13 −0 public/files/gems/gems/RubyInline-3.7.0/demo/hello.rb
  121. +86 −0 public/files/gems/gems/RubyInline-3.7.0/example.rb
  122. +34 −0 public/files/gems/gems/RubyInline-3.7.0/example2.rb
  123. +704 −0 public/files/gems/gems/RubyInline-3.7.0/lib/inline.rb
  124. +688 −0 public/files/gems/gems/RubyInline-3.7.0/test/test_inline.rb
  125. +63 −0 public/files/gems/gems/RubyInline-3.7.0/tutorial/example1.rb
  126. +96 −0 public/files/gems/gems/RubyInline-3.7.0/tutorial/example2.rb
  127. +3 −0  public/files/gems/gems/abstract-1.0.0/ChangeLog
  128. +57 −0 public/files/gems/gems/abstract-1.0.0/README.txt
  129. +48 −0 public/files/gems/gems/abstract-1.0.0/abstract.gemspec
  130. +75 −0 public/files/gems/gems/abstract-1.0.0/lib/abstract.rb
  131. +1,331 −0 public/files/gems/gems/abstract-1.0.0/setup.rb
  132. +91 −0 public/files/gems/gems/abstract-1.0.0/test/test.rb
  133. +85 −0 public/files/gems/gems/builder-2.1.2/CHANGES
  134. +210 −0 public/files/gems/gems/builder-2.1.2/README
  135. +263 −0 public/files/gems/gems/builder-2.1.2/Rakefile
  136. +31 −0 public/files/gems/gems/builder-2.1.2/doc/releases/builder-1.2.4.rdoc
  137. +46 −0 public/files/gems/gems/builder-2.1.2/doc/releases/builder-2.0.0.rdoc
  138. +58 −0 public/files/gems/gems/builder-2.1.2/doc/releases/builder-2.1.1.rdoc
  139. +113 −0 public/files/gems/gems/builder-2.1.2/lib/blankslate.rb
  140. +13 −0 public/files/gems/gems/builder-2.1.2/lib/builder.rb
  141. +20 −0 public/files/gems/gems/builder-2.1.2/lib/builder/blankslate.rb
  142. +115 −0 public/files/gems/gems/builder-2.1.2/lib/builder/xchar.rb
  143. +139 −0 public/files/gems/gems/builder-2.1.2/lib/builder/xmlbase.rb
  144. +63 −0 public/files/gems/gems/builder-2.1.2/lib/builder/xmlevents.rb
  145. +328 −0 public/files/gems/gems/builder-2.1.2/lib/builder/xmlmarkup.rb
  146. +17 −0 public/files/gems/gems/builder-2.1.2/scripts/publish.rb
  147. +30 −0 public/files/gems/gems/builder-2.1.2/test/performance.rb
  148. +29 −0 public/files/gems/gems/builder-2.1.2/test/preload.rb
  149. +37 −0 public/files/gems/gems/builder-2.1.2/test/test_xchar.rb
  150. +183 −0 public/files/gems/gems/builder-2.1.2/test/testblankslate.rb
  151. +133 −0 public/files/gems/gems/builder-2.1.2/test/testeventbuilder.rb
  152. +449 −0 public/files/gems/gems/builder-2.1.2/test/testmarkupbuilder.rb
  153. +46 −0 public/files/gems/gems/diff-lcs-1.1.2/ChangeLog
  154. +6 −0 public/files/gems/gems/diff-lcs-1.1.2/Install
  155. +76 −0 public/files/gems/gems/diff-lcs-1.1.2/README
  156. +116 −0 public/files/gems/gems/diff-lcs-1.1.2/Rakefile
  157. +112 −0 public/files/gems/gems/diff-lcs-1.1.2/bin/htmldiff
  158. +45 −0 public/files/gems/gems/diff-lcs-1.1.2/bin/ldiff
  159. +1,105 −0 public/files/gems/gems/diff-lcs-1.1.2/lib/diff/lcs.rb
  160. +21 −0 public/files/gems/gems/diff-lcs-1.1.2/lib/diff/lcs/array.rb
  161. +51 −0 public/files/gems/gems/diff-lcs-1.1.2/lib/diff/lcs/block.rb
  162. +322 −0 public/files/gems/gems/diff-lcs-1.1.2/lib/diff/lcs/callbacks.rb
  163. +169 −0 public/files/gems/gems/diff-lcs-1.1.2/lib/diff/lcs/change.rb
  164. +257 −0 public/files/gems/gems/diff-lcs-1.1.2/lib/diff/lcs/hunk.rb
  165. +226 −0 public/files/gems/gems/diff-lcs-1.1.2/lib/diff/lcs/ldiff.rb
  166. +19 −0 public/files/gems/gems/diff-lcs-1.1.2/lib/diff/lcs/string.rb
  167. +626 −0 public/files/gems/gems/diff-lcs-1.1.2/tests/00test.rb
  168. +5 −0 public/files/gems/gems/english-0.2.0/CHANGES
  169. +355 −0 public/files/gems/gems/english-0.2.0/COPYING
  170. +12 −0 public/files/gems/gems/english-0.2.0/NOTES
  171. +47 −0 public/files/gems/gems/english-0.2.0/README
  172. +76 −0 public/files/gems/gems/english-0.2.0/lib/english/censor.rb
  173. +353 −0 public/files/gems/gems/english-0.2.0/lib/english/double_metaphone.rb
  174. +56 −0 public/files/gems/gems/english-0.2.0/lib/english/dresner.rb
  175. +213 −0 public/files/gems/gems/english-0.2.0/lib/english/inflect.rb
  176. +44 −0 public/files/gems/gems/english-0.2.0/lib/english/jumble.rb
  177. +78 −0 public/files/gems/gems/english-0.2.0/lib/english/levenshtein.rb
  178. +110 −0 public/files/gems/gems/english-0.2.0/lib/english/metaphone.rb
  179. +71 −0 public/files/gems/gems/english-0.2.0/lib/english/numerals.rb
  180. +49 −0 public/files/gems/gems/english-0.2.0/lib/english/patterns.rb
  181. +188 −0 public/files/gems/gems/english-0.2.0/lib/english/porter_stemming.rb
  182. +174 −0 public/files/gems/gems/english-0.2.0/lib/english/roman.rb
  183. +103 −0 public/files/gems/gems/english-0.2.0/lib/english/similarity.rb
  184. +70 −0 public/files/gems/gems/english-0.2.0/lib/english/soundex.rb
  185. +91 −0 public/files/gems/gems/english-0.2.0/lib/english/textfilter.rb
  186. +81 −0 public/files/gems/gems/english-0.2.0/log/Changelog.txt
  187. +85 −0 public/files/gems/gems/english-0.2.0/log/Testlog.txt
  188. +52 −0 public/files/gems/gems/english-0.2.0/meta/MANIFEST
  189. +2 −0  public/files/gems/gems/english-0.2.0/meta/dependencies
  190. +2 −0  public/files/gems/gems/english-0.2.0/meta/description
  191. +21 −0 public/files/gems/gems/english-0.2.0/meta/project.yaml
  192. +1 −0  public/files/gems/gems/english-0.2.0/meta/version
  193. +6 −0 public/files/gems/gems/english-0.2.0/task/clobber
  194. +10 −0 public/files/gems/gems/english-0.2.0/task/rdoc
  195. +1,616 −0 public/files/gems/gems/english-0.2.0/task/setup
  196. +29 −0 public/files/gems/gems/english-0.2.0/task/test
  197. +1,217 −0 public/files/gems/gems/english-0.2.0/test/fixture/double_metaphone.txt
  198. +51 −0 public/files/gems/gems/english-0.2.0/test/fixture/metaphone.txt
  199. +52 −0 public/files/gems/gems/english-0.2.0/test/fixture/metaphone_lp.txt
  200. +23,531 −0 public/files/gems/gems/english-0.2.0/test/fixture/porter_stemming_input.txt
  201. +23,531 −0 public/files/gems/gems/english-0.2.0/test/fixture/porter_stemming_output.txt
  202. +15 −0 public/files/gems/gems/english-0.2.0/test/fixture/soundex.txt
  203. +18 −0 public/files/gems/gems/english-0.2.0/test/test_censor.rb
  204. +23 −0 public/files/gems/gems/english-0.2.0/test/test_double_metaphone.rb
  205. +17 −0 public/files/gems/gems/english-0.2.0/test/test_dresner.rb
  206. +93 −0 public/files/gems/gems/english-0.2.0/test/test_inflect.rb
  207. +82 −0 public/files/gems/gems/english-0.2.0/test/test_levenshtein.rb
  208. +46 −0 public/files/gems/gems/english-0.2.0/test/test_metaphone.rb
  209. +22 −0 public/files/gems/gems/english-0.2.0/test/test_porter_stemming.rb
  210. +13 −0 public/files/gems/gems/english-0.2.0/test/test_similarity.rb
  211. +25 −0 public/files/gems/gems/english-0.2.0/test/test_soundex.rb
  212. +717 −0 public/files/gems/gems/erubis-2.6.2/CHANGES.txt
  213. +20 −0 public/files/gems/gems/erubis-2.6.2/MIT-LICENSE
  214. +102 −0 public/files/gems/gems/erubis-2.6.2/README.txt
  215. +6 −0 public/files/gems/gems/erubis-2.6.2/benchmark/Makefile
  216. +314 −0 public/files/gems/gems/erubis-2.6.2/benchmark/bench.rb
  217. +141 −0 public/files/gems/gems/erubis-2.6.2/benchmark/bench_context.yaml
  218. +4 −0 public/files/gems/gems/erubis-2.6.2/benchmark/templates/_footer.html
  219. +52 −0 public/files/gems/gems/erubis-2.6.2/benchmark/templates/_header.html
  220. +29 −0 public/files/gems/gems/erubis-2.6.2/benchmark/templates/bench_erb.rhtml
  221. +29 −0 public/files/gems/gems/erubis-2.6.2/benchmark/templates/bench_erubis.rhtml
  222. +29 −0 public/files/gems/gems/erubis-2.6.2/benchmark/templates/bench_eruby.rhtml
  223. +11 −0 public/files/gems/gems/erubis-2.6.2/bin/erubis
  224. +11 −0 public/files/gems/gems/erubis-2.6.2/contrib/erubis
  225. +132 −0 public/files/gems/gems/erubis-2.6.2/contrib/erubis-run.rb
  226. +153 −0 public/files/gems/gems/erubis-2.6.2/contrib/inline-require
  227. +105 −0 public/files/gems/gems/erubis-2.6.2/doc-api/classes/ActionView.html
  228. +181 −0 public/files/gems/gems/erubis-2.6.2/doc-api/classes/ActionView/TemplateHandlers/ErubisHandler.html
  229. +101 −0 public/files/gems/gems/erubis-2.6.2/doc-api/classes/ERB.html
  230. +353 −0 public/files/gems/gems/erubis-2.6.2/doc-api/classes/Erubis.html
  231. +175 −0 public/files/gems/gems/erubis-2.6.2/doc-api/classes/Erubis/ArrayBufferEnhancer.html
  232. +120 −0 public/files/gems/gems/erubis-2.6.2/doc-api/classes/Erubis/ArrayBufferEruby.html
  233. +174 −0 public/files/gems/gems/erubis-2.6.2/doc-api/classes/Erubis/ArrayEnhancer.html
  234. +120 −0 public/files/gems/gems/erubis-2.6.2/doc-api/classes/Erubis/ArrayEruby.html
  235. +112 −0 public/files/gems/gems/erubis-2.6.2/doc-api/classes/Erubis/Basic.html
  236. +327 −0 public/files/gems/gems/erubis-2.6.2/doc-api/classes/Erubis/Basic/Converter.html
  237. +130 −0 public/files/gems/gems/erubis-2.6.2/doc-api/classes/Erubis/Basic/Engine.html
  238. +215 −0 public/files/gems/gems/erubis-2.6.2/doc-api/classes/Erubis/BiPatternEnhancer.html
  239. +120 −0 public/files/gems/gems/erubis-2.6.2/doc-api/classes/Erubis/BiPatternEruby.html
  240. +386 −0 public/files/gems/gems/erubis-2.6.2/doc-api/classes/Erubis/CGenerator.html
  241. +113 −0 public/files/gems/gems/erubis-2.6.2/doc-api/classes/Erubis/CommandOptionError.html
  242. +344 −0 public/files/gems/gems/erubis-2.6.2/doc-api/classes/Erubis/Context.html
  243. +283 −0 public/files/gems/gems/erubis-2.6.2/doc-api/classes/Erubis/Converter.html
  244. +150 −0 public/files/gems/gems/erubis-2.6.2/doc-api/classes/Erubis/DeleteIndentEnhancer.html
  245. +120 −0 public/files/gems/gems/erubis-2.6.2/doc-api/classes/Erubis/DeleteIndentEruby.html
  246. +126 −0 public/files/gems/gems/erubis-2.6.2/doc-api/classes/Erubis/Ec.html
  247. +126 −0 public/files/gems/gems/erubis-2.6.2/doc-api/classes/Erubis/Ejava.html
  248. +126 −0 public/files/gems/gems/erubis-2.6.2/doc-api/classes/Erubis/Ejavascript.html
  249. +305 −0 public/files/gems/gems/erubis-2.6.2/doc-api/classes/Erubis/Engine.html
  250. +126 −0 public/files/gems/gems/erubis-2.6.2/doc-api/classes/Erubis/Eperl.html
  251. +126 −0 public/files/gems/gems/erubis-2.6.2/doc-api/classes/Erubis/Ephp.html
  252. +175 −0 public/files/gems/gems/erubis-2.6.2/doc-api/classes/Erubis/ErboutEnhancer.html
  253. +120 −0 public/files/gems/gems/erubis-2.6.2/doc-api/classes/Erubis/ErboutEruby.html
  254. +117 −0 public/files/gems/gems/erubis-2.6.2/doc-api/classes/Erubis/ErubisError.html
  255. +132 −0 public/files/gems/gems/erubis-2.6.2/doc-api/classes/Erubis/Eruby.html
  256. +165 −0 public/files/gems/gems/erubis-2.6.2/doc-api/classes/Erubis/EscapeEnhancer.html
  257. +120 −0 public/files/gems/gems/erubis-2.6.2/doc-api/classes/Erubis/EscapedEc.html
  258. +120 −0 public/files/gems/gems/erubis-2.6.2/doc-api/classes/Erubis/EscapedEjava.html
  259. +120 −0 public/files/gems/gems/erubis-2.6.2/doc-api/classes/Erubis/EscapedEjavascript.html
  260. +120 −0 public/files/gems/gems/erubis-2.6.2/doc-api/classes/Erubis/EscapedEperl.html
  261. +120 −0 public/files/gems/gems/erubis-2.6.2/doc-api/classes/Erubis/EscapedEphp.html
  262. +127 −0 public/files/gems/gems/erubis-2.6.2/doc-api/classes/Erubis/EscapedEruby.html
  263. +120 −0 public/files/gems/gems/erubis-2.6.2/doc-api/classes/Erubis/EscapedEscheme.html
  264. +126 −0 public/files/gems/gems/erubis-2.6.2/doc-api/classes/Erubis/Escheme.html
  265. +212 −0 public/files/gems/gems/erubis-2.6.2/doc-api/classes/Erubis/Evaluator.html
  266. +131 −0 public/files/gems/gems/erubis-2.6.2/doc-api/classes/Erubis/FastEruby.html
  267. +416 −0 public/files/gems/gems/erubis-2.6.2/doc-api/classes/Erubis/Generator.html
  268. +267 −0 public/files/gems/gems/erubis-2.6.2/doc-api/classes/Erubis/HeaderFooterEnhancer.html
  269. +120 −0 public/files/gems/gems/erubis-2.6.2/doc-api/classes/Erubis/HeaderFooterEruby.html
  270. +116 −0 public/files/gems/gems/erubis-2.6.2/doc-api/classes/Erubis/Helpers.html
  271. +787 −0 public/files/gems/gems/erubis-2.6.2/doc-api/classes/Erubis/Helpers/RailsFormHelper.html
Sorry, we could not display the entire diff because too many files (3,303) changed.
33 Rakefile
@@ -0,0 +1,33 @@
+require 'rubygems'
+require 'rake'
+require 'rake/rdoctask'
+require 'rake/testtask'
+require 'spec/rake/spectask'
+require 'fileutils'
+
+require "merb-core"
+require 'merb-core/tasks/merb'
+include FileUtils
+
+# Load the basic runtime dependencies; this will include
+# any plugins and therefore plugin rake tasks.
+init_env = ENV['MERB_ENV'] || 'rake'
+Merb.load_dependencies(:environment => init_env)
+
+# Get Merb plugins and dependencies
+Merb::Plugins.rakefiles.each { |r| require r }
+
+# Load any app level custom rakefile extensions from lib/tasks
+tasks_path = File.join(File.dirname(__FILE__), "lib", "tasks")
+rake_files = Dir["#{tasks_path}/*.rake"]
+rake_files.each{|rake_file| load rake_file }
+
+desc "start runner environment"
+task :merb_env do
+ Merb.start_environment(:environment => init_env, :adapter => 'runner')
+end
+
+##############################################################################
+# ADD YOUR CUSTOM TASKS IN /lib/tasks
+# NAME YOUR RAKE FILES file_name.rake
+##############################################################################
2  app/controllers/application.rb
@@ -0,0 +1,2 @@
+class Application < Merb::Controller
+end
13 app/controllers/exceptions.rb
@@ -0,0 +1,13 @@
+class Exceptions < Application
+
+ # handle NotFound exceptions (404)
+ def not_found
+ render :format => :html
+ end
+
+ # handle NotAcceptable exceptions (406)
+ def not_acceptable
+ render :format => :html
+ end
+
+end
22 app/controllers/files.rb
@@ -0,0 +1,22 @@
+class Files < Application
+
+ def mp3audio
+ nginx_send_file("/protected/matz_cant_patch.mp3")
+ end
+
+ def image
+ nginx_send_file("/protected/sirens_of_the_sea.jpg")
+ end
+
+ # This is gonna be in merb-core 0.9.8, version in 0.9.7 does
+ # not take care of content type and content disposition headers
+ # at all so it's not very useful and may be confusing for some
+ # people.
+ def nginx_send_file(path)
+ # Let Nginx detect content type unless it is explicitly set
+ headers['Content-Type'] = ""
+ headers["Content-Disposition"] = "attachment; filename=#{path.split('/').last}"
+ headers['X-Accel-Redirect'] = path
+ return ' '
+ end
+end
5 app/helpers/files_helper.rb
@@ -0,0 +1,5 @@
+module Merb
+ module FilesHelper
+
+ end
+end # Merb
5 app/helpers/global_helpers.rb
@@ -0,0 +1,5 @@
+module Merb
+ module GlobalHelpers
+ # helpers defined here available to all views.
+ end
+end
9 app/models/merb/session.rb
@@ -0,0 +1,9 @@
+module Merb
+ module Session
+
+ # The Merb::Session module gets mixed into Merb::SessionContainer to allow
+ # app-level functionality; it will be included and methods will be available
+ # through request.session as instance methods.
+
+ end
+end
216 app/views/exceptions/internal_server_error.html.erb
@@ -0,0 +1,216 @@
+<html>
+<head>
+ <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
+ <title><%= @exception_name %></title>
+ <style type="text/css" media="screen">
+ body {
+ font-family:arial;
+ font-size:11px;
+ }
+ h1 {
+ font-size:48px;
+ letter-spacing:-4px;
+ margin:0;
+ line-height:36px;
+ color:#333;
+ }
+ h1 sup {
+ font-size: 0.5em;
+ }
+ h1 sup.error_500, h1 sup.error_400 {
+ color:#990E05;
+ }
+ h1 sup.error_100, h1 sup.error_200 {
+ color:#00BF10;
+ }
+ h1 sup.error_300 {
+ /* pretty sure you cant 'see' status 300
+ errors but if you could I think they
+ would be blue */
+ color:#1B2099;
+ }
+ h2 {
+ font-size:36px;
+ letter-spacing:-3px;
+ margin:0;
+ line-height:28px;
+ color:#444;
+ }
+ a, a:visited {
+ color:#00BF10;
+ }
+ .internalError {
+ width:800px;
+ margin:50px auto;
+ }
+ .header {
+ border-bottom:10px solid #333;
+ margin-bottom:1px;
+ background-image: url("data:image/gif;base64,R0lGODlhAwADAIAAAP///8zMzCH5BAAAAAAALAAAAAADAAMAAAIEBHIJBQA7");
+ padding:20px;
+ }
+ table.trace {
+ width:100%;
+ font-family:courier, monospace;
+ letter-spacing:-1px;
+ border-collapse: collapse;
+ border-spacing:0;
+ }
+ table.trace tr td{
+ padding:0;
+ height:26px;
+ font-size:13px;
+ vertical-align:middle;
+ }
+ table.trace tr.file{
+ border-top:2px solid #fff;
+ background-color:#F3F3F3;
+ }
+ table.trace tr.source {
+ background-color:#F8F8F8;
+ display:none;
+ }
+ table.trace .open tr.source {
+ display:table-row;
+ }
+ table.trace tr.file td.expand {
+ width:23px;
+ background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABcAAAAXCAIAAABvSEP3AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAdVJREFUeNqMVL+TwUAYxaRIOlEhlZHGDAUzzOQ61+AqXMV1lJSU7q/QRqm8KFUcJTNn5qJkaPyoKKVz7y4mF8na5Kt29tt9+/Z97/u81+vVQ4r9frdarS6Xi7ETDIZisRjxMGPfmk4niNPpZE+xLAugbPaZ53nzvtfMBe/3+/3dbuehBrAKhZdUKkVAWa9Xsiybv0CPZDJZLr/qa5/BwgwRjYqOKIvFYjQa/aNommZh0Ww2K5UqzwfoQOPxaLPZ3FAmk0+7lplMpt1u53J5OpBOR0eZEE9wHJfP5zud93g88QhluwWbjW+5VOmKBgKBer3eaDTDYeGBQF8+x7rqIYoiPgixWJazpA6HA+MSxRArkUgMh0M409g8Ho8+9wYxxCqVSq1W26EDHGM2m4HOHQrEc38f/Yn7cLmlIRhBENzcx8cVRZnPZ/YUep2BWkjTIfA+PKVpZAXR5QxsjiqCKvGEqqp443w+0dvy17swqD0HB3S73V5PpkNg1qBqt8kwGCjmPkinM0QJbIoEa7U6UG6ToVgs4V9G2g0ESoP5Aoi7KYX5oCgf8IKbkvn9/mr1LRQKESamzgJy0g0tSZIuB3nuGqRU9Vv9C4sKkUhEkp4soxvxI8AAhWrrtXa3X8EAAAAASUVORK5CYII=);
+ background-position:top left;
+ background-repeat:no-repeat;
+ }
+ table.trace .open tr.file td.expand {
+ width:19px;
+ background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABcAAAB1CAIAAAAqdO2mAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAXZJREFUeNrslK1ywkAUhcMOBomEOiSdqLxEBJX0NaijOsjyHGGmCGyQQYaiiiw4gktkcOmZbpsuuzQ/M5XnqJ2d3S/n3nM3rTzPLUP7/Tt0+pLcGQwG3W53OLyHzPMtjYL7q9UqSRLrD4E1Gj1orCvKYuFHUWTVkOM44/HjDcp8/lL4r6NerzeZPMm1KFw0QkDn83m5fP2lHA4fNQvRtNvtjsfDd0WzmSfb2e/fdTqdOvdh/HLJZLOn0+d2HJ+KRGzbdl23EpFlmed5cp2maRzHQq1lvQ5KMi6EUZBGfup6E1pTfd+vrGW7jbQ2C9hTt9BpqNyIWaAwAy6xg2eBz5iRC/NomiZhGN5sqmnkauo0BUGgVQoBjQ80oCACgNQdZHfTYBkF2mxCtWWAqunWpahxIDUt3QYUxIFQpJHyIWpXjinabKbbwItMHT+NyjchrP8QKaSQQgoppJBCCimkkEIKKaSQQgoppJBCCimkkEIKKaSo+hRgAEFD17X08O2NAAAAAElFTkSuQmCC);
+ background-position:top left;
+ background-repeat:no-repeat;
+ }
+ table.trace tr.source td.collapse {
+ width:19px;
+ background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABcAAAB1CAIAAAAqdO2mAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAVxJREFUeNrs0zFygkAUBmBlUkgJHdABlQwVkVJKKUxBYWbkALTxMJwhltyDFkss03IF8pudIcwaDaDl/6pd2P327b7d+eHwMXs4lNkzggoVKlSoUKFChQoVKlSoUKFChQoVKlSoUKFChQqVEYqm6ft9+qiSJEkYho7jTlcw2fd9NOI4nq4gEdFwXXe1Cqco63VkWVbXRTqLhTpOwQRpF7quR1E0TgGhqvLKUFCyoQqG/rks3O6kZKW/eRFpevOCoGTXVTcMQ5EyxyDEkML1c5RzuZOICIyXqn7JBVez6282MWrx731HOv2qB8Hri2lamNk0DfpVVdV1Peodappmmua8bdvzuc7zfNprzrLMth1FnGh/X8MjCAIQv/cFz/+65PcDh7rbvYv2ZUfdj+PxsyzLgVl0hKwgTqeqKApx2LeOc7t98zyv/1FWOgvx9RPii23bmL9cetJ8Ed8CDAC6aFW8bCzFhwAAAABJRU5ErkJggg==);
+ background-position:bottom left;
+ background-repeat:no-repeat;
+ background-color:#6F706F;
+ }
+ table.trace tr td.path {
+ padding-left:10px;
+ }
+ table.trace tr td.code {
+ padding-left:35px;
+ white-space: pre;
+ line-height:9px;
+ padding-bottom:10px;
+ }
+ table.trace tr td.code em {
+ font-weight:bold;
+ color:#00BF10;
+ }
+ table.trace tr td.code a {
+ width: 20px;
+ float: left;
+ }
+ table.trace tr td.code .more {
+ color:#666;
+ }
+ table.trace tr td.line {
+ width:30px;
+ text-align:right;
+ padding-right:4px;
+ }
+ .footer {
+ margin-top:5px;
+ font-size:11px;
+ color:#444;
+ text-align:right;
+ }
+ </style>
+</head>
+<body>
+ <div class="internalError">
+
+ <div class="header">
+ <h1><%= @exception_name %> <sup class="error_<%= @exception.class::STATUS %>"><%= @exception.class::STATUS %></sup></h1>
+ <% if show_details = ::Merb::Config[:exception_details] -%>
+ <h2><%=h @exception.message %></h2>
+ <% else -%>
+ <h2>Sorry about that...</h2>
+ <% end -%>
+ <h3>Parameters</h3>
+ <ul>
+ <% params[:original_params].each do |param, value| %>
+ <li><strong><%= param %>:</strong> <%= value.inspect %></li>
+ <% end %>
+ <%= "<li>None</li>" if params[:original_params].empty? %>
+ </ul>
+
+ <h3>Session</h3>
+ <ul>
+ <% params[:original_session].each do |param, value| %>
+ <li><strong><%= param %>:</strong> <%= value.inspect %></li>
+ <% end %>
+ <%= "<li>None</li>" if params[:original_session].empty? %>
+ </ul>
+
+ <h3>Cookies</h3>
+ <ul>
+ <% params[:original_cookies].each do |param, value| %>
+ <li><strong><%= param %>:</strong> <%= value.inspect %></li>
+ <% end %>
+ <%= "<li>None</li>" if params[:original_cookies].empty? %>
+ </ul>
+ </div>
+
+ <% if show_details %>
+ <table class="trace">
+ <% @exception.backtrace.each_with_index do |line, index| %>
+ <tbody class="close">
+ <tr class="file">
+ <td class="expand">
+ </td>
+ <td class="path">
+ <%= (line.match(/^([^:]+)/)[1] rescue 'unknown').sub(/\/((opt|usr)\/local\/lib\/(ruby\/)?(gems\/)?(1.8\/)?(gems\/)?|.+\/app\/)/, '') %>
+ <% unless line.match(/\.erb:/) %>
+ in "<strong><%= line.match(/:in `(.+)'$/)[1] rescue '?' %></strong>"
+ <% else %>
+ (<strong>ERB Template</strong>)
+ <% end %>
+ </td>
+ <td class="line">
+ <a href="txmt://open?url=file://<%=file = (line.match(/^([^:]+)/)[1] rescue 'unknown')%>&amp;line=<%= lineno = line.match(/:([0-9]+):/)[1] rescue '?' %>"><%=lineno%></a>&nbsp;
+ </td>
+ </tr>
+ <tr class="source">
+ <td class="collapse">
+ </td>
+ <td class="code" colspan="2"><% (__caller_lines__(file, lineno, 5) rescue []).each do |llineno, lcode, lcurrent| %>
+<a href="txmt://open?url=file://<%=file%>&amp;line=<%=llineno%>"><%= llineno %></a><%='<em>' if llineno==lineno.to_i %><%= lcode.size > 90 ? CGI.escapeHTML(lcode[0..90])+'<span class="more">......</span>' : CGI.escapeHTML(lcode) %><%='</em>' if llineno==lineno.to_i %>
+<% end %>
+
+</td>
+ </tr>
+ </tbody>
+ <% end %>
+ </table>
+ <script type="text/javascript" charset="utf-8">
+ // swop the open & closed classes
+ els = document.getElementsByTagName('td');
+ for(i=0; i<els.length; i++){
+ if(els[i].className=='expand' || els[i].className=='collapse'){
+ els[i].onclick = function(e){
+ tbody = this.parentNode.parentNode;
+ if(tbody.className=='open'){
+ tbody.className='closed';
+ }else{
+ tbody.className='open';
+ }
+ }
+ }
+ }
+ </script>
+ <% end %>
+ <div class="footer">
+ lots of love, from <a href="#">merb</a>
+ </div>
+ </div>
+</body>
+</html>
63 app/views/exceptions/not_acceptable.html.erb
@@ -0,0 +1,63 @@
+<div id="container">
+ <div id="header-container">
+ <img src="/images/merb.jpg" />
+ <!-- <h1>Mongrel + Erb</h1> -->
+ <h2>pocket rocket web framework</h2>
+ <hr />
+ </div>
+
+ <div id="left-container">
+ <h3>Exception:</h3>
+ <p><%= params[:exception] %></p>
+ </div>
+
+ <div id="main-container">
+ <h3>Why am I seeing this page?</h3>
+ <p>Merb couldn't find an appropriate content_type to return,
+ based on what you said was available via provides() and
+ what the client requested.</p>
+
+ <h3>How to add a mime-type</h3>
+ <pre><code>
+ Merb.add_mime_type :pdf, :to_pdf, %w[application/pdf], &quot;Content-Encoding&quot; =&gt; &quot;gzip&quot;
+ </code></pre>
+ <h3>What this means is:</h3>
+ <ul>
+ <li>Add a mime-type for :pdf</li>
+ <li>Register the method for converting objects to PDF as <code>#to_pdf</code>.</li>
+ <li>Register the incoming mime-type "Accept" header as <code>application/pdf</code>.</li>
+ <li>Specify a new header for PDF types so it will set <code>Content-Encoding</code> to gzip.</li>
+ </ul>
+
+ <h3>You can then do:</h3>
+ <pre><code>
+ class Foo &lt; Application
+ provides :pdf
+ end
+ </code></pre>
+
+ <h3>Where can I find help?</h3>
+ <p>If you have any questions or if you can't figure something out, please take a
+ look at our <a href="http://merbivore.com/"> project page</a>,
+ feel free to come chat at irc.freenode.net, channel #merb,
+ or post to <a href="http://groups.google.com/group/merb">merb mailing list</a>
+ on Google Groups.</p>
+
+ <h3>What if I've found a bug?</h3>
+ <p>If you want to file a bug or make your own contribution to Merb,
+ feel free to register and create a ticket at our
+ <a href="http://merb.lighthouseapp.com/">project development page</a>
+ on Lighthouse.</p>
+
+ <h3>How do I edit this page?</h3>
+ <p>You can change what people see when this happens by editing <tt>app/views/exceptions/not_acceptable.html.erb</tt>.</p>
+
+ </div>
+
+ <div id="footer-container">
+ <hr />
+ <div class="left"></div>
+ <div class="right">&copy; 2008 the merb dev team</div>
+ <p>&nbsp;</p>
+ </div>
+</div>
47 app/views/exceptions/not_found.html.erb
@@ -0,0 +1,47 @@
+<div id="container">
+ <div id="header-container">
+ <img src="/images/merb.jpg" />
+ <!-- <h1>Mongrel + Erb</h1> -->
+ <h2>pocket rocket web framework</h2>
+ <hr />
+ </div>
+
+ <div id="left-container">
+ <h3>Exception:</h3>
+ <p><%= params[:exception] %></p>
+ </div>
+
+ <div id="main-container">
+ <h3>Welcome to Merb!</h3>
+ <p>Merb is a light-weight MVC framework written in Ruby. We hope you enjoy it.</p>
+
+ <h3>Where can I find help?</h3>
+ <p>If you have any questions or if you can't figure something out, please take a
+ look at our <a href="http://merbivore.com/"> project page</a>,
+ feel free to come chat at irc.freenode.net, channel #merb,
+ or post to <a href="http://groups.google.com/group/merb">merb mailing list</a>
+ on Google Groups.</p>
+
+ <h3>What if I've found a bug?</h3>
+ <p>If you want to file a bug or make your own contribution to Merb,
+ feel free to register and create a ticket at our
+ <a href="http://merb.lighthouseapp.com/">project development page</a>
+ on Lighthouse.</p>
+
+ <h3>How do I edit this page?</h3>
+ <p>You're seeing this page because you need to edit the following files:
+ <ul>
+ <li>config/router.rb <strong><em>(recommended)</em></strong></li>
+ <li>app/views/exceptions/not_found.html.erb <strong><em>(recommended)</em></strong></li>
+ <li>app/views/layout/application.html.erb <strong><em>(change this layout)</em></strong></li>
+ </ul>
+ </p>
+ </div>
+
+ <div id="footer-container">
+ <hr />
+ <div class="left"></div>
+ <div class="right">&copy; 2008 the merb dev team</div>
+ <p>&nbsp;</p>
+ </div>
+</div>
1  app/views/files/index.html.erb
@@ -0,0 +1 @@
+You're in index of the Files controller.
11 app/views/layout/application.html.erb
@@ -0,0 +1,11 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-us" lang="en-us">
+ <head>
+ <title>Fresh Merb App</title>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <link rel="stylesheet" href="/stylesheets/master.css" type="text/css" media="screen" charset="utf-8" />
+ </head>
+ <body>
+ <%= catch_content :for_layout %>
+ </body>
+</html>
1  autotest/discover.rb
@@ -0,0 +1 @@
+Autotest.add_discovery { "merb" }
149 autotest/merb.rb
@@ -0,0 +1,149 @@
+# Adapted from Autotest::Rails
+require 'autotest'
+
+class Autotest::Merb < Autotest
+
+ # +model_tests_dir+:: the directory to find model-centric tests
+ # +controller_tests_dir+:: the directory to find controller-centric tests
+ # +view_tests_dir+:: the directory to find view-centric tests
+ # +fixtures_dir+:: the directory to find fixtures in
+ attr_accessor :model_tests_dir, :controller_tests_dir, :view_tests_dir, :fixtures_dir
+
+ def initialize
+ super
+
+ initialize_test_layout
+
+ # Ignore any happenings in these directories
+ add_exception %r%^\./(?:doc|log|public|tmp)%
+
+ # Ignore any mappings that Autotest may have already set up
+ clear_mappings
+
+ # Any changes to a file in the root of the 'lib' directory will run any
+ # model test with a corresponding name.
+ add_mapping %r%^lib\/.*\.rb% do |filename, _|
+ files_matching Regexp.new(["^#{model_test_for(filename)}$"])
+ end
+
+ # Any changes to a fixture will run corresponding view, controller and
+ # model tests
+ add_mapping %r%^#{fixtures_dir}/(.*)s.yml% do |_, m|
+ [
+ model_test_for(m[1]),
+ controller_test_for(m[1]),
+ view_test_for(m[1])
+ ]
+ end
+
+ # Any change to a test or test will cause it to be run
+ add_mapping %r%^test/(unit|models|integration|controllers|views|functional)/.*rb$% do |filename, _|
+ filename
+ end
+
+ # Any change to a model will cause it's corresponding test to be run
+ add_mapping %r%^app/models/(.*)\.rb$% do |_, m|
+ model_test_for(m[1])
+ end
+
+ # Any change to the global helper will result in all view and controller
+ # tests being run
+ add_mapping %r%^app/helpers/global_helpers.rb% do
+ files_matching %r%^test/(views|functional|controllers)/.*_test\.rb$%
+ end
+
+ # Any change to a helper will run it's corresponding view and controller
+ # tests, unless the helper is the global helper. Changes to the global
+ # helper run all view and controller tests.
+ add_mapping %r%^app/helpers/(.*)_helper(s)?.rb% do |_, m|
+ if m[1] == "global" then
+ files_matching %r%^test/(views|functional|controllers)/.*_test\.rb$%
+ else
+ [
+ view_test_for(m[1]),
+ controller_test_for(m[1])
+ ]
+ end
+ end
+
+ # Changes to views result in their corresponding view and controller test
+ # being run
+ add_mapping %r%^app/views/(.*)/% do |_, m|
+ [
+ view_test_for(m[1]),
+ controller_test_for(m[1])
+ ]
+ end
+
+ # Changes to a controller result in its corresponding test being run. If
+ # the controller is the exception or application controller, all
+ # controller tests are run.
+ add_mapping %r%^app/controllers/(.*)\.rb$% do |_, m|
+ if ["application", "exception"].include?(m[1])
+ files_matching %r%^test/(controllers|views|functional)/.*_test\.rb$%
+ else
+ controller_test_for(m[1])
+ end
+ end
+
+ # If a change is made to the router, run all controller and view tests
+ add_mapping %r%^config/router.rb$% do # FIX
+ files_matching %r%^test/(controllers|views|functional)/.*_test\.rb$%
+ end
+
+ # If any of the major files governing the environment are altered, run
+ # everything
+ add_mapping %r%^test/test_helper.rb|config/(init|rack|environments/test.rb|database.yml)% do # FIX
+ files_matching %r%^test/(unit|models|controllers|views|functional)/.*_test\.rb$%
+ end
+ end
+
+private
+
+ # Determines the paths we can expect tests or specs to reside, as well as
+ # corresponding fixtures.
+ def initialize_test_layout
+ self.model_tests_dir = "test/unit"
+ self.controller_tests_dir = "test/functional"
+ self.view_tests_dir = "test/views"
+ self.fixtures_dir = "test/fixtures"
+ end
+
+ # Given a filename and the test type, this method will return the
+ # corresponding test's or spec's name.
+ #
+ # ==== Arguments
+ # +filename+<String>:: the file name of the model, view, or controller
+ # +kind_of_test+<Symbol>:: the type of test we that we should run
+ #
+ # ==== Returns
+ # String:: the name of the corresponding test or spec
+ #
+ # ==== Example
+ #
+ # > test_for("user", :model)
+ # => "user_test.rb"
+ # > test_for("login", :controller)
+ # => "login_controller_test.rb"
+ # > test_for("form", :view)
+ # => "form_view_spec.rb" # If you're running a RSpec-like suite
+ def test_for(filename, kind_of_test)
+ name = [filename]
+ name << kind_of_test.to_s if kind_of_test == :view
+ name << "test"
+ return name.join("_") + ".rb"
+ end
+
+ def model_test_for(filename)
+ [model_tests_dir, test_for(filename, :model)].join("/")
+ end
+
+ def controller_test_for(filename)
+ [controller_tests_dir, test_for(filename, :controller)].join("/")
+ end
+
+ def view_test_for(filename)
+ [view_tests_dir, test_for(filename, :view)].join("/")
+ end
+
+end
165 autotest/merb_rspec.rb
@@ -0,0 +1,165 @@
+# Adapted from Autotest::Rails, RSpec's autotest class, as well as merb-core's.
+require 'autotest'
+
+class RspecCommandError < StandardError; end
+
+# This class maps your application's structure so Autotest can understand what
+# specs to run when files change.
+#
+# Fixtures are _not_ covered by this class. If you change a fixture file, you
+# will have to run your spec suite manually, or, better yet, provide your own
+# Autotest map explaining how your fixtures are set up.
+class Autotest::MerbRspec < Autotest
+ def initialize
+ super
+
+ # Ignore any happenings in these directories
+ add_exception %r%^\./(?:doc|log|public|tmp|\.git|\.hg|\.svn|framework|gems|schema|\.DS_Store|autotest|bin|.*\.sqlite3)%
+ # Ignore SCM directories and custom Autotest mappings
+ %w[.svn .hg .git .autotest].each { |exception| add_exception(exception) }
+
+ # Ignore any mappings that Autotest may have already set up
+ clear_mappings
+
+ # Anything in /lib could have a spec anywhere, if at all. So, look for
+ # files with roughly the same name as the file in /lib
+ add_mapping %r%^lib\/(.*)\.rb% do |_, m|
+ files_matching %r%^spec\/#{m[1]}%
+ end
+
+ add_mapping %r%^spec/(spec_helper|shared/.*)\.rb$% do
+ all_specs
+ end
+
+ # Changing a spec will cause it to run itself
+ add_mapping %r%^spec/.*\.rb$% do |filename, _|
+ filename
+ end
+
+ # Any change to a model will cause it's corresponding test to be run
+ add_mapping %r%^app/models/(.*)\.rb$% do |_, m|
+ spec_for(m[1], 'model')
+ end
+
+ # Any change to global_helpers will result in all view and controller
+ # tests being run
+ add_mapping %r%^app/helpers/global_helpers\.rb% do
+ files_matching %r%^spec/(views|controllers|helpers)/.*_spec\.rb$%
+ end
+
+ # Any change to a helper will cause its spec to be run
+ add_mapping %r%^app/helpers/((.*)_helper(s)?)\.rb% do |_, m|
+ spec_for(m[1], 'helper')
+ end
+
+ # Changes to a view cause its spec to be run
+ add_mapping %r%^app/views/(.*)/% do |_, m|
+ spec_for(m[1], 'view')
+ end
+
+ # Changes to a controller result in its corresponding spec being run. If
+ # the controller is the exception or application controller, all
+ # controller specs are run.
+ add_mapping %r%^app/controllers/(.*)\.rb$% do |_, m|
+ if ["application", "exception"].include?(m[1])
+ files_matching %r%^spec/controllers/.*_spec\.rb$%
+ else
+ spec_for(m[1], 'controller')
+ end
+ end
+
+ # If a change is made to the router, run controller, view and helper specs
+ add_mapping %r%^config/router.rb$% do
+ files_matching %r%^spec/(controllers|views|helpers)/.*_spec\.rb$%
+ end
+
+ # If any of the major files governing the environment are altered, run
+ # everything
+ add_mapping %r%^config/(init|rack|environments/test).*\.rb|database\.yml% do
+ all_specs
+ end
+ end
+
+ def failed_results(results)
+ results.scan(/^\d+\)\n(?:\e\[\d*m)?(?:.*?Error in )?'([^\n]*)'(?: FAILED)?(?:\e\[\d*m)?\n(.*?)\n\n/m)
+ end
+
+ def handle_results(results)
+ @failures = failed_results(results)
+ @files_to_test = consolidate_failures(@failures)
+ @files_to_test.empty? && !$TESTING ? hook(:green) : hook(:red)
+ @tainted = !@files_to_test.empty?
+ end
+
+ def consolidate_failures(failed)
+ filters = Hash.new { |h,k| h[k] = [] }
+ failed.each do |spec, failed_trace|
+ if f = test_files_for(failed).find { |f| f =~ /spec\// }
+ filters[f] << spec
+ break
+ end
+ end
+ filters
+ end
+
+ def make_test_cmd(specs_to_runs)
+ [
+ ruby,
+ "-S",
+ spec_command,
+ add_options_if_present,
+ files_to_test.keys.flatten.join(' ')
+ ].join(' ')
+ end
+
+ def add_options_if_present
+ File.exist?("spec/spec.opts") ? "-O spec/spec.opts " : ""
+ end
+
+ # Finds the proper spec command to use. Precendence is set in the
+ # lazily-evaluated method spec_commands. Alias + Override that in
+ # ~/.autotest to provide a different spec command then the default
+ # paths provided.
+ def spec_command(separator=File::ALT_SEPARATOR)
+ unless defined?(@spec_command)
+ @spec_command = spec_commands.find { |cmd| File.exists?(cmd) }
+
+ raise RspecCommandError, "No spec command could be found" unless @spec_command
+
+ @spec_command.gsub!(File::SEPARATOR, separator) if separator
+ end
+ @spec_command
+ end
+
+ # Autotest will look for spec commands in the following
+ # locations, in this order:
+ #
+ # * default spec bin/loader installed in Rubygems
+ # * any spec command found in PATH
+ def spec_commands
+ [File.join(Config::CONFIG['bindir'], 'spec'), 'spec']
+ end
+
+private
+
+ # Runs +files_matching+ for all specs
+ def all_specs
+ files_matching %r%^spec/.*_spec\.rb$%
+ end
+
+ # Generates a path to some spec given its kind and the match from a mapping
+ #
+ # ==== Arguments
+ # match<String>:: the match from a mapping
+ # kind<String>:: the kind of spec that the match represents
+ #
+ # ==== Returns
+ # String
+ #
+ # ==== Example
+ # > spec_for('post', :view')
+ # => "spec/views/post_spec.rb"
+ def spec_for(match, kind)
+ File.join("spec", kind + 's', "#{match}_spec.rb")
+ end
+end
9 config/environments/development.rb
@@ -0,0 +1,9 @@
+Merb.logger.info("Loaded DEVELOPMENT Environment...")
+Merb::Config.use { |c|
+ c[:exception_details] = true
+ c[:reload_classes] = true
+ c[:reload_time] = 0.5
+ c[:log_auto_flush ] = true
+ c[:ignore_tampered_cookies] = true
+ c[:log_level] = :debug
+}
7 config/environments/production.rb
@@ -0,0 +1,7 @@
+Merb.logger.info("Loaded PRODUCTION Environment...")
+Merb::Config.use { |c|
+ c[:exception_details] = false
+ c[:reload_classes] = false
+ c[:log_level] = :error
+ c[:log_file] = Merb.log_path + "/production.log"
+}
7 config/environments/rake.rb
@@ -0,0 +1,7 @@
+Merb.logger.info("Loaded RAKE Environment...")
+Merb::Config.use { |c|
+ c[:exception_details] = true
+ c[:reload_classes] = false
+ c[:log_auto_flush ] = true
+ c[:log_file] = Merb.log_path / 'merb_rake.log'
+}
6 config/environments/test.rb
@@ -0,0 +1,6 @@
+Merb.logger.info("Loaded TEST Environment...")
+Merb::Config.use { |c|
+ c[:testing] = true
+ c[:exception_details] = true
+ c[:log_auto_flush ] = true
+}
192 config/init.rb
@@ -0,0 +1,192 @@
+$KCODE = 'UTF8'
+
+#
+# ==== Structure of Merb initializer
+#
+# 1. Load paths.
+# 2. Dependencies configuration.
+# 3. Libraries (ORM, testing tool, etc) you use.
+# 4. Application-specific configuration.
+
+#
+# ==== Set up load paths
+#
+
+# Add the app's "gems" directory to the gem load path.
+# Note that the gems directory must mirror the structure RubyGems uses for
+# directories under which gems are kept.
+#
+# To conveniently set it up, use gem install -i <merb_app_root/gems>
+# when installing gems. This will set up the structure under /gems
+# automagically.
+#
+# An example:
+#
+# You want to bundle ActiveRecord and ActiveSupport with your Merb
+# application to be deployment environment independent. To do so,
+# install gems into merb_app_root/gems directory like this:
+#
+# gem install -i merb_app_root/gems activesupport-post-2.0.2.gem activerecord-post-2.0.2.gem
+#
+# Since RubyGems will search merb_app_root/gems for dependencies, order
+# in the statement above is important: we need to install ActiveSupport which
+# ActiveRecord depends on first.
+#
+# Remember that bundling of dependencies as gems with your application
+# makes it independent of the environment it runs in and is a very
+# good, encouraged practice to follow.
+
+# If you want modules and classes from libraries organized like
+# merbapp/lib/magicwand/lib/magicwand.rb to autoload,
+# uncomment this.
+# Merb.push_path(:lib, Merb.root / "lib") # uses **/*.rb as path glob.
+
+# ==== Dependencies
+
+# These are a few, but not all, of the standard merb-more dependencies:
+#
+# dependency "merb-action-args" # Provides support for querystring arguments to be passed in to controller actions
+# dependency "merb-assets" # Provides link_to, asset_path, auto_link, image_tag methods (and lots more)
+# dependency "merb-cache" # Provides your application with caching functions
+# dependency "merb-haml" # Adds rake tasks and the haml generators to your merb app
+# dependency "merb-jquery" # Provides a #jquery method to insert jQuery code in to a content block
+# dependency "merb-mailer" # Integrates mail support via Merb Mailer
+
+# These are a few, but not all, of the merb-plugin dependencies:
+#
+# dependency "merb_helpers" # Provides the form, date/time, and other helpers
+# dependency "merb_param_protection" # Lets you have better control over your query string params and param logging
+# dependency "merb_stories" # Provides rspec helper methods for your application
+
+# Miscellaneous dependencies:
+#
+# Specify more than one dependency at a time with the #dependencies method:
+# dependencies "RedCloth", "BlueCloth"
+
+# Specify a specific version of a dependency
+# dependency "RedCloth", "> 3.0"
+
+# Specify more than one dependency at a time as well as the version:
+# dependencies "RedCloth" => "> 3.0", "BlueCloth" => "= 1.0.0"
+
+# You can also add in dependencies after your application loads.
+Merb::BootLoader.after_app_loads do
+ # For example, the magic_admin gem uses the app's model classes. This requires that the models be
+ # loaded already. So, we can put the magic_admin dependency here:
+ # dependency "magic_admin"
+end
+
+#
+# ==== Set up your ORM of choice
+#
+
+# Merb doesn't come with database support by default. You need
+# an ORM plugin. Install one, and uncomment one of the following lines,
+# if you need a database.
+
+# Uncomment for DataMapper ORM
+# use_orm :datamapper
+
+# Uncomment for ActiveRecord ORM
+# use_orm :activerecord
+
+# Uncomment for Sequel ORM
+# use_orm :sequel
+
+
+#
+# ==== Pick what you test with
+#
+
+# This defines which test framework the generators will use.
+# RSpec is turned on by default.
+#
+# To use Test::Unit, you need to install the merb_test_unit gem.
+# To use RSpec, you don't have to install any additional gems, since
+# merb-core provides support for RSpec.
+#
+# use_test :test_unit
+use_test :rspec
+
+
+#
+# ==== Choose which template engine to use by default
+#
+
+# Merb can generate views for different template engines, choose your favourite as the default.
+
+use_template_engine :erb
+# use_template_engine :haml
+
+
+#
+# ==== Set up your basic configuration
+#
+
+# IMPORTANT:
+#
+# early on Merb boot init file is not yet loaded.
+# Thus setting PORT, PID FILE and ADAPTER using init file does not
+# make sense and only can lead to confusion because default settings
+# will be used instead.
+#
+# Please use command line options for them.
+# See http://wiki.merbivore.com/pages/merb-core-boot-process
+# if you want to know more.
+Merb::Config.use do |c|
+
+ # Sets up a custom session id key which is used for the session persistence
+ # cookie name. If not specified, defaults to '_session_id'.
+ # c[:session_id_key] = '_session_id'
+
+ # The session_secret_key is only required for the cookie session store.
+ c[:session_secret_key] = '443d95fab01ea1780a34742f1815fc2965d2c6a4'
+
+ # There are various options here, by default Merb comes with 'cookie',
+ # 'memory', 'memcache' or 'container'.
+ # You can of course use your favorite ORM instead:
+ # 'datamapper', 'sequel' or 'activerecord'.
+ c[:session_store] = 'cookie'
+end
+
+
+# ==== Tune your inflector
+
+# To fine tune your inflector use the word, singular_word and plural_word
+# methods of English::Inflect module metaclass.
+#
+# Here we define erratum/errata exception case:
+#
+# English::Inflect.word "erratum", "errata"
+#
+# In case singular and plural forms are the same omit
+# second argument on call:
+#
+# English::Inflect.word 'information'
+#
+# You can also define general, singularization and pluralization
+# rules:
+#
+# Once the following rule is defined:
+# English::Inflect.rule 'y', 'ies'
+#
+# You can see the following results:
+# irb> "fly".plural
+# => flies
+# irb> "cry".plural
+# => cries
+#
+# Example for singularization rule:
+#
+# English::Inflect.singular_rule 'o', 'oes'
+#
+# Works like this:
+# irb> "heroes".singular
+# => hero
+#
+# Example of pluralization rule:
+# English::Inflect.singular_rule 'fe', 'ves'
+#
+# And the result is:
+# irb> "wife".plural
+# => wives
35 config/nginx.config.sample
@@ -0,0 +1,35 @@
+upstream x-accel-redirect-backend {
+ server 127.0.0.1:5000;
+}
+
+server {
+ server_name x-accel-redirect.local;
+
+ listen x-accel-redirect.local:80;
+ root /Users/antares/dev/experiments/merb/x-accel-redirect-sample/public;
+
+ access_log logs/access.x-accel-redirect.local.log combined;
+ error_log logs/errors.x-accel-redirect.local.log error; # debug_http;
+ log_not_found on;
+
+ # rewrite_log on;
+
+ # accelerated file streaming location
+ location /protected/ {
+ internal;
+ # NOTE: resulting file directory is public/files/protected/, keep that in mind
+ #
+ # /protected/... path is internal so won't be accessible from the outside
+ # world even though it's shown in the URL after action dispatch
+ root /Users/antares/dev/experiments/merb/x-accel-redirect-sample/public/files/;
+ }
+
+ location / {
+ proxy_redirect off;
+ proxy_set_header Host $host;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+
+ proxy_pass http://x-accel-redirect-backend;
+ }
+}
12 config/rack.rb
@@ -0,0 +1,12 @@
+
+# use PathPrefix Middleware if :path_prefix is set in Merb::Config
+if prefix = ::Merb::Config[:path_prefix]
+ use Merb::Rack::PathPrefix, prefix
+end
+
+# comment this out if you are running merb behind a load balancer
+# that serves static files
+use Merb::Rack::Static, Merb.dir_for(:public)
+
+# this is our main merb application
+run Merb::Rack::Application.new
6 config/router.rb
@@ -0,0 +1,6 @@
+Merb::Router.prepare do |r|
+ r.match("/xsendfile/mp3audio").to(:controller => "files", :action => "mp3audio")
+ r.match("/xsendfile/image").to(:controller => "files", :action => "image")
+
+ r.match("/").to(:controller => "files", :action => "image")
+end
822 merb.thor
@@ -0,0 +1,822 @@
+#!/usr/bin/env ruby
+require 'rubygems'
+require 'rubygems/dependency_installer'
+require 'rubygems/uninstaller'
+require 'thor'
+require 'fileutils'
+require 'yaml'
+
+module MerbThorHelper
+
+ private
+
+ # The current working directory, or Merb app root (--merb-root option).
+ def working_dir
+ @_working_dir ||= File.expand_path(options['merb-root'] || Dir.pwd)
+ end
+
+ # We should have a ./src dir for local and system-wide management.
+ def source_dir
+ @_source_dir ||= File.join(working_dir, 'src')
+ create_if_missing(@_source_dir)
+ @_source_dir
+ end
+
+ # If a local ./gems dir is found, it means we are in a Merb app.
+ def application?
+ gem_dir
+ end
+
+ # If a local ./gems dir is found, return it.
+ def gem_dir
+ if File.directory?(dir = File.join(working_dir, 'gems'))
+ dir
+ end
+ end
+
+ # If we're in a Merb app, we can have a ./bin directory;
+ # create it if it's not there.
+ def bin_dir
+ @_bin_dir ||= begin
+ if gem_dir
+ dir = File.join(working_dir, 'bin')
+ create_if_missing(dir)
+ dir
+ end
+ end
+ end
+
+ # Helper to create dir unless it exists.
+ def create_if_missing(path)
+ FileUtils.mkdir(path) unless File.exists?(path)
+ end
+
+ # Create a modified executable wrapper in the app's ./bin directory.
+ def ensure_local_bin_for(*gems)
+ if bin_dir && File.directory?(bin_dir)
+ gems.each do |gem|
+ if gemspec_path = Dir[File.join(gem_dir, 'specifications', "#{gem}-*.gemspec")].last
+ spec = Gem::Specification.load(gemspec_path)
+ spec.executables.each do |exec|
+ if File.exists?(executable = File.join(gem_dir, 'bin', exec))
+ local_executable = File.join(bin_dir, exec)
+ puts "Adding local executable #{local_executable}"
+ File.open(local_executable, 'w', 0755) do |f|
+ f.write(executable_wrapper(spec, exec))
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+
+ def executable_wrapper(spec, bin_file_name)
+ <<-TEXT
+#!/usr/bin/env #{RbConfig::CONFIG["ruby_install_name"]}
+#
+# This file was generated by merb.thor.
+#
+# The application '#{spec.name}' is installed as part of a gem, and
+# this file is here to facilitate running it.
+#
+
+require 'rubygems'
+
+if File.directory?(gems_dir = File.join(File.dirname(__FILE__), '..', 'gems'))
+ $BUNDLE = true; Gem.clear_paths; Gem.path.unshift(gems_dir)
+end
+
+version = "#{Gem::Requirement.default}"
+
+if ARGV.first =~ /^_(.*)_$/ and Gem::Version.correct? $1 then
+ version = $1
+ ARGV.shift
+end
+
+gem '#{spec.name}', version
+load '#{bin_file_name}'
+TEXT
+ end
+
+end
+
+# TODO
+# - a task to figure out an app's dependencies
+# - pulling a specific UUID/Tag (gitspec hash) with clone/update
+# - a 'deploy' task (in addition to 'redeploy' ?)
+# - eventually take a --orm option for the 'merb-stack' type of tasks
+
+class Merb < Thor
+
+ class SourcePathMissing < Exception
+ end
+
+ class GemPathMissing < Exception
+ end
+
+ class GemInstallError < Exception
+ end
+
+ class GemUninstallError < Exception
+ end
+
+ # Install a Merb stack from stable RubyForge gems. Optionally install a
+ # suitable Rack adapter/server when setting --adapter to one of the
+ # following: mongrel, emongrel, thin or ebb.
+
+ desc 'stable', 'Install extlib, merb-core and merb-more from rubygems'
+ method_options "--merb-root" => :optional,
+ "--adapter" => :optional
+ def stable
+ adapters = %w[mongrel emongrel thin ebb]
+ stable = Stable.new
+ stable.options = options
+ if stable.core && stable.more
+ puts "Installed extlib, merb-core and merb-more"
+ if options[:adapter] && adapters.include?(options[:adapter]) &&
+ stable.refresh_from_gems(options[:adapter])
+ puts "Installed #{options[:adapter]}"
+ elsif options[:adapter]
+ puts "Please specify one of the following adapters: #{adapters.join(' ')}"
+ end
+ end
+ end
+
+ class Stable < Thor
+
+ # The Stable tasks deal with known -stable- gems; available
+ # as shortcuts to Merb and DataMapper gems.
+ #
+ # These are pulled from rubyforge and installed into into the
+ # desired gems dir (either system-wide or into the application's
+ # gems directory).
+
+ include MerbThorHelper
+
+ # Gets latest gem versions from RubyForge and installs them.
+ #
+ # Examples:
+ #
+ # thor merb:edge:core
+ # thor merb:edge:core --merb-root ./path/to/your/app
+ # thor merb:edge:core --sources ./path/to/sources.yml
+
+ desc 'core', 'Install extlib and merb-core from git HEAD'
+ method_options "--merb-root" => :optional
+ def core
+ refresh_from_gems 'extlib', 'merb-core'
+ ensure_local_bin_for('merb-core', 'rake', 'rspec', 'thor')
+ end
+
+ desc 'more', 'Install merb-more from rubygems'
+ method_options "--merb-root" => :optional
+ def more
+ refresh_from_gems 'merb-more'
+ ensure_local_bin_for('merb-gen')
+ end
+
+ desc 'plugins', 'Install merb-plugins from rubygems'
+ method_options "--merb-root" => :optional
+ def plugins
+ refresh_from_gems 'merb-plugins'
+ end
+
+ desc 'dm_core', 'Install dm-core from rubygems'
+ method_options "--merb-root" => :optional
+ def dm_core
+ refresh_from_gems 'extlib', 'dm-core'
+ end
+
+ desc 'dm_more', 'Install dm-more from rubygems'
+ method_options "--merb-root" => :optional
+ def dm_more
+ refresh_from_gems 'extlib', 'dm-core', 'dm-more'
+ end
+
+ # Pull from RubyForge and install.
+ def refresh_from_gems(*components)
+ gems = Gems.new
+ gems.options = options
+ components.all? { |name| gems.install(name) }
+ end
+
+ end
+
+ # Retrieve latest Merb versions from git and optionally install them.
+ #
+ # Note: the --sources option takes a path to a YAML file
+ # with a regular Hash mapping gem names to git urls.
+ #
+ # Examples:
+ #
+ # thor merb:edge
+ # thor merb:edge --install
+ # thor merb:edge --merb-root ./path/to/your/app
+ # thor merb:edge --sources ./path/to/sources.yml
+
+ desc 'edge', 'Install extlib, merb-core and merb-more from git HEAD'
+ method_options "--merb-root" => :optional,
+ "--sources" => :optional,
+ "--install" => :boolean
+ def edge
+ edge = Edge.new
+ edge.options = options
+ edge.core
+ edge.more
+ end
+
+ class Edge < Thor
+
+ # The Edge tasks deal with known gems from the bleeding edge; available
+ # as shortcuts to Merb and DataMapper gems.
+ #
+ # These are pulled from git and optionally installed into into the
+ # desired gems dir (either system-wide or into the application's
+ # gems directory).
+
+ include MerbThorHelper
+
+ # Gets latest gem versions from git - optionally installs them.
+ #
+ # Note: the --sources option takes a path to a YAML file
+ # with a regular Hash mapping gem names to git urls,
+ # allowing pulling forks of the official repositories.
+ #
+ # Examples:
+ #
+ # thor merb:edge:core
+ # thor merb:edge:core --install
+ # thor merb:edge:core --merb-root ./path/to/your/app
+ # thor merb:edge:core --sources ./path/to/sources.yml
+
+ desc 'core', 'Update extlib and merb-core from git HEAD'
+ method_options "--merb-root" => :optional,
+ "--sources" => :optional,
+ "--install" => :boolean
+ def core
+ refresh_from_source 'thor', 'extlib', 'merb-core'
+ ensure_local_bin_for('merb-core', 'rake', 'rspec', 'thor')
+ end
+
+ desc 'more', 'Update merb-more from git HEAD'
+ method_options "--merb-root" => :optional,
+ "--sources" => :optional,
+ "--install" => :boolean
+ def more
+ refresh_from_source 'merb-more'
+ ensure_local_bin_for('merb-gen')
+ end
+
+ desc 'plugins', 'Update merb-plugins from git HEAD'
+ method_options "--merb-root" => :optional,
+ "--sources" => :optional,
+ "--install" => :boolean
+ def plugins
+ refresh_from_source 'merb-plugins'
+ end
+
+ desc 'dm_core', 'Update dm-core from git HEAD'
+ method_options "--merb-root" => :optional,
+ "--sources" => :optional,
+ "--install" => :boolean
+ def dm_core
+ refresh_from_source 'extlib', 'dm-core'
+ end
+
+ desc 'dm_more', 'Update dm-more from git HEAD'
+ method_options "--merb-root" => :optional,
+ "--sources" => :optional,
+ "--install" => :boolean
+ def dm_more
+ refresh_from_source 'extlib', 'dm-core', 'dm-more'
+ end
+
+ private
+
+ # Pull from git and optionally install the resulting gems.
+ def refresh_from_source(*components)
+ source = Source.new
+ source.options = options
+ components.each do |name|
+ source.clone(name)
+ source.install(name) if options[:install]
+ end
+ end
+
+ end
+
+ class Source < Thor
+
+ # The Source tasks deal with gem source packages - mainly from github.
+ # Any directory inside ./src is regarded as a gem that can be packaged
+ # and installed from there into the desired gems dir (either system-wide
+ # or into the application's gems directory).
+
+ include MerbThorHelper
+
+ # Install a particular gem from source.
+ #
+ # If a local ./gems dir is found, or --merb-root is given
+ # the gems will be installed locally into that directory.
+ #
+ # Note that this task doesn't retrieve any (new) source from git;
+ # To update and install you'd execute the following two tasks:
+ #
+ # thor merb:source:update merb-core
+ # thor merb:source:install merb-core
+ #
+ # Alternatively, look at merb:edge and merb:edge:* with --install.
+ #
+ # Examples:
+ #
+ # thor merb:source:install merb-core
+ # thor merb:source:install merb-more
+ # thor merb:source:install merb-more/merb-slices
+ # thor merb:source:install merb-plugins/merb_helpers
+ # thor merb:source:install merb-core --merb-root ./path/to/your/app
+
+ desc 'install GEM_NAME', 'Install a rubygem from (git) source'
+ method_options "--merb-root" => :optional
+ def install(name)
+ puts "Installing #{name}..."
+ gem_src_dir = File.join(source_dir, name)
+ opts = {}
+ opts[:install_dir] = gem_dir if gem_dir
+ Merb.install_gem_from_src(gem_src_dir, opts)
+ rescue Merb::SourcePathMissing
+ puts "Missing rubygem source path: #{gem_src_dir}"
+ rescue Merb::GemPathMissing
+ puts "Missing rubygems path: #{gem_dir}"
+ rescue => e
+ puts "Failed to install #{name} (#{e.message})"
+ end
+
+ # Clone a git repository into ./src. The repository can be
+ # a direct git url or a known -named- repository.
+ #
+ # Examples:
+ #
+ # thor merb:source:clone dm-core
+ # thor merb:source:clone dm-core --sources ./path/to/sources.yml
+ # thor merb:source:clone git://github.com/sam/dm-core.git
+
+ desc 'clone REPOSITORY', 'Clone a git repository into ./src'
+ method_options "--sources" => :optional
+ def clone(repository)
+ if repository =~ /^git:\/\//
+ repository_url = repository
+ elsif url = Merb.repos(options[:sources])[repository]
+ repository_url = url
+ end
+
+ if repository_url
+ repository_name = repository_url[/([\w+|-]+)\.git/u, 1]
+ fork_name = repository_url[/.com\/+?(.+)\/.+\.git/u, 1]
+ local_repo_path = "#{source_dir}/#{repository_name}"
+
+ if File.directory?(local_repo_path)
+ puts "\n#{repository_name} repository exists, updating or branching instead of cloning..."
+ FileUtils.cd(local_repo_path) do
+
+ # to avoid conflicts we need to set a remote branch for non official repos
+ existing_repos = `git remote -v`.split("\n").map{|branch| branch.split(/\s+/)}
+ origin_repo_url = existing_repos.detect{ |r| r.first == "origin" }.last
+
+ # pull from the original repository - no branching needed
+ if repository_url == origin_repo_url
+ puts "Pulling from #{repository_url}"
+ system %{
+ git fetch
+ git checkout master
+ git rebase origin/master
+ }
+ # update and switch to a branch for a particular github fork
+ elsif existing_repos.map{ |r| r.last }.include?(repository_url)
+ puts "Switching to remote branch: #{fork_name}"
+ `git checkout -b #{fork_name} #{fork_name}/master`
+ `git rebase #{fork_name}/master`
+ # create a new remote branch for a particular github fork
+ else
+ puts "Add a new remote branch: #{fork_name}"
+ `git remote add -f #{fork_name} #{repository_url}`
+ `git checkout -b#{fork_name} #{fork_name}/master`
+ end
+ end
+ else
+ FileUtils.cd(source_dir) do
+ puts "\nCloning #{repository_name} repository from #{repository_url}..."
+ system("git clone --depth=1 #{repository_url} ")
+ end
+ end
+ else
+ puts "No valid repository url given"
+ end
+ end
+
+ # Update a specific gem source directory from git. See #clone.
+
+ desc 'update REPOSITORY_URL', 'Update a git repository in ./src'
+ alias :update :clone
+
+ # Update all gem sources from git - based on the current branch.
+
+ desc 'refresh', 'Pull fresh copies of all source gems'
+ def refresh
+ repos = Dir["#{source_dir}/*"]
+ repos.each do |repo|
+ next unless File.directory?(repo) && File.exists?(File.join(repo, '.git'))
+ FileUtils.cd(repo) do
+ puts "Refreshing #{File.basename(repo)}"
+ branch = `git branch --no-color 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/(\1) /'`[/\* (.+)/, 1]
+ system %{git rebase #{branch}}
+ end
+ end
+ end
+
+ end
+
+ class Gems < Thor
+
+ # The Gems tasks deal directly with rubygems, either through remotely
+ # available sources (rubyforge for example) or by searching the
+ # system-wide gem cache for matching gems. The gems are installed from
+ # there into the desired gems dir (either system-wide or into the
+ # application's gems directory).
+
+ include MerbThorHelper
+
+ # Install a gem and its dependencies.
+ #
+ # If a local ./gems dir is found, or --merb-root is given
+ # the gems will be installed locally into that directory.
+ #
+ # The option --cache will look in the system's gem cache
+ # for the latest version and install it in the apps' gems.
+ # This is particularly handy for gems that aren't available
+ # through rubyforge.org - like in-house merb slices etc.
+ #
+ # Examples:
+ #
+ # thor merb:gems:install merb-core
+ # thor merb:gems:install merb-core --cache
+ # thor merb:gems:install merb-core --version 0.9.7
+ # thor merb:gems:install merb-core --merb-root ./path/to/your/app
+
+ desc 'install GEM_NAME', 'Install a gem from rubygems'
+ method_options "--version" => :optional,
+ "--merb-root" => :optional,
+ "--cache" => :boolean
+ def install(name)
+ puts "Installing #{name}..."
+ opts = {}
+ opts[:version] = options[:version]
+ opts[:cache] = options[:cache] if gem_dir
+ opts[:install_dir] = gem_dir if gem_dir
+ Merb.install_gem(name, opts)
+ rescue => e
+ puts "Failed to install #{name} (#{e.message})"
+ end
+
+ # Update a gem and its dependencies.
+ #
+ # If a local ./gems dir is found, or --merb-root is given
+ # the gems will be installed locally into that directory.
+ #
+ # The option --cache will look in the system's gem cache
+ # for the latest version and install it in the apps' gems.
+ # This is particularly handy for gems that aren't available
+ # through rubyforge.org - like in-house merb slices etc.
+ #
+ # Examples:
+ #
+ # thor merb:gems:update merb-core
+ # thor merb:gems:update merb-core --cache
+ # thor merb:gems:update merb-core --merb-root ./path/to/your/app
+
+ desc 'update GEM_NAME', 'Update a gem from rubygems'
+ method_options "--merb-root" => :optional,
+ "--cache" => :boolean
+ def update(name)
+ puts "Updating #{name}..."
+ opts = {}
+ if gem_dir
+ if gemspec_path = Dir[File.join(gem_dir, 'specifications', "#{name}-*.gemspec")].last
+ gemspec = Gem::Specification.load(gemspec_path)
+ opts[:version] = Gem::Requirement.new [">#{gemspec.version}"]
+ end
+ opts[:install_dir] = gem_dir
+ opts[:cache] = options[:cache]
+ end
+ Merb.install_gem(name, opts)
+ rescue => e
+ puts "Failed to update #{name} (#{e.message})"
+ end
+
+ # Uninstall a gem - ignores dependencies.
+ #
+ # If a local ./gems dir is found, or --merb-root is given
+ # the gems will be uninstalled locally from that directory.
+ #
+ # Examples:
+ #
+ # thor merb:gems:uninstall merb-core
+ # thor merb:gems:uninstall merb-core --all
+ # thor merb:gems:uninstall merb-core --version 0.9.7
+ # thor merb:gems:uninstall merb-core --merb-root ./path/to/your/app
+
+ desc 'install GEM_NAME', 'Install a gem from rubygems'
+ desc 'uninstall GEM_NAME', 'Uninstall a gem'
+ method_options "--version" => :optional,
+ "--merb-root" => :optional,
+ "--all" => :boolean
+ def uninstall(name)
+ puts "Uninstalling #{name}..."
+ opts = {}
+ opts[:ignore] = true
+ opts[:all] = options[:all]
+ opts[:executables] = true
+ opts[:version] = options[:version]
+ opts[:install_dir] = gem_dir if gem_dir
+ Merb.uninstall_gem(name, opts)
+ rescue => e
+ puts "Failed to uninstall #{name} (#{e.message})"
+ end
+
+ # Completely remove a gem and all its versions - ignores dependencies.
+ #
+ # If a local ./gems dir is found, or --merb-root is given
+ # the gems will be uninstalled locally from that directory.
+ #
+ # Examples:
+ #
+ # thor merb:gems:wipe merb-core
+ # thor merb:gems:wipe merb-core --merb-root ./path/to/your/app
+
+ desc 'wipe GEM_NAME', 'Remove a gem completely'
+ method_options "--merb-root" => :optional
+ def wipe(name)
+ puts "Wiping #{name}..."
+ opts = {}
+ opts[:ignore] = true
+ opts[:all] = true
+ opts[:executables] = true
+ opts[:install_dir] = gem_dir if gem_dir
+ Merb.uninstall_gem(name, opts)
+ rescue => e
+ puts "Failed to wipe #{name} (#{e.message})"
+ end
+
+ # This task should be executed as part of a deployment setup, where
+ # the deployment system runs this after the app has been installed.
+ # Usually triggered by Capistrano, God...
+ #
+ # It will regenerate gems from the bundled gems cache for any gem
+ # that has C extensions - which need to be recompiled for the target
+ # deployment platform.
+
+ desc 'redeploy', 'Recreate any binary gems on the target deployment platform'
+ def redeploy
+ require 'tempfile' # for
+ if File.directory?(specs_dir = File.join(gem_dir, 'specifications')) &&
+ File.directory?(cache_dir = File.join(gem_dir, 'cache'))
+ Dir[File.join(specs_dir, '*.gemspec')].each do |gemspec_path|
+ unless (gemspec = Gem::Specification.load(gemspec_path)).extensions.empty?
+ if File.exists?(gem_file = File.join(cache_dir, "#{gemspec.full_name}.gem"))
+ gem_file_copy = File.join(Dir::tmpdir, File.basename(gem_file))
+ # Copy the gem to a temporary file, because otherwise RubyGems/FileUtils
+ # will complain about copying identical files (same source/destination).
+ FileUtils.cp(gem_file, gem_file_copy)
+ Merb.install_gem(gem_file_copy, :install_dir => gem_dir)
+ File.delete(gem_file_copy)
+ end
+ end
+ end
+ else
+ puts "No application local gems directory found"
+ end
+ end
+
+ end
+
+ class << self
+
+ # Default Git repositories - pass source_config option
+ # to load a yaml configuration file.
+ def repos(source_config = nil)
+ @_repos ||= begin
+ repositories = {
+ 'merb-core' => "git://github.com/wycats/merb-core.git",
+ 'merb-more' => "git://github.com/wycats/merb-more.git",
+ 'merb-plugins' => "git://github.com/wycats/merb-plugins.git",
+ 'extlib' => "git://github.com/sam/extlib.git",
+ 'dm-core' => "git://github.com/sam/dm-core.git",
+ 'dm-more' => "git://github.com/sam/dm-more.git",
+ 'thor' => "git://github.com/wycats/thor.git"
+ }
+ end
+ if source_config && File.exists?(source_config)
+ @_repos.merge(YAML.load(File.read(source_config)))
+ else
+ @_repos
+ end
+ end
+
+ # Install a gem - looks remotely and local gem cache;
+ # won't process rdoc or ri options.
+ def install_gem(gem, options = {})
+ from_cache = (options.key?(:cache) && options.delete(:cache))
+ if from_cache
+ install_gem_from_cache(gem, options)
+ else
+ version = options.delete(:version)
+ Gem.configuration.update_sources = false
+ installer = Gem::DependencyInstaller.new(options.merge(:user_install => false))
+ exception = nil
+ begin
+ installer.install gem, version
+ rescue Gem::InstallError => e
+ exception = e
+ rescue Gem::GemNotFoundException => e
+ if from_cache && gem_file = find_gem_in_cache(gem, version)
+ puts "Located #{gem} in gem cache..."
+ installer.install gem_file
+ else
+ exception = e
+ end
+ rescue => e
+ exception = e
+ end
+ if installer.installed_gems.empty? && exception
+ puts "Failed to install gem '#{gem}' (#{exception.message})"
+ end
+ installer.installed_gems.each do |spec|
+ puts "Successfully installed #{spec.full_name}"
+ end
+ end
+ end
+
+ # Install a gem - looks in the system's gem cache instead of remotely;
+ # won't process rdoc or ri options.
+ def install_gem_from_cache(gem, options = {})
+ version = options.delete(:version)
+ Gem.configuration.update_sources = false
+ installer = Gem::DependencyInstaller.new(options.merge(:user_install => false))
+ exception = nil
+ begin
+ if gem_file = find_gem_in_cache(gem, version)
+ puts "Located #{gem} in gem cache..."
+ installer.install gem_file
+ else
+ raise Gem::InstallError, "Unknown gem #{gem}"
+ end
+ rescue Gem::InstallError => e
+ exception = e
+ end
+ if installer.installed_gems.empty? && exception
+ puts "Failed to install gem '#{gem}' (#{e.message})"
+ end
+ installer.installed_gems.each do |spec|
+ puts "Successfully installed #{spec.full_name}"
+ end
+ end
+
+ # Install a gem from source - builds and packages it first then installs it.
+ def install_gem_from_src(gem_src_dir, options = {})
+ raise SourcePathMissing unless File.directory?(gem_src_dir)
+ raise GemPathMissing if options[:install_dir] && !File.directory?(options[:install_dir])
+
+ gem_name = File.basename(gem_src_dir)
+ gem_pkg_dir = File.expand_path(File.join(gem_src_dir, 'pkg'))
+
+ # We need to use local bin executables if available.
+ thor = which('thor')
+ rake = which('rake')
+
+ # Handle pure Thor installation instead of Rake
+ if File.exists?(File.join(gem_src_dir, 'Thorfile'))
+ # Remove any existing packages.
+ FileUtils.rm_rf(gem_pkg_dir) if File.directory?(gem_pkg_dir)
+ # Create the package.
+ FileUtils.cd(gem_src_dir) { system("#{thor} :package") }
+ # Install the package using rubygems.
+ if package = Dir[File.join(gem_pkg_dir, "#{gem_name}-*.gem")].last
+ FileUtils.cd(File.dirname(package)) do
+ install_gem(File.basename(package), options.dup)
+ return
+ end
+ else
+ raise Merb::GemInstallError, "No package found for #{gem_name}"
+ end
+ # Handle standard installation through Rake
+ else
+ # Clean and regenerate any subgems for meta gems.
+ Dir[File.join(gem_src_dir, '*', 'Rakefile')].each do |rakefile|
+ FileUtils.cd(File.dirname(rakefile)) { system("#{rake} clobber_package; #{rake} package") }
+ end
+
+ # Handle the main gem install.
+ if File.exists?(File.join(gem_src_dir, 'Rakefile'))
+ # Remove any existing packages.
+ FileUtils.cd(gem_src_dir) { system("#{rake} clobber_package") }
+ # Create the main gem pkg dir if it doesn't exist.
+ FileUtils.mkdir_p(gem_pkg_dir) unless File.directory?(gem_pkg_dir)
+ # Copy any subgems to the main gem pkg dir.
+ Dir[File.join(gem_src_dir, '**', 'pkg', '*.gem')].each do |subgem_pkg|
+ FileUtils.cp(subgem_pkg, gem_pkg_dir)
+ end
+
+ # Finally generate the main package and install it; subgems
+ # (dependencies) are local to the main package.
+ FileUtils.cd(gem_src_dir) do
+ system("#{rake} package")
+ if package = Dir[File.join(gem_pkg_dir, "#{gem_name}-*.gem")].last
+ FileUtils.cd(File.dirname(package)) do
+ install_gem(File.basename(package), options.dup)
+ return
+ end
+ else
+ raise Merb::GemInstallError, "No package found for #{gem_name}"
+ end
+ end
+ end
+ end
+ raise Merb::GemInstallError, "No Rakefile found for #{gem_name}"
+ end
+
+ # Uninstall a gem.
+ def uninstall_gem(gem, options = {})
+ if options[:version] && !options[:version].is_a?(Gem::Requirement)
+ options[:version] = Gem::Requirement.new ["= #{version}"]
+ end
+ begin
+ Gem::Uninstaller.new(gem, options).uninstall
+ rescue => e
+ raise GemUninstallError, "Failed to uninstall #{gem}"
+ end
+ end
+
+ # Will prepend sudo on a suitable platform.
+ def sudo
+ @_sudo ||= begin
+ windows = PLATFORM =~ /win32|cygwin/ rescue nil
+ windows ? "" : "sudo "
+ end