awestructx 0.4.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 (64) hide show
  1. data/bin/awestruct +8 -0
  2. data/lib/awestruct/astruct.rb +22 -0
  3. data/lib/awestruct/astruct_mixin.rb +71 -0
  4. data/lib/awestruct/cli/auto.rb +20 -0
  5. data/lib/awestruct/cli/generate.rb +26 -0
  6. data/lib/awestruct/cli/invoker.rb +109 -0
  7. data/lib/awestruct/cli/options.rb +116 -0
  8. data/lib/awestruct/cli/server.rb +24 -0
  9. data/lib/awestruct/config.rb +30 -0
  10. data/lib/awestruct/context.rb +22 -0
  11. data/lib/awestruct/context_helper.rb +68 -0
  12. data/lib/awestruct/engine.rb +254 -0
  13. data/lib/awestruct/extensions/assets.rb +39 -0
  14. data/lib/awestruct/extensions/atomizer.rb +44 -0
  15. data/lib/awestruct/extensions/cachebuster.rb +12 -0
  16. data/lib/awestruct/extensions/coffeescripttransform.rb +42 -0
  17. data/lib/awestruct/extensions/data_dir.rb +31 -0
  18. data/lib/awestruct/extensions/disqus.rb +62 -0
  19. data/lib/awestruct/extensions/extend_string.rb +97 -0
  20. data/lib/awestruct/extensions/flattr.rb +42 -0
  21. data/lib/awestruct/extensions/google_analytics.rb +38 -0
  22. data/lib/awestruct/extensions/gsub.rb +20 -0
  23. data/lib/awestruct/extensions/indexifier.rb +17 -0
  24. data/lib/awestruct/extensions/intense_debate.rb +38 -0
  25. data/lib/awestruct/extensions/minify.rb +178 -0
  26. data/lib/awestruct/extensions/obfuscate.rb +32 -0
  27. data/lib/awestruct/extensions/paginator.rb +105 -0
  28. data/lib/awestruct/extensions/partial.rb +25 -0
  29. data/lib/awestruct/extensions/pipeline.rb +50 -0
  30. data/lib/awestruct/extensions/posts.rb +70 -0
  31. data/lib/awestruct/extensions/relative.rb +11 -0
  32. data/lib/awestruct/extensions/remotePartial.rb +17 -0
  33. data/lib/awestruct/extensions/sitemap.rb +85 -0
  34. data/lib/awestruct/extensions/sitemap.xml.haml +16 -0
  35. data/lib/awestruct/extensions/tag_cloud.html.haml +7 -0
  36. data/lib/awestruct/extensions/tag_cloud.rb +34 -0
  37. data/lib/awestruct/extensions/tagger.rb +107 -0
  38. data/lib/awestruct/extensions/template.atom.haml +39 -0
  39. data/lib/awestruct/handler_chain.rb +28 -0
  40. data/lib/awestruct/handler_chains.rb +65 -0
  41. data/lib/awestruct/handlers/base_handler.rb +92 -0
  42. data/lib/awestruct/handlers/base_sass_handler.rb +42 -0
  43. data/lib/awestruct/handlers/file_handler.rb +61 -0
  44. data/lib/awestruct/handlers/front_matter_handler.rb +80 -0
  45. data/lib/awestruct/handlers/haml_handler.rb +42 -0
  46. data/lib/awestruct/handlers/interpolation_handler.rb +28 -0
  47. data/lib/awestruct/handlers/layout_handler.rb +61 -0
  48. data/lib/awestruct/handlers/markdown_handler.rb +36 -0
  49. data/lib/awestruct/handlers/no_op_handler.rb +34 -0
  50. data/lib/awestruct/handlers/sass_handler.rb +14 -0
  51. data/lib/awestruct/handlers/scss_handler.rb +14 -0
  52. data/lib/awestruct/handlers/string_handler.rb +29 -0
  53. data/lib/awestruct/handlers/textile_handler.rb +43 -0
  54. data/lib/awestruct/handlers/yaml_handler.rb +25 -0
  55. data/lib/awestruct/layouts.rb +15 -0
  56. data/lib/awestruct/page.rb +128 -0
  57. data/lib/awestruct/page_loader.rb +72 -0
  58. data/lib/awestruct/pipeline.rb +49 -0
  59. data/lib/awestruct/site.rb +51 -0
  60. data/lib/awestruct/util/default_inflections.rb +45 -0
  61. data/lib/awestruct/util/inflector.rb +242 -0
  62. data/lib/awestruct/version.rb +4 -0
  63. data/lib/guard/awestruct.rb +38 -0
  64. 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( /&nbsp;/, ' ' )
8
+ end
9
+
10
+ def clean_html(str)
11
+ str.gsub( /&nbsp;/, ' ' )
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,12 @@
1
+ module Awestruct
2
+ module Extensions
3
+ module Cachebuster
4
+ def timestamp
5
+ (Time.now.to_i / 1000).to_i
6
+ end
7
+ def cache(href)
8
+ "#{href}?#{site.cachebuster||timestamp}"
9
+ end
10
+ end
11
+ end
12
+ 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