broadway 0.0.3.5 → 0.1.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.
Files changed (60) hide show
  1. data/README.markdown +155 -0
  2. data/lib/broadway.rb +64 -4
  3. data/lib/broadway/{core_ext.rb → ext.rb} +40 -6
  4. data/lib/broadway/filters/erb.rb +10 -0
  5. data/lib/broadway/filters/haml.rb +10 -0
  6. data/lib/broadway/filters/liquid.rb +14 -0
  7. data/lib/broadway/filters/markdown.rb +10 -0
  8. data/lib/broadway/filters/textile.rb +11 -0
  9. data/lib/broadway/migrators/blogger.rb +7 -0
  10. data/lib/broadway/migrators/wordpress.rb +7 -0
  11. data/lib/broadway/mixins/assetable.rb +48 -0
  12. data/lib/broadway/mixins/configurable.rb +32 -0
  13. data/lib/broadway/mixins/convertible.rb +25 -0
  14. data/lib/broadway/mixins/hierarchical.rb +61 -0
  15. data/lib/broadway/mixins/layoutable.rb +18 -0
  16. data/lib/broadway/mixins/pageable.rb +5 -0
  17. data/lib/broadway/mixins/processable.rb +44 -0
  18. data/lib/broadway/mixins/publishable.rb +36 -0
  19. data/lib/broadway/mixins/readable.rb +73 -0
  20. data/lib/broadway/mixins/resourceful.rb +27 -0
  21. data/lib/broadway/mixins/sluggable.rb +36 -0
  22. data/lib/broadway/mixins/sortable.rb +24 -0
  23. data/lib/broadway/mixins/taggable.rb +46 -0
  24. data/lib/broadway/mixins/themeable.rb +39 -0
  25. data/lib/broadway/processors/link.rb +45 -0
  26. data/lib/broadway/processors/post.rb +117 -0
  27. data/lib/broadway/processors/site.rb +77 -0
  28. data/lib/broadway/processors/tree.rb +121 -0
  29. data/lib/broadway/resources/asset.rb +28 -0
  30. data/lib/broadway/resources/configuration.rb +114 -0
  31. data/lib/broadway/resources/file.rb +88 -0
  32. data/lib/broadway/resources/layout.rb +28 -0
  33. data/lib/broadway/resources/link.rb +16 -0
  34. data/lib/broadway/resources/post.rb +63 -0
  35. data/lib/broadway/resources/site.rb +164 -0
  36. data/lib/broadway/resources/slug.rb +69 -0
  37. data/lib/broadway/sinatra/app.rb +21 -0
  38. data/lib/broadway/sinatra/helpers/collection_helper.rb +2 -1
  39. data/lib/broadway/sinatra/helpers/partial_helper.rb +5 -5
  40. data/lib/broadway/sinatra/helpers/text_helper.rb +5 -11
  41. data/lib/broadway/sinatra/processor.rb +84 -0
  42. data/lib/broadway/tasks.rb +1 -0
  43. data/lib/broadway/tasks/default.rake +85 -0
  44. metadata +46 -41
  45. data/README.textile +0 -306
  46. data/Rakefile +0 -85
  47. data/lib/broadway/api.rb +0 -51
  48. data/lib/broadway/asset.rb +0 -17
  49. data/lib/broadway/base.rb +0 -120
  50. data/lib/broadway/convertible.rb +0 -91
  51. data/lib/broadway/page.rb +0 -71
  52. data/lib/broadway/post.rb +0 -112
  53. data/lib/broadway/rails.rb +0 -3
  54. data/lib/broadway/resource.rb +0 -128
  55. data/lib/broadway/runner.rb +0 -62
  56. data/lib/broadway/sinatra.rb +0 -5
  57. data/lib/broadway/sinatra/base.rb +0 -90
  58. data/lib/broadway/sinatra/helpers.rb +0 -7
  59. data/lib/broadway/site.rb +0 -421
  60. data/lib/broadway/static_file.rb +0 -32
