ruhoh 0.3.0 → 1.0.0.alpha
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +1 -0
- data/README.md +0 -33
- data/dash.html +1 -0
- data/history.json +29 -0
- data/lib/ruhoh/client/client.rb +30 -22
- data/lib/ruhoh/client/help.yml +6 -2
- data/lib/ruhoh/compiler.rb +8 -20
- data/lib/ruhoh/compilers/rss.rb +36 -0
- data/lib/ruhoh/compilers/theme.rb +41 -0
- data/lib/ruhoh/config.rb +49 -0
- data/lib/ruhoh/converters/converter.rb +17 -4
- data/lib/ruhoh/converters/markdown.rb +2 -2
- data/lib/ruhoh/db.rb +29 -2
- data/lib/ruhoh/deployers/s3.rb +1 -1
- data/lib/ruhoh/logger.rb +1 -1
- data/lib/ruhoh/page.rb +38 -22
- data/lib/ruhoh/parsers/javascripts.rb +67 -0
- data/lib/ruhoh/parsers/layouts.rb +6 -10
- data/lib/ruhoh/parsers/pages.rb +17 -24
- data/lib/ruhoh/parsers/partials.rb +6 -14
- data/lib/ruhoh/parsers/payload.rb +47 -0
- data/lib/ruhoh/parsers/posts.rb +27 -29
- data/lib/ruhoh/parsers/site.rb +2 -2
- data/lib/ruhoh/parsers/stylesheets.rb +75 -0
- data/lib/ruhoh/parsers/widgets.rb +104 -0
- data/lib/ruhoh/paths.rb +75 -0
- data/lib/ruhoh/previewer.rb +11 -5
- data/lib/ruhoh/program.rb +35 -4
- data/lib/ruhoh/templaters/asset_helpers.rb +66 -0
- data/lib/ruhoh/templaters/base_helpers.rb +143 -0
- data/lib/ruhoh/templaters/helpers.rb +1 -148
- data/lib/ruhoh/templaters/rmustache.rb +45 -4
- data/lib/ruhoh/urls.rb +46 -0
- data/lib/ruhoh/utils.rb +59 -17
- data/lib/ruhoh/version.rb +2 -2
- data/lib/ruhoh/watch.rb +26 -14
- data/lib/ruhoh.rb +38 -96
- data/ruhoh.gemspec +29 -10
- data/scaffolds/draft.html +9 -0
- data/scaffolds/page.html +0 -2
- data/scaffolds/post.html +0 -4
- data/scaffolds/theme/{images → javascripts}/.gitkeep +0 -0
- data/scaffolds/theme/layouts/default.html +2 -4
- data/scaffolds/theme/layouts/page.html +1 -1
- data/scaffolds/theme/layouts/post.html +1 -1
- data/scaffolds/theme/{css/style.css → media/.gitkeep} +0 -0
- data/scaffolds/theme/stylesheets/style.css +0 -0
- data/scaffolds/theme/theme.yml +27 -0
- data/scaffolds/theme/widgets/.gitkeep +0 -0
- data/spec/config_spec.rb +50 -0
- data/spec/db_spec.rb +28 -14
- data/spec/page_spec.rb +24 -35
- data/spec/parsers/layouts_spec.rb +5 -13
- data/spec/parsers/pages_spec.rb +13 -11
- data/spec/parsers/posts_spec.rb +34 -29
- data/spec/parsers/routes_spec.rb +2 -1
- data/spec/parsers/site_spec.rb +6 -5
- data/spec/setup_spec.rb +3 -47
- data/widgets/analytics/config.yml +5 -0
- data/{system_partials/analytics/getclicky → widgets/analytics/layouts/getclicky.html} +2 -2
- data/{system_partials/analytics/google → widgets/analytics/layouts/google.html} +1 -1
- data/widgets/comments/config.yml +12 -0
- data/{system_partials/comments/disqus → widgets/comments/layouts/disqus.html} +2 -2
- data/{system_partials/comments/facebook → widgets/comments/layouts/facebook.html} +1 -1
- data/{system_partials/comments/intensedebate → widgets/comments/layouts/intensedebate.html} +1 -1
- data/{system_partials/comments/livefyre → widgets/comments/layouts/livefyre.html} +1 -1
- data/widgets/google_prettify/config.yml +1 -0
- data/widgets/google_prettify/layouts/google_prettify.html +10 -0
- metadata +54 -31
- data/lib/ruhoh/templaters/base.rb +0 -57
- data/system_partials/syntax/google_prettify +0 -11
@@ -0,0 +1,67 @@
|
|
1
|
+
class Ruhoh
|
2
|
+
module Parsers
|
3
|
+
# Collect all the javascripts.
|
4
|
+
# Themes explicitly define which javascripts to load via theme.yml.
|
5
|
+
# Additionally, widgets may register javascript dependencies, which are resolved here.
|
6
|
+
module Javascripts
|
7
|
+
|
8
|
+
# Generates mappings to all registered javascripts.
|
9
|
+
# Returns Hash with layout names as keys and Array of asset Objects as values
|
10
|
+
def self.generate
|
11
|
+
theme_config = self.theme_config
|
12
|
+
assets = self.theme_javascripts(theme_config)
|
13
|
+
assets[Ruhoh.names.widgets] = self.widget_javascripts(theme_config)
|
14
|
+
assets
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.theme_javascripts(theme_config)
|
18
|
+
return {} unless theme_config[Ruhoh.names.javascripts].is_a? Hash
|
19
|
+
assets = {}
|
20
|
+
theme_config[Ruhoh.names.javascripts].each do |key, value|
|
21
|
+
next if key == Ruhoh.names.widgets # Widgets are handled separately.
|
22
|
+
assets[key] = Array(value).map { |v|
|
23
|
+
{
|
24
|
+
"url" => "#{Ruhoh.urls.theme_javascripts}/#{v}",
|
25
|
+
"id" => File.join(Ruhoh.paths.theme_javascripts, v)
|
26
|
+
}
|
27
|
+
}
|
28
|
+
end
|
29
|
+
|
30
|
+
assets
|
31
|
+
end
|
32
|
+
|
33
|
+
# Notes:
|
34
|
+
# The automatic script inclusion is currently handled within the widget parser.
|
35
|
+
# This differs from the auto-stylesheet inclusion relative to themes,
|
36
|
+
# which is handled in the stylesheet parser.
|
37
|
+
# Make sure there are some standards with this.
|
38
|
+
def self.widget_javascripts(theme_config)
|
39
|
+
assets = []
|
40
|
+
Ruhoh::DB.widgets.each_value do |widget|
|
41
|
+
next unless widget[Ruhoh.names.javascripts]
|
42
|
+
assets += Array(widget[Ruhoh.names.javascripts]).map {|path|
|
43
|
+
{
|
44
|
+
"url" => [Ruhoh.urls.widgets, widget['name'], Ruhoh.names.javascripts, path].join('/'),
|
45
|
+
"id" => File.join(Ruhoh.paths.widgets, widget['name'], Ruhoh.names.javascripts, path)
|
46
|
+
}
|
47
|
+
}
|
48
|
+
end
|
49
|
+
|
50
|
+
assets
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.theme_config
|
54
|
+
theme_config = Ruhoh::Utils.parse_yaml_file(Ruhoh.paths.theme_config_data)
|
55
|
+
if theme_config.nil?
|
56
|
+
Ruhoh::Friend.say{
|
57
|
+
yellow "WARNING: theme.yml config file not found:"
|
58
|
+
yellow " #{Ruhoh.paths.theme_config_data}"
|
59
|
+
}
|
60
|
+
return {}
|
61
|
+
end
|
62
|
+
return {} unless theme_config.is_a? Hash
|
63
|
+
theme_config
|
64
|
+
end
|
65
|
+
end #Javascripts
|
66
|
+
end #Parsers
|
67
|
+
end #Ruhoh
|
@@ -5,23 +5,20 @@ class Ruhoh
|
|
5
5
|
# Generate layouts only from the active theme.
|
6
6
|
def self.generate
|
7
7
|
layouts = {}
|
8
|
-
invalid = []
|
9
8
|
self.files.each do |filename|
|
10
9
|
id = File.basename(filename, File.extname(filename))
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
error = "Invalid YAML Front Matter. Ensure this page has valid YAML, even if it's empty."
|
15
|
-
invalid << [filename, error]
|
16
|
-
end
|
10
|
+
data = Ruhoh::Utils.parse_layout_file(Ruhoh.paths.theme_layouts, filename)
|
11
|
+
data['id'] = id
|
12
|
+
layouts[id] = data
|
17
13
|
end
|
18
14
|
|
19
|
-
Ruhoh::Utils.report('Layouts', layouts,
|
15
|
+
Ruhoh::Utils.report('Layouts', layouts, [])
|
20
16
|
layouts
|
21
17
|
end
|
22
18
|
|
23
19
|
def self.files
|
24
|
-
|
20
|
+
return [] unless FileTest.directory?(Ruhoh.paths.theme_layouts)
|
21
|
+
FileUtils.cd(Ruhoh.paths.theme_layouts) {
|
25
22
|
return Dir["**/*.*"].select { |filename|
|
26
23
|
next if FileTest.directory?(filename)
|
27
24
|
next if ['_','.'].include? filename[0]
|
@@ -30,7 +27,6 @@ class Ruhoh
|
|
30
27
|
}
|
31
28
|
end
|
32
29
|
|
33
|
-
|
34
30
|
end #Layouts
|
35
31
|
end #Parsers
|
36
32
|
end #Ruhoh
|
data/lib/ruhoh/parsers/pages.rb
CHANGED
@@ -8,32 +8,30 @@ class Ruhoh
|
|
8
8
|
Ruhoh.ensure_setup
|
9
9
|
|
10
10
|
pages = self.files
|
11
|
-
invalid = []
|
12
11
|
dictionary = {}
|
13
12
|
|
14
13
|
pages.each do |filename|
|
15
14
|
id = self.make_id(filename)
|
16
15
|
parsed_page = ''
|
17
|
-
FileUtils.cd(Ruhoh.paths.
|
18
|
-
if parsed_page.empty?
|
19
|
-
error = "Invalid Yaml Front Matter.\n Ensure this page has valid YAML, even if it's empty."
|
20
|
-
invalid << [filename, error] ; next
|
21
|
-
end
|
16
|
+
FileUtils.cd(Ruhoh.paths.base) { parsed_page = Ruhoh::Utils.parse_page_file(filename) }
|
22
17
|
|
23
18
|
parsed_page['data']['id'] = id
|
24
19
|
parsed_page['data']['url'] = self.permalink(parsed_page['data'])
|
25
20
|
parsed_page['data']['title'] = parsed_page['data']['title'] || self.to_title(filename)
|
26
|
-
|
21
|
+
if parsed_page['data']['layout'].nil?
|
22
|
+
parsed_page['data']['layout'] = Ruhoh.config.pages_layout
|
23
|
+
end
|
24
|
+
|
27
25
|
dictionary[id] = parsed_page['data']
|
28
26
|
end
|
29
27
|
|
30
|
-
Ruhoh::Utils.report('Pages', dictionary,
|
28
|
+
Ruhoh::Utils.report('Pages', dictionary, [])
|
31
29
|
dictionary
|
32
30
|
end
|
33
31
|
|
34
32
|
def self.files
|
35
|
-
FileUtils.cd(Ruhoh.paths.
|
36
|
-
return Dir["#{Ruhoh.
|
33
|
+
FileUtils.cd(Ruhoh.paths.base) {
|
34
|
+
return Dir["#{Ruhoh.names.pages}/**/*.*"].select { |filename|
|
37
35
|
next unless self.is_valid_page?(filename)
|
38
36
|
true
|
39
37
|
}
|
@@ -43,40 +41,35 @@ class Ruhoh
|
|
43
41
|
def self.is_valid_page?(filepath)
|
44
42
|
return false if FileTest.directory?(filepath)
|
45
43
|
return false if ['.'].include? filepath[0]
|
46
|
-
Ruhoh.
|
44
|
+
Ruhoh.config.pages_exclude.each {|regex| return false if filepath =~ regex }
|
47
45
|
true
|
48
46
|
end
|
49
47
|
|
50
48
|
def self.make_id(filename)
|
51
|
-
filename.gsub(Regexp.new("^#{Ruhoh.
|
49
|
+
filename.gsub(Regexp.new("^#{Ruhoh.names.pages}/"), '')
|
52
50
|
end
|
53
51
|
|
54
52
|
def self.to_title(filename)
|
55
53
|
name = File.basename( filename, File.extname(filename) )
|
56
54
|
name = filename.split('/')[-2] if name == 'index' && !filename.index('/').nil?
|
57
|
-
name.gsub(/[
|
55
|
+
name.gsub(/[^\p{Word}+]/u, ' ').gsub(/\b\w/){$&.upcase}
|
58
56
|
end
|
59
57
|
|
60
58
|
# Build the permalink for the given page.
|
61
|
-
# Only recognize
|
59
|
+
# Only recognize extensions registered from a 'convertable' module.
|
62
60
|
# This means 'non-convertable' extensions should pass-through.
|
63
61
|
#
|
64
62
|
# Returns [String] the permalink for this page.
|
65
63
|
def self.permalink(page)
|
66
|
-
url = '/'
|
67
64
|
ext = File.extname(page['id'])
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
end
|
73
|
-
|
74
|
-
url = url.split('/').reject{ |part| part[0] == '.' }.join('/')
|
75
|
-
url = url.gsub(/\/index.html$/, '')
|
65
|
+
name = page['id'].gsub(Regexp.new("#{ext}$"), '')
|
66
|
+
ext = '.html' if Ruhoh::Converter.extensions.include?(ext)
|
67
|
+
url = name.split('/').map {|p| Ruhoh::Urls.to_url_slug(p) }.join('/')
|
68
|
+
url = "/#{url}#{ext}".gsub(/\/index.html$/, '')
|
76
69
|
if page['permalink'] == 'pretty' || Ruhoh.config.pages_permalink == 'pretty'
|
77
70
|
url = url.gsub(/\.html$/, '')
|
78
71
|
end
|
79
|
-
url =
|
72
|
+
url = '/' if url.empty?
|
80
73
|
|
81
74
|
url
|
82
75
|
end
|
@@ -1,25 +1,19 @@
|
|
1
1
|
class Ruhoh
|
2
|
-
|
3
2
|
module Parsers
|
4
|
-
|
5
3
|
module Partials
|
6
4
|
|
7
5
|
def self.generate
|
8
|
-
self.
|
6
|
+
self.global_partials.merge(self.theme_partials)
|
9
7
|
end
|
10
|
-
|
8
|
+
|
11
9
|
def self.theme_partials
|
12
|
-
self.process(Ruhoh.paths.
|
10
|
+
self.process(Ruhoh.paths.theme_partials)
|
13
11
|
end
|
14
12
|
|
15
13
|
def self.global_partials
|
16
|
-
self.process(Ruhoh.paths.
|
17
|
-
end
|
18
|
-
|
19
|
-
def self.system_partials
|
20
|
-
self.process(File.join(Ruhoh::Root, 'system_partials'))
|
14
|
+
self.process(Ruhoh.paths.partials)
|
21
15
|
end
|
22
|
-
|
16
|
+
|
23
17
|
def self.process(path)
|
24
18
|
return {} unless File.exist?(path)
|
25
19
|
|
@@ -28,14 +22,12 @@ class Ruhoh
|
|
28
22
|
Dir.glob("**/*").each { |filename|
|
29
23
|
next if FileTest.directory?(filename)
|
30
24
|
next if ['.'].include? filename[0]
|
31
|
-
File.open(filename) { |f| partials[filename] = f.read }
|
25
|
+
File.open(filename, 'r:UTF-8') { |f| partials[filename] = f.read }
|
32
26
|
}
|
33
27
|
}
|
34
28
|
partials
|
35
29
|
end
|
36
30
|
|
37
31
|
end #Partials
|
38
|
-
|
39
32
|
end #Parsers
|
40
|
-
|
41
33
|
end #Ruhoh
|
@@ -0,0 +1,47 @@
|
|
1
|
+
class Ruhoh
|
2
|
+
module Parsers
|
3
|
+
module Payload
|
4
|
+
|
5
|
+
def self.generate
|
6
|
+
{
|
7
|
+
"db" => {
|
8
|
+
"pages" => Ruhoh::DB.pages,
|
9
|
+
"posts" => self.determine_category_and_tag_urls,
|
10
|
+
},
|
11
|
+
"site" => Ruhoh::DB.site,
|
12
|
+
'page' => {},
|
13
|
+
"urls" => {
|
14
|
+
"theme_stylesheets" => Ruhoh.urls.theme_stylesheets,
|
15
|
+
"theme_javascripts" => Ruhoh.urls.theme_javascripts,
|
16
|
+
"theme_media" => Ruhoh.urls.theme_media,
|
17
|
+
"media" => Ruhoh.urls.media,
|
18
|
+
}
|
19
|
+
}
|
20
|
+
end
|
21
|
+
|
22
|
+
# This is an ugly hack to determine the proper category and tag urls.
|
23
|
+
# TODO: Refactor this out.
|
24
|
+
def self.determine_category_and_tag_urls
|
25
|
+
return nil unless Ruhoh::DB.routes && Ruhoh::DB.posts
|
26
|
+
categories_url = nil
|
27
|
+
['/categories', '/categories.html'].each { |url|
|
28
|
+
categories_url = url and break if Ruhoh::DB.routes.key?(url)
|
29
|
+
}
|
30
|
+
Ruhoh::DB.posts['categories'].each do |key, value|
|
31
|
+
Ruhoh::DB.posts['categories'][key]['url'] = "#{categories_url}##{value['name']}-ref"
|
32
|
+
end
|
33
|
+
|
34
|
+
tags_url = nil
|
35
|
+
['/tags', '/tags.html'].each { |url|
|
36
|
+
tags_url = url and break if Ruhoh::DB.routes.key?(url)
|
37
|
+
}
|
38
|
+
Ruhoh::DB.posts['tags'].each do |key, value|
|
39
|
+
Ruhoh::DB.posts['tags'][key]['url'] = "#{tags_url}##{value['name']}-ref"
|
40
|
+
end
|
41
|
+
|
42
|
+
Ruhoh::DB.posts
|
43
|
+
end
|
44
|
+
|
45
|
+
end #Payload
|
46
|
+
end #Parsers
|
47
|
+
end #Ruhoh
|
data/lib/ruhoh/parsers/posts.rb
CHANGED
@@ -30,14 +30,10 @@ class Ruhoh
|
|
30
30
|
|
31
31
|
self.files.each do |filename|
|
32
32
|
parsed_page = ''
|
33
|
-
FileUtils.cd(Ruhoh.paths.
|
34
|
-
if parsed_page.empty?
|
35
|
-
error = "Invalid YAML Front Matter. Ensure this page has valid YAML, even if it's empty."
|
36
|
-
invalid << [filename, error] ; next
|
37
|
-
end
|
33
|
+
FileUtils.cd(Ruhoh.paths.base) { parsed_page = Ruhoh::Utils.parse_page_file(filename) }
|
38
34
|
data = parsed_page['data']
|
39
35
|
|
40
|
-
filename_data = self.
|
36
|
+
filename_data = self.parse_page_filename(filename)
|
41
37
|
if filename_data.empty?
|
42
38
|
error = "Invalid Filename Format. Format should be: my-post-title.ext"
|
43
39
|
invalid << [filename, error] ; next
|
@@ -59,6 +55,7 @@ class Ruhoh
|
|
59
55
|
data['id'] = filename
|
60
56
|
data['title'] = data['title'] || filename_data['title']
|
61
57
|
data['url'] = self.permalink(data)
|
58
|
+
data['layout'] = Ruhoh.config.posts_layout if data['layout'].nil?
|
62
59
|
dictionary[filename] = data
|
63
60
|
end
|
64
61
|
|
@@ -77,8 +74,8 @@ class Ruhoh
|
|
77
74
|
end
|
78
75
|
|
79
76
|
def self.files
|
80
|
-
FileUtils.cd(Ruhoh.paths.
|
81
|
-
return Dir["#{Ruhoh.
|
77
|
+
FileUtils.cd(Ruhoh.paths.base) {
|
78
|
+
return Dir["#{Ruhoh.names.posts}/**/*.*"].select { |filename|
|
82
79
|
next unless self.is_valid_page?(filename)
|
83
80
|
true
|
84
81
|
}
|
@@ -88,7 +85,7 @@ class Ruhoh
|
|
88
85
|
def self.is_valid_page?(filepath)
|
89
86
|
return false if FileTest.directory?(filepath)
|
90
87
|
return false if ['.'].include? filepath[0]
|
91
|
-
Ruhoh.
|
88
|
+
Ruhoh.config.posts_exclude.each {|regex| return false if filepath =~ regex }
|
92
89
|
true
|
93
90
|
end
|
94
91
|
|
@@ -102,7 +99,7 @@ class Ruhoh
|
|
102
99
|
ordered_posts
|
103
100
|
end
|
104
101
|
|
105
|
-
def self.
|
102
|
+
def self.parse_page_filename(filename)
|
106
103
|
data = *filename.match(DateMatcher)
|
107
104
|
data = *filename.match(Matcher) if data.empty?
|
108
105
|
return {} if data.empty?
|
@@ -127,41 +124,44 @@ class Ruhoh
|
|
127
124
|
|
128
125
|
# my-post-title ===> My Post Title
|
129
126
|
def self.to_title(file_slug)
|
130
|
-
file_slug.gsub(/[
|
127
|
+
file_slug.gsub(/[^\p{Word}+]/u, ' ').gsub(/\b\w/){$&.upcase}
|
131
128
|
end
|
132
129
|
|
133
|
-
# My Post Title ===> my-post-title
|
134
|
-
def self.to_slug(title)
|
135
|
-
title.downcase.strip.gsub(/\s/, '-').gsub(/[^\w-]/, '')
|
136
|
-
end
|
137
|
-
|
138
130
|
# Used in the client implementation to turn a draft into a post.
|
139
131
|
def self.to_filename(data)
|
140
|
-
File.join(Ruhoh.paths.posts, "#{
|
132
|
+
File.join(Ruhoh.paths.posts, "#{Ruhoh::Urls.to_slug(data['title'])}.#{data['ext']}")
|
141
133
|
end
|
142
134
|
|
143
135
|
# Another blatently stolen method from Jekyll
|
136
|
+
# The category is only the first one if multiple categories exist.
|
144
137
|
def self.permalink(post)
|
145
138
|
date = Date.parse(post['date'])
|
146
|
-
title = post['title']
|
147
|
-
format = post['permalink'] || Ruhoh.config.
|
139
|
+
title = Ruhoh::Urls.to_url_slug(post['title'])
|
140
|
+
format = post['permalink'] || Ruhoh.config.posts_permalink || "/:categories/:year/:month/:day/:title.html"
|
141
|
+
|
142
|
+
# Use the literal permalink if it is a non-tokenized string.
|
143
|
+
unless format.include?(':')
|
144
|
+
url = format.gsub(/^\//, '').split('/').map {|p| CGI::escape(p) }.join('/')
|
145
|
+
return "/#{url}"
|
146
|
+
end
|
147
|
+
|
148
|
+
filename = File.basename(post['id'], File.extname(post['id']))
|
149
|
+
category = Array(post['categories'])[0]
|
150
|
+
category = category.split('/').map {|c| Ruhoh::Urls.to_url_slug(c) }.join('/') if category
|
148
151
|
|
149
152
|
url = {
|
150
153
|
"year" => date.strftime("%Y"),
|
151
154
|
"month" => date.strftime("%m"),
|
152
155
|
"day" => date.strftime("%d"),
|
153
|
-
"title" =>
|
156
|
+
"title" => title,
|
157
|
+
"filename" => filename,
|
154
158
|
"i_day" => date.strftime("%d").to_i.to_s,
|
155
159
|
"i_month" => date.strftime("%m").to_i.to_s,
|
156
|
-
"categories" =>
|
157
|
-
"output_ext" => 'html' # what's this for?
|
160
|
+
"categories" => category || '',
|
158
161
|
}.inject(format) { |result, token|
|
159
162
|
result.gsub(/:#{Regexp.escape token.first}/, token.last)
|
160
|
-
}.gsub(
|
163
|
+
}.gsub(/\/+/, "/")
|
161
164
|
|
162
|
-
# sanitize url
|
163
|
-
url = url.split('/').reject{ |part| part =~ /^\.+$/ }.join('/')
|
164
|
-
url += "/" if url =~ /\/$/
|
165
165
|
url
|
166
166
|
end
|
167
167
|
|
@@ -223,7 +223,6 @@ class Ruhoh
|
|
223
223
|
tags[tag] = {
|
224
224
|
'count' => 1,
|
225
225
|
'name' => tag,
|
226
|
-
'url' => "/tags.html##{tag}-ref",
|
227
226
|
'posts' => []
|
228
227
|
}
|
229
228
|
end
|
@@ -236,7 +235,7 @@ class Ruhoh
|
|
236
235
|
|
237
236
|
def self.parse_categories(ordered_posts)
|
238
237
|
categories = {}
|
239
|
-
|
238
|
+
|
240
239
|
ordered_posts.each do |post|
|
241
240
|
Array(post['categories']).each do |cat|
|
242
241
|
cat = Array(cat).join('/')
|
@@ -246,7 +245,6 @@ class Ruhoh
|
|
246
245
|
categories[cat] = {
|
247
246
|
'count' => 1,
|
248
247
|
'name' => cat,
|
249
|
-
'url' => "/categories.html##{cat}-ref",
|
250
248
|
'posts' => []
|
251
249
|
}
|
252
250
|
end
|
data/lib/ruhoh/parsers/site.rb
CHANGED
@@ -6,8 +6,8 @@ class Ruhoh
|
|
6
6
|
module Site
|
7
7
|
|
8
8
|
def self.generate
|
9
|
-
site = Ruhoh::Utils.
|
10
|
-
config = Ruhoh::Utils.
|
9
|
+
site = Ruhoh::Utils.parse_yaml_file(Ruhoh.paths.site_data) || {}
|
10
|
+
config = Ruhoh::Utils.parse_yaml_file(Ruhoh.paths.config_data)
|
11
11
|
site['config'] = config
|
12
12
|
site
|
13
13
|
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
class Ruhoh
|
2
|
+
module Parsers
|
3
|
+
# Collect all registered stylesheets.
|
4
|
+
# Themes explicitly define which stylesheets to load via theme.yml.
|
5
|
+
# All styling is managed by the theme, including widget styles.
|
6
|
+
# If the theme provides widget stylesheets they will load automatically.
|
7
|
+
# theme.yml may also specify an explicit widget stylesheet to load.
|
8
|
+
module Stylesheets
|
9
|
+
|
10
|
+
# Generates mappings to all registered stylesheets.
|
11
|
+
# Returns Hash with layout names as keys and Array of asset Objects as values
|
12
|
+
def self.generate
|
13
|
+
theme_config = self.theme_config
|
14
|
+
assets = self.theme_stylesheets(theme_config)
|
15
|
+
assets[Ruhoh.names.widgets] = self.widget_stylesheets(theme_config)
|
16
|
+
assets
|
17
|
+
end
|
18
|
+
|
19
|
+
# Create mappings for stylesheets registered to the theme layouts.
|
20
|
+
# Themes register stylesheets relative to their layouts.
|
21
|
+
# Returns Hash with layout names as keys and Array of asset Objects as values.
|
22
|
+
def self.theme_stylesheets(theme_config)
|
23
|
+
return {} unless theme_config[Ruhoh.names.stylesheets].is_a? Hash
|
24
|
+
assets = {}
|
25
|
+
theme_config[Ruhoh.names.stylesheets].each do |key, value|
|
26
|
+
next if key == Ruhoh.names.widgets # Widgets are handled separately.
|
27
|
+
assets[key] = Array(value).map { |v|
|
28
|
+
{
|
29
|
+
"url" => "#{Ruhoh.urls.theme_stylesheets}/#{v}",
|
30
|
+
"id" => File.join(Ruhoh.paths.theme_stylesheets, v)
|
31
|
+
}
|
32
|
+
}
|
33
|
+
end
|
34
|
+
|
35
|
+
assets
|
36
|
+
end
|
37
|
+
|
38
|
+
# Create mappings for stylesheets registered to a given widget.
|
39
|
+
# A theme may provide widget stylesheets which will load automatically,
|
40
|
+
# provided they adhere to the default naming rules.
|
41
|
+
# Themes may also specify an explicit widget stylesheet to load.
|
42
|
+
#
|
43
|
+
# Returns Array of asset objects.
|
44
|
+
def self.widget_stylesheets(theme_config)
|
45
|
+
assets = []
|
46
|
+
Ruhoh::DB.widgets.each_key do |name|
|
47
|
+
default_name = "#{name}.css"
|
48
|
+
stylesheet = theme_config[Ruhoh.names.stylesheets][Ruhoh.names.widgets][name] rescue default_name
|
49
|
+
stylesheet ||= default_name
|
50
|
+
file = File.join(Ruhoh.paths.theme_widgets, name, Ruhoh.names.stylesheets, stylesheet)
|
51
|
+
next unless File.exists?(file)
|
52
|
+
assets << {
|
53
|
+
"url" => [Ruhoh.urls.theme_widgets, name, Ruhoh.names.stylesheets, stylesheet].join('/'),
|
54
|
+
"id" => file
|
55
|
+
}
|
56
|
+
end
|
57
|
+
|
58
|
+
assets
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.theme_config
|
62
|
+
theme_config = Ruhoh::Utils.parse_yaml_file(Ruhoh.paths.theme_config_data)
|
63
|
+
if theme_config.nil?
|
64
|
+
Ruhoh::Friend.say{
|
65
|
+
yellow "WARNING: theme.yml config file not found:"
|
66
|
+
yellow " #{Ruhoh.paths.theme_config_data}"
|
67
|
+
}
|
68
|
+
return {}
|
69
|
+
end
|
70
|
+
return {} unless theme_config.is_a? Hash
|
71
|
+
theme_config
|
72
|
+
end
|
73
|
+
end #Stylesheets
|
74
|
+
end #Parsers
|
75
|
+
end #Ruhoh
|
@@ -0,0 +1,104 @@
|
|
1
|
+
class Ruhoh
|
2
|
+
module Parsers
|
3
|
+
module Widgets
|
4
|
+
WidgetStructure = Struct.new(
|
5
|
+
:name,
|
6
|
+
:config,
|
7
|
+
:javascripts,
|
8
|
+
:layout
|
9
|
+
)
|
10
|
+
|
11
|
+
# Process available widgets into widget dictionary.
|
12
|
+
#
|
13
|
+
# Returns Dictionary of widget data.
|
14
|
+
def self.generate
|
15
|
+
widgets = {}
|
16
|
+
self.widgets.each do |name|
|
17
|
+
config = self.process_config(name)
|
18
|
+
widgets[name] = WidgetStructure.new(
|
19
|
+
name,
|
20
|
+
config,
|
21
|
+
self.process_javascripts(config, name),
|
22
|
+
self.process_layout(config, name)
|
23
|
+
)
|
24
|
+
end
|
25
|
+
Ruhoh::Utils.report('Widgets', widgets, [])
|
26
|
+
|
27
|
+
widgets
|
28
|
+
end
|
29
|
+
|
30
|
+
# Find the widgets.
|
31
|
+
#
|
32
|
+
# Returns Array of widget names.
|
33
|
+
def self.widgets
|
34
|
+
names = []
|
35
|
+
if FileTest.directory?(Ruhoh.paths.widgets)
|
36
|
+
FileUtils.cd(Ruhoh.paths.widgets) { names += Dir["*"] }
|
37
|
+
end
|
38
|
+
if FileTest.directory?(Ruhoh.paths.system_widgets)
|
39
|
+
FileUtils.cd(Ruhoh.paths.system_widgets) { names += Dir["*"] }
|
40
|
+
end
|
41
|
+
names.uniq!
|
42
|
+
names
|
43
|
+
end
|
44
|
+
|
45
|
+
# Process the widget configuration params.
|
46
|
+
#
|
47
|
+
# Returns Hash of configuration params.
|
48
|
+
def self.process_config(widget_name)
|
49
|
+
system_config = Ruhoh::Utils.parse_yaml_file(Ruhoh.paths.system_widgets, widget_name, Ruhoh.names.config_data) || {}
|
50
|
+
user_config = Ruhoh::Utils.parse_yaml_file(Ruhoh.paths.widgets, widget_name, Ruhoh.names.config_data) || {}
|
51
|
+
config = Ruhoh::Utils.deep_merge(system_config, user_config)
|
52
|
+
config['layout'] ||= widget_name
|
53
|
+
config['stylesheet'] ||= widget_name
|
54
|
+
config
|
55
|
+
end
|
56
|
+
|
57
|
+
# Process widget script dependencies.
|
58
|
+
# Script dependencies may be set in the config.
|
59
|
+
# Look for default script at: scripts/{widget_name}.js if no config.
|
60
|
+
# If found, we include it, else no javascripts will load.
|
61
|
+
#
|
62
|
+
# Returns Array of script filenames to load.
|
63
|
+
def self.process_javascripts(config, widget_name)
|
64
|
+
scripts = config[Ruhoh.names.javascripts] ? Array(config[Ruhoh.names.javascripts]) : []
|
65
|
+
|
66
|
+
# Try for the default script if no config.
|
67
|
+
if scripts.empty?
|
68
|
+
script_file = File.join(Ruhoh.paths.widgets, widget_name, Ruhoh.names.javascripts, "#{widget_name}.js")
|
69
|
+
if File.exist?(script_file)
|
70
|
+
scripts << "#{widget_name}.js"
|
71
|
+
else
|
72
|
+
script_file = File.join(Ruhoh.paths.system_widgets, widget_name, Ruhoh.names.javascripts, "#{widget_name}.js")
|
73
|
+
scripts << "#{widget_name}.js" if File.exist?(script_file)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
scripts
|
78
|
+
end
|
79
|
+
|
80
|
+
# Determine and process the correct widget layout.
|
81
|
+
# The layout may be manually configured by the user,
|
82
|
+
# else system defaults will be used.
|
83
|
+
# Layouts cascade from: theme -> blog -> system
|
84
|
+
#
|
85
|
+
# Returns String of rendered layout content.
|
86
|
+
def self.process_layout(config, widget_name)
|
87
|
+
layout = nil
|
88
|
+
layout_path = File.join(widget_name, 'layouts', "#{config['layout']}.html")
|
89
|
+
[
|
90
|
+
File.join(Ruhoh.paths.theme_widgets, layout_path),
|
91
|
+
File.join(Ruhoh.paths.widgets, layout_path),
|
92
|
+
File.join(Ruhoh.paths.system_widgets, layout_path)
|
93
|
+
].each do |path|
|
94
|
+
layout = path and break if File.exist?(path)
|
95
|
+
end
|
96
|
+
|
97
|
+
return '' unless layout
|
98
|
+
content = File.open(layout, 'r:UTF-8') { |f| f.read }
|
99
|
+
Mustache.render(content, {'config' => config})
|
100
|
+
end
|
101
|
+
|
102
|
+
end #Widgets
|
103
|
+
end #Parsers
|
104
|
+
end #Ruhoh
|