serious 0.1.0

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.
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,21 @@
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.swp
15
+
16
+ ## PROJECT::GENERAL
17
+ coverage
18
+ rdoc
19
+ pkg
20
+
21
+ ## PROJECT::SPECIFIC
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010 Christoph Olszowka
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.rdoc ADDED
@@ -0,0 +1,17 @@
1
+ = serious
2
+
3
+ TODO...
4
+
5
+ == Note on Patches/Pull Requests
6
+
7
+ * Fork the project.
8
+ * Make your feature addition or bug fix.
9
+ * Add tests for it. This is important so I don't break it in a
10
+ future version unintentionally.
11
+ * Commit, do not mess with rakefile, version, or history.
12
+ (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
13
+ * Send me a pull request. Bonus points for topic branches.
14
+
15
+ == Copyright
16
+
17
+ Copyright (c) 2010 Christoph Olszowka. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,57 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "serious"
8
+ gem.summary = %Q{Serious is a simple, file-driven blog engine inspired by toto and driven by sinatra}
9
+ gem.description = %Q{Serious is a simple, file-driven blog engine inspired by toto and driven by sinatra}
10
+ gem.email = "christoph at olszowka dot de"
11
+ gem.homepage = "http://github.com/colszowka/serious"
12
+ gem.authors = ["Christoph Olszowka"]
13
+ gem.add_dependency 'sinatra', ">= 0.9.4"
14
+ gem.add_dependency 'stupid_formatter', '>= 0.1.1'
15
+ gem.add_development_dependency "shoulda", ">= 0"
16
+ gem.add_development_dependency "hpricot", ">= 0"
17
+ gem.add_development_dependency "rack-test", ">= 0"
18
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
19
+ end
20
+ Jeweler::GemcutterTasks.new
21
+ rescue LoadError
22
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
23
+ end
24
+
25
+ require 'rake/testtask'
26
+ Rake::TestTask.new(:test) do |test|
27
+ test.libs << 'lib' << 'test'
28
+ test.pattern = 'test/**/test_*.rb'
29
+ test.verbose = true
30
+ end
31
+
32
+ begin
33
+ require 'rcov/rcovtask'
34
+ Rcov::RcovTask.new do |test|
35
+ test.libs << 'test'
36
+ test.pattern = 'test/**/test_*.rb'
37
+ test.verbose = true
38
+ end
39
+ rescue LoadError
40
+ task :rcov do
41
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
42
+ end
43
+ end
44
+
45
+ task :test => :check_dependencies
46
+
47
+ task :default => :test
48
+
49
+ require 'rake/rdoctask'
50
+ Rake::RDocTask.new do |rdoc|
51
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
52
+
53
+ rdoc.rdoc_dir = 'rdoc'
54
+ rdoc.title = "serious #{version}"
55
+ rdoc.rdoc_files.include('README*')
56
+ rdoc.rdoc_files.include('lib/**/*.rb')
57
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
data/lib/serious.rb ADDED
@@ -0,0 +1,61 @@
1
+ require 'rubygems'
2
+ gem 'sinatra', '~> 0.9.4'
3
+ require 'sinatra/base'
4
+ require 'stupid_formatter'
5
+ require 'yaml'
6
+
7
+ class Serious < Sinatra::Base
8
+
9
+ set :articles, Proc.new { File.join(root, 'articles') }
10
+ set :static, true # Required to serve static files, see http://www.sinatrarb.com/configuration.html
11
+
12
+ not_found do
13
+ erb :"404"
14
+ end
15
+
16
+ helpers do
17
+ def format(text)
18
+ StupidFormatter.result(text)
19
+ end
20
+
21
+ # Helper for rendering partial _archives
22
+ def render_archived(articles)
23
+ render :erb, :'_archives', :locals => { :articles => articles }, :layout => false
24
+ end
25
+
26
+ def render_article(article, summary_only=false)
27
+ render :erb, :'_article', :locals => { :article => article, :summary_only => summary_only }, :layout => !summary_only
28
+ end
29
+ end
30
+
31
+ # Index page
32
+ get '/' do
33
+ @recent = Article.all(:limit => 3)
34
+ @archived = Article.all(:limit => 10, :offset => 3)
35
+ erb :index
36
+ end
37
+
38
+ # Specific article route
39
+ get %r{^/(\d{4})/(\d{1,2})/(\d{1,2})/([^\\]+)} do
40
+ halt 404 unless @article = Article.first(*params[:captures])
41
+ render_article @article
42
+ end
43
+
44
+ # Archives route
45
+ get %r{^/(\d{4})[/]{0,1}(\d{0,2})[/]{0,1}(\d{0,2})[/]{0,1}$} do
46
+ @selection = params[:captures].reject {|s| s.strip.length == 0 }.map {|n| n.length == 1 ? "%02d" % n : n}
47
+ @articles = Article.find(*@selection)
48
+ erb :archives
49
+ end
50
+
51
+ get "/archives" do
52
+ @articles = Article.all
53
+ erb :archives
54
+ end
55
+ end
56
+
57
+ $:.unshift File.dirname(__FILE__)
58
+ require 'serious/article'
59
+ # Set up default stupid_formatter chain
60
+ StupidFormatter.chain = [StupidFormatter::Erb, StupidFormatter::RDiscount]
61
+ Serious.set :root, Dir.getwd
@@ -0,0 +1,111 @@
1
+ #
2
+ # Backend for file-system based articles
3
+ #
4
+ class Serious::Article
5
+ class << self
6
+ #
7
+ # Returns all articles. Can be drilled down by (optional) :limit and :offset options
8
+ #
9
+ def all(options={})
10
+ options = {:limit => 10000, :offset => 0}.merge(options)
11
+ (article_paths[options[:offset]...options[:limit]+options[:offset]] || []).map {|article_path| new(article_path) }
12
+ end
13
+
14
+ #
15
+ # Retrieves the article(s) for the given arguments. The arguments must be part of the filename.
16
+ # You can give any combination, but the arguments must appear in the same order as given in the
17
+ # arguments, so find(2009, 11) works for all articles in november 2009,
18
+ # find('foo-bar') works for all articles with permalink 'foo-bar', but find(2009, 'foo-bar')
19
+ # will not return anything.
20
+ #
21
+ def find(*args)
22
+ # Reformat arguments (one-digit months and days should be converted to two-digit format)
23
+ args = args.map {|a| a.to_s =~ /^\d{1}$/ ? "%02d" % a : a }
24
+ articles = article_paths.select {|path| File.basename(path) =~ /#{args.join('-')}/i }.map {|path| new(path) }
25
+ end
26
+
27
+ #
28
+ # Find the article for given arguments (same as find), but returns only the first one
29
+ #
30
+ def first(*args)
31
+ find(*args).first
32
+ end
33
+
34
+ private
35
+
36
+ # Returns all article files in articles path
37
+ def article_paths
38
+ @article_paths ||= Dir[File.join(Serious.articles, '*')].sort.reverse
39
+ end
40
+ end
41
+
42
+ attr_reader :path, :date, :permalink
43
+
44
+ def initialize(path)
45
+ @path = path
46
+ extract_date_and_permalink!
47
+ # TODO: Add some nice error handling!
48
+ end
49
+
50
+ # Lazy-loading title accessor
51
+ def title
52
+ @title ||= yaml["title"]
53
+ end
54
+
55
+ # Cached lazy-loading of summary
56
+ def summary
57
+ return @summary if @summary
58
+ @summary ||= content.split("~", 2).first.chomp
59
+ end
60
+
61
+ # Cached lazy-loading of body
62
+ def body
63
+ return @body if @body
64
+ @body ||= content.split("~", 2).join("").chomp
65
+ end
66
+
67
+ # Compiles the url for this article
68
+ def url
69
+ "/#{date.year}/#{"%02d" % date.month}/#{"%02d" % date.day}/#{permalink}"
70
+ end
71
+
72
+ # Equality comparison
73
+ def ==(article)
74
+ path == article.path
75
+ rescue NoMethodError
76
+ false
77
+ end
78
+
79
+ private
80
+
81
+ # Will extract the date and permalink from the filename.
82
+ def extract_date_and_permalink!
83
+ match = File.basename(path).match(/(\d{4})-(\d{1,2})-(\d{1,2})-([^\.]+)/)
84
+ @date = Date.new(match[1].to_i, match[2].to_i, match[3].to_i)
85
+ @permalink = match[4]
86
+ end
87
+
88
+ #
89
+ # Will read the actual article file and store the yaml front processed in @yaml,
90
+ # the content in @content
91
+ #
92
+ def load!
93
+ return [@yaml, @content] if @yaml and @content
94
+ yaml, @content = File.read(path).split(/\n\n/, 2)
95
+ @yaml = YAML.load(yaml)
96
+ end
97
+
98
+ # Cached lazy-loading yaml config
99
+ def yaml
100
+ return @yaml if @yaml
101
+ load!
102
+ @yaml
103
+ end
104
+
105
+ # Cached lazy-loading content
106
+ def content
107
+ return @content if @content
108
+ load!
109
+ @content
110
+ end
111
+ end
data/serious.gemspec ADDED
@@ -0,0 +1,81 @@
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{serious}
8
+ s.version = "0.1.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Christoph Olszowka"]
12
+ s.date = %q{2010-02-12}
13
+ s.description = %q{Serious is a simple, file-driven blog engine inspired by toto and driven by sinatra}
14
+ s.email = %q{christoph at olszowka dot de}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README.rdoc"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ ".gitignore",
22
+ "LICENSE",
23
+ "README.rdoc",
24
+ "Rakefile",
25
+ "VERSION",
26
+ "lib/serious.rb",
27
+ "lib/serious/article.rb",
28
+ "serious.gemspec",
29
+ "test/articles/2000-01-01-disco-2000.txt",
30
+ "test/articles/2009-04-01-foo-bar.txt",
31
+ "test/articles/2009-12-11-ruby-is-the-shit.txt",
32
+ "test/articles/2009-12-24-merry-christmas.txt",
33
+ "test/helper.rb",
34
+ "test/public/css/coderay.css",
35
+ "test/public/css/serious.css",
36
+ "test/test_article.rb",
37
+ "test/test_serious.rb",
38
+ "test/views/404.erb",
39
+ "test/views/_archives.erb",
40
+ "test/views/_article.erb",
41
+ "test/views/archives.erb",
42
+ "test/views/index.erb",
43
+ "test/views/layout.erb"
44
+ ]
45
+ s.homepage = %q{http://github.com/colszowka/serious}
46
+ s.rdoc_options = ["--charset=UTF-8"]
47
+ s.require_paths = ["lib"]
48
+ s.rubygems_version = %q{1.3.5}
49
+ s.summary = %q{Serious is a simple, file-driven blog engine inspired by toto and driven by sinatra}
50
+ s.test_files = [
51
+ "test/test_serious.rb",
52
+ "test/helper.rb",
53
+ "test/test_article.rb"
54
+ ]
55
+
56
+ if s.respond_to? :specification_version then
57
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
58
+ s.specification_version = 3
59
+
60
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
61
+ s.add_runtime_dependency(%q<sinatra>, [">= 0.9.4"])
62
+ s.add_runtime_dependency(%q<stupid_formatter>, [">= 0.1.1"])
63
+ s.add_development_dependency(%q<shoulda>, [">= 0"])
64
+ s.add_development_dependency(%q<hpricot>, [">= 0"])
65
+ s.add_development_dependency(%q<rack-test>, [">= 0"])
66
+ else
67
+ s.add_dependency(%q<sinatra>, [">= 0.9.4"])
68
+ s.add_dependency(%q<stupid_formatter>, [">= 0.1.1"])
69
+ s.add_dependency(%q<shoulda>, [">= 0"])
70
+ s.add_dependency(%q<hpricot>, [">= 0"])
71
+ s.add_dependency(%q<rack-test>, [">= 0"])
72
+ end
73
+ else
74
+ s.add_dependency(%q<sinatra>, [">= 0.9.4"])
75
+ s.add_dependency(%q<stupid_formatter>, [">= 0.1.1"])
76
+ s.add_dependency(%q<shoulda>, [">= 0"])
77
+ s.add_dependency(%q<hpricot>, [">= 0"])
78
+ s.add_dependency(%q<rack-test>, [">= 0"])
79
+ end
80
+ end
81
+
@@ -0,0 +1,23 @@
1
+ title: Disco 2000
2
+
3
+ Well we were born within one hour of each other.
4
+ Our mothers said we could be sister and brother.
5
+ Your name is Deborah, Deborah.
6
+ ~
7
+ ### by Pulp
8
+
9
+ It never suited ya.
10
+ Oh they thought that when we grew up,
11
+ we'd get married, and never split up.
12
+ We never did it, although often I thought of it.
13
+ Oh Deborah, do you recall?
14
+ Your house was very small,
15
+ with wood chip on the wall.
16
+ When I came around to call,
17
+ you didn't notice me at all.
18
+ I said let's all meet up in the year 2000.
19
+ Won't it be strange when we're all fully grown.
20
+ Be there at 2 o'clock by the fountain down the road.
21
+ I never knew that you'd get married.
22
+ I would be living down here on my own on
23
+ that damp and lonely Thursday years ago.
@@ -0,0 +1,4 @@
1
+ title: Foo Bar
2
+
3
+ Baz!
4
+
@@ -0,0 +1,17 @@
1
+ title: Ruby is the shit!
2
+
3
+ Some kind of introduction and summary
4
+ ~
5
+ The number is <%= 1 + 3 %>
6
+
7
+ <% highlight do %>
8
+ #
9
+ # Will read the actual article file and store the yaml front processed in @yaml,
10
+ # the content in @content
11
+ #
12
+ def load!
13
+ return [@yaml, @content] if @yaml and @content
14
+ yaml, @content = File.read(path).split(/\n\n/, 2)
15
+ @yaml = YAML.load(yaml)
16
+ end
17
+ <% end %>
@@ -0,0 +1,5 @@
1
+ title: Merry Christmas!
2
+
3
+ Merry christmas, dear reader!
4
+ ~
5
+ Lorem ipsum dolor...
data/test/helper.rb ADDED
@@ -0,0 +1,46 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'shoulda'
4
+ require 'rack/test'
5
+ require 'hpricot'
6
+
7
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
8
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
9
+ require 'serious'
10
+
11
+ class Test::Unit::TestCase
12
+ include Rack::Test::Methods
13
+ Serious.root = File.dirname(__FILE__)
14
+ StupidFormatter.chain = [StupidFormatter::Erb, StupidFormatter::RDiscount]
15
+
16
+ def app
17
+ Serious
18
+ end
19
+
20
+ def self.should_contain_elements(count, selector)
21
+ should "contain #{count} elements in '#{selector}'" do
22
+ doc = Hpricot.parse(last_response.body)
23
+ assert_equal count, (doc/selector).size
24
+ end
25
+ end
26
+
27
+ def self.should_respond_with(status)
28
+ should "respond with #{status}" do
29
+ assert_equal status, last_response.status
30
+ end
31
+ end
32
+
33
+ def self.should_contain_text(text, selector)
34
+ should "contain '#{text}' in '#{selector}'" do
35
+ doc = Hpricot.parse(last_response.body)
36
+ assert_match /#{text}/, (doc/selector).inner_html
37
+ end
38
+ end
39
+
40
+ def self.should_not_contain_text(text, selector)
41
+ should "not contain '#{text}' in '#{selector}'" do
42
+ doc = Hpricot.parse(last_response.body)
43
+ assert_no_match /#{text}/, (doc/selector).inner_html
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,35 @@
1
+ /* Shamelessly stolen from railscasts.com - thank you Ryan! */
2
+ .CodeRay {
3
+ background-color: #232323;
4
+ border: 1px solid black;
5
+ font-family: 'Consolas', 'Inconsolata', 'Monaco', 'Courier New', 'Terminal', monospace;
6
+ line-height: 1.4;
7
+ color: #E6E0DB;
8
+ padding: 3px 5px;
9
+ overflow: auto;
10
+ font-size: 12px;
11
+ margin: 12px 0;
12
+ }
13
+ .CodeRay pre {
14
+ margin: 0px;
15
+ padding: 0px;
16
+ }
17
+
18
+ .CodeRay .an { color:#E7BE69 } /* html attribute */
19
+ .CodeRay .c { color:#BC9358; font-style: italic; } /* comment */
20
+ .CodeRay .ch { color:#509E4F } /* escaped character */
21
+ .CodeRay .cl { color:#FFF } /* class */
22
+ .CodeRay .co { color:#FFF } /* constant */
23
+ .CodeRay .fl { color:#A4C260 } /* float */
24
+ .CodeRay .fu { color:#FFC56D } /* function */
25
+ .CodeRay .gv { color:#D0CFFE } /* global variable */
26
+ .CodeRay .i { color:#A4C260 } /* integer */
27
+ .CodeRay .il { background:#151515 } /* inline code */
28
+ .CodeRay .iv { color:#D0CFFE } /* instance variable */
29
+ .CodeRay .pp { color:#E7BE69 } /* doctype */
30
+ .CodeRay .r { color:#CB7832 } /* keyword */
31
+ .CodeRay .rx { color:#A4C260 } /* regex */
32
+ .CodeRay .s { color:#A4C260 } /* string */
33
+ .CodeRay .sy { color:#6C9CBD } /* symbol */
34
+ .CodeRay .ta { color:#E7BE69 } /* html tag */
35
+ .CodeRay .pc { color:#6C9CBD } /* boolean */
@@ -0,0 +1,77 @@
1
+ body {
2
+ margin: 0 auto;
3
+ font-family: 'Baskerville', Georgia, Times, serif;
4
+ font-size: 20px;
5
+ line-height: 30px;
6
+ width: 800px;
7
+ }
8
+
9
+ div, p {
10
+ font-family: 'Baskerville', Georgia, Times, serif;
11
+ }
12
+
13
+ h1, h2, h3, h4 {
14
+ font-family: "Helvetica", "Arial", "Verdana", sans-serif;
15
+ padding: 0;
16
+ margin: 0;
17
+ }
18
+
19
+ .date {
20
+ font-style: italic;
21
+ color: #666;
22
+ }
23
+
24
+ .right {
25
+ float: right;
26
+ }
27
+
28
+ #header {
29
+ margin: 25px 0px 50px 0px;
30
+ }
31
+
32
+ #header a {
33
+ color: black;
34
+ text-decoration: none;
35
+ }
36
+
37
+ #container a {
38
+ color: black;
39
+ text-decoration: none;
40
+ }
41
+
42
+ #container a:hover {
43
+ color: #BE2805;
44
+ text-decoration: none;
45
+ }
46
+
47
+ #container ul {
48
+ list-style: none;
49
+ padding: 0;
50
+ margin; 0;
51
+ }
52
+
53
+ #container ul li {
54
+ padding: 0;
55
+ margin; 0;
56
+ }
57
+
58
+ #container ul.archives li {
59
+ margin-left: 25px;
60
+ }
61
+
62
+ #container .article {
63
+ margin-bottom: 50px;
64
+ }
65
+
66
+
67
+ #footer {
68
+ margin-top: 50px;
69
+ color: #666;
70
+ text-align: right;
71
+ font-size: 14px;
72
+ }
73
+
74
+ #footer a {
75
+ text-decoration: none;
76
+ color: black;
77
+ }
@@ -0,0 +1,255 @@
1
+ require 'helper'
2
+
3
+ class TestArticle < Test::Unit::TestCase
4
+ # ========================================================================
5
+ # Tests for all articles and limited all articles finder
6
+ # ========================================================================
7
+ context "Serious::Article.all" do
8
+ setup do
9
+ @articles = Serious::Article.all
10
+ end
11
+
12
+ should("return 4 articles") { assert_equal 4, @articles.length }
13
+ should "have only instances of Serious::Article in the collection" do
14
+ assert @articles.all? {|a| a.instance_of?(Serious::Article) }
15
+ end
16
+
17
+ should "return an existing path for all articles" do
18
+ assert @articles.all? {|a| File.exist? a.path }
19
+ end
20
+
21
+ should "have 2009-12-24 as the first article's date" do
22
+ assert_equal Date.new(2009, 12, 24), @articles.first.date
23
+ end
24
+
25
+ should "have 2000-01-01 as the last article's date" do
26
+ assert_equal Date.new(2000, 1, 1), @articles.last.date
27
+ end
28
+
29
+ should "not have instance variable @yaml set on any article" do
30
+ @articles.each do |article|
31
+ assert_nil article.instance_variable_get(:@yaml)
32
+ end
33
+ end
34
+
35
+ should "not have instance variable @content set on any article" do
36
+ @articles.each do |article|
37
+ assert_nil article.instance_variable_get(:@content)
38
+ end
39
+ end
40
+ end
41
+
42
+ context "Serious::Article.all(:limit => 2)" do
43
+ setup do
44
+ @articles = Serious::Article.all(:limit => 2)
45
+ end
46
+
47
+ should("return 2 articles") { assert_equal 2, @articles.length }
48
+
49
+ should "have 2009-12-24 as the first article's date" do
50
+ assert_equal Date.new(2009, 12, 24), @articles.first.date
51
+ end
52
+
53
+ should "have 2009-12-11 as the last article's date" do
54
+ assert_equal Date.new(2009, 12, 11), @articles.last.date
55
+ end
56
+ end
57
+
58
+ context "Serious::Article.all(:limit => 2, :offset => 2)" do
59
+ setup do
60
+ @articles = Serious::Article.all(:limit => 2, :offset => 2)
61
+ end
62
+
63
+ should("return 2 articles") { assert_equal 2, @articles.length }
64
+
65
+ should "have 2009-04-01 as the first article's date" do
66
+ assert_equal Date.new(2009, 4, 1), @articles.first.date
67
+ end
68
+
69
+ should "have 2000-01-01 as the last article's date" do
70
+ assert_equal Date.new(2000, 1, 1), @articles.last.date
71
+ end
72
+ end
73
+
74
+ context "Serious::Article.all(:limit => 50, :offset => 5)" do
75
+ should "return an empty array" do
76
+ assert_equal [], Serious::Article.all(:limit => 50, :offset => 5)
77
+ end
78
+ end
79
+
80
+ # ========================================================================
81
+ # Tests for initializer and extracting date and permalink from path
82
+ # ========================================================================
83
+ context "Serious::Article.new('2010-01-15-foo-bar.txt')" do
84
+ setup do
85
+ @article = Serious::Article.new('2010-01-15-foo-bar.txt')
86
+ end
87
+
88
+ should "return Date 2010-01-15" do
89
+ assert_equal Date.new(2010, 1, 15), @article.date
90
+ end
91
+
92
+ should "return permalink 'foo-bar'" do
93
+ assert_equal 'foo-bar', @article.permalink
94
+ end
95
+
96
+ should "return '/2010/01/15/foo-bar' as url" do
97
+ assert_equal '/2010/01/15/foo-bar', @article.url
98
+ end
99
+ end
100
+
101
+ # Making sure one-digit month and day work as well
102
+ context "Serious::Article.new('2010-1-1-foo-bar.txt')" do
103
+ setup do
104
+ @article = Serious::Article.new('2010-1-1-foo-bar.txt')
105
+ end
106
+
107
+ should "return Date 2010-01-01" do
108
+ assert_equal Date.new(2010, 1, 1), @article.date
109
+ end
110
+
111
+ should "return permalink 'foo-bar'" do
112
+ assert_equal 'foo-bar', @article.permalink
113
+ end
114
+
115
+ should "return '/2010/01/01/foo-bar' as url" do
116
+ assert_equal '/2010/01/01/foo-bar', @article.url
117
+ end
118
+ end
119
+
120
+ context "Serious::Article.new('2010-02-16-some-text-for-permalink.txt')" do
121
+ setup do
122
+ @article = Serious::Article.new('2010-02-16-some-text-for-permalink.txt')
123
+ end
124
+
125
+ should "return Date 2010-02-16" do
126
+ assert_equal Date.new(2010, 2, 16), @article.date
127
+ end
128
+
129
+ should "return permalink 'some-text-for-permalink'" do
130
+ assert_equal 'some-text-for-permalink', @article.permalink
131
+ end
132
+
133
+ should "return '/2010/02/16/some-text-for-permalink' as url" do
134
+ assert_equal '/2010/02/16/some-text-for-permalink', @article.url
135
+ end
136
+ end
137
+
138
+ # ========================================================================
139
+ # Tests for finders
140
+ # ========================================================================
141
+ context "When calling find with (2009, 12, 24, 'merry-christmas'), the returned articles" do
142
+ setup do
143
+ @articles = Serious::Article.find(2009, 12, 24, 'merry-christmas')
144
+ end
145
+
146
+ should("have a length of 1") { assert_equal 1, @articles.length}
147
+
148
+ context "the found article" do
149
+ setup { @article = @articles.first }
150
+
151
+ should "have date 2009-12-24" do
152
+ assert_equal Date.new(2009, 12, 24), @article.date
153
+ end
154
+
155
+ should "have permalink 'merry-christmas'" do
156
+ assert_equal 'merry-christmas', @article.permalink
157
+ end
158
+
159
+ should "be the same as when calling Serious::Article.first(2009, 12, 24, 'merry-christmas')" do
160
+ assert_equal @article, Serious::Article.first(2009, 12, 24, 'merry-christmas')
161
+ end
162
+ end
163
+ end
164
+
165
+ should "find article for date '2009, 12, 24' with Serious::Article.first('merry-christmas')" do
166
+ assert_equal Date.new(2009, 12, 24), Serious::Article.first('merry-christmas').date
167
+ end
168
+
169
+ should "find article for date '2009, 12, 24' with Serious::Article.first(12, 24)" do
170
+ assert_equal Date.new(2009, 12, 24), Serious::Article.first(12, 24).date
171
+ end
172
+
173
+ should "find article for date '2009, 12, 24' with Serious::Article.first('12', '24')" do
174
+ assert_equal Date.new(2009, 12, 24), Serious::Article.first('12', '24').date
175
+ end
176
+
177
+ should "find article for date '2000, 1, 1' with Serious::Article.first(2000, 1, 1)" do
178
+ assert_equal Date.new(2000, 1, 1), Serious::Article.first(2000, 1, 1).date
179
+ end
180
+
181
+ should "find article for date '2000, 1, 1' with Serious::Article.first('2000', '1', '1')" do
182
+ assert_equal Date.new(2000, 1, 1), Serious::Article.first('2000', '1', '1').date
183
+ end
184
+
185
+ should "find article for date '2000, 1, 1' with Serious::Article.first('2000', '01', '01')" do
186
+ assert_equal Date.new(2000, 1, 1), Serious::Article.first('2000', '01', '01').date
187
+ end
188
+
189
+ context "Serious::Article.find(2009, 12)" do
190
+ setup do
191
+ @articles = Serious::Article.find(2009, 12)
192
+ end
193
+
194
+ should("have found 2 articles") { assert_equal 2, @articles.length }
195
+ should "return article with permalink 'merry-christmas' first" do
196
+ assert_equal 'merry-christmas', @articles.first.permalink
197
+ end
198
+ should "return article with permalink 'ruby-is-the-shit' last" do
199
+ assert_equal 'ruby-is-the-shit', @articles.last.permalink
200
+ end
201
+ end
202
+
203
+ # ========================================================================
204
+ # Tests for dynamic loading and processing of title, summary and body
205
+ # ========================================================================
206
+ context "The article 'merry-christmas'" do
207
+ setup do
208
+ @article = Serious::Article.first('merry-christmas')
209
+ end
210
+
211
+ should "not have instance variable @yaml set" do
212
+ assert_nil @article.instance_variable_get(:@yaml)
213
+ end
214
+
215
+ should "not have instance variable @content set" do
216
+ assert_nil @article.instance_variable_get(:@content)
217
+ end
218
+
219
+ context "after getting the article's title" do
220
+ setup { @title = @article.title }
221
+
222
+ should "have returned 'Merry Christmas!'" do
223
+ assert_equal 'Merry Christmas!', @title
224
+ end
225
+
226
+ should "have initialized the @yaml instance variable to a hash" do
227
+ assert @article.instance_variable_get(:@yaml).kind_of?(Hash)
228
+ end
229
+
230
+ should "have initialized the @content instance variable to a string" do
231
+ assert @article.instance_variable_get(:@content).kind_of?(String)
232
+ end
233
+
234
+ should "have summary set to 'Merry christmas, dear reader!'" do
235
+ assert_equal 'Merry christmas, dear reader!', @article.summary
236
+ end
237
+
238
+ should 'have body set to "Merry christmas, dear reader!\n\nLorem ipsum dolor..."' do
239
+ assert_equal "Merry christmas, dear reader!\n\nLorem ipsum dolor...", @article.body
240
+ end
241
+ end
242
+ end
243
+
244
+ context "The article 'foo-bar'" do
245
+ setup do
246
+ @article = Serious::Article.first('foo-bar')
247
+ end
248
+
249
+ should("have title 'Foo Bar'") { assert_equal 'Foo Bar', @article.title }
250
+ should('have summary "Baz!"') { assert_equal "Baz!\n", @article.summary }
251
+ should('have body "Baz!"') { assert_equal "Baz!\n", @article.body }
252
+ should('have summary equal to body') { assert_equal @article.summary, @article.body}
253
+ end
254
+
255
+ end
@@ -0,0 +1,160 @@
1
+ require 'helper'
2
+
3
+ class TestSerious < Test::Unit::TestCase
4
+
5
+ # ===================================================================
6
+ # Tests for the main page
7
+ # ===================================================================
8
+ context "GET /" do
9
+ setup { get '/' }
10
+
11
+ should_respond_with 200
12
+ should_contain_elements 3, "ul#articles li"
13
+ should_contain_text "Merry Christmas!", "ul#articles li:first"
14
+ should_contain_text "Merry christmas, dear reader!", "ul#articles li:first"
15
+ should_not_contain_text "Lorem ipsum dolor...", "ul#articles li:first"
16
+
17
+ should_contain_text "Ruby is the shit!", "ul#articles"
18
+ should_contain_text "Some kind of introduction and summary", "ul#articles li"
19
+ should_not_contain_text "The number is 4", "ul#articles li"
20
+
21
+ should_contain_text "Foo Bar", "ul#articles"
22
+
23
+ should_contain_elements 1, "ul.archives li"
24
+ should_contain_text "Disco 2000", "ul.archives li:first"
25
+ end
26
+
27
+ # ===================================================================
28
+ # Tests for the Archives
29
+ # ===================================================================
30
+ context "GET /2009" do
31
+ setup { get '/2009' }
32
+
33
+ should_respond_with 200
34
+ should_contain_text "Archives for 2009", "#container h2:first"
35
+ should_contain_elements 3, "ul.archives li"
36
+ should_contain_text "Merry Christmas!", "ul.archives li:first"
37
+ should_contain_text "Ruby is the shit!", "ul.archives"
38
+ should_contain_text "Foo Bar", "ul.archives"
39
+ end
40
+
41
+ context "GET /2009/12" do
42
+ setup { get '/2009/12' }
43
+
44
+ should_respond_with 200
45
+ should_contain_text "Archives for 2009-12", "#container h2:first"
46
+ should_contain_elements 2, "ul.archives li"
47
+ should_contain_text "Merry Christmas!", "ul.archives li:first"
48
+ should_contain_text "Ruby is the shit!", "ul.archives"
49
+ end
50
+
51
+ context "GET /2009/12/11" do
52
+ setup { get '/2009/12/11' }
53
+
54
+ should_respond_with 200
55
+ should_contain_text "Archives for 2009-12-11", "#container h2:first"
56
+ should_contain_elements 1, "ul.archives li"
57
+ should_contain_text "Ruby is the shit!", "ul.archives li:first"
58
+ end
59
+
60
+ context "GET /2000/" do
61
+ setup { get '/2000' }
62
+
63
+ should_respond_with 200
64
+ should_contain_text "Archives for 2000", "#container h2:first"
65
+ should_contain_elements 1, "ul.archives li"
66
+ should_contain_text "Disco 2000", "ul.archives li:first"
67
+ end
68
+
69
+ context "GET /2005/" do
70
+ setup { get '/2005' }
71
+
72
+ should_respond_with 200
73
+ should_contain_text "Archives for 2005", "#container h2:first"
74
+ should_contain_elements 0, "ul.archives li"
75
+ end
76
+
77
+ context "GET /2000/1" do
78
+ setup { get '/2000/1' }
79
+
80
+ should_respond_with 200
81
+ should_contain_text "Archives for 2000-01", "#container h2:first"
82
+ should_contain_elements 1, "ul.archives li"
83
+ should_contain_text "Disco 2000", "ul.archives li:first"
84
+ end
85
+
86
+ context "GET /2000/1/01" do
87
+ setup { get '/2000/1/01' }
88
+
89
+ should_respond_with 200
90
+ should_contain_text "Archives for 2000-01-01", "#container h2:first"
91
+ should_contain_elements 1, "ul.archives li"
92
+ should_contain_text "Disco 2000", "ul.archives li:first"
93
+ end
94
+
95
+ context "GET /archives" do
96
+ setup { get '/archives' }
97
+
98
+ should_respond_with 200
99
+ should_contain_text "Archives", "#container h2:first"
100
+ should_contain_elements 4, "ul.archives li"
101
+ should_contain_text "Merry Christmas!", "ul.archives li:first"
102
+ should_contain_text "Ruby is the shit!", "ul.archives"
103
+ should_contain_text "Foo Bar", "ul.archives"
104
+ should_contain_text "Disco 2000", "ul.archives li:last"
105
+ end
106
+
107
+ # ===================================================================
108
+ # Tests for the article view
109
+ # ===================================================================
110
+
111
+ context "GET /2009/12/24/merry-christmas" do
112
+ setup { get '/2009/12/24/merry-christmas' }
113
+
114
+ should_respond_with 200
115
+ should_contain_text "Merry Christmas!", "#container h2:first"
116
+ should_contain_text "Merry christmas, dear reader!", ".article .body"
117
+ should_contain_text "Lorem ipsum dolor...", ".article .body"
118
+ end
119
+
120
+ context "GET /2009/12/11/ruby-is-the-shit" do
121
+ setup { get '/2009/12/11/ruby-is-the-shit' }
122
+
123
+ should_respond_with 200
124
+ should_contain_text "Ruby is the shit!", "#container h2:first"
125
+ should_contain_text "Some kind of introduction and summary", ".article .body"
126
+ # Erb should evaluate properly
127
+ should_contain_text "The number is 4", ".article .body"
128
+ end
129
+
130
+ context "GET /2000/1/1/disco-2000" do
131
+ setup { get '/2000/1/1/disco-2000' }
132
+
133
+ should_respond_with 200
134
+ should_contain_text "Disco 2000", "#container h2:first"
135
+ should_contain_text "Well we were born within one hour of each other.", ".article .body"
136
+ # Markdown should evaluate properly
137
+ should_contain_text "by Pulp", ".article .body h3:first"
138
+ end
139
+
140
+ context "GET /2009/1/1/disco-2000" do
141
+ setup { get '/2009/1/1/disco-2000' }
142
+
143
+ should_respond_with 404
144
+ should_contain_text "The requested page could not be found!", "#container h2:first"
145
+ should_not_contain_text "Well we were born within one hour of each other.", ".article .body"
146
+ end
147
+
148
+ # ===================================================================
149
+ # Tests for the public folder
150
+ # ===================================================================
151
+ context "GET /css/serious.css" do
152
+ setup { get '/css/serious.css' }
153
+ should_respond_with 200
154
+ end
155
+
156
+ context "GET /foobar.baz" do
157
+ setup { get '/foobar.baz' }
158
+ should_respond_with 404
159
+ end
160
+ end
@@ -0,0 +1 @@
1
+ <h2>The requested page could not be found!</h2>
@@ -0,0 +1,8 @@
1
+ <ul class="archives">
2
+ <% articles.each do |article| %>
3
+ <li>
4
+ <a href="<%= article.url %>"><%= article.title %></a>
5
+ <span class="date"><%= article.date %></span>
6
+ </li>
7
+ <% end %>
8
+ </ul>
@@ -0,0 +1,7 @@
1
+ <div class="article">
2
+ <span class="date right"><%= article.date %></span>
3
+ <h2><a href="<%= article.url %>"><%= article.title %></a></h2>
4
+ <div class="body">
5
+ <%= format summary_only ? article.summary : article.body %>
6
+ </div>
7
+ </div>
@@ -0,0 +1,2 @@
1
+ <h2>Archives<%= @selection ? " for " + @selection.join("-") : "" %></h2>
2
+ <%= render_archived @articles %>
@@ -0,0 +1,9 @@
1
+ <ul id="articles">
2
+ <% @recent.each do |article| %>
3
+ <li>
4
+ <%= render_article article, true %>
5
+ </li>
6
+ <% end %>
7
+ </ul>
8
+ <h3><a href="/archives">Archives</a></h3>
9
+ <%= render_archived @archived %>
@@ -0,0 +1,22 @@
1
+ <html>
2
+ <head>
3
+ <link rel="stylesheet" type="text/css" href="/css/serious.css">
4
+ <link rel="stylesheet" type="text/css" href="/css/coderay.css">
5
+ <link rel="alternate" type="application/atom+xml" title="Serious Test Layout" href="/atom.xml" />
6
+ <title>Serious Test Layout</title>
7
+ </head>
8
+
9
+ <body>
10
+ <div id="header">
11
+ <h1><a href="/">Serious Blog</a></h1>
12
+ </div>
13
+ <div id="container">
14
+ <%= yield %>
15
+ </div>
16
+
17
+ <div id="footer">
18
+ This blog is <a href="http://github.com/colszowka/serious">serious</a>
19
+ </div>
20
+ </body>
21
+ </html>
22
+
metadata ADDED
@@ -0,0 +1,130 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: serious
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Christoph Olszowka
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2010-02-12 00:00:00 +01:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: sinatra
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 0.9.4
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: stupid_formatter
27
+ type: :runtime
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 0.1.1
34
+ version:
35
+ - !ruby/object:Gem::Dependency
36
+ name: shoulda
37
+ type: :development
38
+ version_requirement:
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: "0"
44
+ version:
45
+ - !ruby/object:Gem::Dependency
46
+ name: hpricot
47
+ type: :development
48
+ version_requirement:
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: "0"
54
+ version:
55
+ - !ruby/object:Gem::Dependency
56
+ name: rack-test
57
+ type: :development
58
+ version_requirement:
59
+ version_requirements: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: "0"
64
+ version:
65
+ description: Serious is a simple, file-driven blog engine inspired by toto and driven by sinatra
66
+ email: christoph at olszowka dot de
67
+ executables: []
68
+
69
+ extensions: []
70
+
71
+ extra_rdoc_files:
72
+ - LICENSE
73
+ - README.rdoc
74
+ files:
75
+ - .document
76
+ - .gitignore
77
+ - LICENSE
78
+ - README.rdoc
79
+ - Rakefile
80
+ - VERSION
81
+ - lib/serious.rb
82
+ - lib/serious/article.rb
83
+ - serious.gemspec
84
+ - test/articles/2000-01-01-disco-2000.txt
85
+ - test/articles/2009-04-01-foo-bar.txt
86
+ - test/articles/2009-12-11-ruby-is-the-shit.txt
87
+ - test/articles/2009-12-24-merry-christmas.txt
88
+ - test/helper.rb
89
+ - test/public/css/coderay.css
90
+ - test/public/css/serious.css
91
+ - test/test_article.rb
92
+ - test/test_serious.rb
93
+ - test/views/404.erb
94
+ - test/views/_archives.erb
95
+ - test/views/_article.erb
96
+ - test/views/archives.erb
97
+ - test/views/index.erb
98
+ - test/views/layout.erb
99
+ has_rdoc: true
100
+ homepage: http://github.com/colszowka/serious
101
+ licenses: []
102
+
103
+ post_install_message:
104
+ rdoc_options:
105
+ - --charset=UTF-8
106
+ require_paths:
107
+ - lib
108
+ required_ruby_version: !ruby/object:Gem::Requirement
109
+ requirements:
110
+ - - ">="
111
+ - !ruby/object:Gem::Version
112
+ version: "0"
113
+ version:
114
+ required_rubygems_version: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - ">="
117
+ - !ruby/object:Gem::Version
118
+ version: "0"
119
+ version:
120
+ requirements: []
121
+
122
+ rubyforge_project:
123
+ rubygems_version: 1.3.5
124
+ signing_key:
125
+ specification_version: 3
126
+ summary: Serious is a simple, file-driven blog engine inspired by toto and driven by sinatra
127
+ test_files:
128
+ - test/test_serious.rb
129
+ - test/helper.rb
130
+ - test/test_article.rb