pdf_editor 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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 3b1b62c38f16c894a3346eb4a497c550164ccc26
4
+ data.tar.gz: 3645b303f8f571981dc741d8fab15fd1e0747a8c
5
+ SHA512:
6
+ metadata.gz: 3a5a99102a50b09523bb1af5165c705dd0c6e272b284a5c1494fa70f7d7a4dc0813304d1f889194b2efe65d3a97f4af0db0257052e39e9664609872af9f2310e
7
+ data.tar.gz: 42ac888243b6808e95617ee0e6e88e87097f5396d20ce54cc86472d4e8a9a981da1fb5aab45702a33c9a5af0d68b64e2ed574c3acddcfb343681ceaa0b7ef72f
data/.gitignore ADDED
@@ -0,0 +1,22 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format documentation
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
3
+
4
+ gem 'active_pdftk', git: 'git@github.com:tcocca/active_pdftk.git'
5
+
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 bradwheel
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,29 @@
1
+ # PdfEditor
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'pdf_editor'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install pdf_editor
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it ( https://github.com/[my-github-username]/pdf_editor/fork )
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require 'bundler/gem_tasks'
data/lib/pdf_editor.rb ADDED
@@ -0,0 +1,17 @@
1
+ require 'pdf_editor/version'
2
+ require 'pdf_editor/mixins/prawn_dsl'
3
+ require 'pdf_editor/mixins/errors'
4
+ require 'pdf_editor/mixins/pdf_runner'
5
+ require 'pdf_editor/mixins/service'
6
+ require 'pdf_editor/title_page'
7
+ require 'pdf_editor/table_of_contents'
8
+ require 'pdf_editor/shuffle'
9
+ require 'pdf_editor/rotate_page'
10
+ require 'pdf_editor/resource'
11
+ require 'pdf_editor/reorder'
12
+ require 'pdf_editor/remove_pages'
13
+ require 'pdf_editor/merge'
14
+ require 'pdf_editor/bundle'
15
+
16
+ module PdfEditor
17
+ end
@@ -0,0 +1,77 @@
1
+ require_relative 'title_page'
2
+ require_relative 'table_of_contents'
3
+ require_relative 'merge'
4
+ require_relative 'resource'
5
+ require_relative 'mixins/service'
6
+
7
+ module PdfEditor
8
+ class Bundle
9
+ include PdfEditor::Service
10
+
11
+ attr_reader :title, :resources, :with_toc, :with_title_pages
12
+
13
+ def post_init
14
+ @resources = args.fetch(:resources, [])
15
+ @ready_for_toc = []
16
+ @table_of_contents = nil
17
+
18
+ @title = args.fetch(:title, '')
19
+ @with_toc = args.fetch(:with_toc, true)
20
+ @with_title_pages = args.fetch(:with_title_pages, true)
21
+ end
22
+
23
+ def call
24
+ create_title_pages
25
+ create_table_of_contents
26
+ bundle_documents
27
+ end
28
+
29
+ private
30
+
31
+ attr_accessor :ready_for_toc, :table_of_contents
32
+
33
+ def bundle_documents
34
+ bundle_resources = ready_for_toc
35
+ bundle_resources.unshift(table_of_contents) if table_of_contents
36
+ PdfEditor::Merge.call({resources: bundle_resources})
37
+ end
38
+
39
+ def create_table_of_contents
40
+ return if ready_for_toc.empty?
41
+ return unless with_toc
42
+
43
+ self.table_of_contents = PdfEditor::TableOfContents.call({resources: ready_for_toc})
44
+ end
45
+
46
+ def create_title_pages
47
+ ready_for_toc.clear
48
+
49
+ if with_title_pages
50
+
51
+ resources.each do |resource|
52
+ new_resource = merge_resource_with_title_page(resource)
53
+ ready_for_toc << new_resource
54
+ end
55
+
56
+ else
57
+ self.ready_for_toc = resources.dup
58
+ end
59
+
60
+ ready_for_toc
61
+ end
62
+
63
+
64
+ def merge_resource_with_title_page(resource)
65
+ title_page_resource = create_title_page(resource)
66
+ PdfEditor::Merge.call({
67
+ resources: [title_page_resource, resource],
68
+ merged_name: title_page_resource.name
69
+ })
70
+ end
71
+
72
+ def create_title_page(resource)
73
+ PdfEditor::TitlePage.call({title: resource.name})
74
+ end
75
+
76
+ end
77
+ end
@@ -0,0 +1,47 @@
1
+ require_relative 'resource'
2
+ require_relative 'mixins/service'
3
+ require_relative 'mixins/pdf_runner'
4
+ require_relative 'mixins/errors'
5
+
6
+ module PdfEditor
7
+ class Merge
8
+ include PdfEditor::Service
9
+ include PdfEditor::PdfRunner
10
+ include PdfEditor::Errors
11
+
12
+ attr_reader :resources, :merged_name
13
+
14
+ def post_init
15
+ @resources = args.fetch(:resources, [])
16
+ @merged_name = args.fetch(:merged_name, nil)
17
+ end
18
+
19
+ def call
20
+ if resources.empty?
21
+ raise Errors::ResourcesEmptyError,
22
+ 'There must be at least one resource to merge'
23
+ end
24
+ PdfEditor::Resource.new(
25
+ create_tempfile {run_command},
26
+ merged_name
27
+ )
28
+ end
29
+
30
+ private
31
+
32
+ def run_command
33
+ read_from_io do
34
+ pdf_runner.cat(format_command)
35
+ end
36
+ rescue ::ActivePdftk::CommandError => e
37
+ raise InvalidInputError, e.message
38
+ end
39
+
40
+ def format_command
41
+ resources.map do |resource|
42
+ {:pdf => resource.path}
43
+ end
44
+ end
45
+
46
+ end
47
+ end
@@ -0,0 +1,14 @@
1
+ module PdfEditor
2
+ module Errors
3
+
4
+ InvalidPDFError = Class.new(StandardError)
5
+ InvalidInputError = Class.new(StandardError)
6
+ PageCountError = Class.new(StandardError)
7
+ PageRangeError = Class.new(StandardError)
8
+ TitlePageTitleError = Class.new(StandardError)
9
+ ResourcesEmptyError = Class.new(StandardError)
10
+ PageOrderInvalidError = Class.new(StandardError)
11
+ ArgumentMissingError = Class.new(StandardError)
12
+
13
+ end
14
+ end
@@ -0,0 +1,11 @@
1
+ require 'active_pdftk'
2
+
3
+ module PdfEditor
4
+ module PdfRunner
5
+
6
+ def pdf_runner
7
+ @pdf_runner ||= ::ActivePdftk::Wrapper.new
8
+ end
9
+
10
+ end
11
+ end
@@ -0,0 +1,31 @@
1
+ require 'prawn'
2
+
3
+ module PdfEditor
4
+ module PrawnDSL
5
+
6
+ def document
7
+ @document ||= Prawn::Document.new
8
+ end
9
+
10
+ def update_pdf(&b)
11
+ instance_eval(&b)
12
+ end
13
+
14
+ def to_pdf
15
+ document.render
16
+ end
17
+
18
+ def save_to_file(file_name)
19
+ document.render_file(file_name)
20
+ end
21
+
22
+ def respond_to_missing?(method_sym, include_private=false)
23
+ document.respond_to_missing?(method_sym, include_private) || super
24
+ end
25
+
26
+ def method_missing(method, *args, &b)
27
+ document.send(method, *args, &b)
28
+ end
29
+
30
+ end
31
+ end
@@ -0,0 +1,57 @@
1
+ require 'tempfile'
2
+
3
+ module PdfEditor
4
+ module Service
5
+
6
+ InterfaceNotImplementedError = Class.new(StandardError)
7
+ MustPassBlockToAsTempfile = Class.new(StandardError)
8
+
9
+ def self.included(klass)
10
+ klass.extend ClassMethods
11
+ end
12
+
13
+ def initialize(args={})
14
+ @args = args
15
+ post_init
16
+ end
17
+
18
+ # overwrite to use the args hash
19
+ def post_init
20
+ end
21
+
22
+ def call
23
+ raise InterfaceNotImplementedError, 'Service Interface requires call to be defined'
24
+ end
25
+
26
+ private def args
27
+ @args
28
+ end
29
+
30
+ private def create_tempfile
31
+ tempfile = ::Tempfile.open(['', '.pdf'])
32
+ begin
33
+ file_contents = yield tempfile.path
34
+ tempfile.write(file_contents)
35
+ ensure
36
+ tempfile.close
37
+ end
38
+ tempfile
39
+ end
40
+
41
+ private def read_from_io
42
+ io = yield
43
+ io.rewind
44
+ return io.read
45
+ end
46
+
47
+ module ClassMethods
48
+
49
+ def call(args={})
50
+ service = new(args)
51
+ service.call
52
+ end
53
+
54
+ end
55
+
56
+ end
57
+ end
@@ -0,0 +1,47 @@
1
+ require_relative 'shuffle'
2
+
3
+ module PdfEditor
4
+ class RemovePages < Shuffle
5
+
6
+ #
7
+ # Page order has a unique set of members and
8
+ # is sorted. This allows pdftk to not burst
9
+ # the document into single pages where possible.
10
+ #
11
+
12
+ def post_init
13
+ super
14
+ @page_order = @page_order.uniq.sort
15
+ end
16
+
17
+ private
18
+
19
+ def format_command
20
+ consecutive_pages = find_consecutives
21
+ consecutive_pages.map do |sub_arr|
22
+ {
23
+ :pdf => resource.path,
24
+ :start => sub_arr.first,
25
+ :end => sub_arr.last
26
+ }
27
+ end
28
+ end
29
+
30
+ def find_consecutives
31
+ enum = page_order.to_enum
32
+ result, consecutives = [], []
33
+
34
+ loop do
35
+ consecutives << enum.next
36
+ unless enum.peek == consecutives.last.succ
37
+ result << consecutives
38
+ consecutives = []
39
+ end
40
+ end
41
+
42
+ result << consecutives unless consecutives.empty?
43
+ result
44
+ end
45
+
46
+ end
47
+ end
@@ -0,0 +1,19 @@
1
+ require_relative 'shuffle'
2
+
3
+ module PdfEditor
4
+ class Reorder < Shuffle
5
+
6
+ #
7
+ # Page order requires a unique set of members
8
+ # and is not sorted.
9
+ #
10
+
11
+ def post_init
12
+ super
13
+ @page_order = @page_order.uniq
14
+ end
15
+
16
+ end
17
+
18
+
19
+ end
@@ -0,0 +1,59 @@
1
+ require 'pdf/reader'
2
+ require_relative 'mixins/errors'
3
+
4
+ module PdfEditor
5
+ class Resource
6
+ include PdfEditor::Errors
7
+
8
+ #
9
+ # Object that contains a tempfile and other pertinent
10
+ # info about that file, such as it's name and page count.
11
+ # All methods are delegated to file that aren't found in
12
+ # Resource.
13
+ #
14
+
15
+ attr_reader :file, :name
16
+
17
+ def initialize(file, name=nil)
18
+ @file = file
19
+ @name = name
20
+ end
21
+
22
+ def read(length=nil)
23
+ open_file do |f|
24
+ f.rewind
25
+ f.read(length)
26
+ end
27
+ end
28
+
29
+ def open_file
30
+ begin
31
+ file.open if file.closed?
32
+ yield file
33
+ ensure
34
+ file.close
35
+ end
36
+ end
37
+
38
+ def write(contents)
39
+ file.write(contents)
40
+ end
41
+
42
+ def page_count
43
+ open_file do |f|
44
+ ::PDF::Reader.new(f).page_count
45
+ end
46
+ rescue PDF::Reader::MalformedPDFError => e
47
+ raise Errors::InvalidPDFError, e.message
48
+ end
49
+
50
+ def respond_to_missing?(method_sym, include_private=false)
51
+ file.respond_to?(method_sym, include_private) || super
52
+ end
53
+
54
+ def method_missing(method, *args, &b)
55
+ file.send(method, *args, &b)
56
+ end
57
+
58
+ end
59
+ end