rack-esi 0.1.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/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,21 @@
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.swp
15
+
16
+ ## PROJECT::GENERAL
17
+ coverage
18
+ rdoc
19
+ pkg
20
+
21
+ ## PROJECT::SPECIFIC
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Florian Assmann
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,17 @@
1
+ = rack-esi
2
+
3
+ Description goes here.
4
+
5
+ == Note on Patches/Pull Requests
6
+
7
+ * Fork the project.
8
+ * Make your feature addition or bug fix.
9
+ * Add tests for it. This is important so I don't break it in a
10
+ future version unintentionally.
11
+ * Commit, do not mess with rakefile, version, or history.
12
+ (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
13
+ * Send me a pull request. Bonus points for topic branches.
14
+
15
+ == Copyright
16
+
17
+ Copyright (c) 2009 Florian Assmann. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,53 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "rack-esi"
8
+ gem.summary = %Q{ESI middleware implementation for Rack.}
9
+ gem.description = %Q{Nokogiri based ESI middleware implementation for Rack with (limited) support for include, remove and comment.}
10
+ gem.email = "florian.assmann@email.de"
11
+ gem.homepage = "http://github.com/boof/rack-esi"
12
+ gem.authors = ["Florian Assmann"]
13
+ gem.add_development_dependency "riot", ">= 0"
14
+ gem.add_development_dependency "yard", ">= 0"
15
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
16
+ end
17
+ Jeweler::GemcutterTasks.new
18
+ rescue LoadError
19
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
20
+ end
21
+
22
+ require 'rake/testtask'
23
+ Rake::TestTask.new(:test) do |test|
24
+ test.libs << 'lib' << 'test'
25
+ test.pattern = 'test/**/*_test.rb'
26
+ test.verbose = true
27
+ end
28
+
29
+ begin
30
+ require 'rcov/rcovtask'
31
+ Rcov::RcovTask.new do |test|
32
+ test.libs << 'test'
33
+ test.pattern = 'test/**/*_test.rb'
34
+ test.verbose = true
35
+ end
36
+ rescue LoadError
37
+ task :rcov do
38
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
39
+ end
40
+ end
41
+
42
+ task :test => :check_dependencies
43
+
44
+ task :default => :test
45
+
46
+ begin
47
+ require 'yard'
48
+ YARD::Rake::YardocTask.new
49
+ rescue LoadError
50
+ task :yardoc do
51
+ abort "YARD is not available. In order to run yardoc, you must: sudo gem install yard"
52
+ end
53
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
data/lib/rack-esi.rb ADDED
@@ -0,0 +1,75 @@
1
+ require 'rack'
2
+ require 'nokogiri'
3
+
4
+ class Rack::ESI
5
+ NS = { 'esi' => 'http://www.edge-delivery.org/esi/1.0' }
6
+ Error = Class.new RuntimeError
7
+
8
+ def initialize(app, options = {})
9
+ @app = app
10
+
11
+ @paths = options[:skip]
12
+ @types = options[:only] || /^text\/(?:x|ht)ml/
13
+ @max_includes = options[:includes] || 32
14
+ @max_recursion = options[:depth] || 5
15
+ end
16
+
17
+ def call env, counter = { :recursion => 0, :includes => 0 }
18
+ return @app.call(env) if skip_path? env['PATH_INFO']
19
+
20
+ status, headers, source = @app.call env
21
+ return status, headers, source if skip_type? headers['Content-Type']
22
+
23
+ Rack::Response.new { |target|
24
+ source.each { |body| target.write compile(body, env, counter) }
25
+ }.finish
26
+ end
27
+
28
+ private
29
+
30
+ def fetch(path, env, counter)
31
+ call env.merge('PATH_INFO' => path), counter if path
32
+ end
33
+
34
+ # Should I use XML::SAX::Parser?
35
+ def compile(body, env, counter)
36
+ document = Nokogiri.XML body
37
+
38
+ document.css('esi|include,esi|remove,esi|comment', NS).each do |node|
39
+ case node.name
40
+ when 'include'
41
+ next unless counter[:includes] < @max_includes
42
+ counter[:includes] += 1
43
+ begin
44
+ next unless counter[:recursion] < @max_recursion
45
+ counter[:recursion] += 1
46
+ status, headers, compiled = fetch node['src'], env, counter
47
+ status, headers, compiled = fetch node['alt'], env, counter if status != 200
48
+ ensure
49
+ counter[:recursion] -= 1
50
+ end
51
+
52
+ if status != 200
53
+ raise Error if node['onerror'] != 'continue'
54
+ compiled = []
55
+ end
56
+
57
+ data = '' and compiled.each { |body| data << body }
58
+ node.swap data
59
+
60
+ when 'remove', 'comment'
61
+ node.unlink
62
+ end
63
+ end
64
+
65
+ document.to_xhtml
66
+ end
67
+
68
+ def skip_path?(path)
69
+ @paths =~ path if @paths
70
+ end
71
+ def skip_type?(type)
72
+ @types !~ type
73
+ end
74
+
75
+ end
@@ -0,0 +1,11 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
2
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
3
+ <html xmlns="http://www.w3.org/1999/xhtml" xmlns:esi="http://www.edge-delivery.org/esi/1.0">
4
+ <head>
5
+ <title>index.html</title>
6
+ <esi:comment text="This comment should be removed!" />
7
+ <esi:include src="/metatags.fragment" />
8
+ </head>
9
+ <body>
10
+ </body>
11
+ </html>
@@ -0,0 +1 @@
1
+ <meta name="replacement" content="content" />
@@ -0,0 +1,10 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
2
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
3
+ <html xmlns="http://www.w3.org/1999/xhtml" xmlns:esi="http://www.edge-delivery.org/esi/1.0">
4
+ <head>
5
+ <title>raw.html</title>
6
+ <esi:comment text="This comment should be removed!" />
7
+ </head>
8
+ <body>
9
+ </body>
10
+ </html>
@@ -0,0 +1,31 @@
1
+ require 'teststrap'
2
+
3
+ context 'Rack::ESI' do
4
+
5
+ __dirname__ = File.expand_path File.dirname(__FILE__)
6
+ root = Pathname.new File.join(__dirname__, 'fixtures')
7
+ opts = { :urls => ['/'], :root => root }
8
+
9
+ setup { ESI.new Static.new(App.new, opts), :skip => /raw/ }
10
+
11
+ context 'GET /raw.html' do
12
+ setup { MockRequest.new(topic).get '/raw.html' }
13
+ asserts('Content-Type') { topic.content_type }.equals 'text/html'
14
+ should('not be altered') { topic.body == root.join('raw.html').read }
15
+ end
16
+
17
+ context 'GET /index.html' do
18
+ setup { MockRequest.new(topic).get '/index.html' }
19
+
20
+ asserts('Content-Type') { topic.content_type }.equals 'text/html'
21
+ should('not have any ESI specific nodes') do
22
+ html(topic.body).
23
+ at('//esi:include|//esi:remove|//esi:comment', Rack::ESI::NS).nil?
24
+ end
25
+ should('have meta replacement with content') do
26
+ not html(topic.body).
27
+ at("//meta[@name='replacement' and @content='content']").nil?
28
+ end
29
+ end
30
+
31
+ end
data/test/teststrap.rb ADDED
@@ -0,0 +1,17 @@
1
+ require 'pathname'
2
+ require 'rubygems'
3
+ require 'riot'
4
+ require 'rack-esi'
5
+ require 'rack/mock'
6
+
7
+ def html(body)
8
+ Nokogiri.HTML(body).root
9
+ end
10
+
11
+ class App
12
+ def call(env)
13
+ Rack::Response.new.finish
14
+ end
15
+ end
16
+
17
+ include Rack
metadata ADDED
@@ -0,0 +1,87 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rack-esi
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Florian Assmann
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-11-26 00:00:00 +01:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: riot
17
+ type: :development
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: yard
27
+ type: :development
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: "0"
34
+ version:
35
+ description: Nokogiri based ESI middleware implementation for Rack with (limited) support for include, remove and comment.
36
+ email: florian.assmann@email.de
37
+ executables: []
38
+
39
+ extensions: []
40
+
41
+ extra_rdoc_files:
42
+ - LICENSE
43
+ - README.rdoc
44
+ files:
45
+ - .document
46
+ - .gitignore
47
+ - LICENSE
48
+ - README.rdoc
49
+ - Rakefile
50
+ - VERSION
51
+ - lib/rack-esi.rb
52
+ - test/fixtures/index.html
53
+ - test/fixtures/metatags.fragment
54
+ - test/fixtures/raw.html
55
+ - test/rack-esi_test.rb
56
+ - test/teststrap.rb
57
+ has_rdoc: true
58
+ homepage: http://github.com/boof/rack-esi
59
+ licenses: []
60
+
61
+ post_install_message:
62
+ rdoc_options:
63
+ - --charset=UTF-8
64
+ require_paths:
65
+ - lib
66
+ required_ruby_version: !ruby/object:Gem::Requirement
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ version: "0"
71
+ version:
72
+ required_rubygems_version: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: "0"
77
+ version:
78
+ requirements: []
79
+
80
+ rubyforge_project:
81
+ rubygems_version: 1.3.5
82
+ signing_key:
83
+ specification_version: 3
84
+ summary: ESI middleware implementation for Rack.
85
+ test_files:
86
+ - test/rack-esi_test.rb
87
+ - test/teststrap.rb