ceilingfish-toto 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ *.sw?
2
+ .DS_Store
3
+ coverage
4
+ rdoc
5
+ pkg
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 cloudhead
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,153 @@
1
+ toto
2
+ ====
3
+
4
+ the tiniest blogging engine in Oz!
5
+
6
+ introduction
7
+ ------------
8
+
9
+ toto is a git-powered, minimalist blog engine for the hackers of Oz. The engine weights around ~300 sloc at its worse.
10
+ There is no toto client, at least for now; everything goes through git.
11
+
12
+ blog in 10 seconds
13
+ ------------------
14
+
15
+ $ git clone git://github.com/cloudhead/dorothy.git myblog
16
+ $ cd myblog
17
+ $ heroku create myblog
18
+ $ git push heroku master
19
+
20
+ philosophy
21
+ ----------
22
+
23
+ Everything that can be done better with another tool should be, but one should not have too much pie to stay fit.
24
+ In other words, toto does away with web frameworks or DSLs such as sinatra, and is built right on top of **rack**.
25
+ There is no database or ORM either, we use plain text files.
26
+
27
+ Toto was designed to be used with a reverse-proxy cache, such as [Varnish](http://varnish-cache.org).
28
+ This makes it an ideal candidate for [heroku](http://heroku.com).
29
+
30
+ Oh, and everything that can be done with git, _is_.
31
+
32
+ how it works
33
+ ------------
34
+
35
+ - content is entirely managed through **git**; you get full fledged version control for free.
36
+ - articles are stored as _.txt_ files, with embeded metadata (in yaml format).
37
+ - articles are processed through a markdown converter (rdiscount) by default.
38
+ - templating is done through **ERB**.
39
+ - toto is built right on top of **Rack**.
40
+ - toto was built to take advantage of _HTTP caching_.
41
+ - toto was built with heroku in mind.
42
+ - comments are handled by [disqus](http://disqus.com)
43
+ - individual articles can be accessed through urls such as _/2009/11/21/blogging-with-toto_
44
+ - the archives can be accessed by year, month or day, wih the same format as above.
45
+ - arbitrary metadata can be included in articles files, and accessed from the templates.
46
+ - summaries are generated intelligently by toto, following the `:max` setting you give it.
47
+ - you can also define how long your summary is, by adding `~` at the end of it (`:delim`).
48
+
49
+ dorothy
50
+ -------
51
+
52
+ Dorothy is toto's default template, you can get it at <http://github.com/cloudhead/dorothy>. It
53
+ comes with a very minimalistic but functional template, and a _config.ru_ file to get you started.
54
+ It also includes a _.gems_ file, for heroku.
55
+
56
+ synopsis
57
+ --------
58
+
59
+ One would start by installing _toto_, with `sudo gem install toto`, and then forking or
60
+ cloning the `dorothy` repo, to get a basic skeleton:
61
+
62
+ $ git clone git://github.com/cloudhead/dorothy.git weblog
63
+ $ cd weblog/
64
+
65
+ One would then edit the template at will, it has the following structure:
66
+
67
+ templates/
68
+ |
69
+ +- layout.rhtml # the main site layout, shared by all pages
70
+ |
71
+ +- feed.builder # the builder template for the atom feed
72
+ |
73
+ +- pages/ # pages, such as home, about, etc go here
74
+ |
75
+ +- index.rhtml # the default page loaded from `/`, it displays the list of articles
76
+ |
77
+ +- article.rhtml # the article (post) partial and page
78
+ |
79
+ +- about.rhtml
80
+
81
+ One could then create a .txt article file in the `articles/` folder, and make sure it has the following format:
82
+
83
+ title: The Wonderful Wizard of Oz
84
+ author: Lyman Frank Baum
85
+ date: 1900/05/17
86
+
87
+ Dorothy lived in the midst of the great Kansas prairies, with Uncle Henry,
88
+ who was a farmer, and Aunt Em, who was the farmer's wife.
89
+
90
+ If one is familiar with webby or aerial, this shouldn't look funny. Basically the top of the file is in YAML format,
91
+ and the rest of it is the blog post. They are delimited by an empty line `/\n\n/`, as you can see above.
92
+ None of the information is compulsory, but it's strongly encouraged you specify it.
93
+ Note that one can also use `rake` to create an article stub, with `rake new`.
94
+
95
+ Once he finishes writing his beautiful tale, one can push to the git repo, as usual:
96
+
97
+ $ git add articles/wizard-of-oz.txt
98
+ $ git commit -m 'wrote the wizard of oz.'
99
+ $ git push remote master
100
+
101
+ Where `remote` is the name of your remote git repository. The article is now published.
102
+
103
+ ### deployment
104
+
105
+ Toto is built on top of **Rack**, and hence has a **rackup** file: _config.ru_.
106
+
107
+ #### on your own server
108
+
109
+ Once you have created the remote git repo, and pushed your changes to it, you can run toto with any Rack compliant web server,
110
+ such as **thin**, **mongrel** or **unicorn**.
111
+
112
+ With thin, you would do something like:
113
+
114
+ $ thin start -R config.ru
115
+
116
+ With unicorn, you can just do:
117
+
118
+ $ unicorn
119
+
120
+ #### on heroku
121
+
122
+ Toto was designed to work well with [heroku](http://heroku.com), it makes the most out of it's state-of-the-art caching,
123
+ by setting the _Cache-Control_ and _Etag_ HTTP headers. Deploying on Heroku is really easy, just get the heroku gem,
124
+ create a heroku app with `heroku create`, and push with `git push heroku master`.
125
+
126
+ $ heroku create weblog
127
+ $ git push heroku master
128
+ $ heroku open
129
+
130
+ ### configuration
131
+
132
+ You can configure toto, by modifying the _config.ru_ file. For example, if you want to set the blog author to 'John Galt',
133
+ you could add `set :author, 'John Galt'` inside the `Toto::Server.new` block. Here are the defaults, to get you started:
134
+
135
+ set :author, ENV['USER'] # blog author
136
+ set :title, Dir.pwd.split('/').last # site title
137
+ set :url, 'http://example.com' # site root URL
138
+ set :root, "index" # page to load on /
139
+ set :date, lambda {|now| now.strftime("%d/%m/%Y") } # date format for articles
140
+ set :markdown, :smart # use markdown + smart-mode
141
+ set :disqus, false # disqus id, or false
142
+ set :summary, :max => 150, :delim => /~\n/ # length of article summary and delimiter
143
+ set :ext, 'txt' # file extension for articles
144
+ set :cache, 28800 # cache site for 8 hours
145
+
146
+ thanks
147
+ ------
148
+
149
+ To heroku for making this easy as pie.
150
+ To adam wiggins, as I stole a couple of ideas from Scanty.
151
+ To the developpers of Rack, for making such an awesome platform.
152
+
153
+ Copyright (c) 2009 cloudhead. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,31 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "ceilingfish-toto"
8
+ gem.summary = %Q{the tiniest blog-engine in Oz}
9
+ gem.description = %Q{the tiniest blog-engine in Oz.}
10
+ gem.email = "ceilingfish@gmail.com"
11
+ gem.homepage = "http://github.com/ceilingfish/toto"
12
+ gem.authors = ["cloudhead", "ceilingfish"]
13
+ gem.add_development_dependency "riot"
14
+ gem.add_dependency "builder"
15
+ gem.add_dependency "rack"
16
+ gem.add_dependency "rdiscount"
17
+ end
18
+ Jeweler::GemcutterTasks.new
19
+ rescue LoadError
20
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
21
+ end
22
+
23
+ require 'rake/testtask'
24
+ Rake::TestTask.new(:test) do |test|
25
+ test.libs << 'lib' << 'test'
26
+ test.pattern = 'test/**/*_test.rb'
27
+ test.verbose = true
28
+ end
29
+
30
+ task :test => :check_dependencies
31
+ task :default => :test
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.3.2
@@ -0,0 +1,76 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{ceilingfish-toto}
8
+ s.version = "0.3.2"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["cloudhead", "ceilingfish"]
12
+ s.date = %q{2010-02-12}
13
+ s.description = %q{the tiniest blog-engine in Oz.}
14
+ s.email = %q{ceilingfish@gmail.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README.md"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ ".gitignore",
22
+ "LICENSE",
23
+ "README.md",
24
+ "Rakefile",
25
+ "VERSION",
26
+ "ceilingfish-toto.gemspec",
27
+ "test/articles/1900-05-17-the-wonderful-wizard-of-oz.txt",
28
+ "test/articles/2001-01-01-two-thousand-and-one.txt",
29
+ "test/articles/2009-04-01-tilt-factor.txt",
30
+ "test/articles/2009-12-04-some-random-article.txt",
31
+ "test/articles/2009-12-11-the-dichotomy-of-design.txt",
32
+ "test/autotest.rb",
33
+ "test/templates/about.rhtml",
34
+ "test/templates/archives.rhtml",
35
+ "test/templates/article.rhtml",
36
+ "test/templates/feed.builder",
37
+ "test/templates/index.rhtml",
38
+ "test/templates/layout.rhtml",
39
+ "test/templates/repo.rhtml",
40
+ "test/test_helper.rb",
41
+ "test/toto_test.rb"
42
+ ]
43
+ s.homepage = %q{http://github.com/ceilingfish/toto}
44
+ s.rdoc_options = ["--charset=UTF-8"]
45
+ s.require_paths = ["lib"]
46
+ s.rubygems_version = %q{1.3.5}
47
+ s.summary = %q{the tiniest blog-engine in Oz}
48
+ s.test_files = [
49
+ "test/autotest.rb",
50
+ "test/test_helper.rb",
51
+ "test/toto_test.rb"
52
+ ]
53
+
54
+ if s.respond_to? :specification_version then
55
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
56
+ s.specification_version = 3
57
+
58
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
59
+ s.add_development_dependency(%q<riot>, [">= 0"])
60
+ s.add_runtime_dependency(%q<builder>, [">= 0"])
61
+ s.add_runtime_dependency(%q<rack>, [">= 0"])
62
+ s.add_runtime_dependency(%q<rdiscount>, [">= 0"])
63
+ else
64
+ s.add_dependency(%q<riot>, [">= 0"])
65
+ s.add_dependency(%q<builder>, [">= 0"])
66
+ s.add_dependency(%q<rack>, [">= 0"])
67
+ s.add_dependency(%q<rdiscount>, [">= 0"])
68
+ end
69
+ else
70
+ s.add_dependency(%q<riot>, [">= 0"])
71
+ s.add_dependency(%q<builder>, [">= 0"])
72
+ s.add_dependency(%q<rack>, [">= 0"])
73
+ s.add_dependency(%q<rdiscount>, [">= 0"])
74
+ end
75
+ end
76
+
@@ -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,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,185 @@
1
+ require 'test/test_helper'
2
+
3
+ URL = "http://toto.oz"
4
+ AUTHOR = "toto"
5
+
6
+ context Toto do
7
+ setup do
8
+ @config = Toto::Config.new(:markdown => true, :author => AUTHOR, :url => URL)
9
+ @toto = Rack::MockRequest.new(Toto::Server.new(@config))
10
+ Toto::Paths[:articles] = "test/articles"
11
+ Toto::Paths[:pages] = "test/templates"
12
+ Toto::Paths[:templates] = "test/templates"
13
+ end
14
+
15
+ context "GET /" do
16
+ setup { @toto.get('/') }
17
+
18
+ asserts("returns a 200") { topic.status }.equals 200
19
+ asserts("body is not empty") { not topic.body.empty? }
20
+ asserts("content type is set properly") { topic.content_type }.equals "text/html"
21
+ should("include a couple of article") { topic.body }.includes_elements("#articles li", 3)
22
+ should("include an archive") { topic.body }.includes_elements("#archives li", 2)
23
+
24
+ context "with no articles" do
25
+ setup { Rack::MockRequest.new(Toto::Server.new(@config.merge(:ext => 'oxo'))).get('/') }
26
+
27
+ asserts("body is not empty") { not topic.body.empty? }
28
+ asserts("returns a 200") { topic.status }.equals 200
29
+ end
30
+ end
31
+
32
+ context "GET /about" do
33
+ setup { @toto.get('/about') }
34
+ asserts("returns a 200") { topic.status }.equals 200
35
+ asserts("body is not empty") { not topic.body.empty? }
36
+ should("have access to @articles") { topic.body }.includes_html("#count" => /5/)
37
+ end
38
+
39
+ context "GET a single article" do
40
+ setup { @toto.get("/1900/05/17/the-wonderful-wizard-of-oz") }
41
+ asserts("returns a 200") { topic.status }.equals 200
42
+ asserts("content type is set properly") { topic.content_type }.equals "text/html"
43
+ should("contain the article") { topic.body }.includes_html("p" => /<em>Once upon a time<\/em>/)
44
+ end
45
+
46
+ context "GET to the archive" do
47
+ context "through a year" do
48
+ setup { @toto.get('/2009') }
49
+ asserts("returns a 200") { topic.status }.equals 200
50
+ should("includes the entries for that year") { topic.body }.includes_elements("li.entry", 3)
51
+ end
52
+
53
+ context "through a year & month" do
54
+ setup { @toto.get('/2009/12') }
55
+ asserts("returns a 200") { topic.status }.equals 200
56
+ should("includes the entries for that month") { topic.body }.includes_elements("li.entry", 2)
57
+ should("includes the year & month") { topic.body }.includes_html("h1" => /2009\/12/)
58
+ end
59
+
60
+ context "through /archive" do
61
+ setup { @toto.get('/archive') }
62
+ end
63
+ end
64
+
65
+ context "GET to an unknown route" do
66
+ setup { @toto.get('/unknown') }
67
+ should("returns a 404") { topic.status }.equals 404
68
+ end
69
+
70
+ context "Request is invalid" do
71
+ setup { @toto.delete('/invalid') }
72
+ should("returns a 400") { topic.status }.equals 400
73
+ end
74
+
75
+ context "GET /index.xml (atom feed)" do
76
+ setup { @toto.get('/index.xml') }
77
+ asserts("content type is set properly") { topic.content_type }.equals "application/xml"
78
+ asserts("body should be valid xml") { topic.body }.includes_html("feed > entry" => /.+/)
79
+ asserts("summary shouldn't be empty") { topic.body }.includes_html("summary" => /.{10,}/)
80
+ end
81
+
82
+ context "GET to a repo name" do
83
+ setup do
84
+ class Toto::Repo
85
+ def readme() "#{self[:name]}'s README" end
86
+ end
87
+ end
88
+
89
+ context "when the repo is in the :repos array" do
90
+ setup do
91
+ @config[:github] = {:user => "cloudhead", :repos => ['the-repo']}
92
+ @toto.get('/the-repo')
93
+ end
94
+ should("return the-repo's README") { topic.body }.includes("the-repo's README")
95
+ end
96
+
97
+ context "when the repo is not in the :repos array" do
98
+ setup do
99
+ @config[:github] = {:user => "cloudhead", :repos => []}
100
+ @toto.get('/the-repo')
101
+ end
102
+ should("return a 404") { topic.status }.equals 404
103
+ end
104
+ end
105
+
106
+ context "creating an article" do
107
+ setup do
108
+ @config[:markdown] = true
109
+ @config[:date] = lambda {|t| "the time is #{t.strftime("%Y/%m/%d %H:%M")}" }
110
+ @config[:summary] = {:length => 50}
111
+ end
112
+
113
+ context "with the bare essentials" do
114
+ setup do
115
+ Toto::Article.new({
116
+ :title => "Toto & The Wizard of Oz.",
117
+ :body => "#Chapter I\nhello, *stranger*."
118
+ }, @config)
119
+ end
120
+
121
+ should("have a title") { topic.title }.equals "Toto & The Wizard of Oz."
122
+ should("parse the body as markdown") { topic.body }.equals "<h1>Chapter I</h1>\n\n<p>hello, <em>stranger</em>.</p>\n"
123
+ should("create an appropriate slug") { topic.slug }.equals "toto-and-the-wizard-of-oz"
124
+ should("set the date") { topic.date }.equals "the time is #{Time.now.strftime("%Y/%m/%d %H:%M")}"
125
+ should("create a summary") { topic.summary == topic.body }
126
+ should("have an author") { topic.author }.equals AUTHOR
127
+ should("have a path") { topic.path }.equals Time.now.strftime("/%Y/%m/%d/toto-and-the-wizard-of-oz/")
128
+ should("have a url") { topic.url }.equals Time.now.strftime("#{URL}/%Y/%m/%d/toto-and-the-wizard-of-oz/")
129
+ end
130
+
131
+ context "with a user-defined summary" do
132
+ setup do
133
+ Toto::Article.new({
134
+ :title => "Toto & The Wizard of Oz.",
135
+ :body => "Well,\nhello ~\n, *stranger*."
136
+ }, @config.merge(:markdown => false, :summary => {:max => 150, :delim => /~\n/}))
137
+ end
138
+
139
+ should("split the article at the delimiter") { topic.summary }.equals "Well,\nhello"
140
+ should("not have the delimiter in the body") { topic.body !~ /~/ }
141
+ end
142
+
143
+ context "with everything specified" do
144
+ setup do
145
+ Toto::Article.new({
146
+ :title => "The Wizard of Oz",
147
+ :body => ("a little bit of text." * 5) + "\n" + "filler" * 10,
148
+ :date => "19/10/1976",
149
+ :slug => "wizard-of-oz",
150
+ :author => "toetoe"
151
+ }, @config)
152
+ end
153
+
154
+ should("parse the date") { [topic[:date].month, topic[:date].year] }.equals [10, 1976]
155
+ should("use the slug") { topic.slug }.equals "wizard-of-oz"
156
+ should("use the author") { topic.author }.equals "toetoe"
157
+
158
+ context "and long first paragraph" do
159
+ should("create a valid summary") { topic.summary }.equals "<p>" + ("a little bit of text." * 5).chop + "&hellip;</p>\n"
160
+ end
161
+
162
+ context "and a short first paragraph" do
163
+ setup do
164
+ @config[:markdown] = false
165
+ Toto::Article.new({:body => "there ain't such thing as a free lunch\n" * 10}, @config)
166
+ end
167
+
168
+ should("create a valid summary") { topic.summary.size }.within 75..80
169
+ end
170
+ end
171
+ end
172
+
173
+ context "using Config#set with a hash" do
174
+ setup do
175
+ conf = Toto::Config.new({})
176
+ conf.set(:summary, {:delim => /%/})
177
+ conf
178
+ end
179
+
180
+ should("set summary[:delim] to /%/") { topic[:summary][:delim].source }.equals "%"
181
+ should("leave the :max intact") { topic[:summary][:max] }.equals 150
182
+ end
183
+ end
184
+
185
+
metadata ADDED
@@ -0,0 +1,119 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ceilingfish-toto
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.2
5
+ platform: ruby
6
+ authors:
7
+ - cloudhead
8
+ - ceilingfish
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2010-02-12 00:00:00 +00:00
14
+ default_executable:
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: riot
18
+ type: :development
19
+ version_requirement:
20
+ version_requirements: !ruby/object:Gem::Requirement
21
+ requirements:
22
+ - - ">="
23
+ - !ruby/object:Gem::Version
24
+ version: "0"
25
+ version:
26
+ - !ruby/object:Gem::Dependency
27
+ name: builder
28
+ type: :runtime
29
+ version_requirement:
30
+ version_requirements: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: "0"
35
+ version:
36
+ - !ruby/object:Gem::Dependency
37
+ name: rack
38
+ type: :runtime
39
+ version_requirement:
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ version: "0"
45
+ version:
46
+ - !ruby/object:Gem::Dependency
47
+ name: rdiscount
48
+ type: :runtime
49
+ version_requirement:
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: "0"
55
+ version:
56
+ description: the tiniest blog-engine in Oz.
57
+ email: ceilingfish@gmail.com
58
+ executables: []
59
+
60
+ extensions: []
61
+
62
+ extra_rdoc_files:
63
+ - LICENSE
64
+ - README.md
65
+ files:
66
+ - .document
67
+ - .gitignore
68
+ - LICENSE
69
+ - README.md
70
+ - Rakefile
71
+ - VERSION
72
+ - ceilingfish-toto.gemspec
73
+ - test/articles/1900-05-17-the-wonderful-wizard-of-oz.txt
74
+ - test/articles/2001-01-01-two-thousand-and-one.txt
75
+ - test/articles/2009-04-01-tilt-factor.txt
76
+ - test/articles/2009-12-04-some-random-article.txt
77
+ - test/articles/2009-12-11-the-dichotomy-of-design.txt
78
+ - test/autotest.rb
79
+ - test/templates/about.rhtml
80
+ - test/templates/archives.rhtml
81
+ - test/templates/article.rhtml
82
+ - test/templates/feed.builder
83
+ - test/templates/index.rhtml
84
+ - test/templates/layout.rhtml
85
+ - test/templates/repo.rhtml
86
+ - test/test_helper.rb
87
+ - test/toto_test.rb
88
+ has_rdoc: true
89
+ homepage: http://github.com/ceilingfish/toto
90
+ licenses: []
91
+
92
+ post_install_message:
93
+ rdoc_options:
94
+ - --charset=UTF-8
95
+ require_paths:
96
+ - lib
97
+ required_ruby_version: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - ">="
100
+ - !ruby/object:Gem::Version
101
+ version: "0"
102
+ version:
103
+ required_rubygems_version: !ruby/object:Gem::Requirement
104
+ requirements:
105
+ - - ">="
106
+ - !ruby/object:Gem::Version
107
+ version: "0"
108
+ version:
109
+ requirements: []
110
+
111
+ rubyforge_project:
112
+ rubygems_version: 1.3.5
113
+ signing_key:
114
+ specification_version: 3
115
+ summary: the tiniest blog-engine in Oz
116
+ test_files:
117
+ - test/autotest.rb
118
+ - test/test_helper.rb
119
+ - test/toto_test.rb