schreihals 0.0.2 → 0.0.3
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/.gitignore +1 -0
- data/.watchr +14 -0
- data/README.md +13 -1
- data/Rakefile +9 -4
- data/bin/schreihals +5 -0
- data/example/Gemfile +0 -4
- data/lib/schreihals.rb +13 -140
- data/lib/schreihals/actions.rb +45 -0
- data/lib/schreihals/app.rb +73 -0
- data/lib/schreihals/cli.rb +42 -0
- data/lib/schreihals/document.rb +52 -0
- data/lib/schreihals/helpers.rb +38 -0
- data/lib/schreihals/post.rb +74 -0
- data/lib/schreihals/static.rb +17 -0
- data/lib/schreihals/version.rb +1 -1
- data/lib/templates/first-post.md.tt +1 -0
- data/lib/templates/new-post.md.tt +13 -0
- data/lib/templates/new_blog/.gitignore +5 -0
- data/lib/templates/new_blog/Gemfile +3 -0
- data/lib/templates/new_blog/config.ru.tt +14 -0
- data/lib/templates/new_blog/posts/.gitkeep +0 -0
- data/lib/templates/new_blog/public/media/.gitkeep +0 -0
- data/lib/views/404.haml +3 -4
- data/lib/views/blog.scss +1 -0
- data/lib/views/index.haml +2 -3
- data/lib/views/layout.haml +13 -9
- data/lib/views/partials/_gauges.haml +12 -0
- data/lib/views/partials/_post.haml +10 -2
- data/lib/views/post.haml +2 -5
- data/lib/views/schreihals.scss +24 -12
- data/schreihals.gemspec +14 -5
- data/test/app_test.rb +68 -0
- data/test/document_test.rb +41 -0
- data/test/files/simple_document.md +7 -0
- data/test/posts/2011-12-23-first-post.md +8 -0
- data/test/posts/2011-12-24-second-post.md +8 -0
- data/test/posts/static-page.md +5 -0
- data/test/test_helper.rb +63 -0
- metadata +172 -43
- data/.rspec +0 -2
- data/spec/spec_helper.rb +0 -7
data/.gitignore
CHANGED
data/.watchr
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
def run(cmd)
|
2
|
+
puts "=== %s" % cmd
|
3
|
+
system cmd
|
4
|
+
puts "\n"
|
5
|
+
end
|
6
|
+
|
7
|
+
watch("test/.*_test\.rb") { |m| run("bundle exec ruby %s" % m[0]) }
|
8
|
+
watch("lib/schreihals/(.*)\.rb") { |m| run("bundle exec ruby test/%s_test.rb" % m[1]) }
|
9
|
+
watch('^test/test_helper\.rb') { run "rake test" }
|
10
|
+
|
11
|
+
# Ctrl-\
|
12
|
+
Signal.trap('QUIT') { run("rake test") }
|
13
|
+
# Ctrl-C
|
14
|
+
Signal.trap('INT') { abort("\nQuitting.") }
|
data/README.md
CHANGED
@@ -29,12 +29,24 @@ Just a list of keywords I need to write about:
|
|
29
29
|
* pages (= posts without dates)
|
30
30
|
* deployment (Heroku!)
|
31
31
|
* code highlighting
|
32
|
-
* `google_analytics_id`
|
32
|
+
* `google_analytics_id` and `gauges_id`
|
33
|
+
* `footer`
|
33
34
|
* `link`
|
34
35
|
* `read_more`
|
36
|
+
* `schreihals create NAME`
|
37
|
+
* `schreihals post TITLE`
|
38
|
+
* `documents_store`, `documents_source`
|
39
|
+
* `twitter_id`
|
40
|
+
* cascading views
|
35
41
|
|
36
42
|
## Version History
|
37
43
|
|
44
|
+
### development
|
45
|
+
|
46
|
+
* Add `schreihals` executable. Use it to generate new Schreihals blogs (`schreihals create <name>`) and blog posts (`schreihals post <title>`).
|
47
|
+
* Removed dependency from `data_mapper` and added our own implementation.
|
48
|
+
* The contents of the `blog_description` configuration variable are now displayed at the top of the home page. The small footer at the bottom of all pages is now being populated through the `footer` variable.
|
49
|
+
|
38
50
|
### 0.0.2
|
39
51
|
|
40
52
|
* Fix various stupid bugs from the initial release, including the broken example app. Duh!
|
data/Rakefile
CHANGED
@@ -1,7 +1,12 @@
|
|
1
1
|
#!/usr/bin/env rake
|
2
2
|
require "bundler/gem_tasks"
|
3
3
|
|
4
|
-
# integrate
|
5
|
-
require '
|
6
|
-
|
7
|
-
|
4
|
+
# integrate riot
|
5
|
+
require 'rake/testtask'
|
6
|
+
Rake::TestTask.new(:test) do |test|
|
7
|
+
test.libs << 'lib' << 'test'
|
8
|
+
test.pattern = 'test/*_test.rb'
|
9
|
+
test.verbose = true
|
10
|
+
end
|
11
|
+
|
12
|
+
task :default => :test
|
data/bin/schreihals
ADDED
data/example/Gemfile
CHANGED
@@ -3,7 +3,3 @@ source 'https://rubygems.org'
|
|
3
3
|
# In a real-world schreihals blog, remove the :path option, obviously.
|
4
4
|
#
|
5
5
|
gem 'schreihals', :path => '../'
|
6
|
-
|
7
|
-
# For the time being, we need this fork of document_mapper.
|
8
|
-
#
|
9
|
-
gem 'document_mapper', :git => 'git://github.com/hmans/document_mapper.git', :branch => "after_load_hook"
|
data/lib/schreihals.rb
CHANGED
@@ -1,155 +1,28 @@
|
|
1
1
|
require 'schreihals/version'
|
2
|
+
|
2
3
|
require 'sinatra'
|
3
4
|
require 'haml'
|
4
5
|
require 'sass'
|
5
6
|
require 'redcarpet'
|
6
7
|
require 'schnitzelstyle'
|
7
|
-
require 'document_mapper'
|
8
8
|
require 'rack-cache'
|
9
9
|
require 'coderay'
|
10
10
|
require 'rack/codehighlighter'
|
11
|
+
require 'yaml'
|
11
12
|
|
12
13
|
require 'active_support/core_ext/string/inflections'
|
14
|
+
require 'active_support/core_ext/class'
|
15
|
+
require 'active_support/concern'
|
13
16
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
#
|
21
|
-
self.attributes = {
|
22
|
-
disqus: true,
|
23
|
-
status: 'published',
|
24
|
-
summary: nil,
|
25
|
-
link: nil
|
26
|
-
}.merge(attributes)
|
27
|
-
|
28
|
-
# Set slug
|
29
|
-
#
|
30
|
-
if !attributes.has_key? :slug
|
31
|
-
begin
|
32
|
-
match = attributes[:file_name_without_extension].match(/(\d{4}-\d{1,2}-\d{1,2}[-_])?(.*)/)
|
33
|
-
attributes[:slug] = match[2]
|
34
|
-
rescue NoMethodError => err
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
def to_url
|
40
|
-
date.present? ? "/#{year}/#{month}/#{day}/#{slug}/" : "/#{slug}/"
|
41
|
-
end
|
42
|
-
|
43
|
-
def disqus_identifier
|
44
|
-
attributes[:disqus_identifier] || file_name_without_extension
|
45
|
-
end
|
46
|
-
|
47
|
-
def disqus?
|
48
|
-
disqus && published?
|
49
|
-
end
|
50
|
-
|
51
|
-
def published?
|
52
|
-
status == 'published'
|
53
|
-
end
|
54
|
-
|
55
|
-
def post?
|
56
|
-
date.present?
|
57
|
-
end
|
58
|
-
|
59
|
-
def page?
|
60
|
-
!post?
|
61
|
-
end
|
62
|
-
|
63
|
-
# load all posts.
|
64
|
-
self.directory = 'posts'
|
65
|
-
end
|
66
|
-
|
67
|
-
class App < Sinatra::Application
|
68
|
-
set :blog_title, "My Schreihals Blog"
|
69
|
-
set :blog_url, ""
|
70
|
-
set :blog_description, ""
|
71
|
-
set :author_name, "Author"
|
72
|
-
set :disqus_name, nil
|
73
|
-
set :google_analytics_id, nil
|
74
|
-
set :read_more, "Read Complete Article"
|
75
|
-
|
76
|
-
use Rack::ShowExceptions
|
77
|
-
use Rack::Cache
|
78
|
-
use Rack::Static, :urls => ["/media"], :root => "public"
|
79
|
-
use Rack::Codehighlighter, :coderay, :markdown => true, :element => "pre>code", :pattern => /\A:::(\w+)\s*\n/
|
80
|
-
|
81
|
-
helpers do
|
82
|
-
def partial(thing, locals = {})
|
83
|
-
name = case thing
|
84
|
-
when String then thing
|
85
|
-
else thing.class.to_s.demodulize.underscore
|
86
|
-
end
|
17
|
+
require 'schreihals/static'
|
18
|
+
require 'schreihals/helpers'
|
19
|
+
require 'schreihals/document'
|
20
|
+
require 'schreihals/post'
|
21
|
+
require 'schreihals/actions'
|
22
|
+
require 'schreihals/app'
|
87
23
|
|
88
|
-
|
89
|
-
|
24
|
+
Sass::Engine::DEFAULT_OPTIONS[:load_paths].unshift(File.expand_path("../views", __FILE__))
|
25
|
+
Sass::Engine::DEFAULT_OPTIONS[:load_paths].unshift(File.expand_path("./views"))
|
90
26
|
|
91
|
-
|
92
|
-
@page_title = title
|
93
|
-
end
|
94
|
-
|
95
|
-
def link_to(title, thing)
|
96
|
-
haml "%a{href: '#{url_for thing}'} #{title}"
|
97
|
-
end
|
98
|
-
|
99
|
-
def url_for(thing, options = {})
|
100
|
-
url = thing.respond_to?(:to_url) ? thing.to_url : thing.to_s
|
101
|
-
url = "#{settings.blog_url}#{url}" if options[:absolute]
|
102
|
-
url
|
103
|
-
end
|
104
|
-
|
105
|
-
def show_disqus?
|
106
|
-
settings.disqus_name.present?
|
107
|
-
end
|
108
|
-
|
109
|
-
def production?
|
110
|
-
settings.environment.to_sym == :production
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
|
-
before do
|
115
|
-
cache_control :public, :must_revalidate, :max_age => 60
|
116
|
-
end
|
117
|
-
|
118
|
-
get '/' do
|
119
|
-
@posts = Post.order_by(:date => :desc)
|
120
|
-
@posts = @posts.where(:status => 'published') if production?
|
121
|
-
@posts = @posts.limit(10).all
|
122
|
-
haml :index
|
123
|
-
end
|
124
|
-
|
125
|
-
get '/schreihals.css' do
|
126
|
-
scss :schreihals
|
127
|
-
end
|
128
|
-
|
129
|
-
get '/atom.xml' do
|
130
|
-
@posts = Post.where(:status => 'published').order_by(:date => :desc).limit(10).all
|
131
|
-
content_type 'application/xml+atom'
|
132
|
-
haml :atom, :layout => false
|
133
|
-
end
|
134
|
-
|
135
|
-
get '/:year/:month/:day/:slug/?' do |year, month, day, slug|
|
136
|
-
render_page(slug)
|
137
|
-
end
|
138
|
-
|
139
|
-
get '/:slug/?' do |slug|
|
140
|
-
render_page(slug)
|
141
|
-
end
|
142
|
-
|
143
|
-
def render_page(slug)
|
144
|
-
if @post = Post.where(:slug => slug).first
|
145
|
-
haml :post
|
146
|
-
else
|
147
|
-
halt 404
|
148
|
-
end
|
149
|
-
end
|
150
|
-
|
151
|
-
not_found do
|
152
|
-
haml :"404"
|
153
|
-
end
|
154
|
-
end
|
27
|
+
module Schreihals
|
155
28
|
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Schreihals
|
2
|
+
module Actions
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
before do
|
7
|
+
refresh_documents! if refresh_documents_now?
|
8
|
+
cache_control :public, :must_revalidate, :max_age => 60
|
9
|
+
end
|
10
|
+
|
11
|
+
get '/' do
|
12
|
+
@posts = Post.latest(published_only: production?)
|
13
|
+
|
14
|
+
@show_description = true
|
15
|
+
haml :index
|
16
|
+
end
|
17
|
+
|
18
|
+
get '/blog.css' do
|
19
|
+
scss :blog
|
20
|
+
end
|
21
|
+
|
22
|
+
get '/atom.xml' do
|
23
|
+
@posts = Post.latest(published_only: production?)
|
24
|
+
|
25
|
+
xml = haml :atom, :layout => false
|
26
|
+
|
27
|
+
doc = Nokogiri::XML(xml)
|
28
|
+
doc.css("content img").each do |node|
|
29
|
+
node['src'] = absolutionize(node['src'])
|
30
|
+
end
|
31
|
+
|
32
|
+
content_type 'application/xml+atom'
|
33
|
+
doc.to_xml
|
34
|
+
end
|
35
|
+
|
36
|
+
get '/:year/:month/:day/:slug/?' do |year, month, day, slug|
|
37
|
+
render_page(slug)
|
38
|
+
end
|
39
|
+
|
40
|
+
get '/:slug/?' do |slug|
|
41
|
+
render_page(slug)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
module Schreihals
|
2
|
+
class App < Sinatra::Base
|
3
|
+
set :views, ['./views/', File.expand_path('../../views/', __FILE__)]
|
4
|
+
set :public_folder, File.expand_path('../../public/', __FILE__)
|
5
|
+
|
6
|
+
use Schreihals::Static
|
7
|
+
use Rack::ShowExceptions
|
8
|
+
use Rack::Cache
|
9
|
+
use Rack::Codehighlighter, :coderay, :markdown => true, :element => "pre>code", :pattern => /\A:::(\w+)\s*\n/
|
10
|
+
|
11
|
+
helpers Schreihals::Helpers
|
12
|
+
include Schreihals::Actions
|
13
|
+
|
14
|
+
configure do
|
15
|
+
set :blog_title, "My Schreihals Blog"
|
16
|
+
set :blog_url, ""
|
17
|
+
set :blog_description, ""
|
18
|
+
set :author_name, "Author"
|
19
|
+
set :disqus_name, nil
|
20
|
+
set :google_analytics_id, nil
|
21
|
+
set :gauges_id, nil
|
22
|
+
set :read_more, "Read Complete Article"
|
23
|
+
set :documents_store, :filesystem
|
24
|
+
set :documents_source, './posts'
|
25
|
+
set :documents_cache, nil
|
26
|
+
set :twitter_id, nil
|
27
|
+
set :footer, ""
|
28
|
+
end
|
29
|
+
|
30
|
+
def refresh_documents_now?
|
31
|
+
!Post.documents.any?
|
32
|
+
end
|
33
|
+
|
34
|
+
def refresh_documents!
|
35
|
+
case settings.documents_store
|
36
|
+
when :filesystem
|
37
|
+
Post.load_from_directory(settings.documents_source)
|
38
|
+
# when :dropbox
|
39
|
+
# Post.load_from_dropbox(settings.documents_source)
|
40
|
+
else
|
41
|
+
raise "Unknown documents store '#{settings.documents_store}'."
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def render_page(slug)
|
46
|
+
if @post = Post.with_slug(slug)
|
47
|
+
haml :post
|
48
|
+
else
|
49
|
+
halt 404
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def absolutionize(url)
|
54
|
+
if should_absolutionize?(url)
|
55
|
+
"#{base_url}#{url}"
|
56
|
+
else
|
57
|
+
url
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def should_absolutionize?(url)
|
62
|
+
url && url[0] == '/'
|
63
|
+
end
|
64
|
+
|
65
|
+
def base_url
|
66
|
+
"#{env['rack.url_scheme']}://#{env['HTTP_HOST']}"
|
67
|
+
end
|
68
|
+
|
69
|
+
not_found do
|
70
|
+
haml :"404"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require "thor"
|
2
|
+
require 'active_support/core_ext/string/inflections'
|
3
|
+
|
4
|
+
module Schreihals
|
5
|
+
class Cli < Thor
|
6
|
+
include Thor::Actions
|
7
|
+
|
8
|
+
source_root(File.expand_path('../../templates', __FILE__))
|
9
|
+
|
10
|
+
desc "create NAME", "Creates a new Schreihals blog."
|
11
|
+
|
12
|
+
method_option :git, :aliases => "-g", :default => false,
|
13
|
+
:desc => "Initialize a git repository in your blog's directory."
|
14
|
+
|
15
|
+
method_option :bundle, :aliases => "-b", :default => false,
|
16
|
+
:desc => "Run 'bundle install' after generating your new blog."
|
17
|
+
|
18
|
+
def create(name)
|
19
|
+
@name = name
|
20
|
+
self.destination_root = name
|
21
|
+
directory 'new_blog', '.'
|
22
|
+
post('My First Post')
|
23
|
+
|
24
|
+
in_root do
|
25
|
+
run "bundle" if options[:bundle]
|
26
|
+
run "git init" if options[:git]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
desc "post TITLE", "Creates a new blog post."
|
32
|
+
|
33
|
+
def post(title)
|
34
|
+
@title = title
|
35
|
+
@date = Date.today.strftime("%Y-%m-%d")
|
36
|
+
@slug = title.downcase.gsub(/ +/,'-')
|
37
|
+
@text = "Type your post body here."
|
38
|
+
|
39
|
+
template 'new-post.md.tt', "posts/#{@date}-#{@slug}.md"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'tilt'
|
2
|
+
|
3
|
+
module Schreihals
|
4
|
+
class Document
|
5
|
+
cattr_accessor :documents
|
6
|
+
@@documents = []
|
7
|
+
|
8
|
+
attr_accessor :attributes
|
9
|
+
|
10
|
+
def initialize(attrs = {})
|
11
|
+
@attributes = attrs
|
12
|
+
@@documents << self
|
13
|
+
end
|
14
|
+
|
15
|
+
def file_extension
|
16
|
+
File.extname(file_name).sub(/^\./, '')
|
17
|
+
end
|
18
|
+
|
19
|
+
def file_name_without_extension
|
20
|
+
File.basename(file_name, '.'+file_extension)
|
21
|
+
end
|
22
|
+
|
23
|
+
def method_missing(name, *args)
|
24
|
+
attributes.has_key?(name.to_s) ? attributes[name.to_s] : super
|
25
|
+
end
|
26
|
+
|
27
|
+
def to_html
|
28
|
+
Tilt.new(file_extension) { body }.render
|
29
|
+
end
|
30
|
+
|
31
|
+
class << self
|
32
|
+
def from_string(s, attrs = {})
|
33
|
+
frontmatter, body = split_original_document(s)
|
34
|
+
new(Psych.load(frontmatter).
|
35
|
+
merge('body' => body.strip).
|
36
|
+
merge(attrs))
|
37
|
+
end
|
38
|
+
|
39
|
+
def from_file(name)
|
40
|
+
from_string(open(name).read, 'file_name' => File.basename(name))
|
41
|
+
end
|
42
|
+
|
43
|
+
def load_from_directory(dir)
|
44
|
+
Dir[File.join(dir, "*")].collect { |f| from_file f }
|
45
|
+
end
|
46
|
+
|
47
|
+
def split_original_document(s)
|
48
|
+
s =~ /.*(---\s*\n.*)\n---\s*\n(.*)/m ? [$1, $2] : [nil, s]
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|