cartera-toto 0.4.5

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,9 @@
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
+
@@ -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,275 @@
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 to a repo name" do
106
+ setup do
107
+ class Toto::Repo
108
+ def readme() "#{self[:name]}'s README" end
109
+ end
110
+ end
111
+
112
+ context "when the repo is in the :repos array" do
113
+ setup do
114
+ @config[:github] = {:user => "cloudhead", :repos => ['the-repo']}
115
+ @toto.get('/the-repo')
116
+ end
117
+ should("return the-repo's README") { topic.body }.includes("the-repo's README")
118
+ end
119
+
120
+ context "when the repo is not in the :repos array" do
121
+ setup do
122
+ @config[:github] = {:user => "cloudhead", :repos => []}
123
+ @toto.get('/the-repo')
124
+ end
125
+ should("return a 404") { topic.status }.equals 404
126
+ end
127
+ end
128
+
129
+ context "creating an article" do
130
+ setup do
131
+ @config[:markdown] = true
132
+ @config[:date] = lambda {|t| "the time is #{t.strftime("%Y/%m/%d %H:%M")}" }
133
+ @config[:summary] = {:length => 50}
134
+ end
135
+
136
+ context "with the bare essentials" do
137
+ setup do
138
+ Toto::Article.new({
139
+ :title => "Toto & The Wizard of Oz.",
140
+ :body => "#Chapter I\nhello, *stranger*."
141
+ }, @config)
142
+ end
143
+
144
+ should("have a title") { topic.title }.equals "Toto & The Wizard of Oz."
145
+ should("parse the body as markdown") { topic.body }.equals "<h1>Chapter I</h1>\n\n<p>hello, <em>stranger</em>.</p>\n"
146
+ should("create an appropriate slug") { topic.slug }.equals "toto-and-the-wizard-of-oz"
147
+ should("set the date") { topic.date }.equals "the time is #{Date.today.strftime("%Y/%m/%d %H:%M")}"
148
+ should("create a summary") { topic.summary == topic.body }
149
+ should("have an author") { topic.author }.equals AUTHOR
150
+ should("have a path") { topic.path }.equals Date.today.strftime("/%Y/%m/%d/toto-and-the-wizard-of-oz/")
151
+ should("have a url") { topic.url }.equals Date.today.strftime("#{URL}/%Y/%m/%d/toto-and-the-wizard-of-oz/")
152
+ end
153
+
154
+ context "with a user-defined summary" do
155
+ setup do
156
+ Toto::Article.new({
157
+ :title => "Toto & The Wizard of Oz.",
158
+ :body => "Well,\nhello ~\n, *stranger*."
159
+ }, @config.merge(:markdown => false, :summary => {:max => 150, :delim => /~\n/}))
160
+ end
161
+
162
+ should("split the article at the delimiter") { topic.summary }.equals "Well,\nhello"
163
+ should("not have the delimiter in the body") { topic.body !~ /~/ }
164
+ end
165
+
166
+ context "with everything specified" do
167
+ setup do
168
+ Toto::Article.new({
169
+ :title => "The Wizard of Oz",
170
+ :body => ("a little bit of text." * 5) + "\n" + "filler" * 10,
171
+ :date => "19/10/1976",
172
+ :slug => "wizard-of-oz",
173
+ :author => "toetoe"
174
+ }, @config)
175
+ end
176
+
177
+ should("parse the date") { [topic[:date].month, topic[:date].year] }.equals [10, 1976]
178
+ should("use the slug") { topic.slug }.equals "wizard-of-oz"
179
+ should("use the author") { topic.author }.equals "toetoe"
180
+
181
+ context "and long first paragraph" do
182
+ should("create a valid summary") { topic.summary }.equals "<p>" + ("a little bit of text." * 5).chop + "&hellip;</p>\n"
183
+ end
184
+
185
+ context "and a short first paragraph" do
186
+ setup do
187
+ @config[:markdown] = false
188
+ Toto::Article.new({:body => "there ain't such thing as a free lunch\n" * 10}, @config)
189
+ end
190
+
191
+ should("create a valid summary") { topic.summary.size }.within 75..80
192
+ end
193
+ end
194
+
195
+ context "in a subdirectory" do
196
+ context "with implicit leading forward slash" do
197
+ setup do
198
+ conf = Toto::Config.new({})
199
+ conf.set(:prefix, "blog")
200
+ Toto::Article.new({
201
+ :title => "Toto & The Wizard of Oz.",
202
+ :body => "#Chapter I\nhello, *stranger*."
203
+ }, conf)
204
+ end
205
+
206
+ should("be in the directory") { topic.path }.equals Date.today.strftime("/blog/%Y/%m/%d/toto-and-the-wizard-of-oz/")
207
+ end
208
+
209
+ context "with explicit leading forward slash" do
210
+ setup do
211
+ conf = Toto::Config.new({})
212
+ conf.set(:prefix, "/blog")
213
+ Toto::Article.new({
214
+ :title => "Toto & The Wizard of Oz.",
215
+ :body => "#Chapter I\nhello, *stranger*."
216
+ }, conf)
217
+ end
218
+
219
+ should("be in the directory") { topic.path }.equals Date.today.strftime("/blog/%Y/%m/%d/toto-and-the-wizard-of-oz/")
220
+ end
221
+
222
+ context "with explicit trailing forward slash" do
223
+ setup do
224
+ conf = Toto::Config.new({})
225
+ conf.set(:prefix, "blog/")
226
+ Toto::Article.new({
227
+ :title => "Toto & The Wizard of Oz.",
228
+ :body => "#Chapter I\nhello, *stranger*."
229
+ }, conf)
230
+ end
231
+
232
+ should("be in the directory") { topic.path }.equals Date.today.strftime("/blog/%Y/%m/%d/toto-and-the-wizard-of-oz/")
233
+ end
234
+ end
235
+ end
236
+
237
+ context "using Config#set with a hash" do
238
+ setup do
239
+ conf = Toto::Config.new({})
240
+ conf.set(:summary, {:delim => /%/})
241
+ conf
242
+ end
243
+
244
+ should("set summary[:delim] to /%/") { topic[:summary][:delim].source }.equals "%"
245
+ should("leave the :max intact") { topic[:summary][:max] }.equals 150
246
+ end
247
+
248
+ context "using Config#set with a block" do
249
+ setup do
250
+ conf = Toto::Config.new({})
251
+ conf.set(:to_html) {|path, p, _| path + p }
252
+ conf
253
+ end
254
+
255
+ should("set the value to a proc") { topic[:to_html] }.respond_to :call
256
+ end
257
+
258
+ context "testing individual configuration parameters" do
259
+ context "generate error pages" do
260
+ setup do
261
+ conf = Toto::Config.new({})
262
+ conf.set(:error) {|code| "error code #{code}" }
263
+ conf
264
+ end
265
+
266
+ should("create an error page") { topic[:error].call(400) }.equals "error code 400"
267
+ end
268
+ end
269
+
270
+ context "extensions to the core Ruby library" do
271
+ should("respond to iso8601") { Date.today }.respond_to?(:iso8601)
272
+ end
273
+ end
274
+
275
+