Skip to content
Browse files

Update to allow a second tier of notifcations

  • Loading branch information...
1 parent fd2219a commit a2a4bb4045b56bf1756110a883e01a6e5db353e7 @brianjlandau brianjlandau committed Nov 18, 2010
Showing with 5,367 additions and 2,929 deletions.
  1. +1 −0 .gitignore
  2. +10 −0 app/helpers/sites_helper.rb
  3. +1 −1 app/models/monit.rb
  4. +1 −0 app/models/site.rb
  5. +3 −0 app/templates/edit_site.mustache
  6. +15 −0 app/templates/monit_check.mustache
  7. +3 −0 app/templates/new_site.mustache
  8. +6 −0 app/templates/show_site.mustache
  9. +3 −2 app/templates/stylesheet.sass
  10. +6 −0 app/views/layout.rb
  11. +16 −0 app/views/monit_check.rb
  12. +1 −1 app/views/show_site.rb
  13. +11 −0 db/migrate/003_add_second_tier_to_sites.rb
  14. +3 −1 db/schema.rb
  15. +6 −6 dependencies
  16. +5 −2 init.rb
  17. +2 −3 test/stories/sites_test.rb
  18. +1 −1 test/stories_helper.rb
  19. +0 −5 vendor/dependencies-0.0.7/Rakefile
  20. 0 vendor/{dependencies-0.0.7 → dependencies-0.0.9}/README.markdown
  21. +7 −0 vendor/dependencies-0.0.9/Rakefile
  22. +1 −1 vendor/{dependencies-0.0.7 → dependencies-0.0.9}/bin/dep
  23. +2 −2 vendor/{dependencies-0.0.7 → dependencies-0.0.9}/dependencies.gemspec
  24. 0 vendor/{dependencies-0.0.7 → dependencies-0.0.9}/lib/dependencies.rb
  25. +2 −1 vendor/{dependencies-0.0.7 → dependencies-0.0.9}/lib/dependencies/dep.rb
  26. +13 −0 vendor/{dependencies-0.0.7 → dependencies-0.0.9}/test/dependencies_test.rb
  27. 0 vendor/{dependencies-0.0.7 → dependencies-0.0.9}/test/foobaz-0.3.gem
  28. +0 −17 vendor/monk-glue/lib/monk/glue.rb
  29. +1 −2 vendor/monk-glue/lib/monk/glue/logger.rb
  30. +1 −1 vendor/monk-glue/lib/monk/glue/reloader.rb
  31. +4 −5 vendor/monk-glue/lib/monk/glue/settings.rb
  32. 0 vendor/{mustache-0.3.0 → mustache-0.11.2}/LICENSE
  33. +136 −131 vendor/{mustache-0.3.0 → mustache-0.11.2}/README.md
  34. +103 −0 vendor/mustache-0.11.2/Rakefile
  35. +90 −0 vendor/mustache-0.11.2/bin/mustache
  36. +159 −10 vendor/{mustache-0.3.0 → mustache-0.11.2}/lib/mustache.rb
  37. +108 −0 vendor/mustache-0.11.2/lib/mustache/context.rb
  38. +158 −0 vendor/mustache-0.11.2/lib/mustache/generator.rb
  39. +230 −0 vendor/mustache-0.11.2/lib/mustache/parser.rb
  40. +180 −0 vendor/mustache-0.11.2/lib/mustache/sinatra.rb
  41. +59 −0 vendor/mustache-0.11.2/lib/mustache/template.rb
  42. +3 −0 vendor/mustache-0.11.2/lib/mustache/version.rb
  43. +81 −0 vendor/mustache-0.11.2/lib/rack/bug/panels/mustache_panel.rb
  44. +27 −0 vendor/mustache-0.11.2/lib/rack/bug/panels/mustache_panel/mustache_extension.rb
  45. +46 −0 vendor/mustache-0.11.2/lib/rack/bug/panels/mustache_panel/view.mustache
  46. +180 −0 vendor/mustache-0.11.2/man/mustache.1
  47. +204 −0 vendor/mustache-0.11.2/man/mustache.1.html
  48. +127 −0 vendor/mustache-0.11.2/man/mustache.1.ron
  49. +576 −0 vendor/mustache-0.11.2/man/mustache.5
  50. +415 −0 vendor/mustache-0.11.2/man/mustache.5.html
  51. +324 −0 vendor/mustache-0.11.2/man/mustache.5.ron
  52. +52 −0 vendor/mustache-0.11.2/test/autoloading_test.rb
  53. +1 −0 vendor/mustache-0.11.2/test/fixtures/comments.mustache
  54. 0 vendor/{mustache-0.3.0/examples → mustache-0.11.2/test/fixtures}/comments.rb
  55. +3 −2 ...{mustache-0.3.0/examples/complex_view.html → mustache-0.11.2/test/fixtures/complex_view.mustache}
  56. +1 −1 vendor/{mustache-0.3.0/examples → mustache-0.11.2/test/fixtures}/complex_view.rb
  57. +9 −0 vendor/mustache-0.11.2/test/fixtures/crazy_recursive.mustache
  58. +31 −0 vendor/mustache-0.11.2/test/fixtures/crazy_recursive.rb
  59. +8 −0 vendor/mustache-0.11.2/test/fixtures/delimiters.mustache
  60. +6 −5 vendor/{mustache-0.3.0/examples → mustache-0.11.2/test/fixtures}/delimiters.rb
  61. +7 −0 vendor/mustache-0.11.2/test/fixtures/double_section.mustache
  62. +14 −0 vendor/mustache-0.11.2/test/fixtures/double_section.rb
  63. 0 vendor/{mustache-0.3.0/examples/escaped.html → mustache-0.11.2/test/fixtures/escaped.mustache}
  64. 0 vendor/{mustache-0.3.0/examples → mustache-0.11.2/test/fixtures}/escaped.rb
  65. 0 ...ustache-0.3.0/examples/inner_partial.html → mustache-0.11.2/test/fixtures/inner_partial.mustache}
  66. 0 vendor/{mustache-0.3.0/examples → mustache-0.11.2/test/fixtures}/inner_partial.txt
  67. +7 −0 vendor/mustache-0.11.2/test/fixtures/inverted_section.mustache
  68. +14 −0 vendor/mustache-0.11.2/test/fixtures/inverted_section.rb
  69. +3 −0 vendor/mustache-0.11.2/test/fixtures/lambda.mustache
  70. +27 −0 vendor/mustache-0.11.2/test/fixtures/lambda.rb
  71. +1 −0 vendor/mustache-0.11.2/test/fixtures/namespaced.mustache
  72. +25 −0 vendor/mustache-0.11.2/test/fixtures/namespaced.rb
  73. +17 −0 vendor/mustache-0.11.2/test/fixtures/nested_objects.mustache
  74. +35 −0 vendor/mustache-0.11.2/test/fixtures/nested_objects.rb
  75. +8 −0 vendor/mustache-0.11.2/test/fixtures/node.mustache
  76. +3 −0 vendor/mustache-0.11.2/test/fixtures/partial_with_module.mustache
  77. +37 −0 vendor/mustache-0.11.2/test/fixtures/partial_with_module.rb
  78. 0 vendor/{mustache-0.3.0/examples → mustache-0.11.2/test/fixtures}/passenger.conf
  79. 0 vendor/{mustache-0.3.0/examples → mustache-0.11.2/test/fixtures}/passenger.rb
  80. +4 −0 vendor/mustache-0.11.2/test/fixtures/recursive.mustache
  81. +4 −8 vendor/{mustache-0.3.0/examples/view_partial.rb → mustache-0.11.2/test/fixtures/recursive.rb}
  82. 0 vendor/{mustache-0.3.0/examples/simple.html → mustache-0.11.2/test/fixtures/simple.mustache}
  83. 0 vendor/{mustache-0.3.0/examples → mustache-0.11.2/test/fixtures}/simple.rb
  84. +1 −1 ...e-0.3.0/examples/template_partial.html → mustache-0.11.2/test/fixtures/template_partial.mustache}
  85. 0 vendor/{mustache-0.3.0/examples → mustache-0.11.2/test/fixtures}/template_partial.rb
  86. +1 −1 vendor/{mustache-0.3.0/examples → mustache-0.11.2/test/fixtures}/template_partial.txt
  87. 0 vendor/{mustache-0.3.0/examples/unescaped.html → mustache-0.11.2/test/fixtures/unescaped.mustache}
  88. 0 vendor/{mustache-0.3.0/examples → mustache-0.11.2/test/fixtures}/unescaped.rb
  89. +3 −0 vendor/mustache-0.11.2/test/fixtures/utf8.mustache
  90. +1 −0 vendor/mustache-0.11.2/test/fixtures/utf8_partial.mustache
  91. +7 −0 vendor/mustache-0.11.2/test/helper.rb
  92. +476 −0 vendor/mustache-0.11.2/test/mustache_test.rb
  93. +54 −0 vendor/mustache-0.11.2/test/parser_test.rb
  94. +168 −0 vendor/mustache-0.11.2/test/partial_test.rb
  95. +0 −1 vendor/mustache-0.3.0/.gitignore
  96. +0 −26 vendor/mustache-0.3.0/.kick
  97. +0 −5 vendor/mustache-0.3.0/CONTRIBUTORS
  98. +0 −24 vendor/mustache-0.3.0/HISTORY.md
  99. +0 −62 vendor/mustache-0.3.0/Rakefile
  100. +0 −15 vendor/mustache-0.3.0/benchmarks/complex.erb
  101. +0 −20 vendor/mustache-0.3.0/benchmarks/helper.rb
  102. +0 −5 vendor/mustache-0.3.0/benchmarks/simple.erb
  103. +0 −53 vendor/mustache-0.3.0/benchmarks/speed.rb
  104. +0 −1 vendor/mustache-0.3.0/examples/comments.html
  105. +0 −6 vendor/mustache-0.3.0/examples/delimiters.html
  106. +0 −3 vendor/mustache-0.3.0/examples/view_partial.html
  107. +0 −20 vendor/mustache-0.3.0/lib/mustache/context.rb
  108. +0 −109 vendor/mustache-0.3.0/lib/mustache/sinatra.rb
  109. +0 −162 vendor/mustache-0.3.0/lib/mustache/template.rb
  110. +0 −3 vendor/mustache-0.3.0/lib/mustache/version.rb
  111. +0 −264 vendor/mustache-0.3.0/test/mustache_test.rb
  112. +0 −423 vendor/rack-1.0.0/RDOX
  113. +0 −164 vendor/rack-1.0.0/Rakefile
  114. +0 −176 vendor/rack-1.0.0/bin/rackup
  115. +0 −480 vendor/rack-1.0.0/lib/rack/auth/openid.rb
  116. +0 −61 vendor/rack-1.0.0/lib/rack/commonlogger.rb
  117. +0 −109 vendor/rack-1.0.0/lib/rack/session/memcache.rb
  118. +0 −54 vendor/rack-1.0.0/rack.gemspec
  119. +0 −20 vendor/rack-1.0.0/test/cgi/lighttpd.conf
  120. +0 −9 vendor/rack-1.0.0/test/cgi/test
  121. +0 −8 vendor/rack-1.0.0/test/cgi/test.fcgi
  122. +0 −7 vendor/rack-1.0.0/test/cgi/test.ru
  123. BIN vendor/rack-1.0.0/test/multipart/binary
  124. +0 −10 vendor/rack-1.0.0/test/multipart/empty
  125. +0 −6 vendor/rack-1.0.0/test/multipart/ie
  126. +0 −10 vendor/rack-1.0.0/test/multipart/nested
  127. +0 −9 vendor/rack-1.0.0/test/multipart/none
  128. +0 −10 vendor/rack-1.0.0/test/multipart/text
  129. +0 −84 vendor/rack-1.0.0/test/spec_rack_auth_openid.rb
  130. +0 −32 vendor/rack-1.0.0/test/spec_rack_commonlogger.rb
  131. +0 −57 vendor/rack-1.0.0/test/testrequest.rb
  132. +0 −7 vendor/rack-1.0.0/test/unregistered_handler/rack/handler/unregistered.rb
  133. +0 −7 vendor/rack-1.0.0/test/unregistered_handler/rack/handler/unregistered_long_one.rb
  134. +1 −1 vendor/{rack-1.0.0 → rack-1.1.0}/COPYING
  135. +3 −0 vendor/{rack-1.0.0 → rack-1.1.0}/KNOWN-ISSUES
  136. 0 vendor/rack-1.1.0/RDOX
  137. +72 −26 vendor/{rack-1.0.0 → rack-1.1.0}/README
  138. +11 −2 vendor/{rack-1.0.0 → rack-1.1.0}/SPEC
  139. +4 −0 vendor/rack-1.1.0/bin/rackup
  140. 0 vendor/{rack-1.0.0 → rack-1.1.0}/contrib/rack_logo.svg
  141. 0 vendor/{rack-1.0.0 → rack-1.1.0}/example/lobster.ru
  142. 0 vendor/{rack-1.0.0 → rack-1.1.0}/example/protectedlobster.rb
  143. 0 vendor/{rack-1.0.0 → rack-1.1.0}/example/protectedlobster.ru
  144. +10 −8 vendor/{rack-1.0.0 → rack-1.1.0}/lib/rack.rb
  145. 0 vendor/{rack-1.0.0 → rack-1.1.0}/lib/rack/adapter/camping.rb
  146. 0 vendor/{rack-1.0.0 → rack-1.1.0}/lib/rack/auth/abstract/handler.rb
  147. 0 vendor/{rack-1.0.0 → rack-1.1.0}/lib/rack/auth/abstract/request.rb
  148. 0 vendor/{rack-1.0.0 → rack-1.1.0}/lib/rack/auth/basic.rb
  149. 0 vendor/{rack-1.0.0 → rack-1.1.0}/lib/rack/auth/digest/md5.rb
  150. 0 vendor/{rack-1.0.0 → rack-1.1.0}/lib/rack/auth/digest/nonce.rb
  151. 0 vendor/{rack-1.0.0 → rack-1.1.0}/lib/rack/auth/digest/params.rb
  152. 0 vendor/{rack-1.0.0 → rack-1.1.0}/lib/rack/auth/digest/request.rb
  153. +17 −0 vendor/{rack-1.0.0 → rack-1.1.0}/lib/rack/builder.rb
  154. +17 −12 vendor/{rack-1.0.0 → rack-1.1.0}/lib/rack/cascade.rb
  155. +2 −2 vendor/{rack-1.0.0 → rack-1.1.0}/lib/rack/chunked.rb
  156. +49 −0 vendor/rack-1.1.0/lib/rack/commonlogger.rb
  157. 0 vendor/{rack-1.0.0 → rack-1.1.0}/lib/rack/conditionalget.rb
  158. +15 −0 vendor/rack-1.1.0/lib/rack/config.rb
  159. 0 vendor/{rack-1.0.0 → rack-1.1.0}/lib/rack/content_length.rb
  160. +1 −1 vendor/{rack-1.0.0 → rack-1.1.0}/lib/rack/content_type.rb
  161. +1 −1 vendor/{rack-1.0.0 → rack-1.1.0}/lib/rack/deflater.rb
  162. +6 −2 vendor/{rack-1.0.0 → rack-1.1.0}/lib/rack/directory.rb
  163. +23 −0 vendor/rack-1.1.0/lib/rack/etag.rb
  164. +4 −2 vendor/{rack-1.0.0 → rack-1.1.0}/lib/rack/file.rb
  165. +19 −0 vendor/{rack-1.0.0 → rack-1.1.0}/lib/rack/handler.rb
  166. +1 −1 vendor/{rack-1.0.0 → rack-1.1.0}/lib/rack/handler/cgi.rb
  167. 0 vendor/{rack-1.0.0 → rack-1.1.0}/lib/rack/handler/evented_mongrel.rb
  168. +10 −9 vendor/{rack-1.0.0 → rack-1.1.0}/lib/rack/handler/fastcgi.rb
  169. +16 −8 vendor/{rack-1.0.0 → rack-1.1.0}/lib/rack/handler/lsws.rb
  170. +12 −6 vendor/{rack-1.0.0 → rack-1.1.0}/lib/rack/handler/mongrel.rb
  171. +9 −6 vendor/{rack-1.0.0 → rack-1.1.0}/lib/rack/handler/scgi.rb
  172. 0 vendor/{rack-1.0.0 → rack-1.1.0}/lib/rack/handler/swiftiplied_mongrel.rb
  173. 0 vendor/{rack-1.0.0 → rack-1.1.0}/lib/rack/handler/thin.rb
  174. +7 −5 vendor/{rack-1.0.0 → rack-1.1.0}/lib/rack/handler/webrick.rb
  175. 0 vendor/{rack-1.0.0 → rack-1.1.0}/lib/rack/head.rb
  176. +53 −15 vendor/{rack-1.0.0 → rack-1.1.0}/lib/rack/lint.rb
  177. 0 vendor/{rack-1.0.0 → rack-1.1.0}/lib/rack/lobster.rb
  178. 0 vendor/{rack-1.0.0 → rack-1.1.0}/lib/rack/lock.rb
  179. +20 −0 vendor/rack-1.1.0/lib/rack/logger.rb
  180. 0 vendor/{rack-1.0.0 → rack-1.1.0}/lib/rack/methodoverride.rb
  181. +3 −1 vendor/{rack-1.0.0 → rack-1.1.0}/lib/rack/mime.rb
  182. +35 −6 vendor/{rack-1.0.0 → rack-1.1.0}/lib/rack/mock.rb
  183. +18 −0 vendor/rack-1.1.0/lib/rack/nulllogger.rb
  184. 0 vendor/{rack-1.0.0 → rack-1.1.0}/lib/rack/recursive.rb
  185. +6 −3 vendor/{rack-1.0.0 → rack-1.1.0}/lib/rack/reloader.rb
  186. +40 −23 vendor/{rack-1.0.0 → rack-1.1.0}/lib/rack/request.rb
  187. +5 −39 vendor/{rack-1.0.0 → rack-1.1.0}/lib/rack/response.rb
  188. +2 −0 vendor/{rack-1.0.0 → rack-1.1.0}/lib/rack/rewindable_input.rb
  189. +27 −0 vendor/rack-1.1.0/lib/rack/runtime.rb
  190. +142 −0 vendor/rack-1.1.0/lib/rack/sendfile.rb
  191. +212 −0 vendor/rack-1.1.0/lib/rack/server.rb
  192. +3 −5 vendor/{rack-1.0.0 → rack-1.1.0}/lib/rack/session/abstract/id.rb
  193. +3 −4 vendor/{rack-1.0.0 → rack-1.1.0}/lib/rack/session/cookie.rb
  194. +119 −0 vendor/rack-1.1.0/lib/rack/session/memcache.rb
  195. +1 −1 vendor/{rack-1.0.0 → rack-1.1.0}/lib/rack/session/pool.rb
  196. 0 vendor/{rack-1.0.0 → rack-1.1.0}/lib/rack/showexceptions.rb
  197. 0 vendor/{rack-1.0.0 → rack-1.1.0}/lib/rack/showstatus.rb
  198. 0 vendor/{rack-1.0.0 → rack-1.1.0}/lib/rack/static.rb
  199. +9 −8 vendor/{rack-1.0.0 → rack-1.1.0}/lib/rack/urlmap.rb
