Class: Slimmer::Skin
- Inherits:
-
Object
- Object
- Slimmer::Skin
- Defined in:
- lib/slimmer/skin.rb,
lib/slimmer/test.rb
Instance Attribute Summary collapse
-
#asset_host ⇒ Object
Returns the value of attribute asset_host.
-
#logger ⇒ Object
Returns the value of attribute logger.
-
#options ⇒ Object
Returns the value of attribute options.
-
#strict ⇒ Object
Returns the value of attribute strict.
-
#template_cache ⇒ Object
Returns the value of attribute template_cache.
-
#use_cache ⇒ Object
Returns the value of attribute use_cache.
Instance Method Summary collapse
- #artefact_from_header(response) ⇒ Object
- #context(html, error) ⇒ Object
- #error(template_name, body) ⇒ Object
- #ignorable?(error) ⇒ Boolean
-
#initialize(options = {}) ⇒ Skin
constructor
TODO: Extract the cache to something we can pass in instead of using true/false and an in-memory cache.
- #load_template(name) ⇒ Object
- #parse_html(html, description_for_error_message) ⇒ Object
- #process(processors, body, template) ⇒ Object
- #report_parse_errors_if_strict!(nokogiri_doc, description_for_error_message) ⇒ Object
- #success(source_request, response, body) ⇒ Object
- #template(template_name) ⇒ Object
- #template_url(template_name) ⇒ Object
Constructor Details
#initialize(options = {}) ⇒ Skin
TODO: Extract the cache to something we can pass in instead of using true/false and an in-memory cache.
7 8 9 10 11 12 13 14 15 16 17 |
# File 'lib/slimmer/skin.rb', line 7 def initialize = {} @options = @asset_host = [:asset_host] @use_cache = [:use_cache] || false @cache_ttl = [:cache_ttl] || (15 * 60) # 15 mins @template_cache = LRUCache.new(:ttl => @cache_ttl) if @use_cache @logger = [:logger] || NullLogger.instance @strict = [:strict] || (%w{development test}.include?(ENV['RACK_ENV'])) end |
Instance Attribute Details
#asset_host ⇒ Object
Returns the value of attribute asset_host.
3 4 5 |
# File 'lib/slimmer/skin.rb', line 3 def asset_host @asset_host end |
#logger ⇒ Object
Returns the value of attribute logger.
3 4 5 |
# File 'lib/slimmer/skin.rb', line 3 def logger @logger end |
#options ⇒ Object
Returns the value of attribute options.
3 4 5 |
# File 'lib/slimmer/skin.rb', line 3 def @options end |
#strict ⇒ Object
Returns the value of attribute strict.
3 4 5 |
# File 'lib/slimmer/skin.rb', line 3 def strict @strict end |
#template_cache ⇒ Object
Returns the value of attribute template_cache.
3 4 5 |
# File 'lib/slimmer/skin.rb', line 3 def template_cache @template_cache end |
#use_cache ⇒ Object
Returns the value of attribute use_cache.
3 4 5 |
# File 'lib/slimmer/skin.rb', line 3 def use_cache @use_cache end |
Instance Method Details
#artefact_from_header(response) ⇒ Object
146 147 148 149 150 151 152 153 154 155 |
# File 'lib/slimmer/skin.rb', line 146 def artefact_from_header(response) if response.headers.include?(Headers::ARTEFACT_HEADER) Artefact.new JSON.parse(response.headers[Headers::ARTEFACT_HEADER]) else nil end rescue JSON::ParserError => e logger.error "Slimmer: Failed while parsing artefact header: #{[ e., e.backtrace ].flatten.join("\n")}" nil end |
#context(html, error) ⇒ Object
72 73 74 75 76 77 78 79 80 81 |
# File 'lib/slimmer/skin.rb', line 72 def context(html, error) context_size = 5 lines = [""] + html.split("\n") from = [1, error.line - context_size].max to = [lines.size - 1, error.line + context_size].min context = (from..to).zip(lines[from..to]).map {|lineno, line| "%4d: %s" % [lineno, line] } marker = " " * (error.column - 1) + "-----v" context.insert(context_size, marker) context.join("\n") end |
#error(template_name, body) ⇒ Object
139 140 141 142 143 144 |
# File 'lib/slimmer/skin.rb', line 139 def error(template_name, body) processors = [ Processors::TitleInserter.new() ] process(processors, body, template(template_name)) end |
#ignorable?(error) ⇒ Boolean
83 84 85 86 |
# File 'lib/slimmer/skin.rb', line 83 def ignorable?(error) ignorable_codes = [801] ignorable_codes.include?(error.code) || error..match(/Element script embeds close tag/) || error..match(/Unexpected end tag : noscript/) end |
#load_template(name) ⇒ Object
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
# File 'lib/slimmer/skin.rb', line 29 def load_template(template_name) url = template_url(template_name) source = open(url, "r:UTF-8", :ssl_verify_mode => OpenSSL::SSL::VERIFY_NONE).read if template_name =~ /\.raw/ template = source else template = ERB.new(source).result binding end template rescue OpenURI::HTTPError => e raise TemplateNotFoundException, "Unable to fetch: '#{template_name}' from '#{url}' because #{e}", caller rescue Errno::ECONNREFUSED => e raise CouldNotRetrieveTemplate, "Unable to fetch: '#{template_name}' from '#{url}' because #{e}", caller rescue SocketError => e raise CouldNotRetrieveTemplate, "Unable to fetch: '#{template_name}' from '#{url}' because #{e}", caller end |
#parse_html(html, description_for_error_message) ⇒ Object
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
# File 'lib/slimmer/skin.rb', line 56 def parse_html(html, ) doc = Nokogiri::HTML.parse(html) if strict errors = doc.errors.select {|e| e.error?}.reject {|e| ignorable?(e)} if errors.size > 0 error = errors.first = "In #{}: '#{error.}' at line #{error.line} col #{error.column} (code #{error.code}).\n" << "Add ?skip_slimmer=1 to the url to show the raw backend request.\n\n" << context(html, error) raise end end doc end |
#process(processors, body, template) ⇒ Object
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
# File 'lib/slimmer/skin.rb', line 88 def process(processors,body,template) logger.debug "Slimmer: starting skinning process" src = parse_html(body.to_s, "backend response") dest = parse_html(template, "template") start_time = Time.now logger.debug "Slimmer: Start time = #{start_time}" processors.each do |p| processor_start_time = Time.now logger.debug "Slimmer: Processor #{p} started at #{processor_start_time}" begin p.filter(src,dest) rescue => e logger.error "Slimmer: Failed while processing #{p}: #{[ e., e.backtrace ].flatten.join("\n")}" end processor_end_time = Time.now process_time = processor_end_time - processor_start_time logger.debug "Slimmer: Processor #{p} ended at #{processor_end_time} (#{process_time}s)" end end_time = Time.now logger.debug "Slimmer: Skinning process completed at #{end_time} (#{end_time - start_time}s)" # this is a horrible fix to Nokogiri removing the closing </noscript> tag required by Google Website Optimizer. # http://www.google.com/support/websiteoptimizer/bin/answer.py?hl=en_us&answer=64418 dest.to_html.sub(/<noscript rel=("|')placeholder("|')>/, "") end |
#report_parse_errors_if_strict!(nokogiri_doc, description_for_error_message) ⇒ Object
52 53 54 |
# File 'lib/slimmer/skin.rb', line 52 def report_parse_errors_if_strict!(nokogiri_doc, ) nokogiri_doc end |
#success(source_request, response, body) ⇒ Object
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
# File 'lib/slimmer/skin.rb', line 115 def success(source_request, response, body) artefact = artefact_from_header(response) processors = [ Processors::TitleInserter.new(), Processors::TagMover.new(), Processors::ConditionalCommentMover.new(), Processors::BodyInserter.new([:wrapper_id] || 'wrapper'), Processors::BodyClassCopier.new, Processors::HeaderContextInserter.new(), Processors::SectionInserter.new(artefact), Processors::GoogleAnalyticsConfigurator.new(response, artefact), Processors::RelatedItemsInserter.new(self, artefact), Processors::LogoClassInserter.new(artefact), Processors::ReportAProblemInserter.new(self, source_request.url), Processors::SearchIndexSetter.new(response), Processors::MetaViewportRemover.new(response), Processors::CampaignNotificationInserter.new(self, response.headers), Processors::BetaNoticeInserter.new(self, response.headers), ] template_name = response.headers[Headers::TEMPLATE_HEADER] || 'wrapper' process(processors, body, template(template_name)) end |
#template(template_name) ⇒ Object
19 20 21 22 23 24 25 26 27 |
# File 'lib/slimmer/skin.rb', line 19 def template(template_name) if use_cache template_cache.fetch(template_name) do load_template(template_name) end else load_template(template_name) end end |
#template_url(template_name) ⇒ Object
46 47 48 49 50 |
# File 'lib/slimmer/skin.rb', line 46 def template_url(template_name) host = asset_host.dup host += '/' unless host =~ /\/$/ "#{host}templates/#{template_name}.html.erb" end |