rock_books 0.7.0 → 0.11.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/{manual.md → MANUAL.md} +26 -26
- data/README.md +20 -12
- data/RELEASE_NOTES.md +55 -10
- data/REPORTS.md +81 -0
- data/assets/doc-images/sample-index-html.png +0 -0
- data/lib/rock_books/cmd_line/command_line_interface.rb +12 -21
- data/lib/rock_books/documents/book_set.rb +4 -1
- data/lib/rock_books/documents/journal.rb +2 -3
- data/lib/rock_books/reports/balance_sheet.rb +2 -2
- data/lib/rock_books/reports/book_set_reporter.rb +69 -55
- data/lib/rock_books/reports/data/bs_is_section_data.rb +3 -1
- data/lib/rock_books/reports/data/journal_data.rb +1 -0
- data/lib/rock_books/reports/data/multidoc_txn_by_account_data.rb +1 -1
- data/lib/rock_books/reports/data/tx_one_account_data.rb +1 -1
- data/lib/rock_books/reports/helpers/erb_helper.rb +1 -6
- data/lib/rock_books/reports/helpers/receipts_hyperlink_converter.rb +59 -0
- data/lib/rock_books/reports/helpers/{reporter.rb → text_report_helper.rb} +11 -1
- data/lib/rock_books/reports/income_statement.rb +2 -2
- data/lib/rock_books/reports/index_html_page.rb +27 -0
- data/lib/rock_books/reports/journal_report.rb +18 -8
- data/lib/rock_books/reports/multidoc_txn_by_account_report.rb +2 -2
- data/lib/rock_books/reports/multidoc_txn_report.rb +2 -2
- data/lib/rock_books/reports/receipts_report.rb +1 -1
- data/lib/rock_books/reports/templates/html/index.html.erb +45 -6
- data/lib/rock_books/reports/templates/html/report_page.html.erb +14 -1
- data/lib/rock_books/reports/templates/text/balance_sheet.txt.erb +2 -0
- data/lib/rock_books/reports/templates/text/income_statement.txt.erb +3 -1
- data/lib/rock_books/reports/templates/text/journal.txt.erb +5 -2
- data/lib/rock_books/reports/templates/text/multidoc_txn_by_account_report.txt.erb +3 -0
- data/lib/rock_books/reports/templates/text/multidoc_txn_report.txt.erb +3 -0
- data/lib/rock_books/reports/templates/text/receipts_report.txt.erb +3 -0
- data/lib/rock_books/reports/templates/text/tx_one_account.txt.erb +3 -0
- data/lib/rock_books/reports/tx_one_account.rb +2 -2
- data/lib/rock_books/version.rb +2 -1
- data/rock_books.gemspec +1 -0
- metadata +22 -5
- data/lib/rock_books/helpers/html_helper.rb +0 -35
@@ -4,7 +4,8 @@ require 'ostruct'
|
|
4
4
|
|
5
5
|
require_relative '../../rock_books'
|
6
6
|
require_relative '../version'
|
7
|
-
require_relative '../reports/
|
7
|
+
require_relative '../reports/data/receipts_report_data'
|
8
|
+
require_relative '../reports/helpers/text_report_helper'
|
8
9
|
require_relative '../helpers/book_set_loader'
|
9
10
|
|
10
11
|
module RockBooks
|
@@ -51,12 +52,11 @@ Commands:
|
|
51
52
|
|
52
53
|
rec[eipts] - receipts: a/:a all, m/:m missing, e/:e existing, u/:u unused
|
53
54
|
rep[orts] - return an OpenStruct containing all reports (interactive shell mode only)
|
54
|
-
d[isplay_reports] - display all reports on stdout
|
55
55
|
w[rite_reports] - write all reports to the output directory (see -o option)
|
56
56
|
c[hart_of_accounts] - chart of accounts
|
57
57
|
h[elp] - prints this help
|
58
58
|
jo[urnals] - list of the journals' short names
|
59
|
-
proj[ect_page] -
|
59
|
+
proj[ect_page] - prints the RockBooks Github project page URL
|
60
60
|
rel[oad_data] - reload data from input files
|
61
61
|
q[uit] - exits this program (interactive shell mode only) (see also 'x')
|
62
62
|
x[it] - exits this program (interactive shell mode only) (see also 'q')
|
@@ -281,7 +281,7 @@ When in interactive shell mode:
|
|
281
281
|
# All reports as Ruby objects; only makes sense in shell mode.
|
282
282
|
def cmd_rep
|
283
283
|
unless run_options.interactive_mode
|
284
|
-
raise Error.new("Option 'all_reports' is only available in shell mode. Try '
|
284
|
+
raise Error.new("Option 'all_reports' is only available in shell mode. Try 'write_reports'.")
|
285
285
|
end
|
286
286
|
|
287
287
|
os = OpenStruct.new(book_set.all_reports($filter))
|
@@ -297,18 +297,8 @@ When in interactive shell mode:
|
|
297
297
|
end
|
298
298
|
|
299
299
|
|
300
|
-
def cmd_d
|
301
|
-
book_set.all_reports($filter).each do |short_name, text_report|
|
302
|
-
puts "#{short_name}:\n\n"
|
303
|
-
puts text_report
|
304
|
-
puts "\n\n\n"
|
305
|
-
end
|
306
|
-
nil
|
307
|
-
end
|
308
|
-
|
309
|
-
|
310
300
|
def cmd_proj
|
311
|
-
|
301
|
+
puts 'https://github.com/keithrbennett/rock_books'
|
312
302
|
end
|
313
303
|
|
314
304
|
|
@@ -317,7 +307,9 @@ When in interactive shell mode:
|
|
317
307
|
raise Error.new("Receipt processing was requested but has been disabled with --no-receipts.")
|
318
308
|
end
|
319
309
|
|
320
|
-
|
310
|
+
data = ReceiptsReportData.new(all_entries, run_options.receipt_dir).fetch
|
311
|
+
|
312
|
+
missing, existing, unused = data[:missing], data[:existing], data[:unused]
|
321
313
|
|
322
314
|
print_missing = -> { puts "\n\nMissing Receipts:"; ap missing }
|
323
315
|
print_existing = -> { puts "\n\nExisting Receipts:"; ap existing }
|
@@ -326,11 +318,11 @@ When in interactive shell mode:
|
|
326
318
|
case options.first.to_s
|
327
319
|
when 'a' # all
|
328
320
|
if run_options.interactive_mode
|
329
|
-
|
321
|
+
data
|
330
322
|
else
|
331
|
-
|
332
|
-
|
333
|
-
|
323
|
+
print_missing.()
|
324
|
+
print_existing.()
|
325
|
+
print_unused.()
|
334
326
|
end
|
335
327
|
|
336
328
|
when 'm'
|
@@ -372,7 +364,6 @@ When in interactive shell mode:
|
|
372
364
|
@commands_ ||= [
|
373
365
|
Command.new('rec', 'receipts', -> (*options) { cmd_rec(options) }),
|
374
366
|
Command.new('rep', 'reports', -> (*_options) { cmd_rep }),
|
375
|
-
Command.new('d', 'display_reports', -> (*_options) { cmd_d }),
|
376
367
|
Command.new('w', 'write_reports', -> (*_options) { cmd_w }),
|
377
368
|
Command.new('c', 'chart_of_accounts', -> (*_options) { cmd_c }),
|
378
369
|
Command.new('jo', 'journals', -> (*_options) { cmd_j }),
|
@@ -4,7 +4,6 @@ require 'os'
|
|
4
4
|
require_relative 'chart_of_accounts'
|
5
5
|
require_relative 'journal'
|
6
6
|
require_relative '../filters/journal_entry_filters' # for shell mode
|
7
|
-
require_relative '../helpers/html_helper'
|
8
7
|
require_relative '../helpers/parse_helper'
|
9
8
|
require_relative '../reports/book_set_reporter'
|
10
9
|
|
@@ -39,6 +38,10 @@ module RockBooks
|
|
39
38
|
@all_entries ||= Journal.entries_in_documents(journals)
|
40
39
|
end
|
41
40
|
|
41
|
+
|
42
|
+
def all_reports(filter = nil)
|
43
|
+
BookSetReporter.new(self, nil, filter).get_all_report_data
|
44
|
+
end
|
42
45
|
end
|
43
46
|
end
|
44
47
|
|
@@ -7,7 +7,7 @@ require_relative '../types/acct_amount'
|
|
7
7
|
require_relative '../types/journal_entry_context'
|
8
8
|
require_relative 'journal_entry'
|
9
9
|
require_relative 'journal_entry_builder'
|
10
|
-
require_relative '../reports/helpers/
|
10
|
+
require_relative '../reports/helpers/text_report_helper'
|
11
11
|
|
12
12
|
module RockBooks
|
13
13
|
|
@@ -65,9 +65,8 @@ class Journal
|
|
65
65
|
attr_reader :short_name, :account_code, :chart_of_accounts, :date_prefix, :debit_or_credit, :doc_type, :title, :entries
|
66
66
|
|
67
67
|
# short_name is a name that will appear on reports identifying the journal from which a transaction comes
|
68
|
-
def initialize(chart_of_accounts, input_lines
|
68
|
+
def initialize(chart_of_accounts, input_lines)
|
69
69
|
@chart_of_accounts = chart_of_accounts
|
70
|
-
@short_name = short_name
|
71
70
|
@entries = []
|
72
71
|
@date_prefix = ''
|
73
72
|
input_lines.each_with_index do |line, linenum|
|
@@ -1,5 +1,5 @@
|
|
1
1
|
require_relative 'helpers/erb_helper'
|
2
|
-
require_relative 'helpers/
|
2
|
+
require_relative 'helpers/text_report_helper'
|
3
3
|
|
4
4
|
module RockBooks
|
5
5
|
|
@@ -8,7 +8,7 @@ module RockBooks
|
|
8
8
|
# in order to calculate the correct balances, so we ignore the global $filter.
|
9
9
|
class BalanceSheet
|
10
10
|
|
11
|
-
include
|
11
|
+
include TextReportHelper
|
12
12
|
include ErbHelper
|
13
13
|
|
14
14
|
attr_accessor :context, :data
|
@@ -4,6 +4,7 @@ require_relative 'balance_sheet'
|
|
4
4
|
require_relative 'data/bs_is_data'
|
5
5
|
require_relative 'data/receipts_report_data'
|
6
6
|
require_relative 'income_statement'
|
7
|
+
require_relative 'index_html_page'
|
7
8
|
require_relative 'multidoc_txn_report'
|
8
9
|
require_relative 'receipts_report'
|
9
10
|
require_relative 'report_context'
|
@@ -11,16 +12,18 @@ require_relative 'journal_report'
|
|
11
12
|
require_relative 'multidoc_txn_by_account_report'
|
12
13
|
require_relative 'tx_one_account'
|
13
14
|
require_relative 'helpers/erb_helper'
|
14
|
-
require_relative 'helpers/
|
15
|
+
require_relative 'helpers/text_report_helper'
|
16
|
+
require_relative 'helpers/receipts_hyperlink_converter'
|
15
17
|
|
16
18
|
require 'prawn'
|
19
|
+
require 'tty-progressbar'
|
17
20
|
|
18
21
|
module RockBooks
|
19
22
|
class BookSetReporter
|
20
23
|
|
21
24
|
extend Forwardable
|
22
25
|
|
23
|
-
attr_reader :book_set, :
|
26
|
+
attr_reader :book_set, :context, :filter, :output_dir, :progress_bar
|
24
27
|
|
25
28
|
def_delegator :book_set, :all_entries
|
26
29
|
def_delegator :book_set, :journals
|
@@ -35,6 +38,7 @@ class BookSetReporter
|
|
35
38
|
@output_dir = output_dir
|
36
39
|
@filter = filter
|
37
40
|
@context = ReportContext.new(book_set.chart_of_accounts, book_set.journals, 80)
|
41
|
+
@progress_bar = TTY::ProgressBar.new("[:bar] :caption", total: report_count + 10)
|
38
42
|
end
|
39
43
|
|
40
44
|
|
@@ -47,9 +51,44 @@ class BookSetReporter
|
|
47
51
|
do_transaction_reports
|
48
52
|
do_single_account_reports
|
49
53
|
do_receipts_report
|
54
|
+
progress_bar.advance(caption: 'Finished generating reports.')
|
55
|
+
progress_bar.finish
|
50
56
|
end
|
51
57
|
|
52
58
|
|
59
|
+
def report_count
|
60
|
+
bal_sheet_income_statement = 2
|
61
|
+
journal_count = journals.size
|
62
|
+
txn_report_count = 3
|
63
|
+
single_account_count = chart_of_accounts.accounts.size
|
64
|
+
receipt_report_count = 1
|
65
|
+
bal_sheet_income_statement + journal_count + txn_report_count + single_account_count + receipt_report_count
|
66
|
+
end
|
67
|
+
|
68
|
+
|
69
|
+
def get_all_report_data
|
70
|
+
reports = {}
|
71
|
+
|
72
|
+
reports[:bs_is] = BsIsData.new(context)
|
73
|
+
|
74
|
+
reports[:journals] = journals.each_with_object({}) do |journal, journals|
|
75
|
+
journals[journal.short_name] = JournalData.new(journal, context, filter).fetch
|
76
|
+
end
|
77
|
+
|
78
|
+
reports[:txn_reports] = {
|
79
|
+
by_account: MultidocTxnByAccountData.new(context).fetch,
|
80
|
+
by_date: MultidocTxnReportData.new(context, :date, filter).fetch,
|
81
|
+
by_amount: MultidocTxnReportData.new(context, :amount, filter).fetch
|
82
|
+
}
|
83
|
+
|
84
|
+
reports[:single_accounts] = chart_of_accounts.accounts.each_with_object({}) do |account, single_accts|
|
85
|
+
single_accts[account.code.to_sym] = TxOneAccountData.new(context, account.code).fetch
|
86
|
+
end
|
87
|
+
|
88
|
+
reports[:receipts] = ReceiptsReportData.new(book_set.all_entries, run_options.receipt_dir).fetch
|
89
|
+
reports
|
90
|
+
end
|
91
|
+
|
53
92
|
# All methods after this point are private.
|
54
93
|
|
55
94
|
private def do_statements
|
@@ -109,16 +148,6 @@ class BookSetReporter
|
|
109
148
|
end
|
110
149
|
|
111
150
|
|
112
|
-
private def run_command(command)
|
113
|
-
puts "\n----\nRunning command: #{command}"
|
114
|
-
stdout, stderr, status = Open3.capture3(command)
|
115
|
-
puts "Exit code was #{status.exitstatus}."
|
116
|
-
puts "\nStdout was:\n\n#{stdout}" unless stdout.size == 0
|
117
|
-
puts "\nStderr was:\n\n#{stderr}" unless stderr.size == 0
|
118
|
-
puts
|
119
|
-
end
|
120
|
-
|
121
|
-
|
122
151
|
private def create_directories
|
123
152
|
%w(txt pdf html).each do |format|
|
124
153
|
dir = File.join(output_dir, format, SINGLE_ACCT_SUBDIR)
|
@@ -138,22 +167,29 @@ class BookSetReporter
|
|
138
167
|
end
|
139
168
|
|
140
169
|
|
141
|
-
private def
|
142
|
-
|
143
|
-
|
144
|
-
|
170
|
+
private def report_metadata(doc_short_name)
|
171
|
+
{
|
172
|
+
RBCreator: "RockBooks v#{VERSION} (#{PROJECT_URL})",
|
173
|
+
RBEntity: context.entity,
|
174
|
+
RBCreated: Time.now.to_s,
|
175
|
+
RBDocumentCode: doc_short_name.to_s,
|
176
|
+
}
|
145
177
|
end
|
146
178
|
|
147
179
|
|
148
|
-
private def prawn_create_document(pdf_filespec,
|
149
|
-
Prawn::Document.generate(pdf_filespec) do
|
180
|
+
private def prawn_create_document(pdf_filespec, report_text, doc_short_name)
|
181
|
+
Prawn::Document.generate(pdf_filespec, info: report_metadata(doc_short_name)) do
|
150
182
|
font(FONT_FILESPEC, size: 10)
|
151
183
|
|
152
184
|
utf8_nonbreaking_space = "\uC2A0"
|
153
185
|
unicode_nonbreaking_space = "\u00A0"
|
154
|
-
text(
|
186
|
+
text(report_text.gsub(' ', unicode_nonbreaking_space))
|
155
187
|
end
|
156
|
-
|
188
|
+
end
|
189
|
+
|
190
|
+
|
191
|
+
private def html_metadata_comment(doc_short_name)
|
192
|
+
"\n" + report_metadata(doc_short_name).ai(plain: true) + "\n"
|
157
193
|
end
|
158
194
|
|
159
195
|
|
@@ -165,12 +201,16 @@ class BookSetReporter
|
|
165
201
|
|
166
202
|
create_text_report = -> { File.write(txt_filespec, text_report) }
|
167
203
|
|
168
|
-
create_pdf_report = -> { prawn_create_document(pdf_filespec, text_report) }
|
204
|
+
create_pdf_report = -> { prawn_create_document(pdf_filespec, text_report, short_name) }
|
169
205
|
|
170
206
|
create_html_report = -> do
|
171
|
-
data = {
|
207
|
+
data = {
|
208
|
+
report_body: text_report,
|
209
|
+
title: "#{short_name} Report -- RockBooks",
|
210
|
+
metadata_comment: html_metadata_comment(short_name)
|
211
|
+
}
|
172
212
|
html_raw_report = ErbHelper.render_hashes("html/report_page.html.erb", data, {})
|
173
|
-
html_report =
|
213
|
+
html_report = ReceiptsHyperlinkConverter.convert(html_raw_report, html_filespec)
|
174
214
|
File.write(html_filespec, html_report)
|
175
215
|
end
|
176
216
|
|
@@ -178,41 +218,15 @@ class BookSetReporter
|
|
178
218
|
create_pdf_report.()
|
179
219
|
create_html_report.()
|
180
220
|
|
181
|
-
|
182
|
-
puts "Created reports in txt, html, and pdf for #{"%-20s" % short_name} at #{File.dirname(txt_filespec)}.\n\n\n"
|
183
|
-
end
|
184
|
-
|
185
|
-
|
186
|
-
private def missing_existing_unused_receipts
|
187
|
-
missing_receipts = []
|
188
|
-
existing_receipts = []
|
189
|
-
receipt_full_filespec = ->(receipt_filespec) { File.join(run_options.receipt_dir, receipt_filespec) }
|
190
|
-
|
191
|
-
# We will start out putting all filespecs in the unused array, and delete them as they are found in the transactions.
|
192
|
-
unused_receipt_filespecs = Dir['receipts/**/*'].select { |s| File.file?(s) } \
|
193
|
-
.sort \
|
194
|
-
.map { |s| "./" + s } # Prepend './' to match the data
|
195
|
-
|
196
|
-
all_entries.each do |entry|
|
197
|
-
entry.receipts.each do |receipt|
|
198
|
-
filespec = receipt_full_filespec.(receipt)
|
199
|
-
unused_receipt_filespecs.delete(filespec)
|
200
|
-
file_exists = File.file?(filespec)
|
201
|
-
list = (file_exists ? existing_receipts : missing_receipts)
|
202
|
-
list << { receipt: receipt, journal: entry.doc_short_name }
|
203
|
-
end
|
204
|
-
end
|
205
|
-
[missing_receipts, existing_receipts, unused_receipt_filespecs]
|
221
|
+
progress_bar.advance(caption: "Generating report: #{short_name}")
|
206
222
|
end
|
207
223
|
|
208
224
|
|
209
|
-
private def
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
chart_of_accounts: chart_of_accounts,
|
215
|
-
run_options: run_options)
|
225
|
+
private def create_index_html
|
226
|
+
progress_bar.advance(caption: 'Generating index.html')
|
227
|
+
filespec = build_filespec(output_dir, 'index', 'html')
|
228
|
+
content = IndexHtmlPage.new(context, html_metadata_comment('index.html'), run_options).generate
|
229
|
+
File.write(filespec, content)
|
216
230
|
end
|
217
231
|
end
|
218
232
|
end
|
@@ -19,7 +19,9 @@ class BsIsSectionData
|
|
19
19
|
totals = journals_acct_totals.select { |code, _amount| codes.include?(code) }
|
20
20
|
need_to_reverse_sign = %i{liability equity income}.include?(type)
|
21
21
|
if need_to_reverse_sign
|
22
|
-
totals.keys.each
|
22
|
+
totals.keys.each do |code|
|
23
|
+
totals[code] = -totals[code] unless totals[code] == 0.0
|
24
|
+
end
|
23
25
|
end
|
24
26
|
totals
|
25
27
|
end
|
@@ -25,6 +25,7 @@ class JournalData
|
|
25
25
|
name: journal.chart_of_accounts.name_for_code(journal.account_code),
|
26
26
|
title: journal.title,
|
27
27
|
short_name: journal.short_name,
|
28
|
+
debit_or_credit: journal.debit_or_credit,
|
28
29
|
start_date: context.chart_of_accounts.start_date,
|
29
30
|
end_date: context.chart_of_accounts.end_date,
|
30
31
|
entries: entries,
|
@@ -8,19 +8,14 @@ module ErbHelper
|
|
8
8
|
|
9
9
|
|
10
10
|
def self.render_binding(erb_relative_filespec, template_binding)
|
11
|
-
print "Rendering template #{erb_relative_filespec}..."
|
12
11
|
result = erb_template(erb_relative_filespec).result(template_binding)
|
13
|
-
puts 'done.'
|
14
12
|
result
|
15
13
|
end
|
16
14
|
|
17
15
|
# Takes 2 hashes, one with data, and the other with presentation functions/lambdas, and passes their union to ERB
|
18
16
|
# for rendering.
|
19
17
|
def self.render_hashes(erb_relative_filespec, data_hash, presentation_hash)
|
20
|
-
print "Rendering template #{erb_relative_filespec}..."
|
21
18
|
combined_hash = (data_hash || {}).merge(presentation_hash || {})
|
22
|
-
|
23
|
-
puts 'done.'
|
24
|
-
result
|
19
|
+
erb_template(erb_relative_filespec).result_with_hash(combined_hash)
|
25
20
|
end
|
26
21
|
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module RockBooks
|
2
|
+
class ReceiptsHyperlinkConverter
|
3
|
+
|
4
|
+
def self.convert(html_string, html_filespec)
|
5
|
+
ReceiptsHyperlinkConverter.new(html_string, html_filespec).convert
|
6
|
+
end
|
7
|
+
|
8
|
+
RECEIPT_REGEX = /Receipt:\s*(\S*)/
|
9
|
+
INVOICE_REGEX = /Invoice:\s*(\S*)/
|
10
|
+
|
11
|
+
attr_reader :html_string, :num_dirs_up
|
12
|
+
|
13
|
+
def initialize(html_string, html_filespec)
|
14
|
+
@html_string = html_string
|
15
|
+
@num_dirs_up = html_filespec.include?('/single-account/') ? 3 : 2
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
def convert
|
20
|
+
process_link_type = ->(line, regex, dir_name) do
|
21
|
+
matches = regex.match(line)
|
22
|
+
if matches
|
23
|
+
listed_filespec = matches[1]
|
24
|
+
anchor_line(line, listed_filespec, dir_name)
|
25
|
+
else
|
26
|
+
line
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
html_string.split("\n").map do |line|
|
31
|
+
line = process_link_type.(line, RECEIPT_REGEX, 'receipts')
|
32
|
+
process_link_type.(line, INVOICE_REGEX, 'invoices')
|
33
|
+
end.join("\n")
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
# If the HTML file being created is in DATA_DIR/rockbooks-reports/html/single-account, then
|
38
|
+
# the processed link should be '../../../receipts/[receipt_filespec]'
|
39
|
+
# else it's in DATA_DIR/rockbooks-reports/html, and
|
40
|
+
# the processed link should be '../../receipts/[receipt_filespec]'
|
41
|
+
#
|
42
|
+
# `dir_name` will be 'receipts' or 'invoices'
|
43
|
+
private def dirized_filespec(listed_filespec, dir_name)
|
44
|
+
File.join(('../' * num_dirs_up), dir_name, listed_filespec)
|
45
|
+
end
|
46
|
+
|
47
|
+
private def anchor_line(line, listed_filespec, dir_name)
|
48
|
+
label = {
|
49
|
+
'receipts' => 'Receipt',
|
50
|
+
'invoices' => 'Invoice'
|
51
|
+
}.fetch(dir_name)
|
52
|
+
|
53
|
+
line.gsub( \
|
54
|
+
/#{label}:\s*#{listed_filespec}/, \
|
55
|
+
%Q{#{label}: <a href="#{dirized_filespec(listed_filespec, dir_name)}">#{listed_filespec}</a>})
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|