persona 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +3 -0
- data/Gemfile +4 -0
- data/README.rdoc +5 -0
- data/Rakefile +2 -0
- data/bin/persona +12 -0
- data/lib/persona/file.rb +24 -0
- data/lib/persona/page.rb +13 -0
- data/lib/persona/post.rb +38 -0
- data/lib/persona/version.rb +3 -0
- data/lib/persona.rb +78 -0
- data/lib/tasks/persona_tasks.rb +10 -0
- data/persona.gemspec +21 -0
- data/template/Gemfile +1 -0
- data/template/config/persona.yaml +4 -0
- data/template/config.ru +9 -0
- data/template/contents/pages/about.txt +5 -0
- data/template/contents/posts/1900-01-01-hello-world.txt +5 -0
- data/template/public/css/main.css +108 -0
- data/template/views/index.erb +26 -0
- data/template/views/layout.erb +41 -0
- data/template/views/not_found.erb +10 -0
- data/template/views/page.erb +4 -0
- data/template/views/post.erb +4 -0
- metadata +101 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.rdoc
ADDED
data/Rakefile
ADDED
data/bin/persona
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require File.join(File.dirname(__FILE__), "..", "lib", "tasks", "persona_tasks")
|
3
|
+
|
4
|
+
|
5
|
+
def create_site(name)
|
6
|
+
p Dir.new('.').entries
|
7
|
+
end
|
8
|
+
|
9
|
+
if (ARGV.length == 2 and ARGV[0] == 'create_site')
|
10
|
+
PersonaTasks.create_site Dir.new('.'), ARGV[1]
|
11
|
+
end
|
12
|
+
|
data/lib/persona/file.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
class File
|
4
|
+
|
5
|
+
def content_as_string
|
6
|
+
doc_started = false
|
7
|
+
metadata, data = '', ''
|
8
|
+
self.each_line do |line|
|
9
|
+
doc_started = true if line.chop == ''
|
10
|
+
if (doc_started)
|
11
|
+
data += line
|
12
|
+
else
|
13
|
+
metadata +=line
|
14
|
+
end
|
15
|
+
end
|
16
|
+
@metadata = YAML.parse(metadata)
|
17
|
+
return data
|
18
|
+
end
|
19
|
+
|
20
|
+
def metadata(name)
|
21
|
+
@metadata[name].value
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
data/lib/persona/page.rb
ADDED
data/lib/persona/post.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
class Post
|
2
|
+
|
3
|
+
attr_reader :content, :title, :author, :url, :date, :excerpt, :is_excerpt
|
4
|
+
|
5
|
+
def initialize(file_name)
|
6
|
+
f = File.open("./contents/posts/#{file_name}","r")
|
7
|
+
@content = f.content_as_string
|
8
|
+
@title = f.metadata 'title'
|
9
|
+
@author = f.metadata 'author'
|
10
|
+
@date = Date.strptime(f.metadata('date'), '%Y/%m/%d')
|
11
|
+
@excerpt = create_excerpt(@content)
|
12
|
+
|
13
|
+
splits = /(\d{4}-\d{2}-\d{2})-([^\/]*)\.txt$/.match file_name
|
14
|
+
if splits
|
15
|
+
@url = splits[1].gsub(/[-]/, "/") + "/" + splits[2] + "/"
|
16
|
+
end
|
17
|
+
|
18
|
+
f.close
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.from_url(y,m,d,name)
|
22
|
+
Post.new "#{y}-#{m}-#{d}-#{name}.txt"
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
MORE_TAG = '<!--more-->'
|
28
|
+
|
29
|
+
def create_excerpt(content)
|
30
|
+
if content.include? MORE_TAG
|
31
|
+
@is_excerpt = true
|
32
|
+
content.partition(MORE_TAG)[0] + "(... continued ...) "
|
33
|
+
else
|
34
|
+
content
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
data/lib/persona.rb
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'erb'
|
3
|
+
require 'bundler'
|
4
|
+
require 'sinatra'
|
5
|
+
require 'builder'
|
6
|
+
|
7
|
+
require File.join(File.dirname(__FILE__), './persona', 'file')
|
8
|
+
autoload :Post, 'persona/post'
|
9
|
+
autoload :Page, 'persona/page'
|
10
|
+
|
11
|
+
|
12
|
+
#ROUTES
|
13
|
+
|
14
|
+
get '/' do
|
15
|
+
@posts = load_posts
|
16
|
+
erb :index
|
17
|
+
end
|
18
|
+
|
19
|
+
get '/feed/' do
|
20
|
+
builder do |xml|
|
21
|
+
xml.instruct! :xml, :version => '1.0'
|
22
|
+
xml.rss :version => "2.0" do
|
23
|
+
xml.channel do
|
24
|
+
xml.title ($config['site']['title'])
|
25
|
+
xml.description ($config['site']['description'])
|
26
|
+
xml.link ($config['site']['url'])
|
27
|
+
|
28
|
+
load_posts.first(10).each do |post|
|
29
|
+
xml.item do
|
30
|
+
xml.title post.title
|
31
|
+
xml.link(($config['site']['url'])+"/"+post.url)
|
32
|
+
xml.description post.content
|
33
|
+
xml.pubDate post.date.strftime("%a, %d %b %Y %H:%M:%S %z")
|
34
|
+
xml.guid(($config['site']['url'])+"/"+post.url)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
get '/feed' do
|
43
|
+
redirect '/feed/'
|
44
|
+
end
|
45
|
+
|
46
|
+
get '/:y/:m/:d/:name/' do
|
47
|
+
@page = Post.from_url params[:y], params[:m], params[:d], params[:name]
|
48
|
+
erb :post
|
49
|
+
end
|
50
|
+
|
51
|
+
get '/:y/:m/:d/:name' do #wrong link, but WP supports it
|
52
|
+
redirect "/#{params[:y]}/#{params[:m]}/#{params[:d]}/#{params[:name]}/"
|
53
|
+
end
|
54
|
+
|
55
|
+
get '/pages/:name' do
|
56
|
+
@page = Page.new params[:name]
|
57
|
+
erb :page
|
58
|
+
end
|
59
|
+
|
60
|
+
error do
|
61
|
+
erb :not_found
|
62
|
+
end
|
63
|
+
|
64
|
+
not_found do
|
65
|
+
erb :not_found
|
66
|
+
end
|
67
|
+
|
68
|
+
|
69
|
+
def load_posts
|
70
|
+
posts = Dir.entries('./contents/posts').sort.reverse.reject do |it|
|
71
|
+
not it.end_with? '.txt'
|
72
|
+
end
|
73
|
+
|
74
|
+
posts.map do |it|
|
75
|
+
Post.new it
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
data/persona.gemspec
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "persona/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "persona"
|
7
|
+
s.version = Persona::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Filippo Diotalevi"]
|
10
|
+
s.email = ["filippo.diotalevi@gmail.com"]
|
11
|
+
s.homepage = "https://github.com/fdiotalevi/persona-cms"
|
12
|
+
s.summary = %q{Minimal personal content manager}
|
13
|
+
s.description = %q{A minimal personal content manager}
|
14
|
+
|
15
|
+
s.add_dependency('sinatra', '>= 1.1.0')
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
|
+
s.require_paths = ["lib"]
|
21
|
+
end
|
data/template/Gemfile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'persona'
|
data/template/config.ru
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
html { margin: 20px }
|
2
|
+
body {
|
3
|
+
margin: 0 auto;
|
4
|
+
font-family: Georgia, 'Baskerville', Times, serif;
|
5
|
+
font-size: 18px;
|
6
|
+
line-height: 27px;
|
7
|
+
padding: 15px;
|
8
|
+
width: 780px;
|
9
|
+
|
10
|
+
}
|
11
|
+
header, footer, section, article {
|
12
|
+
display: block;
|
13
|
+
}
|
14
|
+
|
15
|
+
body > header {
|
16
|
+
height: 30px;
|
17
|
+
font-size: 16px;
|
18
|
+
vertical-align: top;
|
19
|
+
margin-bottom: 60px;
|
20
|
+
}
|
21
|
+
|
22
|
+
#content {
|
23
|
+
}
|
24
|
+
#by {
|
25
|
+
font-style: italic;
|
26
|
+
margin-right: 5px;
|
27
|
+
font-size: 28px;
|
28
|
+
}
|
29
|
+
#caption {
|
30
|
+
position: absolute;
|
31
|
+
font-size: 24px;
|
32
|
+
margin: -135px 0 0 70px;
|
33
|
+
}
|
34
|
+
#path {
|
35
|
+
color: #b53131;
|
36
|
+
}
|
37
|
+
.date {
|
38
|
+
font-style: italic;
|
39
|
+
line-height: 43px;
|
40
|
+
}
|
41
|
+
a {
|
42
|
+
color: #b83000;
|
43
|
+
}
|
44
|
+
h1 a {
|
45
|
+
color: black;
|
46
|
+
text-decoration: none;
|
47
|
+
}
|
48
|
+
a:hover {
|
49
|
+
text-decoration: underline;
|
50
|
+
}
|
51
|
+
|
52
|
+
.post header {
|
53
|
+
margin-bottom: 10px;
|
54
|
+
}
|
55
|
+
.post .body p:first-child {
|
56
|
+
margin-top: 0;
|
57
|
+
}
|
58
|
+
.post .body p:last-child {
|
59
|
+
margin-bottom: 0;
|
60
|
+
}
|
61
|
+
.post {
|
62
|
+
margin-bottom: 30px;
|
63
|
+
}
|
64
|
+
.post:last-child {
|
65
|
+
margin-bottom: 10px;
|
66
|
+
}
|
67
|
+
.post p {
|
68
|
+
margin: 10px 0;
|
69
|
+
}
|
70
|
+
.post .more {
|
71
|
+
margin-top: -10px;
|
72
|
+
margin-right: 30px;
|
73
|
+
font-style: italic;
|
74
|
+
text-align: right;
|
75
|
+
}
|
76
|
+
.more a {
|
77
|
+
text-decoration: none;
|
78
|
+
}
|
79
|
+
.more a:hover { text-decoration: underline }
|
80
|
+
|
81
|
+
.spaced {
|
82
|
+
margin-bottom: 50px;
|
83
|
+
}
|
84
|
+
|
85
|
+
h1, h2, h3, h4 {
|
86
|
+
margin: 0;
|
87
|
+
font-weight: normal;
|
88
|
+
}
|
89
|
+
ul, li {
|
90
|
+
list-style-type: none;
|
91
|
+
}
|
92
|
+
code {
|
93
|
+
font-family: 'Anonymous Pro', 'Bitstream Vera Sans', 'Monaco', Courier, mono;
|
94
|
+
}
|
95
|
+
pre {
|
96
|
+
padding: 20px;
|
97
|
+
}
|
98
|
+
blockquote {
|
99
|
+
font-style: italic;
|
100
|
+
}
|
101
|
+
|
102
|
+
body > footer {
|
103
|
+
text-align: left;
|
104
|
+
margin-left: 10px;
|
105
|
+
font-style: italic;
|
106
|
+
font-size: 18px;
|
107
|
+
color: #888;
|
108
|
+
}
|
@@ -0,0 +1,26 @@
|
|
1
|
+
|
2
|
+
<% @posts.first(3).each do |page| %>
|
3
|
+
|
4
|
+
<div class="spaced">
|
5
|
+
<h1><a href="<%= page.url %>"><%= page.title %></a></h1>
|
6
|
+
<div class="date">published on <%= page.date.strftime('%b %d, %Y') %> by <%= page.author %> </div>
|
7
|
+
|
8
|
+
<%= page.excerpt %>
|
9
|
+
|
10
|
+
<% if page.is_excerpt %>
|
11
|
+
<div class="date"><a href="<%= page.url %>">Read the complete post</a></div>
|
12
|
+
<% end %>
|
13
|
+
</div>
|
14
|
+
|
15
|
+
<% end %>
|
16
|
+
|
17
|
+
<h2>Older posts</h2>
|
18
|
+
<ul>
|
19
|
+
<% if @posts.size > 3%>
|
20
|
+
<% @posts[3..-1].each do |post| %>
|
21
|
+
<li>
|
22
|
+
<a href="<%= post.url %>"><%= post.title %></a>, published on <%= post.date.strftime('%b %d, %Y') %>
|
23
|
+
</li>
|
24
|
+
<%end%>
|
25
|
+
<%end%>
|
26
|
+
</ul>
|
@@ -0,0 +1,41 @@
|
|
1
|
+
<!doctype html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<link rel="stylesheet" type="text/css" href="/css/main.css">
|
5
|
+
<link rel="alternate" type="application/atom+xml" title="feed" href="/feed/" />
|
6
|
+
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
7
|
+
<title>Filippo Diotalevi</title>
|
8
|
+
<meta name="keywords" content="startup,technology,java,ruby,rails,osgi">
|
9
|
+
<meta name="author" content="Filippo Diotalevi">
|
10
|
+
|
11
|
+
<script type="text/javascript">
|
12
|
+
|
13
|
+
var _gaq = _gaq || [];
|
14
|
+
_gaq.push(['_setAccount', 'UA-398358-5']);
|
15
|
+
_gaq.push(['_trackPageview']);
|
16
|
+
|
17
|
+
(function() {
|
18
|
+
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
|
19
|
+
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
20
|
+
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
21
|
+
})();
|
22
|
+
|
23
|
+
</script>
|
24
|
+
|
25
|
+
|
26
|
+
</head>
|
27
|
+
<body>
|
28
|
+
<header>
|
29
|
+
<a href='/'>Home</a> | <a href='/pages/about'>About</a>
|
30
|
+
</header>
|
31
|
+
|
32
|
+
<section>
|
33
|
+
<%= yield %>
|
34
|
+
</section>
|
35
|
+
<footer>
|
36
|
+
powered by Persona (unreleased yet), the minimal personal content manager
|
37
|
+
</footer>
|
38
|
+
</body>
|
39
|
+
</html>
|
40
|
+
|
41
|
+
|
metadata
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: persona
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
version: 0.0.1
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Filippo Diotalevi
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2011-01-26 00:00:00 +01:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: sinatra
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
none: false
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
segments:
|
29
|
+
- 1
|
30
|
+
- 1
|
31
|
+
- 0
|
32
|
+
version: 1.1.0
|
33
|
+
type: :runtime
|
34
|
+
version_requirements: *id001
|
35
|
+
description: A minimal personal content manager
|
36
|
+
email:
|
37
|
+
- filippo.diotalevi@gmail.com
|
38
|
+
executables:
|
39
|
+
- persona
|
40
|
+
extensions: []
|
41
|
+
|
42
|
+
extra_rdoc_files: []
|
43
|
+
|
44
|
+
files:
|
45
|
+
- .gitignore
|
46
|
+
- Gemfile
|
47
|
+
- README.rdoc
|
48
|
+
- Rakefile
|
49
|
+
- bin/persona
|
50
|
+
- lib/persona.rb
|
51
|
+
- lib/persona/file.rb
|
52
|
+
- lib/persona/page.rb
|
53
|
+
- lib/persona/post.rb
|
54
|
+
- lib/persona/version.rb
|
55
|
+
- lib/tasks/persona_tasks.rb
|
56
|
+
- persona.gemspec
|
57
|
+
- template/Gemfile
|
58
|
+
- template/config.ru
|
59
|
+
- template/config/persona.yaml
|
60
|
+
- template/contents/pages/about.txt
|
61
|
+
- template/contents/posts/1900-01-01-hello-world.txt
|
62
|
+
- template/public/css/main.css
|
63
|
+
- template/views/index.erb
|
64
|
+
- template/views/layout.erb
|
65
|
+
- template/views/not_found.erb
|
66
|
+
- template/views/page.erb
|
67
|
+
- template/views/post.erb
|
68
|
+
has_rdoc: true
|
69
|
+
homepage: https://github.com/fdiotalevi/persona-cms
|
70
|
+
licenses: []
|
71
|
+
|
72
|
+
post_install_message:
|
73
|
+
rdoc_options: []
|
74
|
+
|
75
|
+
require_paths:
|
76
|
+
- lib
|
77
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
78
|
+
none: false
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
segments:
|
83
|
+
- 0
|
84
|
+
version: "0"
|
85
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
86
|
+
none: false
|
87
|
+
requirements:
|
88
|
+
- - ">="
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
segments:
|
91
|
+
- 0
|
92
|
+
version: "0"
|
93
|
+
requirements: []
|
94
|
+
|
95
|
+
rubyforge_project:
|
96
|
+
rubygems_version: 1.3.7
|
97
|
+
signing_key:
|
98
|
+
specification_version: 3
|
99
|
+
summary: Minimal personal content manager
|
100
|
+
test_files: []
|
101
|
+
|