@@ -1,3 +0,0 @@
1
- module Broadway::Rails
2
-
3
- end
@@ -1,128 +0,0 @@
1
- module Broadway::Resource
2
-
3
- def self.included(base)
4
- base.class_eval do
5
- include InstanceMethods
6
- end
7
- end
8
-
9
- module InstanceMethods
10
- attr_accessor :site, :position # order
11
- # where the file is
12
- attr_accessor :path, :dir, :basename, :ext, :title
13
- attr_accessor :data, :content, :output
14
- attr_accessor :date, :slug, :published, :categories, :asset
15
-
16
- # Extract information from the post filename
17
- # +name+ is the String filename of the post file
18
- #
19
- # Returns nothing
20
- def process(options = {})
21
- return if options.has_key?(:process) and options[:process] == false
22
-
23
- self.read_yaml(path)
24
-
25
- self.title = data["title"] || self.slug.split('-').select {|w| w.capitalize! || w }.join(' ')
26
-
27
- # If we've added a date and time to the yaml, use that instead of the filename date
28
- # Means we'll sort correctly.
29
- self.date = Time.parse(self.data["date"].to_s) if self.data.has_key?('date')
30
-
31
- if self.data.has_key?('published') && self.data['published'] == false
32
- self.published = false
33
- else
34
- self.published = true
35
- end
36
-
37
- if self.data.has_key?("asset")
38
- data["asset"]["title"] ||= self.title
39
- self.asset = ::Broadway::Asset.new(data["asset"])
40
- end
41
-
42
- self.tags = self.data["tags"]
43
- self.tags ||= []
44
- end
45
-
46
- def children
47
- key = self.categories.last
48
- length = self.url.split("/").length
49
- @children = site.find_pages_by_category(key) + site.find_posts_by_category(key)
50
- @children.delete_if do |child|
51
- (child.url == self.url) ||
52
- (child.url.split("/").length <= length) ||
53
- (child.is_a?(Broadway::Post) && child.categories != self.categories) ||
54
- (child.is_a?(Broadway::Page) && child.categories[0..-2] != self.categories)
55
- end
56
- end
57
-
58
- # The UID for this post (useful in feeds)
59
- # e.g. /2008/11/05/my-awesome-post
60
- #
61
- # Returns <String>
62
- def id
63
- File.join(self.dir, self.slug)
64
- end
65
-
66
- def menu_title
67
- self.data['menu_title'] || self.title
68
- end
69
-
70
- def tooltip
71
- self.data["tooltip"]
72
- end
73
-
74
- def permalink
75
- self.data['permalink']
76
- end
77
-
78
- def excerpt
79
- self.data['excerpt']
80
- end
81
-
82
- def show_children?
83
- return true if self.data.nil?
84
- if self.data.has_key?("show_children")
85
- return self.data["show_children"] == "true" || self.data["show_children"] == true
86
- end
87
- return true
88
- end
89
-
90
- def parent
91
- url ? site.find_page_by_url(url[1..-1].split("/").first) : nil
92
- end
93
-
94
- def layout
95
- self.data and self.data.has_key?("layout") ? self.data["layout"] : self.categories.first
96
- end
97
-
98
- def tags=(value)
99
- @tags = case value
100
- when Hash
101
- value = value.each { |k, v| value[k] = tag_array(v) }
102
- else
103
- {"tags" => tag_array(value)}
104
- end
105
- end
106
-
107
- # tags can be stored under multiple contexts
108
- # default is "tags" (use "categories" or whatever else you want)
109
- def tags(context = "tags")
110
- @tags[context.to_s]
111
- end
112
-
113
- private
114
-
115
- # helper method to convert tags to arrays
116
- def tag_array(value)
117
- result = case value
118
- when String
119
- value.split(",\s+")
120
- when Array
121
- value
122
- end
123
- result
124
- end
125
-
126
- end
127
-
128
- end
@@ -1,62 +0,0 @@
1
- module Broadway
2
-
3
- class Runner
4
-
5
- attr_accessor :site, :content, :url
6
-
7
- def initialize(site)
8
- self.site = site
9
- self.url = URI.parse(site.config[:url])
10
- self.content = site.pages + site.posts
11
- end
12
-
13
- def run(&block)
14
- versions = site.config[:theme_versions]
15
- puts "Connecting to... #{url.scheme}://#{url.host}:#{url.port}"
16
- item_url = nil
17
- versions.each do |version|
18
- prefix = version == "main" ? "" : version
19
- begin
20
- Net::HTTP.start(url.host, url.port) do |http|
21
- self.content.each do |item|
22
- if block_given?
23
- item_url = yield(item)
24
- else
25
- if prefix == "touch"
26
- item_url = "/touch#{item.url.gsub(".", "")}?layout=false"
27
- else
28
- item_url = ("/" + File.join(prefix, item.url.gsub(".", ""))).squeeze("/")
29
- end
30
- end
31
- puts "Connecting to... #{url.scheme}://#{url.host}:#{url.port}#{item_url}"
32
- item_dir = File.expand_path(File.join(site.config[:destination], prefix, item.url).squeeze("/"))
33
- response = http.get(item_url)
34
- # if the file doesn't exist or is not rendered correctly
35
- next if error?(response, item_url, false)
36
- FileUtils.mkdir_p(item_dir)
37
- name = File.join(item_dir, "index.html").squeeze("/")
38
- text = ""
39
- text << response.body
40
- puts "Writing... #{name}"
41
- File.open(name, "w") {|f| f.write(text) }
42
- end
43
- end
44
- rescue Exception => e
45
- puts e.inspect
46
- raise "Make sure you've started the server, run: 'ruby app.rb'"
47
- end
48
- end
49
- end
50
-
51
- def error?(response, path, whiny = true)
52
- if !response.is_a?(Net::HTTPSuccess)
53
- raise message if whiny
54
- puts "Error at '#{path}': #{response.to_s}"
55
- return true
56
- end
57
- false
58
- end
59
-
60
- end
61
-
62
- end
@@ -1,5 +0,0 @@
1
- module Broadway::Sinatra
2
-
3
- end
4
-
5
- require_local "sinatra/*"
@@ -1,90 +0,0 @@
1
- libdir = File.dirname(__FILE__)
2
- $LOAD_PATH.unshift(libdir) unless $LOAD_PATH.include?(libdir)
3
-
4
- require "sinatra"
5
- require "sinatra/base"
6
- require "sinatra_more"
7
-
8
- @site = site = Broadway.build
9
-
10
- Sinatra::Application.instance_eval do
11
- cattr_accessor :site
12
- self.site = site
13
- end
14
-
15
- def site
16
- @site
17
- end
18
-
19
- def default_locals(locals = {})
20
- {
21
- :environment => Sinatra::Application.environment,
22
- :theme_version => "main"
23
- }.merge(locals)
24
- end
25
-
26
- def default_options(options = {})
27
- if params.has_key?("layout") and params["layout"] == false
28
- options[:layout] = false
29
- else
30
- options[:layout] = !request.xhr?
31
- end
32
- options
33
- end
34
-
35
- def theme_path(version = "main")
36
- File.join(site.config[:theme_path], site.config[:theme], version)
37
- end
38
-
39
- # "main" is the default, so remove it
40
- def theme_versions
41
- site.config[:theme_versions]
42
- end
43
-
44
- def pages
45
- Dir.entries("public")
46
- end
47
-
48
- Sinatra::Application.class_eval do
49
- register SinatraMore::MarkupPlugin
50
- register SinatraMore::RoutingPlugin
51
- end
52
-
53
- def page_path(page, version)
54
- content_path(page, version, "index")
55
- end
56
-
57
- def post_path(post, version)
58
- content_path(post, version, "show")
59
- end
60
-
61
- def c(path)
62
- result = site.config
63
- path.to_s.split(".").each { |node| result = result[node.to_sym] if result }
64
- result.nil? ? [] : result
65
- end
66
-
67
- def content_path(content, version, action)
68
- # first check if it's in the posts directory (where textile files are)
69
- path = File.join(content.dir, action).squeeze("/")
70
- exists = false
71
- extensions = %w(html haml erb html.haml html.erb)
72
- target_path = File.join(site.config[:source], path)
73
- extensions.each do |ext|
74
- exists = true if File.exists?("#{target_path}.#{ext}")
75
- end
76
- return path if exists
77
- # then check if it's in the theme directory
78
- checked = [target_path]
79
- path = target_path = File.join(theme_path(version), content.layout, action).squeeze("/")
80
- exists = false
81
- extensions.each do |ext|
82
- exists = true if File.exists?(File.join(site.config[:source], "#{target_path}.#{ext}"))
83
- end
84
- return path if exists
85
- return File.join(theme_path(version), "index") if content.url == "/"
86
- checked << target_path
87
-
88
- puts "Couldn't find any paths for #{content.class.to_s.downcase.split(":").last} '#{content.url}': #{checked.inspect}"
89
- return nil
90
- end
@@ -1,7 +0,0 @@
1
- require_local "sinatra/helpers/*"
2
-
3
- helpers do
4
- files("sinatra/helpers/*") do |file|
5
- include "Broadway::Helpers::#{File.basename(file).split(".").first.camelize}".constantize
6
- end
7
- end
@@ -1,421 +0,0 @@
1
- module Broadway
2
-
3
- class Site
4
- attr_accessor :config, :layouts, :posts, :pages, :static_files, :categories, :exclude,
5
- :source, :dest, :lsi, :pygments, :permalink_style, :tags, :tree
6
-
7
- def self.generate
8
-
9
- end
10
-
11
- # Initialize the site
12
- # +config+ is a Hash containing site configurations details
13
- #
14
- # Returns <Site>
15
- def initialize(config)
16
- merge_extra_config!(config)
17
-
18
- config.recursive_symbolize_keys!
19
-
20
- self.config = config.clone
21
-
22
- self.source = config[:source]
23
- self.dest = config[:destination]
24
- self.lsi = config[:lsi]
25
- self.pygments = config[:pygments]
26
- self.permalink_style = config[:permalink].to_sym
27
- self.exclude = config[:exclude] || []
28
- self.tree = []
29
-
30
- self.reset
31
- self.setup
32
- end
33
-
34
- def merge_extra_config!(config)
35
- locale = File.join(config[:locales], "#{config[:language]}.yml")
36
-
37
- config.merge!(YAML.load_file(locale)) if File.exists?(locale)
38
-
39
-
40
- config_dir = File.join(config[:source], "config")
41
- return unless File.exists?(config_dir)
42
- Dir.glob("#{config_dir}/**/*").each do |file|
43
- next if File.directory?(file)
44
- path = file.gsub(/config\//, "").split(".")[0..-2].join("")
45
- ext = File.extname(file)
46
- if ext =~ /yml/
47
- data = YAML.load_file(file)
48
- elsif ext =~ /xml/
49
- data = parse_children Nokogiri::XML(IO.read(file)).children[0]
50
- else
51
- data = IO.read(file)
52
- end
53
- next unless data
54
- name = path.split("/").first
55
- if path =~ /\//
56
- config[name] ||= {}
57
- target = config[name]
58
- name = path.split("/").last
59
- else
60
- target = config
61
- end
62
- if target.has_key?(name)
63
- target[name].merge!(data)
64
- else
65
- target[name] = data
66
- end
67
- end
68
- end
69
-
70
- # first
71
- def reset
72
- self.layouts = {}
73
- self.posts = []
74
- self.pages = []
75
- self.static_files = []
76
- self.categories = Hash.new { |hash, key| hash[key] = [] }
77
- self.tags = Hash.new { |hash, key| hash[key] = [] }
78
- end
79
-
80
- # second
81
- # this just sets configuration variables on the dependencies, if necessary
82
- def setup
83
- # Check to see if LSI is enabled.
84
- require 'classifier' if self.lsi
85
-
86
- # Set the Markdown interpreter (and Maruku self.config, if necessary)
87
- case self.config[:markdown]
88
- when 'rdiscount'
89
- begin
90
- require 'rdiscount'
91
-
92
- def markdown(content)
93
- RDiscount.new(content).to_html
94
- end
95
-
96
- rescue LoadError
97
- puts 'You must have the rdiscount gem installed first'
98
- end
99
- when 'maruku'
100
- begin
101
- require 'maruku'
102
-
103
- def markdown(content)
104
- Maruku.new(content).to_html
105
- end
106
-
107
- if self.config[:maruku][:use_divs]
108
- require 'maruku/ext/div'
109
- puts 'Maruku: Using extended syntax for div elements.'
110
- end
111
-
112
- if self.config[:maruku][:use_tex]
113
- require 'maruku/ext/math'
114
- puts "Maruku: Using LaTeX extension. Images in `#{self.config[:maruku][:png_dir]}`."
115
-
116
- # Switch off MathML output
117
- MaRuKu::Globals[:html_math_output_mathml] = false
118
- MaRuKu::Globals[:html_math_engine] = 'none'
119
-
120
- # Turn on math to PNG support with blahtex
121
- # Resulting PNGs stored in `images/latex`
122
- MaRuKu::Globals[:html_math_output_png] = true
123
- MaRuKu::Globals[:html_png_engine] = self.config[:maruku][:png_engine]
124
- MaRuKu::Globals[:html_png_dir] = self.config[:maruku][:png_dir]
125
- MaRuKu::Globals[:html_png_url] = self.config[:maruku][:png_url]
126
- end
127
- rescue LoadError
128
- puts "The maruku gem is required for markdown support!"
129
- end
130
- else
131
- raise "Invalid Markdown processor: '#{self.config[:markdown]}' -- did you mean 'maruku' or 'rdiscount'?"
132
- end
133
- end
134
-
135
- def textile(content)
136
- RedCloth.new(content).to_html
137
- end
138
-
139
- # third
140
- # Do the actual work of processing the site and generating the
141
- # real deal. Now has 4 phases; reset, read, render, write. This allows
142
- # rendering to have full site payload available.
143
- #
144
- # Returns nothing
145
- def process
146
- build
147
- generate
148
- end
149
-
150
- def build
151
- puts "Building site: #{config[:source]} -> #{config[:destination]}"
152
- self.reset
153
- self.read
154
- puts "Successfully built site, nothing was written."
155
- end
156
-
157
- def generate
158
- puts "Generating site: #{config[:source]} -> #{config[:destination]}"
159
- self.render
160
- self.write
161
- puts "Successfully generated site: #{config[:source]} -> #{config[:destination]}"
162
- end
163
-
164
- def read
165
- self.read_layouts # existing implementation did this at top level only so preserved that
166
- self.read_directories
167
- end
168
-
169
- # Read all the files in <source>/<dir>/_layouts and create a new Layout
170
- # object with each one.
171
- #
172
- # Returns nothing
173
- def read_layouts(dir = '')
174
- base = File.join(self.source, dir, config[:layouts])
175
- return unless File.exists?(base)
176
- entries = []
177
- Dir.chdir(base) { entries = filter_entries(Dir['*.*']) }
178
- entries.each do |f|
179
- name = f.split(".")[0..-2].join(".")
180
- self.layouts[name] = Layout.new(self, base, f)
181
- end
182
- end
183
-
184
- # Reads the directories and finds posts, pages and static files that will
185
- # become part of the valid site according to the rules in +filter_entries+.
186
- # The +dir+ String is a relative path used to call this method
187
- # recursively as it descends through directories
188
- #
189
- # Returns nothing
190
- def read_directories(dir = '')
191
- base = File.join(self.source, dir).gsub(/\/$/, "")
192
- lists = []
193
-
194
- # RULES:
195
- # Pages are only index.textile files, or static .html files (TODO)
196
- # Posts are leaf nodes (name.textile files)
197
- # Categories are the directory name split plus anything extra defined
198
- # Pages and Posts can also be obtained via index.xml files
199
- Dir.glob("#{base}/**/*").each do |path|
200
- # removes junk, leaves us with .xml, .textile, .html
201
- next if filtered?(path)
202
- name = File.basename(path).split(".").first
203
- ext = File.extname(path).gsub(".", "")
204
- if name == "index"
205
- if ext != "xml"
206
- new_page(path)
207
- end
208
- elsif %w(textile markdown).include?(ext)
209
- new_post(path)
210
- else
211
- self.static_files << StaticFile.new(:site => self, :path => path)
212
- end
213
- end
214
-
215
- # lists are xml files we've collect, but we want to make sure we've
216
- # created all the posts we need to beforehand
217
- # this also sorts everything
218
- list = File.join(config[:source], "index.xml")
219
- lists << list if File.exists?(list)
220
- lists.each do |path|
221
- new_tree(path)
222
- end
223
-
224
- sort!
225
-
226
- # finally, we have set all the initial variables on the
227
- # pages and posts we need, now we can process them to find
228
- # the content and generate the urls
229
- self.pages.each do |page|
230
- page.process
231
- page.categories.each { |c| self.categories[c] << page }
232
- page.tags.each { |c| self.tags[c] << page }
233
- end
234
- self.posts.each do |post|
235
- post.process
236
- post.categories.each { |c| self.categories[c] << post }
237
- post.tags.each { |c| self.tags[c] << post }
238
- end
239
- end
240
-
241
- def new_page(path, options = {})
242
- return if path.nil? || path.empty?
243
- page = Page.new(options.merge(:site => self, :path => path, :process => false))
244
- self.pages << page
245
- page
246
- end
247
-
248
- def new_post(path, options = {})
249
- return if path.nil? || path.empty?
250
- post = Post.new(options.merge(:site => self, :path => path, :process => false))
251
- self.posts << post
252
- post
253
- end
254
-
255
- def new_tree(path)
256
- self.tree.concat parse_tree(Nokogiri::XML(IO.read(path)).root)
257
- end
258
-
259
- def parse_tree(parent)
260
- result = []
261
- return result if parent.nil? || parent.children.nil? || parent.children.empty?
262
- parent.children.each_with_index do |child, index|
263
- next unless child.elem?
264
- content = child.children.empty? ? post_from_xml(child) : page_from_xml(child)
265
- next unless content
266
- if content.respond_to?(:children)
267
- content.children.concat parse_tree(child)
268
- end
269
- content.position = index
270
- result << content
271
- end
272
- result
273
- end
274
-
275
- # http://stackoverflow.com/questions/1769126/fastest-one-liner-way-to-get-xml-nodes-into-array-of-path-to-nodes-in-ruby
276
- def node_list(elem, &proc)
277
- return [] unless elem.class == Nokogiri::XML::Element
278
- str = proc.call(elem)
279
- [str] + elem.children.inject([]){|a,c| a+node_list(c,&proc)}.map{|e| "#{str}/#{e}"}
280
- end
281
-
282
- def post_from_xml(content)
283
- # post
284
- # 1. If a "src" is defined, then we should have already created the post
285
- # 2. If no "src", then content is specified inline (or there is no content yet)
286
- post = find_post_by_path(content["src"]) || find_post_by_url(content["url"])
287
- path = (content["src"] || content["url"] || "").gsub(/^\//, "")
288
- post ||= new_post(path)
289
- return unless post
290
- %w(title image excerpt menu_title tooltip show_children content layout).each do |key|
291
- post.data[key] = content[key] if content.has_attribute?(key)
292
- end
293
- post
294
- end
295
-
296
- def page_from_xml(content)
297
- # page
298
- # 1. If a "src" is defined, then we should have already created the post
299
- # 2. If no "src", then content is specified inline (or there is no content yet)
300
- page = find_page_by_path(content["src"]) || find_page_by_url(content["url"])
301
- path = (content["src"] || content["url"] || "").gsub(/^\//, "")
302
- page ||= new_page(path)
303
- return unless page
304
- %w(title image excerpt menu_title tooltip show_children content layout).each do |key|
305
- page.data[key] = content[key] if content.has_attribute?(key)
306
- end
307
- page
308
- end
309
-
310
- # sort all pages and posts
311
- # determined by index.xml file (and later, for dates)
312
- def sort!
313
- sort_content(:page, self.pages)
314
- sort_content(:post, self.posts)
315
- end
316
-
317
- def sort_content(type, contents)
318
-
319
- method = type.to_s.pluralize
320
- unnumbered = self.send(method).select { |content| content.position.nil? }
321
- start_index = self.send(method).length - unnumbered.length
322
- unnumbered.each_with_index { |content, index| content.position = start_index + index }
323
- self.send(method).sort!
324
- self.send(method)
325
- end
326
-
327
- # While in Jekyll this method renders the content explicitly,
328
- # I'm using Sinatra, partly because I like having the flexibility
329
- # of using their get/post methods, and partly because I don't have
330
- # the time/desire to try to hack jekyll to use haml.
331
- # I'd rather just start over
332
- def render
333
- Runner.new(self).run
334
- end
335
-
336
- # Write static files, pages and posts
337
- #
338
- # Returns nothing
339
- def write
340
- self.static_files.each do |sf|
341
- sf.write(self.dest)
342
- end
343
- end
344
-
345
- # Constructs a hash map of Posts indexed by the specified Post attribute
346
- #
347
- # Returns {post_attr => [<Post>]}
348
- def post_attr_hash(post_attr)
349
- # Build a hash map based on the specified post attribute ( post attr => array of posts )
350
- # then sort each array in reverse order
351
- hash = Hash.new { |hash, key| hash[key] = Array.new }
352
- self.posts.each { |p| p.send(post_attr.to_sym).each { |t| hash[t] << p } }
353
- hash.values.map { |sortme| sortme.sort! { |a, b| b <=> a} }
354
- return hash
355
- end
356
-
357
- # The Hash payload containing site-wide data
358
- #
359
- # Returns {"site" => {"time" => <Time>,
360
- # "posts" => [<Post>],
361
- # "categories" => [<Post>]}
362
- def site_payload
363
- {"site" => self.config.merge({
364
- "time" => Time.now,
365
- "posts" => self.posts.sort { |a,b| b <=> a },
366
- "categories" => post_attr_hash('categories'),
367
- "tags" => post_attr_hash('tags')})}
368
- end
369
-
370
- # Filter out any files/directories that are hidden or backup files (start
371
- # with "." or "#" or end with "~"), or contain site content (start with "_"),
372
- # or are excluded in the site configuration, unless they are web server
373
- # files such as '.htaccess'
374
- def filtered?(path)
375
- return true if File.directory?(path)
376
- file = File.basename(path)
377
- return true if ['.htaccess'].include?(file)
378
- ['.', '_', '#'].include?(file[0..0]) || file[-1..-1] == '~' || self.exclude.include?(file)
379
- end
380
-
381
- def find(type, method, value)
382
- self.send(type.to_s.pluralize).select do |content|
383
- if content.respond_to?(method)
384
- content.send(method) == value
385
- else
386
- content.send(method.to_s.pluralize).include?(value)
387
- end
388
- end
389
- end
390
-
391
- def first(type, method, value)
392
- find(type, method, value).first
393
- end
394
-
395
- %w(category url path tag title).each do |property|
396
- %w(post page).each do |type|
397
- define_method "find_#{type}_by_#{property}" do |value|
398
- first(type.to_sym, property, value)
399
- end
400
- define_method "find_#{type.pluralize}_by_#{property}" do |value|
401
- find(type.to_sym, property, value)
402
- end
403
- end
404
- define_method "find_by_#{property}" do |value|
405
- first(:page, property, value) || first(:post, property, value)
406
- end
407
- end
408
-
409
- def page_count
410
- self.pages ? self.pages.length : 0
411
- end
412
-
413
- def post_count
414
- self.posts ? self.posts.length : 0
415
- end
416
-
417
- def inspect
418
- "#<Broadway:Site @page_count=#{self.page_count.to_s} @post_count=#{self.post_count.to_s}>"
419
- end
420
- end
421
- end