citeproc-ruby 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.md +78 -0
- data/lib/citeproc.rb +100 -0
- data/lib/citeproc/bibliography.rb +57 -0
- data/lib/citeproc/data.rb +149 -0
- data/lib/citeproc/date.rb +133 -0
- data/lib/citeproc/formatter.rb +38 -0
- data/lib/citeproc/item.rb +53 -0
- data/lib/citeproc/name.rb +284 -0
- data/lib/citeproc/processor.rb +166 -0
- data/lib/citeproc/selector.rb +61 -0
- data/lib/citeproc/variable.rb +82 -0
- data/lib/citeproc/version.rb +3 -0
- data/lib/csl/locale.rb +223 -0
- data/lib/csl/node.rb +72 -0
- data/lib/csl/nodes.rb +1364 -0
- data/lib/csl/renderer.rb +88 -0
- data/lib/csl/sort.rb +53 -0
- data/lib/csl/style.rb +110 -0
- data/lib/csl/term.rb +124 -0
- data/lib/extensions/core.rb +43 -0
- data/lib/plugins/filters/bibtex.rb +12 -0
- data/lib/plugins/formats/default.rb +134 -0
- data/lib/plugins/formats/html.rb +67 -0
- data/lib/support/attributes.rb +99 -0
- data/lib/support/tree.rb +80 -0
- data/resource/locale/locales-af-ZA.xml +304 -0
- data/resource/locale/locales-ar-AR.xml +304 -0
- data/resource/locale/locales-bg-BG.xml +304 -0
- data/resource/locale/locales-ca-AD.xml +304 -0
- data/resource/locale/locales-cs-CZ.xml +304 -0
- data/resource/locale/locales-da-DK.xml +304 -0
- data/resource/locale/locales-de-AT.xml +304 -0
- data/resource/locale/locales-de-CH.xml +304 -0
- data/resource/locale/locales-de-DE.xml +332 -0
- data/resource/locale/locales-el-GR.xml +303 -0
- data/resource/locale/locales-en-US.xml +313 -0
- data/resource/locale/locales-es-ES.xml +304 -0
- data/resource/locale/locales-et-EE.xml +304 -0
- data/resource/locale/locales-fr-FR.xml +304 -0
- data/resource/locale/locales-he-IL.xml +304 -0
- data/resource/locale/locales-hu-HU.xml +304 -0
- data/resource/locale/locales-is-IS.xml +304 -0
- data/resource/locale/locales-it-IT.xml +304 -0
- data/resource/locale/locales-ja-JP.xml +304 -0
- data/resource/locale/locales-kh-KH.xml +303 -0
- data/resource/locale/locales-ko-KR.xml +304 -0
- data/resource/locale/locales-mn-MN.xml +304 -0
- data/resource/locale/locales-nb-NO.xml +304 -0
- data/resource/locale/locales-nl-NL.xml +304 -0
- data/resource/locale/locales-nn-NO.xml +304 -0
- data/resource/locale/locales-pl-PL.xml +304 -0
- data/resource/locale/locales-pt-BR.xml +304 -0
- data/resource/locale/locales-pt-PT.xml +304 -0
- data/resource/locale/locales-ro-RO.xml +304 -0
- data/resource/locale/locales-ru-RU.xml +304 -0
- data/resource/locale/locales-sk-SK.xml +304 -0
- data/resource/locale/locales-sl-SI.xml +304 -0
- data/resource/locale/locales-sr-RS.xml +304 -0
- data/resource/locale/locales-sv-SE.xml +304 -0
- data/resource/locale/locales-th-TH.xml +304 -0
- data/resource/locale/locales-tr-TR.xml +304 -0
- data/resource/locale/locales-uk-UA.xml +304 -0
- data/resource/locale/locales-vi-VN.xml +304 -0
- data/resource/locale/locales-zh-CN.xml +304 -0
- data/resource/locale/locales-zh-TW.xml +304 -0
- data/resource/schema/csl-categories.rnc +39 -0
- data/resource/schema/csl-data.rnc +98 -0
- data/resource/schema/csl-terms.rnc +106 -0
- data/resource/schema/csl-types.rnc +39 -0
- data/resource/schema/csl-variables.rnc +182 -0
- data/resource/schema/csl.rnc +941 -0
- data/resource/style/acta-materialia-x.csl +128 -0
- data/resource/style/advanced-engineering-materials-x.csl +121 -0
- data/resource/style/ama.csl +185 -0
- data/resource/style/ama2-x.csl +179 -0
- data/resource/style/apa-x.csl +324 -0
- data/resource/style/apa.csl +254 -0
- data/resource/style/apsa-x.csl +163 -0
- data/resource/style/apsa.csl +176 -0
- data/resource/style/asa-x.csl +203 -0
- data/resource/style/asa.csl +216 -0
- data/resource/style/asm-journals-x.csl +131 -0
- data/resource/style/bibtex-x2.csl +175 -0
- data/resource/style/bluebook-demo-x.csl +392 -0
- data/resource/style/bluebook-demo.csl +942 -0
- data/resource/style/chicago-author-date-listing.csl +434 -0
- data/resource/style/chicago-author-date.csl +369 -0
- data/resource/style/chicago-fullnote-bibliography-bb.csl +928 -0
- data/resource/style/chicago-fullnote-bibliography.csl +695 -0
- data/resource/style/chicago-note-bibliography.csl +446 -0
- data/resource/style/chicago-note.csl +388 -0
- data/resource/style/greek-chicago-x.csl +1182 -0
- data/resource/style/harvard1-institution-italic.csl +190 -0
- data/resource/style/harvard1.csl +181 -0
- data/resource/style/ieee.csl +129 -0
- data/resource/style/mhra-x.csl +312 -0
- data/resource/style/mhra.csl +390 -0
- data/resource/style/mhra_note_without_bibliography-x.csl +330 -0
- data/resource/style/mhra_note_without_bibliography.csl +338 -0
- data/resource/style/mla-x.csl +178 -0
- data/resource/style/mla.csl +189 -0
- data/resource/style/nature-x.csl +81 -0
- data/resource/style/nature.csl +88 -0
- data/resource/style/nlm.csl +117 -0
- data/spec/citeproc/bibliography_spec.rb +45 -0
- data/spec/citeproc/citeproc_spec.rb +76 -0
- data/spec/citeproc/date_spec.rb +85 -0
- data/spec/citeproc/formatter_spec.rb +101 -0
- data/spec/citeproc/item_spec.rb +71 -0
- data/spec/citeproc/name_spec.rb +30 -0
- data/spec/citeproc/processor_spec.rb +61 -0
- data/spec/citeproc/selector_spec.rb +82 -0
- data/spec/citeproc/variable_spec.rb +69 -0
- data/spec/csl/locale_spec.rb +208 -0
- data/spec/csl/node_spec.rb +25 -0
- data/spec/csl/nodes_spec.rb +140 -0
- data/spec/csl/style_spec.rb +62 -0
- data/spec/csl/term_spec.rb +56 -0
- data/spec/fixtures/dates.yaml +80 -0
- data/spec/fixtures/names.yaml +115 -0
- data/spec/fixtures/nodes.yaml +245 -0
- data/spec/spec_helper.rb +18 -0
- data/spec/support/attributes_spec.rb +39 -0
- data/spec/support/tree_spec.rb +163 -0
- metadata +264 -0
data/README.md
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
CiteProc-Ruby
|
|
2
|
+
=============
|
|
3
|
+
|
|
4
|
+
CiteProc-Ruby is a CSL 1.0 ([Citation Style Language](http://citationstyles.org/))
|
|
5
|
+
Processor written in Ruby.
|
|
6
|
+
|
|
7
|
+
A word of caution: this release of CiteProc-Ruby is purely experimental; the API
|
|
8
|
+
is not complete and liable to change frequently. This release is expected to
|
|
9
|
+
work in Ruby version 1.9.2.
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
Quickstart
|
|
13
|
+
----------
|
|
14
|
+
|
|
15
|
+
$ [sudo] gem install citeproc-ruby
|
|
16
|
+
$ irb
|
|
17
|
+
>> require 'citeproc'
|
|
18
|
+
>> book = {
|
|
19
|
+
'author' => [{ 'given' => 'Edgar Allen', 'family' => 'Poe' }],
|
|
20
|
+
'title' => 'Poetry, Tales, and Selected Essays',
|
|
21
|
+
'type' => 'book',
|
|
22
|
+
'issued' => { 'date-parts' => [[1996]] },
|
|
23
|
+
'editor' => [{ 'family' => 'Quinn', 'given' => 'Patrick F.'}, { 'family' => 'Thompson', 'given' => 'G.R.' }],
|
|
24
|
+
'publisher' => 'Library of America',
|
|
25
|
+
'publisher-place' => 'New York'
|
|
26
|
+
}
|
|
27
|
+
>> CiteProc.process(book)
|
|
28
|
+
=> "Poe, E. A. (1996). Poetry, Tales, and Selected Essays. (P. F. Quinn & G. R. Thompson, Eds.). New York: Library of America."
|
|
29
|
+
>> CiteProc.process(book, :format => :html)
|
|
30
|
+
=> "Poe, E. A. (1996). <i>Poetry, Tales, and Selected Essays</i>. (P. F. Quinn & G. R. Thompson, Eds.). New York: Library of America."
|
|
31
|
+
>> CiteProc.process(book, :mode => :citation)
|
|
32
|
+
=> ["(Poe, 1996)"]
|
|
33
|
+
>> CiteProc.process(book, :style => "https://github.com/citation-style-language/styles/raw/master/chicago-author-date.csl")
|
|
34
|
+
=> "Poe, Edgar Allen. 1996. Poetry, Tales, and Selected Essays. Ed. Patrick F. Quinn and G.R. Thompson. New York: Library of America."
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
The RSpec examples are a valuable resource of usage examples.
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
Credits
|
|
41
|
+
-------
|
|
42
|
+
|
|
43
|
+
CiteProc-Ruby was written by [Sylvester Keil](http://sylvester.keil.or.at);
|
|
44
|
+
thanks to the excellent documentation and specifications of the
|
|
45
|
+
[CSL](http://citationstyles.org), [citeproc-js](http://bitbucket.org/fbennett/citeproc-js/wiki/Home),
|
|
46
|
+
the [citeproc-test suite](https://bitbucket.org/bdarcus/citeproc-test), and the
|
|
47
|
+
kind feedback and support at the [xbiblio mailing list](http://sourceforge.net/mail/?group_id=117435).
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
License
|
|
51
|
+
-------
|
|
52
|
+
|
|
53
|
+
Copyright 2009-2011 Sylvester Keil. All rights reserved.
|
|
54
|
+
|
|
55
|
+
Redistribution and use in source and binary forms, with or without
|
|
56
|
+
modification, are permitted provided that the following conditions are met:
|
|
57
|
+
|
|
58
|
+
1. Redistributions of source code must retain the above copyright notice,
|
|
59
|
+
this list of conditions and the following disclaimer.
|
|
60
|
+
|
|
61
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
62
|
+
this list of conditions and the following disclaimer in the documentation
|
|
63
|
+
and/or other materials provided with the distribution.
|
|
64
|
+
|
|
65
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER ``AS IS'' AND ANY EXPRESS OR
|
|
66
|
+
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
67
|
+
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
|
68
|
+
EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
|
69
|
+
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
70
|
+
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
71
|
+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
|
72
|
+
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
73
|
+
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
|
74
|
+
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
75
|
+
|
|
76
|
+
The views and conclusions contained in the software and documentation are
|
|
77
|
+
those of the authors and should not be interpreted as representing official
|
|
78
|
+
policies, either expressed or implied, of the copyright holder.
|
data/lib/citeproc.rb
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
$:.unshift(File.dirname(__FILE__)) unless
|
|
2
|
+
$:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
|
3
|
+
|
|
4
|
+
require 'open-uri'
|
|
5
|
+
|
|
6
|
+
require 'logging'
|
|
7
|
+
require 'nokogiri'
|
|
8
|
+
require 'json'
|
|
9
|
+
|
|
10
|
+
#require 'activesupport'
|
|
11
|
+
|
|
12
|
+
require 'unicode_utils/upcase'
|
|
13
|
+
require 'unicode_utils/downcase'
|
|
14
|
+
|
|
15
|
+
module CiteProc
|
|
16
|
+
|
|
17
|
+
@log = Logging.logger[self.name]
|
|
18
|
+
@log.add_appenders(Logging.appenders.stderr)
|
|
19
|
+
|
|
20
|
+
@log.level = ENV.has_key?('DEBUG') ? :debug : :info
|
|
21
|
+
|
|
22
|
+
class << self
|
|
23
|
+
def log(*args)
|
|
24
|
+
return @log if args.empty?
|
|
25
|
+
|
|
26
|
+
level, message, exception = args
|
|
27
|
+
|
|
28
|
+
@log.send(level, [message, exception && exception.message || nil].compact.join(': '))
|
|
29
|
+
@log.debug exception.backtrace[0,10].join("\n\t") unless exception.nil?
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Load debugger
|
|
36
|
+
require 'ruby-debug'
|
|
37
|
+
Debugger.start
|
|
38
|
+
|
|
39
|
+
require 'extensions/core'
|
|
40
|
+
require 'support/attributes'
|
|
41
|
+
require 'support/tree'
|
|
42
|
+
|
|
43
|
+
require 'csl/node'
|
|
44
|
+
require 'csl/term'
|
|
45
|
+
require 'csl/locale'
|
|
46
|
+
require 'csl/nodes'
|
|
47
|
+
require 'csl/sort'
|
|
48
|
+
require 'csl/renderer'
|
|
49
|
+
require 'csl/style'
|
|
50
|
+
|
|
51
|
+
require 'citeproc/version'
|
|
52
|
+
require 'citeproc/variable'
|
|
53
|
+
require 'citeproc/name'
|
|
54
|
+
require 'citeproc/date'
|
|
55
|
+
require 'citeproc/data'
|
|
56
|
+
require 'citeproc/selector'
|
|
57
|
+
require 'citeproc/item'
|
|
58
|
+
require 'citeproc/bibliography'
|
|
59
|
+
require 'citeproc/formatter'
|
|
60
|
+
require 'citeproc/processor'
|
|
61
|
+
|
|
62
|
+
# Load filter and format plugins
|
|
63
|
+
Dir.glob("#{File.expand_path('..', __FILE__)}/plugins/formats/*.rb").each do |format|
|
|
64
|
+
require format
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
require 'plugins/formats/default'
|
|
68
|
+
|
|
69
|
+
Dir.glob("#{File.expand_path('..', __FILE__)}/plugins/filters/*.rb").each do |format|
|
|
70
|
+
require format
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
# Top-level CSL utility functions
|
|
75
|
+
|
|
76
|
+
module CiteProc
|
|
77
|
+
|
|
78
|
+
module_function
|
|
79
|
+
|
|
80
|
+
def default_format; Format.default; end
|
|
81
|
+
|
|
82
|
+
def process(*arguments, &block); Processor.process(*arguments, &block); end
|
|
83
|
+
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
module CSL
|
|
87
|
+
|
|
88
|
+
module_function
|
|
89
|
+
|
|
90
|
+
def default_locale
|
|
91
|
+
Locale.new(Locale.default)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def default_style
|
|
95
|
+
Style.new(Style.default)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def process(*arguments, &block); CiteProc.process(*arguments, &block); end
|
|
99
|
+
|
|
100
|
+
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
module CiteProc
|
|
2
|
+
|
|
3
|
+
# A bibliography is an array of bibliographic entries and, optionally,
|
|
4
|
+
# a list of errors. The bibliography should be format agnostic; it is
|
|
5
|
+
# simply encapsulates two lists.
|
|
6
|
+
class Bibliography
|
|
7
|
+
|
|
8
|
+
def initialize(*args)
|
|
9
|
+
args.each { |argument| parse_argument(argument) }
|
|
10
|
+
|
|
11
|
+
yield self if block_given?
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def data; @data ||= []; end
|
|
15
|
+
def errors; @errors ||= []; end
|
|
16
|
+
def options; @options ||= {}; end
|
|
17
|
+
|
|
18
|
+
# @data proxy
|
|
19
|
+
[:[], :[]=, :<<, :map, :each, :empty?, :push, :pop, :unshift, :+, :concat].each do |method_id|
|
|
20
|
+
define_method method_id do |*args, &block|
|
|
21
|
+
@data.send(method_id, *args, &block)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def to_json
|
|
26
|
+
[options.merge('bibliography-errors' => errors), data].to_json
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def to_s
|
|
30
|
+
[options['bibstart'] || '<div class="csl-bib-body">', data.map { |d| " <div class=\"csl-entry\">#{d}</div>" }, options['bibend'] || '</div>'].flatten.join("\n")
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
protected
|
|
34
|
+
|
|
35
|
+
def parse_argument(argument)
|
|
36
|
+
case
|
|
37
|
+
when argument.is_a?(String)
|
|
38
|
+
parse_argument(JSON.parse(argument))
|
|
39
|
+
when argument.is_a?(Hash)
|
|
40
|
+
parse_attributes(argument)
|
|
41
|
+
when argument.is_a?(Array) && argument.length == 2 && argument[0].is_a?(Hash) && argument[1].is_a?(Array)
|
|
42
|
+
parse_attributes(argument[0])
|
|
43
|
+
@data = argument[1]
|
|
44
|
+
when argument.is_a?(Array)
|
|
45
|
+
@data = argument
|
|
46
|
+
else
|
|
47
|
+
CiteProc.log.warn "failed to initialize Bibliography from argument #{ argument.inspect }." unless argument.nil?
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def parse_attributes(attributes)
|
|
52
|
+
@errors = attributes.delete('bibliography-errors') || []
|
|
53
|
+
@options = {}.merge(attributes)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
module CiteProc
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
# == CiteProc::Data
|
|
5
|
+
#
|
|
6
|
+
# A minimal citation data object, used as input by both the
|
|
7
|
+
# processCitationCluster() and appendCitationCluster() command, has the
|
|
8
|
+
# following form:
|
|
9
|
+
#
|
|
10
|
+
# {
|
|
11
|
+
# "citationItems": [ { "id": "ITEM-1" } ],
|
|
12
|
+
# "properties": {"noteIndex": 1 }
|
|
13
|
+
# }
|
|
14
|
+
#
|
|
15
|
+
# The citationItems array is a list of one or more citation item objects,
|
|
16
|
+
# each containing an id used to retrieve the bibliographic details of the
|
|
17
|
+
# target resource. A citation item object may contain one or more
|
|
18
|
+
# additional optional values:
|
|
19
|
+
#
|
|
20
|
+
# * locator: a string identifying a page number or other pinpoint location
|
|
21
|
+
# or range within the resource;
|
|
22
|
+
# * label: a label type, indicating whether the locator is to a page, a
|
|
23
|
+
# chapter, or other subdivision of the target resource. Valid labels are
|
|
24
|
+
# defined in the link CSL specification.
|
|
25
|
+
# * suppress-author: if true, author names will not be included in the
|
|
26
|
+
# citation output for this cite;
|
|
27
|
+
# * author-only: if true, only the author name will be included in the
|
|
28
|
+
# citation output for this cite -- this optional parameter provides a
|
|
29
|
+
# means for certain demanding styles that require the processor output
|
|
30
|
+
# to be divided between the main text and a footnote.
|
|
31
|
+
# * prefix: a string to print before this cite item;
|
|
32
|
+
# * suffix: a string to print after this cite item.
|
|
33
|
+
#
|
|
34
|
+
# In the properties portion of a citation, the noteIndex value indicates
|
|
35
|
+
# the footnote number in which the citation is located within the
|
|
36
|
+
# document. Citations within the main text of the document have a
|
|
37
|
+
# noteIndex of zero.
|
|
38
|
+
#
|
|
39
|
+
# The processor will add a number of data items to a citation during
|
|
40
|
+
# processing. Values added at the top level of the citation structure
|
|
41
|
+
# include:
|
|
42
|
+
#
|
|
43
|
+
# * citationID: A unique ID assigned to the citation, for internal use by
|
|
44
|
+
# the processor. This ID may be assigned by the calling application, but
|
|
45
|
+
# it must uniquely identify the citation, and it must not be changed
|
|
46
|
+
# during processing or during an editing session.
|
|
47
|
+
# * sortedItems: This is an array of citation objects and accompanying
|
|
48
|
+
# bibliographic data objects, sorted as required by the configured
|
|
49
|
+
# style. Calling applications should not need to access the data in this
|
|
50
|
+
# array directly.
|
|
51
|
+
#
|
|
52
|
+
# Values added to individual citation item objects may include:
|
|
53
|
+
#
|
|
54
|
+
# * sortkeys: an array of sort keys used by the processor to produce the
|
|
55
|
+
# sorted list in sortedItems. Calling applications should not need to
|
|
56
|
+
# touch this array directly.
|
|
57
|
+
# * position: an integer flag that indicates whether the cite item should
|
|
58
|
+
# be rendered as a first reference, an immediately-following reference
|
|
59
|
+
# (i.e. ibid), an immediately-following reference with locator
|
|
60
|
+
# information, or a subsequent reference.
|
|
61
|
+
# * first-reference-note-number: the number of the noteIndex of the first
|
|
62
|
+
# reference to this resource in the document.
|
|
63
|
+
# * near-note: a boolean flag indicating whether another reference to this
|
|
64
|
+
# resource can be found within a specific number of notes, counting back
|
|
65
|
+
# from the current position. What is "near" in this sense is
|
|
66
|
+
# style-dependent.
|
|
67
|
+
# * unsorted: a boolean flag indicating whether sorting imposed by the
|
|
68
|
+
# style should be suspended for this citation. When true, cites are
|
|
69
|
+
# rendered in the order in which they are presented in citationItems.
|
|
70
|
+
#
|
|
71
|
+
class CitationData
|
|
72
|
+
include Support::Attributes
|
|
73
|
+
|
|
74
|
+
attr_fields %w{ citation-id citation-items properites sorted-items }
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def initialize(attributes={})
|
|
78
|
+
|
|
79
|
+
self.key_filter = Hash.new do |hash, key|
|
|
80
|
+
hash[key] = key.to_s.gsub(/([[:lower:]])([[:upper:]])/, '\1-\2').downcase
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
merge!(attributes)
|
|
84
|
+
|
|
85
|
+
yield self if block_given?
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# @returns a list of citation data
|
|
89
|
+
def self.parse(argument)
|
|
90
|
+
return [] if argument.nil?
|
|
91
|
+
argument = [argument] unless argument.kind_of?(Array)
|
|
92
|
+
argument.map { |d| CitationData.new(d) }
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
#
|
|
96
|
+
# Merges the argument into the citation data. The argument can be a list
|
|
97
|
+
# of citation items (hashes), a single citation item (hash), another
|
|
98
|
+
# citation data instance or hash, or a single id of a citation item.
|
|
99
|
+
#
|
|
100
|
+
def merge!(argument)
|
|
101
|
+
case
|
|
102
|
+
when argument.is_a?(Array) && argument.map(&:class).uniq == [Hash]
|
|
103
|
+
super('citation-items' => argument.map { |argument| Item.new(argument) })
|
|
104
|
+
|
|
105
|
+
when argument.is_a?(Array) && (argument.empty? || argument.map(&:class).uniq == [Item])
|
|
106
|
+
super('citation-items' => argument)
|
|
107
|
+
|
|
108
|
+
when argument.is_a?(Hash)
|
|
109
|
+
argument.has_key?('id') ? super('citation-items' => [Item.new(argument)]) : super(argument)
|
|
110
|
+
|
|
111
|
+
when argument.is_a?(String) || argument.is_a?(Symbol)
|
|
112
|
+
super('citation-items' => [{ 'id' => argument.to_s }])
|
|
113
|
+
|
|
114
|
+
when argument.is_a?(CitationData)
|
|
115
|
+
super(argument.attributes)
|
|
116
|
+
|
|
117
|
+
else
|
|
118
|
+
raise(ArgumentError, "unable to merge #{argument.inspect} into citation data")
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def citation_items
|
|
123
|
+
attributes['citation-items'] ||= []
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def populate!(items)
|
|
127
|
+
citation_items.each { |item| item.reverse_merge!(items[item.id.to_s]) }
|
|
128
|
+
self
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def properties
|
|
132
|
+
self.attributes['properties'] ||= {}
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
[[:items, :citation_items], [:id, :citation_id]].each do |a, m|
|
|
136
|
+
alias_method a, m
|
|
137
|
+
alias_method "#{a}=", "#{m}="
|
|
138
|
+
alias_method "#{a}?", "#{m}?"
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
[:each, :map, :empty?, :first, :last, :sort].each do |method_id|
|
|
142
|
+
define_method method_id do |*args, &block|
|
|
143
|
+
self.items.send(method_id, *args, &block)
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
end
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
require 'date'
|
|
2
|
+
|
|
3
|
+
module CiteProc
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
# == Date Variables
|
|
7
|
+
#
|
|
8
|
+
# Date objects wrap an underlying JavaScript object, within which the
|
|
9
|
+
# "date-parts" element is a nested JavaScript array containing a start date
|
|
10
|
+
# and optional end date, each of which consists of a year, an optional month
|
|
11
|
+
# and an optional day, in that order if present. Additionally, the string
|
|
12
|
+
# fields "season", "literal", as well as the boolean field "circa" are
|
|
13
|
+
# supported.
|
|
14
|
+
#
|
|
15
|
+
class Date < Variable
|
|
16
|
+
|
|
17
|
+
attr_fields %w{ date-parts season circa literal }
|
|
18
|
+
|
|
19
|
+
Variable.date_fields.each { |field| Variable.types[field] = Date }
|
|
20
|
+
|
|
21
|
+
[:year, :month, :day].each_with_index do |method_id, index|
|
|
22
|
+
define_method method_id do
|
|
23
|
+
date_parts[0].nil? ? nil : date_parts[0][index]
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
define_method [method_id, '='].join do |value|
|
|
27
|
+
date_parts[0] = [] if date_parts[0].nil?
|
|
28
|
+
date_parts[0][index] = value.to_i
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def defaults
|
|
33
|
+
Hash['delimiter', '-']
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def parse!(argument)
|
|
37
|
+
return super unless argument.is_a?(::Date) || argument.is_a?(String)
|
|
38
|
+
parse_date!(date)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def merge!(argument)
|
|
42
|
+
case
|
|
43
|
+
when argument.has_key?('raw')
|
|
44
|
+
parse_date!(argument.delete('raw'))
|
|
45
|
+
argument.delete('date-parts')
|
|
46
|
+
when argument.has_key?('date-parts')
|
|
47
|
+
argument['date-parts'].map! { |parts| parts.map(&:to_i) }
|
|
48
|
+
end
|
|
49
|
+
super
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def parse_date!(date)
|
|
53
|
+
# TODO find out what the Ruby parser can do
|
|
54
|
+
date = ::Date.parse(date) unless date.is_a?(::Date)
|
|
55
|
+
date_parts[0] = [date.year, date.month, date.day]
|
|
56
|
+
self
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def date_parts
|
|
60
|
+
attributes['date-parts'] ||= []
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
alias :parts :date_parts
|
|
64
|
+
alias :parts= :date_parts=
|
|
65
|
+
|
|
66
|
+
def range?
|
|
67
|
+
parts[1] && !parts[1].empty?
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def open_range?
|
|
71
|
+
self.range? && parts[1].uniq == [0]
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def uncertain!; self['circa'] = true; end
|
|
75
|
+
|
|
76
|
+
def bc?; year && year < 0; end
|
|
77
|
+
def ad?; !bc? && year < 1000; end
|
|
78
|
+
|
|
79
|
+
alias :uncertain? :circa?
|
|
80
|
+
|
|
81
|
+
def from
|
|
82
|
+
parts[0] || []
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def to
|
|
86
|
+
Date.new('date-parts' => [parts[1] || []])
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# @returns a value in 0..3 depending on how many of the date parts in the
|
|
90
|
+
# range match.
|
|
91
|
+
def range_match
|
|
92
|
+
parts[0].zip(parts[1] || []).take_while { |p| p[0] == p[1] }.length
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def display_parts
|
|
96
|
+
rm = range_match
|
|
97
|
+
|
|
98
|
+
case
|
|
99
|
+
when !range? || open_range?
|
|
100
|
+
[%w{day month year}, []]
|
|
101
|
+
when rm == 1
|
|
102
|
+
[%w{day month}, %w{day month year} ]
|
|
103
|
+
when rm == 2
|
|
104
|
+
[%w{day}, %w{day month year} ]
|
|
105
|
+
else
|
|
106
|
+
[%w{day month year}, %w{day month year} ]
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def display(options={})
|
|
111
|
+
options = defaults.merge(options)
|
|
112
|
+
from.compact.join(options['delimiter'])
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def to_s
|
|
116
|
+
literal || attributes.inspect
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def value; self; end
|
|
120
|
+
|
|
121
|
+
def numeric?; false; end
|
|
122
|
+
|
|
123
|
+
def sort_order
|
|
124
|
+
"%04d%02d%02d-%04d%02d%02d" % ((parts[0] + [0,0,0])[0,3] + ((parts[1] || []) + [0,0,0])[0,3])
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def <=>(other)
|
|
128
|
+
return nil unless other.is_a?(Date)
|
|
129
|
+
[year, sort_order] <=> [other.year, other.sort_order]
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
end
|