slimmer 1.2.5 → 2.0.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.
- data/CHANGELOG.md +14 -1
- data/lib/slimmer.rb +28 -17
- data/lib/slimmer/app.rb +9 -9
- data/lib/slimmer/headers.rb +32 -1
- data/lib/slimmer/{admin_title_inserter.rb → processors/admin_title_inserter.rb} +1 -1
- data/lib/slimmer/{body_class_copier.rb → processors/body_class_copier.rb} +1 -1
- data/lib/slimmer/{body_inserter.rb → processors/body_inserter.rb} +1 -1
- data/lib/slimmer/{conditional_comment_mover.rb → processors/conditional_comment_mover.rb} +1 -1
- data/lib/slimmer/{footer_remover.rb → processors/footer_remover.rb} +1 -1
- data/lib/slimmer/{google_analytics_configurator.rb → processors/google_analytics_configurator.rb} +3 -2
- data/lib/slimmer/{header_context_inserter.rb → processors/header_context_inserter.rb} +1 -1
- data/lib/slimmer/processors/logo_class_inserter.rb +20 -0
- data/lib/slimmer/processors/related_items_inserter.rb +20 -0
- data/lib/slimmer/{search_path_setter.rb → processors/search_path_setter.rb} +2 -4
- data/lib/slimmer/{section_inserter.rb → processors/section_inserter.rb} +1 -1
- data/lib/slimmer/{tag_mover.rb → processors/tag_mover.rb} +1 -1
- data/lib/slimmer/{title_inserter.rb → processors/title_inserter.rb} +1 -1
- data/lib/slimmer/skin.rb +28 -20
- data/lib/slimmer/template.rb +1 -1
- data/lib/slimmer/test.rb +5 -1
- data/lib/slimmer/test_template.rb +7 -1
- data/lib/slimmer/version.rb +1 -1
- data/test/fixtures/related.raw.html.erb +26 -22
- data/test/fixtures/wrapper.html.erb +2 -0
- data/test/headers_test.rb +56 -1
- data/test/processors/body_inserter_test.rb +4 -4
- data/test/{google_analytics_test.rb → processors/google_analytics_test.rb} +31 -0
- data/test/processors/header_context_inserter_test.rb +5 -5
- data/test/processors/logo_class_inserter_test.rb +55 -0
- data/test/processors/related_items_inserter_test.rb +61 -0
- data/test/{search_path_setter_test.rb → processors/search_path_setter_test.rb} +0 -0
- data/test/processors/section_inserter_test.rb +20 -5
- data/test/test_helper.rb +31 -22
- data/test/typical_usage_test.rb +101 -70
- metadata +60 -70
- data/lib/slimmer/related_items_inserter.rb +0 -36
- data/lib/slimmer/url_rewriter.rb +0 -40
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,18 @@
|
|
1
|
+
# 2.0.0
|
2
|
+
|
3
|
+
Backwards-incompatible changes:
|
4
|
+
|
5
|
+
* Artefact has to be explicitly passed to slimmer.
|
6
|
+
* RelatedItemsInserter uses passed artefact instead of calling out to panopticon.
|
7
|
+
* Slimmer now strips all X-Slimmer-* HTTP headers from the final response.
|
8
|
+
|
9
|
+
Other changes
|
10
|
+
|
11
|
+
* new LogoClassInserter module - adds classes to the `#wrapper` element to control the appearence of the directgov and businesslink logos
|
12
|
+
* Rounded Corners!!! (it is 2.0 after all)
|
13
|
+
|
1
14
|
# 0.9.0
|
2
15
|
|
3
16
|
* Moved templates into slimmer rather than using separate static project
|
4
17
|
* Added railtie so that slimmer can be dropped into a rails app without configuration
|
5
|
-
* Began to write *gasp* tests!
|
18
|
+
* Began to write *gasp* tests!
|
data/lib/slimmer.rb
CHANGED
@@ -1,3 +1,8 @@
|
|
1
|
+
#########################################
|
2
|
+
####### Look, Rounded corners.... It's 2.0 #####
|
3
|
+
#####################################################
|
4
|
+
#######################################################
|
5
|
+
|
1
6
|
require 'nokogiri'
|
2
7
|
require 'erb'
|
3
8
|
require 'open-uri'
|
@@ -5,33 +10,39 @@ require 'plek'
|
|
5
10
|
require 'null_logger'
|
6
11
|
require 'openssl'
|
7
12
|
|
13
|
+
require 'slimmer/version'
|
8
14
|
require 'slimmer/railtie' if defined? Rails
|
9
15
|
|
10
16
|
module Slimmer
|
11
|
-
TEMPLATE_HEADER = 'X-Slimmer-Template'
|
12
|
-
SKIP_HEADER = 'X-Slimmer-Skip'
|
13
|
-
SEARCH_PATH_HEADER = 'X-Slimmer-Search-Path'
|
14
17
|
|
15
|
-
autoload :Version, 'slimmer/version'
|
16
18
|
autoload :Railtie, 'slimmer/railtie'
|
17
19
|
autoload :Skin, 'slimmer/skin'
|
18
20
|
|
19
21
|
autoload :Template, 'slimmer/template'
|
20
22
|
autoload :App, 'slimmer/app'
|
21
|
-
autoload :
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
23
|
+
autoload :Headers, 'slimmer/headers'
|
24
|
+
|
25
|
+
module Processors
|
26
|
+
autoload :AdminTitleInserter, 'slimmer/processors/admin_title_inserter'
|
27
|
+
autoload :BodyClassCopier, 'slimmer/processors/body_class_copier'
|
28
|
+
autoload :BodyInserter, 'slimmer/processors/body_inserter'
|
29
|
+
autoload :ConditionalCommentMover, 'slimmer/processors/conditional_comment_mover'
|
30
|
+
autoload :FooterRemover, 'slimmer/processors/footer_remover'
|
31
|
+
autoload :GoogleAnalyticsConfigurator, 'slimmer/processors/google_analytics_configurator'
|
32
|
+
autoload :HeaderContextInserter, 'slimmer/processors/header_context_inserter'
|
33
|
+
autoload :LogoClassInserter, 'slimmer/processors/logo_class_inserter'
|
34
|
+
autoload :RelatedItemsInserter, 'slimmer/processors/related_items_inserter'
|
35
|
+
autoload :SearchPathSetter, 'slimmer/processors/search_path_setter'
|
36
|
+
autoload :SectionInserter, 'slimmer/processors/section_inserter'
|
37
|
+
autoload :TagMover, 'slimmer/processors/tag_mover'
|
38
|
+
autoload :TitleInserter, 'slimmer/processors/title_inserter'
|
39
|
+
end
|
34
40
|
|
35
41
|
class TemplateNotFoundException < StandardError; end
|
36
42
|
class CouldNotRetrieveTemplate < StandardError; end
|
37
43
|
end
|
44
|
+
|
45
|
+
#######################################################
|
46
|
+
#####################################################
|
47
|
+
#################################################
|
48
|
+
#########################################
|
data/lib/slimmer/app.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
require "gds_api/exceptions"
|
2
|
-
|
3
1
|
module Slimmer
|
4
2
|
class App
|
5
3
|
attr_accessor :logger
|
@@ -29,10 +27,10 @@ module Slimmer
|
|
29
27
|
response = Rack::Response.new(body, status, headers)
|
30
28
|
|
31
29
|
if response_can_be_rewritten?(response) && !skip_slimmer?(env, response)
|
32
|
-
rewrite_response(env, response)
|
33
|
-
else
|
34
|
-
[status, headers, body]
|
30
|
+
status, headers, body = rewrite_response(env, response)
|
35
31
|
end
|
32
|
+
|
33
|
+
[status, strip_slimmer_headers(headers), body]
|
36
34
|
end
|
37
35
|
|
38
36
|
def response_can_be_rewritten?(response)
|
@@ -53,7 +51,7 @@ module Slimmer
|
|
53
51
|
end
|
54
52
|
|
55
53
|
def skip_slimmer_header?(response)
|
56
|
-
!!response.headers[SKIP_HEADER]
|
54
|
+
!!response.headers[Headers::SKIP_HEADER]
|
57
55
|
end
|
58
56
|
|
59
57
|
def s(body)
|
@@ -74,7 +72,7 @@ module Slimmer
|
|
74
72
|
|
75
73
|
rewritten_body = case response.status
|
76
74
|
when 200
|
77
|
-
if response.headers[TEMPLATE_HEADER] == 'admin' || request.path =~ /^\/admin(\/|$)/
|
75
|
+
if response.headers[Headers::TEMPLATE_HEADER] == 'admin' || request.path =~ /^\/admin(\/|$)/
|
78
76
|
@skin.admin s(response.body)
|
79
77
|
else
|
80
78
|
@skin.success request, response, s(response.body)
|
@@ -90,8 +88,10 @@ module Slimmer
|
|
90
88
|
response.headers['Content-Length'] = content_length(response.body)
|
91
89
|
|
92
90
|
response.finish
|
93
|
-
|
94
|
-
|
91
|
+
end
|
92
|
+
|
93
|
+
def strip_slimmer_headers(headers)
|
94
|
+
headers.reject {|k, v| k =~ /\A#{Headers::HEADER_PREFIX}/ }
|
95
95
|
end
|
96
96
|
end
|
97
97
|
end
|
data/lib/slimmer/headers.rb
CHANGED
@@ -2,6 +2,8 @@ module Slimmer
|
|
2
2
|
module Headers
|
3
3
|
InvalidHeader = Class.new(RuntimeError)
|
4
4
|
|
5
|
+
HEADER_PREFIX = "X-Slimmer"
|
6
|
+
|
5
7
|
SLIMMER_HEADER_MAPPING = {
|
6
8
|
section: "Section",
|
7
9
|
need_id: "Need-ID",
|
@@ -12,12 +14,41 @@ module Slimmer
|
|
12
14
|
skip: "Skip",
|
13
15
|
}
|
14
16
|
|
17
|
+
TEMPLATE_HEADER = "#{HEADER_PREFIX}-Template"
|
18
|
+
SKIP_HEADER = "#{HEADER_PREFIX}-Skip"
|
19
|
+
SEARCH_PATH_HEADER = "#{HEADER_PREFIX}-Search-Path"
|
20
|
+
ARTEFACT_HEADER = "#{HEADER_PREFIX}-Artefact"
|
21
|
+
|
15
22
|
def set_slimmer_headers(hash)
|
16
23
|
raise InvalidHeader if (hash.keys - SLIMMER_HEADER_MAPPING.keys).any?
|
17
24
|
SLIMMER_HEADER_MAPPING.each do |hash_key, header_suffix|
|
18
25
|
value = hash[hash_key]
|
19
|
-
headers["
|
26
|
+
headers["#{HEADER_PREFIX}-#{header_suffix}"] = value.to_s if value
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def set_slimmer_artefact(artefact_input)
|
31
|
+
if artefact_input.is_a?(Hash) or artefact_input.is_a?(OpenStruct)
|
32
|
+
artefact = artefact_input.dup
|
33
|
+
elsif artefact_input.respond_to?(:to_hash) # e.g. GdsApi::Response
|
34
|
+
artefact = artefact_input.to_hash.dup
|
35
|
+
end
|
36
|
+
|
37
|
+
if artefact.is_a?(Hash)
|
38
|
+
# Temporary deletions until the actions are removed from the API.
|
39
|
+
# The actions increase the size of the artefact significantly, and will
|
40
|
+
# only grow over time.
|
41
|
+
#
|
42
|
+
# We skip this when given an OpenStruct as they won't have actions etc...
|
43
|
+
artefact.delete("actions")
|
44
|
+
if artefact["related_items"]
|
45
|
+
artefact["related_items"].each do |ri|
|
46
|
+
ri["artefact"].delete("actions") if ri["artefact"]
|
47
|
+
end
|
48
|
+
end
|
20
49
|
end
|
50
|
+
|
51
|
+
headers[ARTEFACT_HEADER] = artefact.to_json
|
21
52
|
end
|
22
53
|
end
|
23
54
|
end
|
data/lib/slimmer/{google_analytics_configurator.rb → processors/google_analytics_configurator.rb}
RENAMED
@@ -1,6 +1,6 @@
|
|
1
1
|
require "json"
|
2
2
|
|
3
|
-
module Slimmer
|
3
|
+
module Slimmer::Processors
|
4
4
|
class GoogleAnalyticsConfigurator
|
5
5
|
PAGE_LEVEL_EVENT = 3
|
6
6
|
HEADER_MAPPING = {
|
@@ -29,7 +29,8 @@ module Slimmer
|
|
29
29
|
def set_custom_var(slot, name, value)
|
30
30
|
return nil unless value
|
31
31
|
value.downcase!
|
32
|
-
"_gaq.push(#{JSON.dump([ "_setCustomVar", slot, name, value, PAGE_LEVEL_EVENT])})
|
32
|
+
response = "_gaq.push(#{JSON.dump([ "_setCustomVar", slot, name, value, PAGE_LEVEL_EVENT])});\n"
|
33
|
+
response + "GOVUK.Analytics.#{name} = \"#{value}\";"
|
33
34
|
end
|
34
35
|
end
|
35
36
|
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Slimmer
|
2
|
+
module Processors
|
3
|
+
class LogoClassInserter
|
4
|
+
LOGO_CLASSES = %w(businesslink directgov)
|
5
|
+
|
6
|
+
def initialize(artefact)
|
7
|
+
@artefact = artefact
|
8
|
+
end
|
9
|
+
|
10
|
+
def filter(source, dest)
|
11
|
+
return unless @artefact and @artefact["tag_ids"]
|
12
|
+
logo_classes = LOGO_CLASSES & @artefact["tag_ids"]
|
13
|
+
wrapper = dest.css('#wrapper')
|
14
|
+
logo_classes.each do |klass|
|
15
|
+
wrapper.add_class(klass)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
class Slimmer::Processors::RelatedItemsInserter
|
2
|
+
include ERB::Util
|
3
|
+
|
4
|
+
def initialize(related_block_template, artefact)
|
5
|
+
@related_block_template = related_block_template
|
6
|
+
@artefact = artefact
|
7
|
+
end
|
8
|
+
|
9
|
+
def filter(content_document, page_template)
|
10
|
+
if content_document.at_css('body.mainstream div#related-items')
|
11
|
+
page_template.at_css('body.mainstream div#related-items').replace(related_item_block)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def related_item_block
|
16
|
+
artefact = @artefact
|
17
|
+
html = ERB.new(@related_block_template).result(binding)
|
18
|
+
Nokogiri::HTML.fragment(html)
|
19
|
+
end
|
20
|
+
end
|
@@ -1,6 +1,4 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
module Slimmer
|
1
|
+
module Slimmer::Processors
|
4
2
|
class SearchPathSetter
|
5
3
|
def initialize(response)
|
6
4
|
@response = response
|
@@ -13,7 +11,7 @@ module Slimmer
|
|
13
11
|
end
|
14
12
|
|
15
13
|
def search_scope
|
16
|
-
@response.headers[SEARCH_PATH_HEADER]
|
14
|
+
@response.headers[Slimmer::Headers::SEARCH_PATH_HEADER]
|
17
15
|
end
|
18
16
|
end
|
19
17
|
end
|
data/lib/slimmer/skin.rb
CHANGED
@@ -92,8 +92,6 @@ module Slimmer
|
|
92
92
|
logger.debug "Slimmer: Processor #{p} started at #{processor_start_time}"
|
93
93
|
begin
|
94
94
|
p.filter(src,dest)
|
95
|
-
rescue GdsApi::TimedOutException
|
96
|
-
raise
|
97
95
|
rescue => e
|
98
96
|
logger.error "Slimmer: Failed while processing #{p}: #{[ e.message, e.backtrace ].flatten.join("\n")}"
|
99
97
|
end
|
@@ -111,39 +109,49 @@ module Slimmer
|
|
111
109
|
|
112
110
|
def admin(body)
|
113
111
|
processors = [
|
114
|
-
TitleInserter.new(),
|
115
|
-
TagMover.new(),
|
116
|
-
AdminTitleInserter.new,
|
117
|
-
FooterRemover.new,
|
118
|
-
BodyInserter.new(),
|
119
|
-
BodyClassCopier.new,
|
112
|
+
Processors::TitleInserter.new(),
|
113
|
+
Processors::TagMover.new(),
|
114
|
+
Processors::AdminTitleInserter.new,
|
115
|
+
Processors::FooterRemover.new,
|
116
|
+
Processors::BodyInserter.new(),
|
117
|
+
Processors::BodyClassCopier.new,
|
120
118
|
]
|
121
119
|
process(processors, body, template('admin'))
|
122
120
|
end
|
123
121
|
|
124
122
|
def success(source_request, response, body)
|
123
|
+
artefact = artefact_from_header(response)
|
125
124
|
processors = [
|
126
|
-
TitleInserter.new(),
|
127
|
-
TagMover.new(),
|
128
|
-
ConditionalCommentMover.new(),
|
129
|
-
BodyInserter.new(options[:wrapper_id] || 'wrapper'),
|
130
|
-
BodyClassCopier.new,
|
131
|
-
HeaderContextInserter.new(),
|
132
|
-
SectionInserter.new(),
|
133
|
-
GoogleAnalyticsConfigurator.new(response),
|
134
|
-
SearchPathSetter.new(response),
|
135
|
-
RelatedItemsInserter.new(template('related.raw'),
|
125
|
+
Processors::TitleInserter.new(),
|
126
|
+
Processors::TagMover.new(),
|
127
|
+
Processors::ConditionalCommentMover.new(),
|
128
|
+
Processors::BodyInserter.new(options[:wrapper_id] || 'wrapper'),
|
129
|
+
Processors::BodyClassCopier.new,
|
130
|
+
Processors::HeaderContextInserter.new(),
|
131
|
+
Processors::SectionInserter.new(),
|
132
|
+
Processors::GoogleAnalyticsConfigurator.new(response),
|
133
|
+
Processors::SearchPathSetter.new(response),
|
134
|
+
Processors::RelatedItemsInserter.new(template('related.raw'), artefact),
|
135
|
+
Processors::LogoClassInserter.new(artefact),
|
136
136
|
]
|
137
137
|
|
138
|
-
template_name = response.headers[TEMPLATE_HEADER] || 'wrapper'
|
138
|
+
template_name = response.headers[Headers::TEMPLATE_HEADER] || 'wrapper'
|
139
139
|
process(processors, body, template(template_name))
|
140
140
|
end
|
141
141
|
|
142
142
|
def error(template_name, body)
|
143
143
|
processors = [
|
144
|
-
TitleInserter.new()
|
144
|
+
Processors::TitleInserter.new()
|
145
145
|
]
|
146
146
|
process(processors, body, template(template_name))
|
147
147
|
end
|
148
|
+
|
149
|
+
def artefact_from_header(response)
|
150
|
+
if response.headers.include?(Headers::ARTEFACT_HEADER)
|
151
|
+
JSON.parse(response.headers[Headers::ARTEFACT_HEADER])
|
152
|
+
else
|
153
|
+
nil
|
154
|
+
end
|
155
|
+
end
|
148
156
|
end
|
149
157
|
end
|
data/lib/slimmer/template.rb
CHANGED
data/lib/slimmer/test.rb
CHANGED
@@ -5,7 +5,11 @@ module Slimmer
|
|
5
5
|
class Skin
|
6
6
|
def load_template name
|
7
7
|
logger.debug "Slimmer: TEST MODE - Loading fixture template from #{__FILE__}"
|
8
|
-
|
8
|
+
if name == 'related.raw'
|
9
|
+
%{<div id="test-related-items"></div>}
|
10
|
+
else
|
11
|
+
Slimmer::TestTemplate::TEMPLATE
|
12
|
+
end
|
9
13
|
end
|
10
14
|
end
|
11
15
|
end
|
@@ -15,7 +15,13 @@ module Slimmer::TestTemplate
|
|
15
15
|
<script src="http://static.preview.alphagov.co.uk/static/customisation-settings.js" defer></script>
|
16
16
|
</head>
|
17
17
|
<body>
|
18
|
-
<
|
18
|
+
<nav role="navigation" class="header-context">
|
19
|
+
<ol class="group">
|
20
|
+
<li><a href="/">Home</a></li>
|
21
|
+
<li><a href="/browse">All sections</a></li>
|
22
|
+
</ol>
|
23
|
+
</nav>
|
24
|
+
|
19
25
|
<div id="wrapper"></div>
|
20
26
|
</body>
|
21
27
|
</html>
|
data/lib/slimmer/version.rb
CHANGED