pan_handler 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +8 -0
- data/Gemfile +3 -0
- data/Guardfile +6 -0
- data/LICENSE +21 -0
- data/README.md +10 -0
- data/Rakefile +1 -0
- data/lib/pan_handler/configuration.rb +29 -0
- data/lib/pan_handler/middleware.rb +107 -0
- data/lib/pan_handler/pan_handler.rb +107 -0
- data/lib/pan_handler/source.rb +23 -0
- data/lib/pan_handler/version.rb +3 -0
- data/lib/pan_handler.rb +4 -0
- data/pan_handler.gemspec +29 -0
- data/rspec +1 -0
- data/spec/fixtures/example.css +1 -0
- data/spec/fixtures/example.html +5 -0
- data/spec/fixtures/test.jpg +0 -0
- data/spec/middleware_spec.rb +307 -0
- data/spec/pan_handler_spec.rb +114 -0
- data/spec/source_spec.rb +78 -0
- data/spec/spec_helper.rb +9 -0
- metadata +121 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Guardfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
Copyright (c) 2012 J. Doveston
|
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.
|
21
|
+
|
data/README.md
ADDED
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,29 @@
|
|
1
|
+
class PanHandler
|
2
|
+
class Configuration
|
3
|
+
attr_accessor :default_options, :root_path
|
4
|
+
attr_writer :pandoc
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@default_options = {
|
8
|
+
:from => 'html',
|
9
|
+
:to => 'odt'
|
10
|
+
}
|
11
|
+
end
|
12
|
+
|
13
|
+
def pandoc
|
14
|
+
@pandoc ||= (defined?(Bundler::GemfileError) ? `bundle exec which pandoc` : `which pandoc`).chomp
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class << self
|
19
|
+
attr_accessor :configuration
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.configuration
|
23
|
+
@configuration ||= Configuration.new
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.configure
|
27
|
+
yield(configuration)
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
class PanHandler
|
2
|
+
|
3
|
+
class Middleware
|
4
|
+
|
5
|
+
def initialize(app, options = {}, conditions = {})
|
6
|
+
@app = app
|
7
|
+
@options = options
|
8
|
+
@conditions = conditions
|
9
|
+
end
|
10
|
+
|
11
|
+
def call(env)
|
12
|
+
@request = Rack::Request.new(env)
|
13
|
+
@render_odt = false
|
14
|
+
|
15
|
+
set_request_to_render_as_odt(env) if render_as_odt?
|
16
|
+
status, headers, response = @app.call(env)
|
17
|
+
|
18
|
+
if rendering_odt? && headers['Content-Type'] =~ /text\/html|application\/xhtml\+xml/
|
19
|
+
body = response.respond_to?(:body) ? response.body : response.join
|
20
|
+
body = body.join if body.is_a?(Array)
|
21
|
+
body = PanHandler.new(translate_paths(body, env), @options).to_odt
|
22
|
+
response = [body]
|
23
|
+
|
24
|
+
# Do not cache ODTs
|
25
|
+
headers.delete('ETag')
|
26
|
+
headers.delete('Cache-Control')
|
27
|
+
|
28
|
+
headers["Content-Length"] = (body.respond_to?(:bytesize) ? body.bytesize : body.size).to_s
|
29
|
+
headers["Content-Type"] = "application/vnd.oasis.opendocument.text"
|
30
|
+
end
|
31
|
+
|
32
|
+
[status, headers, response]
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
# Change relative paths to absolute
|
38
|
+
def translate_paths(body, env)
|
39
|
+
# Host with protocol
|
40
|
+
root_path = PanHandler.configuration.root_path || ''
|
41
|
+
rel_path = env['REQUEST_URI'][/#{env['HTTP_HOST']}(.*)\//,1] || '/'
|
42
|
+
body.gsub(/(href|src)=(['"])([^\"']*|[^"']*)['"](\s?)/) do |match|
|
43
|
+
attr, delim, value, trailing = $1, $2, $3, $4
|
44
|
+
if value =~ /^http:\/\//i
|
45
|
+
# absolute url
|
46
|
+
''
|
47
|
+
else
|
48
|
+
file_path = root_path
|
49
|
+
# relative path
|
50
|
+
file_path = File.join(file_path, rel_path) if value[0] != '/'
|
51
|
+
# remove a possible query string
|
52
|
+
file_path = File.join(file_path, value[/^(.*)\?/,1] || value)
|
53
|
+
if File.exists?(file_path)
|
54
|
+
"#{attr}=#{delim}#{file_path}#{delim}#{trailing || ''}"
|
55
|
+
else
|
56
|
+
''
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def rendering_odt?
|
63
|
+
@render_odt
|
64
|
+
end
|
65
|
+
|
66
|
+
def render_as_odt?
|
67
|
+
request_path_is_odt = @request.path.match(%r{\.odt$})
|
68
|
+
|
69
|
+
if request_path_is_odt && @conditions[:only]
|
70
|
+
rules = [@conditions[:only]].flatten
|
71
|
+
rules.any? do |pattern|
|
72
|
+
if pattern.is_a?(Regexp)
|
73
|
+
@request.path =~ pattern
|
74
|
+
else
|
75
|
+
@request.path[0, pattern.length] == pattern
|
76
|
+
end
|
77
|
+
end
|
78
|
+
elsif request_path_is_odt && @conditions[:except]
|
79
|
+
rules = [@conditions[:except]].flatten
|
80
|
+
rules.map do |pattern|
|
81
|
+
if pattern.is_a?(Regexp)
|
82
|
+
return false if @request.path =~ pattern
|
83
|
+
else
|
84
|
+
return false if @request.path[0, pattern.length] == pattern
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
return true
|
89
|
+
else
|
90
|
+
request_path_is_odt
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def set_request_to_render_as_odt(env)
|
95
|
+
@render_odt = true
|
96
|
+
path = @request.path.sub(%r{\.odt$}, '')
|
97
|
+
%w[PATH_INFO REQUEST_URI].each { |e| env[e] = path }
|
98
|
+
env['HTTP_ACCEPT'] = concat(env['HTTP_ACCEPT'], Rack::Mime.mime_type('.html'))
|
99
|
+
env["Rack-Middleware-PanHandler"] = "true"
|
100
|
+
end
|
101
|
+
|
102
|
+
def concat(accepts, type)
|
103
|
+
(accepts || '').split(',').unshift(type).compact.join(',')
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
107
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
require 'tempfile'
|
2
|
+
|
3
|
+
class PanHandler
|
4
|
+
|
5
|
+
class NoExecutableError < StandardError
|
6
|
+
def initialize
|
7
|
+
msg = "No pandoc executable found at #{PanHandler.configuration.pandoc}\n"
|
8
|
+
msg << ">> Please install pandoc"
|
9
|
+
super(msg)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class ImproperSourceError < StandardError
|
14
|
+
def initialize(msg)
|
15
|
+
super("Improper Source: #{msg}")
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
attr_accessor :source
|
20
|
+
attr_reader :options
|
21
|
+
|
22
|
+
def initialize(url_file_or_html, options = {})
|
23
|
+
@source = Source.new(url_file_or_html)
|
24
|
+
@options = PanHandler.configuration.default_options.merge(options)
|
25
|
+
@options = normalize_options(@options)
|
26
|
+
|
27
|
+
raise NoExecutableError.new unless File.exists?(PanHandler.configuration.pandoc)
|
28
|
+
end
|
29
|
+
|
30
|
+
def command(path = nil)
|
31
|
+
args = [executable]
|
32
|
+
args += @options.to_a.flatten.compact
|
33
|
+
|
34
|
+
|
35
|
+
args << '--output'
|
36
|
+
args << (path || '-') # Write to file or stdout
|
37
|
+
|
38
|
+
unless @source.html?
|
39
|
+
args << @source.to_s
|
40
|
+
end
|
41
|
+
|
42
|
+
args.map {|arg| %Q{"#{arg.gsub('"', '\"')}"}}
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
def executable
|
47
|
+
default = PanHandler.configuration.pandoc
|
48
|
+
return default if default !~ /^\// # its not a path, so nothing we can do
|
49
|
+
if File.exist?(default)
|
50
|
+
default
|
51
|
+
else
|
52
|
+
default.split('/').last
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def to_odt(path=nil)
|
57
|
+
if path.nil?
|
58
|
+
tempfile = Tempfile.new('panhandler')
|
59
|
+
path = tempfile.path
|
60
|
+
end
|
61
|
+
args = command(path)
|
62
|
+
invoke = args.join(' ')
|
63
|
+
|
64
|
+
result = IO.popen(invoke, "wb+") do |odt|
|
65
|
+
odt.puts(@source.to_s) if @source.html?
|
66
|
+
odt.close_write
|
67
|
+
odt.gets(nil)
|
68
|
+
end
|
69
|
+
result = File.read(path) if path
|
70
|
+
tempfile.unlink if tempfile
|
71
|
+
|
72
|
+
raise "command failed: #{invoke}" if result.empty?
|
73
|
+
return result
|
74
|
+
end
|
75
|
+
|
76
|
+
def to_file(path)
|
77
|
+
self.to_odt(path)
|
78
|
+
File.new(path)
|
79
|
+
end
|
80
|
+
|
81
|
+
protected
|
82
|
+
|
83
|
+
def normalize_options(options)
|
84
|
+
normalized_options = {}
|
85
|
+
|
86
|
+
options.each do |key, value|
|
87
|
+
next if !value
|
88
|
+
normalized_key = "--#{normalize_arg key}"
|
89
|
+
normalized_options[normalized_key] = normalize_value(value)
|
90
|
+
end
|
91
|
+
normalized_options
|
92
|
+
end
|
93
|
+
|
94
|
+
def normalize_arg(arg)
|
95
|
+
arg.to_s.downcase.gsub(/[^a-z0-9]/,'-')
|
96
|
+
end
|
97
|
+
|
98
|
+
def normalize_value(value)
|
99
|
+
case value
|
100
|
+
when TrueClass
|
101
|
+
nil
|
102
|
+
else
|
103
|
+
value.to_s
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
class PanHandler
|
2
|
+
class Source
|
3
|
+
def initialize(url_file_or_html)
|
4
|
+
@source = url_file_or_html
|
5
|
+
end
|
6
|
+
|
7
|
+
def url?
|
8
|
+
@source.is_a?(String) && @source.match(/\Ahttp/)
|
9
|
+
end
|
10
|
+
|
11
|
+
def file?
|
12
|
+
@source.kind_of?(File)
|
13
|
+
end
|
14
|
+
|
15
|
+
def html?
|
16
|
+
!(url? || file?)
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_s
|
20
|
+
file? ? @source.path : @source
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/lib/pan_handler.rb
ADDED
data/pan_handler.gemspec
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "pan_handler/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "pan_handler"
|
7
|
+
s.version = PanHandler::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Jon Doveston"]
|
10
|
+
s.email = ["jon@doveston.me.uk"]
|
11
|
+
s.homepage = ""
|
12
|
+
s.summary = "Pandoc wrapper"
|
13
|
+
s.description = "Uses Pandoc to convert html"
|
14
|
+
|
15
|
+
s.rubyforge_project = "pan_handler"
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
|
+
s.require_paths = ["lib"]
|
21
|
+
|
22
|
+
# Developmnet Dependencies
|
23
|
+
s.add_development_dependency "rspec", "~> 2.8.0"
|
24
|
+
s.add_development_dependency "guard"
|
25
|
+
s.add_development_dependency "guard-rspec"
|
26
|
+
s.add_development_dependency "rack-test", ">= 0.5.6"
|
27
|
+
s.add_development_dependency "activesupport", ">= 3.0.8"
|
28
|
+
|
29
|
+
end
|
data/rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
@@ -0,0 +1 @@
|
|
1
|
+
body { font-size: 20px; }
|
Binary file
|
@@ -0,0 +1,307 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
def app; Rack::Lint.new(@app); end
|
4
|
+
|
5
|
+
def mock_app(options = {}, conditions = {})
|
6
|
+
main_app = lambda { |env|
|
7
|
+
@env = env
|
8
|
+
headers = {'Content-Type' => "text/html"}
|
9
|
+
[200, headers, @body || ['Hello world!']]
|
10
|
+
}
|
11
|
+
|
12
|
+
builder = Rack::Builder.new
|
13
|
+
builder.use PanHandler::Middleware, options, conditions
|
14
|
+
builder.run main_app
|
15
|
+
@app = builder.to_app
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
describe PanHandler::Middleware do
|
20
|
+
|
21
|
+
describe "#call" do
|
22
|
+
describe "conditions" do
|
23
|
+
describe ":only" do
|
24
|
+
|
25
|
+
describe "regex" do
|
26
|
+
describe "one" do
|
27
|
+
before { mock_app({}, :only => %r[^/public]) }
|
28
|
+
|
29
|
+
context "matching" do
|
30
|
+
specify do
|
31
|
+
get 'http://www.example.org/public/test.odt'
|
32
|
+
last_response.headers["Content-Type"].should == "application/vnd.oasis.opendocument.text"
|
33
|
+
last_response.body.bytesize.should == PanHandler.new("Hello world!").to_odt.bytesize
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
context "not matching" do
|
38
|
+
specify do
|
39
|
+
get 'http://www.example.org/secret/test.odt'
|
40
|
+
last_response.headers["Content-Type"].should == "text/html"
|
41
|
+
last_response.body.should == "Hello world!"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end # one regex
|
45
|
+
|
46
|
+
describe "multiple" do
|
47
|
+
before { mock_app({}, :only => [%r[^/invoice], %r[^/public]]) }
|
48
|
+
|
49
|
+
context "matching" do
|
50
|
+
specify do
|
51
|
+
get 'http://www.example.org/public/test.odt'
|
52
|
+
last_response.headers["Content-Type"].should == "application/vnd.oasis.opendocument.text"
|
53
|
+
last_response.body.bytesize.should == PanHandler.new("Hello world!").to_odt.bytesize
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
context "not matching" do
|
58
|
+
specify do
|
59
|
+
get 'http://www.example.org/secret/test.odt'
|
60
|
+
last_response.headers["Content-Type"].should == "text/html"
|
61
|
+
last_response.body.should == "Hello world!"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end # multiple regex
|
65
|
+
end # regex
|
66
|
+
|
67
|
+
describe "string" do
|
68
|
+
describe "one" do
|
69
|
+
before { mock_app({}, :only => '/public') }
|
70
|
+
|
71
|
+
context "matching" do
|
72
|
+
specify do
|
73
|
+
get 'http://www.example.org/public/test.odt'
|
74
|
+
last_response.headers["Content-Type"].should == "application/vnd.oasis.opendocument.text"
|
75
|
+
last_response.body.bytesize.should == PanHandler.new("Hello world!").to_odt.bytesize
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
context "not matching" do
|
80
|
+
specify do
|
81
|
+
get 'http://www.example.org/secret/test.odt'
|
82
|
+
last_response.headers["Content-Type"].should == "text/html"
|
83
|
+
last_response.body.should == "Hello world!"
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end # one string
|
87
|
+
|
88
|
+
describe "multiple" do
|
89
|
+
before { mock_app({}, :only => ['/invoice', '/public']) }
|
90
|
+
|
91
|
+
context "matching" do
|
92
|
+
specify do
|
93
|
+
get 'http://www.example.org/public/test.odt'
|
94
|
+
last_response.headers["Content-Type"].should == "application/vnd.oasis.opendocument.text"
|
95
|
+
last_response.body.bytesize.should == PanHandler.new("Hello world!").to_odt.bytesize
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
context "not matching" do
|
100
|
+
specify do
|
101
|
+
get 'http://www.example.org/secret/test.odt'
|
102
|
+
last_response.headers["Content-Type"].should == "text/html"
|
103
|
+
last_response.body.should == "Hello world!"
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end # multiple string
|
107
|
+
end # string
|
108
|
+
|
109
|
+
end
|
110
|
+
|
111
|
+
describe ":except" do
|
112
|
+
|
113
|
+
describe "regex" do
|
114
|
+
describe "one" do
|
115
|
+
before { mock_app({}, :except => %r[^/secret]) }
|
116
|
+
|
117
|
+
context "matching" do
|
118
|
+
specify do
|
119
|
+
get 'http://www.example.org/public/test.odt'
|
120
|
+
last_response.headers["Content-Type"].should == "application/vnd.oasis.opendocument.text"
|
121
|
+
last_response.body.bytesize.should == PanHandler.new("Hello world!").to_odt.bytesize
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
context "not matching" do
|
126
|
+
specify do
|
127
|
+
get 'http://www.example.org/secret/test.odt'
|
128
|
+
last_response.headers["Content-Type"].should == "text/html"
|
129
|
+
last_response.body.should == "Hello world!"
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end # one regex
|
133
|
+
|
134
|
+
describe "multiple" do
|
135
|
+
before { mock_app({}, :except => [%r[^/prawn], %r[^/secret]]) }
|
136
|
+
|
137
|
+
context "matching" do
|
138
|
+
specify do
|
139
|
+
get 'http://www.example.org/public/test.odt'
|
140
|
+
last_response.headers["Content-Type"].should == "application/vnd.oasis.opendocument.text"
|
141
|
+
last_response.body.bytesize.should == PanHandler.new("Hello world!").to_odt.bytesize
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
context "not matching" do
|
146
|
+
specify do
|
147
|
+
get 'http://www.example.org/secret/test.odt'
|
148
|
+
last_response.headers["Content-Type"].should == "text/html"
|
149
|
+
last_response.body.should == "Hello world!"
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end # multiple regex
|
153
|
+
end # regex
|
154
|
+
|
155
|
+
describe "string" do
|
156
|
+
describe "one" do
|
157
|
+
before { mock_app({}, :except => '/secret') }
|
158
|
+
|
159
|
+
context "matching" do
|
160
|
+
specify do
|
161
|
+
get 'http://www.example.org/public/test.odt'
|
162
|
+
last_response.headers["Content-Type"].should == "application/vnd.oasis.opendocument.text"
|
163
|
+
last_response.body.bytesize.should == PanHandler.new("Hello world!").to_odt.bytesize
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
context "not matching" do
|
168
|
+
specify do
|
169
|
+
get 'http://www.example.org/secret/test.odt'
|
170
|
+
last_response.headers["Content-Type"].should == "text/html"
|
171
|
+
last_response.body.should == "Hello world!"
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end # one string
|
175
|
+
|
176
|
+
describe "multiple" do
|
177
|
+
before { mock_app({}, :except => ['/prawn', '/secret']) }
|
178
|
+
|
179
|
+
context "matching" do
|
180
|
+
specify do
|
181
|
+
get 'http://www.example.org/public/test.odt'
|
182
|
+
last_response.headers["Content-Type"].should == "application/vnd.oasis.opendocument.text"
|
183
|
+
last_response.body.bytesize.should == PanHandler.new("Hello world!").to_odt.bytesize
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
context "not matching" do
|
188
|
+
specify do
|
189
|
+
get 'http://www.example.org/secret/test.odt'
|
190
|
+
last_response.headers["Content-Type"].should == "text/html"
|
191
|
+
last_response.body.should == "Hello world!"
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end # multiple string
|
195
|
+
end # string
|
196
|
+
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
describe "remove .odt from PATH_INFO and REQUEST_URI" do
|
201
|
+
before { mock_app }
|
202
|
+
|
203
|
+
context "matching" do
|
204
|
+
specify do
|
205
|
+
get 'http://www.example.org/public/file.odt'
|
206
|
+
@env["PATH_INFO"].should == "/public/file"
|
207
|
+
@env["REQUEST_URI"].should == "/public/file"
|
208
|
+
end
|
209
|
+
specify do
|
210
|
+
get 'http://www.example.org/public/file.txt'
|
211
|
+
@env["PATH_INFO"].should == "/public/file.txt"
|
212
|
+
@env["REQUEST_URI"].should be_nil
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
describe "#translate_paths of absolute urls" do
|
220
|
+
before do
|
221
|
+
@odt = PanHandler::Middleware.new({})
|
222
|
+
@env = { 'REQUEST_URI' => 'http://example.com/document.odt', 'rack.url_scheme' => 'http', 'HTTP_HOST' => 'example.com' }
|
223
|
+
end
|
224
|
+
|
225
|
+
it "should correctly parse with single quotes" do
|
226
|
+
@body = %{<html><head><link href='http://example.com/stylesheets/application.css' media='screen' rel='stylesheet' type='text/css' /></head><body><img alt='test' src="HTTP://example.com/test.png" /></body></html>}
|
227
|
+
body = @odt.send :translate_paths, @body, @env
|
228
|
+
body.should == "<html><head><link media='screen' rel='stylesheet' type='text/css' /></head><body><img alt='test' /></body></html>"
|
229
|
+
end
|
230
|
+
|
231
|
+
it "should correctly parse with double quotes" do
|
232
|
+
@body = %{<link href="http://example.com/stylesheets/application.css" media="screen" rel="stylesheet" type="text/css" />}
|
233
|
+
body = @odt.send :translate_paths, @body, @env
|
234
|
+
body.should == "<link media=\"screen\" rel=\"stylesheet\" type=\"text/css\" />"
|
235
|
+
end
|
236
|
+
|
237
|
+
it "should return the body even if there are no valid substitutions found" do
|
238
|
+
@body = "NO MATCH"
|
239
|
+
body = @odt.send :translate_paths, @body, @env
|
240
|
+
body.should == "NO MATCH"
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
describe "#translate_paths of absolute files that do not exists" do
|
245
|
+
before do
|
246
|
+
@odt = PanHandler::Middleware.new({})
|
247
|
+
@env = { 'REQUEST_URI' => 'http://example.com/document.odt', 'rack.url_scheme' => 'http', 'HTTP_HOST' => 'example.com' }
|
248
|
+
end
|
249
|
+
|
250
|
+
it "should correctly parse relative url with single quotes" do
|
251
|
+
@body = %{<html><head><link href='/does_not_exist.css' media='screen' rel='stylesheet' type='text/css' /></head><body><img alt='test' src="/does_not_exist.png" /></body></html>}
|
252
|
+
body = @odt.send :translate_paths, @body, @env
|
253
|
+
body.should == "<html><head><link media='screen' rel='stylesheet' type='text/css' /></head><body><img alt='test' /></body></html>"
|
254
|
+
end
|
255
|
+
|
256
|
+
it "should correctly parse relative url with double quotes" do
|
257
|
+
@body = %{<link href="/does_not_exist.css" media="screen" rel="stylesheet" type="text/css" />}
|
258
|
+
body = @odt.send :translate_paths, @body, @env
|
259
|
+
body.should == "<link media=\"screen\" rel=\"stylesheet\" type=\"text/css\" />"
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
describe "#translate_paths with root_path configuration" do
|
264
|
+
before do
|
265
|
+
@odt = PanHandler::Middleware.new({})
|
266
|
+
@env = { 'REQUEST_URI' => 'http://example.com/document.odt', 'rack.url_scheme' => 'http', 'HTTP_HOST' => 'example.com' }
|
267
|
+
@root = File.dirname(__FILE__)
|
268
|
+
PanHandler.configure do |config|
|
269
|
+
config.root_path = @root
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
it "should add the root_path" do
|
274
|
+
@body = %{<html><head><link href='/fixtures/example.css' media='screen' rel='stylesheet' type='text/css' /></head><body><img alt='test' src="/fixtures/test.jpg" /></body></html>}
|
275
|
+
body = @odt.send :translate_paths, @body, @env
|
276
|
+
body.should == "<html><head><link href='#{@root}/fixtures/example.css' media='screen' rel='stylesheet' type='text/css' /></head><body><img alt='test' src=\"#{@root}/fixtures/test.jpg\" /></body></html>"
|
277
|
+
end
|
278
|
+
|
279
|
+
after do
|
280
|
+
PanHandler.configure do |config|
|
281
|
+
config.root_path = nil
|
282
|
+
end
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
286
|
+
describe "#translate_paths with relative files"
|
287
|
+
describe "#translate_paths with query strings"
|
288
|
+
|
289
|
+
it "should not get stuck rendering each request as odt" do
|
290
|
+
mock_app
|
291
|
+
# false by default. No requests.
|
292
|
+
@app.send(:rendering_odt?).should be_false
|
293
|
+
|
294
|
+
# Remain false on a normal request
|
295
|
+
get 'http://www.example.org/public/file'
|
296
|
+
@app.send(:rendering_odt?).should be_false
|
297
|
+
|
298
|
+
# Return true on a odt request.
|
299
|
+
get 'http://www.example.org/public/file.odt'
|
300
|
+
@app.send(:rendering_odt?).should be_true
|
301
|
+
|
302
|
+
# Restore to false on any non-odt request.
|
303
|
+
get 'http://www.example.org/public/file'
|
304
|
+
@app.send(:rendering_odt?).should be_false
|
305
|
+
end
|
306
|
+
|
307
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
#encoding: UTF-8
|
2
|
+
require 'spec_helper'
|
3
|
+
require 'tempfile'
|
4
|
+
|
5
|
+
describe PanHandler do
|
6
|
+
|
7
|
+
context "initialization" do
|
8
|
+
it "should accept HTML as the source" do
|
9
|
+
panhandler = PanHandler.new('<h1>Oh Hai</h1>')
|
10
|
+
panhandler.source.should be_html
|
11
|
+
panhandler.source.to_s.should == '<h1>Oh Hai</h1>'
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should accept a URL as the source" do
|
15
|
+
panhandler = PanHandler.new('http://google.com')
|
16
|
+
panhandler.source.should be_url
|
17
|
+
panhandler.source.to_s.should == 'http://google.com'
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should accept a File as the source" do
|
21
|
+
file_path = File.join('spec','fixtures','example.html')
|
22
|
+
panhandler = PanHandler.new(File.new(file_path))
|
23
|
+
panhandler.source.should be_file
|
24
|
+
panhandler.source.to_s.should == file_path
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should parse the options into a cmd line friendly format" do
|
28
|
+
panhandler = PanHandler.new('html', :reference_odt => 'reference')
|
29
|
+
panhandler.options.should have_key('--reference-odt')
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should provide default options" do
|
33
|
+
panhandler = PanHandler.new('<h1>Oh Hai</h1>')
|
34
|
+
['--from', '--to'].each do |option|
|
35
|
+
panhandler.options.should have_key(option)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
context "command" do
|
41
|
+
it "should contstruct the correct command" do
|
42
|
+
panhandler = PanHandler.new('html', :from => 'html', :to => 'odt', :reference_odt => 'reference')
|
43
|
+
panhandler.command[0].should include('pandoc')
|
44
|
+
panhandler.command[panhandler.command.index('"--from"') + 1].should == '"html"'
|
45
|
+
panhandler.command[panhandler.command.index('"--to"') + 1].should == '"odt"'
|
46
|
+
panhandler.command[panhandler.command.index('"--reference-odt"') + 1].should == '"reference"'
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should encapsulate string arguments in quotes" do
|
50
|
+
panhandler = PanHandler.new('html', :reference_odt => "i am a reference file.odt")
|
51
|
+
panhandler.command[panhandler.command.index('"--reference-odt"') + 1].should == '"i am a reference file.odt"'
|
52
|
+
end
|
53
|
+
|
54
|
+
it "read the source from stdin if it is html" do
|
55
|
+
panhandler = PanHandler.new('html')
|
56
|
+
panhandler.command[-1].should_not be == 'html'
|
57
|
+
end
|
58
|
+
|
59
|
+
it "specify the URL to the source if it is a url" do
|
60
|
+
panhandler = PanHandler.new('http://google.com')
|
61
|
+
panhandler.command[-1].should == '"http://google.com"'
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should specify the path to the source if it is a file" do
|
65
|
+
file_path = File.join('spec','fixtures','example.html')
|
66
|
+
panhandler = PanHandler.new(File.new(file_path))
|
67
|
+
panhandler.command[-1].should be == %Q{"#{file_path}"}
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should specify the path for the ouput if a path is given" do
|
71
|
+
file_path = "/path/to/output.odt"
|
72
|
+
panhandler = PanHandler.new("html")
|
73
|
+
panhandler.command(file_path)[-1].should be == %Q{"#{file_path}"}
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
context "#to_odt" do
|
78
|
+
|
79
|
+
before { @tempfile = Tempfile.new('panhandler') }
|
80
|
+
after { @tempfile.unlink if @tempfile }
|
81
|
+
|
82
|
+
[ PanHandler.new("<html><head></head><body>Hai!</body></html>"),
|
83
|
+
PanHandler.new('http://google.com'),
|
84
|
+
PanHandler.new(File.new(File.join('spec','fixtures','example.html')))
|
85
|
+
].each do |panhandler|
|
86
|
+
it "should generate an ODT of HTML" do
|
87
|
+
odt = panhandler.to_odt(@tempfile.path)
|
88
|
+
odt[0..1].should == "PK"
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
|
94
|
+
context "#to_file" do
|
95
|
+
|
96
|
+
before { @tempfile = Tempfile.new('panhandler') }
|
97
|
+
after { @tempfile.unlink if @tempfile }
|
98
|
+
|
99
|
+
[ PanHandler.new("<html><head></head><body>Hai!</body></html>"),
|
100
|
+
PanHandler.new('http://google.com'),
|
101
|
+
PanHandler.new(File.new(File.join('spec','fixtures','example.html')))
|
102
|
+
].each do |panhandler|
|
103
|
+
it "should generate an ODT of HTML" do
|
104
|
+
file = panhandler.to_file(@tempfile.path)
|
105
|
+
file.should be_instance_of(File)
|
106
|
+
File.exists?(file).should be_true
|
107
|
+
file.size.should be > 0
|
108
|
+
File.read(file)[0..1].should == "PK"
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
data/spec/source_spec.rb
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe PanHandler::Source do
|
4
|
+
|
5
|
+
describe "#url?" do
|
6
|
+
it "should return true if passed a url like string" do
|
7
|
+
source = PanHandler::Source.new('http://google.com')
|
8
|
+
source.should be_url
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should return false if passed a file" do
|
12
|
+
source = PanHandler::Source.new(File.new(__FILE__))
|
13
|
+
source.should_not be_url
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should return false if passed HTML" do
|
17
|
+
source = PanHandler::Source.new('<blink>Oh Hai!</blink>')
|
18
|
+
source.should_not be_url
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should return false if passed HTML with embedded urls at the beginning of a line" do
|
22
|
+
source = PanHandler::Source.new("<blink>Oh Hai!</blink>\nhttp://www.google.com")
|
23
|
+
source.should_not be_url
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "#file?" do
|
28
|
+
it "should return true if passed a file" do
|
29
|
+
source = PanHandler::Source.new(File.new(__FILE__))
|
30
|
+
source.should be_file
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should return false if passed a url like string" do
|
34
|
+
source = PanHandler::Source.new('http://google.com')
|
35
|
+
source.should_not be_file
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should return false if passed HTML" do
|
39
|
+
source = PanHandler::Source.new('<blink>Oh Hai!</blink>')
|
40
|
+
source.should_not be_file
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe "#html?" do
|
45
|
+
it "should return true if passed HTML" do
|
46
|
+
source = PanHandler::Source.new('<blink>Oh Hai!</blink>')
|
47
|
+
source.should be_html
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should return false if passed a file" do
|
51
|
+
source = PanHandler::Source.new(File.new(__FILE__))
|
52
|
+
source.should_not be_html
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should return false if passed a url like string" do
|
56
|
+
source = PanHandler::Source.new('http://google.com')
|
57
|
+
source.should_not be_html
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
describe "#to_s" do
|
62
|
+
it "should return the HTML if passed HTML" do
|
63
|
+
source = PanHandler::Source.new('<blink>Oh Hai!</blink>')
|
64
|
+
source.to_s.should == '<blink>Oh Hai!</blink>'
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should return a path if passed a file" do
|
68
|
+
source = PanHandler::Source.new(File.new(__FILE__))
|
69
|
+
source.to_s.should == __FILE__
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should return the url if passed a url like string" do
|
73
|
+
source = PanHandler::Source.new('http://google.com')
|
74
|
+
source.to_s.should == 'http://google.com'
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,121 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: pan_handler
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Jon Doveston
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-02-05 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rspec
|
16
|
+
requirement: &9643620 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 2.8.0
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *9643620
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: guard
|
27
|
+
requirement: &9642100 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :development
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *9642100
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: guard-rspec
|
38
|
+
requirement: &9674200 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
44
|
+
type: :development
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *9674200
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: rack-test
|
49
|
+
requirement: &9670460 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 0.5.6
|
55
|
+
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *9670460
|
58
|
+
- !ruby/object:Gem::Dependency
|
59
|
+
name: activesupport
|
60
|
+
requirement: &9685240 !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ! '>='
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: 3.0.8
|
66
|
+
type: :development
|
67
|
+
prerelease: false
|
68
|
+
version_requirements: *9685240
|
69
|
+
description: Uses Pandoc to convert html
|
70
|
+
email:
|
71
|
+
- jon@doveston.me.uk
|
72
|
+
executables: []
|
73
|
+
extensions: []
|
74
|
+
extra_rdoc_files: []
|
75
|
+
files:
|
76
|
+
- .gitignore
|
77
|
+
- Gemfile
|
78
|
+
- Guardfile
|
79
|
+
- LICENSE
|
80
|
+
- README.md
|
81
|
+
- Rakefile
|
82
|
+
- lib/pan_handler.rb
|
83
|
+
- lib/pan_handler/configuration.rb
|
84
|
+
- lib/pan_handler/middleware.rb
|
85
|
+
- lib/pan_handler/pan_handler.rb
|
86
|
+
- lib/pan_handler/source.rb
|
87
|
+
- lib/pan_handler/version.rb
|
88
|
+
- pan_handler.gemspec
|
89
|
+
- rspec
|
90
|
+
- spec/fixtures/example.css
|
91
|
+
- spec/fixtures/example.html
|
92
|
+
- spec/fixtures/test.jpg
|
93
|
+
- spec/middleware_spec.rb
|
94
|
+
- spec/pan_handler_spec.rb
|
95
|
+
- spec/source_spec.rb
|
96
|
+
- spec/spec_helper.rb
|
97
|
+
homepage: ''
|
98
|
+
licenses: []
|
99
|
+
post_install_message:
|
100
|
+
rdoc_options: []
|
101
|
+
require_paths:
|
102
|
+
- lib
|
103
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
104
|
+
none: false
|
105
|
+
requirements:
|
106
|
+
- - ! '>='
|
107
|
+
- !ruby/object:Gem::Version
|
108
|
+
version: '0'
|
109
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
110
|
+
none: false
|
111
|
+
requirements:
|
112
|
+
- - ! '>='
|
113
|
+
- !ruby/object:Gem::Version
|
114
|
+
version: '0'
|
115
|
+
requirements: []
|
116
|
+
rubyforge_project: pan_handler
|
117
|
+
rubygems_version: 1.8.15
|
118
|
+
signing_key:
|
119
|
+
specification_version: 3
|
120
|
+
summary: Pandoc wrapper
|
121
|
+
test_files: []
|