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
data/README.markdown
ADDED
@@ -0,0 +1,155 @@
|
|
1
|
+
<h1>
|
2
|
+
<span>Broadway</span>
|
3
|
+
<span><img src="http://viatropos.github.com/broadway/favicon.png"/></span>
|
4
|
+
</h1>
|
5
|
+
|
6
|
+
Pluggable, portable, framework-friendly static site generator. Setting the Stage for the Ruby CMS.
|
7
|
+
|
8
|
+
## Usage
|
9
|
+
|
10
|
+
### Install
|
11
|
+
|
12
|
+
sudo gem install broadway
|
13
|
+
|
14
|
+
#### Test
|
15
|
+
|
16
|
+
rake test
|
17
|
+
|
18
|
+
### Structure
|
19
|
+
|
20
|
+
Everything uses relative paths from the site root.
|
21
|
+
|
22
|
+
.
|
23
|
+
|-- _config.yml
|
24
|
+
|-- _layouts
|
25
|
+
|-- _posts (generated output)
|
26
|
+
|-- _site (github's place)
|
27
|
+
|-- _source (sinatra application for development)
|
28
|
+
| |-- files (blog files to-be published)
|
29
|
+
| |-- posts (blog files)
|
30
|
+
| |-- lib (sinatra helpers)
|
31
|
+
| `-- public (sinatra public directory)
|
32
|
+
|-- shared (javascripts, css, media, etc.)
|
33
|
+
|-- index.html
|
34
|
+
|-- robots.txt (what google should ignore)
|
35
|
+
`-- sitemap.xml (google's sitemap from jekyll)
|
36
|
+
|
37
|
+
### Run
|
38
|
+
|
39
|
+
If you want to use this entirely as a web server, run this at your source root:
|
40
|
+
|
41
|
+
broadway
|
42
|
+
|
43
|
+
If you want to use it inside of Sinatra or Rails, create the site manually:
|
44
|
+
|
45
|
+
site = Broadway.build!
|
46
|
+
|
47
|
+
### Models
|
48
|
+
|
49
|
+
Broadway uses Site, Post, Asset, File, Link, Slug, and Configuration to solve pretty much everything for creating a fully featured site using just Textmate.
|
50
|
+
|
51
|
+
#### The Site
|
52
|
+
|
53
|
+
The `Site` is basically the static database.
|
54
|
+
|
55
|
+
- It holds a reference to all of your other models.
|
56
|
+
- It reads a `_config.yml` file from a directory.
|
57
|
+
- Creates `File` objects out of the directory tree.
|
58
|
+
- Converts `Files` into `Posts` with slugs, tags, categories, and dates if they fit the profile.
|
59
|
+
- Finds `Assets` from within `Posts`.
|
60
|
+
- And uses a DSL to build menus out of `Links`.
|
61
|
+
|
62
|
+
##### Api
|
63
|
+
|
64
|
+
site = Broadway::Site.new
|
65
|
+
# dynamic finders
|
66
|
+
site.(models) #=> array of all models
|
67
|
+
site.find_(model)_by_(property)(value) #=> first model matching property value
|
68
|
+
site.find_(models)_by_(property)(value) #=> all models matching property value
|
69
|
+
site.find_(model)(attributes) #=> first model matching attributes
|
70
|
+
site.find_(models)(attributes) #=> all models matching attributes
|
71
|
+
site.(model)_roots #=> all hierarchical models without a parent
|
72
|
+
|
73
|
+
#### The Post
|
74
|
+
|
75
|
+
The `Post` works just like the other static site generators, it is the content input.
|
76
|
+
|
77
|
+
- It has `metadata` (YAML header) which defines (nested) key-value attributes.
|
78
|
+
- It has a `Slug` based on the folder structure, title, date, and is customizable.
|
79
|
+
- It has `tags` defined by `metadata`, which can be scoped (e.g tags by "skill" vs. "favorite")
|
80
|
+
- It has `categories` based on the folder structure.
|
81
|
+
- It has a `kind`, specifying how the post should be treated (currently `post` or `page`).
|
82
|
+
- It has `children` if it is a `page`.
|
83
|
+
- It has `Assets` defined by `metadata`, if desired.
|
84
|
+
- It has a `date` if a) its title was formatted like `yyyy-mm-dd-title.extension`, or b) metadata has defined a `date` attribute.
|
85
|
+
|
86
|
+
##### Api
|
87
|
+
|
88
|
+
post = site.posts.first #=> e.g...
|
89
|
+
post.tags #=> ["ruby", "sinatra", "rails"]
|
90
|
+
post.categories #=> ["path", "to", "post"]
|
91
|
+
post.assets #=> array of Asset objects, if defined
|
92
|
+
post.file #=> associate file object, where all calculations are based
|
93
|
+
post.slug #=> slug calculation object
|
94
|
+
post.path #=> "/path/to/post"
|
95
|
+
post.url #=> "http://site.com/path/to/post"
|
96
|
+
post.kind #=> "page" or "post" (or whatever you define)
|
97
|
+
post.children #=> array of Post objects, if it's a "page"
|
98
|
+
post.title
|
99
|
+
post.data #=> access to everything in the yaml header
|
100
|
+
|
101
|
+
### The Configuration
|
102
|
+
|
103
|
+
The `Configuration` object is defined from `_config.yml` in the Broadway Site root.
|
104
|
+
|
105
|
+
- Nested YAML properties
|
106
|
+
- Can be used to store arbitrary data, such as site seo stuff, author, etc.
|
107
|
+
- Accessed in views via `c("path.to.attribute")`.
|
108
|
+
|
109
|
+
## Context
|
110
|
+
|
111
|
+
There are plenty of static site generators out there: [Jekyll](http://github.com/mojombo/jekyll), [Webby](http://github.com/TwP/webby), [Nanoc](http://github.com/ddfreyne/nanoc), [StaticMatic](http://github.com/staticmatic/staticmatic), [Middleman](http://github.com/tdreyno/middleman), [Mercury](http://github.com/jackhq/mercury), [Frank](http://github.com/blahed/frank), [DynamicMatic](http://github.com/nex3/dynamicmatic), [WebGen](http://github.com/gettalong/webgen), [Pekky](http://github.com/lukesutton/pekky), [Awestruct](http://github.com/bobmcwhirter/awestruct), [Massimo](http://github.com/petebrowne/massimo)... The problem with them is that they are completely separate frameworks from Sinatra and Rails. They're not meant to be used with either of those. It's a lot of work to integrate them.
|
112
|
+
|
113
|
+
Broadway makes Rails and Sinatra static-compatible.
|
114
|
+
|
115
|
+
Why integrate static sites with Rails and Sinatra?
|
116
|
+
|
117
|
+
1. So you can write posts in Textmate.
|
118
|
+
2. So you can organize your documents and still write complex app code around them.
|
119
|
+
3. So you can use all the helpers the frameworks have built in.
|
120
|
+
4. So you can use Haml and Sass.
|
121
|
+
5. So you can make pretty blogs and still think like a programmer.
|
122
|
+
6. So you can host it on Github Pages if you want.
|
123
|
+
|
124
|
+
## Tools
|
125
|
+
|
126
|
+
- [SeeSaw](http://meetseesaw.com): Convert HTML to HAML, Textile/Markdown to HTML, and lots of other conversions. Useful for converting html you find on sites to Haml for learning.
|
127
|
+
- [Sinatra, HAML, JQuery, Textile (cool blog)](http://blog.peepcode.com/tutorials/2010/about-this-blog). Random site I thought was cool.
|
128
|
+
- [Tilt](http://github.com/rtomayko/tilt)
|
129
|
+
|
130
|
+
## Sinatra on Broadway
|
131
|
+
|
132
|
+
Here is a [Sinatra + Broadway Example App](http://github.com/viatropos/broadway).
|
133
|
+
|
134
|
+
Below is a description on how you might setup a Sinatra app to be themeable and run via markdown files. TODO.
|
135
|
+
|
136
|
+
### Themes
|
137
|
+
|
138
|
+
Create a folder called shared/themes/my-theme-name. In there, create folders for html, touch, and flash. In the html folder, you need the following
|
139
|
+
|
140
|
+
.
|
141
|
+
|-- index.haml # home page (layout.haml is somewhere else entirely)
|
142
|
+
|-- about
|
143
|
+
|-- blog
|
144
|
+
|-- features
|
145
|
+
|-- demos
|
146
|
+
|-- download
|
147
|
+
|-- support
|
148
|
+
|-- community
|
149
|
+
|-- shared
|
150
|
+
| |-- stylesheets
|
151
|
+
| |-- javascripts
|
152
|
+
| |-- images
|
153
|
+
| `-- partials
|
154
|
+
| |-- _head.haml
|
155
|
+
| `-- _header.haml
|
data/lib/broadway.rb
CHANGED
@@ -1,6 +1,66 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
require "rubygems"
|
2
|
+
require "active_support"
|
3
|
+
require "active_support/core_ext"
|
4
|
+
require "fileutils"
|
5
|
+
require "time"
|
6
|
+
require "yaml"
|
7
|
+
require "cgi"
|
3
8
|
|
4
|
-
|
9
|
+
# settings
|
10
|
+
# require 'cockpit'
|
11
|
+
this = File.dirname(__FILE__) + "/broadway"
|
12
|
+
require "#{this}/ext"
|
13
|
+
requirements = %w(builders processors mixins resources).map { |dir| Dir["#{this}/#{dir}/*"] }
|
5
14
|
|
6
|
-
|
15
|
+
if defined?(::Sinatra)
|
16
|
+
requirements << Dir["#{this}/sinatra/**/*"]
|
17
|
+
end
|
18
|
+
|
19
|
+
requirements.flatten.each { |file| require file if File.extname(file) == ".rb" }
|
20
|
+
|
21
|
+
module Broadway
|
22
|
+
class << self
|
23
|
+
attr_accessor :site, :generator
|
24
|
+
|
25
|
+
def build(options = {})
|
26
|
+
process(:build, options)
|
27
|
+
end
|
28
|
+
|
29
|
+
def generator(&block)
|
30
|
+
@generator = block if block_given?
|
31
|
+
@generator
|
32
|
+
end
|
33
|
+
|
34
|
+
def generate(options = {}, &block)
|
35
|
+
block = generator unless block_given?
|
36
|
+
process(:generate, options, &block)
|
37
|
+
end
|
38
|
+
|
39
|
+
def process(method, options = {}, &block)
|
40
|
+
self.site ||= Broadway::Site.new(options)
|
41
|
+
self.site.send(method, &block)
|
42
|
+
self.site
|
43
|
+
end
|
44
|
+
|
45
|
+
def menu!(site, name, &block)
|
46
|
+
Broadway::Processor::Link.menu!(site, name, &block)
|
47
|
+
end
|
48
|
+
|
49
|
+
# path to views
|
50
|
+
def views
|
51
|
+
site.views_path
|
52
|
+
end
|
53
|
+
|
54
|
+
def public
|
55
|
+
site.public_path
|
56
|
+
end
|
57
|
+
|
58
|
+
def index
|
59
|
+
site.index_path
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def Broadway(*args, &block)
|
65
|
+
Broadway.define!(*args, &block)
|
66
|
+
end
|
@@ -1,27 +1,45 @@
|
|
1
1
|
class Hash
|
2
|
-
def
|
2
|
+
def recursively_symbolize_keys!
|
3
3
|
self.symbolize_keys!
|
4
4
|
self.values.each do |v|
|
5
5
|
if v.is_a? Hash
|
6
|
-
v.
|
6
|
+
v.recursively_symbolize_keys!
|
7
7
|
elsif v.is_a? Array
|
8
|
-
v.
|
8
|
+
v.recursively_symbolize_keys!
|
9
9
|
end
|
10
10
|
end
|
11
11
|
self
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
15
|
+
class String
|
16
|
+
def taggify(separator = "-", quoted = false)
|
17
|
+
result = self.dup.downcase.strip.gsub(/[^a-z0-9\.]/, separator).squeeze(separator)
|
18
|
+
result = "\"#{result}\"" if quoted && !(result =~ /\s+/).nil?
|
19
|
+
result
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
15
23
|
class Array
|
16
|
-
def
|
24
|
+
def recursively_symbolize_keys!
|
17
25
|
self.each do |item|
|
18
26
|
if item.is_a? Hash
|
19
|
-
item.
|
27
|
+
item.recursively_symbolize_keys!
|
20
28
|
elsif item.is_a? Array
|
21
|
-
item.
|
29
|
+
item.recursively_symbolize_keys!
|
22
30
|
end
|
23
31
|
end
|
24
32
|
end
|
33
|
+
|
34
|
+
# separator = ", ",
|
35
|
+
# max = 10_000
|
36
|
+
# quote = true|false
|
37
|
+
def taggify(space = " ", separator = ", ", max = 10_000)
|
38
|
+
quoted = !(separator =~ /\s+/).nil?
|
39
|
+
chop(separator, max) do |word|
|
40
|
+
word.taggify(space, quoted)
|
41
|
+
end.join(separator)
|
42
|
+
end
|
25
43
|
|
26
44
|
# http://snippets.dzone.com/posts/show/3486
|
27
45
|
def chunk(pieces)
|
@@ -39,6 +57,22 @@ class Array
|
|
39
57
|
end
|
40
58
|
end
|
41
59
|
|
60
|
+
class String
|
61
|
+
def nested_parameterize(sep = '-')
|
62
|
+
parameterized_string = self.dup
|
63
|
+
# Turn unwanted chars into the seperator
|
64
|
+
parameterized_string = parameterized_string.gsub(/'/, "").gsub(/[^a-z0-9\-_\+\/]+/i, sep)
|
65
|
+
unless sep.blank?
|
66
|
+
re_sep = Regexp.escape(sep)
|
67
|
+
# No more than one of the separator in a row.
|
68
|
+
parameterized_string.gsub!(/#{re_sep}{2,}/, sep)
|
69
|
+
# Remove leading/trailing separator.
|
70
|
+
parameterized_string.gsub!(/^#{re_sep}|#{re_sep}$/i, '')
|
71
|
+
end
|
72
|
+
parameterized_string.downcase
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
42
76
|
class Hash
|
43
77
|
# Merges self with another hash, recursively.
|
44
78
|
#
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Broadway
|
2
|
+
class Liquid
|
3
|
+
|
4
|
+
class << self
|
5
|
+
def transform(payload, layouts)
|
6
|
+
info = { :filters => [], :registers => { :site => self.site } }
|
7
|
+
# render and transform content (this becomes the final content of the object)
|
8
|
+
payload["content_type"] = self.content_type
|
9
|
+
self.output = Liquid::Template.parse(self.content).render(payload, info)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module Broadway
|
2
|
+
module Assetable
|
3
|
+
def self.included(base)
|
4
|
+
base.send :include, InstanceMethods
|
5
|
+
end
|
6
|
+
|
7
|
+
module InstanceMethods
|
8
|
+
def asset_types
|
9
|
+
%w(image video audio asset)
|
10
|
+
end
|
11
|
+
|
12
|
+
def assets
|
13
|
+
unless @assets
|
14
|
+
@assets = []
|
15
|
+
if self.data.has_key?("asset")
|
16
|
+
@assets << ::Broadway::Asset.new(self, "asset", data["asset"])
|
17
|
+
elsif self.data.has_key?("assets")
|
18
|
+
self.data["assets"].each do |name, asset|
|
19
|
+
@assets << ::Broadway::Asset.new(self, name, asset)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
@assets
|
25
|
+
end
|
26
|
+
|
27
|
+
def asset
|
28
|
+
assets.first
|
29
|
+
end
|
30
|
+
|
31
|
+
def num_assets
|
32
|
+
assets.length
|
33
|
+
end
|
34
|
+
|
35
|
+
def find_asset_by_name(name)
|
36
|
+
assets.detect { |asset| asset.name == name }
|
37
|
+
end
|
38
|
+
|
39
|
+
def method_missing(meth, *args, &block)
|
40
|
+
if asset_types.detect { |type| meth.to_s =~ /(\w+)_#{type}/ }
|
41
|
+
find_asset_by_name($1.to_s)
|
42
|
+
else
|
43
|
+
super(meth, *args, &block)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Broadway
|
2
|
+
module Configurable
|
3
|
+
def self.included(base)
|
4
|
+
base.send :include, InstanceMethods
|
5
|
+
end
|
6
|
+
|
7
|
+
module InstanceMethods
|
8
|
+
attr_accessor :data
|
9
|
+
|
10
|
+
# should only read the beginning of the file
|
11
|
+
def configure
|
12
|
+
self.content = file.read
|
13
|
+
|
14
|
+
if self.content =~ /^(---\s*\n.*?\n?)^(---\s*$\n?)/m
|
15
|
+
self.content = self.content[($1.size + $2.size)..-1]
|
16
|
+
|
17
|
+
self.data.merge!(YAML.load($1))
|
18
|
+
end
|
19
|
+
|
20
|
+
self.data ||= {}
|
21
|
+
end
|
22
|
+
|
23
|
+
def method_missing(meth, *args, &block)
|
24
|
+
if self.data && self.data.has_key?(meth.to_s)
|
25
|
+
self.data[meth.to_s]
|
26
|
+
else
|
27
|
+
super(meth, *args, &block)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|