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