toto-bongo 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,14 @@
1
+ <!doctype html>
2
+ %html
3
+ %head
4
+ %link{:href => "/stylesheets/blog.css", :rel => "stylesheet", :type => "text/css"}
5
+ %link{:href => "/index.xml", :rel => "alternate", :title => "#{title} - feed", :type => "application/atom+xml"}/
6
+ %meta{:content => "text/html; charset=UTF-8", "http-equiv" => "Content-Type"}/
7
+ %title= title
8
+ %body
9
+ %section
10
+ = yield
11
+ %footer
12
+ powered by
13
+ %a{:href => "http://github.com/danpal/toto-bongo"} toto
14
+
@@ -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,285 @@
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
+ context "GET /index?param=testparam (get parameter)" do
105
+ setup { @toto.get('/index?param=testparam') }
106
+ asserts("returns a 200") { topic.status }.equals 200
107
+ asserts("content type is set properly") { topic.content_type }.equals "text/html"
108
+ asserts("contain the env variable") { topic.body }.includes_html("p" => /env passed: true/)
109
+ asserts("access the http get parameter") { topic.body }.includes_html("p" => /request method type: GET/)
110
+ asserts("access the http parameter name value pair") { topic.body }.includes_html("p" => /request name value pair: param=testparam/)
111
+ end
112
+
113
+
114
+
115
+ context "GET to a repo name" do
116
+ setup do
117
+ class Toto::Repo
118
+ def readme() "#{self[:name]}'s README" end
119
+ end
120
+ end
121
+
122
+ context "when the repo is in the :repos array" do
123
+ setup do
124
+ @config[:github] = {:user => "cloudhead", :repos => ['the-repo']}
125
+ @toto.get('/the-repo')
126
+ end
127
+ should("return the-repo's README") { topic.body }.includes("the-repo's README")
128
+ end
129
+
130
+ context "when the repo is not in the :repos array" do
131
+ setup do
132
+ @config[:github] = {:user => "cloudhead", :repos => []}
133
+ @toto.get('/the-repo')
134
+ end
135
+ should("return a 404") { topic.status }.equals 404
136
+ end
137
+ end
138
+
139
+ context "creating an article" do
140
+ setup do
141
+ @config[:markdown] = true
142
+ @config[:date] = lambda {|t| "the time is #{t.strftime("%Y/%m/%d %H:%M")}" }
143
+ @config[:summary] = {:length => 50}
144
+ end
145
+
146
+ context "with the bare essentials" do
147
+ setup do
148
+ Toto::Article.new({
149
+ :title => "Toto & The Wizard of Oz.",
150
+ :body => "#Chapter I\nhello, *stranger*."
151
+ }, @config)
152
+ end
153
+
154
+ should("have a title") { topic.title }.equals "Toto & The Wizard of Oz."
155
+ should("parse the body as markdown") { topic.body }.equals "<h1>Chapter I</h1>\n\n<p>hello, <em>stranger</em>.</p>\n"
156
+ should("create an appropriate slug") { topic.slug }.equals "toto-and-the-wizard-of-oz"
157
+ should("set the date") { topic.date }.equals "the time is #{Date.today.strftime("%Y/%m/%d %H:%M")}"
158
+ should("create a summary") { topic.summary == topic.body }
159
+ should("have an author") { topic.author }.equals AUTHOR
160
+ should("have a path") { topic.path }.equals Date.today.strftime("/%Y/%m/%d/toto-and-the-wizard-of-oz/")
161
+ should("have a url") { topic.url }.equals Date.today.strftime("#{URL}/%Y/%m/%d/toto-and-the-wizard-of-oz/")
162
+ end
163
+
164
+ context "with a user-defined summary" do
165
+ setup do
166
+ Toto::Article.new({
167
+ :title => "Toto & The Wizard of Oz.",
168
+ :body => "Well,\nhello ~\n, *stranger*."
169
+ }, @config.merge(:markdown => false, :summary => {:max => 150, :delim => /~\n/}))
170
+ end
171
+
172
+ should("split the article at the delimiter") { topic.summary }.equals "Well,\nhello"
173
+ should("not have the delimiter in the body") { topic.body !~ /~/ }
174
+ end
175
+
176
+ context "with everything specified" do
177
+ setup do
178
+ Toto::Article.new({
179
+ :title => "The Wizard of Oz",
180
+ :body => ("a little bit of text." * 5) + "\n" + "filler" * 10,
181
+ :date => "19/10/1976",
182
+ :slug => "wizard-of-oz",
183
+ :author => "toetoe"
184
+ }, @config)
185
+ end
186
+
187
+ should("parse the date") { [topic[:date].month, topic[:date].year] }.equals [10, 1976]
188
+ should("use the slug") { topic.slug }.equals "wizard-of-oz"
189
+ should("use the author") { topic.author }.equals "toetoe"
190
+
191
+ context "and long first paragraph" do
192
+ should("create a valid summary") { topic.summary }.equals "<p>" + ("a little bit of text." * 5).chop + "&hellip;</p>\n"
193
+ end
194
+
195
+ context "and a short first paragraph" do
196
+ setup do
197
+ @config[:markdown] = false
198
+ Toto::Article.new({:body => "there ain't such thing as a free lunch\n" * 10}, @config)
199
+ end
200
+
201
+ should("create a valid summary") { topic.summary.size }.within 75..80
202
+ end
203
+ end
204
+
205
+ context "in a subdirectory" do
206
+ context "with implicit leading forward slash" do
207
+ setup do
208
+ conf = Toto::Config.new({})
209
+ conf.set(:prefix, "blog")
210
+ Toto::Article.new({
211
+ :title => "Toto & The Wizard of Oz.",
212
+ :body => "#Chapter I\nhello, *stranger*."
213
+ }, conf)
214
+ end
215
+
216
+ should("be in the directory") { topic.path }.equals Date.today.strftime("/blog/%Y/%m/%d/toto-and-the-wizard-of-oz/")
217
+ end
218
+
219
+ context "with explicit leading forward slash" do
220
+ setup do
221
+ conf = Toto::Config.new({})
222
+ conf.set(:prefix, "/blog")
223
+ Toto::Article.new({
224
+ :title => "Toto & The Wizard of Oz.",
225
+ :body => "#Chapter I\nhello, *stranger*."
226
+ }, conf)
227
+ end
228
+
229
+ should("be in the directory") { topic.path }.equals Date.today.strftime("/blog/%Y/%m/%d/toto-and-the-wizard-of-oz/")
230
+ end
231
+
232
+ context "with explicit trailing forward slash" do
233
+ setup do
234
+ conf = Toto::Config.new({})
235
+ conf.set(:prefix, "blog/")
236
+ Toto::Article.new({
237
+ :title => "Toto & The Wizard of Oz.",
238
+ :body => "#Chapter I\nhello, *stranger*."
239
+ }, conf)
240
+ end
241
+
242
+ should("be in the directory") { topic.path }.equals Date.today.strftime("/blog/%Y/%m/%d/toto-and-the-wizard-of-oz/")
243
+ end
244
+ end
245
+ end
246
+
247
+ context "using Config#set with a hash" do
248
+ setup do
249
+ conf = Toto::Config.new({})
250
+ conf.set(:summary, {:delim => /%/})
251
+ conf
252
+ end
253
+
254
+ should("set summary[:delim] to /%/") { topic[:summary][:delim].source }.equals "%"
255
+ should("leave the :max intact") { topic[:summary][:max] }.equals 150
256
+ end
257
+
258
+ context "using Config#set with a block" do
259
+ setup do
260
+ conf = Toto::Config.new({})
261
+ conf.set(:to_html) {|path, p, _| path + p }
262
+ conf
263
+ end
264
+
265
+ should("set the value to a proc") { topic[:to_html] }.respond_to :call
266
+ end
267
+
268
+ context "testing individual configuration parameters" do
269
+ context "generate error pages" do
270
+ setup do
271
+ conf = Toto::Config.new({})
272
+ conf.set(:error) {|code| "error code #{code}" }
273
+ conf
274
+ end
275
+
276
+ should("create an error page") { topic[:error].call(400) }.equals "error code 400"
277
+ end
278
+ end
279
+
280
+ context "extensions to the core Ruby library" do
281
+ should("respond to iso8601") { Date.today }.respond_to?(:iso8601)
282
+ end
283
+ end
284
+
285
+
@@ -0,0 +1,75 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{toto-bongo}
8
+ s.version = "1.0.1"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Daniel Palacio"]
12
+ s.date = %q{2011-05-10}
13
+ s.description = %q{Minimal blog to use with your existing app}
14
+ s.extra_rdoc_files = [
15
+ "LICENSE",
16
+ "README.md"
17
+ ]
18
+ s.files = [
19
+ ".document",
20
+ "LICENSE",
21
+ "README.md",
22
+ "Rakefile",
23
+ "VERSION",
24
+ "lib/ext/ext.rb",
25
+ "lib/toto-bongo.rb",
26
+ "test/articles/1900-05-17-the-wonderful-wizard-of-oz.txt",
27
+ "test/articles/2001-01-01-two-thousand-and-one.txt",
28
+ "test/articles/2009-04-01-tilt-factor.txt",
29
+ "test/articles/2009-12-04-some-random-article.txt",
30
+ "test/articles/2009-12-11-the-dichotomy-of-design.txt",
31
+ "test/autotest.rb",
32
+ "test/templates/about.html.haml",
33
+ "test/templates/archives.html.haml",
34
+ "test/templates/article.html.haml",
35
+ "test/templates/feed.builder",
36
+ "test/templates/index.builder",
37
+ "test/templates/index.html.haml",
38
+ "test/templates/layout.html.haml",
39
+ "test/test_helper.rb",
40
+ "test/toto_test.rb",
41
+ "toto-bongo.gemspec"
42
+ ]
43
+ s.homepage = %q{https://github.com/danpal/toto-bongo}
44
+ s.require_paths = ["lib"]
45
+ s.rubygems_version = %q{1.3.7}
46
+ s.summary = %q{Tiny blog for your existing app}
47
+ s.test_files = [
48
+ "test/autotest.rb",
49
+ "test/test_helper.rb",
50
+ "test/toto_test.rb"
51
+ ]
52
+
53
+ if s.respond_to? :specification_version then
54
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
55
+ s.specification_version = 3
56
+
57
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
58
+ s.add_development_dependency(%q<riot>, [">= 0"])
59
+ s.add_runtime_dependency(%q<builder>, [">= 0"])
60
+ s.add_runtime_dependency(%q<rack>, [">= 0"])
61
+ s.add_runtime_dependency(%q<RedCloth>, [">= 0"])
62
+ else
63
+ s.add_dependency(%q<riot>, [">= 0"])
64
+ s.add_dependency(%q<builder>, [">= 0"])
65
+ s.add_dependency(%q<rack>, [">= 0"])
66
+ s.add_dependency(%q<RedCloth>, [">= 0"])
67
+ end
68
+ else
69
+ s.add_dependency(%q<riot>, [">= 0"])
70
+ s.add_dependency(%q<builder>, [">= 0"])
71
+ s.add_dependency(%q<rack>, [">= 0"])
72
+ s.add_dependency(%q<RedCloth>, [">= 0"])
73
+ end
74
+ end
75
+
metadata ADDED
@@ -0,0 +1,140 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: toto-bongo
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 1
7
+ - 0
8
+ - 1
9
+ version: 1.0.1
10
+ platform: ruby
11
+ authors:
12
+ - Daniel Palacio
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2011-05-10 00:00:00 -05:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: riot
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ segments:
29
+ - 0
30
+ version: "0"
31
+ type: :development
32
+ version_requirements: *id001
33
+ - !ruby/object:Gem::Dependency
34
+ name: builder
35
+ prerelease: false
36
+ requirement: &id002 !ruby/object:Gem::Requirement
37
+ none: false
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ segments:
42
+ - 0
43
+ version: "0"
44
+ type: :runtime
45
+ version_requirements: *id002
46
+ - !ruby/object:Gem::Dependency
47
+ name: rack
48
+ prerelease: false
49
+ requirement: &id003 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ segments:
55
+ - 0
56
+ version: "0"
57
+ type: :runtime
58
+ version_requirements: *id003
59
+ - !ruby/object:Gem::Dependency
60
+ name: RedCloth
61
+ prerelease: false
62
+ requirement: &id004 !ruby/object:Gem::Requirement
63
+ none: false
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ segments:
68
+ - 0
69
+ version: "0"
70
+ type: :runtime
71
+ version_requirements: *id004
72
+ description: Minimal blog to use with your existing app
73
+ email:
74
+ executables: []
75
+
76
+ extensions: []
77
+
78
+ extra_rdoc_files:
79
+ - LICENSE
80
+ - README.md
81
+ files:
82
+ - .document
83
+ - LICENSE
84
+ - README.md
85
+ - Rakefile
86
+ - VERSION
87
+ - lib/ext/ext.rb
88
+ - lib/toto-bongo.rb
89
+ - test/articles/1900-05-17-the-wonderful-wizard-of-oz.txt
90
+ - test/articles/2001-01-01-two-thousand-and-one.txt
91
+ - test/articles/2009-04-01-tilt-factor.txt
92
+ - test/articles/2009-12-04-some-random-article.txt
93
+ - test/articles/2009-12-11-the-dichotomy-of-design.txt
94
+ - test/autotest.rb
95
+ - test/templates/about.html.haml
96
+ - test/templates/archives.html.haml
97
+ - test/templates/article.html.haml
98
+ - test/templates/feed.builder
99
+ - test/templates/index.builder
100
+ - test/templates/index.html.haml
101
+ - test/templates/layout.html.haml
102
+ - test/test_helper.rb
103
+ - test/toto_test.rb
104
+ - toto-bongo.gemspec
105
+ has_rdoc: true
106
+ homepage: https://github.com/danpal/toto-bongo
107
+ licenses: []
108
+
109
+ post_install_message:
110
+ rdoc_options: []
111
+
112
+ require_paths:
113
+ - lib
114
+ required_ruby_version: !ruby/object:Gem::Requirement
115
+ none: false
116
+ requirements:
117
+ - - ">="
118
+ - !ruby/object:Gem::Version
119
+ segments:
120
+ - 0
121
+ version: "0"
122
+ required_rubygems_version: !ruby/object:Gem::Requirement
123
+ none: false
124
+ requirements:
125
+ - - ">="
126
+ - !ruby/object:Gem::Version
127
+ segments:
128
+ - 0
129
+ version: "0"
130
+ requirements: []
131
+
132
+ rubyforge_project:
133
+ rubygems_version: 1.3.7
134
+ signing_key:
135
+ specification_version: 3
136
+ summary: Tiny blog for your existing app
137
+ test_files:
138
+ - test/autotest.rb
139
+ - test/test_helper.rb
140
+ - test/toto_test.rb