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.
Files changed (71) hide show
  1. data/Gemfile +1 -0
  2. data/README.md +0 -33
  3. data/dash.html +1 -0
  4. data/history.json +29 -0
  5. data/lib/ruhoh/client/client.rb +30 -22
  6. data/lib/ruhoh/client/help.yml +6 -2
  7. data/lib/ruhoh/compiler.rb +8 -20
  8. data/lib/ruhoh/compilers/rss.rb +36 -0
  9. data/lib/ruhoh/compilers/theme.rb +41 -0
  10. data/lib/ruhoh/config.rb +49 -0
  11. data/lib/ruhoh/converters/converter.rb +17 -4
  12. data/lib/ruhoh/converters/markdown.rb +2 -2
  13. data/lib/ruhoh/db.rb +29 -2
  14. data/lib/ruhoh/deployers/s3.rb +1 -1
  15. data/lib/ruhoh/logger.rb +1 -1
  16. data/lib/ruhoh/page.rb +38 -22
  17. data/lib/ruhoh/parsers/javascripts.rb +67 -0
  18. data/lib/ruhoh/parsers/layouts.rb +6 -10
  19. data/lib/ruhoh/parsers/pages.rb +17 -24
  20. data/lib/ruhoh/parsers/partials.rb +6 -14
  21. data/lib/ruhoh/parsers/payload.rb +47 -0
  22. data/lib/ruhoh/parsers/posts.rb +27 -29
  23. data/lib/ruhoh/parsers/site.rb +2 -2
  24. data/lib/ruhoh/parsers/stylesheets.rb +75 -0
  25. data/lib/ruhoh/parsers/widgets.rb +104 -0
  26. data/lib/ruhoh/paths.rb +75 -0
  27. data/lib/ruhoh/previewer.rb +11 -5
  28. data/lib/ruhoh/program.rb +35 -4
  29. data/lib/ruhoh/templaters/asset_helpers.rb +66 -0
  30. data/lib/ruhoh/templaters/base_helpers.rb +143 -0
  31. data/lib/ruhoh/templaters/helpers.rb +1 -148
  32. data/lib/ruhoh/templaters/rmustache.rb +45 -4
  33. data/lib/ruhoh/urls.rb +46 -0
  34. data/lib/ruhoh/utils.rb +59 -17
  35. data/lib/ruhoh/version.rb +2 -2
  36. data/lib/ruhoh/watch.rb +26 -14
  37. data/lib/ruhoh.rb +38 -96
  38. data/ruhoh.gemspec +29 -10
  39. data/scaffolds/draft.html +9 -0
  40. data/scaffolds/page.html +0 -2
  41. data/scaffolds/post.html +0 -4
  42. data/scaffolds/theme/{images → javascripts}/.gitkeep +0 -0
  43. data/scaffolds/theme/layouts/default.html +2 -4
  44. data/scaffolds/theme/layouts/page.html +1 -1
  45. data/scaffolds/theme/layouts/post.html +1 -1
  46. data/scaffolds/theme/{css/style.css → media/.gitkeep} +0 -0
  47. data/scaffolds/theme/stylesheets/style.css +0 -0
  48. data/scaffolds/theme/theme.yml +27 -0
  49. data/scaffolds/theme/widgets/.gitkeep +0 -0
  50. data/spec/config_spec.rb +50 -0
  51. data/spec/db_spec.rb +28 -14
  52. data/spec/page_spec.rb +24 -35
  53. data/spec/parsers/layouts_spec.rb +5 -13
  54. data/spec/parsers/pages_spec.rb +13 -11
  55. data/spec/parsers/posts_spec.rb +34 -29
  56. data/spec/parsers/routes_spec.rb +2 -1
  57. data/spec/parsers/site_spec.rb +6 -5
  58. data/spec/setup_spec.rb +3 -47
  59. data/widgets/analytics/config.yml +5 -0
  60. data/{system_partials/analytics/getclicky → widgets/analytics/layouts/getclicky.html} +2 -2
  61. data/{system_partials/analytics/google → widgets/analytics/layouts/google.html} +1 -1
  62. data/widgets/comments/config.yml +12 -0
  63. data/{system_partials/comments/disqus → widgets/comments/layouts/disqus.html} +2 -2
  64. data/{system_partials/comments/facebook → widgets/comments/layouts/facebook.html} +1 -1
  65. data/{system_partials/comments/intensedebate → widgets/comments/layouts/intensedebate.html} +1 -1
  66. data/{system_partials/comments/livefyre → widgets/comments/layouts/livefyre.html} +1 -1
  67. data/widgets/google_prettify/config.yml +1 -0
  68. data/widgets/google_prettify/layouts/google_prettify.html +10 -0
  69. metadata +54 -31
  70. data/lib/ruhoh/templaters/base.rb +0 -57
  71. 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
