mandown 0.0.7 → 0.0.8
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/Manifest.txt +3 -0
- data/README.txt +3 -81
- data/bin/bibdown +2 -520
- data/bin/mandown-sample +124 -0
- data/lib/bibdown_lib.rb +537 -0
- data/lib/mandown/version.rb +1 -1
- data/test/test_bibdown.rb +94 -0
- data/website/index.html +92 -32
- data/website/index.txt +72 -22
- data/website/template.rhtml +1 -1
- metadata +7 -2
data/Manifest.txt
CHANGED
@@ -4,8 +4,10 @@ Manifest.txt
|
|
4
4
|
README.txt
|
5
5
|
Rakefile
|
6
6
|
bin/bibdown
|
7
|
+
bin/mandown-sample
|
7
8
|
config/hoe.rb
|
8
9
|
config/requirements.rb
|
10
|
+
lib/bibdown_lib.rb
|
9
11
|
lib/mandown.rb
|
10
12
|
lib/mandown/version.rb
|
11
13
|
log/debug.log
|
@@ -18,6 +20,7 @@ tasks/environment.rake
|
|
18
20
|
tasks/website.rake
|
19
21
|
test/test_helper.rb
|
20
22
|
test/test_mandown.rb
|
23
|
+
test/test_bibdown.rb
|
21
24
|
website/index.html
|
22
25
|
website/index.txt
|
23
26
|
website/javascripts/rounded_corners_lite.inc.js
|
data/README.txt
CHANGED
@@ -1,89 +1,11 @@
|
|
1
1
|
= Mandown Readme
|
2
2
|
|
3
|
-
|
3
|
+
Mandown provides simple extensions to the "Markdown":http://daringfireball.net/projects/markdown/ syntax that are useful for academic writing.
|
4
4
|
|
5
|
-
|
6
|
-
Markdown syntax (see http://daringfireball.net/projects/markdown/). It
|
7
|
-
provides simple extensions to the Markdown syntax that are useful for academic
|
8
|
-
writing.
|
5
|
+
For up-to-date information about Mandown, please see the "Mandown website":http://mandown.rubyforge.org/
|
9
6
|
|
10
|
-
Using a combination of Mandown (and its syntax), the Markdown syntax and a
|
11
|
-
Markdown processor (such as Pandoc, see http://johnmacfarlane.net/pandoc/) it is
|
12
|
-
possible to write academic manuscripts using a simple plain-text syntax which
|
13
|
-
can then be converted into useful formats such as Rich Text Format (RTF, which
|
14
|
-
can in turn be opened by Microsoft Word), PDF, LaTeX etc.
|
15
7
|
|
16
|
-
|
17
|
-
system such as LaTeX is that is allows manuscripts to be kept in a plain text
|
18
|
-
format (ASCII/UTF-8/etc.) while allowing you to convert to Word or LaTeX. This
|
19
|
-
is particularly useful if you don't want to draft in Word but have a co-author
|
20
|
-
who has a confusing attachment to Microsoft products. Let them hack at the Word
|
21
|
-
version you prepared for them, then bring their changes into your Mandown source
|
22
|
-
file (this task may still be tricky, sorry...). Your papers will be readable
|
23
|
-
'forever' and you won't need to worry about losing your data.
|
24
|
-
|
25
|
-
Mandown is not attempting to be a document preparation system like LaTeX; if you
|
26
|
-
can use LaTeX you probably should---it's far more powerful than Mandown.
|
27
|
-
However, it can be difficult to convert from LaTeX to Word format, and this is
|
28
|
-
when Mandown may become useful to you.
|
29
|
-
|
30
|
-
The Mandown tools are designed to be used in a UNIX pipeline (see the Usage
|
31
|
-
section, below). You may choose to use one or more of the tools. You may also
|
32
|
-
want to develop your own tools which I would be glad to consider adding to
|
33
|
-
Mandown.
|
34
|
-
|
35
|
-
The name Mandown is a portmanteaux of 'manuscript' and 'Markdown', which I find
|
36
|
-
slightly amusing ("Man down!").
|
37
|
-
|
38
|
-
|
39
|
-
== Usage:
|
40
|
-
|
41
|
-
The Mandown tools are designed to be chained together on the UNIX command line
|
42
|
-
in a pipeline. Here is an example of how to process a file containing a bibliography with bibdown and convert the resulting file into an RTF file using Pandoc (the resulting RTF file could then be opened using Word, for example; ignore the initial > characters, which denote the start of a new command):
|
43
|
-
|
44
|
-
> cat sample-manuscript.txt | bibdown > sample-out.txt
|
45
|
-
> pandoc --smart -s sample-out.txt -o sample.rtf
|
46
|
-
|
47
|
-
This assumes that the Mandown tool directory and the Pandoc program are on your system's $PATH.
|
48
|
-
|
49
|
-
If you are unfamiliar with the UNIX command line, here's what's going on:
|
50
|
-
|
51
|
-
1. The cat program reads the sample-manuscript.txt and sends it to the standard output device (usually the terminal).
|
52
|
-
2. The contents of sample-manuscript.txt are intercepted by a 'pipe' (denoted by the '|' character) which sends them to the bibdown program.
|
53
|
-
3. The bibdown program processes the bibliography and sends the resulting manuscript to the standard output device.
|
54
|
-
4. The processed manuscript is intercepted by the '>' operator, which causes standard output to be the file called sample-out.txt. We now have a manuscript with proper citations and a bibliography in Markdown format.
|
55
|
-
5. We then run Pandoc on the result to create an RTF file.
|
56
|
-
|
57
|
-
The Mandown tools are designed to be chained together into a pipeline, so for example you might do:
|
58
|
-
|
59
|
-
> cat my-manu.txt | bibdown | eqndown | secdown > my-manu-out.txt
|
60
|
-
> pandoc ...
|
61
|
-
|
62
|
-
Note: only bibdown is currently implemented.
|
63
|
-
|
64
|
-
|
65
|
-
== FAQ, gotchas and common problems:
|
66
|
-
|
67
|
-
Q1: How do I ...
|
68
|
-
A1: Email me; there isn't much implemented yet, but the bare bones are there. No guarantees, but I'll try and take your feature requests into consideration. Or better yet, send me code!
|
69
|
-
|
70
|
-
Q2: I have a problem running bibdown.
|
71
|
-
A2: Check that you are not using hard tabs; Ruby's YAML parser requires that soft tabs (i.e. emulated using spaces). Also check the alignment of the various fields.
|
72
|
-
|
73
|
-
Q3: bibdown chokes on titles etc. that contain colons.
|
74
|
-
A3: Surround the title in quotes; these will be ignored, but fix the problem. I think this is a bug in Ruby's YAML parser (as of Ruby 1.8.6).
|
75
|
-
|
76
|
-
Q4: The tools don't run.
|
77
|
-
A4: Mandown requires Ruby version 1.8.6 or higher. Check that the tools are executable (try 'chmod u+x bibdown', for example). Check that the Mandown directory is on your system's $PATH. Try running the using the Ruby interpreter explicitly (e.g. 'ruby bibdown' rather than just 'bibdown').
|
78
|
-
|
79
|
-
|
80
|
-
== Author and Contact Information:
|
81
|
-
|
82
|
-
The Mandown set of tools was written by Chris Rose. You can contact me at
|
83
|
-
mandown@microserf.org.uk.
|
84
|
-
|
85
|
-
|
86
|
-
== Copyright and license:
|
8
|
+
= Copyright and license:
|
87
9
|
|
88
10
|
Copyright (c) 2008 Chris Rose
|
89
11
|
|
data/bin/bibdown
CHANGED
@@ -17,525 +17,7 @@
|
|
17
17
|
#
|
18
18
|
################################################################################
|
19
19
|
|
20
|
-
require '
|
21
|
-
|
22
|
-
|
23
|
-
# Define the text that is displayed when the user asks for documentation
|
24
|
-
def documentation
|
25
|
-
<<END
|
26
|
-
|
27
|
-
|
28
|
-
bibdown --- part of the Mandown set of tools.
|
29
|
-
|
30
|
-
bibdown processes standard input, builds a bibliography from a YAML-format set
|
31
|
-
of references and inserts citation keys.
|
32
|
-
|
33
|
-
Copyright © 2008 Chris Rose.
|
34
|
-
Distributed according to the GNU General Public License.
|
35
|
-
|
36
|
-
Usage:
|
37
|
-
------
|
38
|
-
cat infile.txt | bibdown > outfile.txt
|
39
|
-
|
40
|
-
Syntax:
|
41
|
-
-------
|
42
|
-
|
43
|
-
Place references at the end of your Markdown file in a level 1 section
|
44
|
-
called 'Bibliography' using the exact string '# Bibliography' (as given in the
|
45
|
-
example below). Cite references in your text using 'cite:MyKey', where 'MyKey'
|
46
|
-
is a key to one of your references. Keys may contain any characters, but end
|
47
|
-
with a space character (i.e. 'cite:SomeKey' refers to the key 'SomeKey', while
|
48
|
-
'cite:Some Key' refers to the key 'Some').
|
49
|
-
|
50
|
-
------------------------------- Example -------------------------------------
|
51
|
-
...
|
52
|
-
This is some text that needs to cite the very important work of Jones and
|
53
|
-
Smith cite:Jones.
|
54
|
-
...
|
55
|
-
|
56
|
-
# Bibliogrqaphy
|
57
|
-
|
58
|
-
Jones:
|
59
|
-
authors: Jones, Bob & Smith, Fred J.
|
60
|
-
title: Spaghetti-Wall Interactions
|
61
|
-
journal: Am. J. Pasta Phys.
|
62
|
-
volume: 3
|
63
|
-
number: 2
|
64
|
-
month: January
|
65
|
-
year: 2008
|
66
|
-
pages: 111--112
|
67
|
-
note: In press.
|
68
|
-
------------------------------- End of example ------------------------------
|
69
|
-
|
70
|
-
Suppoted fields:
|
71
|
-
----------------
|
72
|
-
|
73
|
-
The following fields are supported by bibdown and all are optional; you may
|
74
|
-
use other arbitrarily-named fields, but they will be ignored (by this version
|
75
|
-
of bibdown, at least).
|
76
|
-
|
77
|
-
authors -- Use 'surname, first names' format; separate authors with '&'.
|
78
|
-
e.g. "Einstein, Albert & Bohr, Neils"
|
79
|
-
organization -- Use if the publication is authored by an organization.
|
80
|
-
e.g. "Amnesty International"
|
81
|
-
title -- The title of the reference.
|
82
|
-
e.g. "Some Clever Stuff on Quantum Physics"
|
83
|
-
journal -- The name of the journal; this field causes the reference to be
|
84
|
-
treated as an article in a journal.
|
85
|
-
e.g. "Int. J. Quan. Phys."
|
86
|
-
conference -- The name of the conference; this field causes the reference to
|
87
|
-
be treated as a paper in a conference proceedings.
|
88
|
-
e.g. "Medical Image Understanding and Analysis"
|
89
|
-
booktitle -- The title of a book; this field causes the reference to be
|
90
|
-
treated as a book.
|
91
|
-
e.g. "Moby Dick"
|
92
|
-
chapter -- The chapter in a book being cited; only valid for references
|
93
|
-
that use the booktitle field.
|
94
|
-
e.g. "4"
|
95
|
-
edition -- The edition of a book being cited; only valid for references
|
96
|
-
that use the booktitle field.
|
97
|
-
e.g. "5"
|
98
|
-
editors -- The editors of a book being cited; only valid for references
|
99
|
-
that use the booktitle field.
|
100
|
-
e.g. "Harris, Thomas & Hopper, Dennis"
|
101
|
-
isbn -- The ISBN number of a book being cited; only valid for references
|
102
|
-
that use the booktitle field.
|
103
|
-
e.g. "9783540356257"
|
104
|
-
month -- The month of publication.
|
105
|
-
e.g. "January"
|
106
|
-
volume -- The volume of the publication being cited.
|
107
|
-
e.g. "2"
|
108
|
-
number -- The number/issue of the journal article being cited; only valid for
|
109
|
-
references that use the journal field.
|
110
|
-
e.g. "2"
|
111
|
-
pages -- The pages in the publication being referred to.
|
112
|
-
e.g. "201--211"
|
113
|
-
series -- The series the book being cited belongs to; only valid for
|
114
|
-
references that use the booktitle field.
|
115
|
-
e.g. "Mathematical Statistics"
|
116
|
-
url -- A URL for the publication being cited.
|
117
|
-
e.g. "http://www.something.com/somedocument"
|
118
|
-
accessed -- The date the URL was accessed (note: do not use this field without
|
119
|
-
also including a URL).
|
120
|
-
e.g. "28 January 2008"
|
121
|
-
year -- The year the publication being cited was published.
|
122
|
-
e.g. 2008
|
123
|
-
note -- Any notable comment about the publication being cited.
|
124
|
-
e.g. "In press."
|
125
|
-
|
126
|
-
|
127
|
-
Notes:
|
128
|
-
------
|
129
|
-
|
130
|
-
You must use soft tabs (emulated using spaces) in the bibliography. If you
|
131
|
-
need to include a colon in the reference (e.g. in the title field), you
|
132
|
-
will need to surround the field entry in quotes (e.g. "title: 'Gnocci: nasty
|
133
|
-
or nice?'").
|
134
|
-
|
135
|
-
If you are going to process the resulting file (outfile.txt, in the usage
|
136
|
-
example given above), you may wish to use a double-dash for page ranges
|
137
|
-
(and be sure to use the 'smart typography' mode of Pandoc)---see the example
|
138
|
-
above.
|
139
|
-
|
140
|
-
See also:
|
141
|
-
---------
|
142
|
-
|
143
|
-
Markdown -- http://daringfireball.net/projects/markdown/
|
144
|
-
Pandoc -- http://johnmacfarlane.net/pandoc/
|
145
|
-
|
146
|
-
END
|
147
|
-
end
|
148
|
-
|
149
|
-
|
150
|
-
# Given a symbol identifying a part of a citation (e.g. :journal), return the
|
151
|
-
# separator string that should follow it (e.g. a '. ' follows the name of the
|
152
|
-
# journal). (Note: include any following space!)
|
153
|
-
def get_sep(part)
|
154
|
-
sep = case part
|
155
|
-
when :authors, :organization, :title, :booktitle, :isbn, :series, :accessed, :year
|
156
|
-
'. '
|
157
|
-
when :journal, :conference, :chapter, :edition, :pages, :url
|
158
|
-
', '
|
159
|
-
when :editors
|
160
|
-
', editors. '
|
161
|
-
when :month, :note
|
162
|
-
' '
|
163
|
-
when :number, :volume
|
164
|
-
''
|
165
|
-
end
|
166
|
-
|
167
|
-
sep
|
168
|
-
end
|
169
|
-
|
170
|
-
# Define a function that takes a string and returns that string marked as being of :normal (upright) or :italic using Markdown notation.
|
171
|
-
def markdown_format(string, style)
|
172
|
-
case style
|
173
|
-
when :normal: string
|
174
|
-
when :italic: '*' + string + '*'
|
175
|
-
end
|
176
|
-
end
|
177
|
-
|
178
|
-
# Define a function to render a string as normal using Markdown notation.
|
179
|
-
def r_norm(string)
|
180
|
-
markdown_format(string, :normal)
|
181
|
-
end
|
182
|
-
|
183
|
-
# Define a function to render a string as italic using Markdown notation.
|
184
|
-
def r_ital(string)
|
185
|
-
markdown_format(string, :italic)
|
186
|
-
end
|
187
|
-
|
188
|
-
|
189
|
-
# Given a bib entry (a hash that maps the parts of a reference to the content
|
190
|
-
# for that reference), construct a string that can be used in a paper as the
|
191
|
-
# bibliographic entry for that entry. Also return information that can be used
|
192
|
-
# to sort the bibliography (first author surname, publication year). Also
|
193
|
-
# return the key that was used in the text to refer to this citation. Return a
|
194
|
-
# hash with fields :reference (containing the reference), :sort_info and :key.
|
195
|
-
# :sort_info is a hash with fields :surname and :year.
|
196
|
-
#
|
197
|
-
# See the documentation string above for details on what fields are supported
|
198
|
-
# and how they should behave.
|
199
|
-
def make_bib_entry_string(bib_entry, key)
|
200
|
-
# We'll encode the order in which the parts of the reference appear for the
|
201
|
-
# three types of reference in three arrays; we'll associate these arrays
|
202
|
-
# with symbols that specify the reference type.
|
203
|
-
order = {
|
204
|
-
:journal =>
|
205
|
-
[:authors, :organization, :title, :journal, :volume, :number, :pages,
|
206
|
-
:month, :year, :url, :accessed, :note],
|
207
|
-
:conference =>
|
208
|
-
[:authors, :organization, :title, :conference, :editors, :volume, :pages,
|
209
|
-
:month, :year, :isbn, :url, :accessed, :note],
|
210
|
-
:book =>
|
211
|
-
[:authors, :organization, :editors, :booktitle, :series, :edition,
|
212
|
-
:volume, :chapter, :pages, :month, :year, :isbn, :url, :accessed,
|
213
|
-
:note]}
|
214
|
-
|
215
|
-
# Cope with the misc type.
|
216
|
-
order[:misc] = order[:journal]
|
217
|
-
|
218
|
-
# Use an associative array to specify how each part of a citation should be
|
219
|
-
# styled. We map from the parts to functions which perform the required
|
220
|
-
# styling.
|
221
|
-
styles = {:authors => proc {|x| r_norm(x)},
|
222
|
-
:organization => proc {|x| r_norm(x)}, :title => proc {|x| r_norm(x)},
|
223
|
-
:journal => proc {|x| r_ital(x)}, :conference => proc {|x| r_ital(x)},
|
224
|
-
:booktitle => proc {|x| r_ital(x)}, :chapter => proc {|x| r_norm(x)},
|
225
|
-
:edition => proc {|x| r_norm(x)}, :editors => proc {|x| r_norm(x)},
|
226
|
-
:isbn => proc {|x| r_norm(x)}, :month => proc {|x| r_norm(x)},
|
227
|
-
:note => proc {|x| r_norm(x)}, :number => proc {|x| r_norm(x)},
|
228
|
-
:pages => proc {|x| r_norm(x)}, :series => proc {|x| r_norm(x)},
|
229
|
-
:url => proc {|x| r_norm(x)}, :accessed => proc {|x| r_norm(x)},
|
230
|
-
:volume => proc {|x| r_norm(x)}, :year => proc {|x| r_norm(x)}}
|
231
|
-
|
232
|
-
# Make a copy for later, as we alter the original bib_entry object.
|
233
|
-
org_bib_entry = bib_entry.clone
|
234
|
-
|
235
|
-
# Make the author string and replace the entry in the bib_entry with the
|
236
|
-
# formatted version. Do similarly with the editors.
|
237
|
-
bib_entry['authors'] =
|
238
|
-
make_author_string(bib_entry['authors']) if !bib_entry['authors'].nil?
|
239
|
-
bib_entry['editors'] =
|
240
|
-
make_author_string(bib_entry['editors']) if !bib_entry['editors'].nil?
|
241
|
-
|
242
|
-
# See if we're making a journal article, conference paper or book reference.
|
243
|
-
ref_type = :journal unless bib_entry['journal'].nil?
|
244
|
-
ref_type = :conference unless bib_entry['conference'].nil?
|
245
|
-
ref_type = :book unless bib_entry['booktitle'].nil?
|
246
|
-
if !(defined? ref_type) || ref_type.nil?
|
247
|
-
ref_type = :misc
|
248
|
-
STDERR.puts('Note: Reference type not found for reference ' + key)
|
249
|
-
end
|
250
|
-
|
251
|
-
# Get the order for the type of entry we're dealing with.
|
252
|
-
order = order[ref_type]
|
253
|
-
|
254
|
-
# Iterate over the parts of the citation for this type of reference and
|
255
|
-
# build the bibliography entry.
|
256
|
-
bib_entry_string = ''
|
257
|
-
order.each do |part_name|
|
258
|
-
# Construct the part of the entry for the given part_name, taking into
|
259
|
-
# account the fact that some parts need to be formatted in certain ways.
|
260
|
-
if bib_entry[part_name.to_s] # If there is an entry for this part name...
|
261
|
-
part = bib_entry[part_name.to_s].to_s
|
262
|
-
else
|
263
|
-
part = ''
|
264
|
-
end
|
265
|
-
|
266
|
-
# Format the part of the reference using the appropriate style.
|
267
|
-
part = styles[part_name].call(part)
|
268
|
-
|
269
|
-
part = case part_name
|
270
|
-
when :authors, :organization, :booktitle, :isbn, :series, :year
|
271
|
-
part + '. '
|
272
|
-
when :title
|
273
|
-
# Only add an '.' if doesn't already end with a punctuation character.
|
274
|
-
if /[[:punct:]]$/.match(part): part + ' '
|
275
|
-
else part + '. '
|
276
|
-
end
|
277
|
-
when :conference
|
278
|
-
'In proc. ' + part + ', '
|
279
|
-
when :journal, :conference, :chapter, :edition
|
280
|
-
part + ', '
|
281
|
-
when :editors
|
282
|
-
part + ', editors. '
|
283
|
-
when :month
|
284
|
-
part + ' '
|
285
|
-
when :volume
|
286
|
-
part
|
287
|
-
when :number, :note
|
288
|
-
'(' + part + ')'
|
289
|
-
when :pages
|
290
|
-
if ref_type == :journal
|
291
|
-
':' + part + ', '
|
292
|
-
elsif ref_type == :conference || ref_type == :book
|
293
|
-
'pp' + part + ', '
|
294
|
-
end
|
295
|
-
when :url
|
296
|
-
'Available at: ' + part
|
297
|
-
when :accessed
|
298
|
-
', accessed ' + part + '. '
|
299
|
-
else
|
300
|
-
part
|
301
|
-
end
|
302
|
-
|
303
|
-
bib_entry_string += part if bib_entry[part_name.to_s]
|
304
|
-
end
|
305
|
-
|
306
|
-
# Make sure the bib_entry_string ends with a punctuation character,
|
307
|
-
# appending a full stop if it doesn't.
|
308
|
-
bib_entry_string.strip!
|
309
|
-
bib_entry_string += '.' unless /[[:punct:]]$/.match(bib_entry_string)
|
310
|
-
|
311
|
-
# Get the surname for sorting purposes. Use the author as first preference
|
312
|
-
# if it is available, otherwise use the organisation, otherwise use a sort
|
313
|
-
# surname that will place it last.
|
314
|
-
sort_surname = 'ZZZ' # The default if we can't find something better.
|
315
|
-
sort_surname =
|
316
|
-
org_bib_entry[:organization] if !bib_entry['organization'].nil?
|
317
|
-
sort_surname =
|
318
|
-
get_first_author_surname(org_bib_entry) if !bib_entry['author'].nil?
|
319
|
-
|
320
|
-
|
321
|
-
# Make the hash to return.
|
322
|
-
{ :reference => bib_entry_string,
|
323
|
-
:key => key,
|
324
|
-
:sort_info => {:surname => sort_surname, :year => bib_entry['year']}}
|
325
|
-
end
|
326
|
-
|
327
|
-
# Return the surname of the first author in lowercase.
|
328
|
-
def get_first_author_surname(bib_entry)
|
329
|
-
make_author_string(
|
330
|
-
bib_entry['authors'], true, true).split[0][0..-2].downcase
|
331
|
-
end
|
332
|
-
|
333
|
-
|
334
|
-
# Given a string of the form 'Chris James' turn it into a string of the form 'C. J.'
|
335
|
-
def make_initials(firstnames)
|
336
|
-
firstnames = firstnames.split(' ')
|
337
|
-
firstnames.each_index do |i|
|
338
|
-
firstnames[i] = firstnames[i][0].chr + '.'
|
339
|
-
end
|
340
|
-
end
|
341
|
-
|
342
|
-
# Given a string of the form 'Rose, Chris & Jones, Bob', make an authors
|
343
|
-
# string that can be placed in the bibliography.
|
344
|
-
#
|
345
|
-
# use_initials specifies whether the full firstnames are used, or whether
|
346
|
-
# initials are used instead.
|
347
|
-
#
|
348
|
-
# surname_first specifies whether the author surnames should appear before
|
349
|
-
# their first names or initials.
|
350
|
-
def make_author_string(authors, use_initials=true, surname_first=false)
|
351
|
-
# Strip out the individual authors and remove leading and trailing
|
352
|
-
# whitespace, and split each into surname and firstnames.
|
353
|
-
authors = authors.split('&')
|
354
|
-
authors.each_index do |i|
|
355
|
-
authors[i].strip!
|
356
|
-
authors[i] = authors[i].split(',')
|
357
|
-
authors[i][0].strip!
|
358
|
-
authors[i][1].strip!
|
359
|
-
end
|
360
|
-
|
361
|
-
# If we have to use first initials for the first names, then make them.
|
362
|
-
if use_initials
|
363
|
-
authors.each_index do |i|
|
364
|
-
authors[i][1] = make_initials(authors[i][1])
|
365
|
-
end
|
366
|
-
end
|
367
|
-
|
368
|
-
# Now make the authors string.
|
369
|
-
authors_string = ''
|
370
|
-
authors.each_index do |i|
|
371
|
-
# Get a string for the forename(s) for the i-th author.
|
372
|
-
this_forenames = ''
|
373
|
-
authors[i][1].each do |name_or_initial|
|
374
|
-
this_forenames += name_or_initial + ' '
|
375
|
-
end
|
376
|
-
|
377
|
-
# Concatenate the forename(s) and surname in the appropriate order.
|
378
|
-
if surname_first
|
379
|
-
authors_string += authors[i][0] + ', '
|
380
|
-
authors_string += this_forenames
|
381
|
-
else
|
382
|
-
authors_string += this_forenames
|
383
|
-
authors_string += authors[i][0]
|
384
|
-
end
|
385
|
-
authors_string += ', ' unless i == authors.length-1 or i == authors.length-2
|
386
|
-
authors_string += ' and ' if i == authors.length-2
|
387
|
-
end
|
388
|
-
|
389
|
-
authors_string.strip! # Remove leading and trailing whitespace.
|
390
|
-
authors_string # Return the authors string.
|
391
|
-
end
|
392
|
-
|
393
|
-
|
394
|
-
# Given an array of bib_entries, each made using the make_bib_entry_string
|
395
|
-
# function, sort this array according to first author surname, or year of
|
396
|
-
# publication, or by the order in which the papers were cited in the text.
|
397
|
-
#
|
398
|
-
# keys_in_order must be an array containing the keys used in the text, in the
|
399
|
-
# order the keys appear in the text, without repetition. by must be one of
|
400
|
-
# :surname, :year or :order_in_text
|
401
|
-
def sort_bib_entries(bib_entries, keys_in_order, by = :surname)
|
402
|
-
case by
|
403
|
-
when :surname, :year
|
404
|
-
bib_entries.sort {|x,y| x[:sort_info][by] <=> y[:sort_info][by]}
|
405
|
-
when :order_in_text
|
406
|
-
to_return = []
|
407
|
-
keys_in_order.each do |key|
|
408
|
-
bib_entries.each do |entry|
|
409
|
-
to_return.push(entry) if entry[:key] == key
|
410
|
-
end
|
411
|
-
end
|
412
|
-
to_return
|
413
|
-
end
|
414
|
-
end
|
415
|
-
|
416
|
-
|
417
|
-
# Given a string containing the YAML for the bibliography, and an array
|
418
|
-
# containing the keys in the order they appear in the text (without
|
419
|
-
# repetitions), make an array of strings where each string is a bibliographic
|
420
|
-
# entry (i.e. can be placed directly in the bibliography). The entries
|
421
|
-
# returned will be sorted in an appropriate order.
|
422
|
-
def make_bib_entries(bibliography_yaml, keys_in_order)
|
423
|
-
# Convert the YAML text to a Ruby data type.
|
424
|
-
objs = YAML.load(bibliography_yaml)
|
425
|
-
|
426
|
-
# Make each bibliography entry string (the references).
|
427
|
-
bib_entries = Array.new
|
428
|
-
objs.each_key do |key|
|
429
|
-
bib_entries.push(make_bib_entry_string(objs[key], key))
|
430
|
-
end
|
431
|
-
|
432
|
-
# Sort the references & return.
|
433
|
-
sort_bib_entries(bib_entries, keys_in_order, :order_in_text)
|
434
|
-
end
|
435
|
-
|
436
|
-
# Define a function that returns true if bib_entries contains an entry for a
|
437
|
-
# given citation key.
|
438
|
-
def has_key?(key, bib_entries)
|
439
|
-
ret_val = false
|
440
|
-
bib_entries.each do |entry|
|
441
|
-
ret_val = true if entry[:key] == key
|
442
|
-
end
|
443
|
-
ret_val
|
444
|
-
end
|
445
|
-
|
446
|
-
# Get an array that contains the reference keys in the order they are cited,
|
447
|
-
# without repetitions.
|
448
|
-
def get_keys_in_order(plaintext)
|
449
|
-
all_keys = plaintext.scan(/cite:\w*/)
|
450
|
-
all_keys.uniq! # Remove duplicates.
|
451
|
-
uniq_keys = []
|
452
|
-
all_keys.each {|x| uniq_keys.push(x.split('cite:')[1])} # Remove the 'cite:'
|
453
|
-
uniq_keys
|
454
|
-
end
|
455
|
-
|
456
|
-
# Convert bib_entries into a string that can be placed at the end of the
|
457
|
-
# plaintext as the bibliography. The parenthesis style using the
|
458
|
-
# citation_parens argument.
|
459
|
-
def render_bibliography(bib_entries, citation_parens)
|
460
|
-
ret_val = "\n"
|
461
|
-
bib_entries.each_index do |i|
|
462
|
-
ret_val += # The reference number.
|
463
|
-
citation_parens[0].chr + (i+1).to_s + citation_parens[1].chr
|
464
|
-
ret_val += ' ' + bib_entries[i][:reference] # The reference.
|
465
|
-
ret_val += " \n" # __\n is Markdown for a linebreak.
|
466
|
-
end
|
467
|
-
|
468
|
-
ret_val
|
469
|
-
end
|
470
|
-
|
471
|
-
# Given the plaintext containing the key-based citations, and the bib_entries,
|
472
|
-
# make the final manuscript by replacing the key-based citations (in the text)
|
473
|
-
# with human-readable citations and place the bibliography at the end. Specify
|
474
|
-
# the parenthesis style using the optional citation_parens argument.
|
475
|
-
def make_manuscript(plaintext, bib_entries, citation_parens='[]')
|
476
|
-
bib_entries.each_index do |i|
|
477
|
-
plaintext.gsub!("cite:#{bib_entries[i][:key]}",
|
478
|
-
citation_parens[0].chr + "#{i+1}" + citation_parens[1].chr)
|
479
|
-
end
|
480
|
-
|
481
|
-
plaintext + render_bibliography(bib_entries, citation_parens)
|
482
|
-
end
|
483
|
-
|
484
|
-
# Check the final manuscript for instances of cite:SomeKey (for example), and
|
485
|
-
# return an array of messages identifying the keys that were not defined in
|
486
|
-
# the bibliography.
|
487
|
-
def check_missing_citations(manuscript)
|
488
|
-
ret_val = []
|
489
|
-
# Get the remaining keys.
|
490
|
-
remaining_keys = get_keys_in_order(manuscript)
|
491
|
-
remaining_keys.each do |key|
|
492
|
-
ret_val.push('The following reference key was undefined: ' + key)
|
493
|
-
end
|
494
|
-
|
495
|
-
ret_val
|
496
|
-
end
|
497
|
-
|
498
|
-
# Read the text containing the citations from standard input, process the
|
499
|
-
# references and send the result to standard output, reporting errors to
|
500
|
-
# standard error. This program is written to allow it to be chained with other
|
501
|
-
# manuscript-processing tools in a UNIX pipeline. To read/write from/to files,
|
502
|
-
# do:
|
503
|
-
#
|
504
|
-
# cat my-paper.txt | ruby make_paper.rb > my-paper-with-bib.txt
|
505
|
-
def main
|
506
|
-
# Handle request for documentation.
|
507
|
-
if ARGV.length > 0 && ARGV[0] == '--help'
|
508
|
-
puts documentation
|
509
|
-
exit
|
510
|
-
end
|
511
|
-
|
512
|
-
# Read the .txt file from standard input and get the plain text and the
|
513
|
-
# bibliography
|
514
|
-
parts = STDIN.readlines('# Bibliography')
|
515
|
-
plaintext = parts[0]
|
516
|
-
bibliography_yaml = parts[1]
|
517
|
-
|
518
|
-
# Get an array that contains the reference keys in the order they are cited,
|
519
|
-
# without repetitions.
|
520
|
-
keys_in_order = get_keys_in_order(plaintext)
|
521
|
-
|
522
|
-
# Make a list of bibliography enties, sorted in the correct order.
|
523
|
-
bib_entries = make_bib_entries(bibliography_yaml, keys_in_order)
|
524
|
-
|
525
|
-
# Now make the final manuscript by replacing the key-based citations (in the
|
526
|
-
# text) with human-readable citations and place the bibliography at the end.
|
527
|
-
manuscript = make_manuscript(plaintext, bib_entries)
|
528
|
-
|
529
|
-
# Send the manuscript to standard output.
|
530
|
-
STDOUT.puts(manuscript)
|
531
|
-
|
532
|
-
# Now perform some checks for possible user errors and report then on
|
533
|
-
# standard error.
|
534
|
-
user_errors = []
|
535
|
-
user_errors.concat(check_missing_citations(manuscript))
|
536
|
-
user_errors.each {|x| STDERR.puts(x)} # Report the user errors.
|
537
|
-
|
538
|
-
end
|
20
|
+
require 'bibdown_lib'
|
539
21
|
|
540
22
|
# Entry point
|
541
|
-
|
23
|
+
bibdown_main
|