schreihals 0.0.3 → 0.0.4
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 -1
- data/.rspec +1 -0
- data/.travis.yml +9 -0
- data/.watchr +6 -5
- data/LICENSE +2 -2
- data/README.md +2 -54
- data/Rakefile +4 -9
- data/lib/schreihals.rb +10 -9
- data/lib/schreihals/actions/admin.rb +49 -0
- data/lib/schreihals/actions/auth.rb +29 -0
- data/lib/schreihals/actions/blog.rb +68 -0
- data/lib/schreihals/app.rb +15 -43
- data/lib/schreihals/cli.rb +0 -14
- data/lib/schreihals/helpers.rb +38 -5
- data/lib/schreihals/post.rb +126 -44
- data/lib/schreihals/rake.rb +21 -0
- data/lib/schreihals/version.rb +1 -1
- data/lib/templates/new_blog/Gemfile +17 -1
- data/lib/templates/new_blog/Rakefile +2 -0
- data/lib/templates/new_blog/app.rb.tt +28 -0
- data/lib/templates/new_blog/config.ru.tt +2 -14
- data/{example/public/media → lib/templates/new_blog/public}/.gitkeep +0 -0
- data/lib/views/admin/admin.haml +12 -0
- data/lib/views/admin/edit.haml +3 -0
- data/lib/views/admin/new.haml +3 -0
- data/lib/views/atom.haml +12 -10
- data/lib/views/index.haml +3 -0
- data/lib/views/layout.haml +4 -3
- data/lib/views/partials/_admin_post_list.haml +11 -0
- data/lib/views/partials/_form_field.haml +27 -0
- data/lib/views/partials/_post.haml +16 -12
- data/lib/views/partials/_post_form.haml +12 -0
- data/lib/views/schreihals.scss +61 -25
- data/schreihals.gemspec +27 -11
- data/spec/app_spec.rb +56 -0
- data/spec/factories.rb +15 -0
- data/spec/post_spec.rb +60 -0
- data/spec/spec_helper.rb +35 -0
- data/{test → test.old}/app_test.rb +0 -0
- data/{test → test.old}/files/simple_document.md +0 -0
- data/test.old/post_test.rb +62 -0
- data/{test → test.old}/posts/2011-12-23-first-post.md +0 -0
- data/{test → test.old}/posts/2011-12-24-second-post.md +0 -0
- data/{test → test.old}/posts/static-page.md +0 -0
- data/{test → test.old}/test_helper.rb +0 -0
- metadata +158 -87
- data/example/Gemfile +0 -5
- data/example/config.ru +0 -8
- data/example/posts/2010-06-17-pythton-is-great.md +0 -9
- data/example/posts/2011-12-22-ruby-is-great.md +0 -16
- data/lib/schreihals/actions.rb +0 -45
- data/lib/schreihals/document.rb +0 -52
- data/lib/templates/first-post.md.tt +0 -1
- data/lib/templates/new-post.md.tt +0 -13
- data/lib/templates/new_blog/posts/.gitkeep +0 -0
- data/lib/templates/new_blog/public/media/.gitkeep +0 -0
- data/test/document_test.rb +0 -41
data/.gitignore
CHANGED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/.travis.yml
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
language: ruby
|
2
|
+
rvm:
|
3
|
+
- 1.9.2
|
4
|
+
- 1.9.3
|
5
|
+
#- jruby-19mode # JRuby in 1.9 mode
|
6
|
+
# - rbx-18mode
|
7
|
+
# - rbx-19mode # currently in active development, may or may not work for your project
|
8
|
+
# uncomment this line if your project needs to run something other than `rake`:
|
9
|
+
# script: bundle exec rspec spec
|
data/.watchr
CHANGED
@@ -1,14 +1,15 @@
|
|
1
|
-
def run(cmd)
|
1
|
+
def run(cmd, msg = nil)
|
2
|
+
puts "=== %s" % msg if msg
|
2
3
|
puts "=== %s" % cmd
|
3
4
|
system cmd
|
4
5
|
puts "\n"
|
5
6
|
end
|
6
7
|
|
7
|
-
watch("
|
8
|
-
watch("lib/schreihals/(.*)\.rb") { |m| run("bundle exec
|
9
|
-
watch('^
|
8
|
+
watch("spec/.*_spec\.rb") { |m| run("bundle exec rspec %s" % m[0]) }
|
9
|
+
watch("lib/schreihals/(.*)\.rb") { |m| run("bundle exec rspec spec/%s_spec.rb" % m[1]) }
|
10
|
+
watch('^spec/(spec_helper|factories)\.rb') { |f| run "bundle exec rake spec", "%s.rb has been modified" % f }
|
10
11
|
|
11
12
|
# Ctrl-\
|
12
|
-
Signal.trap('QUIT') { run("rake
|
13
|
+
Signal.trap('QUIT') { run("bundle exec rake spec") }
|
13
14
|
# Ctrl-C
|
14
15
|
Signal.trap('INT') { abort("\nQuitting.") }
|
data/LICENSE
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
Copyright (c)
|
1
|
+
Copyright (c) 2012 Hendrik Mans
|
2
2
|
|
3
3
|
MIT License
|
4
4
|
|
@@ -19,4 +19,4 @@ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
19
19
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
20
|
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
21
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
-
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
CHANGED
@@ -1,57 +1,5 @@
|
|
1
1
|
# Schreihals
|
2
2
|
|
3
|
-
|
4
|
-
Documentation is pretty minimal at the moment, so for now, how about a list of
|
5
|
-
overall design goals?
|
3
|
+
## A blogging engine for sane hackers.
|
6
4
|
|
7
|
-
|
8
|
-
|
9
|
-
* Minimal code design.
|
10
|
-
* Author your blog through git, using Markdown and friends.
|
11
|
-
* Near-zero boilerplate code in your blog project. (It's all in the gem.)
|
12
|
-
* Theme support through gems.
|
13
|
-
* No static document generation. (Not interested, there are enough engines out there that do this.)
|
14
|
-
* HAML and SASS support out of the box.
|
15
|
-
|
16
|
-
## Usage
|
17
|
-
|
18
|
-
TODO: soon
|
19
|
-
|
20
|
-
## Stuff
|
21
|
-
|
22
|
-
Just a list of keywords I need to write about:
|
23
|
-
|
24
|
-
* Configuration
|
25
|
-
* Automatic `date` and `slug` recognition
|
26
|
-
* `status` attribute and drafts
|
27
|
-
* `disqus` and `disqus_identifier` attributes
|
28
|
-
* Using different post formats (markdown, textile, haml etc.)
|
29
|
-
* pages (= posts without dates)
|
30
|
-
* deployment (Heroku!)
|
31
|
-
* code highlighting
|
32
|
-
* `google_analytics_id` and `gauges_id`
|
33
|
-
* `footer`
|
34
|
-
* `link`
|
35
|
-
* `read_more`
|
36
|
-
* `schreihals create NAME`
|
37
|
-
* `schreihals post TITLE`
|
38
|
-
* `documents_store`, `documents_source`
|
39
|
-
* `twitter_id`
|
40
|
-
* cascading views
|
41
|
-
|
42
|
-
## Version History
|
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
|
-
|
50
|
-
### 0.0.2
|
51
|
-
|
52
|
-
* Fix various stupid bugs from the initial release, including the broken example app. Duh!
|
53
|
-
* When a post or page could not be found, we now display a proper 404 page (with correct status code.)
|
54
|
-
|
55
|
-
### 0.0.1
|
56
|
-
|
57
|
-
* Initial release.
|
5
|
+
[](http://travis-ci.org/hmans/schreihals)
|
data/Rakefile
CHANGED
@@ -1,12 +1,7 @@
|
|
1
1
|
#!/usr/bin/env rake
|
2
2
|
require "bundler/gem_tasks"
|
3
3
|
|
4
|
-
# integrate
|
5
|
-
require '
|
6
|
-
|
7
|
-
|
8
|
-
test.pattern = 'test/*_test.rb'
|
9
|
-
test.verbose = true
|
10
|
-
end
|
11
|
-
|
12
|
-
task :default => :test
|
4
|
+
# integrate rspec
|
5
|
+
require 'rspec/core/rake_task'
|
6
|
+
RSpec::Core::RakeTask.new('spec')
|
7
|
+
task :default => :spec
|
data/lib/schreihals.rb
CHANGED
@@ -6,23 +6,24 @@ require 'sass'
|
|
6
6
|
require 'redcarpet'
|
7
7
|
require 'schnitzelstyle'
|
8
8
|
require 'rack-cache'
|
9
|
-
require '
|
10
|
-
require 'rack/codehighlighter'
|
11
|
-
require 'yaml'
|
9
|
+
require 'mongoid'
|
12
10
|
|
13
|
-
require 'active_support/
|
11
|
+
require 'active_support/inflector'
|
14
12
|
require 'active_support/core_ext/class'
|
15
13
|
require 'active_support/concern'
|
16
14
|
|
17
|
-
require 'schreihals/static'
|
18
|
-
require 'schreihals/helpers'
|
19
|
-
require 'schreihals/document'
|
20
|
-
require 'schreihals/post'
|
21
|
-
require 'schreihals/actions'
|
22
15
|
require 'schreihals/app'
|
23
16
|
|
24
17
|
Sass::Engine::DEFAULT_OPTIONS[:load_paths].unshift(File.expand_path("../views", __FILE__))
|
25
18
|
Sass::Engine::DEFAULT_OPTIONS[:load_paths].unshift(File.expand_path("./views"))
|
26
19
|
|
20
|
+
Mongoid.logger.level = 3
|
21
|
+
|
27
22
|
module Schreihals
|
23
|
+
mattr_reader :mongo_uri
|
24
|
+
|
25
|
+
def self.mongo_uri=(uri)
|
26
|
+
Mongoid::Config.from_hash("uri" => uri)
|
27
|
+
@@mongo_uri = uri
|
28
|
+
end
|
28
29
|
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Schreihals
|
2
|
+
module Actions
|
3
|
+
module Admin
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
before '/admin/?*' do
|
8
|
+
admin_only!
|
9
|
+
end
|
10
|
+
|
11
|
+
get '/admin/?' do
|
12
|
+
@posts = Post.published.posts.desc(:published_at)
|
13
|
+
@pages = Post.published.pages
|
14
|
+
@drafts = Post.drafts
|
15
|
+
haml :'admin/admin'
|
16
|
+
end
|
17
|
+
|
18
|
+
get '/admin/new/?' do
|
19
|
+
@post = Post.new
|
20
|
+
haml :'admin/new'
|
21
|
+
end
|
22
|
+
|
23
|
+
post '/admin/new/?' do
|
24
|
+
@post = Post.new(params[:post])
|
25
|
+
if @post.save
|
26
|
+
redirect url_for(@post)
|
27
|
+
else
|
28
|
+
haml :'admin/new'
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
get '/admin/edit/:id/?' do
|
33
|
+
@post = Post.find(params[:id])
|
34
|
+
haml :'admin/edit'
|
35
|
+
end
|
36
|
+
|
37
|
+
post '/admin/edit/:id/?' do
|
38
|
+
@post = Post.find(params[:id])
|
39
|
+
@post.attributes = params[:post]
|
40
|
+
if @post.save
|
41
|
+
redirect url_for(@post)
|
42
|
+
else
|
43
|
+
haml :'admin/edit'
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'omniauth'
|
2
|
+
require 'omniauth-browserid'
|
3
|
+
|
4
|
+
module Schreihals
|
5
|
+
module Actions
|
6
|
+
module Auth
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
included do
|
10
|
+
use OmniAuth::Strategies::BrowserID
|
11
|
+
|
12
|
+
post '/auth/:provider/callback' do
|
13
|
+
auth = request.env['omniauth.auth']
|
14
|
+
session[:user] = "#{auth['provider']}:#{auth['uid']}"
|
15
|
+
redirect admin_logged_in? ? '/admin/' : '/'
|
16
|
+
end
|
17
|
+
|
18
|
+
get '/login' do
|
19
|
+
redirect '/auth/browser_id'
|
20
|
+
end
|
21
|
+
|
22
|
+
get '/logout' do
|
23
|
+
session[:user] = nil
|
24
|
+
redirect '/'
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module Schreihals
|
2
|
+
module Actions
|
3
|
+
module Blog
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
get '/' do
|
8
|
+
# cache_for 5.minutes
|
9
|
+
@posts = Post.latest.skip(params[:page].to_i * 10).limit(10)
|
10
|
+
@show_description = true
|
11
|
+
haml :index
|
12
|
+
end
|
13
|
+
|
14
|
+
get '/blog.css' do
|
15
|
+
cache_for 1.hour
|
16
|
+
scss :blog
|
17
|
+
end
|
18
|
+
|
19
|
+
get '/index.atom' do
|
20
|
+
cache_for 3.minutes
|
21
|
+
@posts = Post.latest.limit(10)
|
22
|
+
content_type 'application/atom+xml; charset=utf-8'
|
23
|
+
haml :atom, :format => :xhtml, :layout => false
|
24
|
+
end
|
25
|
+
|
26
|
+
get '/feed/?' do
|
27
|
+
redirect settings.feed_url
|
28
|
+
end
|
29
|
+
|
30
|
+
get %r{^/(\d{4})/(\d{1,2})/?$} do
|
31
|
+
year, month = params[:captures]
|
32
|
+
@posts = Post.for_month(year.to_i, month.to_i)
|
33
|
+
haml :index
|
34
|
+
end
|
35
|
+
|
36
|
+
get %r{^/(\d{4})/?$} do
|
37
|
+
year = params[:captures].first
|
38
|
+
@posts = Post.for_year(year.to_i)
|
39
|
+
haml :index
|
40
|
+
end
|
41
|
+
|
42
|
+
get '/:year/:month/:day/:slug/?' do |year, month, day, slug|
|
43
|
+
# cache_for 1.hour
|
44
|
+
render_post(slug)
|
45
|
+
end
|
46
|
+
|
47
|
+
get '/:slug/?' do |slug|
|
48
|
+
# cache_for 1.hour
|
49
|
+
render_post(slug)
|
50
|
+
end
|
51
|
+
|
52
|
+
def render_post(slug)
|
53
|
+
|
54
|
+
if @post = Post.where(slugs: slug).first
|
55
|
+
# enforce canonical URL
|
56
|
+
if request.path != url_for(@post)
|
57
|
+
redirect url_for(@post)
|
58
|
+
else
|
59
|
+
haml :post
|
60
|
+
end
|
61
|
+
else
|
62
|
+
halt 404
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
data/lib/schreihals/app.rb
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
require 'schreihals/static'
|
2
|
+
require 'schreihals/helpers'
|
3
|
+
require 'schreihals/post'
|
4
|
+
require 'schreihals/actions/blog'
|
5
|
+
require 'schreihals/actions/auth'
|
6
|
+
require 'schreihals/actions/admin'
|
7
|
+
|
1
8
|
module Schreihals
|
2
9
|
class App < Sinatra::Base
|
3
10
|
set :views, ['./views/', File.expand_path('../../views/', __FILE__)]
|
@@ -6,64 +13,29 @@ module Schreihals
|
|
6
13
|
use Schreihals::Static
|
7
14
|
use Rack::ShowExceptions
|
8
15
|
use Rack::Cache
|
9
|
-
use Rack::
|
16
|
+
use Rack::Session::Cookie
|
10
17
|
|
11
18
|
helpers Schreihals::Helpers
|
12
|
-
include Schreihals::Actions
|
19
|
+
include Schreihals::Actions::Auth
|
20
|
+
include Schreihals::Actions::Admin
|
21
|
+
include Schreihals::Actions::Blog
|
13
22
|
|
14
23
|
configure do
|
15
24
|
set :blog_title, "My Schreihals Blog"
|
16
|
-
set :blog_url, ""
|
17
25
|
set :blog_description, ""
|
18
26
|
set :author_name, "Author"
|
19
27
|
set :disqus_name, nil
|
20
28
|
set :google_analytics_id, nil
|
21
29
|
set :gauges_id, nil
|
22
30
|
set :read_more, "Read Complete Article"
|
23
|
-
set :documents_store, :filesystem
|
24
|
-
set :documents_source, './posts'
|
25
|
-
set :documents_cache, nil
|
26
31
|
set :twitter_id, nil
|
27
32
|
set :footer, ""
|
33
|
+
set :administrator, nil
|
34
|
+
set :feed_url, '/index.atom'
|
28
35
|
end
|
29
36
|
|
30
|
-
def
|
31
|
-
|
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']}"
|
37
|
+
def cache_for(time)
|
38
|
+
cache_control :public, :must_revalidate, :max_age => time.to_i
|
67
39
|
end
|
68
40
|
|
69
41
|
not_found do
|
data/lib/schreihals/cli.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
require "thor"
|
2
|
-
require 'active_support/core_ext/string/inflections'
|
3
2
|
|
4
3
|
module Schreihals
|
5
4
|
class Cli < Thor
|
@@ -19,24 +18,11 @@ module Schreihals
|
|
19
18
|
@name = name
|
20
19
|
self.destination_root = name
|
21
20
|
directory 'new_blog', '.'
|
22
|
-
post('My First Post')
|
23
21
|
|
24
22
|
in_root do
|
25
23
|
run "bundle" if options[:bundle]
|
26
24
|
run "git init" if options[:git]
|
27
25
|
end
|
28
26
|
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
27
|
end
|
42
28
|
end
|
data/lib/schreihals/helpers.rb
CHANGED
@@ -4,6 +4,10 @@ module Schreihals
|
|
4
4
|
Array(views).each { |v| super(v, name, engine, &block) }
|
5
5
|
end
|
6
6
|
|
7
|
+
def base_url
|
8
|
+
"#{env['rack.url_scheme']}://#{env['HTTP_HOST']}/"
|
9
|
+
end
|
10
|
+
|
7
11
|
def partial(thing, locals = {})
|
8
12
|
name = case thing
|
9
13
|
when String then thing
|
@@ -17,13 +21,9 @@ module Schreihals
|
|
17
21
|
@page_title = title
|
18
22
|
end
|
19
23
|
|
20
|
-
def link_to(title, thing)
|
21
|
-
haml "%a{href: '#{url_for thing}'} #{title}"
|
22
|
-
end
|
23
|
-
|
24
24
|
def url_for(thing, options = {})
|
25
25
|
url = thing.respond_to?(:to_url) ? thing.to_url : thing.to_s
|
26
|
-
url = "#{
|
26
|
+
url = "#{base_url.sub(/\/$/, '')}#{url}" if options[:absolute]
|
27
27
|
url
|
28
28
|
end
|
29
29
|
|
@@ -34,5 +34,38 @@ module Schreihals
|
|
34
34
|
def production?
|
35
35
|
settings.environment.to_sym == :production
|
36
36
|
end
|
37
|
+
|
38
|
+
def user_logged_in?
|
39
|
+
session[:user].present?
|
40
|
+
end
|
41
|
+
|
42
|
+
def admin_logged_in?
|
43
|
+
user_logged_in? && session[:user] == settings.administrator
|
44
|
+
end
|
45
|
+
|
46
|
+
def admin_only!
|
47
|
+
redirect '/login' unless admin_logged_in?
|
48
|
+
end
|
49
|
+
|
50
|
+
def form_field(object, attribute, options = {})
|
51
|
+
options = {
|
52
|
+
label: attribute.to_s.humanize,
|
53
|
+
value: object.send(attribute),
|
54
|
+
errors: object.errors[attribute.to_sym],
|
55
|
+
class_name: object.class.to_s.demodulize.underscore
|
56
|
+
}.merge(options)
|
57
|
+
|
58
|
+
options[:name] ||= "#{options[:class_name]}[#{attribute}]"
|
59
|
+
options[:id] ||= object.new_record? ?
|
60
|
+
"new_#{options[:class_name]}_#{attribute}" :
|
61
|
+
"#{options[:class_name]}_#{object.id}_#{attribute}"
|
62
|
+
|
63
|
+
options[:type] ||= case options[:value]
|
64
|
+
when DateTime, Time, Date then :datetime
|
65
|
+
else :text
|
66
|
+
end
|
67
|
+
|
68
|
+
partial 'form_field', object: object, attribute: attribute, options: options
|
69
|
+
end
|
37
70
|
end
|
38
71
|
end
|