Sorry, we could not display the entire diff because too many files (949) changed.
View
1 .gitignore
@@ -11,3 +11,4 @@ config/settings.yml
config/deploy.rb
config/database.yml
db/*.sqlite3
+.rvmrc
View
10 app/helpers/sites_helper.rb
@@ -22,6 +22,16 @@ def threshold_input(value = nil)
def email_input(value = nil)
input(:text, 'site[email]', site.email, :id => 'site-email', :label => 'Email Address')
end
+
+ def tier_two_threshold_input(value = nil)
+ input(:text, 'site[threshold_tier_two]', site.threshold_tier_two, :id => 'site-threshold_tier_two',
+ :label => '# of Failures for Tier Two Notification')
+ end
+
+ def tier_two_email_input(value = nil)
+ input(:text, 'site[email_tier_two]', site.email_tier_two, :id => 'site-email_tier_two',
+ :label => 'Tier Two Email Address')
+ end
def site_errors
errors = site.errors.map {|attr, msg| { :message => "#{attr} #{msg}" } }
View
2 app/models/monit.rb
@@ -17,6 +17,6 @@ def statuses
private
def format_command(command)
- "#{File.join(settings(:monit_bin_dir), 'monit')} #{settings(:monit_cli_options)} #{command}"
+ "#{File.join(monk_settings(:monit_bin_dir), 'monit')} #{monk_settings(:monit_cli_options)} #{command}"
end
end
View
1 app/models/site.rb
@@ -34,6 +34,7 @@ def self.http_url
validates_uniqueness_of :url
validates_format_of :email, :with => Regex.email, :allow_nil => true
+ validates_format_of :email_tier_two, :with => Regex.email, :allow_blank => true
validates_format_of :url, :with => Regex.http_url, :allow_nil => true
def host
View
3 app/templates/edit_site.mustache
@@ -13,6 +13,9 @@
{{{match_text_input}}}
{{{threshold_input}}}
{{{email_input}}}
+ <br />
+ {{{tier_two_threshold_input}}}
+ {{{tier_two_email_input}}}
</fieldset>
<input type="submit" value="save" />
View
15 app/templates/monit_check.mustache
@@ -10,3 +10,18 @@ check host {{monit_check_name}} with address {{host_name}}
$DESCRIPTION
}
{{/emails}}
+
+{{#tier_two?}}
+check host {{monit_check_name}}_tier_two with address {{host_name}}
+ if failed url {{url}}
+ {{#match_text?}}and content == "{{match_text}}" {{/match_text?}}
+ with timeout 30 seconds for {{threshold_tier_two}} cycles
+ then alert
+ {{#emails_tier_two}}
+ alert {{email}} with mail-format {
+ subject: [WATCH DOG] $EVENT for {{site_name}}
+ message: As of $DATE {{site_name}} is $EVENT:
+ $DESCRIPTION
+ }
+ {{/emails_tier_two}}
+{{/tier_two?}}
View
3 app/templates/new_site.mustache
@@ -14,6 +14,9 @@
{{{match_text_input}}}
{{{threshold_input}}}
{{{email_input}}}
+ <br />
+ {{{tier_two_threshold_input}}}
+ {{{tier_two_email_input}}}
</fieldset>
<input type="submit" value="add" />
View
6 app/templates/show_site.mustache
@@ -13,6 +13,12 @@
<dt>Email Address</dt>
<dd>{{site_email}}</dd>
+
+ <dt># of Failures for Tier Two Notification</dt>
+ <dd>{{site_threshold_tier_two}}</dd>
+
+ <dt>Tier Two Email Address</dt>
+ <dd>{{site_email_tier_two}}</dd>
</dl>
<form action="/sites/{{site_id}}" method="POST" onsubmit="return confirm('Delete this site?')">
View
5 app/templates/stylesheet.sass
@@ -17,11 +17,12 @@ a
dt
float: left
- width: 150px
+ width: 230px
+ font-weight: bold
text-transform: capitalize
dd
- margin-bottom: 20px
+ margin-bottom: 25px
fieldset
border: none
View
6 app/views/layout.rb
@@ -0,0 +1,6 @@
+class Main
+ module Views
+ class Layout < Mustache
+ end
+ end
+end
View
16 app/views/monit_check.rb
@@ -30,6 +30,22 @@ def threshold
@site.threshold
end
+ def tier_two?
+ !@site.email_tier_two.blank? && !@site.threshold_tier_two.blank?
+ end
+
+ def threshold_tier_two
+ @site.threshold_tier_two
+ end
+
+ def emails_tier_two
+ unless @site.email_tier_two.blank?
+ @site.email_tier_two.split(/\s*,\s*/).map {|e| {:email => e} }
+ else
+ []
+ end
+ end
+
def match_text?
!@site.match_text.blank?
end
View
2 app/views/show_site.rb
@@ -3,7 +3,7 @@ module Views
class ShowSite < Mustache
attr_reader :site
- [:id, :name, :url, :threshold, :email].each do |attribute|
+ [:id, :name, :url, :threshold, :email, :email_tier_two, :threshold_tier_two].each do |attribute|
define_method("site_#{attribute}") { site.send(attribute) }
end
View
11 db/migrate/003_add_second_tier_to_sites.rb
@@ -0,0 +1,11 @@
+class AddSecondTierToSites < ActiveRecord::Migration
+ def self.up
+ add_column :sites, :threshold_tier_two, :integer
+ add_column :sites, :email_tier_two, :string
+ end
+
+ def self.down
+ remove_column :sites, :email_tier_two
+ remove_column :sites, :threshold_tier_two
+ end
+end
View
4 db/schema.rb
@@ -9,7 +9,7 @@
#
# It's strongly recommended to check this file into your version control system.
-ActiveRecord::Schema.define(:version => 2) do
+ActiveRecord::Schema.define(:version => 3) do
create_table "sites", :force => true do |t|
t.string "name"
@@ -19,6 +19,8 @@
t.string "email"
t.datetime "created_at"
t.datetime "updated_at"
+ t.integer "threshold_tier_two"
+ t.string "email_tier_two"
end
end
View
12 dependencies
@@ -1,16 +1,16 @@
-dependencies 0.0.7 git://github.com/djanowski/dependencies.git
+dependencies 0.0.9 git://github.com/djanowski/dependencies.git
monk-glue git://github.com/monkrb/glue.git
quietbacktrace 0.1.1 git://github.com/thoughtbot/quietbacktrace.git
-rack 1.0.0 git://github.com/rack/rack.git
-sinatra 0.9.4 git://github.com/sinatra/sinatra.git
-mustache 0.3.0 git://github.com/defunkt/mustache.git
+rack 1.1.0 git://github.com/rack/rack.git
+sinatra 1.1.0 git://github.com/sinatra/sinatra.git
+mustache 0.11.2 git://github.com/defunkt/mustache.git
activesupport 2.3.4
activerecord 2.3.4
contest 0.1.2 (test) git://github.com/citrusbyte/contest.git
stories 0.1.3 (test) git://github.com/citrusbyte/stories.git
faker 0.3.1 (test) git://github.com/yyyc514/faker.git
-rack-test 0.5.0 (test) git://github.com/brynary/rack-test.git
-webrat 0.5.3 (test) git://github.com/brynary/webrat.git
+rack-test 0.5.6 (test) git://github.com/brynary/rack-test.git
+webrat 0.7.2 (test) git://github.com/brynary/webrat.git
mocha 0.9.8 (test)
factory_girl 1.2.3 (test)
haml 2.2.24
View
7 init.rb
@@ -3,7 +3,7 @@
require "rubygems"
begin
- require "vendor/dependencies-0.0.7/lib/dependencies"
+ require "vendor/dependencies-0.0.9/lib/dependencies"
rescue LoadError
require "dependencies"
end
@@ -19,7 +19,10 @@ class Main < Monk::Glue
use Rack::Session::Cookie
register Mustache::Sinatra
set :views, root_path('app', 'templates')
- set :mustaches, root_path('app', 'views')
+ set :mustache, {
+ :templates => root_path('app', 'templates'),
+ :views => root_path('app', 'views')
+ }
configure do
# Set up ActiveRecord
View
5 test/stories/sites_test.rb
@@ -4,7 +4,6 @@ class SitesTest < Test::Unit::TestCase
story "I should be able to visit the home page which is a list of sites" do
scenario "A visitor goes to the root URL" do
site = Factory(:site)
-
visit "/"
assert_contain "Watchdog"
@@ -44,7 +43,7 @@ class SitesTest < Test::Unit::TestCase
fill_in "site-threshold", :with => "5"
fill_in "site-email", :with => "admin@google.com"
click_button "add"
-
+
assert_have_no_selector 'form input[type="text"]'
assert_contain "admin@google.com"
end
@@ -105,7 +104,7 @@ class SitesTest < Test::Unit::TestCase
site = Factory(:site, :name => "Yahoo")
visit "/sites/#{site.id}"
click_button "delete"
-
+
assert_equal nil, Site.find_by_id(site.id)
assert_not_contain "Yahoo"
end
View
2 test/stories_helper.rb
@@ -6,7 +6,7 @@
require "stories/runner"
Webrat.configure do |config|
- config.mode = :rack
+ config.mode = :sinatra
end
class Test::Unit::TestCase
View
5 vendor/dependencies-0.0.7/Rakefile
@@ -1,5 +0,0 @@
-task :test do
- system "cd test && env GEM_HOME=#{File.expand_path("tmp")} ruby dependencies_test.rb"
-end
-
-task :default => :test
View
0 vendor/dependencies-0.0.7/README.markdown → vendor/dependencies-0.0.9/README.markdown
File renamed without changes.
View
7 vendor/dependencies-0.0.9/Rakefile
@@ -0,0 +1,7 @@
+task :test do
+ binary = File.open($0) { |f| f.gets }[/#\s*!\s*(.*)/, 1]
+ puts "Running suite with #{binary}"
+ system "cd test && env GEM_HOME=#{File.expand_path("tmp")} #{binary} dependencies_test.rb"
+end
+
+task :default => :test
View
2 vendor/dependencies-0.0.7/bin/dep → vendor/dependencies-0.0.9/bin/dep
@@ -51,7 +51,7 @@ protected
def fetch(dep)
if dep.version
- run "gem unpack #{dep.name} -v #{dep.version}"
+ run "gem unpack #{dep.name} -v '#{dep.version}'"
else
run "git clone #{dep.url} #{dep.name} -q --depth 1"
end
View
4 ...r/dependencies-0.0.7/dependencies.gemspec → ...r/dependencies-0.0.9/dependencies.gemspec
@@ -1,6 +1,6 @@
Gem::Specification.new do |s|
s.name = "dependencies"
- s.version = "0.0.7"
+ s.version = "0.0.9"
s.summary = "Specify your project's dependencies in one file."
s.authors = ["Damian Janowski", "Michel Martens"]
s.email = ["djanowski@dimaion.com", "michel@soveran.com"]
@@ -9,7 +9,7 @@ Gem::Specification.new do |s|
s.executables << "dep"
- s.files = ["README.markdown", "Rakefile", "bin/dep", "dependencies.gemspec", "lib/dependencies/dep.rb", "lib/dependencies.rb", "test/dependencies_test.rb", "test/foobaz-0.3.gem", "test/vendor/bar/lib", "test/vendor/barz-2.0/lib", "test/vendor/baz-1.0/lib"]
+ s.files = ["README.markdown", "Rakefile", "bin/dep", "dependencies.gemspec", "lib/dependencies/dep.rb", "lib/dependencies.rb", "test/dependencies_test.rb", "test/foobaz-0.3.gem", "test/vendor/bar/lib", "test/vendor/bar-core-1.0/lib", "test/vendor/barz-2.0/lib", "test/vendor/baz-1.0/lib"]
s.add_dependency("thor", "~> 0.11")
end
View
0 ...or/dependencies-0.0.7/lib/dependencies.rb → ...or/dependencies-0.0.9/lib/dependencies.rb
File renamed without changes.
View
3 ...ependencies-0.0.7/lib/dependencies/dep.rb → ...ependencies-0.0.9/lib/dependencies/dep.rb
@@ -25,7 +25,8 @@ def vendor_name
end
def vendor_path
- Dir[File.join("vendor", "#{vendor_name}*", "lib")].first ||
+ Dir[File.join("vendor", vendor_name, "lib")].first ||
+ Dir[File.join("vendor", "#{vendor_name}*", "lib")].first ||
Dir[File.join("vendor", name, "lib")].first
end
View
13 ...endencies-0.0.7/test/dependencies_test.rb → ...endencies-0.0.9/test/dependencies_test.rb
@@ -7,6 +7,11 @@
require "stringio"
require "fileutils"
+begin
+ require "ruby-debug"
+rescue LoadError
+end
+
$:.unshift File.join(File.dirname(__FILE__), "..", "lib")
class Dep
@@ -53,6 +58,14 @@ def with_dependencies(deps)
end
end
+ test "does not conflict with similar names" do
+ with_dependencies "bar\nbar-core 1.0" do
+ do_require
+ assert_equal File.expand_path("vendor/bar/lib"), $:[2]
+ assert_equal File.expand_path("vendor/bar-core-1.0/lib"), $:[1]
+ end
+ end
+
test "honors the version number for the vendor directory" do
with_dependencies "foo 2.0" do
do_require
View
0 ...or/dependencies-0.0.7/test/foobaz-0.3.gem → ...or/dependencies-0.0.9/test/foobaz-0.3.gem
File renamed without changes.
View
17 vendor/monk-glue/lib/monk/glue.rb
@@ -12,8 +12,6 @@ def root_path(*args)
end
require "sinatra/base"
-require "haml"
-require "sass"
Monk = Module.new unless defined? Monk
@@ -28,8 +26,6 @@ class Monk::Glue < Sinatra::Base
set :static, true
set :views, root_path("app", "views")
- use Rack::Session::Cookie
-
configure :development do
require "monk/glue/reloader"
@@ -42,19 +38,6 @@ class Monk::Glue < Sinatra::Base
rescue LoadError
end
end
-
- helpers do
- # TODO Add documentation.
- def haml(template, options = {}, locals = {})
- options[:escape_html] = true unless options.include?(:escape_html)
- super(template, options, locals)
- end
-
- # TODO Add documentation.
- def partial(template, locals = {})
- haml(template, {:layout => false}, locals)
- end
- end
end
require "monk/glue/logger"
View
3 vendor/monk-glue/lib/monk/glue/logger.rb
@@ -1,10 +1,9 @@
require 'logger'
-# TODO Add documentation.
def logger
$logger ||= begin
$logger = ::Logger.new(root_path("log", "#{RACK_ENV}.log"))
- $logger.level = ::Logger.const_get((settings(:log_level) || :warn).to_s.upcase)
+ $logger.level = ::Logger.const_get((monk_settings(:log_level) || :warn).to_s.upcase)
$logger.datetime_format = "%Y-%m-%d %H:%M:%S"
$logger
end
View
2 vendor/monk-glue/lib/monk/glue/reloader.rb
@@ -28,7 +28,7 @@ def reload!
@app_class.reset!
- require @app_class.app_file
+ require File.expand_path(@app_class.app_file)
end
# Returns the timestamp for the most recently modified app file.
View
9 vendor/monk-glue/lib/monk/glue/settings.rb
@@ -1,14 +1,13 @@
require 'yaml'
-# TODO Add documentation.
-def settings(key)
- $settings ||= YAML.load_file(root_path("config", "settings.yml"))[RACK_ENV.to_sym]
+def monk_settings(key)
+ $monk_settings ||= YAML.load_file(root_path("config", "settings.yml"))[RACK_ENV.to_sym]
- unless $settings.include?(key)
+ unless $monk_settings.include?(key)
message = "No setting defined for #{key.inspect}."
defined?(logger) ? logger.warn(message) : $stderr.puts(message)
end
- $settings[key]
+ $monk_settings[key]
end
View
0 vendor/mustache-0.3.0/LICENSE → vendor/mustache-0.11.2/LICENSE
File renamed without changes.
View
267 vendor/mustache-0.3.0/README.md → vendor/mustache-0.11.2/README.md
@@ -7,6 +7,9 @@ framework-agnostic way to render logic-free views.
As ctemplates says, "It emphasizes separating logic from presentation:
it is impossible to embed application logic in this template language."
+For a list of implementations (other than Ruby) and tips, see
+<http://mustache.github.com/>.
+
Overview
--------
@@ -72,9 +75,9 @@ reference others, some return values, some return only booleans.
Now let's write the template:
Hello {{name}}
- You have just won ${{value}}!
+ You have just won {{value}} dollars!
{{#in_ca}}
- Well, ${{taxed_value}}, after taxes.
+ Well, {{taxed_value}} dollars, after taxes.
{{/in_ca}}
This template references our view methods. To bring it all together,
@@ -85,127 +88,31 @@ here's the code to render actual HTML;
Which returns the following:
Hello Chris
- You have just won $10000!
- Well, $6000.0, after taxes.
+ You have just won 10000 dollars!
+ Well, 6000.0 dollars, after taxes.
Simple.
Tag Types
---------
-Tags are indicated by the double mustaches. `{{name}}` is a tag. Let's
-talk about the different types of tags.
-
-### Variables
-
-The most basic tag is the variable. A `{{name}}` tag in a basic
-template will try to call the `name` method on your view. If there is
-no `name` method, an exception will be raised.
-
-All variables are HTML escaped by default. If you want, for some
-reason, to return unescaped HTML you can use the triple mustache:
-`{{{name}}}`.
-
-### Boolean Sections
-
-A section begins with a pound and ends with a slash. That is,
-`{{#person}}` begins a "person" section while `{{/person}}` ends it.
-
-If the `person` method exists and calling it returns false, the HTML
-between the pound and slash will not be displayed.
-
-If the `person` method exists and calling it returns true, the HTML
-between the pound and slash will be rendered and displayed.
-
-### Enumerable Sections
-
-Enumerable sections are syntactically identical to boolean sections in
-that they begin with a pound and end with a slash. The difference,
-however, is in the view: if the method called returns an enumerable,
-the section is repeated as the enumerable is iterated over.
-
-Each item in the enumerable is expected to be a hash which will then
-become the context of the corresponding iteration. In this way we can
-construct loops.
+For a language-agnostic overview of Mustache's template syntax, see
+the `mustache(5)` manpage or
+<http://mustache.github.com/mustache.5.html>.
-For example, imagine this template:
- {{#repo}}
- <b>{{name}}</b>
- {{/repo}}
-
-And this view code:
-
- def repo
- Repository.all.map { |r| { :name => r.to_s } }
- end
-
-When rendered, our view will contain a list of all repository names in
-the database.
-
-As a convenience, if a section returns a hash (as opposed to an array
-or a boolean) it will be treated as a single item array.
-
-With the above template, we could use this Ruby code for a single
-iteration:
-
- def repo
- { :name => Repository.first.to_s }
- end
-
-This would be treated by Mustache as functionally equivalent to the
-following:
-
- def repo
- [ { :name => Repository.first.to_s } ]
- end
-
-
-### Comments
-
-Comments begin with a bang and are ignored. The following template:
-
- <h1>Today{{! ignore me }}.</h1>
-
-Will render as follows:
-
- <h1>Today.</h1>
-
-### Partials
-
-Partials begin with a less than sign, like `{{< box}}`.
-
-If a partial's view is loaded, we use that to render the HTML. If
-nothing is loaded we render the template directly using our current context.
-
-In this way partials can reference variables or sections the calling
-view defines.
-
-
-### Set Delimiter
-
-Set Delimiter tags start with an equal sign and change the tag
-delimiters from {{ and }} to custom strings.
-
-Consider the following contrived example:
-
- * {{ default_tags }}
- {{=<% %>=}}
- * <% erb_style_tags %>
- <%={{ }}=%>
- * {{ default_tags_again }}
-
-Here we have a list with three items. The first item uses the default
-tag style, the second uses erb style as defined by the Set Delimiter
-tag, and the third returns to the default style after yet another Set
-Delimiter declaration.
+Escaping
+--------
-According to [ctemplates][3], this "is useful for languages like TeX, where
-double-braces may occur in the text and are awkward to use for
-markup."
+Mustache does escape all values when using the standard double
+Mustache syntax. Characters which will be escaped: `& \ " < >`. To
+disable escaping, simply use tripple mustaches like
+`{{{unescaped_variable}}}`.
-Custom delimiters may not contain whitespace or the equals sign.
+Example: Using `{{variable}}` inside a template for `5 > 2` will
+result in `5 &gt; 2`, where as the usage of `{{{variable}}}` will
+result in `5 > 2`.
Dict-Style Views
@@ -215,10 +122,10 @@ ctemplate and friends want you to hand a dictionary to the template
processor. Mustache supports a similar concept. Feel free to mix the
class-based and this more procedural style at your leisure.
-Given this template (winner.html):
+Given this template (winner.mustache):
Hello {{name}}
- You have just won ${{value}}!
+ You have just won {{value}} bucks!
We can fill in the values at will:
@@ -230,14 +137,14 @@ We can fill in the values at will:
Which returns:
Hello George
- You have just won $100!
+ You have just won 100 bucks!
We can re-use the same object, too:
view[:name] = 'Tony'
view.render
Hello Tony
- You have just won $100!
+ You have just won 100 bucks!
Templates
@@ -247,7 +154,7 @@ A word on templates. By default, a view will try to find its template
on disk by searching for an HTML file in the current directory that
follows the classic Ruby naming convention.
- TemplatePartial => ./template_partial.html
+ TemplatePartial => ./template_partial.mustache
You can set the search path using `Mustache.template_path`. It can be set on a
class by class basis:
@@ -257,13 +164,13 @@ class by class basis:
... etc ...
end
-Now `Simple` will look for `simple.html` in the directory it resides
+Now `Simple` will look for `simple.mustache` in the directory it resides
in, no matter the cwd.
If you want to just change what template is used you can set
`Mustache.template_file` directly:
- Simple.template_file = './blah.html'
+ Simple.template_file = './blah.mustache'
Mustache also allows you to define the extension it'll use.
@@ -283,6 +190,15 @@ Or set a different template for a single instance:
Whatever works.
+Views
+-----
+
+Mustache supports a bit of magic when it comes to views. If you're
+authoring a plugin or extension for a web framework (Sinatra, Rails,
+etc), check out the `view_namespace` and `view_path` settings on the
+`Mustache` class. They will surely provide needed assistance.
+
+
Helpers
-------
@@ -357,23 +273,79 @@ Sinatra
Mustache ships with Sinatra integration. Please see
`lib/mustache/sinatra.rb` or
-<http://defunkt.github.com/mustache/classes/Mustache/Sinatra.html> for
-complete documentation.
+<http://github.com/defunkt/mustache/blob/master/lib/mustache/sinatra.rb>
+for complete documentation.
An example Sinatra application is also provided:
<http://github.com/defunkt/mustache-sinatra-example>
+If you are upgrading to Sinatra 1.0 and Mustache 0.9.0+ from Mustache
+0.7.0 or lower, the settings have changed. But not that much.
-Installation
+See [this diff](http://gist.github.com/345490) for what you need to
+do. Basically, things are named properly now and all should be
+contained in a hash set using `set :mustache, hash`.
+
+
+[Rack::Bug][4]
+--------------
+
+Mustache also ships with a `Rack::Bug` panel. In your `config.ru` add
+the following code:
+
+ require 'rack/bug/panels/mustache_panel'
+ use Rack::Bug::MustachePanel
+
+Using Rails? Add this to your initializer or environment file:
+
+ require 'rack/bug/panels/mustache_panel'
+ config.middleware.use "Rack::Bug::MustachePanel"
+
+[![Rack::Bug](http://img.skitch.com/20091027-xyf4h1yxnefpp7usyddrcmc7dn.png)][5]
+
+
+Vim
+---
+
+Thanks to [Juvenn Woo](http://github.com/juvenn) for mustache.vim. It
+is included under the contrib/ directory.
+
+See <http://gist.github.com/323622> for installation instructions.
+
+
+Emacs
+-----
+
+mustache-mode.el is included under the contrib/ directory for any
+Emacs users. Based on Google's tpl-mode for ctemplates, it adds
+support for Mustache's more lenient tag values and includes a few
+commands for your editing pleasure.
+
+See <http://gist.github.com/323619> for installation instructions.
+
+
+TextMate
+--------
+
+[Mustache.tmbundle](http://github.com/defunkt/Mustache.tmbundle)
+
+See <http://gist.github.com/323624> for installation instructions.
+
+
+Command Line
------------
-### [Gemcutter](http://gemcutter.org/)
+See `mustache(1)` man page or
+<http://mustache.github.com/mustache.1.html>
+for command line docs.
- $ gem install mustache
-### [Rip](http://hellorip.com)
+Installation
+------------
- $ rip install git://github.com/defunkt/mustache.git
+### [RubyGems](http://rubygems.org/)
+
+ $ gem install mustache
Acknowledgements
@@ -382,19 +354,52 @@ Acknowledgements
Thanks to [Tom Preston-Werner](http://github.com/mojombo) for showing
me ctemplate and [Leah Culver](http://github.com/leah) for the name "Mustache."
+Special thanks to [Magnus Holm](http://judofyr.net/) for all his
+awesome work on Mustache's parser.
+
+
+Contributing
+------------
+
+Once you've made your great commits:
+
+1. [Fork][fk] Mustache
+2. Create a topic branch - `git checkout -b my_branch`
+3. Push to your branch - `git push origin my_branch`
+4. Create an [Issue][is] with a link to your branch
+5. That's it!
+
+You might want to checkout Resque's [Contributing][cb] wiki page for information
+on coding standards, new features, etc.
+
+
+Mailing List
+------------
+
+To join the list simply send an email to <mustache@librelist.com>. This
+will subscribe you and send you information about your subscription,
+including unsubscribe information.
+
+The archive can be found at <http://librelist.com/browser/>.
+
Meta
----
* Code: `git clone git://github.com/defunkt/mustache.git`
-* Home: <http://github.com/defunkt/mustache>
-* Docs: <http://defunkt.github.com/mustache>
+* Home: <http://mustache.github.com>
* Bugs: <http://github.com/defunkt/mustache/issues>
-* List: <http://groups.google.com/group/mustache-rb>
+* List: <mustache@librelist.com>
* Test: <http://runcoderun.com/defunkt/mustache>
-* Gems: <http://gemcutter.org/gems/mustache>
-* Boss: Chris Wanstrath :: <http://github.com/defunkt>
+* Gems: <http://rubygems.org/gems/mustache>
+
+You can also find us in `#{` on irc.freenode.net.
[1]: http://code.google.com/p/google-ctemplate/
[2]: http://www.ivan.fomichev.name/2008/05/erlang-template-engine-prototype.html
[3]: http://google-ctemplate.googlecode.com/svn/trunk/doc/howto.html
+[4]: http://github.com/brynary/rack-bug/
+[5]: http://img.skitch.com/20091027-n8pxwwx8r61tc318a15q1n6m14.png
+[cb]: http://wiki.github.com/defunkt/resque/contributing
+[fk]: http://help.github.com/forking/
+[is]: http://github.com/defunkt/mustache/issues
View
103 vendor/mustache-0.11.2/Rakefile
@@ -0,0 +1,103 @@
+require 'rake/testtask'
+require 'rake/rdoctask'
+
+#
+# Helpers
+#
+
+def command?(command)
+ system("type #{command} > /dev/null")
+end
+
+
+#
+# Tests
+#
+
+task :default => :test
+
+if command? :turn
+ desc "Run tests"
+ task :test do
+ suffix = "-n #{ENV['TEST']}" if ENV['TEST']
+ sh "turn test/*.rb #{suffix}"
+ end
+else
+ Rake::TestTask.new do |t|
+ t.libs << 'lib'
+ t.pattern = 'test/**/*_test.rb'
+ t.verbose = false
+ end
+end
+
+if command? :kicker
+ desc "Launch Kicker (like autotest)"
+ task :kicker do
+ puts "Kicking... (ctrl+c to cancel)"
+ exec "kicker -e rake test lib examples"
+ end
+end
+
+
+#
+# Ron
+#
+
+if command? :ronn
+ desc "Show the manual"
+ task :man => "man:build" do
+ exec "man man/mustache.1"
+ end
+
+ desc "Build the manual"
+ task "man:build" do
+ sh "ronn -br5 --organization=DEFUNKT --manual='Mustache Manual' man/*.ron"
+ end
+end
+
+
+#
+# Gems
+#
+
+desc "Push a new version to Gemcutter and publish docs."
+task :publish do
+ require File.dirname(__FILE__) + '/lib/mustache/version'
+
+ system "git tag v#{Mustache::Version}"
+ sh "gem build mustache.gemspec"
+ sh "gem push mustache-#{Mustache::Version}.gem"
+ sh "git push origin master --tags"
+ sh "git clean -fd"
+ exec "rake pages"
+end
+
+#
+# Documentation
+#
+
+begin
+ require 'sdoc_helpers'
+rescue LoadError
+ warn "sdoc support not enabled. Please gem install sdoc-helpers."
+end
+
+desc "Publish to GitHub Pages"
+task :pages => [ "man:build" ] do
+ Dir['man/*.html'].each do |f|
+ cp f, File.basename(f).sub('.html', '.newhtml')
+ end
+
+ `git commit -am 'generated manual'`
+ `git checkout site`
+
+ Dir['*.newhtml'].each do |f|
+ mv f, f.sub('.newhtml', '.html')
+ end
+
+ `git add .`
+ `git commit -m updated`
+ `git push site site:master`
+ `git checkout master`
+ puts :done
+end
View
90 vendor/mustache-0.11.2/bin/mustache
@@ -0,0 +1,90 @@
+#!/usr/bin/env ruby
+
+require 'yaml'
+require 'optparse'
+
+require 'mustache'
+require 'mustache/version'
+
+class Mustache
+ class CLI
+ # Return a structure describing the options.
+ def self.parse_options(args)
+ opts = OptionParser.new do |opts|
+ opts.banner = "Usage: mustache [-c] [-t] FILE ..."
+
+ opts.separator " "
+
+ opts.separator "Examples:"
+ opts.separator " $ mustache data.yml template.mustache"
+ opts.separator " $ cat data.yml | mustache - template.mustache"
+ opts.separator " $ mustache -c template.mustache"
+
+ opts.separator " "
+
+ opts.separator " See mustache(1) or " +
+ "http://mustache.github.com/mustache.1.html"
+ opts.separator " for more details."
+
+ opts.separator " "
+ opts.separator "Options:"
+
+ opts.on("-c", "--compile FILE",
+ "Print the compiled Ruby for a given template.") do |file|
+ puts Mustache::Template.new(File.read(file)).compile
+ exit
+ end
+
+ opts.on("-t", "--tokens FILE",
+ "Print the tokenized form of a given template.") do |file|
+ require 'pp'
+ pp Mustache::Template.new(File.read(file)).tokens
+ exit
+ end
+
+ opts.separator "Common Options:"
+
+ opts.on("-v", "--version", "Print the version") do |v|
+ puts "Mustache v#{Mustache::Version}"
+ exit
+ end
+
+ opts.on_tail("-h", "--help", "Show this message") do
+ puts opts
+ exit
+ end
+ end
+
+ opts.separator ""
+
+ opts.parse!(args)
+ end
+
+ # Does the dirty work of reading files from STDIN and the command
+ # line then processing them. The meat of this script, if you will.
+ def self.process_files(input_stream)
+ doc = input_stream.read
+
+ if doc =~ /^(\s*---(.+)---\s*)/m
+ yaml = $2.strip
+ template = doc.sub($1, '')
+
+ YAML.each_document(yaml) do |data|
+ puts Mustache.render(template, data)
+ end
+ else
+ puts Mustache.render(doc)
+ end
+ end
+ end
+end
+
+# Help is the default.
+ARGV << '-h' if ARGV.empty? && $stdin.tty?
+
+# Process options
+Mustache::CLI.parse_options(ARGV) if $stdin.tty?
+
+# Still here - process ARGF
+Mustache::CLI.process_files(ARGF)
+
View
169 vendor/mustache-0.3.0/lib/mustache.rb → vendor/mustache-0.11.2/lib/mustache.rb
@@ -7,7 +7,7 @@
# The typical Mustache workflow is as follows:
#
# * Create a Mustache subclass: class Stats < Mustache
-# * Create a template: stats.html
+# * Create a template: stats.mustache
# * Instantiate an instance: view = Stats.new
# * Render that instance: view.render
#
@@ -30,12 +30,12 @@
# looking for a template. By default it is "."
# Setting it to /usr/local/templates, for example, means (given all
# other settings are default) a Mustache subclass `Stats` will try to
-# load /usr/local/templates/stats.html
+# load /usr/local/templates/stats.mustache
#
# * template_extension
#
# The `template_extension` is the extension Mustache uses when looking
-# for template files. By default it is "html"
+# for template files. By default it is "mustache"
#
# * template_file
#
@@ -56,6 +56,19 @@
# view.template = "Hi, {{person}}!"
# view[:person] = 'Mom'
# view.render # => Hi, mom!
+#
+# * view_namespace
+#
+# To make life easy on those developing Mustache plugins for web frameworks or
+# other libraries, Mustache will attempt to load view classes (i.e. Mustache
+# subclasses) using the `view_class` class method. The `view_namespace` tells
+# Mustache under which constant view classes live. By default it is `Object`.
+#
+# * view_path
+#
+# Similar to `template_path`, the `view_path` option tells Mustache where to look
+# for files containing view classes when using the `view_class` method.
+#
class Mustache
# Helper method for quickly instantiating and rendering a view.
def self.render(*args)
@@ -72,10 +85,38 @@ def self.to_text(*args)
render(*args)
end
+ # Given a file name and an optional context, attempts to load and
+ # render the file as a template.
+ def self.render_file(name, context = {})
+ render(partial(name), context)
+ end
+
+ # Given a file name and an optional context, attempts to load and
+ # render the file as a template.
+ def render_file(name, context = {})
+ self.class.render_file(name, context)
+ end
+
+ # Given a name, attempts to read a file and return the contents as a
+ # string. The file is not rendered, so it might contain
+ # {{mustaches}}.
+ #
+ # Call `render` if you need to process it.
+ def self.partial(name)
+ File.read("#{template_path}/#{name}.#{template_extension}")
+ end
+
+ # Override this in your subclass if you want to do fun things like
+ # reading templates from a database. It will be rendered by the
+ # context, so all you need to do is return a string.
+ def partial(name)
+ self.class.partial(name)
+ end
+
# The template path informs your Mustache subclass where to look for its
# corresponding template. By default it's the current directory (".")
def self.template_path
- @template_path ||= '.'
+ @template_path ||= inheritable_config_for :template_path, '.'
end
def self.template_path=(path)
@@ -93,20 +134,31 @@ def self.path=(path)
self.template_path = path
end
- # A Mustache template's default extension is 'html'
+ # A Mustache template's default extension is 'mustache'
def self.template_extension
- @template_extension ||= 'html'
+ @template_extension ||= inheritable_config_for :template_extension, 'mustache'
end
def self.template_extension=(template_extension)
@template_extension = template_extension
@template = nil
end
+ # The template name is the Mustache template file without any
+ # extension or other information. Defaults to `class_name`.
+ def self.template_name
+ @template_name || underscore
+ end
+
+ def self.template_name=(template_name)
+ @template_name = template_name
+ @template = nil
+ end
+
# The template file is the absolute path of the file Mustache will
- # use as its template. By default it's ./class_name.html
+ # use as its template. By default it's ./class_name.mustache
def self.template_file
- @template_file || "#{path}/#{underscore}.#{template_extension}"
+ @template_file || "#{path}/#{template_name}.#{template_extension}"
end
def self.template_file=(template_file)
@@ -126,6 +178,77 @@ def self.template=(template)
@template = templateify(template)
end
+ # The constant under which Mustache will look for views. By default it's
+ # `Object`, but it might be nice to set it to something like `Hurl::Views` if
+ # your app's main namespace is `Hurl`.
+ def self.view_namespace
+ @view_namespace ||= inheritable_config_for(:view_namespace, Object)
+ end
+
+ def self.view_namespace=(namespace)
+ @view_namespace = namespace
+ end
+
+ # Mustache searches the view path for .rb files to require when asked to find a
+ # view class. Defaults to "."
+ def self.view_path
+ @view_path ||= inheritable_config_for(:view_path, '.')
+ end
+
+ def self.view_path=(path)
+ @view_path = path
+ end
+
+ # When given a symbol or string representing a class, will try to produce an
+ # appropriate view class.
+ # e.g.
+ # Mustache.view_namespace = Hurl::Views
+ # Mustache.view_class(:Partial) # => Hurl::Views::Partial
+ def self.view_class(name)
+ if name != classify(name.to_s)
+ name = classify(name.to_s)
+ end
+
+ # Emptiness begets emptiness.
+ if name.to_s == ''
+ return Mustache
+ end
+
+ file_name = underscore(name)
+ namespace = view_namespace
+
+ if namespace.const_defined?(:Views) && namespace::Views.const_defined?(name)
+ namespace::Views.const_get(name)
+ elsif namespace.const_defined?(name)
+ namespace.const_get(name)
+ elsif File.exists?(file = "#{view_path}/#{file_name}.rb")
+ require "#{file}".chomp('.rb')
+ if namespace.const_defined?(:Views)
+ namespace::Views.const_get(name)
+ else
+ namespace.const_get(name)
+ end
+ else
+ Mustache
+ end
+ rescue NameError
+ Mustache
+ end
+
+ # Should an exception be raised when we cannot find a corresponding method
+ # or key in the current context? By default this is false to emulate ctemplate's
+ # behavior, but it may be useful to enable when debugging or developing.
+ #
+ # If set to true and there is a context miss, `Mustache::ContextMiss` will
+ # be raised.
+ def self.raise_on_context_miss?
+ @raise_on_context_miss
+ end
+
+ def self.raise_on_context_miss=(boolean)
+ @raise_on_context_miss = boolean
+ end
+
# Has this template already been compiled? Compilation is somewhat
# expensive so it may be useful to check this before attempting it.
def self.compiled?
@@ -161,10 +284,21 @@ def self.templateify(obj)
if obj.is_a?(Template)
obj
else
- Template.new(obj.to_s, template_path, template_extension)
+ Template.new(obj.to_s)
end
end
+ # Return the value of the configuration setting on the superclass, or return
+ # the default.
+ #
+ # attr_name - Symbol name of the attribute. It should match the instance variable.
+ # default - Default value to use if the superclass does not respond.
+ #
+ # Returns the inherited or default configuration setting.
+ def self.inheritable_config_for(attr_name, default)
+ superclass.respond_to?(attr_name) ? superclass.send(attr_name) : default
+ end
+
def templateify(obj)
self.class.templateify(obj)
end
@@ -178,6 +312,12 @@ def template=(template)
@template = templateify(template)
end
+ # Instance level version of `Mustache.raise_on_context_miss?`
+ def raise_on_context_miss?
+ self.class.raise_on_context_miss? || @raise_on_context_miss
+ end
+ attr_writer :raise_on_context_miss
+
# A helper method which gives access to the context at a given time.
# Kind of a hack for now, but useful when you're in an iterating section
# and want access to the hash currently being iterated over.
@@ -202,7 +342,16 @@ def []=(key, value)
# Parses our fancy pants template file and returns normal file with
# all special {{tags}} and {{#sections}}replaced{{/sections}}.
def render(data = template, ctx = {})
- templateify(data).render(context.update(ctx))
+ tpl = templateify(data)
+
+ return tpl.render(context) if ctx == {}
+
+ begin
+ context.push(ctx)
+ tpl.render(context)
+ ensure
+ context.pop
+ end
end
alias_method :to_html, :render
alias_method :to_text, :render
View
108 vendor/mustache-0.11.2/lib/mustache/context.rb
@@ -0,0 +1,108 @@
+class Mustache
+ # A ContextMiss is raised whenever a tag's target can not be found
+ # in the current context if `Mustache#raise_on_context_miss?` is
+ # set to true.
+ #
+ # For example, if your View class does not respond to `music` but
+ # your template contains a `{{music}}` tag this exception will be raised.
+ #
+ # By default it is not raised. See Mustache.raise_on_context_miss.
+ class ContextMiss < RuntimeError; end
+
+ # A Context represents the context which a Mustache template is
+ # executed within. All Mustache tags reference keys in the Context.
+ class Context
+ # Expect to be passed an instance of `Mustache`.
+ def initialize(mustache)
+ @stack = [mustache]
+ end
+
+ # A {{>partial}} tag translates into a call to the context's
+ # `partial` method, which would be this sucker right here.
+ #
+ # If the Mustache view handling the rendering (e.g. the view
+ # representing your profile page or some other template) responds
+ # to `partial`, we call it and render the result.
+ def partial(name)
+ # Look for the first Mustache in the stack.
+ mustache = mustache_in_stack
+
+ # Call its `partial` method and render the result.
+ mustache.render(mustache.partial(name), self)
+ end
+
+ # Find the first Mustache in the stack. If we're being rendered
+ # inside a Mustache object as a context, we'll use that one.
+ def mustache_in_stack
+ @stack.detect { |frame| frame.is_a?(Mustache) }
+ end
+
+ # Adds a new object to the context's internal stack.
+ #
+ # Returns the Context.
+ def push(new)
+ @stack.unshift(new)
+ self
+ end
+ alias_method :update, :push
+
+ # Removes the most recently added object from the context's
+ # internal stack.
+ #
+ # Returns the Context.
+ def pop
+ @stack.shift
+ self
+ end
+
+ # Can be used to add a value to the context in a hash-like way.
+ #
+ # context[:name] = "Chris"
+ def []=(name, value)
+ push(name => value)
+ end
+
+ # Alias for `fetch`.
+ def [](name)
+ fetch(name, nil)
+ end
+
+ # Do we know about a particular key? In other words, will calling
+ # `context[key]` give us a result that was set. Basically.
+ def has_key?(key)
+ !!fetch(key)
+ rescue ContextMiss
+ false
+ end
+
+ # Similar to Hash#fetch, finds a value by `name` in the context's
+ # stack. You may specify the default return value by passing a
+ # second parameter.
+ #
+ # If no second parameter is passed (or raise_on_context_miss is
+ # set to true), will raise a ContextMiss exception on miss.
+ def fetch(name, default = :__raise)
+ @stack.each do |frame|
+ # Prevent infinite recursion.
+ next if frame == self
+
+ # Is this frame a hash?
+ hash = frame.respond_to?(:has_key?)
+
+ if hash && frame.has_key?(name)
+ return frame[name]
+ elsif hash && frame.has_key?(name.to_s)
+ return frame[name.to_s]
+ elsif !hash && frame.respond_to?(name)
+ return frame.__send__(name)
+ end
+ end
+
+ if default == :__raise || mustache_in_stack.raise_on_context_miss?
+ raise ContextMiss.new("Can't find #{name} in #{@stack.inspect}")
+ else
+ default
+ end
+ end
+ end
+end
View
158 vendor/mustache-0.11.2/lib/mustache/generator.rb
@@ -0,0 +1,158 @@
+class Mustache
+ # The Generator is in charge of taking an array of Mustache tokens,
+ # usually assembled by the Parser, and generating an interpolatable
+ # Ruby string. This string is considered the "compiled" template
+ # because at that point we're relying on Ruby to do the parsing and
+ # run our code.
+ #
+ # For example, let's take this template:
+ #
+ # Hi {{thing}}!
+ #
+ # If we run this through the Parser we'll get these tokens:
+ #
+ # [:multi,
+ # [:static, "Hi "],
+ # [:mustache, :etag, "thing"],
+ # [:static, "!\n"]]
+ #
+ # Now let's hand that to the Generator:
+ #
+ # >> puts Mustache::Generator.new.compile(tokens)
+ # "Hi #{CGI.escapeHTML(ctx[:thing].to_s)}!\n"
+ #
+ # You can see the generated Ruby string for any template with the
+ # mustache(1) command line tool:
+ #
+ # $ mustache --compile test.mustache
+ # "Hi #{CGI.escapeHTML(ctx[:thing].to_s)}!\n"
+ class Generator
+ # Options are unused for now but may become useful in the future.
+ def initialize(options = {})
+ @options = options
+ end
+
+ # Given an array of tokens, returns an interpolatable Ruby string.
+ def compile(exp)
+ "\"#{compile!(exp)}\""
+ end
+
+ # Given an array of tokens, converts them into Ruby code. In
+ # particular there are three types of expressions we are concerned
+ # with:
+ #
+ # :multi
+ # Mixed bag of :static, :mustache, and whatever.
+ #
+ # :static
+ # Normal HTML, the stuff outside of {{mustaches}}.
+ #
+ # :mustache
+ # Any Mustache tag, from sections to partials.
+ #
+ # To give you an idea of what you'll be dealing with take this
+ # template:
+ #
+ # Hello {{name}}
+ # You have just won ${{value}}!
+ # {{#in_ca}}
+ # Well, ${{taxed_value}}, after taxes.
+ # {{/in_ca}}
+ #
+ # If we run this through the Parser, we'll get back this array of
+ # tokens:
+ #
+ # [:multi,
+ # [:static, "Hello "],
+ # [:mustache, :etag, "name"],
+ # [:static, "\nYou have just won $"],
+ # [:mustache, :etag, "value"],
+ # [:static, "!\n"],
+ # [:mustache,
+ # :section,
+ # "in_ca",
+ # [:multi,
+ # [:static, "Well, $"],
+ # [:mustache, :etag, "taxed_value"],
+ # [:static, ", after taxes.\n"]]]]
+ def compile!(exp)
+ case exp.first
+ when :multi
+ exp[1..-1].map { |e| compile!(e) }.join
+ when :static
+ str(exp[1])
+ when :mustache
+ send("on_#{exp[1]}", *exp[2..-1])
+ else
+ raise "Unhandled exp: #{exp.first}"
+ end
+ end
+
+ # Callback fired when the compiler finds a section token. We're
+ # passed the section name and the array of tokens.
+ def on_section(name, content)
+ # Convert the tokenized content of this section into a Ruby
+ # string we can use.
+ code = compile(content)
+
+ # Compile the Ruby for this section now that we know what's
+ # inside the section.
+ ev(<<-compiled)
+ if v = ctx[#{name.to_sym.inspect}]
+ if v == true
+ #{code}
+ elsif v.is_a?(Proc)
+ v.call(#{code})
+ else
+ v = [v] unless v.is_a?(Array) # shortcut when passed non-array
+ v.map { |h| ctx.push(h); r = #{code}; ctx.pop; r }.join
+ end
+ end
+ compiled
+ end
+
+ # Fired when we find an inverted section. Just like `on_section`,
+ # we're passed the inverted section name and the array of tokens.
+ def on_inverted_section(name, content)
+ # Convert the tokenized content of this section into a Ruby
+ # string we can use.
+ code = compile(content)
+
+ # Compile the Ruby for this inverted section now that we know
+ # what's inside.
+ ev(<<-compiled)
+ v = ctx[#{name.to_sym.inspect}]
+ if v.nil? || v == false || v.respond_to?(:empty?) && v.empty?
+ #{code}
+ end
+ compiled
+ end
+
+ # Fired when the compiler finds a partial. We want to return code
+ # which calls a partial at runtime instead of expanding and
+ # including the partial's body to allow for recursive partials.
+ def on_partial(name)
+ ev("ctx.partial(#{name.to_sym.inspect})")
+ end
+
+ # An unescaped tag.
+ def on_utag(name)
+ ev("ctx[#{name.to_sym.inspect}]")
+ end
+
+ # An escaped tag.
+ def on_etag(name)
+ ev("CGI.escapeHTML(ctx[#{name.to_sym.inspect}].to_s)")
+ end
+
+ # An interpolation-friendly version of a string, for use within a
+ # Ruby string.
+ def ev(s)
+ "#\{#{s}}"
+ end
+
+ def str(s)
+ s.inspect[1..-2]
+ end
+ end
+end
View
230 vendor/mustache-0.11.2/lib/mustache/parser.rb
@@ -0,0 +1,230 @@
+require 'strscan'
+
+class Mustache
+ # The Parser is responsible for taking a string template and
+ # converting it into an array of tokens and, really, expressions. It
+ # raises SyntaxError if there is anything it doesn't understand and
+ # knows which sigil corresponds to which tag type.
+ #
+ # For example, given this template:
+ #
+ # Hi {{thing}}!
+ #
+ # Run through the Parser we'll get these tokens:
+ #
+ # [:multi,
+ # [:static, "Hi "],
+ # [:mustache, :etag, "thing"],
+ # [:static, "!\n"]]
+ #
+ # You can see the array of tokens for any template with the
+ # mustache(1) command line tool:
+ #
+ # $ mustache --tokens test.mustache
+ # [:multi, [:static, "Hi "], [:mustache, :etag, "thing"], [:static, "!\n"]]
+ class Parser
+ # A SyntaxError is raised when the Parser comes across unclosed
+ # tags, sections, illegal content in tags, or anything of that
+ # sort.
+ class SyntaxError < StandardError
+ def initialize(message, position)
+ @message = message
+ @lineno, @column, @line = position
+ @stripped_line = @line.strip
+ @stripped_column = @column - (@line.size - @line.lstrip.size)
+ end
+
+ def to_s
+ <<-EOF
+#{@message}
+ Line #{@lineno}
+ #{@stripped_line}
+ #{' ' * @stripped_column}^
+EOF
+ end
+ end
+
+ # After these types of tags, all whitespace will be skipped.
+ SKIP_WHITESPACE = [ '#', '^', '/' ]
+
+ # The content allowed in a tag name.
+ ALLOWED_CONTENT = /(\w|[?!\/-])*/
+
+ # These types of tags allow any content,
+ # the rest only allow ALLOWED_CONTENT.
+ ANY_CONTENT = [ '!', '=' ]
+
+ attr_reader :scanner, :result
+ attr_writer :otag, :ctag
+
+ # Accepts an options hash which does nothing but may be used in
+ # the future.
+ def initialize(options = {})
+ @options = {}
+ end
+
+ # The opening tag delimiter. This may be changed at runtime.
+ def otag
+ @otag ||= '{{'
+ end
+
+ # The closing tag delimiter. This too may be changed at runtime.
+ def ctag
+ @ctag ||= '}}'
+ end
+
+ # Given a string template, returns an array of tokens.
+ def compile(template)
+ if template.respond_to?(:encoding)
+ @encoding = template.encoding
+ template = template.dup.force_encoding("BINARY")
+ else
+ @encoding = nil
+ end
+
+ # Keeps information about opened sections.
+ @sections = []
+ @result = [:multi]
+ @scanner = StringScanner.new(template)
+
+ # Scan until the end of the template.
+ until @scanner.eos?
+ scan_tags || scan_text
+ end
+
+ if !@sections.empty?
+ # We have parsed the whole file, but there's still opened sections.
+ type, pos, result = @sections.pop
+ error "Unclosed section #{type.inspect}", pos
+ end
+
+ @result
+ end
+
+ # Find {{mustaches}} and add them to the @result array.
+ def scan_tags
+ # Scan until we hit an opening delimiter.
+ return unless @scanner.scan(regexp(otag))
+
+ # Since {{= rewrites ctag, we store the ctag which should be used
+ # when parsing this specific tag.
+ current_ctag = self.ctag
+ type = @scanner.scan(/#|\^|\/|=|!|<|>|&|\{/)
+ @scanner.skip(/\s*/)
+
+ # ANY_CONTENT tags allow any character inside of them, while
+ # other tags (such as variables) are more strict.
+ if ANY_CONTENT.include?(type)
+ r = /\s*#{regexp(type)}?#{regexp(current_ctag)}/
+ content = scan_until_exclusive(r)
+ else
+ content = @scanner.scan(ALLOWED_CONTENT)
+ end
+
+ # We found {{ but we can't figure out what's going on inside.
+ error "Illegal content in tag" if content.empty?
+
+ # Based on the sigil, do what needs to be done.
+ case type
+ when '#'
+ block = [:multi]
+ @result << [:mustache, :section, content, block]
+ @sections << [content, position, @result]
+ @result = block
+ when '^'
+ block = [:multi]
+ @result << [:mustache, :inverted_section, content, block]
+ @sections << [content, position, @result]
+ @result = block
+ when '/'
+ section, pos, result = @sections.pop
+ @result = result
+
+ if section.nil?
+ error "Closing unopened #{content.inspect}"
+ elsif section != content
+ error "Unclosed section #{section.inspect}", pos
+ end
+ when '!'
+ # ignore comments
+ when '='
+ self.otag, self.ctag = content.split(' ', 2)
+ when '>', '<'
+ @result << [:mustache, :partial, content]
+ when '{', '&'
+ # The closing } in unescaped tags is just a hack for
+ # aesthetics.
+ type = "}" if type == "{"
+ @result << [:mustache, :utag, content]
+ else
+ @result << [:mustache, :etag, content]
+ end
+
+ # Skip whitespace and any balancing sigils after the content
+ # inside this tag.
+ @scanner.skip(/\s+/)
+ @scanner.skip(regexp(type)) if type
+
+ # Try to find the closing tag.
+ unless close = @scanner.scan(regexp(current_ctag))
+ error "Unclosed tag"
+ end
+
+ # Skip whitespace following this tag if we need to.
+ @scanner.skip(/\s+/) if SKIP_WHITESPACE.include?(type)
+ end
+
+ # Try to find static text, e.g. raw HTML with no {{mustaches}}.
+ def scan_text
+ text = scan_until_exclusive(regexp(otag))
+
+ if text.nil?
+ # Couldn't find any otag, which means the rest is just static text.
+ text = @scanner.rest
+ # Mark as done.
+ @scanner.clear
+ end
+
+ text.force_encoding(@encoding) if @encoding
+
+ @result << [:static, text]
+ end
+
+ # Scans the string until the pattern is matched. Returns the substring
+ # *excluding* the end of the match, advancing the scan pointer to that
+ # location. If there is no match, nil is returned.
+ def scan_until_exclusive(regexp)
+ pos = @scanner.pos
+ if @scanner.scan_until(regexp)
+ @sc