siterest 0.1.0.pre1
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/Gemfile +9 -0
- data/Gemfile.lock +38 -0
- data/Rakefile +23 -0
- data/VERSION +1 -0
- data/bin/siterest +10 -0
- data/config.ru +6 -0
- data/lib/encoded_attachment/.gitignore +7 -0
- data/lib/encoded_attachment/Gemfile +11 -0
- data/lib/encoded_attachment/LICENSE +20 -0
- data/lib/encoded_attachment/README.md +107 -0
- data/lib/encoded_attachment/Rakefile +41 -0
- data/lib/encoded_attachment/encoded_attachment.gemspec +23 -0
- data/lib/encoded_attachment/lib/activerecord/base.rb +63 -0
- data/lib/encoded_attachment/lib/activeresource/base.rb +121 -0
- data/lib/encoded_attachment/lib/activeresource/connection.rb +7 -0
- data/lib/encoded_attachment/lib/encoded_attachment/version.rb +3 -0
- data/lib/encoded_attachment/lib/encoded_attachment.rb +47 -0
- data/lib/encoded_attachment/test/active_record_test.rb +136 -0
- data/lib/encoded_attachment/test/active_resource_test.rb +276 -0
- data/lib/encoded_attachment/test/avatars/.gitignore +0 -0
- data/lib/encoded_attachment/test/config/database.yml +19 -0
- data/lib/encoded_attachment/test/config/schema.rb +17 -0
- data/lib/encoded_attachment/test/fixtures/kitten.jpg +0 -0
- data/lib/encoded_attachment/test/fixtures/tapir.jpg +0 -0
- data/lib/encoded_attachment/test/test_helper.rb +73 -0
- data/lib/siterest/asset.rb +27 -0
- data/lib/siterest/client.rb +149 -0
- data/lib/siterest/command.rb +105 -0
- data/lib/siterest/server.rb +58 -0
- data/lib/siterest/site.rb +6 -0
- data/lib/siterest/template/filters/core_filters.rb +57 -0
- data/lib/siterest/template/filters/datetime_filters.rb +8 -0
- data/lib/siterest/template/filters/url_filters.rb +82 -0
- data/lib/siterest/template/objects/article.rb +35 -0
- data/lib/siterest/template/objects/page.rb +71 -0
- data/lib/siterest/template/objects/site.rb +51 -0
- data/lib/siterest/template.rb +6 -0
- data/lib/siterest/user.rb +6 -0
- data/lib/siterest.rb +56 -0
- data/lib/upfile.rb +51 -0
- data/readme.md +86 -0
- data/site/data/articles/2008-04-24-my-first-blog-post.md +12 -0
- data/site/data/pages/about-us/something.md +0 -0
- data/site/data/pages/about-us.md +12 -0
- data/site/data/pages/contact.md +12 -0
- data/site/data/pages/home.md +14 -0
- data/site/data/site.yaml +2 -0
- data/siterest.gemspec +101 -0
- metadata +203 -0
@@ -0,0 +1,149 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'stringio'
|
3
|
+
require 'pp'
|
4
|
+
|
5
|
+
module Siterest
|
6
|
+
class Client
|
7
|
+
def pull_templates(site)
|
8
|
+
reset_path(templates_path)
|
9
|
+
|
10
|
+
results = []
|
11
|
+
page = 1
|
12
|
+
|
13
|
+
while page == 1 || results.size > 0
|
14
|
+
results = Template.all(:params => {:subdomain => site, :page => page}).each do |template|
|
15
|
+
filename = templates_path + template.name
|
16
|
+
|
17
|
+
File.open(filename, 'w') do |f|
|
18
|
+
f.write(template.source)
|
19
|
+
end
|
20
|
+
|
21
|
+
puts "Downloaded #{filename}"
|
22
|
+
end
|
23
|
+
|
24
|
+
page += 1
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
def pull_assets(site)
|
31
|
+
reset_path(
|
32
|
+
[assets_path + 'images', assets_path + 'javascripts', assets_path + 'stylesheets']
|
33
|
+
)
|
34
|
+
|
35
|
+
results = []
|
36
|
+
page = 1
|
37
|
+
|
38
|
+
while page == 1 || results.size > 0
|
39
|
+
results = Asset.all(:params => {:subdomain => site, :page => page}).each do |asset|
|
40
|
+
file = asset.to_file
|
41
|
+
if file.size > 0
|
42
|
+
mode = asset.binary? ? 'wb' : 'w'
|
43
|
+
filename = assets_path + asset.path.split('/').slice(2..-1).join('/')
|
44
|
+
|
45
|
+
File.open(filename, mode) do |f|
|
46
|
+
f.write(file.read)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
puts "Downloaded #{asset.id} #{filename}"
|
51
|
+
end
|
52
|
+
|
53
|
+
page += 1
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
def push_templates(site)
|
59
|
+
|
60
|
+
Dir.glob("templates/*").each do |filename|
|
61
|
+
basename = File.basename(filename)
|
62
|
+
source = File.read(filename)
|
63
|
+
|
64
|
+
existing = Template.first(:params => {
|
65
|
+
:subdomain => site,
|
66
|
+
:search => {:name_eq => basename}
|
67
|
+
})
|
68
|
+
|
69
|
+
if existing
|
70
|
+
existing.update_attributes(:source => source, :subdomain => site)
|
71
|
+
else
|
72
|
+
Template.create(
|
73
|
+
:subdomain => site,
|
74
|
+
:name => basename,
|
75
|
+
:source => source
|
76
|
+
)
|
77
|
+
end
|
78
|
+
|
79
|
+
puts "#{existing ? 'Updated' : 'Created'} #{filename}"
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
|
84
|
+
def push_assets(site)
|
85
|
+
require 'siterest/asset'
|
86
|
+
|
87
|
+
Dir.glob("assets/*/*").each do |filename|
|
88
|
+
file = open(filename)
|
89
|
+
# puts file
|
90
|
+
#
|
91
|
+
# io = StringIO.new(open(file).read)
|
92
|
+
# io.original_filename = File.basename(file)
|
93
|
+
#
|
94
|
+
existing = Asset.first(:params => {
|
95
|
+
:subdomain => site, :search => {:data_file_name_eq => File.basename(filename)}
|
96
|
+
})
|
97
|
+
|
98
|
+
if existing
|
99
|
+
existing.data = file
|
100
|
+
existing.save
|
101
|
+
else
|
102
|
+
Asset.create(:data => file, :subdomain => site, :layout => true)
|
103
|
+
end
|
104
|
+
|
105
|
+
puts "#{existing ? 'Updated' : 'Created'} #{filename}"
|
106
|
+
end
|
107
|
+
#
|
108
|
+
# asset = Asset.new(:subdomain => site)
|
109
|
+
# new_path = asset.send(:new_element_path).to_s
|
110
|
+
# collection_path = asset.send(:collection_path).to_s
|
111
|
+
#
|
112
|
+
# puts Siterest.url.to_s
|
113
|
+
#
|
114
|
+
#
|
115
|
+
# resource = RestClient::Resource.new(Siterest.url.gsub('//', "//#{Siterest.token}:x@"))
|
116
|
+
#
|
117
|
+
# resource[collection_path].post :content_type => 'application/xml', :asset => {:data => open('assets/images/bg.png'), :layout => true}
|
118
|
+
|
119
|
+
# RestClient.post 'http://localhost:3000/foo', fields_hash.merge(:file => File.new('/path/to/file'))
|
120
|
+
|
121
|
+
#
|
122
|
+
# Dir.glob("site/assets/*/*").each do |file|
|
123
|
+
# Asset.create(
|
124
|
+
# :data => open(file)
|
125
|
+
# :subdomain => site
|
126
|
+
# )
|
127
|
+
# end
|
128
|
+
end
|
129
|
+
|
130
|
+
def request_path
|
131
|
+
|
132
|
+
end
|
133
|
+
|
134
|
+
private
|
135
|
+
def templates_path
|
136
|
+
Pathname.new(Dir.pwd) + 'templates'
|
137
|
+
end
|
138
|
+
|
139
|
+
def assets_path
|
140
|
+
Pathname.new(Dir.pwd) + 'assets'
|
141
|
+
end
|
142
|
+
|
143
|
+
def reset_path(path)
|
144
|
+
FileUtils.rm_rf(path)
|
145
|
+
FileUtils.mkdir_p(path)
|
146
|
+
end
|
147
|
+
|
148
|
+
end
|
149
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
module Siterest
|
2
|
+
class Command
|
3
|
+
attr_accessor :input, :output, :command, :args
|
4
|
+
|
5
|
+
def initialize(input=STDIN, output=STDOUT, *args)
|
6
|
+
@input = input
|
7
|
+
@output = output
|
8
|
+
self.command, *self.args = args
|
9
|
+
|
10
|
+
self.command ||= 'render'
|
11
|
+
|
12
|
+
|
13
|
+
end
|
14
|
+
|
15
|
+
def put(string, newline=true)
|
16
|
+
@output.print(newline ? string + "\n" : string)
|
17
|
+
end
|
18
|
+
|
19
|
+
def run!
|
20
|
+
puts Dir.pwd
|
21
|
+
puts "#{self.command} Command"
|
22
|
+
|
23
|
+
unless File.exist?(config_file)
|
24
|
+
config
|
25
|
+
else
|
26
|
+
self.send(command)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def render
|
31
|
+
Thread.new { Launchy.open("http://localhost:8888") }
|
32
|
+
Server.run! :host => 'localhost', :port => 8888
|
33
|
+
end
|
34
|
+
|
35
|
+
def config
|
36
|
+
put "Let's setup your SiteRest, visit follow url if you don't have a account"
|
37
|
+
put "http://www.siterest.com"
|
38
|
+
|
39
|
+
put "API token: ", false
|
40
|
+
token = input.gets.chomp
|
41
|
+
|
42
|
+
put "Server (default: http://api.siterest.com): ", false
|
43
|
+
server = input.gets.chomp
|
44
|
+
|
45
|
+
server = server == '' ? 'http://api.siterest.com' : server
|
46
|
+
|
47
|
+
save_config(:api_token => token, :server_url => server)
|
48
|
+
end
|
49
|
+
|
50
|
+
def setup
|
51
|
+
FileUtils.cp_r(File.dirname(__FILE__) + '/../../site/data', 'data')
|
52
|
+
end
|
53
|
+
|
54
|
+
def pull
|
55
|
+
site = self.args.shift
|
56
|
+
|
57
|
+
client.pull_templates(site)
|
58
|
+
client.pull_assets(site)
|
59
|
+
end
|
60
|
+
|
61
|
+
def push
|
62
|
+
site = self.args.shift
|
63
|
+
|
64
|
+
put "Are you sure you want to overwrite your site design(type in yes)"
|
65
|
+
|
66
|
+
put "[yes|no]: ", false
|
67
|
+
answer = input.gets.chomp
|
68
|
+
|
69
|
+
if answer == 'yes'
|
70
|
+
put "Pushing templates..."
|
71
|
+
|
72
|
+
client.push_templates(site)
|
73
|
+
|
74
|
+
put "Pushing site assets..."
|
75
|
+
|
76
|
+
client.push_assets(site)
|
77
|
+
else
|
78
|
+
put 'May be next time'
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
|
83
|
+
def client
|
84
|
+
Client.new
|
85
|
+
end
|
86
|
+
|
87
|
+
def home_directory
|
88
|
+
ENV['HOME']
|
89
|
+
end
|
90
|
+
|
91
|
+
def config_file
|
92
|
+
"#{ENV['HOME']}/.siterest/config.yml"
|
93
|
+
end
|
94
|
+
|
95
|
+
def save_config(config)
|
96
|
+
File.open(config_file, "w") do|file|
|
97
|
+
file.puts(config.to_yaml)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def load_config
|
102
|
+
YAML.load_file(config_file)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'sinatra/base'
|
3
|
+
require 'cgi'
|
4
|
+
|
5
|
+
# require 'h2o'
|
6
|
+
# require 'yaml'
|
7
|
+
# require 'rdiscount'
|
8
|
+
# require 'ostruct'
|
9
|
+
|
10
|
+
module Siterest
|
11
|
+
class Server < Sinatra::Base
|
12
|
+
set :public, 'assets'
|
13
|
+
|
14
|
+
get '/' do
|
15
|
+
render_h2o 'home.html', :page => Page.find('home')
|
16
|
+
end
|
17
|
+
|
18
|
+
get %r{/(news|blog)} do
|
19
|
+
render_h2o 'list.html', :collection => Article.all
|
20
|
+
end
|
21
|
+
|
22
|
+
get %r{^/(\d{4})(?:/(\d{2}))$} do
|
23
|
+
year, month = params[:captures]
|
24
|
+
|
25
|
+
results = Article.all.find_all do |a|
|
26
|
+
puts a.published_at
|
27
|
+
|
28
|
+
a.published_at.year == year.to_i && a.published_at.month == month.to_i
|
29
|
+
end
|
30
|
+
|
31
|
+
render_h2o 'list.html', :collection => results
|
32
|
+
end
|
33
|
+
|
34
|
+
get '/tags/:tag' do
|
35
|
+
results = Article.all.find_all do |a|
|
36
|
+
a.tags.include?(params[:tag])
|
37
|
+
end
|
38
|
+
|
39
|
+
render_h2o 'list.html', :collection => results
|
40
|
+
end
|
41
|
+
|
42
|
+
get '/:year/:month/:permalink' do
|
43
|
+
render_h2o 'article.html', :page => Article.find(request.path_info[1..-1])
|
44
|
+
end
|
45
|
+
|
46
|
+
get '/:permalink' do
|
47
|
+
render_h2o 'page.html', :page => Page.find(params[:permalink])
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def render_h2o(template, context = {})
|
53
|
+
global = {
|
54
|
+
:site => Site.new(YAML.load_file('data/site.yaml'))
|
55
|
+
}
|
56
|
+
template = H2o::Template.new("templates/#{template}")
|
57
|
+
template.render global.merge(context)
|
58
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module CoreFilters
|
2
|
+
|
3
|
+
# String filters
|
4
|
+
def upper string
|
5
|
+
string.to_s.upcase
|
6
|
+
end
|
7
|
+
|
8
|
+
def lower string
|
9
|
+
string.to_s.downcase
|
10
|
+
end
|
11
|
+
|
12
|
+
def capitalize string
|
13
|
+
string.to_s.capitalize
|
14
|
+
end
|
15
|
+
|
16
|
+
def escape string, attribute=false
|
17
|
+
string = string.dup.to_s
|
18
|
+
|
19
|
+
{
|
20
|
+
'&' => '&',
|
21
|
+
'>' => '>',
|
22
|
+
'<' => '<'
|
23
|
+
}.each do |v, k|
|
24
|
+
string.tr!(v, k)
|
25
|
+
end
|
26
|
+
|
27
|
+
string.gsub!(/"/, '"') if attribute
|
28
|
+
|
29
|
+
string
|
30
|
+
end
|
31
|
+
|
32
|
+
# Array Filters
|
33
|
+
def join(list, delimiter=', ')
|
34
|
+
list.join(delimiter)
|
35
|
+
end
|
36
|
+
|
37
|
+
def first(list)
|
38
|
+
list.first
|
39
|
+
end
|
40
|
+
|
41
|
+
def last(list)
|
42
|
+
list.last
|
43
|
+
end
|
44
|
+
|
45
|
+
#String Filters
|
46
|
+
# def raw(stringish)
|
47
|
+
# stringish.to_s.html_safe
|
48
|
+
# end
|
49
|
+
|
50
|
+
#sliding Filters
|
51
|
+
# def sliding_it(content)
|
52
|
+
# content.split(/<h2>/).delete_if(&:blank?).map{|a| "<h2>" + a}
|
53
|
+
# end
|
54
|
+
|
55
|
+
|
56
|
+
H2o::Filters << self
|
57
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module UrlFilters
|
2
|
+
|
3
|
+
def base_url(path = '')
|
4
|
+
asset_url(path)
|
5
|
+
end
|
6
|
+
|
7
|
+
def asset_url(path = '')
|
8
|
+
assets_path + path
|
9
|
+
end
|
10
|
+
|
11
|
+
def css_tag(stylesheet, attributes = {})
|
12
|
+
attributes = {
|
13
|
+
'media' => "screen", 'rel' => "stylesheet", 'type' => "text/css"
|
14
|
+
}.merge(attributes)
|
15
|
+
source = <<-css
|
16
|
+
<link href="#{asset_url + stylesheet}" #{html_attr_for(attributes)} />
|
17
|
+
css
|
18
|
+
|
19
|
+
source.lstrip
|
20
|
+
end
|
21
|
+
|
22
|
+
def script_tag(script)
|
23
|
+
source = <<-src
|
24
|
+
<script src="#{asset_url + script}" type="text/javascript"></script>
|
25
|
+
src
|
26
|
+
|
27
|
+
source.lstrip
|
28
|
+
end
|
29
|
+
|
30
|
+
def image_tag(image, attributes = {})
|
31
|
+
source = <<-img
|
32
|
+
<img src="#{asset_url + image}" #{html_attr_for(attributes)}/>
|
33
|
+
img
|
34
|
+
|
35
|
+
source.lstrip
|
36
|
+
end
|
37
|
+
|
38
|
+
def links_to(anchor, object, attributes = {})
|
39
|
+
if object.is_a? String
|
40
|
+
url = object
|
41
|
+
elsif object.respond_to?(:url)
|
42
|
+
url = object.url
|
43
|
+
end
|
44
|
+
|
45
|
+
attributes.merge!(:href => url)
|
46
|
+
|
47
|
+
"<a #{html_attr_for(attributes)}>#{anchor}</a>"
|
48
|
+
end
|
49
|
+
|
50
|
+
# Paginate collection
|
51
|
+
# * <tt>:previous_label</tt> -- default: "« Previous" (this parameter is called <tt>:prev_label</tt> in versions <b>2.3.2</b> and older!)
|
52
|
+
# * <tt>:next_label</tt> -- default: "Next »"
|
53
|
+
# * <tt>:page_links</tt> -- when false, only previous/next links are rendered (default: true)
|
54
|
+
# * <tt>:inner_window</tt> -- how many links are shown around the current page (default: 4)
|
55
|
+
# * <tt>:outer_window</tt> -- how many links are around the first and the last page (default: 1)
|
56
|
+
# * <tt>:separator</tt> -- string separator for page HTML elements (default: single space)
|
57
|
+
#
|
58
|
+
def paginate(collection, options = {})
|
59
|
+
options[:request_uri] = @context.resolve(:request_uri)
|
60
|
+
Paginator.new.will_paginate(collection, options)
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
def html_attr_for(attributes = {})
|
65
|
+
attrs = attributes.inject([]) do |attr, (key, value)|
|
66
|
+
attr << "#{key}=\"#{value}\""
|
67
|
+
end
|
68
|
+
|
69
|
+
attrs.join(' ')
|
70
|
+
end
|
71
|
+
|
72
|
+
def assets_path
|
73
|
+
'/'
|
74
|
+
end
|
75
|
+
|
76
|
+
H2o::Filters << self
|
77
|
+
end
|
78
|
+
#
|
79
|
+
# class Paginator
|
80
|
+
# include ActionView::Helpers::TagHelper
|
81
|
+
# include WillPaginate::H2oCompatible::ViewHelpers
|
82
|
+
# end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
|
2
|
+
class Article < OpenStruct
|
3
|
+
h2o_expose :title, :body, :excerpt, :author_name, :url, :permalink, :created_at, :published_at
|
4
|
+
|
5
|
+
def self.all
|
6
|
+
Dir.glob("data/articles/*.md").map do |path|
|
7
|
+
build(path)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.find(url)
|
12
|
+
year, month, permalink = url.split('/')
|
13
|
+
pattern = "data/articles/#{year}-#{month}-*-#{permalink}.md"
|
14
|
+
|
15
|
+
path = Dir.glob(pattern).first or raise "Article not found"
|
16
|
+
|
17
|
+
return build(path)
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.build(path)
|
21
|
+
if path =~ %r(data/articles/(\d{4})-(\d{2})-(\d{2})-(.+).md)
|
22
|
+
year, month, day, permalink = $1, $2, $3, $4
|
23
|
+
end
|
24
|
+
|
25
|
+
attributes = Page.build_content(path).merge(
|
26
|
+
'published_at' => Time.local(year, month, day),
|
27
|
+
'url' => "/" + [year, month, permalink].join('/'),
|
28
|
+
'permalink' => permalink
|
29
|
+
)
|
30
|
+
|
31
|
+
self.new attributes
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
|
@@ -0,0 +1,71 @@
|
|
1
|
+
class Page < OpenStruct
|
2
|
+
h2o_expose :title, :body, :url, :permalink, :created_at, :published_at, :children
|
3
|
+
|
4
|
+
def self.all
|
5
|
+
cache = {}
|
6
|
+
pages = recursive_build('data/pages', cache).uniq
|
7
|
+
|
8
|
+
homepage = pages.find{|p| p.permalink == 'home'}
|
9
|
+
|
10
|
+
subpages = pages - [homepage]
|
11
|
+
homepage.children = subpages
|
12
|
+
|
13
|
+
pages
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.recursive_build(start_path, cache)
|
17
|
+
Dir.glob("#{start_path}/*").map do |path|
|
18
|
+
if File.directory?(path)
|
19
|
+
page = cache[path + '.md'] = build(path + '.md')
|
20
|
+
page.children = recursive_build(path, cache)
|
21
|
+
elsif !cache[path]
|
22
|
+
page = cache[path] = build(path)
|
23
|
+
else
|
24
|
+
page = cache[path]
|
25
|
+
end
|
26
|
+
page
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.build(path)
|
31
|
+
attributes = build_content(path)
|
32
|
+
url = path.gsub(%r(data/pages/(.+).md)){|m| $1 }
|
33
|
+
permalink = url.split('/').last
|
34
|
+
|
35
|
+
self.new attributes.merge(:url => url, :permalink => permalink)
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.find(permalink)
|
39
|
+
path = Dir.glob("data/pages/#{permalink}.md").first or raise "Page not found"
|
40
|
+
|
41
|
+
attributes = build_content(path)
|
42
|
+
url = path.gsub(%r(data/pages/(.+).md)){|m| $1 }
|
43
|
+
permalink = url.split('/').last
|
44
|
+
|
45
|
+
if permalink == 'home'
|
46
|
+
permalink = nil
|
47
|
+
url = ''
|
48
|
+
end
|
49
|
+
|
50
|
+
url = "/" + url
|
51
|
+
|
52
|
+
self.new attributes.merge(:url => url, :permalink => permalink)
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.build_content(filename)
|
56
|
+
source = File.read(filename)
|
57
|
+
meta, content = source.split(/---\n(.+?)---/sm)[1,2]
|
58
|
+
|
59
|
+
if meta
|
60
|
+
attributes = YAML.load(meta)
|
61
|
+
else
|
62
|
+
attributes = {}
|
63
|
+
end
|
64
|
+
|
65
|
+
attributes.merge(
|
66
|
+
'body' => content && RDiscount.new(content).to_html,
|
67
|
+
'published_at' => attributes['published_at'] || File.mtime(filename)
|
68
|
+
)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
@@ -0,0 +1,51 @@
|
|
1
|
+
class Site < OpenStruct
|
2
|
+
h2o_expose :title, :subdomain, :url, :about, :created_at, :homepage,
|
3
|
+
:articles, :latest_articles, :archives, :tag_cloud
|
4
|
+
|
5
|
+
def homepage
|
6
|
+
@homepage ||= self.pages.find{|p| p.permalink == 'home'}
|
7
|
+
end
|
8
|
+
|
9
|
+
def articles
|
10
|
+
@articles ||= Article.all
|
11
|
+
end
|
12
|
+
alias latest_articles articles
|
13
|
+
|
14
|
+
def pages
|
15
|
+
@pages ||= Page.all
|
16
|
+
end
|
17
|
+
|
18
|
+
def archives
|
19
|
+
Dir.glob("data/articles/*.md").map do |path|
|
20
|
+
|
21
|
+
if path =~ %r(data/articles/(\d{4})-(\d{2})-(\d{2})-(.+).md)
|
22
|
+
year, month, day, permalink = $1.to_i, $2.to_i, $3.to_i, $4
|
23
|
+
end
|
24
|
+
|
25
|
+
date = Date.new(year, month, day)
|
26
|
+
|
27
|
+
{
|
28
|
+
:date => date,
|
29
|
+
:url => "/#{date.strftime('%Y/%m')}"
|
30
|
+
}
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def tag_cloud
|
35
|
+
tags = {}
|
36
|
+
self.articles.map(&:tags).flatten.map do |t|
|
37
|
+
tags[t] ||= 0
|
38
|
+
tags[t] += 1
|
39
|
+
end
|
40
|
+
|
41
|
+
tags.map do |key, value|
|
42
|
+
{
|
43
|
+
:name => key,
|
44
|
+
:count => value,
|
45
|
+
:url => "/tags/#{CGI.escape(key)}"
|
46
|
+
}
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
|
data/lib/siterest.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
|
3
|
+
require "bundler"
|
4
|
+
Bundler.setup
|
5
|
+
|
6
|
+
require 'yaml'
|
7
|
+
require 'h2o'
|
8
|
+
require 'launchy'
|
9
|
+
require 'active_resource'
|
10
|
+
require 'rest_client'
|
11
|
+
require 'yaml'
|
12
|
+
require 'rdiscount'
|
13
|
+
require 'ostruct'
|
14
|
+
|
15
|
+
module Siterest
|
16
|
+
|
17
|
+
autoload :Server, 'siterest/server'
|
18
|
+
autoload :Client, 'siterest/client'
|
19
|
+
autoload :Command, 'siterest/command'
|
20
|
+
|
21
|
+
autoload :Template, 'siterest/template'
|
22
|
+
autoload :Asset, 'siterest/asset'
|
23
|
+
autoload :User, 'siterest/user'
|
24
|
+
autoload :Site, 'siterest/site'
|
25
|
+
|
26
|
+
# load template api
|
27
|
+
require 'siterest/template/objects/site'
|
28
|
+
require 'siterest/template/objects/page'
|
29
|
+
require 'siterest/template/objects/article'
|
30
|
+
|
31
|
+
# load filters
|
32
|
+
require 'siterest/template/filters/core_filters'
|
33
|
+
require 'siterest/template/filters/datetime_filters'
|
34
|
+
require 'siterest/template/filters/url_filters'
|
35
|
+
|
36
|
+
def self.config
|
37
|
+
YAML.load_file("#{ENV['HOME']}/.siterest/config.yml")
|
38
|
+
rescue
|
39
|
+
raise "You need to setup API key, run siterest setup"
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.token
|
43
|
+
@token ||= config[:api_token]
|
44
|
+
rescue
|
45
|
+
raise "You need to setup API key, run siterest setup"
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.url
|
49
|
+
@token ||= config[:server_url]
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.site_resource_url
|
53
|
+
"#{self.url}/sites/:subdomain"
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|