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,31 @@
1
+ module Awestruct
2
+ module Extensions
3
+ class DataDir
4
+
5
+ def initialize(data_dir="_data")
6
+ @data_dir = data_dir
7
+ end
8
+
9
+ def watch(watched_dirs)
10
+ watched_dirs << @data_dir
11
+ end
12
+
13
+ def execute(site)
14
+ Dir[ "#{site.dir}/#{@data_dir}/*" ].each do |entry|
15
+ if ( File.directory?( entry ) )
16
+ data_key = File.basename( entry )
17
+ data_map = {}
18
+ Dir[ "#{entry}/*" ].each do |chunk|
19
+ File.basename( chunk ) =~ /^([^\.]+)/
20
+ key = $1.to_sym
21
+ chunk_page = site.engine.load_page( chunk )
22
+ data_map[ key ] = chunk_page
23
+ end
24
+ site.send( "#{data_key}=", data_map )
25
+ end
26
+ end
27
+ end
28
+
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,62 @@
1
+ require 'digest/sha1'
2
+
3
+ module Awestruct
4
+ module Extensions
5
+ class Disqus
6
+
7
+ def execute(site)
8
+ site.pages.each{ |p| p.extend Disqus }
9
+ end
10
+
11
+ module Disqus
12
+ def disqus_comments()
13
+ identifier = "null"
14
+ if self.disqus_identifier or site.disqus_generate_id
15
+ identifier = %Q("#{self.resolve_disqus_identifier()}")
16
+ end
17
+ %Q{
18
+ <div id="disqus_thread"></div>
19
+ <script type="text/javascript">
20
+ var disqus_shortname = '#{site.disqus}';
21
+ var disqus_url = "#{site.base_url}#{self.url}";
22
+ var disqus_developer = #{site.disqus_developer ? 1 : "null"};
23
+ var disqus_identifier = #{identifier};
24
+ (function() {
25
+ var dsq = document.createElement("script"); dsq.type = "text/javascript"; dsq.async = true;
26
+ dsq.src = "http://#{site.disqus}.disqus.com/embed.js";
27
+ (document.getElementsByTagName("head")[0] || document.getElementsByTagName("body")[0]).appendChild(dsq);
28
+ })();
29
+ </script>
30
+ <noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript=#{site.disqus}">comments powered by Disqus.</a></noscript>
31
+ }
32
+ end
33
+
34
+ def disqus_comments_link()
35
+ identifier = ''
36
+ if self.disqus_identifier or site.disqus_generate_id
37
+ identifier = %Q{ data-disqus-identifier="#{self.resolve_disqus_identifier()}"}
38
+ end
39
+ %Q{ <a href="#{self.url}#disqus_thread"#{identifier}>Comments</a> }
40
+ end
41
+
42
+ def disqus_comments_count()
43
+ %Q{
44
+ <script type="text/javascript">
45
+ var disqus_shortname = '#{site.disqus}';
46
+ (function () {
47
+ var s = document.createElement('script'); s.async = true;
48
+ s.src = "http://disqus.com/forums/#{site.disqus}/count.js";
49
+ (document.getElementsByTagName('HEAD')[0] || document.getElementsByTagName('BODY')[0]).appendChild(s);
50
+ }());
51
+ </script>
52
+ }
53
+ end
54
+
55
+ def resolve_disqus_identifier()
56
+ self.disqus_identifier ? self.disqus_identifier : Digest::SHA1.hexdigest(self.date.strftime('%Y-%m-%d-') + self.slug)
57
+ end
58
+
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,97 @@
1
+ # RemoveAccents version 1.0.3 (c) 2008-2009 Solutions Informatiques Techniconseils inc.
2
+ #
3
+ # This module adds 2 methods to the string class.
4
+ # Up-to-date version and documentation available at:
5
+ #
6
+ # http://www.techniconseils.ca/en/scripts-remove-accents-ruby.php
7
+ #
8
+ # This script is available under the following license :
9
+ # Creative Commons Attribution-Share Alike 2.5.
10
+ #
11
+ # See full license and details at :
12
+ # http://creativecommons.org/licenses/by-sa/2.5/ca/
13
+ #
14
+ # Version history:
15
+ # * 1.0.3 : July 23 2009
16
+ # Corrected some incorrect character codes. Source is now wikipedia at:
17
+ # http://en.wikipedia.org/wiki/ISO/IEC_8859-1#Related_character_maps
18
+ # Thanks to Raimon Fernandez for pointing out the incorrect codes.
19
+ # * 1.0.2 : October 29 2008
20
+ # Slightly optimized version of urlize - Jonathan Grenier (jgrenier@techniconseils.ca)
21
+ # * 1.0.1 : October 29 2008
22
+ # First public revision - Jonathan Grenier (jgrenier@techniconseils.ca)
23
+ #
24
+
25
+ class String
26
+ # The extended characters map used by removeaccents. The accented characters
27
+ # are coded here using their numerical equivalent to sidestep encoding issues.
28
+ # These correspond to ISO-8859-1 encoding.
29
+ ACCENTS_MAPPING = {
30
+ 'E' => [200,201,202,203],
31
+ 'e' => [232,233,234,235],
32
+ 'A' => [192,193,194,195,196,197],
33
+ 'a' => [224,225,226,227,228,229,230],
34
+ 'C' => [199],
35
+ 'c' => [231],
36
+ 'O' => [210,211,212,213,214,216],
37
+ 'o' => [242,243,244,245,246,248],
38
+ 'I' => [204,205,206,207],
39
+ 'i' => [236,237,238,239],
40
+ 'U' => [217,218,219,220],
41
+ 'u' => [249,250,251,252],
42
+ 'N' => [209],
43
+ 'n' => [241],
44
+ 'Y' => [221],
45
+ 'y' => [253,255],
46
+ 'AE' => [306],
47
+ 'ae' => [346],
48
+ 'OE' => [188],
49
+ 'oe' => [189]
50
+ }
51
+
52
+
53
+ # Remove the accents from the string. Uses String::ACCENTS_MAPPING as the source map.
54
+ def removeaccents
55
+ str = String.new(self)
56
+ String::ACCENTS_MAPPING.each {|letter,accents|
57
+ packed = accents.pack('U*')
58
+ rxp = Regexp.new("[#{packed}]", nil, 'U')
59
+ str.gsub!(rxp, letter)
60
+ }
61
+
62
+ str
63
+ end
64
+
65
+
66
+ # Convert a string to a format suitable for a URL without ever using escaped characters.
67
+ # It calls strip, removeaccents, downcase (optional) then removes the spaces (optional)
68
+ # and finally removes any characters matching the default regexp (/[^-_A-Za-z0-9]/).
69
+ #
70
+ # Options
71
+ #
72
+ # * :downcase => call downcase on the string (defaults to true)
73
+ # * :convert_spaces => Convert space to underscore (defaults to false)
74
+ # * :regexp => The regexp matching characters that will be converting to an empty string (defaults to /[^-_A-Za-z0-9]/)
75
+ def urlize(options = {})
76
+ options[:downcase] ||= true
77
+ options[:convert_spaces] ||= false
78
+ options[:regexp] ||= /[^-_A-Za-z0-9]/
79
+
80
+ str = self.strip.removeaccents
81
+ str.downcase! if options[:downcase]
82
+ str.gsub!(/\ /,'-') if options[:convert_spaces]
83
+ str.gsub(options[:regexp], '')
84
+ end
85
+
86
+ # This follows the generated ID rules
87
+ def anchorize(options = {})
88
+ options[:downcase] ||= true
89
+ options[:convert_spaces] ||= false
90
+ options[:regexp] ||= /[^-_A-Za-z0-9]/
91
+
92
+ str = self.strip.removeaccents
93
+ str.downcase! if options[:downcase]
94
+ str.gsub!(/\ /,'_') if options[:convert_spaces]
95
+ str.gsub(options[:regexp], '')
96
+ end
97
+ end
@@ -0,0 +1,42 @@
1
+ module Awestruct
2
+ module Extensions
3
+ class Flattr
4
+
5
+ def execute(site)
6
+ site.pages.each{|p| p.extend Flattrable }
7
+ end
8
+
9
+ module Flattrable
10
+ def flattr_javascript()
11
+ html = %Q|<script type='text/javascript'> /* <![CDATA[ */ (function() {\n|
12
+ html += %Q|var s = document.createElement('script'), t = document.getElementsByTagName('script')[0];|
13
+ html += %Q|s.type = 'text/javascript';\n|
14
+ html += %Q|s.async = true;\n|
15
+ html += %Q|s.src = 'http://api.flattr.com/js/0.6/load.js?mode=auto&uid=#{site.flattr_username}&category=text';\n|
16
+ html += %Q|t.parentNode.insertBefore(s, t);\n|
17
+ html += %Q|})(); /* ]]> */ </script>|
18
+ html
19
+ end
20
+ def flattr_large_counter(param={})
21
+ url = param[:url] ? param[:url] : site.base_url + self.url
22
+ title = param[:title] ? param[:title] : self.title
23
+ category = param[:category] ? param[:category] : "text"
24
+ tags = param[:tags] ? "tags:" + param[:tags] + ";" : ""
25
+ html = %Q|<a class="FlattrButton" style="display:none;" href="#{url}" title="#{title}" |
26
+ html += %Q|rev="flattr;uid:#{site.flattr_username};category:#{category};#{tags}"></a>|
27
+ html
28
+ end
29
+ def flattr_compact_counter(param={})
30
+ url = param[:url] ? param[:url] : site.base_url + self.url
31
+ title = param[:title] ? param[:title] : self.title
32
+ category = param[:category] ? param[:category] : "text"
33
+ tags = param[:tags] ? "tags:" + param[:tags] + ";" : ""
34
+ html = %Q|<a class="FlattrButton" style="display:none;" href="#{url}" title="#{title}" |
35
+ html += %Q|rev="flattr;button:compact;uid:#{site.flattr_username};category:#{category};#{tags}"></a>|
36
+ html
37
+ end
38
+ end
39
+
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,38 @@
1
+ module Awestruct
2
+ module Extensions
3
+ module GoogleAnalytics
4
+
5
+ def google_analytics()
6
+ html = ''
7
+ html += %Q(<script type="text/javascript">\n)
8
+ html += %Q(var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");\n)
9
+ html += %Q(document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));\n)
10
+ html += %Q(</script>\n)
11
+ html += %Q(<script type="text/javascript">\n)
12
+ html += %Q(try {\n)
13
+ html += %Q(var pageTracker = _gat._getTracker("#{site.google_analytics}");\n)
14
+ html += %Q(pageTracker._trackPageview();\n)
15
+ html += %Q(} catch(err) {}</script>\n)
16
+ html
17
+ end
18
+
19
+ def google_analytics_async()
20
+ html = ''
21
+ html += %Q(<script type="text/javascript">\n)
22
+ html += %Q(var _gaq = _gaq || [];\n)
23
+ html += %Q(_gaq.push(['_setAccount','#{site.google_analytics}']);\n)
24
+ if site.google_analytics_anonymize
25
+ html += %Q(_gaq.push(['_gat._anonymizeIp']);\n)
26
+ end
27
+ html += %Q(_gaq.push(['_trackPageview']);\n)
28
+ html += %Q[(function() {\n]
29
+ html += %Q( var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;\n)
30
+ html += %Q( ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';\n)
31
+ html += %Q( var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);\n)
32
+ html += %Q[})();\n</script>\n]
33
+ html
34
+ end
35
+
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,20 @@
1
+ module Awestruct
2
+ module Extensions
3
+ class Gsub
4
+
5
+ def initialize(pattern, replacement, options = {})
6
+ @pattern = pattern
7
+ @replacement = replacement
8
+ @gsub_required = options[:gsub_required] || lambda { |site, page| page.output_path.end_with?(".html") }
9
+ end
10
+
11
+ def transform(site, page, rendered)
12
+ if (@gsub_required.call(site, page))
13
+ rendered = rendered.gsub(@pattern, @replacement)
14
+ end
15
+ rendered
16
+ end
17
+
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,17 @@
1
+ module Awestruct
2
+ module Extensions
3
+ class Indexifier
4
+
5
+ def execute(site)
6
+ site.pages.each do |page|
7
+ if ( page.inhibit_indexifier || ( page.output_path =~ /^(.*\/)?index.html$/ ) )
8
+ # skip it!
9
+ else
10
+ page.output_path = page.output_path.gsub( /.html$/, '/index.html' )
11
+ end
12
+ end
13
+ end
14
+
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,38 @@
1
+ require 'digest/sha1'
2
+
3
+ module Awestruct
4
+ module Extensions
5
+ class IntenseDebate
6
+
7
+ def execute(site)
8
+ site.pages.each{|p| p.extend IntenseDebatable }
9
+ end
10
+
11
+ module IntenseDebatable
12
+ def intense_debate_comments()
13
+ post_id = self.post_id ? self.post_id : Digest::SHA1.hexdigest( self.url )
14
+ html = %Q(<script>\n)
15
+ html += %Q( var idcomments_acct='#{site.intense_debate_acct}';\n)
16
+ html += %Q( var idcomments_post_id='#{post_id}';\n )
17
+ html += %Q( var idcomments_post_url='#{site.intense_debate_base_url || site.base_url}#{self.url}';\n)
18
+ html += %Q(</script>\n)
19
+ html += %Q(<span id="IDCommentsPostTitle" style="display:none"></span>\n)
20
+ html += %Q(<script type='text/javascript' src='http://www.intensedebate.com/js/genericCommentWrapperV2.js'></script>\n)
21
+ html
22
+ end
23
+
24
+ def intense_debate_comments_link()
25
+ post_id = self.post_id ? self.post_id : Digest::SHA1.hexdigest( self.url )
26
+ html = %Q(<script>\n)
27
+ html += %Q( var idcomments_acct='#{site.intense_debate_acct}';\n)
28
+ html += %Q( var idcomments_post_id='#{post_id}';\n )
29
+ html += %Q( var idcomments_post_url='#{self.url}';\n)
30
+ html += %Q(</script>\n)
31
+ html += %Q(<script type='text/javascript' src='http://www.intensedebate.com/js/genericLinkWrapperV2.js'></script>\n)
32
+ html
33
+ end
34
+
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,178 @@
1
+ require 'fileutils'
2
+
3
+ ##
4
+ # Awestruct:Extensions:Minify is a transformer that minimizes JavaScript, CSS and HTML files.
5
+ # The transform runs on the rendered stream before it's written to the output path.
6
+ #
7
+ # Minification is performed by the following three libraries:
8
+ #
9
+ # htmlcompressor (minifies HTML): http://code.google.com/p/htmlcompressor/
10
+ # yuicompressor (minifies JavaScript and CSS): http://developer.yahoo.com/yui/compressor/
11
+ # pngcrush (minifies PNG): http://pmt.sourceforge.net/pngcrush/
12
+ #
13
+ # These commands must be available on your PATH in order to use them.
14
+ #
15
+ # This class is loaded as a transformer in the Awestruct pipeline. The
16
+ # constructor accepts an array of symbols representing the file types to minimize.
17
+ #
18
+ # extension Awestruct::Extensions::Minify.new
19
+ #
20
+ # This transform recognizes the following symbols:
21
+ #
22
+ # :css - CSS files with extension .css
23
+ # :js - JavaScript files with extension .js
24
+ # :html - HTML files with extension .html
25
+ # :png - PNG files with extension .png
26
+ #
27
+ # If no types are specified, the default value [:css, :js] is used.
28
+ #
29
+ # In addition to registering the transformer in the pipeline, it must be enabled
30
+ # by setting the following site property in _ext/config.yml:
31
+ #
32
+ # minify: true
33
+ #
34
+ # You can limit activation to one or more profiles:
35
+ #
36
+ # profiles:
37
+ # production:
38
+ # minify: true
39
+ #
40
+ # You can also configure the option arguments passed to the compressor programs. Here's
41
+ # how you specify options arguments for the htmlcompressor command:
42
+ #
43
+ # minify_html_opts:
44
+ # remove_intertag_spaces: true
45
+ # compress_js: true
46
+ # compress_css: true
47
+ #
48
+ # Note that any hypen (-) must be represented as an underscore (_) in the configuration.
49
+
50
+ module Awestruct
51
+ module Extensions
52
+ class Minify
53
+
54
+ def initialize(types = [ :css, :js ])
55
+ @types = types
56
+ end
57
+
58
+ def transform(site, page, input)
59
+ if site.minify
60
+ ext = File.extname(page.output_path)[1..-1].to_sym
61
+ if @types.include?(ext)
62
+ case ext
63
+ when :html
64
+ print "minifying html #{page.output_path}"
65
+ htmlcompressor(page, input, site.minify_html_opts)
66
+ when :css
67
+ print "minifying css #{page.output_path}"
68
+ yuicompressor(page, input, :css)
69
+ when :js
70
+ print "minifying js #{page.output_path}"
71
+ yuicompressor(page, input, :js)
72
+ when :png
73
+ print "minifying png #{page.output_path}"
74
+ pngcrush(page, input)
75
+ else
76
+ input
77
+ end
78
+ else
79
+ input
80
+ end
81
+ else
82
+ input
83
+ end
84
+ end
85
+
86
+ private
87
+
88
+ def htmlcompressor(page, input, minify_html_opts)
89
+ output = ''
90
+ cmd = "htmlcompressor"
91
+ if minify_html_opts
92
+ minify_html_opts.each do |p, v|
93
+ # boolean options are simple flags (i.e., do not accept values)
94
+ if v === true
95
+ cmd += " --#{p.gsub('_', '-')}"
96
+ elsif not v === false
97
+ cmd += " --#{p.gsub('_', '-')}=#{v}"
98
+ end
99
+ end
100
+ end
101
+ Open3.popen3(cmd) do |stdin, stdout, stderr|
102
+ threads = []
103
+ threads << Thread.new(stdout) do |o|
104
+ while ( ! o.eof? )
105
+ output << o.readline
106
+ end
107
+ end
108
+ threads << Thread.new(stdin) do |i|
109
+ i.write input
110
+ i.close
111
+ end
112
+ threads.each{ |t|t.join }
113
+ end
114
+
115
+ input_len = input.length
116
+ output_len = output.length
117
+
118
+ if input_len > output_len
119
+ puts " %d bytes -> %d bytes = %.1f%%" % [ input_len, output_len, 100 * output_len/input_len ]
120
+ output
121
+ else
122
+ puts " no gain"
123
+ input
124
+ end
125
+ end
126
+
127
+ def yuicompressor(page, input, type)
128
+ output = ''
129
+ Open3.popen3("yuicompressor --type #{type}") do |stdin, stdout, stderr|
130
+ threads = []
131
+ threads << Thread.new(stdout) do |o|
132
+ while ( ! o.eof? )
133
+ output << o.readline
134
+ end
135
+ end
136
+ threads << Thread.new(stdin) do |i|
137
+ i.write input
138
+ i.close
139
+ end
140
+ threads.each{ |t|t.join }
141
+ end
142
+
143
+ input_len = input.length
144
+ output_len = output.length
145
+
146
+ if input_len > output_len
147
+ puts " %d bytes -> %d bytes = %.1f%%" % [ input_len, output_len, 100 * output_len/input_len ]
148
+ output
149
+ else
150
+ puts " no gain"
151
+ input
152
+ end
153
+ end
154
+
155
+ def pngcrush(page, input)
156
+ filename = page.source_path
157
+ cmd = "pngcrush #{filename} /tmp/pngcrush"
158
+ `#{cmd}`
159
+ if $?.exitstatus != 0
160
+ raise "Failed to execute pngcrush: #{cmd}"
161
+ end
162
+ output = File.read('/tmp/pngcrush')
163
+
164
+ input_len = File.stat(filename).size
165
+ output_len = output.length
166
+
167
+ if input_len > output_len
168
+ puts " %d bytes -> %d bytes = %.1f%%" % [ input_len, output_len, 100 * output_len/input_len ]
169
+ output
170
+ else
171
+ puts " no gain"
172
+ input
173
+ end
174
+ end
175
+ end
176
+
177
+ end
178
+ end