slimmer 0.8.0 → 0.9.0.beta1

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 ADDED
@@ -0,0 +1,5 @@
1
+ # 0.9.0
2
+
3
+ * Moved templates into slimmer rather than using separate static project
4
+ * Added railtie so that slimmer can be dropped into a rails app without configuration
5
+ * Began to write *gasp* tests!
data/README.md ADDED
@@ -0,0 +1,66 @@
1
+ Slimmer provides rack middleware for applying a standard header and footer around pages
2
+ returned by a ruby (rack) application.
3
+
4
+ It does this by taking the page rendered by the application, extracting the contents of
5
+ a div with id 'wrapper' and inserting that into one of its templates. It also transfers
6
+ various other details, such as meta, script, and style tags.
7
+
8
+ ## Use in a Rails app
9
+
10
+ Slimmer provides a Railtie so no configuration is necessary should you want to use one
11
+ of the supplied templates. If you want to use your own set of templates you will need
12
+ to specify the appropriate path or host (slimmer can load templates over http) eg.
13
+
14
+ YourApp::Application.configure do
15
+ config.slimmer.template_path = '/place/on/file/system'
16
+ end
17
+
18
+ YourApp::Application.configure do
19
+ config.slimmer.template_host = 'http://your.server.somewhere'
20
+ end
21
+
22
+ it expects to find templates in a folder called 'templates' on that host or in that folder
23
+
24
+ ## Use elsewhere
25
+
26
+ Slimmer will work as standard rack middleware:
27
+
28
+ use Slimmer::App
29
+
30
+ or
31
+
32
+ use Slimmer::App, :template_path => "/path/to/my/templates"
33
+
34
+ ## Specifying a template
35
+
36
+ A specific template can be requested by giving its name in the X-Slimmer-Template HTTP header
37
+
38
+ eg in a rails app
39
+
40
+ class MyController < ApplicationController
41
+ def index
42
+ headers['X-Slimmer-Template'] = 'homepage'
43
+ end
44
+ end
45
+
46
+ There's also a macro style method:
47
+
48
+ class YourController < ApplicationController
49
+ slimmer_template :admin
50
+ end
51
+
52
+ To get this, include Slimmer::Template in your controller:
53
+
54
+ class ApplicationController < ActionController::Base
55
+ include Slimmer::Template
56
+ end
57
+
58
+ ## The name
59
+
60
+ Slimmer was extracted from a much larger project called 'skinner'. 'slimmer' referred to the size
61
+ of its code compared to skinner (which also acted as an HTTP proxy and mixed in a few other
62
+ concerns). Over time the codebase has grown a little, but the name stuck.
63
+
64
+ ## Python
65
+
66
+ The repository also includes a python version but this is not currently maintained.
data/Rakefile CHANGED
@@ -1,15 +1,19 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
 
3
- require "rubygems"
4
- require "rake/gempackagetask"
3
+ require "bundler/gem_tasks"
4
+ require "rdoc/task"
5
+ require 'rake/testtask'
5
6
 
6
- spec = Gem::Specification.load('slimmer.gemspec')
7
-
8
- Rake::GemPackageTask.new(spec) do
9
- end
10
-
11
- Rake::RDocTask.new do |rd|
7
+ RDoc::Task.new do |rd|
12
8
  rd.rdoc_files.include("lib/**/*.rb")
13
9
  rd.rdoc_dir = "rdoc"
14
10
  end
15
11
 
12
+ Rake::TestTask.new("test") do |t|
13
+ t.ruby_opts << "-rubygems"
14
+ t.libs << "test"
15
+ t.test_files = FileList["test/**/*_test.rb"]
16
+ t.verbose = true
17
+ end
18
+
19
+ task :default => :test
@@ -0,0 +1,9 @@
1
+ module Slimmer
2
+ class Railtie < Rails::Railtie
3
+ config.slimmer = ActiveSupport::OrderedOptions.new
4
+
5
+ initializer "slimmer.configure" do |app|
6
+ app.middleware.use Slimmer::App, app.config.slimmer.to_hash
7
+ end
8
+ end
9
+ end
@@ -6,9 +6,9 @@ module Slimmer
6
6
 
7
7
  module ClassMethods
8
8
  def slimmer_template template_name
9
- after_filter do
10
- response.headers[Slimmer::TEMPLATE_HEADER] = template_name.to_s
11
- end
9
+ after_filter do
10
+ response.headers[Slimmer::TEMPLATE_HEADER] = template_name.to_s
11
+ end
12
12
  end
