awestructx 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/awestruct +8 -0
- data/lib/awestruct/astruct.rb +22 -0
- data/lib/awestruct/astruct_mixin.rb +71 -0
- data/lib/awestruct/cli/auto.rb +20 -0
- data/lib/awestruct/cli/generate.rb +26 -0
- data/lib/awestruct/cli/invoker.rb +109 -0
- data/lib/awestruct/cli/options.rb +116 -0
- data/lib/awestruct/cli/server.rb +24 -0
- data/lib/awestruct/config.rb +30 -0
- data/lib/awestruct/context.rb +22 -0
- data/lib/awestruct/context_helper.rb +68 -0
- data/lib/awestruct/engine.rb +254 -0
- data/lib/awestruct/extensions/assets.rb +39 -0
- data/lib/awestruct/extensions/atomizer.rb +44 -0
- data/lib/awestruct/extensions/cachebuster.rb +12 -0
- data/lib/awestruct/extensions/coffeescripttransform.rb +42 -0
- data/lib/awestruct/extensions/data_dir.rb +31 -0
- data/lib/awestruct/extensions/disqus.rb +62 -0
- data/lib/awestruct/extensions/extend_string.rb +97 -0
- data/lib/awestruct/extensions/flattr.rb +42 -0
- data/lib/awestruct/extensions/google_analytics.rb +38 -0
- data/lib/awestruct/extensions/gsub.rb +20 -0
- data/lib/awestruct/extensions/indexifier.rb +17 -0
- data/lib/awestruct/extensions/intense_debate.rb +38 -0
- data/lib/awestruct/extensions/minify.rb +178 -0
- data/lib/awestruct/extensions/obfuscate.rb +32 -0
- data/lib/awestruct/extensions/paginator.rb +105 -0
- data/lib/awestruct/extensions/partial.rb +25 -0
- data/lib/awestruct/extensions/pipeline.rb +50 -0
- data/lib/awestruct/extensions/posts.rb +70 -0
- data/lib/awestruct/extensions/relative.rb +11 -0
- data/lib/awestruct/extensions/remotePartial.rb +17 -0
- data/lib/awestruct/extensions/sitemap.rb +85 -0
- data/lib/awestruct/extensions/sitemap.xml.haml +16 -0
- data/lib/awestruct/extensions/tag_cloud.html.haml +7 -0
- data/lib/awestruct/extensions/tag_cloud.rb +34 -0
- data/lib/awestruct/extensions/tagger.rb +107 -0
- data/lib/awestruct/extensions/template.atom.haml +39 -0
- data/lib/awestruct/handler_chain.rb +28 -0
- data/lib/awestruct/handler_chains.rb +65 -0
- data/lib/awestruct/handlers/base_handler.rb +92 -0
- data/lib/awestruct/handlers/base_sass_handler.rb +42 -0
- data/lib/awestruct/handlers/file_handler.rb +61 -0
- data/lib/awestruct/handlers/front_matter_handler.rb +80 -0
- data/lib/awestruct/handlers/haml_handler.rb +42 -0
- data/lib/awestruct/handlers/interpolation_handler.rb +28 -0
- data/lib/awestruct/handlers/layout_handler.rb +61 -0
- data/lib/awestruct/handlers/markdown_handler.rb +36 -0
- data/lib/awestruct/handlers/no_op_handler.rb +34 -0
- data/lib/awestruct/handlers/sass_handler.rb +14 -0
- data/lib/awestruct/handlers/scss_handler.rb +14 -0
- data/lib/awestruct/handlers/string_handler.rb +29 -0
- data/lib/awestruct/handlers/textile_handler.rb +43 -0
- data/lib/awestruct/handlers/yaml_handler.rb +25 -0
- data/lib/awestruct/layouts.rb +15 -0
- data/lib/awestruct/page.rb +128 -0
- data/lib/awestruct/page_loader.rb +72 -0
- data/lib/awestruct/pipeline.rb +49 -0
- data/lib/awestruct/site.rb +51 -0
- data/lib/awestruct/util/default_inflections.rb +45 -0
- data/lib/awestruct/util/inflector.rb +242 -0
- data/lib/awestruct/version.rb +4 -0
- data/lib/guard/awestruct.rb +38 -0
- metadata +427 -0
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'hpricot'
|
2
|
+
|
3
|
+
module Awestruct
|
4
|
+
module ContextHelper
|
5
|
+
|
6
|
+
def html_to_text(str)
|
7
|
+
str.gsub( /<[^>]+>/, '' ).gsub( / /, ' ' )
|
8
|
+
end
|
9
|
+
|
10
|
+
def clean_html(str)
|
11
|
+
str.gsub( / /, ' ' )
|
12
|
+
end
|
13
|
+
|
14
|
+
def without_images(str)
|
15
|
+
str.gsub(/<img[^>]+>/,'').gsub(/<a[^>]+>([^<]*)<\/a>/, '\1')
|
16
|
+
end
|
17
|
+
|
18
|
+
def close_tags(s)
|
19
|
+
stack = []
|
20
|
+
s.scan(/<\/?[^>]+>/).each do |tag|
|
21
|
+
if tag[1] != '/'
|
22
|
+
tag = tag[1..-1].scan(/\w+/).first
|
23
|
+
stack = [ tag ] + stack
|
24
|
+
else
|
25
|
+
tag = tag[2..-1].scan(/\w+/).first
|
26
|
+
if stack[0] == tag
|
27
|
+
stack = stack.drop(1)
|
28
|
+
else
|
29
|
+
raise "Malformed HTML expected #{tag[0]} but got #{tag} '#{s}'"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
stack.inject(s) { |memo,tag| memo += "</#{tag}>" }
|
34
|
+
end
|
35
|
+
|
36
|
+
def summarize(text, numwords=20, ellipsis='...')
|
37
|
+
close_tags(text.split(/ /)[0, numwords].join(' ') + ellipsis)
|
38
|
+
end
|
39
|
+
|
40
|
+
def fully_qualify_urls(base_url, text)
|
41
|
+
doc = Hpricot( text )
|
42
|
+
|
43
|
+
doc.search( "//a" ).each do |a|
|
44
|
+
a['href'] = fix_url( base_url, a['href'] )
|
45
|
+
end
|
46
|
+
doc.search( "//link" ).each do |link|
|
47
|
+
link['href'] = fix_url( base_url, link['href'] )
|
48
|
+
end
|
49
|
+
doc.search( "//img" ).each do |img|
|
50
|
+
img['src'] = fix_url( base_url, img['src'] )
|
51
|
+
end
|
52
|
+
# Hpricot::Doc#to_s output encoding is not necessarily the same as the encoding of text
|
53
|
+
if RUBY_VERSION.start_with? '1.8'
|
54
|
+
doc.to_s
|
55
|
+
else
|
56
|
+
doc.to_s.tap do |d|
|
57
|
+
d.force_encoding(text.encoding) if d.encoding != text.encoding
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def fix_url(base_url, url)
|
63
|
+
return url unless ( url =~ /^\// )
|
64
|
+
"#{base_url}#{url}"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
@@ -0,0 +1,254 @@
|
|
1
|
+
require 'awestruct/util/inflector'
|
2
|
+
require 'awestruct/util/default_inflections'
|
3
|
+
|
4
|
+
require 'awestruct/config'
|
5
|
+
require 'awestruct/site'
|
6
|
+
require 'awestruct/pipeline'
|
7
|
+
require 'awestruct/page'
|
8
|
+
require 'awestruct/page_loader'
|
9
|
+
|
10
|
+
require 'awestruct/extensions/pipeline'
|
11
|
+
|
12
|
+
require 'fileutils'
|
13
|
+
|
14
|
+
class OpenStruct
|
15
|
+
def inspect
|
16
|
+
"OpenStruct{...}"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
module Awestruct
|
21
|
+
|
22
|
+
class Engine
|
23
|
+
|
24
|
+
attr_reader :site
|
25
|
+
attr_reader :pipeline
|
26
|
+
|
27
|
+
def self.instance
|
28
|
+
@instance
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.instance=(engine)
|
32
|
+
@instance = engine
|
33
|
+
end
|
34
|
+
|
35
|
+
def initialize(config=Awestruct::Config.new)
|
36
|
+
Engine.instance = self
|
37
|
+
@site = Site.new( self, config)
|
38
|
+
@pipeline = Pipeline.new
|
39
|
+
@site_page_loader = PageLoader.new( @site )
|
40
|
+
@layout_page_loader = PageLoader.new( @site, :layouts )
|
41
|
+
adjust_load_path
|
42
|
+
end
|
43
|
+
|
44
|
+
def config
|
45
|
+
site.config
|
46
|
+
end
|
47
|
+
|
48
|
+
def run(profile, base_url, default_base_url, force=false)
|
49
|
+
load_site_yaml(profile)
|
50
|
+
set_base_url( base_url, default_base_url )
|
51
|
+
load_yamls
|
52
|
+
load_pipeline
|
53
|
+
load_pages
|
54
|
+
execute_pipeline
|
55
|
+
configure_compass
|
56
|
+
set_urls( site.pages )
|
57
|
+
generate_output
|
58
|
+
end
|
59
|
+
|
60
|
+
def set_base_url(base_url, default_base_url)
|
61
|
+
if ( base_url )
|
62
|
+
site.base_url = base_url
|
63
|
+
end
|
64
|
+
|
65
|
+
if ( site.base_url.nil? )
|
66
|
+
site.base_url = default_base_url
|
67
|
+
end
|
68
|
+
|
69
|
+
if ( site.base_url )
|
70
|
+
if ( site.base_url =~ /^(.*)\/$/ )
|
71
|
+
site.base_url = $1
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def load_site_yaml(profile)
|
77
|
+
site_yaml = File.join( site.config.config_dir, 'site.yml' )
|
78
|
+
if ( File.exist?( site_yaml ) )
|
79
|
+
data = YAML.load( File.read( site_yaml ) )
|
80
|
+
site.interpolate = true
|
81
|
+
profile_data = {}
|
82
|
+
data.each do |k,v|
|
83
|
+
if ( ( k == 'profiles' ) && ( ! profile.nil? ) )
|
84
|
+
profile_data = ( v[profile] || {} )
|
85
|
+
else
|
86
|
+
site.send( "#{k}=", v )
|
87
|
+
end
|
88
|
+
end if data
|
89
|
+
site.profile = profile
|
90
|
+
|
91
|
+
profile_data.each do |k,v|
|
92
|
+
site.send( "#{k}=", v )
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def load_yamls
|
98
|
+
Dir[ File.join( site.config.config_dir, '*.yml' ) ].each do |yaml_path|
|
99
|
+
load_yaml( yaml_path ) unless ( File.basename( yaml_path ) == 'site.yml' )
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def load_yaml(yaml_path)
|
104
|
+
data = YAML.load( File.read( yaml_path ) )
|
105
|
+
name = File.basename( yaml_path, '.yml' )
|
106
|
+
site.send( "#{name}=", massage_yaml( data ) )
|
107
|
+
end
|
108
|
+
|
109
|
+
def massage_yaml(obj)
|
110
|
+
result = obj
|
111
|
+
case ( obj )
|
112
|
+
when Hash
|
113
|
+
result = {}
|
114
|
+
obj.each do |k,v|
|
115
|
+
result[k] = massage_yaml(v)
|
116
|
+
end
|
117
|
+
result = AStruct.new( result ).cascade_for_nils!
|
118
|
+
when Array
|
119
|
+
result = []
|
120
|
+
obj.each do |v|
|
121
|
+
result << massage_yaml(v)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
result
|
125
|
+
end
|
126
|
+
|
127
|
+
def adjust_load_path
|
128
|
+
ext_dir = File.join( site.config.extension_dir )
|
129
|
+
if ( $LOAD_PATH.index( ext_dir ).nil? )
|
130
|
+
$LOAD_PATH << ext_dir
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def set_urls(pages)
|
135
|
+
pages.each do |page|
|
136
|
+
#puts "relative_source_path #{page.relative_source_path}"
|
137
|
+
page_path = page.output_path
|
138
|
+
if ( page_path =~ /^\// )
|
139
|
+
page.url = page_path
|
140
|
+
else
|
141
|
+
page.url = "/#{page_path}"
|
142
|
+
end
|
143
|
+
if ( page.url =~ /^(.*\/)index.html$/ )
|
144
|
+
page.url = $1
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
def load_pipeline
|
150
|
+
ext_dir = File.join( site.config.extension_dir )
|
151
|
+
pipeline_file = File.join( ext_dir, 'pipeline.rb' )
|
152
|
+
if ( File.exists?( pipeline_file ) )
|
153
|
+
p = eval(File.read( pipeline_file ), nil, pipeline_file, 1)
|
154
|
+
p.extensions.each do |e|
|
155
|
+
pipeline.extension( e )
|
156
|
+
end
|
157
|
+
p.helpers.each do |h|
|
158
|
+
pipeline.helper( h )
|
159
|
+
end
|
160
|
+
p.transformers.each do |e|
|
161
|
+
pipeline.transformer( e )
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
def execute_pipeline
|
167
|
+
pipeline.execute( site )
|
168
|
+
end
|
169
|
+
|
170
|
+
def configure_compass
|
171
|
+
Compass.configuration.project_type = :standalone
|
172
|
+
Compass.configuration.project_path = site.config.dir
|
173
|
+
Compass.configuration.sass_dir = 'stylesheets'
|
174
|
+
|
175
|
+
site.images_dir = File.join( site.config.output_dir, 'images' )
|
176
|
+
site.stylesheets_dir = File.join( site.config.output_dir, 'stylesheets' )
|
177
|
+
site.javascripts_dir = File.join( site.config.output_dir, 'javascripts' )
|
178
|
+
|
179
|
+
Compass.configuration.css_dir = site.css_dir
|
180
|
+
Compass.configuration.javascripts_dir = 'javascripts'
|
181
|
+
Compass.configuration.images_dir = 'images'
|
182
|
+
end
|
183
|
+
|
184
|
+
def load_pages
|
185
|
+
@layout_page_loader.load_all( :post )
|
186
|
+
@site_page_loader.load_all( :inline )
|
187
|
+
end
|
188
|
+
|
189
|
+
def generate_output
|
190
|
+
@site.pages.each do |page|
|
191
|
+
generated_path = File.join( site.config.output_dir, page.output_path )
|
192
|
+
if ( page.stale_output?( generated_path ) )
|
193
|
+
generate_page( page, generated_path )
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
def generate_page(page, generated_path)
|
199
|
+
puts "Generating: #{generated_path}"
|
200
|
+
FileUtils.mkdir_p( File.dirname( generated_path ) )
|
201
|
+
File.open( generated_path, 'w' ) do |file|
|
202
|
+
file << page.rendered_content
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
def generate_page_by_output_path(path)
|
207
|
+
full_path = File.join( '', path )
|
208
|
+
#puts "regen path #{full_path}"
|
209
|
+
page = site.pages.find{|p| p.relative_source_path.to_s==full_path}
|
210
|
+
if ( page.nil? )
|
211
|
+
#puts "Unable to locate page for #{path}"
|
212
|
+
else
|
213
|
+
generated_path = File.join( site.config.output_dir, page.output_path )
|
214
|
+
generate_page(page, generated_path)
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
####
|
219
|
+
##
|
220
|
+
## compat with awestruct 0.2.x
|
221
|
+
##
|
222
|
+
####
|
223
|
+
|
224
|
+
def load_page(path, options={})
|
225
|
+
page = @site_page_loader.load_page( path )
|
226
|
+
if ( options[:relative_path] )
|
227
|
+
fixed_relative_path = ( options[:relative_path].nil? ? nil : File.join( '', options[:relative_path] ) )
|
228
|
+
page.relative_path = fixed_relative_path
|
229
|
+
end
|
230
|
+
page
|
231
|
+
end
|
232
|
+
|
233
|
+
def load_site_page(relative_path)
|
234
|
+
load_page( File.join( site.config.dir, relative_path ) )
|
235
|
+
end
|
236
|
+
|
237
|
+
def find_and_load_site_page(simple_path)
|
238
|
+
path_glob = File.join( site.config.input_dir, simple_path + '.*' )
|
239
|
+
candidates = Dir[ path_glob ]
|
240
|
+
return nil if candidates.empty?
|
241
|
+
throw Exception.new( "too many choices for #{simple_path}" ) if candidates.size != 1
|
242
|
+
dir_pathname = Pathname.new( site.config.dir )
|
243
|
+
path_name = Pathname.new( candidates[0] )
|
244
|
+
relative_path = path_name.relative_path_from( dir_pathname ).to_s
|
245
|
+
load_page( candidates[0] )
|
246
|
+
end
|
247
|
+
|
248
|
+
def create_context(page, content='')
|
249
|
+
page.create_context( content )
|
250
|
+
end
|
251
|
+
|
252
|
+
end
|
253
|
+
|
254
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'awestruct/extensions/relative'
|
2
|
+
require 'pathname'
|
3
|
+
|
4
|
+
module Awestruct
|
5
|
+
module Extensions
|
6
|
+
module Assets
|
7
|
+
|
8
|
+
def asset(href)
|
9
|
+
if site.assets_url
|
10
|
+
File.join(site.assets_url, href)
|
11
|
+
else
|
12
|
+
relative(File.join("/#{site.assets_path||'assets'}", href))
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class Transformer
|
17
|
+
# FIXME this is not DRY at all
|
18
|
+
def relative(page, href)
|
19
|
+
Pathname.new(href).relative_path_from(Pathname.new(File.dirname(page.output_path))).to_s
|
20
|
+
end
|
21
|
+
def asset(site, page, href)
|
22
|
+
if site.assets_url
|
23
|
+
File.join(site.assets_url, href)
|
24
|
+
else
|
25
|
+
relative(page, File.join("/#{site.assets_path||'assets'}", href))
|
26
|
+
end
|
27
|
+
end
|
28
|
+
def transform(site, page, input)
|
29
|
+
if page.output_path =~ /\.html/
|
30
|
+
input.gsub('asset://', asset(site, page, "#{File.basename(File.basename(page.source_path, ".md"))}") + "/")
|
31
|
+
else
|
32
|
+
input
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Awestruct
|
2
|
+
module Extensions
|
3
|
+
class Atomizer
|
4
|
+
|
5
|
+
def initialize(entries_name, output_path, opts={})
|
6
|
+
@entries_name = entries_name
|
7
|
+
@output_path = output_path
|
8
|
+
@num_entries = opts[:num_entries] || 50
|
9
|
+
@content_url = opts[:content_url]
|
10
|
+
@feed_title = opts[:feed_title]
|
11
|
+
end
|
12
|
+
|
13
|
+
def execute(site)
|
14
|
+
entries = site.send( @entries_name ) || []
|
15
|
+
unless ( @num_entries == :all )
|
16
|
+
entries = entries[0, @num_entries]
|
17
|
+
end
|
18
|
+
|
19
|
+
atom_pages = []
|
20
|
+
|
21
|
+
entries.each do |entry|
|
22
|
+
feed_entry = site.engine.load_page(entry.source_path, :relative_path => entry.relative_source_path, :html_entities => false)
|
23
|
+
|
24
|
+
feed_entry.output_path = entry.output_path
|
25
|
+
feed_entry.date = feed_entry.timestamp.nil? ? entry.date : feed_entry.timestamp
|
26
|
+
|
27
|
+
atom_pages << feed_entry
|
28
|
+
end
|
29
|
+
|
30
|
+
site.engine.set_urls(atom_pages)
|
31
|
+
|
32
|
+
input_page = File.join( File.dirname(__FILE__), 'template.atom.haml' )
|
33
|
+
page = site.engine.load_page( input_page )
|
34
|
+
page.date = page.timestamp unless page.timestamp.nil?
|
35
|
+
page.output_path = @output_path
|
36
|
+
page.entries = atom_pages
|
37
|
+
page.title = @feed_title || site.title || site.base_url
|
38
|
+
page.content_url = @content_url || site.base_url
|
39
|
+
site.pages << page
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'coffee-script'
|
2
|
+
require 'nokogiri'
|
3
|
+
|
4
|
+
##
|
5
|
+
# Awestruct:Extensions:CoffeeScript is a transformer that compiles inline CoffeeScript in HTML files as JavaScript.
|
6
|
+
|
7
|
+
module Awestruct
|
8
|
+
module Extensions
|
9
|
+
class CoffeeScriptTransform
|
10
|
+
|
11
|
+
def transform(site, page, input)
|
12
|
+
ext = File.extname(page.output_path)[1..-1].to_sym
|
13
|
+
case ext
|
14
|
+
when :html
|
15
|
+
encoding = 'UTF-8'
|
16
|
+
encoding = site.encoding unless site.encoding.nil?
|
17
|
+
|
18
|
+
return compile(input, encoding)
|
19
|
+
end
|
20
|
+
return input
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def compile(input, encoding)
|
26
|
+
html = Nokogiri::HTML(input, nil, encoding);
|
27
|
+
html.search('script').each do |script|
|
28
|
+
next unless 'text/coffeescript'.eql? script.attr('type')
|
29
|
+
|
30
|
+
if script.attr('src') =~ /\.coffee$/
|
31
|
+
script.set_attribute('src', File.basename( script.attr('src'), '.coffee' ) + '.js')
|
32
|
+
else
|
33
|
+
script.inner_html = CoffeeScript.compile script.inner_html
|
34
|
+
end
|
35
|
+
script.set_attribute('type', 'text/javascript')
|
36
|
+
|
37
|
+
end
|
38
|
+
return html.to_html
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|