toto_prerelease 0.4.7prerelease

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ title: The Wonderful Wizard of Oz
2
+ date: 17/05/1900
3
+
4
+ _Once upon a time_...
5
+
@@ -0,0 +1,5 @@
1
+ title: the wizard of oz
2
+ date: 12/10/1932
3
+
4
+ Once upon a time...
5
+
@@ -0,0 +1,5 @@
1
+ title: the wizard of oz
2
+ date: 12/10/1932
3
+
4
+ Once upon a time...
5
+
@@ -0,0 +1,5 @@
1
+ title: the wizard of oz
2
+ date: 12/10/1932
3
+
4
+ Once upon a time...
5
+
@@ -0,0 +1,5 @@
1
+ title: the wizard of oz
2
+ date: 12/10/1932
3
+
4
+ Once upon a time...
5
+
data/test/autotest.rb ADDED
@@ -0,0 +1,34 @@
1
+ #
2
+ # Convenience Methods
3
+ #
4
+ def run(cmd)
5
+ print "\n\n"
6
+ puts(cmd)
7
+ system(cmd)
8
+ print "\n\n"
9
+ end
10
+
11
+ def run_all_tests
12
+ # see Rakefile for the definition of the test:all task
13
+ system("rake -s test:all VERBOSE=true")
14
+ end
15
+
16
+ #
17
+ # Watchr Rules
18
+ #
19
+ watch('^test/.*?_test\.rb' ) {|m| run("ruby -rubygems %s" % m[0]) }
20
+ watch('^lib/(.*)\.rb' ) {|m| run("ruby -rubygems test/%s_test.rb" % m[1]) }
21
+ watch('^lib/toto/(.*)\.rb' ) {|m| run("ruby -rubygems test/%s_test.rb" % m[1]) }
22
+ watch('^test/test_helper\.rb') { run_all_tests }
23
+
24
+ #
25
+ # Signal Handling
26
+ #
27
+ # Ctrl-\
28
+ Signal.trap('QUIT') do
29
+ puts " --- Running all tests ---\n\n"
30
+ run_all_tests
31
+ end
32
+
33
+ # Ctrl-C
34
+ Signal.trap('INT') { abort("\n") }
@@ -0,0 +1 @@
1
+ <span id="count"><%= @articles.length %></span>
@@ -0,0 +1,5 @@
1
+ <h1><%= @path %></h1>
2
+ <% for entry in archives %>
3
+ <li class="entry"><%= entry.title %></li>
4
+ <% end %>
5
+
@@ -0,0 +1,4 @@
1
+ <h2><%= title %></h2>
2
+ <span><%= date %></h2>
3
+ <p><%= body %></p>
4
+
@@ -0,0 +1,21 @@
1
+ xml.instruct!
2
+ xml.feed "xmlns" => "http://www.w3.org/2005/Atom" do
3
+ xml.title @config[:title]
4
+ xml.id @config[:url]
5
+ xml.updated articles.first[:date].iso8601 unless articles.empty?
6
+ xml.author { xml.name @config[:author] }
7
+
8
+ articles.each do |article|
9
+ xml.entry do
10
+ xml.title article.title
11
+ xml.link "rel" => "alternate", "href" => article.url
12
+ xml.id article.url
13
+ xml.published article[:date].iso8601
14
+ xml.updated article[:date].iso8601
15
+ xml.author { xml.name @config[:author] }
16
+ xml.summary article.summary, "type" => "html"
17
+ xml.content article.body, "type" => "html"
18
+ end
19
+ end
20
+ end
21
+
@@ -0,0 +1,21 @@
1
+ xml.instruct!
2
+ xml.feed "xmlns" => "http://www.w3.org/2005/Atom" do
3
+ xml.title @config[:title]
4
+ xml.id @config[:url]
5
+ xml.updated articles.first[:date].iso8601 unless articles.empty?
6
+ xml.author { xml.name @config[:author] }
7
+
8
+ articles.each do |article|
9
+ xml.entry do
10
+ xml.title article.title
11
+ xml.link "rel" => "alternate", "href" => article.url
12
+ xml.id article.url
13
+ xml.published article[:date].iso8601
14
+ xml.updated article[:date].iso8601
15
+ xml.author { xml.name @config[:author] }
16
+ xml.summary article.summary, "type" => "html"
17
+ xml.content article.body, "type" => "html"
18
+ end
19
+ end
20
+ end
21
+
@@ -0,0 +1,13 @@
1
+ <ul id="articles">
2
+ <% for article in articles[0...3] %>
3
+ <li><%= article %></li>
4
+ <% end %>
5
+ </ul>
6
+ <div id="archives">
7
+ <%= archives[3...5] %>
8
+ </div>
9
+ <!-- testing env variable passing -->
10
+ <p>env passed: <%= env != nil %><br/></p>
11
+ <!-- testing get/post parameter passing -->
12
+ <p>request method type: <%= env['REQUEST_METHOD'] %><br/></p>
13
+ <p>request name value pair: <%= env['QUERY_STRING'] %><br/></p>
@@ -0,0 +1,4 @@
1
+ <html>
2
+ <%= yield %>
3
+ </html>
4
+
@@ -0,0 +1 @@
1
+ <%= readme %>
@@ -0,0 +1,44 @@
1
+ require 'rubygems'
2
+ require 'hpricot'
3
+ require 'riot'
4
+
5
+ $:.unshift File.dirname(__FILE__)
6
+ $:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
7
+
8
+ require 'toto'
9
+
10
+ module Toto
11
+ class IncludesHTMLMacro < Riot::AssertionMacro
12
+ register :includes_html
13
+
14
+ def evaluate(actual, expected)
15
+ doc = Hpricot.parse(actual)
16
+ expected = expected.to_a.flatten
17
+
18
+ if (doc/expected.first).empty?
19
+ fail("expected #{actual} to contain a <#{expected.first}>")
20
+ elsif !(doc/expected.first).inner_html.match(expected.last)
21
+ fail("expected <#{expected.first}> to contain #{expected.last}")
22
+ else
23
+ pass
24
+ end
25
+ end
26
+ end
27
+
28
+ class IncludesElementsMacro < Riot::AssertionMacro
29
+ register :includes_elements
30
+
31
+ def evaluate(actual, selector, count)
32
+ doc = Hpricot.parse(actual)
33
+ (doc/selector).size == count ? pass : fail("expected #{actual} to contain #{count} #{selector}(s)")
34
+ end
35
+ end
36
+
37
+ class WithinMacro < Riot::AssertionMacro
38
+ register :within
39
+
40
+ def evaluate(actual, expected)
41
+ expected.include?(actual) ? pass : fail("expected #{actual} to be within #{expected}")
42
+ end
43
+ end
44
+ end
data/test/toto_test.rb ADDED
@@ -0,0 +1,286 @@
1
+ require 'test/test_helper'
2
+ require 'date'
3
+
4
+ URL = "http://toto.oz"
5
+ AUTHOR = "toto"
6
+
7
+ context Toto do
8
+ setup do
9
+ @config = Toto::Config.new(:markdown => true, :author => AUTHOR, :url => URL)
10
+ @toto = Rack::MockRequest.new(Toto::Server.new(@config))
11
+ Toto::Paths[:articles] = "test/articles"
12
+ Toto::Paths[:pages] = "test/templates"
13
+ Toto::Paths[:templates] = "test/templates"
14
+ end
15
+
16
+ context "GET /" do
17
+ setup { @toto.get('/') }
18
+
19
+ asserts("returns a 200") { topic.status }.equals 200
20
+ asserts("body is not empty") { not topic.body.empty? }
21
+ asserts("content type is set properly") { topic.content_type }.equals "text/html"
22
+ should("include a couple of article") { topic.body }.includes_elements("#articles li", 3)
23
+ should("include an archive") { topic.body }.includes_elements("#archives li", 2)
24
+
25
+ context "with no articles" do
26
+ setup { Rack::MockRequest.new(Toto::Server.new(@config.merge(:ext => 'oxo'))).get('/') }
27
+
28
+ asserts("body is not empty") { not topic.body.empty? }
29
+ asserts("returns a 200") { topic.status }.equals 200
30
+ end
31
+
32
+ context "with a user-defined to_html" do
33
+ setup do
34
+ @config[:to_html] = lambda do |path, page, binding|
35
+ ERB.new(File.read("#{path}/#{page}.rhtml")).result(binding)
36
+ end
37
+ @toto.get('/')
38
+ end
39
+
40
+ asserts("returns a 200") { topic.status }.equals 200
41
+ asserts("body is not empty") { not topic.body.empty? }
42
+ asserts("content type is set properly") { topic.content_type }.equals "text/html"
43
+ should("include a couple of article") { topic.body }.includes_elements("#articles li", 3)
44
+ should("include an archive") { topic.body }.includes_elements("#archives li", 2)
45
+ asserts("Etag header present") { topic.headers.include? "ETag" }
46
+ asserts("Etag header has a value") { not topic.headers["ETag"].empty? }
47
+ end
48
+ end
49
+
50
+ context "GET /about" do
51
+ setup { @toto.get('/about') }
52
+ asserts("returns a 200") { topic.status }.equals 200
53
+ asserts("body is not empty") { not topic.body.empty? }
54
+ should("have access to @articles") { topic.body }.includes_html("#count" => /5/)
55
+ end
56
+
57
+ context "GET a single article" do
58
+ setup { @toto.get("/1900/05/17/the-wonderful-wizard-of-oz") }
59
+ asserts("returns a 200") { topic.status }.equals 200
60
+ asserts("content type is set properly") { topic.content_type }.equals "text/html"
61
+ should("contain the article") { topic.body }.includes_html("p" => /<em>Once upon a time<\/em>/)
62
+ end
63
+
64
+ context "GET to the archive" do
65
+ context "through a year" do
66
+ setup { @toto.get('/2009') }
67
+ asserts("returns a 200") { topic.status }.equals 200
68
+ should("includes the entries for that year") { topic.body }.includes_elements("li.entry", 3)
69
+ end
70
+
71
+ context "through a year & month" do
72
+ setup { @toto.get('/2009/12') }
73
+ asserts("returns a 200") { topic.status }.equals 200
74
+ should("includes the entries for that month") { topic.body }.includes_elements("li.entry", 2)
75
+ should("includes the year & month") { topic.body }.includes_html("h1" => /2009\/12/)
76
+ end
77
+
78
+ context "through /archive" do
79
+ setup { @toto.get('/archive') }
80
+ end
81
+ end
82
+
83
+ context "GET to an unknown route with a custom error" do
84
+ setup do
85
+ @config[:error] = lambda {|code| "error: #{code}" }
86
+ @toto.get('/unknown')
87
+ end
88
+
89
+ should("returns a 404") { topic.status }.equals 404
90
+ should("return the custom error") { topic.body }.equals "error: 404"
91
+ end
92
+
93
+ context "Request is invalid" do
94
+ setup { @toto.delete('/invalid') }
95
+ should("returns a 400") { topic.status }.equals 400
96
+ end
97
+
98
+ context "GET /index.xml (atom feed)" do
99
+ setup { @toto.get('/index.xml') }
100
+ asserts("content type is set properly") { topic.content_type }.equals "application/xml"
101
+ asserts("body should be valid xml") { topic.body }.includes_html("feed > entry" => /.+/)
102
+ asserts("summary shouldn't be empty") { topic.body }.includes_html("summary" => /.{10,}/)
103
+ end
104
+
105
+ context "GET /index?param=testparam (get parameter)" do
106
+ setup { @toto.get('/index?param=testparam') }
107
+ asserts("returns a 200") { topic.status }.equals 200
108
+ asserts("content type is set properly") { topic.content_type }.equals "text/html"
109
+ asserts("contain the env variable") { topic.body }.includes_html("p" => /env passed: true/)
110
+ asserts("access the http get parameter") { topic.body }.includes_html("p" => /request method type: GET/)
111
+ asserts("access the http parameter name value pair") { topic.body }.includes_html("p" => /request name value pair: param=testparam/)
112
+ end
113
+
114
+
115
+
116
+ context "GET to a repo name" do
117
+ setup do
118
+ class Toto::Repo
119
+ def readme() "#{self[:name]}'s README" end
120
+ end
121
+ end
122
+
123
+ context "when the repo is in the :repos array" do
124
+ setup do
125
+ @config[:github] = {:user => "cloudhead", :repos => ['the-repo']}
126
+ @toto.get('/the-repo')
127
+ end
128
+ should("return the-repo's README") { topic.body }.includes("the-repo's README")
129
+ end
130
+
131
+ context "when the repo is not in the :repos array" do
132
+ setup do
133
+ @config[:github] = {:user => "cloudhead", :repos => []}
134
+ @toto.get('/the-repo')
135
+ end
136
+ should("return a 404") { topic.status }.equals 404
137
+ end
138
+ end
139
+
140
+ context "creating an article" do
141
+ setup do
142
+ @config[:markdown] = true
143
+ @config[:date] = lambda {|t| "the time is #{t.strftime("%Y/%m/%d %H:%M")}" }
144
+ @config[:summary] = {:length => 50}
145
+ end
146
+
147
+ context "with the bare essentials" do
148
+ setup do
149
+ Toto::Article.new({
150
+ :title => "Toto & The Wizard of Oz.",
151
+ :body => "#Chapter I\nhello, *stranger*."
152
+ }, @config)
153
+ end
154
+
155
+ should("have a title") { topic.title }.equals "Toto & The Wizard of Oz."
156
+ should("parse the body as markdown") { topic.body }.equals "<h1>Chapter I</h1>\n\n<p>hello, <em>stranger</em>.</p>\n"
157
+ should("create an appropriate slug") { topic.slug }.equals "toto-and-the-wizard-of-oz"
158
+ should("set the date") { topic.date }.equals "the time is #{Date.today.strftime("%Y/%m/%d %H:%M")}"
159
+ should("create a summary") { topic.summary == topic.body }
160
+ should("have an author") { topic.author }.equals AUTHOR
161
+ should("have a path") { topic.path }.equals Date.today.strftime("/%Y/%m/%d/toto-and-the-wizard-of-oz/")
162
+ should("have a url") { topic.url }.equals Date.today.strftime("#{URL}/%Y/%m/%d/toto-and-the-wizard-of-oz/")
163
+ end
164
+
165
+ context "with a user-defined summary" do
166
+ setup do
167
+ Toto::Article.new({
168
+ :title => "Toto & The Wizard of Oz.",
169
+ :body => "Well,\nhello ~\n, *stranger*."
170
+ }, @config.merge(:markdown => false, :summary => {:max => 150, :delim => /~\n/}))
171
+ end
172
+
173
+ should("split the article at the delimiter") { topic.summary }.equals "Well,\nhello"
174
+ should("not have the delimiter in the body") { topic.body !~ /~/ }
175
+ end
176
+
177
+ context "with everything specified" do
178
+ setup do
179
+ Toto::Article.new({
180
+ :title => "The Wizard of Oz",
181
+ :body => ("a little bit of text." * 5) + "\n" + "filler" * 10,
182
+ :date => "19/10/1976",
183
+ :slug => "wizard-of-oz",
184
+ :author => "toetoe"
185
+ }, @config)
186
+ end
187
+
188
+ should("parse the date") { [topic[:date].month, topic[:date].year] }.equals [10, 1976]
189
+ should("use the slug") { topic.slug }.equals "wizard-of-oz"
190
+ should("use the author") { topic.author }.equals "toetoe"
191
+
192
+ context "and long first paragraph" do
193
+ should("create a valid summary") { topic.summary }.equals "<p>" + ("a little bit of text." * 5).chop + "&hellip;</p>\n"
194
+ end
195
+
196
+ context "and a short first paragraph" do
197
+ setup do
198
+ @config[:markdown] = false
199
+ Toto::Article.new({:body => "there ain't such thing as a free lunch\n" * 10}, @config)
200
+ end
201
+
202
+ should("create a valid summary") { topic.summary.size }.within 75..80
203
+ end
204
+ end
205
+
206
+ context "in a subdirectory" do
207
+ context "with implicit leading forward slash" do
208
+ setup do
209
+ conf = Toto::Config.new({})
210
+ conf.set(:prefix, "blog")
211
+ Toto::Article.new({
212
+ :title => "Toto & The Wizard of Oz.",
213
+ :body => "#Chapter I\nhello, *stranger*."
214
+ }, conf)
215
+ end
216
+
217
+ should("be in the directory") { topic.path }.equals Date.today.strftime("/blog/%Y/%m/%d/toto-and-the-wizard-of-oz/")
218
+ end
219
+
220
+ context "with explicit leading forward slash" do
221
+ setup do
222
+ conf = Toto::Config.new({})
223
+ conf.set(:prefix, "/blog")
224
+ Toto::Article.new({
225
+ :title => "Toto & The Wizard of Oz.",
226
+ :body => "#Chapter I\nhello, *stranger*."
227
+ }, conf)
228
+ end
229
+
230
+ should("be in the directory") { topic.path }.equals Date.today.strftime("/blog/%Y/%m/%d/toto-and-the-wizard-of-oz/")
231
+ end
232
+
233
+ context "with explicit trailing forward slash" do
234
+ setup do
235
+ conf = Toto::Config.new({})
236
+ conf.set(:prefix, "blog/")
237
+ Toto::Article.new({
238
+ :title => "Toto & The Wizard of Oz.",
239
+ :body => "#Chapter I\nhello, *stranger*."
240
+ }, conf)
241
+ end
242
+
243
+ should("be in the directory") { topic.path }.equals Date.today.strftime("/blog/%Y/%m/%d/toto-and-the-wizard-of-oz/")
244
+ end
245
+ end
246
+ end
247
+
248
+ context "using Config#set with a hash" do
249
+ setup do
250
+ conf = Toto::Config.new({})
251
+ conf.set(:summary, {:delim => /%/})
252
+ conf
253
+ end
254
+
255
+ should("set summary[:delim] to /%/") { topic[:summary][:delim].source }.equals "%"
256
+ should("leave the :max intact") { topic[:summary][:max] }.equals 150
257
+ end
258
+
259
+ context "using Config#set with a block" do
260
+ setup do
261
+ conf = Toto::Config.new({})
262
+ conf.set(:to_html) {|path, p, _| path + p }
263
+ conf
264
+ end
265
+
266
+ should("set the value to a proc") { topic[:to_html] }.respond_to :call
267
+ end
268
+
269
+ context "testing individual configuration parameters" do
270
+ context "generate error pages" do
271
+ setup do
272
+ conf = Toto::Config.new({})
273
+ conf.set(:error) {|code| "error code #{code}" }
274
+ conf
275
+ end
276
+
277
+ should("create an error page") { topic[:error].call(400) }.equals "error code 400"
278
+ end
279
+ end
280
+
281
+ context "extensions to the core Ruby library" do
282
+ should("respond to iso8601") { Date.today }.respond_to?(:iso8601)
283
+ end
284
+ end
285
+
286
+