ruhoh 0.1.3 → 0.2.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/Gemfile +3 -3
- data/README.md +40 -0
- data/dash.html +225 -0
- data/history.txt +15 -0
- data/lib/ruhoh/client/client.rb +39 -60
- data/lib/ruhoh/client/help.yml +5 -9
- data/lib/ruhoh/compiler.rb +6 -3
- data/lib/ruhoh/db.rb +7 -13
- data/lib/ruhoh/page.rb +19 -22
- data/lib/ruhoh/parsers/layouts.rb +8 -2
- data/lib/ruhoh/parsers/pages.rb +19 -18
- data/lib/ruhoh/parsers/posts.rb +45 -49
- data/lib/ruhoh/previewer.rb +17 -38
- data/lib/ruhoh/program.rb +28 -0
- data/lib/ruhoh/utils.rb +17 -3
- data/lib/ruhoh/version.rb +2 -2
- data/lib/ruhoh/watch.rb +1 -5
- data/lib/ruhoh.rb +23 -27
- data/ruhoh.gemspec +3 -1
- data/scaffolds/post.html +2 -0
- data/spec/db_spec.rb +2 -9
- data/spec/page_spec.rb +0 -25
- data/spec/parsers/layouts_spec.rb +23 -2
- data/spec/parsers/pages_spec.rb +24 -10
- data/spec/parsers/posts_spec.rb +15 -7
- data/spec/setup_spec.rb +6 -20
- data/spec/spec_helper.rb +3 -1
- metadata +23 -11
- data/lib/ruhoh/parsers/drafts.rb +0 -54
data/Gemfile
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
source "http://rubygems.org"
|
2
2
|
gemspec
|
3
3
|
|
4
|
-
gem 'rake'
|
5
4
|
gem 'rack', "~> 1.4"
|
6
5
|
gem 'directory_watcher', "~> 1.4"
|
7
6
|
gem 'mustache', "~> 0.99"
|
8
7
|
gem 'maruku', "~> 0.6"
|
9
|
-
gem '
|
8
|
+
gem 'psych', "~> 1.3"
|
10
9
|
|
11
10
|
group :development do
|
12
11
|
gem 'rspec'
|
13
|
-
|
12
|
+
gem 'rake'
|
13
|
+
end
|
data/README.md
CHANGED
@@ -7,3 +7,43 @@
|
|
7
7
|
|
8
8
|
$ gem install ruhoh
|
9
9
|
$ ruhoh help
|
10
|
+
|
11
|
+
|
12
|
+
- Ruhoh.setup :after_setup
|
13
|
+
- Ruhoh::DB.update\_all :after_db_update
|
14
|
+
- @page = Ruhoh::Page.new :after_page_initialize
|
15
|
+
- templater
|
16
|
+
- converter
|
17
|
+
|
18
|
+
|
19
|
+
- setup
|
20
|
+
- database
|
21
|
+
- page
|
22
|
+
- templater
|
23
|
+
- converter
|
24
|
+
- preview
|
25
|
+
- compiler
|
26
|
+
|
27
|
+
### Plugins
|
28
|
+
|
29
|
+
|
30
|
+
1. Mustache method additions
|
31
|
+
Extend the templating language
|
32
|
+
* Mounted onto the page object
|
33
|
+
|
34
|
+
|
35
|
+
2. Add additional converter support (textile)
|
36
|
+
* Mounted onto the page object
|
37
|
+
|
38
|
+
3. Generators ? compose extra pages?
|
39
|
+
I'm leaning toward why? any page should be able to be made
|
40
|
+
by calling a custom mustache method within a given textfile.
|
41
|
+
Jekyll's relevant example is to create mass-pages per each category.
|
42
|
+
Generating extra pages can be mounted onto the compiler
|
43
|
+
|
44
|
+
|
45
|
+
|
46
|
+
|
47
|
+
|
48
|
+
|
49
|
+
|
data/dash.html
ADDED
@@ -0,0 +1,225 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html lang="en">
|
3
|
+
<head>
|
4
|
+
<style type="text/css">
|
5
|
+
/*!
|
6
|
+
* Bootstrap v2.0.2
|
7
|
+
*
|
8
|
+
* Copyright 2012 Twitter, Inc
|
9
|
+
* Licensed under the Apache License v2.0
|
10
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
*
|
12
|
+
* Designed and built with all the love in the world @twitter by @mdo and @fat.
|
13
|
+
*/
|
14
|
+
.clearfix{*zoom:1;}.clearfix:before,.clearfix:after{display:table;content:"";}
|
15
|
+
.clearfix:after{clear:both;}
|
16
|
+
.hide-text{overflow:hidden;text-indent:100%;white-space:nowrap;}
|
17
|
+
.input-block-level{display:block;width:100%;min-height:28px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box;}
|
18
|
+
article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block;}
|
19
|
+
audio,canvas,video{display:inline-block;*display:inline;*zoom:1;}
|
20
|
+
audio:not([controls]){display:none;}
|
21
|
+
html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;}
|
22
|
+
a:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;}
|
23
|
+
a:hover,a:active{outline:0;}
|
24
|
+
sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline;}
|
25
|
+
sup{top:-0.5em;}
|
26
|
+
sub{bottom:-0.25em;}
|
27
|
+
img{height:auto;border:0;-ms-interpolation-mode:bicubic;vertical-align:middle;}
|
28
|
+
button,input,select,textarea{margin:0;font-size:100%;vertical-align:middle;}
|
29
|
+
button,input{*overflow:visible;line-height:normal;}
|
30
|
+
button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0;}
|
31
|
+
button,input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button;}
|
32
|
+
input[type="search"]{-webkit-appearance:textfield;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;}
|
33
|
+
input[type="search"]::-webkit-search-decoration,input[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none;}
|
34
|
+
textarea{overflow:auto;vertical-align:top;}
|
35
|
+
body{margin:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;line-height:18px;color:#333333;background-color:#ffffff;}
|
36
|
+
a{color:#0088cc;text-decoration:none;}
|
37
|
+
a:hover{color:#005580;text-decoration:underline;}
|
38
|
+
|
39
|
+
/* deep purple: #2E2633 */
|
40
|
+
/* deep red #99173C */
|
41
|
+
body, html {
|
42
|
+
font-size:14px;
|
43
|
+
height:100%;
|
44
|
+
color: #2E2633;
|
45
|
+
}
|
46
|
+
a, a:hover {
|
47
|
+
color: #2E2633;
|
48
|
+
text-decoration:none;
|
49
|
+
}
|
50
|
+
ul {
|
51
|
+
list-style:none;
|
52
|
+
margin:0; padding:0;
|
53
|
+
}
|
54
|
+
#wrapper {
|
55
|
+
margin:auto;
|
56
|
+
width:500px;
|
57
|
+
min-height:100%;
|
58
|
+
position:relative;
|
59
|
+
border-left:2px solid #99173C;
|
60
|
+
}
|
61
|
+
.page-pane {
|
62
|
+
padding:20px 0;
|
63
|
+
width:500px;
|
64
|
+
}
|
65
|
+
|
66
|
+
/* ----------------------------------------- */
|
67
|
+
#nav-wrapper {
|
68
|
+
position:absolute;
|
69
|
+
top:20px;
|
70
|
+
left:-202px;
|
71
|
+
}
|
72
|
+
#nav {
|
73
|
+
position:fixed;
|
74
|
+
line-height:2em;
|
75
|
+
width:200px;
|
76
|
+
}
|
77
|
+
#nav li {margin-bottom:3px;}
|
78
|
+
#nav li a {
|
79
|
+
display:block;
|
80
|
+
padding:0 25px;
|
81
|
+
line-height:50px;
|
82
|
+
border-radius:5px 0 0 5px;
|
83
|
+
font-size:20px;
|
84
|
+
font-weight:bold;
|
85
|
+
font-family:verdana;
|
86
|
+
text-align:right;
|
87
|
+
}
|
88
|
+
#nav li a:hover {
|
89
|
+
background:#DCE9BE;
|
90
|
+
}
|
91
|
+
#nav li a.active {
|
92
|
+
background:#99173C;
|
93
|
+
color:#FFF;
|
94
|
+
}
|
95
|
+
|
96
|
+
/* ----------------------------------------- */
|
97
|
+
ul.page-list {
|
98
|
+
line-height:1.5em;
|
99
|
+
}
|
100
|
+
ul.page-list li {
|
101
|
+
margin-bottom:3px;
|
102
|
+
}
|
103
|
+
ul.page-list li a{
|
104
|
+
display:block;
|
105
|
+
overflow:hidden;
|
106
|
+
padding:10px 25px;
|
107
|
+
font-family:courier;
|
108
|
+
border-radius:0 5px 5px 0;
|
109
|
+
line-height:24px;
|
110
|
+
}
|
111
|
+
ul.page-list li a:hover {
|
112
|
+
background:#DCE9BE;
|
113
|
+
}
|
114
|
+
ul.page-list li a span.title{
|
115
|
+
font-size:18px;
|
116
|
+
font-weight:bold;
|
117
|
+
}
|
118
|
+
ul.page-list li a span.date{
|
119
|
+
position:absolute;
|
120
|
+
right:25px;
|
121
|
+
font-size:12px;
|
122
|
+
}
|
123
|
+
ul.page-list li a span.id {
|
124
|
+
font-size:12px;
|
125
|
+
}
|
126
|
+
</style>
|
127
|
+
</head>
|
128
|
+
<body>
|
129
|
+
<div id="wrapper">
|
130
|
+
|
131
|
+
<div id="nav-wrapper">
|
132
|
+
<ul id="nav">
|
133
|
+
<li><a href="#drafts" class="active">Drafts</a></li>
|
134
|
+
<li><a href="#public">Posts</a></li>
|
135
|
+
<li><a href="#pages">Pages</a></li>
|
136
|
+
</ul>
|
137
|
+
</div>
|
138
|
+
|
139
|
+
<div id="drafts" class="page-pane">
|
140
|
+
<ul class="page-list">
|
141
|
+
{{# db.posts.drafts?to_posts }}
|
142
|
+
<li>
|
143
|
+
<a href="{{url}}">
|
144
|
+
<span class="title">{{title}}</span>
|
145
|
+
<span class="date">{{date}}</span>
|
146
|
+
<br><span class="id">{{id}}</span></small>
|
147
|
+
</a>
|
148
|
+
</li>
|
149
|
+
{{/ db.posts.drafts?to_posts }}
|
150
|
+
</ul>
|
151
|
+
</div>
|
152
|
+
|
153
|
+
<div id="public" class="page-pane" style="display:none">
|
154
|
+
<ul class="page-list">
|
155
|
+
{{#posts}}
|
156
|
+
{{^ type }}
|
157
|
+
<li>
|
158
|
+
<a href="{{url}}">
|
159
|
+
<span class="title">{{title}}</span>
|
160
|
+
<span class="date">{{date}}</span>
|
161
|
+
<br><span class="id">{{id}}</span></small>
|
162
|
+
</a>
|
163
|
+
</li>
|
164
|
+
{{/ type }}
|
165
|
+
{{/posts}}
|
166
|
+
</ul>
|
167
|
+
</div>
|
168
|
+
|
169
|
+
<div id="pages" class="page-pane" style="display:none">
|
170
|
+
<ul class="page-list">
|
171
|
+
{{#pages}}
|
172
|
+
<li>
|
173
|
+
<a href="{{url}}">
|
174
|
+
<span class="title">{{title}}</span>
|
175
|
+
<span class="date">{{date}}</span>
|
176
|
+
<br><span class="id">{{id}}</span></small>
|
177
|
+
</a>
|
178
|
+
</li>
|
179
|
+
{{/pages}}
|
180
|
+
</ul>
|
181
|
+
</div>
|
182
|
+
|
183
|
+
</div>
|
184
|
+
|
185
|
+
<script>
|
186
|
+
// Tabs is a small script for showing/hiding the different page lists.
|
187
|
+
// This mostly likely only works in modern browsers but
|
188
|
+
// I'd rather not add jQuery as a dependency until it's really warranted.
|
189
|
+
var Tabs = {
|
190
|
+
panes : document.getElementsByClassName('page-pane'),
|
191
|
+
nav : document.getElementById('nav'),
|
192
|
+
listEntries : this.nav.children,
|
193
|
+
links : [],
|
194
|
+
|
195
|
+
init : function(){
|
196
|
+
for (var i = 0; i < Tabs.listEntries.length; ++i) {
|
197
|
+
Tabs.links.push(Tabs.listEntries[i].firstChild);
|
198
|
+
}
|
199
|
+
|
200
|
+
Tabs.nav.addEventListener('click', function(e){
|
201
|
+
e.preventDefault();
|
202
|
+
if (e.target.tagName.toLowerCase() !== 'a') return;
|
203
|
+
|
204
|
+
Tabs.clearActive();
|
205
|
+
Tabs.hidePanes();
|
206
|
+
e.target.className = 'active';
|
207
|
+
var id = e.target.href.split('#')[1];
|
208
|
+
document.getElementById(id).style.display = 'block';
|
209
|
+
}, false)
|
210
|
+
},
|
211
|
+
|
212
|
+
clearActive : function(){
|
213
|
+
for (var i = 0; i < Tabs.links.length; ++i)
|
214
|
+
Tabs.links[i].className = '';
|
215
|
+
},
|
216
|
+
|
217
|
+
hidePanes : function(){
|
218
|
+
for (var i = 0; i < Tabs.panes.length; ++i)
|
219
|
+
Tabs.panes[i].style.display = 'none';
|
220
|
+
}
|
221
|
+
}
|
222
|
+
Tabs.init();
|
223
|
+
</script>
|
224
|
+
</body>
|
225
|
+
</html>
|
data/history.txt
CHANGED
@@ -1,3 +1,18 @@
|
|
1
|
+
|
2
|
+
4.5.2012
|
3
|
+
0.2.0 - API changes:
|
4
|
+
- [change] Dates in post filenames are now optional but will be required in metadata.
|
5
|
+
- [remove] _draft folder. Drafts are now simply a 'type' of post.
|
6
|
+
- [remove] publish and un-publish in favor of specifying 'type' meta attribute.
|
7
|
+
- [add] titleize method to client which renames draft filenames to their titles if set.
|
8
|
+
- [change] /_draft panel is now /dash with updated UI.
|
9
|
+
- [change] - rackup configuration is now through Ruhoh::Program.preview.
|
10
|
+
- FEATURES:
|
11
|
+
- Maintain file extensions for files that don't respond to a converter.
|
12
|
+
- Add 'development'/'production' environment configuration flag.
|
13
|
+
- @ben-biddington Introduces local temporary directory as SampleSitePath.
|
14
|
+
- @ben-biddington adds Travis integration.
|
15
|
+
0.1.4 - BUG: Fix invalid byte sequence in US-ASCII by forcing UTF-8
|
1
16
|
19.4.2012
|
2
17
|
0.1.3 - BUG: Fix drafts not maintaining file extension when publishing
|
3
18
|
BUG: tags helper should use tags database.
|
data/lib/ruhoh/client/client.rb
CHANGED
@@ -7,6 +7,7 @@ class Ruhoh
|
|
7
7
|
BlogScaffold = 'git://github.com/ruhoh/blog.git'
|
8
8
|
|
9
9
|
def initialize(data)
|
10
|
+
@iterator = 0
|
10
11
|
self.setup_paths
|
11
12
|
self.setup_options(data)
|
12
13
|
|
@@ -58,68 +59,24 @@ class Ruhoh
|
|
58
59
|
# Public: Create a new draft file.
|
59
60
|
# Requires no settings as it is meant to be fastest way to create content.
|
60
61
|
def draft
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
end
|
62
|
+
begin
|
63
|
+
filename = File.join(Ruhoh.paths.posts, "untitled-#{@iterator}.#{@options.ext}")
|
64
|
+
@iterator += 1
|
65
|
+
end while File.exist?(filename)
|
65
66
|
|
66
67
|
FileUtils.mkdir_p File.dirname(filename)
|
67
|
-
File.open(@paths.post_template) do |template|
|
68
|
-
File.open(filename, 'w') do |post|
|
69
|
-
post.puts template.read
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
Ruhoh::Friend.say {
|
74
|
-
green "New draft:"
|
75
|
-
green Ruhoh.relative_path(filename)
|
76
|
-
green 'View drafts at the URL: /_drafts'
|
77
|
-
}
|
78
|
-
end
|
79
|
-
|
80
|
-
# Public: Publishes the last active draft file.
|
81
|
-
def publish
|
82
|
-
id = self.last('draft')
|
83
|
-
Ruhoh::Friend.say { yellow "No draft to publish." ; exit } if id.nil?
|
84
|
-
Ruhoh::Friend.say { plain "Publishing draft: #{id}" }
|
85
|
-
draft = Ruhoh::Parsers::Posts.process_file(id)
|
86
|
-
|
87
|
-
Ruhoh::Friend.say { red "Draft title cannot be blank." ; exit } unless draft['data']['title']
|
88
|
-
Ruhoh::Friend.say {
|
89
|
-
red "Invalid date format: #{draft['data']['date']}"
|
90
|
-
red "Date format must be YYYY-MM-DD."
|
91
|
-
exit
|
92
|
-
} unless draft['data']['date']
|
93
|
-
|
94
|
-
draft['data']['ext'] = File.extname(id).gsub('.','')
|
95
|
-
filename = Ruhoh::Parsers::Posts.to_filename(draft['data'])
|
96
68
|
|
97
|
-
|
98
|
-
|
99
|
-
|
69
|
+
output = File.open(@paths.post_template) { |f| f.read }
|
70
|
+
output = output.gsub('{{DATE}}', Ruhoh::Parsers::Posts.formatted_date(Time.now))
|
71
|
+
File.open(filename, 'w') {|f| f.puts output }
|
100
72
|
|
101
|
-
FileUtils.mkdir_p File.dirname(filename)
|
102
|
-
FileUtils.mv id, filename
|
103
|
-
|
104
73
|
Ruhoh::Friend.say {
|
105
|
-
green "
|
74
|
+
green "New draft:"
|
106
75
|
green Ruhoh.relative_path(filename)
|
76
|
+
green 'View drafts at the URL: /dash'
|
107
77
|
}
|
108
78
|
end
|
109
|
-
|
110
|
-
# Public: Unpublishes the last active post file.
|
111
|
-
def unpublish
|
112
|
-
post = self.last('post')
|
113
|
-
Ruhoh::Friend.say { yellow "No post to unpublish." ; exit } if post.nil?
|
114
|
-
Ruhoh::Friend.say { plain "Unpublishing post: #{post}" }
|
115
|
-
|
116
|
-
FileUtils.mv post, File.join(Ruhoh.paths.drafts, File.basename(post))
|
117
|
-
|
118
|
-
Ruhoh::Friend.say {
|
119
|
-
yellow "Unpublished post:"
|
120
|
-
yellow Ruhoh.relative_path(post)
|
121
|
-
}
|
122
|
-
end
|
79
|
+
alias_method :post, :draft
|
123
80
|
|
124
81
|
# Public: Create a new page file.
|
125
82
|
def page
|
@@ -149,6 +106,19 @@ class Ruhoh
|
|
149
106
|
}
|
150
107
|
end
|
151
108
|
|
109
|
+
# Public: Update draft filenames to their corresponding titles.
|
110
|
+
def titleize
|
111
|
+
Ruhoh::Parsers::Posts.files.each do |file|
|
112
|
+
next unless File.basename(file) =~ /^untitled/
|
113
|
+
parsed_page = Ruhoh::Utils.parse_file(file)
|
114
|
+
next unless parsed_page['data']['title']
|
115
|
+
new_name = Ruhoh::Parsers::Posts.to_slug(parsed_page['data']['title'])
|
116
|
+
new_file = File.join(File.dirname(file), "#{new_name}#{File.extname(file)}")
|
117
|
+
FileUtils.mv(file, new_file)
|
118
|
+
Ruhoh::Friend.say { green "Renamed #{file} to: #{new_file}" }
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
152
122
|
# Public: Compile to static website.
|
153
123
|
def compile
|
154
124
|
Ruhoh::Compiler.new(@args[1]).compile
|
@@ -256,7 +226,7 @@ class Ruhoh
|
|
256
226
|
# Return the payload hash for inspection/study.
|
257
227
|
def payload
|
258
228
|
require 'pp'
|
259
|
-
Ruhoh::DB.
|
229
|
+
Ruhoh::DB.update_all
|
260
230
|
Ruhoh::Friend.say {
|
261
231
|
plain Ruhoh::Templaters::Base.build_payload.pretty_inspect
|
262
232
|
}
|
@@ -264,9 +234,20 @@ class Ruhoh
|
|
264
234
|
|
265
235
|
# Internal: Outputs a list of the given data-type to the terminal.
|
266
236
|
def list(type)
|
267
|
-
|
268
|
-
|
269
|
-
|
237
|
+
data = case type
|
238
|
+
when :posts
|
239
|
+
Ruhoh::DB.update(:posts)
|
240
|
+
Ruhoh::DB.posts['dictionary']
|
241
|
+
when :drafts
|
242
|
+
Ruhoh::DB.update(:posts)
|
243
|
+
drafts = Ruhoh::DB.posts['drafts']
|
244
|
+
h = {}
|
245
|
+
drafts.each {|id| h[id] = Ruhoh::DB.posts['dictionary'][id]}
|
246
|
+
h
|
247
|
+
when :pages
|
248
|
+
Ruhoh::DB.update(:pages)
|
249
|
+
Ruhoh::DB.pages
|
250
|
+
end
|
270
251
|
|
271
252
|
if @options.verbose
|
272
253
|
Ruhoh::Friend.say {
|
@@ -298,8 +279,6 @@ class Ruhoh
|
|
298
279
|
case type
|
299
280
|
when 'post'
|
300
281
|
Ruhoh::Parsers::Posts.files
|
301
|
-
when 'draft'
|
302
|
-
Ruhoh::Parsers::Drafts.files
|
303
282
|
when 'page'
|
304
283
|
Ruhoh::Parsers::Pages.files
|
305
284
|
else
|
data/lib/ruhoh/client/help.yml
CHANGED
@@ -15,22 +15,18 @@ commands:
|
|
15
15
|
"desc" : |
|
16
16
|
Compile to static website.
|
17
17
|
-
|
18
|
-
"command" : "draft"
|
18
|
+
"command" : "post | draft"
|
19
19
|
"desc" : |
|
20
20
|
Create a new draft.
|
21
|
-
-
|
22
|
-
"command" : "publish"
|
23
|
-
"desc" : |
|
24
|
-
Publish the last active draft file.
|
25
|
-
-
|
26
|
-
"command" : "unpublish"
|
27
|
-
"desc" : |
|
28
|
-
UnPublish the last active post file.
|
29
21
|
-
|
30
22
|
"command" : "page <path>"
|
31
23
|
"desc" : |
|
32
24
|
Create a new page at the given path.
|
33
25
|
-
|
26
|
+
"command" : "titleize"
|
27
|
+
"desc" : |
|
28
|
+
Update draft filenames to their corresponding titles. Drafts without titles are ignored.
|
29
|
+
-
|
34
30
|
"command" : "drafts"
|
35
31
|
"desc" : |
|
36
32
|
List all drafts.
|
data/lib/ruhoh/compiler.rb
CHANGED
@@ -3,7 +3,10 @@ class Ruhoh
|
|
3
3
|
class Compiler
|
4
4
|
|
5
5
|
def initialize(target_directory)
|
6
|
-
Ruhoh
|
6
|
+
Ruhoh.config.env ||= 'production'
|
7
|
+
Ruhoh::Friend.say { plain "Compiling for environment: '#{Ruhoh.config.env}'" }
|
8
|
+
|
9
|
+
Ruhoh::DB.update_all
|
7
10
|
@target = target_directory || "./#{Ruhoh.folders.compiled}"
|
8
11
|
@page = Ruhoh::Page.new
|
9
12
|
end
|
@@ -21,11 +24,11 @@ class Ruhoh
|
|
21
24
|
|
22
25
|
def pages
|
23
26
|
FileUtils.cd(@target) {
|
24
|
-
Ruhoh::DB.
|
27
|
+
Ruhoh::DB.all_pages.each_value do |p|
|
25
28
|
@page.change(p['id'])
|
26
29
|
|
27
30
|
FileUtils.mkdir_p File.dirname(@page.compiled_path)
|
28
|
-
File.open(@page.compiled_path, 'w') { |p| p.puts @page.render }
|
31
|
+
File.open(@page.compiled_path, 'w:UTF-8') { |p| p.puts @page.render }
|
29
32
|
|
30
33
|
Ruhoh::Friend.say { green "processed: #{p['id']}" }
|
31
34
|
end
|
data/lib/ruhoh/db.rb
CHANGED
@@ -1,12 +1,8 @@
|
|
1
|
-
require "observer"
|
2
|
-
|
3
1
|
class Ruhoh
|
4
|
-
|
5
2
|
# Public: Database class for interacting with "data" in Ruhoh.
|
6
3
|
class DB
|
7
4
|
class << self
|
8
|
-
|
9
|
-
WhiteList = [:site, :posts, :drafts, :pages, :routes, :layouts, :partials]
|
5
|
+
WhiteList = [:site, :posts, :pages, :routes, :layouts, :partials]
|
10
6
|
self.__send__ :attr_reader, *WhiteList
|
11
7
|
|
12
8
|
def update(name)
|
@@ -18,8 +14,6 @@ class Ruhoh
|
|
18
14
|
Ruhoh::Parsers::Routes.generate
|
19
15
|
when :posts
|
20
16
|
Ruhoh::Parsers::Posts.generate
|
21
|
-
when :drafts
|
22
|
-
Ruhoh::Parsers::Drafts.generate
|
23
17
|
when :pages
|
24
18
|
Ruhoh::Parsers::Pages.generate
|
25
19
|
when :layouts
|
@@ -30,18 +24,18 @@ class Ruhoh
|
|
30
24
|
raise "Data type: '#{name}' is not a valid data type."
|
31
25
|
end
|
32
26
|
)
|
33
|
-
changed
|
34
|
-
notify_observers(name)
|
35
27
|
end
|
36
|
-
|
37
|
-
def
|
28
|
+
|
29
|
+
def all_pages
|
30
|
+
self.posts['dictionary'].merge(self.pages)
|
31
|
+
end
|
32
|
+
|
33
|
+
def update_all
|
38
34
|
WhiteList.each do |var|
|
39
35
|
self.__send__ :update, var
|
40
36
|
end
|
41
37
|
end
|
42
38
|
|
43
39
|
end #self
|
44
|
-
|
45
40
|
end #DB
|
46
|
-
|
47
41
|
end #Ruhoh
|
data/lib/ruhoh/page.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
class Ruhoh
|
2
|
-
|
3
2
|
class Page
|
4
3
|
attr_reader :id, :data, :content, :sub_layout, :master_layout
|
5
4
|
attr_accessor :templater, :converter
|
@@ -11,12 +10,10 @@ class Ruhoh
|
|
11
10
|
|
12
11
|
# Public: Change this page using an id.
|
13
12
|
def change(id)
|
14
|
-
|
13
|
+
self.reset
|
15
14
|
@path = id
|
16
15
|
@data = if id =~ Regexp.new("^#{Ruhoh.folders.posts}")
|
17
16
|
Ruhoh::DB.posts['dictionary'][id]
|
18
|
-
elsif id =~ Regexp.new("^#{Ruhoh.folders.drafts}")
|
19
|
-
Ruhoh::DB.drafts[id]
|
20
17
|
else
|
21
18
|
@path = "#{Ruhoh.folders.pages}/#{id}"
|
22
19
|
Ruhoh::DB.pages[id]
|
@@ -26,26 +23,15 @@ class Ruhoh
|
|
26
23
|
@id = id
|
27
24
|
end
|
28
25
|
|
29
|
-
# Public: Change this page using a URL.
|
30
|
-
def change_with_url(url)
|
31
|
-
id = if url =~ Regexp.new("^/#{Ruhoh.folders.drafts}")
|
32
|
-
url.gsub(/^\//,'')
|
33
|
-
else
|
34
|
-
Ruhoh::DB.routes[url]
|
35
|
-
end
|
36
|
-
raise "Page id not found for url: #{url}" unless id
|
37
|
-
self.change(id)
|
38
|
-
end
|
39
|
-
|
40
26
|
def render
|
41
|
-
|
27
|
+
self.ensure_id
|
42
28
|
self.process_layouts
|
43
29
|
self.process_content
|
44
30
|
@templater.render(self)
|
45
31
|
end
|
46
32
|
|
47
33
|
def process_layouts
|
48
|
-
|
34
|
+
self.ensure_id
|
49
35
|
if @data['layout']
|
50
36
|
@sub_layout = Ruhoh::DB.layouts[@data['layout']]
|
51
37
|
raise "Layout does not exist: #{@data['layout']}" unless @sub_layout
|
@@ -61,7 +47,7 @@ class Ruhoh
|
|
61
47
|
# in order to invoke converters on the result.
|
62
48
|
# Converters (markdown) always choke on the templating language.
|
63
49
|
def process_content
|
64
|
-
|
50
|
+
self.ensure_id
|
65
51
|
data = Ruhoh::Utils.parse_file(Ruhoh.paths.site_source, @path)
|
66
52
|
raise "Invalid Frontmatter in page: #{@path}" if data.empty?
|
67
53
|
|
@@ -72,7 +58,7 @@ class Ruhoh
|
|
72
58
|
# Public: Return page attributes suitable for inclusion in the
|
73
59
|
# 'payload' of the given templater.
|
74
60
|
def attributes
|
75
|
-
|
61
|
+
self.ensure_id
|
76
62
|
@data['content'] = @content
|
77
63
|
@data
|
78
64
|
end
|
@@ -81,13 +67,24 @@ class Ruhoh
|
|
81
67
|
#
|
82
68
|
# Returns: [String] The relative path to the compiled file for this page.
|
83
69
|
def compiled_path
|
84
|
-
|
70
|
+
self.ensure_id
|
85
71
|
path = CGI.unescape(@data['url']).gsub(/^\//, '') #strip leading slash.
|
86
72
|
path = "index.html" if path.empty?
|
87
|
-
path += '/index.html' unless path =~
|
73
|
+
path += '/index.html' unless path =~ /\.\w+$/
|
88
74
|
path
|
89
75
|
end
|
90
76
|
|
77
|
+
def reset
|
78
|
+
@id = nil
|
79
|
+
@data = nil
|
80
|
+
@content = nil
|
81
|
+
@sub_layout = nil
|
82
|
+
@master_layout = nil
|
83
|
+
end
|
84
|
+
|
85
|
+
def ensure_id
|
86
|
+
raise '@page ID is null: ID must be set via page.change(id) or page.change_with_url(url)' if @id.nil?
|
87
|
+
end
|
88
|
+
|
91
89
|
end #Page
|
92
|
-
|
93
90
|
end #Ruhoh
|
@@ -5,13 +5,18 @@ class Ruhoh
|
|
5
5
|
# Generate layouts only from the active theme.
|
6
6
|
def self.generate
|
7
7
|
layouts = {}
|
8
|
-
|
8
|
+
invalid = []
|
9
9
|
self.files.each do |filename|
|
10
10
|
id = File.basename(filename, File.extname(filename))
|
11
11
|
layouts[id] = Ruhoh::Utils.parse_file(Ruhoh.paths.layouts, filename)
|
12
|
-
|
12
|
+
|
13
|
+
if layouts[id].empty?
|
14
|
+
error = "Invalid YAML Front Matter. Ensure this page has valid YAML, even if it's empty."
|
15
|
+
invalid << [filename, error]
|
16
|
+
end
|
13
17
|
end
|
14
18
|
|
19
|
+
Ruhoh::Utils.report('Layouts', layouts, invalid)
|
15
20
|
layouts
|
16
21
|
end
|
17
22
|
|
@@ -25,6 +30,7 @@ class Ruhoh
|
|
25
30
|
}
|
26
31
|
end
|
27
32
|
|
33
|
+
|
28
34
|
end #Layouts
|
29
35
|
end #Parsers
|
30
36
|
end #Ruhoh
|