- layouts[id] = Ruhoh::Utils.parse_file(Ruhoh.paths.layouts, filename)
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
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, invalid)
15
+ Ruhoh::Utils.report('Layouts', layouts, [])
20
16
  layouts
21
17
  end
22
18
 
23
19
  def self.files
24
- FileUtils.cd(Ruhoh.paths.layouts) {
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
@@ -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.site_source) { parsed_page = Ruhoh::Utils.parse_file(filename) }
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, invalid)
28
+ Ruhoh::Utils.report('Pages', dictionary, [])
31
29
  dictionary
32
30
  end
33
31
 
34
32
  def self.files
35
- FileUtils.cd(Ruhoh.paths.site_source) {
36
- return Dir["#{Ruhoh.folders.pages}/**/*.*"].select { |filename|
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.filters.pages.each {|regex| return false if filepath =~ regex }
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.folders.pages}/"), '')
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(/[\W\_]/, ' ').gsub(/\b\w/){$&.upcase}
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 'convertable' extensions for Markdown at the moment.
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
- url += if ['.md', '.markdown'].include?(ext)
69
- page['id'].gsub(Regexp.new("#{ext}$"), '.html')
70
- else
71
- page['id']
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 = "/" if url.empty?
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.system_partials.merge(self.global_partials).merge(self.theme_partials)
6
+ self.global_partials.merge(self.theme_partials)
9
7
  end
10
-
8
+
11
9
  def self.theme_partials
12
- self.process(Ruhoh.paths.partials)
10
+ self.process(Ruhoh.paths.theme_partials)
13
11
  end
14
12
 
15
13
  def self.global_partials
16
- self.process(Ruhoh.paths.global_partials)
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
@@ -30,14 +30,10 @@ class Ruhoh
30
30
 
31
31
  self.files.each do |filename|
32
32
  parsed_page = ''
33
- FileUtils.cd(Ruhoh.paths.site_source) { parsed_page = Ruhoh::Utils.parse_file(filename) }
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.parse_filename(filename)
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.site_source) {
81
- return Dir["#{Ruhoh.folders.posts}/**/*.*"].select { |filename|
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.filters.posts.each {|regex| return false if filepath =~ regex }
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.parse_filename(filename)
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(/[\W\_]/, ' ').gsub(/\b\w/){$&.upcase}
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, "#{self.to_slug(data['title'])}.#{data['ext']}")
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'].downcase.gsub(' ', '-').gsub('.','')
147
- format = post['permalink'] || Ruhoh.config.permalink || "/:categories/:year/:month/:day/:title.html"
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" => CGI::escape(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" => Array(post['categories'])[0] || '',
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
@@ -6,8 +6,8 @@ class Ruhoh
6
6
  module Site
7
7
 
8
8
  def self.generate
9
- site = Ruhoh::Utils.parse_file_as_yaml(Ruhoh.paths.site_source, Ruhoh.files.site) || {}
10
- config = Ruhoh::Utils.parse_file_as_yaml(Ruhoh.paths.site_source, Ruhoh.files.config)
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