pan_handler 0.0.1
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/.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: []
|