broadway 0.0.3.5 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.markdown +155 -0
- data/lib/broadway.rb +64 -4
- data/lib/broadway/{core_ext.rb → ext.rb} +40 -6
- data/lib/broadway/filters/erb.rb +10 -0
- data/lib/broadway/filters/haml.rb +10 -0
- data/lib/broadway/filters/liquid.rb +14 -0
- data/lib/broadway/filters/markdown.rb +10 -0
- data/lib/broadway/filters/textile.rb +11 -0
- data/lib/broadway/migrators/blogger.rb +7 -0
- data/lib/broadway/migrators/wordpress.rb +7 -0
- data/lib/broadway/mixins/assetable.rb +48 -0
- data/lib/broadway/mixins/configurable.rb +32 -0
- data/lib/broadway/mixins/convertible.rb +25 -0
- data/lib/broadway/mixins/hierarchical.rb +61 -0
- data/lib/broadway/mixins/layoutable.rb +18 -0
- data/lib/broadway/mixins/pageable.rb +5 -0
- data/lib/broadway/mixins/processable.rb +44 -0
- data/lib/broadway/mixins/publishable.rb +36 -0
- data/lib/broadway/mixins/readable.rb +73 -0
- data/lib/broadway/mixins/resourceful.rb +27 -0
- data/lib/broadway/mixins/sluggable.rb +36 -0
- data/lib/broadway/mixins/sortable.rb +24 -0
- data/lib/broadway/mixins/taggable.rb +46 -0
- data/lib/broadway/mixins/themeable.rb +39 -0
- data/lib/broadway/processors/link.rb +45 -0
- data/lib/broadway/processors/post.rb +117 -0
- data/lib/broadway/processors/site.rb +77 -0
- data/lib/broadway/processors/tree.rb +121 -0
- data/lib/broadway/resources/asset.rb +28 -0
- data/lib/broadway/resources/configuration.rb +114 -0
- data/lib/broadway/resources/file.rb +88 -0
- data/lib/broadway/resources/layout.rb +28 -0
- data/lib/broadway/resources/link.rb +16 -0
- data/lib/broadway/resources/post.rb +63 -0
- data/lib/broadway/resources/site.rb +164 -0
- data/lib/broadway/resources/slug.rb +69 -0
- data/lib/broadway/sinatra/app.rb +21 -0
- data/lib/broadway/sinatra/helpers/collection_helper.rb +2 -1
- data/lib/broadway/sinatra/helpers/partial_helper.rb +5 -5
- data/lib/broadway/sinatra/helpers/text_helper.rb +5 -11
- data/lib/broadway/sinatra/processor.rb +84 -0
- data/lib/broadway/tasks.rb +1 -0
- data/lib/broadway/tasks/default.rake +85 -0
- metadata +46 -41
- data/README.textile +0 -306
- data/Rakefile +0 -85
- data/lib/broadway/api.rb +0 -51
- data/lib/broadway/asset.rb +0 -17
- data/lib/broadway/base.rb +0 -120
- data/lib/broadway/convertible.rb +0 -91
- data/lib/broadway/page.rb +0 -71
- data/lib/broadway/post.rb +0 -112
- data/lib/broadway/rails.rb +0 -3
- data/lib/broadway/resource.rb +0 -128
- data/lib/broadway/runner.rb +0 -62
- data/lib/broadway/sinatra.rb +0 -5
- data/lib/broadway/sinatra/base.rb +0 -90
- data/lib/broadway/sinatra/helpers.rb +0 -7
- data/lib/broadway/site.rb +0 -421
- data/lib/broadway/static_file.rb +0 -32
@@ -0,0 +1,45 @@
|
|
1
|
+
module Broadway
|
2
|
+
module Definition
|
3
|
+
class Link
|
4
|
+
attr_accessor :site, :context, :records
|
5
|
+
|
6
|
+
def initialize(site, context, &block)
|
7
|
+
self.site = site
|
8
|
+
self.context = context
|
9
|
+
self.records = []
|
10
|
+
instance_eval(&block)
|
11
|
+
end
|
12
|
+
|
13
|
+
def link(*args, &block)
|
14
|
+
options = args.extract_options!
|
15
|
+
href = args.shift
|
16
|
+
title = args.shift || options[:title] || href.split("/").last.titleize
|
17
|
+
record = Broadway::Link.new(site, :href => href, :title => title, :categories => [context.to_s])
|
18
|
+
self.records << record
|
19
|
+
site.links << record
|
20
|
+
if block_given?
|
21
|
+
record.children = Broadway::Definition::Link.new(site, context, &block).records
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
module Processor
|
28
|
+
class Link
|
29
|
+
class << self
|
30
|
+
def tree!(site, name, &block)
|
31
|
+
Broadway::Definition::Link.new(site, name, &block).records
|
32
|
+
end
|
33
|
+
alias menu! tree!
|
34
|
+
end
|
35
|
+
|
36
|
+
def initialize(link, site, options = {})
|
37
|
+
link.site = site
|
38
|
+
link.href = options[:href]
|
39
|
+
link.title = options[:title]
|
40
|
+
link.categories = options[:categories]
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
module Broadway
|
2
|
+
module Processor
|
3
|
+
class Post
|
4
|
+
class << self
|
5
|
+
|
6
|
+
# RULES:
|
7
|
+
# Pages are only index.textile files, or static .html files (TODO)
|
8
|
+
# Posts are leaf nodes (name.textile files)
|
9
|
+
# Categories are the directoryectory name split plus anything extra defined
|
10
|
+
# Pages and Posts can also be obtained via index.xml files
|
11
|
+
def build(parent, site)
|
12
|
+
result = Dir.entries(parent).collect do |path|
|
13
|
+
# removes junk, leaves us with .xml, .textile, .html
|
14
|
+
next if skip?(path)
|
15
|
+
name = File.file_name(path)
|
16
|
+
next if name == "index"
|
17
|
+
ext = File.file_ext(path)
|
18
|
+
file = ::File.join(parent, path)
|
19
|
+
if %w(textile markdown html).include?(ext)
|
20
|
+
::Broadway::Post.new(site, :file => file)
|
21
|
+
elsif page = Post.page_exists?(file)
|
22
|
+
::Broadway::Post.new(site, :file => page)
|
23
|
+
else
|
24
|
+
nil
|
25
|
+
end
|
26
|
+
end.compact
|
27
|
+
|
28
|
+
result.sort!
|
29
|
+
|
30
|
+
# finally, we have set all the initial variables on the
|
31
|
+
# pages and posts we need, now we can process them to find
|
32
|
+
# the content and generate the urls
|
33
|
+
result.each do |post|
|
34
|
+
site.posts << post
|
35
|
+
post.categories.each { |c| site.categories[c] << post }
|
36
|
+
post.tags.each { |c| site.tags[c] << post }
|
37
|
+
end
|
38
|
+
|
39
|
+
result
|
40
|
+
end
|
41
|
+
|
42
|
+
def page_exists?(file)
|
43
|
+
%w(markdown textile txt).each do |extension|
|
44
|
+
page = ::File.join(file, "index.#{extension}")
|
45
|
+
return page if ::File.exists?(page)
|
46
|
+
end
|
47
|
+
nil
|
48
|
+
end
|
49
|
+
|
50
|
+
# Filter out any files/directoryectories that are hidden or backup files (start
|
51
|
+
# with "." or "#" or end with "~"), or contain site content (start with "_"),
|
52
|
+
# or are excluded in the site settingsuration, unless they are web server
|
53
|
+
# files such as '.htaccess'
|
54
|
+
def skip?(path)
|
55
|
+
#return true if ::File.directory?(path)
|
56
|
+
file = ::File.basename(path)
|
57
|
+
return true if ['.htaccess'].include?(file)
|
58
|
+
['.', '_', '#'].include?(file[0..0]) || file[-1..-1] == '~'# || self.exclude.include?(file)
|
59
|
+
end
|
60
|
+
|
61
|
+
# sort all pages and posts
|
62
|
+
# determined by index.xml file (and later, for dates)
|
63
|
+
def sort!
|
64
|
+
sort_content(:post, site.posts)
|
65
|
+
end
|
66
|
+
|
67
|
+
def sort_content(type, contents)
|
68
|
+
method = type.to_s.pluralize
|
69
|
+
unnumbered = site.send(method).select { |content| content.position.nil? }
|
70
|
+
start_index = site.send(method).length - unnumbered.length
|
71
|
+
unnumbered.each_with_index { |content, index| content.position = start_index + index }
|
72
|
+
site.send(method).sort!
|
73
|
+
site.send(method)
|
74
|
+
end
|
75
|
+
|
76
|
+
# Constructs a hash map of Posts indexed by the specified Post attribute
|
77
|
+
#
|
78
|
+
# Returns {post_attr => [<Post>]}
|
79
|
+
def post_attr_hash(post_attr)
|
80
|
+
# Build a hash map based on the specified post attribute ( post attr => array of posts )
|
81
|
+
# then sort each array in reverse order
|
82
|
+
hash = Hash.new { |hash, key| hash[key] = Array.new }
|
83
|
+
self.posts.each { |p| p.send(post_attr.to_sym).each { |t| hash[t] << p } }
|
84
|
+
hash.values.map { |sortme| sortme.sort! { |a, b| b <=> a} }
|
85
|
+
return hash
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def initialize(post, site, options = {})
|
90
|
+
post.site = site
|
91
|
+
post.file = Broadway::File.new(site, options)
|
92
|
+
post.kind = "page" if post.file.slug == "index"
|
93
|
+
post.slug = Broadway::Slug.new(post.file.slug, post)
|
94
|
+
post.data = post.file.header
|
95
|
+
post.title = post.data["title"].blank? ? post.slug.titleize : post.data["title"]
|
96
|
+
if post.title.downcase == "index"
|
97
|
+
post.title = ::File.basename(post.file.directory).titleize
|
98
|
+
end
|
99
|
+
unless options[:recursive] == false
|
100
|
+
post.children = children(post.file.directory, site) if post.kind == "page"
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def children(path, site)
|
105
|
+
Post.build(path, site) if path
|
106
|
+
end
|
107
|
+
|
108
|
+
def read(attribute = nil)
|
109
|
+
post.file.read(attribute)
|
110
|
+
end
|
111
|
+
|
112
|
+
def write(to)
|
113
|
+
post.file.write(to)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module Broadway
|
2
|
+
module Processor
|
3
|
+
class Site
|
4
|
+
attr_accessor :site, :source, :destination, :lsi, :pygments, :exclude, :lists, :configuration
|
5
|
+
|
6
|
+
def initialize(site, settings)
|
7
|
+
self.site = Broadway.site = site
|
8
|
+
|
9
|
+
site.configuration = Broadway::Configuration.new(site, settings)
|
10
|
+
|
11
|
+
self.lists = []
|
12
|
+
self.source = settings[:source]
|
13
|
+
self.lsi = settings[:lsi]
|
14
|
+
self.pygments = settings[:pygments]
|
15
|
+
self.exclude = settings[:exclude] || []
|
16
|
+
|
17
|
+
reset
|
18
|
+
end
|
19
|
+
|
20
|
+
# first
|
21
|
+
def reset
|
22
|
+
site.posts = []
|
23
|
+
site.assets = []
|
24
|
+
site.links = []
|
25
|
+
site.files = []
|
26
|
+
site.categories = Hash.new { |hash, key| hash[key] = [] }
|
27
|
+
site.tags = Hash.new { |hash, key| hash[key] = [] }
|
28
|
+
end
|
29
|
+
|
30
|
+
def destination
|
31
|
+
settings[:destination]
|
32
|
+
end
|
33
|
+
|
34
|
+
def settings
|
35
|
+
site.settings
|
36
|
+
end
|
37
|
+
|
38
|
+
def process
|
39
|
+
build
|
40
|
+
generate
|
41
|
+
end
|
42
|
+
|
43
|
+
def build
|
44
|
+
self.reset
|
45
|
+
self.read
|
46
|
+
site
|
47
|
+
end
|
48
|
+
|
49
|
+
def generate(&block)
|
50
|
+
raise "pass a block to `generate`" unless block_given?
|
51
|
+
raise "define a destination for the site to be written to" if destination.blank?
|
52
|
+
Broadway::Sinatra::Processor.new(site).run(&block) if defined?(::Sinatra)
|
53
|
+
site
|
54
|
+
end
|
55
|
+
|
56
|
+
def read
|
57
|
+
roots
|
58
|
+
links
|
59
|
+
end
|
60
|
+
|
61
|
+
def roots
|
62
|
+
site.roots = Broadway::Processor::Post.build(source, site) if source
|
63
|
+
end
|
64
|
+
|
65
|
+
def links
|
66
|
+
#@links ||= Broadway::Processor::Link.build(source, site)
|
67
|
+
@links
|
68
|
+
end
|
69
|
+
|
70
|
+
def write
|
71
|
+
site.files.each do |file|
|
72
|
+
file.write(self.destination)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
# redefine the hierarchy of posts, or order them
|
2
|
+
# DSL for defining initial page hierarchy
|
3
|
+
module Broadway
|
4
|
+
module Processor
|
5
|
+
class Tree
|
6
|
+
attr_accessor :root
|
7
|
+
|
8
|
+
class << self
|
9
|
+
|
10
|
+
# lists are xml files we've collect, but we want to make sure we've
|
11
|
+
# created all the posts we need to beforehand
|
12
|
+
# this also sorts everything
|
13
|
+
def build(path)
|
14
|
+
list = ::File.join(source, "index.xml")
|
15
|
+
lists << list if ::File.exists?(list)
|
16
|
+
unless lists.blank?
|
17
|
+
require 'nokogiri'
|
18
|
+
lists.each do |path|
|
19
|
+
new_tree(path)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def new_tree(path)
|
25
|
+
site.tree.concat parse_tree(Nokogiri::XML(IO.read(path)).root)
|
26
|
+
end
|
27
|
+
|
28
|
+
def parse_tree(parent)
|
29
|
+
result = []
|
30
|
+
return result if parent.nil? || parent.children.nil? || parent.children.empty?
|
31
|
+
parent.children.each_with_index do |child, index|
|
32
|
+
next unless child.elem?
|
33
|
+
post = post_from_xml(child)
|
34
|
+
next unless post
|
35
|
+
if post.respond_to?(:children)
|
36
|
+
post.children.concat parse_tree(child)
|
37
|
+
end
|
38
|
+
post.position = index
|
39
|
+
result << post
|
40
|
+
end
|
41
|
+
result
|
42
|
+
end
|
43
|
+
|
44
|
+
def post_from_xml(post)
|
45
|
+
# post
|
46
|
+
# 1. If a "src" is defined, then we should have already created the post
|
47
|
+
# 2. If no "src", then post is specified inline (or there is no post yet)
|
48
|
+
path = (post["src"] || ::File.join(site.source, post["path"]) || "").gsub(/^\//, "").gsub(/\/$/, "").squeeze("/")
|
49
|
+
post = site.find_post_by_path(path)
|
50
|
+
unless post
|
51
|
+
if ::File.directory?(path)
|
52
|
+
page = Dir.entries(path)[2..-1].detect do |file|
|
53
|
+
::File.basename(file).split(".")[0..-2].join(".").downcase == "index"
|
54
|
+
end
|
55
|
+
if page
|
56
|
+
path = ::File.join(path, page)
|
57
|
+
post = site.find_post_by_path(path)
|
58
|
+
post ||= Broadway::Builder::Post.new_post(path)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
return unless post
|
64
|
+
|
65
|
+
%w(title image excerpt menu_title tooltip show_children post layout).each do |key|
|
66
|
+
post.data[key] = post[key] if post.has_attribute?(key)
|
67
|
+
end
|
68
|
+
post
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def initialize(*args, &block)
|
73
|
+
self.root = ::Broadway::Definition::Post.new(*args, &block)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
module Definition
|
78
|
+
class Base
|
79
|
+
def initialize(*args, &block)
|
80
|
+
options = args.extract_options!
|
81
|
+
|
82
|
+
options.each do |k, v|
|
83
|
+
self.send("#{k}=", v) if self.respond_to?(k)
|
84
|
+
end
|
85
|
+
|
86
|
+
instance_eval(&block) if block_given?
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
class Post
|
91
|
+
attr_accessor :title, :path, :tooltip, :show_children
|
92
|
+
|
93
|
+
def title(value = "")
|
94
|
+
@title = value if value
|
95
|
+
@title
|
96
|
+
end
|
97
|
+
|
98
|
+
def path(value = "")
|
99
|
+
@path = value if value
|
100
|
+
@path
|
101
|
+
end
|
102
|
+
|
103
|
+
def tooltip(value = "")
|
104
|
+
@tooltip = value if value
|
105
|
+
@tooltip
|
106
|
+
end
|
107
|
+
|
108
|
+
def show_children(value = "")
|
109
|
+
@show_children = value if value
|
110
|
+
@show_children
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
114
|
+
|
115
|
+
class Menu
|
116
|
+
|
117
|
+
end
|
118
|
+
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Broadway
|
2
|
+
class Asset
|
3
|
+
attr_accessor :site, :title, :tooltip, :thumb, :width, :height, :resource, :content_type, :name, :path
|
4
|
+
|
5
|
+
include Comparable
|
6
|
+
include Broadway::Resourceful
|
7
|
+
include Broadway::Readable
|
8
|
+
include Broadway::Sortable
|
9
|
+
include Broadway::Taggable
|
10
|
+
include Broadway::Configurable
|
11
|
+
|
12
|
+
def initialize(resource, name, options = {})
|
13
|
+
self.resource = resource
|
14
|
+
self.name = name
|
15
|
+
self.data = options.recursively_symbolize_keys!
|
16
|
+
self.path = options.delete(:path)
|
17
|
+
options.each do |k,v|
|
18
|
+
self.send("#{k}=", v) if self.respond_to?(k)
|
19
|
+
end
|
20
|
+
|
21
|
+
self.title ||= Broadway::File.file_name(self.path).titleize
|
22
|
+
end
|
23
|
+
|
24
|
+
def site
|
25
|
+
resource.site
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
module Broadway
|
2
|
+
class Configuration
|
3
|
+
attr_accessor :settings, :site
|
4
|
+
# Default options. Overriden by values in _settings.yml or command-line opts.
|
5
|
+
# (Strings rather symbols used for compatability with YAML)
|
6
|
+
DEFAULTS = {
|
7
|
+
:auto => false,
|
8
|
+
:server => false,
|
9
|
+
:server_port => 4000,
|
10
|
+
|
11
|
+
:source => ".",
|
12
|
+
:settings => "_config.yml",
|
13
|
+
:destination => "_site",
|
14
|
+
|
15
|
+
:lsi => false,
|
16
|
+
:pygments => false,
|
17
|
+
:markdown => "rdiscount",
|
18
|
+
:permalink => "pretty",
|
19
|
+
:url_type => "relative",
|
20
|
+
:url => "http://localhost:4567",
|
21
|
+
:locales => "locales",
|
22
|
+
:language => "en-US",
|
23
|
+
|
24
|
+
:maruku => {
|
25
|
+
:use_tex => false,
|
26
|
+
:use_divs => false,
|
27
|
+
:png_engine => "blahtex",
|
28
|
+
:png_dir => "images/latex",
|
29
|
+
:png_url => "/images/latex"
|
30
|
+
},
|
31
|
+
|
32
|
+
:layouts => "_layouts",
|
33
|
+
:posts_include => [".textile", ".markdown"],
|
34
|
+
:theme_path => "themes",
|
35
|
+
:theme_versions => ["main"]
|
36
|
+
} unless defined?(Broadway::Configuration::DEFAULTS)
|
37
|
+
|
38
|
+
|
39
|
+
def initialize(site, overrides)
|
40
|
+
self.site = site
|
41
|
+
self.settings = merge(overrides)
|
42
|
+
end
|
43
|
+
|
44
|
+
def merge(overrides)
|
45
|
+
DEFAULTS.deep_merge(read(overrides)).merge(overrides)
|
46
|
+
end
|
47
|
+
|
48
|
+
def get(path)
|
49
|
+
result = settings
|
50
|
+
path.to_s.split(".").each { |node| result = result[node.to_sym] if result }
|
51
|
+
result.nil? ? "" : result
|
52
|
+
end
|
53
|
+
|
54
|
+
def read(overrides)
|
55
|
+
overrides = overrides.recursively_symbolize_keys!
|
56
|
+
# _settings.yml may override default source location, but until
|
57
|
+
# then, we need to know where to look for _settings.yml
|
58
|
+
source = overrides[:source] || DEFAULTS[:source]
|
59
|
+
settings_file = overrides[:settings] || DEFAULTS[:settings]
|
60
|
+
settings_file = ::File.join(source, settings_file) unless ::File.exists?(settings_file)
|
61
|
+
# Get configuration from <source>/_config.yml
|
62
|
+
begin
|
63
|
+
settings = YAML.load_file(settings_file).recursively_symbolize_keys!
|
64
|
+
raise "Invalid configuration - #{settings_file}" if !settings.is_a?(Hash)
|
65
|
+
#$stdout.puts "Configuration from #{settings_file}"
|
66
|
+
rescue => err
|
67
|
+
puts err.inspect
|
68
|
+
#$stderr.puts "WARNING: Could not read configuration. Using defaults (and options)."
|
69
|
+
#$stderr.puts "\t" + err.to_s
|
70
|
+
settings = {}
|
71
|
+
end
|
72
|
+
|
73
|
+
settings
|
74
|
+
end
|
75
|
+
|
76
|
+
def merge_extra_settings!(settings)
|
77
|
+
locale = ::File.join(settings[:locales], "#{settings[:language]}.yml")
|
78
|
+
|
79
|
+
settings.merge!(YAML.load_file(locale)) if ::File.exists?(locale)
|
80
|
+
|
81
|
+
settings_dir = ::File.join(settings[:source], "settings")
|
82
|
+
return unless ::File.exists?(settings_dir)
|
83
|
+
Dir.glob("#{settings_dir}/**/*").each do |file|
|
84
|
+
next if ::File.directory?(file)
|
85
|
+
path = file.gsub(/settings\//, "").split(".")[0..-2].join("")
|
86
|
+
ext = ::File.extname(file)
|
87
|
+
if ext =~ /yml/
|
88
|
+
data = YAML.load_file(file)
|
89
|
+
elsif ext =~ /xml/
|
90
|
+
data = parse_children Nokogiri::XML(IO.read(file)).children[0]
|
91
|
+
else
|
92
|
+
data = IO.read(file)
|
93
|
+
end
|
94
|
+
next unless data
|
95
|
+
name = path.split("/").first
|
96
|
+
if path =~ /\//
|
97
|
+
settings[name] ||= {}
|
98
|
+
target = settings[name]
|
99
|
+
name = path.split("/").last
|
100
|
+
else
|
101
|
+
target = settings
|
102
|
+
end
|
103
|
+
if target.has_key?(name)
|
104
|
+
target[name].merge!(data)
|
105
|
+
else
|
106
|
+
target[name] = data
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def setup
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|