citeproc-ruby 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|