13
13
  end
14
14
  end
@@ -0,0 +1,3 @@
1
+ module Slimmer
2
+ VERSION = '0.9.0.beta1'
3
+ end
data/lib/slimmer.rb CHANGED
@@ -1,6 +1,7 @@
1
- require 'nokogiri'
2
- require 'open-uri'
3
1
  require 'slimmer/template'
2
+ require 'slimmer/railtie' if defined?(Rails)
3
+
4
+ require 'nokogiri'
4
5
  require 'erb'
5
6
 
6
7
  module Slimmer
@@ -9,14 +10,15 @@ module Slimmer
9
10
 
10
11
  class App
11
12
 
12
- def initialize(app,options = {})
13
+ def initialize(app, *args, &block)
14
+ options = args.first || {}
13
15
  @app = app
14
16
  @skin = Skin.new(options[:asset_host], options[:template_path])
15
17
  end
16
18
 
17
19
  def call(env)
18
- status,env2,body = @app.call(env)
19
- rewrite_response(env,[status,env2,body])
20
+ status, headers, body = @app.call(env)
21
+ rewrite_response(env, [status, headers, body])
20
22
  end
21
23
 
22
24
  def on_success(request,body)
@@ -27,12 +29,12 @@ module Slimmer
27
29
  @skin.admin(request,body)
28
30
  end
29
31
 
30
- def on_error(request,status, body)
31
- @skin.error(request, '500')
32
+ def on_error(request, status, body)
33
+ @skin.error(request, '500', body)
32
34
  end
33
35
 
34
36
  def on_404(request,body)
35
- @skin.error(request, '404')
37
+ @skin.error(request, '404', body)
36
38
  end
37
39
 
38
40
  def s(body)
@@ -59,7 +61,7 @@ module Slimmer
59
61
  when 404
60
62
  rewritten_body = on_404(request,s(app_body))
61
63
  else
62
- rewritten_body = on_error(request,status, s(app_body))
64
+ rewritten_body = on_error(request,status,s(app_body))
63
65
  end
64
66
  else
65
67
  rewritten_body = app_body
@@ -197,7 +199,7 @@ module Slimmer
197
199
  dest.at_css(@path).replace(body)
198
200
  end
199
201
  end
200
-
202
+
201
203
  class BodyClassCopier
202
204
  def filter(src, dest)
203
205
  src_body_tag = src.at_css("body")
@@ -231,8 +233,8 @@ module Slimmer
231
233
  class Skin
232
234
 
233
235
  def initialize(asset_host = nil, template_path = nil)
236
+ @template_path = template_path || File.expand_path("../../templates", __FILE__)
234
237
  @asset_host = asset_host
235
- @template_path = template_path
236
238
  @template = {}
237
239
  end
238
240
 
@@ -254,7 +256,7 @@ module Slimmer
254
256
  end
255
257
 
256
258
  def templates_are_local?
257
- File.exists? template_path
259
+ File.exists?(template_path)
258
260
  end
259
261
 
260
262
  def unparse_esi(doc)
@@ -265,11 +267,11 @@ module Slimmer
265
267
  doc.gsub("<include","<esi:include").gsub(/><\/(esi:)?include>/, ' />')
266
268
  end
267
269
 
268
- def error(request, template_name)
270
+ def error(request, template_name, body)
269
271
  processors = [
270
272
  TitleInserter.new()
271
273
  ]
272
- self.process(processors,"<html></html>",template(template_name))
274
+ self.process(processors, body, template(template_name))
273
275
  end
274
276
 
275
277
  def process(processors,body,template)
@@ -3,13 +3,13 @@ require 'rake'
3
3
  namespace :slimmer do
4
4
  desc "Symlink from public directory to static directory"
5
5
  task :link do
6
- path_to_static = "../static/public"
7
- path_to_public = "public"
8
- commands = ["cd #{path_to_public}"]
9
- dirs_to_link = Dir.glob("../static/public/*") {|f|
10
- commands << "ln -s #{path_to_static}/#{f}"
11
- }
12
- commands << ["cd .."]
13
- run commands.join(" && ")
6
+ path_to_static = "../static/public"
7
+ path_to_public = "public"
8
+ commands = ["cd #{path_to_public}"]
9
+ dirs_to_link = Dir.glob("../static/public/*") {|f|
10
+ commands << "ln -s #{path_to_static}/#{f}"
11
+ }
12
+ commands << ["cd .."]
13
+ run commands.join(" && ")
14
14
  end
15
15
  end
