pdfh 3.1.0 → 3.3.0
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 +4 -4
- data/.gitignore +0 -1
- data/.pre-commit-config.yaml +36 -0
- data/.rubocop.yml +4 -3
- data/.rubocop_todo.yml +15 -36
- data/Gemfile.lock +81 -61
- data/README.md +56 -18
- data/bin/run +3 -1
- data/exe/pdfh +2 -16
- data/lib/pdfh/concerns/password_decodable.rb +31 -0
- data/lib/pdfh/main.rb +66 -16
- data/lib/pdfh/models/document.rb +12 -16
- data/lib/pdfh/models/document_sub_type.rb +1 -1
- data/lib/pdfh/models/document_type.rb +46 -28
- data/lib/pdfh/models/settings.rb +28 -4
- data/lib/pdfh/models/zip_types.rb +17 -0
- data/lib/pdfh/utils/console.rb +8 -0
- data/lib/pdfh/utils/dependency_validator.rb +35 -0
- data/lib/pdfh/utils/opt_parser.rb +61 -46
- data/lib/pdfh/utils/pdf_file_handler.rb +2 -1
- data/lib/pdfh/utils/settings_builder.rb +8 -3
- data/lib/pdfh/version.rb +1 -1
- data/lib/pdfh.rb +9 -1
- data/mise.toml +2 -0
- metadata +8 -7
- data/.tool-versions +0 -1
data/lib/pdfh/main.rb
CHANGED
@@ -4,13 +4,12 @@ module Pdfh
|
|
4
4
|
# Main functionality. This class is intended to manage the pdf documents
|
5
5
|
class Main
|
6
6
|
class << self
|
7
|
+
# @param argv [Array<String>]
|
7
8
|
# @return [void]
|
8
|
-
def start
|
9
|
-
arg_options = Pdfh::OptParser.parse_argv
|
9
|
+
def start(argv:)
|
10
|
+
arg_options = Pdfh::OptParser.new(argv: argv).parse_argv
|
10
11
|
@options = Options.new(arg_options)
|
11
|
-
|
12
|
-
Pdfh.instance_variable_set(:@options, options)
|
13
|
-
Pdfh.instance_variable_set(:@console, Console.new(options.verbose?))
|
12
|
+
assign_global_utils(@options)
|
14
13
|
Pdfh.print_options(arg_options)
|
15
14
|
|
16
15
|
@settings = SettingsBuilder.build
|
@@ -22,6 +21,7 @@ module Pdfh
|
|
22
21
|
Pdfh.create_settings_file
|
23
22
|
exit(1)
|
24
23
|
rescue StandardError => e
|
24
|
+
Pdfh.backtrace_print e if Pdfh.verbose?
|
25
25
|
Pdfh.error_print(e.message)
|
26
26
|
end
|
27
27
|
|
@@ -29,8 +29,15 @@ module Pdfh
|
|
29
29
|
|
30
30
|
attr_reader :options, :settings
|
31
31
|
|
32
|
+
# @param options [Options]
|
33
|
+
# @return [void]
|
34
|
+
def assign_global_utils(options)
|
35
|
+
Pdfh.instance_variable_set(:@options, options)
|
36
|
+
Pdfh.instance_variable_set(:@console, Console.new(options.verbose?))
|
37
|
+
end
|
38
|
+
|
32
39
|
# @param [String] file_name
|
33
|
-
# @return [DocumentType]
|
40
|
+
# @return [DocumentType, nil]
|
34
41
|
def match_doc_type(file_name)
|
35
42
|
settings.document_types.each do |type|
|
36
43
|
match = type.re_file.match(file_name)
|
@@ -63,31 +70,74 @@ module Pdfh
|
|
63
70
|
|
64
71
|
# @param [String] work_directory
|
65
72
|
# @return [void]
|
73
|
+
def process_zip_files(work_directory)
|
74
|
+
@settings.zip_types&.each do |zip_type|
|
75
|
+
find_files(work_directory, :zip).each do |file|
|
76
|
+
next unless zip_type.re_file.match?(File.basename(file))
|
77
|
+
|
78
|
+
Pdfh.info " > Processing zip file: #{file.green}"
|
79
|
+
password_opt = "-P #{zip_type.password}" if zip_type.password?
|
80
|
+
`unzip -o #{password_opt} #{file} -d #{work_directory}`
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# @param directory [String]
|
86
|
+
# @param type [String, Symbol]
|
87
|
+
# @return [Array<String>]
|
88
|
+
def find_files(directory, type)
|
89
|
+
glob = File.join(directory, "*.#{type}")
|
90
|
+
Dir.glob(glob)
|
91
|
+
end
|
92
|
+
|
66
93
|
def process_directory(work_directory)
|
67
94
|
Pdfh.headline(work_directory)
|
68
|
-
|
69
|
-
|
70
|
-
files =
|
95
|
+
process_zip_files(work_directory) if @settings.zip_types?
|
96
|
+
processed_result = RunResult.new
|
97
|
+
files = find_files(work_directory, :pdf)
|
71
98
|
files.each do |pdf_file|
|
72
99
|
type = match_doc_type(pdf_file)
|
73
100
|
if type
|
74
|
-
processed_count += 1
|
75
101
|
PdfFileHandler.new(pdf_file, type).process_document(settings.base_path)
|
102
|
+
processed_result.add_processed(pdf_file)
|
76
103
|
else
|
77
|
-
|
104
|
+
processed_result.add_ignored(pdf_file)
|
78
105
|
end
|
79
106
|
end
|
80
|
-
|
81
|
-
return unless Pdfh.verbose?
|
82
|
-
|
83
|
-
puts "\n No document type found for these PDF files:" if ignored_files.any?
|
84
|
-
ignored_files.each.with_index(1) { |file, index| Pdfh.ident_print index, file, color: :magenta }
|
107
|
+
print_processing_results(processed_result)
|
85
108
|
end
|
86
109
|
|
87
110
|
# @return [String]
|
88
111
|
def base_name_no_ext(file)
|
89
112
|
File.basename(file, File.extname(file))
|
90
113
|
end
|
114
|
+
|
115
|
+
def print_processing_results(result)
|
116
|
+
Pdfh.info " (No files processed)".colorize(:light_black) if result.processed.empty?
|
117
|
+
return unless Pdfh.verbose?
|
118
|
+
|
119
|
+
Pdfh.info "\n No document type found for these PDF files:" if result.ignored.any?
|
120
|
+
result.ignored.each.with_index(1) do |file, index|
|
121
|
+
Pdfh.ident_print index, base_name_no_ext(file), color: :magenta
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
# keeps track of the processed and ignored files
|
127
|
+
class RunResult
|
128
|
+
attr_reader :processed, :ignored
|
129
|
+
|
130
|
+
# @return [self]
|
131
|
+
def initialize
|
132
|
+
@processed = []
|
133
|
+
@ignored = []
|
134
|
+
end
|
135
|
+
|
136
|
+
# @return [void]
|
137
|
+
def add_ignored(file) = @ignored << file
|
138
|
+
|
139
|
+
# @return [void]
|
140
|
+
def add_processed(file) = @processed << file
|
91
141
|
end
|
92
142
|
end
|
93
143
|
end
|
data/lib/pdfh/models/document.rb
CHANGED
@@ -12,14 +12,18 @@ module Pdfh
|
|
12
12
|
def initialize(file, type, text)
|
13
13
|
@file = file
|
14
14
|
@type = type
|
15
|
-
Pdfh.debug "=== Document Type: #{type.name} =============================="
|
16
15
|
@text = text
|
16
|
+
end
|
17
|
+
|
18
|
+
# @return [void]
|
19
|
+
def process
|
20
|
+
Pdfh.debug "=== Document Type: #{type.name} =============================="
|
17
21
|
Pdfh.debug "~~~~~~~~~~~~~~~~~~ Finding a subtype"
|
18
22
|
@sub_type = type.sub_type(@text)
|
19
23
|
Pdfh.debug " SubType: #{@sub_type}"
|
20
24
|
@companion = search_companion_files
|
21
25
|
|
22
|
-
month, year, @extra =
|
26
|
+
month, year, @extra = match_date(@sub_type&.re_date || @type.re_date)
|
23
27
|
@period = DocumentPeriod.new(day: extra, month: month, month_offset: @sub_type&.month_offset, year: year)
|
24
28
|
Pdfh.debug " Period: #{@period.inspect}"
|
25
29
|
end
|
@@ -32,7 +36,6 @@ module Pdfh
|
|
32
36
|
print_info_line "New Name", new_name
|
33
37
|
print_info_line "Store Path", store_path
|
34
38
|
print_info_line "Extra files", companion_files(join: true)
|
35
|
-
print_info_line "Print CMD", print_cmd
|
36
39
|
print_info_line "Processed?", "No (in Dry mode)" if Pdfh.dry?
|
37
40
|
end
|
38
41
|
|
@@ -95,14 +98,6 @@ module Pdfh
|
|
95
98
|
type.generate_path(rename_data)
|
96
99
|
end
|
97
100
|
|
98
|
-
# @return [String]
|
99
|
-
def print_cmd
|
100
|
-
return "N/A" if type.print_cmd.nil? || type.print_cmd.empty?
|
101
|
-
|
102
|
-
relative_path = File.join(store_path, new_name)
|
103
|
-
"#{type.print_cmd} #{relative_path}"
|
104
|
-
end
|
105
|
-
|
106
101
|
# @return [String (frozen)]
|
107
102
|
def companion_files(join: false)
|
108
103
|
return @companion unless join
|
@@ -125,16 +120,17 @@ module Pdfh
|
|
125
120
|
# named matches can appear in any order with names 'd', 'm' and 'y'
|
126
121
|
# unnamed matches needs to be in order month, year
|
127
122
|
# @return [Array] - format [month, year, day]
|
128
|
-
|
123
|
+
# @param regex [RegularExpression]
|
124
|
+
def match_date(regex)
|
129
125
|
Pdfh.debug "~~~~~~~~~~~~~~~~~~ Match Data RegEx"
|
130
|
-
Pdfh.debug " Using regex: #{
|
131
|
-
Pdfh.debug " named: #{
|
132
|
-
matched =
|
126
|
+
Pdfh.debug " Using regex: #{regex}"
|
127
|
+
Pdfh.debug " named: #{regex.named_captures}"
|
128
|
+
matched = regex.match(@text)
|
133
129
|
raise ReDateError unless matched
|
134
130
|
|
135
131
|
Pdfh.debug " captured: #{matched.captures}"
|
136
132
|
|
137
|
-
return matched.captures.map(&:downcase) if
|
133
|
+
return matched.captures.map(&:downcase) if regex.named_captures.empty?
|
138
134
|
|
139
135
|
extra = matched.captures.size > 2 ? matched[:d] : nil
|
140
136
|
[matched[:m].downcase, matched[:y], extra]
|
@@ -2,5 +2,5 @@
|
|
2
2
|
|
3
3
|
module Pdfh
|
4
4
|
# Provides a way to divide document type by subtypes, for different name, and month adjustments
|
5
|
-
DocumentSubType = Struct.new(:name, :month_offset, keyword_init: true)
|
5
|
+
DocumentSubType = Struct.new(:name, :month_offset, :re_date, keyword_init: true)
|
6
6
|
end
|
@@ -2,15 +2,33 @@
|
|
2
2
|
|
3
3
|
module Pdfh
|
4
4
|
# Represents a type of document that can be processed by pdfh
|
5
|
-
DocumentType
|
6
|
-
|
5
|
+
class DocumentType
|
6
|
+
include Concerns::PasswordDecodable
|
7
|
+
|
8
|
+
# @!attribute [r] name
|
9
|
+
# @return [String] The name of the document type.
|
10
|
+
# @!attribute [r] re_file
|
11
|
+
# @return [Regexp] The regular expression to match file names.
|
12
|
+
# @!attribute [r] re_date
|
13
|
+
# @return [Regexp] The regular expression to extract dates and its information.
|
14
|
+
# @!attribute [r] pwd
|
15
|
+
# @return [String, nil] The base64 password for the document type, if any.
|
16
|
+
# @!attribute [r] store_path
|
17
|
+
# @return [String] The path where the document will be stored.
|
18
|
+
# @!attribute [r] name_template
|
19
|
+
# @return [String] The template for generating document names.
|
20
|
+
# @!attribute [r] sub_types
|
21
|
+
# @return [Array<DocumentSubType>, nil] The subtypes of the document, if any.
|
22
|
+
attr_reader :name, :re_file, :re_date, :pwd, :store_path, :name_template, :sub_types
|
23
|
+
|
24
|
+
# @param args [Hash]
|
7
25
|
# @return [self]
|
8
26
|
def initialize(args)
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
27
|
+
args.each { |k, v| instance_variable_set(:"@#{k}", v) }
|
28
|
+
@name_template ||= "{original}"
|
29
|
+
@re_file = Regexp.new(re_file)
|
30
|
+
@re_date = Regexp.new(re_date)
|
31
|
+
@sub_types = extract_subtypes(sub_types) if sub_types&.any?
|
14
32
|
@path_validator = RenameValidator.new(store_path)
|
15
33
|
@name_validator = RenameValidator.new(name_template)
|
16
34
|
return if @path_validator.valid? && @name_validator.valid?
|
@@ -18,6 +36,11 @@ module Pdfh
|
|
18
36
|
raise_validators_error
|
19
37
|
end
|
20
38
|
|
39
|
+
# @return [Hash{Symbol->any}]
|
40
|
+
def to_h
|
41
|
+
instance_variables.to_h { |var| [var.to_s.delete_prefix("@"), instance_variable_get(var)] }
|
42
|
+
end
|
43
|
+
|
21
44
|
# removes special characters from string and replaces spaces with dashes
|
22
45
|
# @example usage
|
23
46
|
# "Test This?%&".gid
|
@@ -27,19 +50,13 @@ module Pdfh
|
|
27
50
|
name.downcase.gsub(/[^0-9A-Za-z\s]/, "").tr(" ", "-")
|
28
51
|
end
|
29
52
|
|
53
|
+
# search the subtype name in the pdf document
|
30
54
|
# @return [DocumentSubType]
|
31
55
|
def sub_type(text)
|
32
56
|
# Regexp.new(st.name).match?(name)
|
33
57
|
sub_types&.find { |st| /#{st.name}/i.match?(text) }
|
34
58
|
end
|
35
59
|
|
36
|
-
# @return [String]
|
37
|
-
def password
|
38
|
-
return Base64.decode64(pwd) if base64?
|
39
|
-
|
40
|
-
pwd
|
41
|
-
end
|
42
|
-
|
43
60
|
# @param values [Hash{Symbol->String}
|
44
61
|
# @return [String]
|
45
62
|
def generate_new_name(values)
|
@@ -54,28 +71,29 @@ module Pdfh
|
|
54
71
|
|
55
72
|
private
|
56
73
|
|
57
|
-
|
58
|
-
def base64?
|
59
|
-
pwd.is_a?(String) && Base64.strict_encode64(Base64.decode64(pwd)) == pwd
|
60
|
-
end
|
74
|
+
attr_accessor :path_validator, :name_validator
|
61
75
|
|
62
|
-
# @param sub_types [Array]
|
63
|
-
# @return [DocumentSubType]
|
64
|
-
def
|
76
|
+
# @param sub_types [Array<Hash{Symbol->String}>]
|
77
|
+
# @return [Array<DocumentSubType>]
|
78
|
+
def extract_subtypes(sub_types)
|
65
79
|
sub_types.map do |st|
|
66
|
-
|
67
|
-
|
68
|
-
|
80
|
+
data = {
|
81
|
+
name: st[:name],
|
82
|
+
month_offset: st[:month_offset].to_i,
|
83
|
+
re_date: st[:re_date] && Regexp.new(st[:re_date])
|
84
|
+
}.compact
|
85
|
+
DocumentSubType.new(data)
|
69
86
|
end
|
70
87
|
end
|
71
88
|
|
72
89
|
# @raise [ArgumentError] when called
|
73
90
|
# @return [void]
|
74
91
|
def raise_validators_error
|
75
|
-
template = "has invalid %<
|
76
|
-
|
77
|
-
|
78
|
-
|
92
|
+
template = "has invalid %<field>s[Unknown tokens=%<error>s]"
|
93
|
+
errors = []
|
94
|
+
errors << format(template, field: :store_path, error: path_validator.unknown_list) unless path_validator.valid?
|
95
|
+
errors << format(template, field: :name_template, error: name_validator.unknown_list) unless name_validator.valid?
|
96
|
+
raise ArgumentError, "Document type #{name.inspect} #{errors.join(", ")}"
|
79
97
|
end
|
80
98
|
end
|
81
99
|
end
|
data/lib/pdfh/models/settings.rb
CHANGED
@@ -3,7 +3,13 @@
|
|
3
3
|
module Pdfh
|
4
4
|
# Handles the config yaml data mapping, and associates a file name with a doc type
|
5
5
|
class Settings
|
6
|
-
|
6
|
+
# @!attribute [r] lookup_dirs
|
7
|
+
# @return [Array<String>] List of directories to look up for processing.
|
8
|
+
# @!attribute [r] base_path
|
9
|
+
# @return [String] The base directory path for storing processed files.
|
10
|
+
# @!attribute [r] zip_types
|
11
|
+
# @return [Array<ZipType>, nil] List of zip types to process, or nil if none.
|
12
|
+
attr_reader :lookup_dirs, :base_path, :zip_types
|
7
13
|
|
8
14
|
# @param config_data [Hash]
|
9
15
|
# @return [self]
|
@@ -15,7 +21,8 @@ module Pdfh
|
|
15
21
|
lookup_dirs.each.with_index(1) { |dir, idx| Pdfh.debug " #{idx}. #{dir}" }
|
16
22
|
Pdfh.debug
|
17
23
|
|
18
|
-
|
24
|
+
build_doc_types(config_data[:document_types])
|
25
|
+
build_zip_types(config_data[:zip_types]) if config_data.key?(:zip_types)
|
19
26
|
end
|
20
27
|
|
21
28
|
# @return [Array<DocumentType>]
|
@@ -28,8 +35,14 @@ module Pdfh
|
|
28
35
|
@document_types[id]
|
29
36
|
end
|
30
37
|
|
38
|
+
# @return [Boolean]
|
39
|
+
def zip_types?
|
40
|
+
!!zip_types&.any?
|
41
|
+
end
|
42
|
+
|
31
43
|
private
|
32
44
|
|
45
|
+
# @param lookup_dirs_list [Array[String]]
|
33
46
|
# @return [void]
|
34
47
|
def process_lookup_dirs(lookup_dirs_list)
|
35
48
|
@lookup_dirs = lookup_dirs_list.filter_map do |dir|
|
@@ -44,20 +57,31 @@ module Pdfh
|
|
44
57
|
end
|
45
58
|
|
46
59
|
# @return [void]
|
60
|
+
# @param dir [String]
|
47
61
|
def process_destination_base(dir)
|
48
62
|
@base_path = File.expand_path(dir)
|
49
63
|
raise ArgumentError, "Destination base directory is not configured." if @base_path.nil?
|
50
64
|
raise ArgumentError, "Destination base directory #{@base_path} does not exist." unless File.directory?(@base_path)
|
51
65
|
end
|
52
66
|
|
53
|
-
# @
|
54
|
-
|
67
|
+
# @param doc_types [Array<Hash>]
|
68
|
+
# @return [void]
|
69
|
+
def build_doc_types(doc_types)
|
55
70
|
@document_types = doc_types.each_with_object({}) do |data, result|
|
56
71
|
doc_type = DocumentType.new(data)
|
57
72
|
result.store(doc_type.gid, doc_type)
|
58
73
|
rescue ArgumentError => e
|
59
74
|
Pdfh.error_print e.message, exit_app: false
|
75
|
+
Pdfh.backtrace_print e if Pdfh.verbose?
|
60
76
|
end
|
61
77
|
end
|
78
|
+
|
79
|
+
# @param zip_types [Array<Hash>]
|
80
|
+
# @return [void]
|
81
|
+
def build_zip_types(zip_types)
|
82
|
+
exit(1) if Pdfh::Utils::DependencyValidator.missing?(:unzip)
|
83
|
+
|
84
|
+
@zip_types = zip_types.compact.map { ZipType.new(_1) }
|
85
|
+
end
|
62
86
|
end
|
63
87
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Pdfh
|
4
|
+
# Zip files which contains PDF files that need pre-processing
|
5
|
+
class ZipType
|
6
|
+
include Concerns::PasswordDecodable
|
7
|
+
|
8
|
+
attr_reader :name, :re_file, :pwd
|
9
|
+
|
10
|
+
# @param args [Hash]
|
11
|
+
# @return [self]
|
12
|
+
def initialize(args)
|
13
|
+
args.each { |k, v| instance_variable_set(:"@#{k}", v) }
|
14
|
+
@re_file = Regexp.new(re_file)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/lib/pdfh/utils/console.rb
CHANGED
@@ -41,6 +41,14 @@ module Pdfh
|
|
41
41
|
exit 1 if exit_app
|
42
42
|
end
|
43
43
|
|
44
|
+
# @param e [StandardError]
|
45
|
+
# @return [void]
|
46
|
+
def backtrace_print(e)
|
47
|
+
e.backtrace&.each do |line|
|
48
|
+
output " ↳ #{line.sub("#{Dir.pwd}/", "")}".colorize(:light_black)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
44
52
|
# @param message [String]
|
45
53
|
# @return [void]
|
46
54
|
def warn_print(message)
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "open3"
|
4
|
+
|
5
|
+
module Pdfh
|
6
|
+
module Utils
|
7
|
+
# Provides methods to validate external dependencies
|
8
|
+
module DependencyValidator
|
9
|
+
module_function
|
10
|
+
|
11
|
+
# Validates if the required command-line applications are installed
|
12
|
+
# @param apps [Array<String>] names of required command-line applications
|
13
|
+
# @return [Boolean] true if all applications are installed, false otherwise
|
14
|
+
def installed?(*apps)
|
15
|
+
missing = apps.filter_map do |app|
|
16
|
+
_stdout, _stderr, status = Open3.capture3("which #{app}")
|
17
|
+
|
18
|
+
app.to_s unless status.success?
|
19
|
+
end
|
20
|
+
|
21
|
+
if missing.any?
|
22
|
+
errors = missing.map(&:red)
|
23
|
+
puts "Required dependency #{errors.join(", ")} not found. Please install it before continuing."
|
24
|
+
end
|
25
|
+
missing.empty?
|
26
|
+
end
|
27
|
+
|
28
|
+
# @param apps [Array<String>]
|
29
|
+
# @return [Boolean] true if any application is missing, false if all are installed
|
30
|
+
def missing?(*apps)
|
31
|
+
!installed?(*apps)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -5,58 +5,73 @@ require "optparse"
|
|
5
5
|
module Pdfh
|
6
6
|
# Handles Argument options
|
7
7
|
class OptParser
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
opts.on("-v", "--verbose", "Show more output. Useful for debug")
|
21
|
-
opts.on("-d", "--dry", "Dry run, does not write new pdf")
|
8
|
+
# @param argv [Array<String>] command line arguments (ie. ARGV)
|
9
|
+
# @param console [Pdfh::Console, nil]
|
10
|
+
# @return [self]
|
11
|
+
def initialize(argv:, console: nil)
|
12
|
+
@argv = argv
|
13
|
+
@console = console || Console.new(false)
|
14
|
+
@options = {
|
15
|
+
verbose: false,
|
16
|
+
dry: false,
|
17
|
+
type: nil,
|
18
|
+
files: []
|
19
|
+
}
|
22
20
|
end
|
23
21
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
puts OPT_PARSER.help
|
36
|
-
exit 1
|
37
|
-
end
|
22
|
+
# @return [Hash] Parsed options including flags and file arguments
|
23
|
+
def parse_argv
|
24
|
+
option_parser = build_option_parser
|
25
|
+
non_option_args = option_parser.parse!(@argv)
|
26
|
+
@options[:files] = non_option_args
|
27
|
+
@options.transform_keys { |key| key.to_s.tr("-", "_").to_sym }
|
28
|
+
rescue OptionParser::InvalidOption => e
|
29
|
+
@console.error_print(e.message, exit_app: false)
|
30
|
+
puts option_parser.help
|
31
|
+
exit 1
|
32
|
+
end
|
38
33
|
|
39
|
-
|
40
|
-
def version
|
41
|
-
puts "#{OPT_PARSER.program_name} v#{Pdfh::VERSION}"
|
42
|
-
end
|
34
|
+
private
|
43
35
|
|
44
|
-
|
45
|
-
|
46
|
-
|
36
|
+
# @return [OptionParser] Configured OptionParser instance
|
37
|
+
def build_option_parser
|
38
|
+
OptionParser.new do |opts|
|
39
|
+
opts.banner = "Usage: #{opts.program_name} [options] [file1.pdf, ...]"
|
40
|
+
opts.separator ""
|
41
|
+
opts.separator "Specific options:"
|
42
|
+
|
43
|
+
opts.on("-tID", "--type=ID", "Document type id (requires a trailing file list)") { @options[:type] = _1 }
|
44
|
+
opts.on("-v", "--verbose", "Show more output. Useful for debug") { @options[:verbose] = true }
|
45
|
+
opts.on("-d", "--dry", "Dry run, does not write new pdf") { @options[:dry] = true }
|
46
|
+
opts.on_tail("-T", "--list-types", "List document types in configuration") { list_types && exit }
|
47
|
+
opts.on_tail("-V", "--version", "Show version") { version || exit }
|
48
|
+
opts.on_tail("-h", "--help", "help (this dialog)") { help || exit }
|
47
49
|
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# @return [nil]
|
53
|
+
def version
|
54
|
+
@console.info "#{build_option_parser.program_name} v#{Pdfh::VERSION}"
|
55
|
+
end
|
56
|
+
|
57
|
+
# @return [nil]
|
58
|
+
def help
|
59
|
+
@console.info build_option_parser
|
60
|
+
end
|
61
|
+
|
62
|
+
# Lists the available document types
|
63
|
+
# @return [nil]
|
64
|
+
def list_types
|
65
|
+
Pdfh.instance_variable_set(:@options, Options.new(@options))
|
66
|
+
Pdfh.instance_variable_set(:@console, @console)
|
48
67
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
settings.document_types.each do |type|
|
57
|
-
puts "#{" " * ident}#{type.gid.ljust(max_width).yellow} #{type.name}"
|
58
|
-
end
|
59
|
-
nil
|
68
|
+
settings = SettingsBuilder.build
|
69
|
+
spacing = " " * 2
|
70
|
+
max_width = settings.document_types.map { |t| t.gid.size }.max
|
71
|
+
@console.info "#{spacing}#{"ID".ljust(max_width)} Type Name"
|
72
|
+
@console.info "#{spacing}#{"—" * max_width} #{"—" * 23}"
|
73
|
+
settings.document_types.each do |type|
|
74
|
+
@console.info "#{spacing}#{type.gid.ljust(max_width).yellow} #{type.name}"
|
60
75
|
end
|
61
76
|
end
|
62
77
|
end
|
@@ -25,6 +25,7 @@ module Pdfh
|
|
25
25
|
raise IOError, "File #{file} not found" unless File.exist?(file)
|
26
26
|
|
27
27
|
@document = Document.new(file, type, extract_text)
|
28
|
+
document.process
|
28
29
|
document.print_info
|
29
30
|
write_pdf(base_path)
|
30
31
|
|
@@ -86,7 +87,7 @@ module Pdfh
|
|
86
87
|
end
|
87
88
|
|
88
89
|
# Gets the text from the pdf in order to execute
|
89
|
-
# the regular
|
90
|
+
# the regular expression matches
|
90
91
|
# @return [String]
|
91
92
|
def extract_text
|
92
93
|
temp = Tempfile.new("pdfh")
|
@@ -3,13 +3,17 @@
|
|
3
3
|
module Pdfh
|
4
4
|
# Loads or creates a default settings yaml file
|
5
5
|
class SettingsBuilder
|
6
|
-
CONFIG_FILE_LOCATIONS = [Dir.pwd,
|
6
|
+
CONFIG_FILE_LOCATIONS = [Dir.pwd, ENV.fetch("XDG_CONFIG_HOME", "~/.config"), "~"].freeze
|
7
7
|
SUPPORTED_EXTENSIONS = %w[yml yaml].freeze
|
8
|
+
ENV_VAR = "PDFH_CONFIG_FILE"
|
8
9
|
|
9
10
|
class << self
|
10
11
|
# @return [Pdfh::Settings]
|
11
12
|
def build
|
12
|
-
|
13
|
+
env_config_file = ENV.fetch(ENV_VAR, nil)
|
14
|
+
raise "File path in #{ENV_VAR} not found" if env_config_file && !File.exist?(env_config_file)
|
15
|
+
|
16
|
+
config_file = env_config_file || search_config_file
|
13
17
|
file_hash = YAML.load_file(config_file, symbolize_names: true)
|
14
18
|
Pdfh.debug "Loaded configuration file: #{config_file}"
|
15
19
|
|
@@ -42,7 +46,8 @@ module Pdfh
|
|
42
46
|
# Gets the first settings file found, or creates a new one
|
43
47
|
# @return [String]
|
44
48
|
def search_config_file
|
45
|
-
CONFIG_FILE_LOCATIONS.each do |
|
49
|
+
CONFIG_FILE_LOCATIONS.each do |dir_string|
|
50
|
+
dir = File.expand_path(dir_string)
|
46
51
|
SUPPORTED_EXTENSIONS.each do |ext|
|
47
52
|
path = File.join(dir, "#{config_file_name}.#{ext}")
|
48
53
|
return path if File.exist?(path)
|
data/lib/pdfh/version.rb
CHANGED