slimmer 0.8.0 → 0.9.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
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