@@ -0,0 +1,30 @@
1
+ require "test_helper"
2
+
3
+ class BodyInserterTest < MiniTest::Unit::TestCase
4
+ def test_should_replace_contents_of_wrapper_in_template
5
+ template = as_nokogiri %{
6
+ <html><body><div><div id="wrapper"></div></div></body></html>
7
+ }
8
+ source = as_nokogiri %{
9
+ <html><body><nav></nav><div id="wrapper"><p>this should be moved</p></div></body></html>
10
+ }
11
+
12
+ Slimmer::BodyInserter.new.filter(source, template)
13
+ assert_in template, "#wrapper", %{<p>this should be moved</p>}
14
+ end
15
+
16
+ def test_should_allow_replacement_of_arbitrary_wrappers
17
+ template = as_nokogiri %{
18
+ <html><body><div>
19
+ <div id="wrapper">don't touch this</div>
20
+ <div id="some_other_id"></div></div></body></html>
21
+ }
22
+ source = as_nokogiri %{
23
+ <html><body><div id="some_other_id"><p>this should be moved</p></div></body></html>
24
+ }
25
+
26
+ Slimmer::BodyInserter.new("#some_other_id").filter(source, template)
27
+ assert_in template, "#wrapper", %{don't touch this}
28
+ assert_in template, "#some_other_id", %{<p>this should be moved</p>}
29
+ end
30
+ end
@@ -0,0 +1,8 @@
1
+ require "test_helper"
2
+
3
+ class TestSlimmer < MiniTest::Unit::TestCase
4
+ def test_template_can_be_loaded
5
+ s = Slimmer::Skin.new
6
+ assert s.load_template('wrapper')
7
+ end
8
+ end
@@ -0,0 +1,47 @@
1
+ require_relative '../lib/slimmer'
2
+ require 'minitest/autorun'
3
+ require 'rack/test'
4
+
5
+ class MiniTest::Unit::TestCase
6
+ def as_nokogiri(html_string)
7
+ Nokogiri::HTML.parse(html_string.strip)
8
+ end
9
+
10
+ def assert_in(template, selector, content, message=nil)
11
+ assert_equal content, template.at_css(selector).inner_html.to_s, message
12
+ end
13
+ end
14
+
15
+ class SlimmerIntegrationTest < MiniTest::Unit::TestCase
16
+ include Rack::Test::Methods
17
+
18
+ def self.given_response(code, body)
19
+ define_method(:app) do
20
+ inner_app = proc { |env|
21
+ [code, {"Content-Type" => "text/html"}, body]
22
+ }
23
+ Slimmer::App.new(inner_app)
24
+ end
25
+
26
+ define_method(:setup) { get "/" }
27
+ end
28
+
29
+ private
30
+
31
+ def assert_not_rendered_in_template(content)
32
+ refute_match /#{Regexp.escape(content)}/, last_response.body
33
+ end
34
+
35
+ def assert_rendered_in_template(selector, content=nil, message=nil)
36
+ unless message
37
+ if content
38
+ message = "Expected to find #{content.inspect} at #{selector.inspect} in the output template"
39
+ else
40
+ message = "Expected to find #{selector.inspect} in the output template"
41
+ end
42
+ end
43
+ element = Nokogiri::HTML.parse(last_response.body).at_css(selector)
44
+ assert element, message
45
+ assert_equal content, element.inner_html.to_s, message if content
46
+ end
47
+ end
@@ -0,0 +1,142 @@
1
+ require "test_helper"
2
+
3
+ module TypicalUsage
4
+ class NormalResponseTest < SlimmerIntegrationTest
5
+
6
+ given_response 200, %{
7
+ <html>
8
+ <head><title>The title of the page</title>
9
+ <meta name="something" content="yes">
10
+ <meta name="x-section-name" content="This section">
11
+ <meta name="x-section-link" content="/this_section">
12
+ <script src="blah.js"></script>
13
+ <link href="app.css" rel="stylesheet" type="text/css">
14
+ </head>
15
+ <body class="body_class">
16
+ <div id="wrapper">The body of the page</div>
17
+ </body>
18
+ </html>
19
+ }
20
+
21
+ def test_should_replace_the_wrapper_using_the_app_response
22
+ assert_rendered_in_template "#wrapper", "The body of the page"
23
+ end
24
+
25
+ def test_should_replace_the_title_using_the_app_response
26
+ assert_rendered_in_template "head title", "The title of the page"
27
+ end
28
+
29
+ def test_should_move_script_tags_into_the_head
30
+ assert_rendered_in_template "head script[src='blah.js']"
31
+ end
32
+
33
+ def test_should_move_meta_tags_into_the_head
34
+ assert_rendered_in_template "head meta[name='something']"
35
+ end
36
+
37
+ def test_should_move_stylesheet_tags_into_the_head
38
+ assert_rendered_in_template "head link[href='app.css']"
39
+ end
40
+
41
+ def test_should_copy_the_class_of_the_body_element
42
+ assert_rendered_in_template "body.body_class"
43
+ end
44
+
45
+ def test_should_insert_meta_navigation_links_into_the_navigation
46
+ assert_rendered_in_template "nav[role=navigation] li a[href='/this_section']", "This section"
47
+ end
48
+ end
49
+
50
+ class Error500ResponseTest < SlimmerIntegrationTest
51
+ include Rack::Test::Methods
52
+
53
+ given_response 500, %{
54
+ <html>
55
+ <head><title>500 Error</title>
56
+ <meta name="something" content="yes">
57
+ <meta name="x-section-name" content="This section">
58
+ <meta name="x-section-link" content="/this_section">
59
+ <script src="blah.js"></script>
60
+ <link href="app.css" rel="stylesheet" type="text/css">
61
+ </head>
62
+ <body class="body_class">
63
+ <div id="wrapper"><p class='message'>Something bad happened</p></div>
64
+ </body>
65
+ </html>
66
+ }
67
+
68
+ def test_should_not_replace_the_wrapper_using_the_app_response
69
+ assert_not_rendered_in_template "Something bad happened"
70
+ end
71
+
72
+ def test_should_include_default_500_error_message
73
+ assert_rendered_in_template "body .content header h1", "We seem to be having a problem."
74
+ end
75
+
76
+ def test_should_replace_the_title_using_the_app_response
77
+ assert_rendered_in_template "head title", "500 Error"
78
+ end
79
+ end
80
+
81
+ class Error404ResponseTest < SlimmerIntegrationTest
82
+ include Rack::Test::Methods
83
+
84
+ given_response 404, %{
85
+ <html>
86
+ <head><title>404 Missing</title>
87
+ <meta name="something" content="yes">
88
+ <meta name="x-section-name" content="This section">
89
+ <meta name="x-section-link" content="/this_section">
90
+ <script src="blah.js"></script>
91
+ <link href="app.css" rel="stylesheet" type="text/css">
92
+ </head>
93
+ <body class="body_class">
94
+ <div id="wrapper"><p class='message'>Something bad happened</p></div>
95
+ </body>
96
+ </html>
97
+ }
98
+
99
+ def test_should_not_replace_the_wrapper_using_the_app_response
100
+ assert_not_rendered_in_template "Something bad happened"
101
+ end
102
+
103
+ def test_should_include_default_404_error_message
104
+ assert_rendered_in_template "body .content header h1", "Oops! We can't find what you're looking for."
105
+ end
106
+
107
+ def test_should_replace_the_title_using_the_app_response
108
+ assert_rendered_in_template "head title", "404 Missing"
109
+ end
110
+ end
111
+
112
+ class Error406ResponseTest < SlimmerIntegrationTest
113
+ include Rack::Test::Methods
114
+
115
+ given_response 406, %{
116
+ <html>
117
+ <head><title>406 Not Acceptable</title>
118
+ <meta name="something" content="yes">
119
+ <meta name="x-section-name" content="This section">
120
+ <meta name="x-section-link" content="/this_section">
121
+ <script src="blah.js"></script>
122
+ <link href="app.css" rel="stylesheet" type="text/css">
123
+ </head>
124
+ <body class="body_class">
125
+ <div id="wrapper"><p class='message'>Something bad happened</p></div>
126
+ </body>
127
+ </html>
128
+ }
129
+
130
+ def test_should_not_replace_the_wrapper_using_the_app_response
131
+ assert_not_rendered_in_template "Something bad happened"
132
+ end
133
+
134
+ def test_should_include_default_non_404_error_message
135
+ assert_rendered_in_template "body .content header h1", "We seem to be having a problem."
136
+ end
137
+
138
+ def test_should_replace_the_title_using_the_app_response
139
+ assert_rendered_in_template "head title", "406 Not Acceptable"
140
+ end
141
+ end
142
+ end
@@ -0,0 +1,17 @@
1
+ require "test_helper"
2
+
3
+ class UnparseESITest < MiniTest::Unit::TestCase
4
+ def test_unparse_esi
5
+ options = [
6
+ "<include src='/blah/blah'></include>",
7
+ "<esi:include src='/blah/blah'></esi:include>",
8
+ "<esi:include src='/blah/blah' />",
9
+ "<include src='/blah/blah' />"
10
+ ]
11
+
12
+ options.each do |doc|
13
+ s = Slimmer::Skin.new('blah')
14
+ assert_equal "<esi:include src='/blah/blah' />", s.unparse_esi(doc)
15
+ end
16
+ end
17
+ end
metadata CHANGED
@@ -1,8 +1,8 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: slimmer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.0
5
- prerelease:
4
+ version: 0.9.0.beta1
5
+ prerelease: 6
6
6
  platform: ruby
7
7
  authors:
8
8
  - Ben Griffiths
@@ -10,19 +10,63 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2011-11-01 00:00:00.000000000Z
13
+ date: 2011-11-18 00:00:00.000000000Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: nokogiri
17
- requirement: &70264965293060 !ruby/object:Gem::Requirement
17
+ requirement: &70366350084360 !ruby/object:Gem::Requirement
18
18
  none: false
19
19
  requirements:
20
- - - ! '>='
20
+ - - ~>
21
21
  - !ruby/object:Gem::Version
22
- version: '0'
22
+ version: 1.5.0
23
23
  type: :runtime
24
24
  prerelease: false
25
- version_requirements: *70264965293060
25
+ version_requirements: *70366350084360
26
+ - !ruby/object:Gem::Dependency
27
+ name: rack
28
+ requirement: &70366350083660 !ruby/object:Gem::Requirement
29
+ none: false
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: 1.3.5
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: *70366350083660
37
+ - !ruby/object:Gem::Dependency
38
+ name: rake
39
+ requirement: &70366350082840 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ~>
43
+ - !ruby/object:Gem::Version
44
+ version: 0.9.2.2
45
+ type: :development
46
+ prerelease: false
47
+ version_requirements: *70366350082840
48
+ - !ruby/object:Gem::Dependency
49
+ name: rack-test
50
+ requirement: &70366350076560 !ruby/object:Gem::Requirement
51
+ none: false
52
+ requirements:
53
+ - - ~>
54
+ - !ruby/object:Gem::Version
55
+ version: 0.6.1
56
+ type: :development
57
+ prerelease: false
58
+ version_requirements: *70366350076560
59
+ - !ruby/object:Gem::Dependency
60
+ name: mocha
61
+ requirement: &70366350075780 !ruby/object:Gem::Requirement
62
+ none: false
63
+ requirements:
64
+ - - ~>
65
+ - !ruby/object:Gem::Version
66
+ version: 0.9.12
67
+ type: :development
68
+ prerelease: false
69
+ version_requirements: *70366350075780
26
70
  description: Rack middleware for skinning pages using a specific template
27
71
  email:
28
72
  - bengriffiths@gmail.com
@@ -31,10 +75,19 @@ executables: []
31
75
  extensions: []
32
76
  extra_rdoc_files: []
33
77
  files:
78
+ - README.md
79
+ - CHANGELOG.md
80
+ - lib/slimmer/railtie.rb
34
81
  - lib/slimmer/template.rb
82
+ - lib/slimmer/version.rb
35
83
  - lib/slimmer.rb
36
84
  - lib/tasks/slimmer.rake
37
85
  - Rakefile
86
+ - test/processors/body_inserter_test.rb
87
+ - test/slimmer_test.rb
88
+ - test/test_helper.rb
89
+ - test/typical_usage_test.rb
90
+ - test/unparse_esi_test.rb
38
91
  homepage: http://github.com/alphagov/slimmer
39
92
  licenses: []
40
93
  post_install_message:
@@ -50,13 +103,18 @@ required_ruby_version: !ruby/object:Gem::Requirement
50
103
  required_rubygems_version: !ruby/object:Gem::Requirement
51
104
  none: false
52
105
  requirements:
53
- - - ! '>='
106
+ - - ! '>'
54
107
  - !ruby/object:Gem::Version
55
- version: '0'
108
+ version: 1.3.1
56
109
  requirements: []
57
110
  rubyforge_project: slimmer
58
111
  rubygems_version: 1.8.10
59
112
  signing_key:
60
113
  specification_version: 3
61
114
  summary: Thinner than the skinner
62
- test_files: []
115
+ test_files:
116
+ - test/processors/body_inserter_test.rb
117
+ - test/slimmer_test.rb
118
+ - test/test_helper.rb
119
+ - test/typical_usage_test.rb
120
+ - test/unparse_esi_test.rb