toto_prerelease 0.4.7prerelease

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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
+