citeproc 0.0.8 → 0.0.9
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/.document +5 -0
- data/.gitignore +5 -0
- data/.travis.yml +13 -0
- data/.yardopts +2 -0
- data/AGPL +662 -0
- data/{LICENSE → BSDL} +2 -1
- data/Gemfile +13 -2
- data/README.md +32 -1
- data/Rakefile +39 -0
- data/citeproc.gemspec +18 -11
- data/lib/citeproc.rb +13 -11
- data/lib/citeproc/abbreviate.rb +1 -4
- data/lib/citeproc/assets.rb +11 -4
- data/lib/citeproc/attributes.rb +102 -95
- data/lib/citeproc/bibliography.rb +66 -42
- data/lib/citeproc/citation_data.rb +57 -46
- data/lib/citeproc/compatibility.rb +161 -4
- data/lib/citeproc/date.rb +517 -225
- data/lib/citeproc/engine.rb +0 -2
- data/lib/citeproc/errors.rb +4 -4
- data/lib/citeproc/extensions.rb +6 -5
- data/lib/citeproc/item.rb +85 -22
- data/lib/citeproc/names.rb +642 -543
- data/lib/citeproc/variable.rb +149 -70
- data/lib/citeproc/version.rb +1 -1
- data/spec/citeproc/assets_spec.rb +10 -4
- data/spec/citeproc/date_spec.rb +274 -8
- data/spec/citeproc/item_spec.rb +23 -4
- data/spec/citeproc/names_spec.rb +601 -486
- data/spec/citeproc/variable_spec.rb +4 -12
- data/spec/spec_helper.rb +13 -0
- metadata +64 -31
data/lib/citeproc/variable.rb
CHANGED
@@ -1,10 +1,12 @@
|
|
1
1
|
|
2
2
|
module CiteProc
|
3
|
-
|
4
|
-
#
|
3
|
+
|
5
4
|
# A CiteProc Variable represents the content of a text, numeric, date, or
|
6
|
-
# name variable.
|
5
|
+
# name variable. In its basic form it is thin abstraction that behaves
|
6
|
+
# almost like a regular Ruby string; more complex Variables are handled
|
7
|
+
# by dedicated sub-classes that make the variable's type more explicit.
|
7
8
|
#
|
9
|
+
# @abstract
|
8
10
|
class Variable
|
9
11
|
|
10
12
|
extend Forwardable
|
@@ -12,29 +14,29 @@ module CiteProc
|
|
12
14
|
|
13
15
|
@fields = Hash.new { |h,k| h.fetch(k.to_sym, nil) }.merge({
|
14
16
|
:date => %w{
|
15
|
-
|
16
|
-
|
17
|
+
accessed container event-date issued original-date submitted
|
18
|
+
},
|
17
19
|
|
18
20
|
:names => %w{
|
19
|
-
|
20
|
-
|
21
|
-
|
21
|
+
author collection-editor composer container-author recipient editor
|
22
|
+
editorial-director illustrator interviewer original-author translator
|
23
|
+
},
|
24
|
+
|
25
|
+
:number => %w{
|
26
|
+
chapter-number collection-number edition issue number number-of-pages
|
27
|
+
number-of-volumes volume
|
28
|
+
},
|
22
29
|
|
23
|
-
:number => %w{
|
24
|
-
chapter-number collection-number edition issue number number-of-pages
|
25
|
-
number-of-volumes volume
|
26
|
-
},
|
27
|
-
|
28
30
|
:text => %w{
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
31
|
+
abstract annote archive archive_location archive-place authority
|
32
|
+
call-number citation-label citation-number collection-title
|
33
|
+
container-title container-title-short dimensions DOI event event-place
|
34
|
+
first-reference-note-number genre ISBN ISSN jurisdiction keyword
|
35
|
+
locator medium note original-publisher original-publisher-place
|
36
|
+
original-title page page-first PMID PMCID publisher publisher-place
|
37
|
+
references section source status title title-short URL version
|
38
|
+
year-suffix
|
39
|
+
}
|
38
40
|
})
|
39
41
|
|
40
42
|
@fields.each_value { |v| v.map!(&:to_sym) }
|
@@ -52,37 +54,92 @@ module CiteProc
|
|
52
54
|
|
53
55
|
@fields.freeze
|
54
56
|
|
55
|
-
|
56
|
-
|
57
|
-
|
57
|
+
@markup = /<[^>]*>/.freeze
|
58
|
+
|
59
|
+
|
58
60
|
class << self
|
59
|
-
|
60
|
-
|
61
|
+
|
62
|
+
# @!attribute [r] fields
|
63
|
+
# @return [{Symbol => Array<Symbol>}] mapping of variable types to
|
64
|
+
# their respective field names
|
65
|
+
attr_reader :fields
|
66
|
+
|
67
|
+
# @!attribute [r] types
|
68
|
+
# @return [{Symbol => Symbol}] mapping of field names to variable types
|
69
|
+
attr_reader :types
|
70
|
+
|
71
|
+
# @!attribute [r] factories
|
72
|
+
# @return [{Symbol => Class}] mapping of field names to their respective
|
73
|
+
# Variable classes
|
74
|
+
attr_reader :factories
|
75
|
+
|
76
|
+
# @!attribute markup
|
77
|
+
# @return [Regexp] pattern used to strip markup off values
|
78
|
+
attr_accessor :markup
|
79
|
+
|
80
|
+
# Creates a new {Variable} instance using the passed-in field name
|
81
|
+
# to distinguish which {Variable} class to use as factory. This
|
82
|
+
# method returns nil if the creation fails.
|
83
|
+
#
|
84
|
+
# @see .create!
|
85
|
+
#
|
86
|
+
# @example
|
87
|
+
# Variable.create('foo')
|
88
|
+
# #-> #<CiteProc::Variable "foo">
|
89
|
+
#
|
90
|
+
# Variable.create('foo', :title)
|
91
|
+
# #-> #<CiteProc::Text "foo">
|
92
|
+
#
|
93
|
+
# Variable.create(['Matz', 'Flanagan'], :author)
|
94
|
+
# #-> #<CiteProc::Names "Matz & Flanagan">
|
95
|
+
#
|
96
|
+
# Variable.create(2009, :issued)
|
97
|
+
# #-> #<CiteProc::Date "2009-01-01">
|
98
|
+
#
|
99
|
+
# @param value [Object] the variable's value
|
100
|
+
# @param field [Symbol] the value's field name
|
101
|
+
#
|
102
|
+
# @return [Variable] a new {Variable} (or sub-class) instance
|
103
|
+
def create(value, field = nil)
|
104
|
+
create!(value, field)
|
105
|
+
rescue
|
106
|
+
nil
|
107
|
+
end
|
108
|
+
|
61
109
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
110
|
+
# Creates a new {Variable} instance using the passed-in field name
|
111
|
+
# to distinguish which {Variable} class to use as factory.
|
112
|
+
#
|
113
|
+
# @see .create
|
114
|
+
#
|
115
|
+
# @raise [TypeError] if no variable can be created for the given value
|
116
|
+
# and type
|
117
|
+
#
|
118
|
+
# @param value [Object] the variable's value
|
119
|
+
# @param field [Symbol] the variable's field name
|
120
|
+
#
|
121
|
+
# @return [Variable] a new {Variable} (or sub-class) instance
|
122
|
+
def create!(value, field = nil)
|
123
|
+
factory = factories[field]
|
124
|
+
value.is_a?(factory) ? value : factory.new(value)
|
71
125
|
end
|
72
126
|
|
73
127
|
end
|
74
|
-
|
128
|
+
|
129
|
+
# @!attribute value
|
130
|
+
# @return [Object] the value wrapped by this variable
|
75
131
|
attr_accessor :value
|
76
132
|
|
77
133
|
def_delegators :@value, :to_s,
|
78
|
-
|
134
|
+
*::String.instance_methods(false).select {|m| m.to_s =~ /!$/ }
|
79
135
|
|
80
136
|
def_delegators :to_s, :=~, :===,
|
81
|
-
|
137
|
+
*::String.instance_methods(false).reject {|m| m.to_s =~ /^\W|!$|to_s/ }
|
82
138
|
|
139
|
+
|
140
|
+
# Creates new Variable for the passed-in value
|
83
141
|
def initialize(value = nil)
|
84
142
|
replace(value)
|
85
|
-
yield self if block_given?
|
86
143
|
end
|
87
144
|
|
88
145
|
def initialize_copy(other)
|
@@ -90,72 +147,94 @@ module CiteProc
|
|
90
147
|
end
|
91
148
|
|
92
149
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
150
|
+
# The replace method is typically called by the Variable's constructor. It
|
151
|
+
# will try to set the Variable to the passed in value and should accept
|
152
|
+
# a wide range of argument types; subclasses (especially Date and Names)
|
153
|
+
# override this method.
|
154
|
+
#
|
155
|
+
# @raise [TypeError] if the variable cannot be set to the passed-in value
|
156
|
+
#
|
157
|
+
# @param value [Object] the variable's new value
|
158
|
+
# @return [self]
|
159
|
+
def replace(value)
|
160
|
+
raise TypeError, "failed to set value to #{value.inspect}" unless value.respond_to?(:to_s)
|
161
|
+
@value = value.to_s
|
162
|
+
self
|
163
|
+
end
|
102
164
|
|
103
|
-
|
104
|
-
|
105
|
-
|
165
|
+
# @return [Symbol] the variable's type
|
166
|
+
def type
|
167
|
+
@type ||= self.class.name.split(/::/)[-1].downcase.to_sym
|
168
|
+
end
|
106
169
|
|
107
|
-
|
170
|
+
# @return [Boolean] whether or not the variable can be (safely) cast to a numeric value
|
108
171
|
def numeric?
|
109
|
-
match(/\d/)
|
172
|
+
!!match(/\d/)
|
110
173
|
end
|
111
174
|
|
112
|
-
#
|
175
|
+
# @return [Fixnum] the first (!) numeric data contained in the variable's
|
176
|
+
# value; zero if no numeric data is present
|
113
177
|
def to_i
|
114
|
-
to_s =~ /(
|
178
|
+
to_s =~ /([+-]?\d+)/ && $1.to_i || 0
|
115
179
|
end
|
116
180
|
|
181
|
+
# @return [Float] the first (!) numeric or floating point data contained
|
182
|
+
# in the variable's value; zero if no numeric data is present
|
117
183
|
def to_f
|
118
|
-
to_s =~ /(
|
184
|
+
to_s =~ /([+-]?\d[\d,\.]*)/ && $1.tr(',','.').to_f || 0.0
|
119
185
|
end
|
120
186
|
|
187
|
+
# @return [String] the variable's value stripped of markup
|
121
188
|
def strip_markup
|
122
189
|
gsub(Variable.markup, '')
|
123
190
|
end
|
124
191
|
|
192
|
+
# Strips markup off the variable's value.
|
193
|
+
# @return [self]
|
125
194
|
def strip_markup!
|
126
195
|
gsub!(Variable.markup, '')
|
127
196
|
end
|
128
197
|
|
198
|
+
# Compares the variable with the passed-in value. If other responds
|
199
|
+
# to {#strip_markup} the stripped strings will be compared; otherwise
|
200
|
+
# both objects will be converted to and compared as strings.
|
201
|
+
#
|
202
|
+
# @param other [Object] the object used for comparison
|
203
|
+
# @return [Fixnum,nil] -1, 0, or 1 depending on the result of the
|
204
|
+
# comparison; or nil if the two objects cannot be ignored.
|
129
205
|
def <=>(other)
|
130
206
|
case
|
131
207
|
when other.respond_to?(:strip_markup)
|
132
208
|
strip_markup <=> other.strip_markup
|
133
|
-
|
134
209
|
when other && other.respond_to?(:to_s)
|
135
210
|
to_s <=> other.to_s
|
136
|
-
|
137
211
|
else
|
138
212
|
nil
|
139
213
|
end
|
140
214
|
end
|
215
|
+
|
216
|
+
# @!method to_s
|
217
|
+
# @return [String] the variable's value as a string
|
218
|
+
alias to_citeproc to_s
|
141
219
|
|
142
|
-
|
143
|
-
|
220
|
+
# @return [String] a JSON string representation of the variable
|
144
221
|
def to_json
|
145
222
|
MultiJson.encode(to_citeproc)
|
146
223
|
end
|
147
224
|
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
225
|
+
# @return [String] a human-readable representation of the variable
|
226
|
+
def inspect
|
227
|
+
"#<#{self.class.name} #{to_s.inspect}>"
|
228
|
+
end
|
229
|
+
|
152
230
|
end
|
153
231
|
|
232
|
+
# A CiteProc Variable used for string values.
|
233
|
+
class Text < Variable
|
234
|
+
end
|
154
235
|
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
class Number < Variable
|
159
|
-
end
|
236
|
+
# A CiteProc Variable used for numeric values.
|
237
|
+
class Number < Variable
|
238
|
+
end
|
160
239
|
|
161
240
|
end
|
data/lib/citeproc/version.rb
CHANGED
@@ -1,6 +1,3 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
require 'tempfile'
|
3
|
-
|
4
1
|
module CiteProc
|
5
2
|
|
6
3
|
describe 'Assets' do
|
@@ -56,9 +53,18 @@ module CiteProc
|
|
56
53
|
it 'returns the given string if it looks like XML' do
|
57
54
|
Style.open('<b>foo bar!</b>').to_s.should == '<b>foo bar!</b>'
|
58
55
|
end
|
59
|
-
|
60
56
|
end
|
61
57
|
|
58
|
+
describe '.extend_name' do
|
59
|
+
it 'adds the default extension if the file does not already end with it' do
|
60
|
+
Style.extend_name(name.sub(/#{extension}$/,'')).should == name
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'does not add the default extension if the file already ends with it' do
|
64
|
+
Style.extend_name(name).should == name
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
62
68
|
end
|
63
69
|
end
|
64
70
|
end
|
data/spec/citeproc/date_spec.rb
CHANGED
@@ -3,6 +3,101 @@ require 'spec_helper'
|
|
3
3
|
module CiteProc
|
4
4
|
describe Date do
|
5
5
|
|
6
|
+
class Date
|
7
|
+
describe DateParts do
|
8
|
+
it { should_not be_nil }
|
9
|
+
it { should be_empty }
|
10
|
+
|
11
|
+
describe 'sorting' do
|
12
|
+
it 'treats [2003] as less than [2003,1]' do
|
13
|
+
DateParts.new(2003).should be < DateParts.new(2003,1)
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'treats [1992,9,23] as less than [1993,8,22]' do
|
17
|
+
DateParts.new(1992,9,23).should be < DateParts.new(1993,8,22)
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'treats [1992,9,23] as less than [1992,10,22]' do
|
21
|
+
DateParts.new(1992,9,23).should be < DateParts.new(1992,10,22)
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'treats [1992,9,23] as less than [1992,9,24]' do
|
25
|
+
DateParts.new(1992,9,23).should be < DateParts.new(1992,9,24)
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'treats [-50] as less than [-25]' do
|
29
|
+
DateParts.new(-50).should be < DateParts.new(-25)
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'treats [-50] as less than [-50,12]' do
|
33
|
+
DateParts.new(-50).should be < DateParts.new(-50,12)
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'treats [1994,1,23] as less than today' do
|
37
|
+
DateParts.new(1994,1,23).should be < ::Date.today
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe '#dup' do
|
42
|
+
let(:date) { DateParts.new(1991,8,22) }
|
43
|
+
|
44
|
+
it 'creates a copy that contains the same parts' do
|
45
|
+
date.dup.to_a.should == [1991,8,22]
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'does not return self' do
|
49
|
+
date.dup.should_not equal(date)
|
50
|
+
date.dup.should == date
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe '#update' do
|
55
|
+
it 'accepts a hash' do
|
56
|
+
DateParts.new.update(:month => 2, :year => 80).to_a.should == [80,2,nil]
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'accepts an array' do
|
60
|
+
DateParts.new.update([80,2]).to_a.should == [80,2,nil]
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe '#strftime' do
|
65
|
+
it 'formats the date parts according to the format string' do
|
66
|
+
DateParts.new(1998,2,4).strftime('FOO %0m%0d%y').should == 'FOO 020498'
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
describe 'to_citeproc' do
|
71
|
+
it 'returns an empty list by default' do
|
72
|
+
DateParts.new.to_citeproc.should == []
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'returns a list with the year if only the year is set' do
|
76
|
+
DateParts.new(2001).to_citeproc.should == [2001]
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'supports zero parts' do
|
80
|
+
DateParts.new(0,0).to_citeproc.should == [0,0]
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
describe '#open?' do
|
85
|
+
it 'returns false by default' do
|
86
|
+
DateParts.new.should_not be_open
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'returns false for [1999,8,24]' do
|
90
|
+
DateParts.new(1999, 8, 24).should_not be_open
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'returns true for [0]' do
|
94
|
+
DateParts.new(0).should be_open
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
|
6
101
|
let(:ad2k) { Date.create('date-parts' => [[2000]])}
|
7
102
|
let(:may) { Date.create('date-parts' => [[2000, 5]])}
|
8
103
|
let(:first_of_may) { Date.create('date-parts' => [[2000, 5, 1]])}
|
@@ -17,11 +112,68 @@ module CiteProc
|
|
17
112
|
it { should_not be_numeric }
|
18
113
|
|
19
114
|
describe '.new' do
|
115
|
+
it 'accepts a hash as input' do
|
116
|
+
Date.new(:literal => 'Summer').to_s.should == 'Summer'
|
117
|
+
end
|
118
|
+
|
119
|
+
it 'accepts a hash as input and converts date parts' do
|
120
|
+
Date.new(:'date-parts' => [[2003,2]]).parts[0].should be_a(Date::DateParts)
|
121
|
+
end
|
122
|
+
|
123
|
+
it 'accepts a fixnum and treats it as the year' do
|
124
|
+
Date.new(1666).year.should == 1666
|
125
|
+
end
|
126
|
+
|
127
|
+
it 'accepts a date' do
|
128
|
+
Date.new(::Date.new(1980,4)).month.should == 4
|
129
|
+
end
|
130
|
+
|
131
|
+
it 'accepts a date and creates date parts' do
|
132
|
+
Date.new(::Date.new(1980,4)).parts[0].to_citeproc.should == [1980,4,1]
|
133
|
+
end
|
134
|
+
|
135
|
+
it 'is empty by default' do
|
136
|
+
Date.new.should be_empty
|
137
|
+
end
|
138
|
+
|
139
|
+
it 'accepts date strings' do
|
140
|
+
Date.new('2009-03-19').day.should == 19
|
141
|
+
end
|
142
|
+
|
143
|
+
it 'accepts JSON strings' do
|
144
|
+
Date.new('{ "date-parts": [[2001,1,19]]}').day.should == 19
|
145
|
+
end
|
146
|
+
|
147
|
+
it 'accepts date parts in an array' do
|
148
|
+
Date.new([2009,3]).month.should == 3
|
149
|
+
end
|
150
|
+
|
151
|
+
it 'accepts ranges as an array' do
|
152
|
+
Date.new([[2009],[2012]]).should be_range
|
153
|
+
end
|
154
|
+
|
155
|
+
it 'accepts year ranges' do
|
156
|
+
Date.new(2009..2012).should be_range
|
157
|
+
end
|
158
|
+
|
159
|
+
it 'accepts exclusive date ranges' do
|
160
|
+
Date.new(::Date.new(2009) ... ::Date.new(2011)).end_date.year.should == 2010
|
161
|
+
end
|
162
|
+
|
163
|
+
it 'accepts inclusive date ranges' do
|
164
|
+
Date.new(::Date.new(2009) .. ::Date.new(2011)).end_date.year.should == 2011
|
165
|
+
end
|
20
166
|
|
167
|
+
it 'accepts EDTF date strings' do
|
168
|
+
Date.new('2009?-03-19').should be_uncertain
|
169
|
+
end
|
170
|
+
|
171
|
+
it 'accepts EDTF intervals' do
|
172
|
+
Date.new('2009-03-19/2010-11-21').parts.map(&:to_citeproc).should == [[2009,3,19],[2010,11,21]]
|
173
|
+
end
|
21
174
|
end
|
22
175
|
|
23
176
|
describe '.parse' do
|
24
|
-
|
25
177
|
it 'returns nil by default' do
|
26
178
|
Date.parse('').should be nil
|
27
179
|
Date.parse(nil).should be nil
|
@@ -38,6 +190,32 @@ module CiteProc
|
|
38
190
|
end
|
39
191
|
end
|
40
192
|
|
193
|
+
describe '#dup' do
|
194
|
+
let(:date) { Date.new([1991,8]) }
|
195
|
+
|
196
|
+
it 'creates a copy that contains the same parts' do
|
197
|
+
date.dup.parts.map(&:to_citeproc).should == [[1991,8]]
|
198
|
+
end
|
199
|
+
|
200
|
+
it 'copies uncertainty' do
|
201
|
+
date.dup.should_not be_uncertain
|
202
|
+
date.uncertain!.dup.should be_uncertain
|
203
|
+
end
|
204
|
+
|
205
|
+
it 'makes a deep copy of attributes' do
|
206
|
+
expect { date.dup.uncertain! }.not_to change { date.uncertain? }
|
207
|
+
end
|
208
|
+
|
209
|
+
it 'makes a deep copy of date parts' do
|
210
|
+
expect { date.dup.parts[0].update(:year => 2012) }.not_to change { date.year }
|
211
|
+
end
|
212
|
+
|
213
|
+
it 'does not return self' do
|
214
|
+
date.dup.should_not equal(date)
|
215
|
+
date.dup.should == date
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
41
219
|
describe 'literal dates' do
|
42
220
|
it 'is not literal by default' do
|
43
221
|
Date.new.should_not be_literal
|
@@ -51,16 +229,36 @@ module CiteProc
|
|
51
229
|
Date.create('date-parts' => [[2000]], :literal => 'foo').should be_literal
|
52
230
|
end
|
53
231
|
end
|
232
|
+
|
233
|
+
describe 'seasons' do
|
234
|
+
it 'is no season by default' do
|
235
|
+
Date.new.should_not be_season
|
236
|
+
end
|
237
|
+
|
238
|
+
it 'is a season if contains only a season field' do
|
239
|
+
Date.new(:season => 'Winter').should be_season
|
240
|
+
end
|
241
|
+
|
242
|
+
it 'is a season if contains a season field' do
|
243
|
+
Date.new(:'date-parts' => [[2001]], :season => 'Winter').should be_season
|
244
|
+
end
|
245
|
+
end
|
54
246
|
|
55
247
|
describe 'uncertain dates' do
|
56
248
|
it 'are uncertain' do
|
57
249
|
Date.new({ 'date-parts' => [[-225]], 'circa' => '1' }).should be_uncertain
|
58
|
-
Date.new { |d| d.parts = [[-225]]; d.uncertain! }.
|
250
|
+
Date.new { |d| d.parts = [[-225]]; d.uncertain! }.should_not be_certain
|
251
|
+
end
|
252
|
+
|
253
|
+
describe '#(un)certain!' do
|
254
|
+
it 'returns self' do
|
255
|
+
ad2k.uncertain!.should equal(ad2k)
|
256
|
+
ad2k.certain!.should equal(ad2k)
|
257
|
+
end
|
59
258
|
end
|
60
259
|
end
|
61
260
|
|
62
261
|
describe 'sorting' do
|
63
|
-
|
64
262
|
it 'dates with more date-parts will come after those with fewer parts' do
|
65
263
|
(ad2k < may && may < first_of_may).should be true
|
66
264
|
end
|
@@ -68,8 +266,42 @@ module CiteProc
|
|
68
266
|
it 'negative years are sorted inversely' do
|
69
267
|
[ad50, bc100, bc50, ad100].sort.map(&:year).should == [-100, -50, 50, 100]
|
70
268
|
end
|
269
|
+
|
270
|
+
it 'can be compared to dates' do
|
271
|
+
ad50.should be < ::Date.new(50,2)
|
272
|
+
ad50.should be > ::Date.new(49)
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
describe '#start_date' do
|
277
|
+
it 'returns nil by default' do
|
278
|
+
Date.new.start_date.should be_nil
|
279
|
+
end
|
280
|
+
|
281
|
+
it 'returns a ruby date when date-parts are set' do
|
282
|
+
Date.new(1999).start_date.year.should == 1999
|
283
|
+
end
|
71
284
|
end
|
72
285
|
|
286
|
+
describe '#end_date' do
|
287
|
+
it 'returns nil by default' do
|
288
|
+
Date.new.end_date.should be_nil
|
289
|
+
end
|
290
|
+
|
291
|
+
it 'returns nil when there is a single date-parts set' do
|
292
|
+
Date.new(1312).end_date.should be_nil
|
293
|
+
end
|
294
|
+
|
295
|
+
it 'returns a ruby date when date-parts are a closed range' do
|
296
|
+
Date.new(1999..2000).end_date.year.should == 2000
|
297
|
+
end
|
298
|
+
end
|
299
|
+
|
300
|
+
describe '#-@' do
|
301
|
+
it 'inverts the year' do
|
302
|
+
(-ad50).should == bc50
|
303
|
+
end
|
304
|
+
end
|
73
305
|
|
74
306
|
describe '#display' do
|
75
307
|
it 'returns an empty string by default' do
|
@@ -114,21 +346,49 @@ module CiteProc
|
|
114
346
|
it 'today is not b.c.' do
|
115
347
|
Date.today.should_not be_bc
|
116
348
|
end
|
117
|
-
|
349
|
+
|
118
350
|
it 'the year 2000 is not a.d.' do
|
119
351
|
ad2k.should_not be_ad
|
120
352
|
end
|
121
353
|
|
122
354
|
end
|
123
355
|
|
356
|
+
describe '#empty?' do
|
357
|
+
it 'returns true by default' do
|
358
|
+
Date.new.should be_empty
|
359
|
+
end
|
360
|
+
|
361
|
+
it 'returns true when it contains no date parts' do
|
362
|
+
Date.new({}).should be_empty
|
363
|
+
end
|
364
|
+
|
365
|
+
it 'returns false for today' do
|
366
|
+
Date.today.should_not be_empty
|
367
|
+
end
|
368
|
+
|
369
|
+
it 'returns false for literal dates' do
|
370
|
+
Date.new(:literal => 'foo').should_not be_empty
|
371
|
+
end
|
372
|
+
|
373
|
+
it 'returns false for seasons' do
|
374
|
+
Date.new(:season => 'Summer').should_not be_empty
|
375
|
+
end
|
376
|
+
end
|
377
|
+
|
124
378
|
describe '#to_json' do
|
125
379
|
it 'supports simple parts' do
|
126
380
|
Date.new(%w{2000 1 15}).to_json.should == '{"date-parts":[[2000,1,15]]}'
|
127
381
|
end
|
128
382
|
|
129
|
-
it 'supports
|
383
|
+
it 'supports string parts' do
|
130
384
|
Date.new(['2000', '1', '15']).to_json.should == '{"date-parts":[[2000,1,15]]}'
|
385
|
+
end
|
386
|
+
|
387
|
+
it 'supports integer parts' do
|
131
388
|
Date.new([2000, 1, 15]).to_json.should == '{"date-parts":[[2000,1,15]]}'
|
389
|
+
end
|
390
|
+
|
391
|
+
it 'supports mixed parts' do
|
132
392
|
Date.new(['2000', 1, '15']).to_json.should == '{"date-parts":[[2000,1,15]]}'
|
133
393
|
end
|
134
394
|
|
@@ -136,9 +396,12 @@ module CiteProc
|
|
136
396
|
Date.new(-200).to_json.should == '{"date-parts":[[-200]]}'
|
137
397
|
end
|
138
398
|
|
399
|
+
it 'treats seasons as a strings' do
|
400
|
+
Date.create({:season => '1', 'date-parts' => [[1950]]}).to_json.should =~ /"season":"1"/
|
401
|
+
end
|
402
|
+
|
139
403
|
it 'supports seasons' do
|
140
|
-
Date.create({:season => '
|
141
|
-
Date.create({:season => 'Trinity', 'date-parts' => [[1975]]}).to_json.should == '{"date-parts":[[1975]],"season":"Trinity"}'
|
404
|
+
Date.create({:season => 'Trinity', 'date-parts' => [[1975]]}).to_json.should =~ /"season":"Trinity"/
|
142
405
|
end
|
143
406
|
|
144
407
|
it 'supports string literals' do
|
@@ -149,8 +412,11 @@ module CiteProc
|
|
149
412
|
Date.new(:raw => '23 May 1955').to_json.should == '{"date-parts":[[1955,5,23]]}'
|
150
413
|
end
|
151
414
|
|
152
|
-
it 'supports
|
415
|
+
it 'supports closed ranges' do
|
153
416
|
Date.new([[2000,11],[2000,12]]).to_json.should == '{"date-parts":[[2000,11],[2000,12]]}'
|
417
|
+
end
|
418
|
+
|
419
|
+
it 'supports open ranges' do
|
154
420
|
Date.new([[2000,11],[0,0]]).to_json.should == '{"date-parts":[[2000,11],[0,0]]}'
|
155
421
|
end
|
156
422
|
end
|