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 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: []