pan_handler 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,8 @@
1
+ .DS_Store
2
+ *.sw?
3
+
4
+ *.gem
5
+ .bundle
6
+ Gemfile.lock
7
+ pkg/*
8
+ .rspec
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
data/Guardfile ADDED
@@ -0,0 +1,6 @@
1
+ guard 'rspec', :version => 2 do
2
+ watch(%r{^spec/.+_spec\.rb$})
3
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
4
+ watch('spec/spec_helper.rb') { "spec" }
5
+ end
6
+
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
@@ -0,0 +1,10 @@
1
+ # Pan Handler
2
+
3
+ HTML converter using pandoc. Initially only for ODT but in future releases will generalize
4
+ to any formats produced by pandoc.
5
+
6
+ Needs the pandoc executable.
7
+
8
+ # Credits
9
+
10
+ Blatanly ripped off PDFKit.
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
@@ -0,0 +1,3 @@
1
+ class PanHandler
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,4 @@
1
+ require 'pan_handler/source'
2
+ require 'pan_handler/pan_handler'
3
+ require 'pan_handler/middleware'
4
+ require 'pan_handler/configuration'
@@ -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; }
@@ -0,0 +1,5 @@
1
+ <html>
2
+ <body>
3
+ <h1>Oh Hai!</h1>
4
+ </body>
5
+ </html>
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
@@ -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
@@ -0,0 +1,9 @@
1
+ require 'bundler'
2
+ Bundler.require(:default, :development)
3
+
4
+ require 'rack'
5
+ require 'rack/test'
6
+
7
+ RSpec.configure do |config|
8
+ include Rack::Test::Methods
9
+ end
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: []