citeproc-rb 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README +93 -0
- data/Rakefile +73 -0
- data/TODO +25 -0
- data/VERSION +1 -0
- data/data/locales/locales_en.xml +89 -0
- data/data/locales/locales_nl.xml +96 -0
- data/data/styles/ama.csl +184 -0
- data/data/styles/apa.csl +230 -0
- data/data/styles/apsa.csl +175 -0
- data/data/styles/asa.csl +215 -0
- data/data/styles/chicago-author-date.csl +361 -0
- data/data/styles/chicago-fullnote-bibliography.csl +665 -0
- data/data/styles/chicago-note-bibliography.csl +437 -0
- data/data/styles/chicago-note.csl +383 -0
- data/data/styles/harvard.csl +185 -0
- data/data/styles/ieee.csl +111 -0
- data/data/styles/mhra.csl +317 -0
- data/data/styles/mla.csl +173 -0
- data/data/styles/nature.csl +87 -0
- data/data/styles/nlm.csl +118 -0
- data/examples/citeproc_driver.rb +174 -0
- data/lib/citeproc.rb +28 -0
- data/lib/citeproc/csl.rb +647 -0
- data/lib/citeproc/csl_parser.rb +479 -0
- data/lib/citeproc/csl_processor.rb +485 -0
- data/lib/citeproc/csl_reference.rb +228 -0
- data/lib/citeproc/filters/bibo/bibo.rb +635 -0
- data/lib/citeproc/filters/bibo/bibo_input_filter.rb +242 -0
- data/lib/citeproc/filters/bibo/bibo_utils.rb +75 -0
- data/lib/citeproc/filters/csl_citation/csl_citation.rb +137 -0
- data/lib/citeproc/filters/csl_citation/csl_citation_input_filter.rb +274 -0
- data/lib/citeproc/formatters/base_formatter.rb +115 -0
- data/lib/citeproc/formatters/xhtml_formatter.rb +144 -0
- data/lib/citeproc/input_filter.rb +97 -0
- data/test/fixtures/bibo_test_data.n3 +191 -0
- data/test/fixtures/bibo_test_data.yaml +96 -0
- data/test/fixtures/bibo_test_how_to_cook.n3 +63 -0
- data/test/fixtures/bibo_test_zotero.rdf +129 -0
- data/test/fixtures/csl_test_data.json +62 -0
- data/test/fixtures/csl_test_data.yaml +8 -0
- data/test/fixtures/locales/test_locale_en.xml +89 -0
- data/test/fixtures/styles/test_csl_parse.csl +230 -0
- data/test/fixtures/styles/test_groups.csl +32 -0
- data/test/fixtures/styles/test_names.csl +46 -0
- data/test/fixtures/styles/test_sort.csl +125 -0
- data/test/fixtures/styles/test_text_terms.csl +40 -0
- data/test/test_all.rb +14 -0
- data/test/test_bibo.rb +20 -0
- data/test/test_csl.rb +136 -0
- data/test/test_csl_parser.rb +222 -0
- data/test/test_sample_bibo.rb +82 -0
- metadata +101 -0
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
# == Synopsis
|
|
2
|
+
#
|
|
3
|
+
# Resolves CSL variables to a simple Citation model.
|
|
4
|
+
#
|
|
5
|
+
# == Author
|
|
6
|
+
#
|
|
7
|
+
# Liam Magee
|
|
8
|
+
#
|
|
9
|
+
# == Copyright
|
|
10
|
+
#
|
|
11
|
+
# Copyright (c) 2007, Liam Magee.
|
|
12
|
+
# Licensed under the same terms as Ruby - see http://www.ruby-lang.org/en/LICENSE.txt.
|
|
13
|
+
#
|
|
14
|
+
|
|
15
|
+
module CSL
|
|
16
|
+
class CslInputFilter < Citeproc::InputFilter
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
# Loads the citations from +source+, based on the content_type passed in the +params+.
|
|
20
|
+
def load_citations(source, params)
|
|
21
|
+
io = source.read
|
|
22
|
+
content_type = params[:content_type]
|
|
23
|
+
|
|
24
|
+
# Load the citations from the specified content type
|
|
25
|
+
case content_type.downcase
|
|
26
|
+
when "yaml"
|
|
27
|
+
require 'yaml'
|
|
28
|
+
results = YAML.load(io)
|
|
29
|
+
when "json"
|
|
30
|
+
require 'json'
|
|
31
|
+
results = JSON.parse(io)
|
|
32
|
+
else
|
|
33
|
+
raise RuntimeError.new("Unsupported content-type: " + content_type.inspect + ". Must be either YAML or JSON.")
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
results.each do |key, value|
|
|
37
|
+
citation = load_citation_from_hash(value)
|
|
38
|
+
@citations[key] = citation
|
|
39
|
+
end if results
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
# Loads an individual citation from the +hash+ object
|
|
45
|
+
def load_citation_from_hash(hash)
|
|
46
|
+
citation = Citation.new
|
|
47
|
+
# Much easier, but requires active_support (sudo gem install active_support --include-dependencies)
|
|
48
|
+
# Overkill for just this method?
|
|
49
|
+
if require "active_support"
|
|
50
|
+
hash.each do |k, v|
|
|
51
|
+
citation.send("#{k.underscore}=", v)
|
|
52
|
+
end
|
|
53
|
+
# Long hand... potentially incomplete
|
|
54
|
+
else
|
|
55
|
+
citation.type = hash[:type.to_s]
|
|
56
|
+
citation.title = hash[:title.to_s]
|
|
57
|
+
citation.container_title = hash[:containerTitle.to_s]
|
|
58
|
+
citation.collection_title = hash[:collectionTitle.to_s]
|
|
59
|
+
citation.date_issued = hash[:dateIssued.to_s]
|
|
60
|
+
citation.date_accessed = hash[:dateAccessed.to_s]
|
|
61
|
+
citation.publisher = hash[:publisher.to_s]
|
|
62
|
+
citation.publisher_place = hash[:publisherPlace.to_s]
|
|
63
|
+
citation.issue = hash[:issue.to_s]
|
|
64
|
+
citation.url = hash[:url.to_s]
|
|
65
|
+
citation.pages = hash[:pages.to_s]
|
|
66
|
+
citation.authors = hash[:authors.to_s]
|
|
67
|
+
citation.editors = hash[:editors.to_s]
|
|
68
|
+
end
|
|
69
|
+
citation
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def extract_contributor(role, sort_key = nil)
|
|
75
|
+
contributors = @current_citation.contributors(role, sort_key)
|
|
76
|
+
contributors.each do |contrib|
|
|
77
|
+
yield contrib
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
# Tests the document class, and returns the corresponding CSL type
|
|
84
|
+
def resolve_type
|
|
85
|
+
@current_citation.type
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def extract_date(variable)
|
|
89
|
+
case variable
|
|
90
|
+
when "issued"
|
|
91
|
+
convert_date(@current_citation.date_issued)
|
|
92
|
+
when "event" # Kludgy way of handling event - treat as presentation
|
|
93
|
+
# @current_citation.presented_at.time.start if @current_citation.presented_at and @current_citation.presented_at.time
|
|
94
|
+
when "accessed"
|
|
95
|
+
convert_date(@current_citation.date_accessed)
|
|
96
|
+
when "container"
|
|
97
|
+
# @current_citation.belongs_to.date if @current_citation.belongs_to
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def convert_date(date)
|
|
102
|
+
if date
|
|
103
|
+
date = date + "-01-01" if date.length == 4
|
|
104
|
+
Date.parse(date)
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
# Very simple check on the value of the locator (or, in specific cases, of other document
|
|
110
|
+
# variables) to determine whether
|
|
111
|
+
# It may be be better to simply return the locator value here
|
|
112
|
+
def extract_label(variable)
|
|
113
|
+
singular = true
|
|
114
|
+
if variable == 'page'
|
|
115
|
+
singlular = (@current_citation.pages and @current_citation.pages.include?('-'))
|
|
116
|
+
locator_type = variable
|
|
117
|
+
else
|
|
118
|
+
locator_type = @current_citation.locator_type
|
|
119
|
+
case @current_citation.locator_type
|
|
120
|
+
when 'issue'
|
|
121
|
+
singlular = (@current_citation.issue and @current_citation.issue.include?('-'))
|
|
122
|
+
when 'page'
|
|
123
|
+
singlular = (@current_citation.pages and @current_citation.pages.include?('-'))
|
|
124
|
+
when 'volume'
|
|
125
|
+
singlular = (@current_citation.volume and @current_citation.volume.include?('-'))
|
|
126
|
+
else
|
|
127
|
+
singlular = (@current_citation.locator and @current_citation.locator.include?('-'))
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
return locator_type, singular
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def extract_variable(variable)
|
|
136
|
+
case variable
|
|
137
|
+
|
|
138
|
+
## the primary title for the cited item
|
|
139
|
+
when 'author'
|
|
140
|
+
@current_citation.authors
|
|
141
|
+
|
|
142
|
+
when 'editor'
|
|
143
|
+
@current_citation.editors
|
|
144
|
+
|
|
145
|
+
## the primary title for the cited item
|
|
146
|
+
when 'title'
|
|
147
|
+
@current_citation.title
|
|
148
|
+
|
|
149
|
+
## the secondary title for the cited item; for a book chapter, this
|
|
150
|
+
## would be a book title, for an article the journal title, etc.
|
|
151
|
+
when 'container-title'
|
|
152
|
+
@current_citation.container_title
|
|
153
|
+
|
|
154
|
+
## the tertiary title for the cited item; for example, a series title
|
|
155
|
+
when 'collection-title'
|
|
156
|
+
@current_citation.collection_title
|
|
157
|
+
|
|
158
|
+
## title of a related original version; often useful in cases of translation
|
|
159
|
+
when "original-title"
|
|
160
|
+
@current_citation.title
|
|
161
|
+
|
|
162
|
+
## the name of the publisher
|
|
163
|
+
when "publisher"
|
|
164
|
+
@current_citation.publisher
|
|
165
|
+
|
|
166
|
+
## the location of the publisher
|
|
167
|
+
when "publisher-place"
|
|
168
|
+
@current_citation.publisher_place
|
|
169
|
+
|
|
170
|
+
## the name of the archive
|
|
171
|
+
when "archive"
|
|
172
|
+
# @current_citation.title
|
|
173
|
+
|
|
174
|
+
## the location of the archive
|
|
175
|
+
when "archive-place"
|
|
176
|
+
# @current_citation.title
|
|
177
|
+
|
|
178
|
+
## the location within an archival collection (for example, box and folder)
|
|
179
|
+
when "archive_location"
|
|
180
|
+
# @current_citation.title
|
|
181
|
+
|
|
182
|
+
## the name or title of a related event such as a conference or hearing
|
|
183
|
+
when "event"
|
|
184
|
+
# @current_citation.presented_at.name if @current_citation.presented_at
|
|
185
|
+
|
|
186
|
+
## the location or place for the related event
|
|
187
|
+
when "event-place"
|
|
188
|
+
# @current_citation.presented_at.place.name if @current_citation.presented_at and @current_citation.presented_at.place
|
|
189
|
+
|
|
190
|
+
##
|
|
191
|
+
when "page"
|
|
192
|
+
@current_citation.pages
|
|
193
|
+
|
|
194
|
+
## a description to locate an item within some larger container or
|
|
195
|
+
## collection; a volume or issue number is a kind of locator, for example.
|
|
196
|
+
when "locator"
|
|
197
|
+
@current_citation.locator
|
|
198
|
+
|
|
199
|
+
## version description
|
|
200
|
+
when "version"
|
|
201
|
+
@current_citation.version
|
|
202
|
+
|
|
203
|
+
## volume number for the container periodical
|
|
204
|
+
when "volume"
|
|
205
|
+
@current_citation.volume
|
|
206
|
+
|
|
207
|
+
## refers to the number of items in multi-volume books and such
|
|
208
|
+
when "number-of-volumes"
|
|
209
|
+
# ??
|
|
210
|
+
|
|
211
|
+
## the issue number for the container publication
|
|
212
|
+
when "issue"
|
|
213
|
+
@current_citation.issue
|
|
214
|
+
|
|
215
|
+
##
|
|
216
|
+
when "chapter-number"
|
|
217
|
+
@current_citation.number
|
|
218
|
+
|
|
219
|
+
## medium description (DVD, CD, etc.)
|
|
220
|
+
when "medium"
|
|
221
|
+
@current_citation.format
|
|
222
|
+
|
|
223
|
+
## the (typically publication) status of an item; for example "forthcoming"
|
|
224
|
+
when "status"
|
|
225
|
+
@current_citation.status
|
|
226
|
+
|
|
227
|
+
## an edition description
|
|
228
|
+
when "edition"
|
|
229
|
+
@current_citation.edition
|
|
230
|
+
|
|
231
|
+
##
|
|
232
|
+
when "genre"
|
|
233
|
+
@current_citation.genre
|
|
234
|
+
|
|
235
|
+
## a short inline note, often used to refer to additional details of the resource
|
|
236
|
+
when "note"
|
|
237
|
+
@current_citation.note
|
|
238
|
+
|
|
239
|
+
## notes made by a reader about the content of the resource
|
|
240
|
+
when "annote"
|
|
241
|
+
@current_citation.annote
|
|
242
|
+
|
|
243
|
+
##
|
|
244
|
+
when "abstract"
|
|
245
|
+
@current_citation.abstract
|
|
246
|
+
|
|
247
|
+
##
|
|
248
|
+
when "keyword"
|
|
249
|
+
@current_citation.keyword
|
|
250
|
+
|
|
251
|
+
## a document number; useful for reports and such
|
|
252
|
+
when "number"
|
|
253
|
+
@current_citation.number
|
|
254
|
+
|
|
255
|
+
##
|
|
256
|
+
when "URL"
|
|
257
|
+
@current_citation.uri
|
|
258
|
+
|
|
259
|
+
##
|
|
260
|
+
when "DOI"
|
|
261
|
+
@current_citation.doi
|
|
262
|
+
|
|
263
|
+
##
|
|
264
|
+
when "ISBN"
|
|
265
|
+
@current_citation.isbn10
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
else
|
|
269
|
+
extract_date(variable)
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
end
|
|
273
|
+
end
|
|
274
|
+
end
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# == Synopsis
|
|
2
|
+
#
|
|
3
|
+
# Formats a series of document references according to a given CSL style.
|
|
4
|
+
#
|
|
5
|
+
# == Author
|
|
6
|
+
#
|
|
7
|
+
# Liam Magee
|
|
8
|
+
#
|
|
9
|
+
# == Copyright
|
|
10
|
+
#
|
|
11
|
+
# Copyright (c) 2008, Liam Magee.
|
|
12
|
+
# Licensed under the same terms as Ruby - see http://www.ruby-lang.org/en/LICENSE.txt.
|
|
13
|
+
#
|
|
14
|
+
|
|
15
|
+
module Citeproc
|
|
16
|
+
|
|
17
|
+
class BaseFormatter
|
|
18
|
+
def format(node)
|
|
19
|
+
result = ''
|
|
20
|
+
if node.is_a?(Array)
|
|
21
|
+
node.each do |n|
|
|
22
|
+
tmp = format(n)
|
|
23
|
+
if tmp
|
|
24
|
+
result << tmp
|
|
25
|
+
result << "\n"
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
elsif node
|
|
29
|
+
a = ''
|
|
30
|
+
b = []
|
|
31
|
+
a << delimit_node(node.element, node.results)
|
|
32
|
+
node.children.compact.each{|c| b << format(c) }
|
|
33
|
+
a << delimit_node(node.element, b)
|
|
34
|
+
|
|
35
|
+
result = format_node(node.element, a)
|
|
36
|
+
end
|
|
37
|
+
result
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
private
|
|
42
|
+
|
|
43
|
+
def format_node(formatter, text)
|
|
44
|
+
return text if !formatter.is_a?(Formatting)
|
|
45
|
+
return '' if !text or text.empty?
|
|
46
|
+
results = ''
|
|
47
|
+
|
|
48
|
+
results << formatter.prefix if formatter.prefix and !text.start_with?(formatter.prefix)
|
|
49
|
+
results << '"' if formatter.quotes
|
|
50
|
+
|
|
51
|
+
# Add the actual text
|
|
52
|
+
results << format_text(text, formatter.text_case)
|
|
53
|
+
|
|
54
|
+
results << '"' if formatter.quotes
|
|
55
|
+
results << formatter.suffix if formatter.suffix and !text.end_with?(formatter.suffix)
|
|
56
|
+
|
|
57
|
+
results
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# The following performs direct text changes - should be toggled off for mark-up?
|
|
61
|
+
#lowercase, uppercase, capitalize-first, capitalize-all, title, sentence.
|
|
62
|
+
def format_text(text, textcase)
|
|
63
|
+
case textcase
|
|
64
|
+
when "lowercase"
|
|
65
|
+
text.downcase!
|
|
66
|
+
when "uppercase"
|
|
67
|
+
text.upcase!
|
|
68
|
+
when "capitalize-first"
|
|
69
|
+
text[0] = text[0..0].upcase
|
|
70
|
+
# Need to separate out these cases
|
|
71
|
+
when "capitalize-all", "title", "sentence"
|
|
72
|
+
# Tries a simple exclusion of common words from title capitalisation
|
|
73
|
+
# Suffers from a lack of internationalisation...
|
|
74
|
+
text = text.split(' ').collect{|t|
|
|
75
|
+
t.capitalize unless t == text.split(' ')[0] and ['and', 'the', 'a', 'of', 'by', 'to', 'at'].include?(t)
|
|
76
|
+
}.join(' ')
|
|
77
|
+
end
|
|
78
|
+
text
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def delimit_node(node, elements)
|
|
83
|
+
results = ""
|
|
84
|
+
clean = elements.compact.reject{|e| e if e.to_s.strip.empty?}
|
|
85
|
+
len = clean.length - 1
|
|
86
|
+
delim = node.is_a?(Delimiter)
|
|
87
|
+
(0..len).each do |i|
|
|
88
|
+
case i
|
|
89
|
+
when 0
|
|
90
|
+
# Do nothing
|
|
91
|
+
when len
|
|
92
|
+
if delim
|
|
93
|
+
if node.delimiter_precedes_last and node.delimiter_precedes_last == "never"
|
|
94
|
+
# Still do nothing
|
|
95
|
+
elsif delim and node.delimiter
|
|
96
|
+
results << node.delimiter
|
|
97
|
+
end
|
|
98
|
+
if node.and == "text"
|
|
99
|
+
results.strip!
|
|
100
|
+
results << " and "
|
|
101
|
+
elsif node.and == "symbol"
|
|
102
|
+
results.strip!
|
|
103
|
+
results << " & "
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
else
|
|
107
|
+
results << node.delimiter if delim and node.delimiter
|
|
108
|
+
end
|
|
109
|
+
# Finally, add the content
|
|
110
|
+
results << clean[i].to_s
|
|
111
|
+
end
|
|
112
|
+
results
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# == Synopsis
|
|
2
|
+
#
|
|
3
|
+
# Formats a series of document references according to a given CSL style.
|
|
4
|
+
#
|
|
5
|
+
# == Author
|
|
6
|
+
#
|
|
7
|
+
# Liam Magee
|
|
8
|
+
#
|
|
9
|
+
# == Copyright
|
|
10
|
+
#
|
|
11
|
+
# Copyright (c) 2008, Liam Magee.
|
|
12
|
+
# Licensed under the same terms as Ruby - see http://www.ruby-lang.org/en/LICENSE.txt.
|
|
13
|
+
#
|
|
14
|
+
|
|
15
|
+
module Citeproc
|
|
16
|
+
|
|
17
|
+
class XhtmlFormatter
|
|
18
|
+
|
|
19
|
+
def format(node)
|
|
20
|
+
result = ''
|
|
21
|
+
if node.is_a?(Array)
|
|
22
|
+
node.each do |n|
|
|
23
|
+
tmp = format(n)
|
|
24
|
+
if tmp
|
|
25
|
+
result << "<div>"
|
|
26
|
+
result << tmp
|
|
27
|
+
result << "</div>\n"
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
elsif node
|
|
31
|
+
a = ''
|
|
32
|
+
b = []
|
|
33
|
+
a << delimit_node(node.element, node.results)
|
|
34
|
+
node.children.compact.each{|c| b << format(c) }
|
|
35
|
+
a << delimit_node(node.element, b)
|
|
36
|
+
|
|
37
|
+
result = format_node(node.element, a)
|
|
38
|
+
end
|
|
39
|
+
result
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
private
|
|
44
|
+
|
|
45
|
+
def format_node(formatter, text)
|
|
46
|
+
return text if !formatter.is_a?(Formatting)
|
|
47
|
+
return '' if !text or text.empty?
|
|
48
|
+
results = ''
|
|
49
|
+
|
|
50
|
+
text_content = format_text(text, formatter.text_case)
|
|
51
|
+
already_spanned = text_content.starts_with?("<span") and text_content.ends_with?("</span>")
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
if !already_spanned
|
|
55
|
+
# Note: these attributes should only apply to certain kinds of formatters, i.e. those based on mark-up
|
|
56
|
+
results << '<span' # Could be block/inline/div - needs to be conditional on both 'display' attribute and mark-up variant (XHTML, XSL-FO)
|
|
57
|
+
style = ''
|
|
58
|
+
style << "font-family: #{formatter.font_family}; " if formatter.font_family
|
|
59
|
+
style << "font-style: #{formatter.font_style}; " if formatter.font_style
|
|
60
|
+
style << "font-variant: #{formatter.font_variant}; " if formatter.font_variant
|
|
61
|
+
style << "font-weight: #{formatter.font_weight}; " if formatter.font_weight
|
|
62
|
+
style << "text-decoration: #{formatter.text_decoration}; " if formatter.text_decoration
|
|
63
|
+
style << "text-transform: #{formatter.text_transform}; " if formatter.text_transform
|
|
64
|
+
style << "vertical-align: #{formatter.vertical_align}; " if formatter.vertical_align
|
|
65
|
+
style << "enforce-case: #{formatter.enforce_case}; " if formatter.enforce_case
|
|
66
|
+
display = formatter.formatting[:display.to_s]
|
|
67
|
+
style << "display: #{display}; " if display
|
|
68
|
+
style << "quotes: #{formatter.quotes}; " if formatter.quotes
|
|
69
|
+
results << %Q' style="#{style}"' if !style.empty?
|
|
70
|
+
results << ">"
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
results << formatter.prefix if formatter.prefix and !text.start_with?(formatter.prefix)
|
|
74
|
+
results << '"' if formatter.quotes
|
|
75
|
+
|
|
76
|
+
# Add the actual text
|
|
77
|
+
results << text_content
|
|
78
|
+
|
|
79
|
+
results << '"' if formatter.quotes
|
|
80
|
+
results << formatter.suffix if formatter.suffix and !text.end_with?(formatter.suffix)
|
|
81
|
+
|
|
82
|
+
if !already_spanned
|
|
83
|
+
results << "</span>"
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
results
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# The following performs direct text changes - should be toggled off for mark-up?
|
|
90
|
+
#lowercase, uppercase, capitalize-first, capitalize-all, title, sentence.
|
|
91
|
+
def format_text(text, textcase)
|
|
92
|
+
case textcase
|
|
93
|
+
when "lowercase"
|
|
94
|
+
text.downcase!
|
|
95
|
+
when "uppercase"
|
|
96
|
+
text.upcase!
|
|
97
|
+
when "capitalize-first"
|
|
98
|
+
text[0] = text[0..0].upcase
|
|
99
|
+
# Need to separate out these cases
|
|
100
|
+
when "capitalize-all", "title", "sentence"
|
|
101
|
+
# Tries a simple exclusion of common words from title capitalisation
|
|
102
|
+
# Suffers from a lack of internationalisation...
|
|
103
|
+
text = text.split(' ').collect{|t|
|
|
104
|
+
t.capitalize unless t == text.split(' ')[0] and ['and', 'the', 'a', 'of', 'by', 'to', 'at'].include?(t)
|
|
105
|
+
}.join(' ')
|
|
106
|
+
end
|
|
107
|
+
text
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def delimit_node(node, elements)
|
|
112
|
+
results = ""
|
|
113
|
+
clean = elements.compact.reject{|e| e if e.to_s.strip.empty?}
|
|
114
|
+
len = clean.length - 1
|
|
115
|
+
delim = node.is_a?(Delimiter)
|
|
116
|
+
(0..len).each do |i|
|
|
117
|
+
case i
|
|
118
|
+
when 0
|
|
119
|
+
# Do nothing
|
|
120
|
+
when len
|
|
121
|
+
if delim
|
|
122
|
+
if node.delimiter_precedes_last and node.delimiter_precedes_last == "never"
|
|
123
|
+
# Still do nothing
|
|
124
|
+
elsif delim and node.delimiter
|
|
125
|
+
results << node.delimiter
|
|
126
|
+
end
|
|
127
|
+
if node.and == "text"
|
|
128
|
+
results.strip!
|
|
129
|
+
results << " and "
|
|
130
|
+
elsif node.and == "symbol"
|
|
131
|
+
results.strip!
|
|
132
|
+
results << " & "
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
else
|
|
136
|
+
results << node.delimiter if delim and node.delimiter
|
|
137
|
+
end
|
|
138
|
+
# Finally, add the content
|
|
139
|
+
results << clean[i].to_s
|
|
140
|
+
end
|
|
141
|
+
results
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
end
|