mandown 0.0.7 → 0.0.8
Sign up to get free protection for your applications and to get access to all the features.
- 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
|