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.
@@ -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
- accessed container event-date issued original-date submitted
16
- },
17
+ accessed container event-date issued original-date submitted
18
+ },
17
19
 
18
20
  :names => %w{
19
- author collection-editor composer container-author recipient editor
20
- editorial-director illustrator interviewer original-author translator
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
- abstract annote archive archive_location archive-place authority
30
- call-number citation-label citation-number collection-title
31
- container-title container-title-short dimensions DOI event event-place
32
- first-reference-note-number genre ISBN ISSN jurisdiction keyword
33
- locator medium note original-publisher original-publisher-place
34
- original-title page page-first PMID PMCID publisher publisher-place
35
- references section source status title title-short URL version
36
- year-suffix
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
- @markup = /<[^>]*>/.freeze
56
-
57
-
57
+ @markup = /<[^>]*>/.freeze
58
+
59
+
58
60
  class << self
59
-
60
- attr_reader :fields, :types, :markup, :factories
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
- def create(value, type = nil)
63
- create!(value, type)
64
- rescue
65
- nil
66
- end
67
-
68
- def create!(value, type = nil)
69
- factory = factories[type]
70
- value.is_a?(factory) ? value : factory.new(value)
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
- *::String.instance_methods(false).select {|m| m.to_s =~ /!$/ }
134
+ *::String.instance_methods(false).select {|m| m.to_s =~ /!$/ }
79
135
 
80
136
  def_delegators :to_s, :=~, :===,
81
- *::String.instance_methods(false).reject {|m| m.to_s =~ /^\W|!$|to_s/ }
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
- # The replace method is typically called by the Variable's constructor. It
94
- # will try to set the Variable to the passed in value and should accept
95
- # a wide range of argument types; subclasses (especially Date and Names)
96
- # override this method.
97
- def replace(value)
98
- raise TypeError, "failed to set value to #{value.inspect}" unless value.respond_to?(:to_s)
99
- @value = value.to_s
100
- self
101
- end
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
- def type
104
- @type ||= self.class.name.split(/::/)[-1].downcase.to_sym
105
- end
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
- # Returns true if the Variable can be (safely) cast to a numeric value.
170
+ # @return [Boolean] whether or not the variable can be (safely) cast to a numeric value
108
171
  def numeric?
109
- match(/\d/) ? to_i : false
172
+ !!match(/\d/)
110
173
  end
111
174
 
112
- # Returns (first) numeric data contained in the variable's value
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 =~ /(-?\d+)/ && $1.to_i || 0
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 =~ /(-?\d[\d,\.]*)/ && $1.tr(',','.').to_f || 0.0
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
- alias to_citeproc to_s
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
- def inspect
149
- "#<#{self.class.name}: #{to_s.inspect}>"
150
- end
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
- class Text < Variable
156
- end
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
@@ -1,3 +1,3 @@
1
1
  module CiteProc
2
- VERSION = '0.0.8'.freeze
2
+ VERSION = '0.0.9'.freeze
3
3
  end
@@ -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
@@ -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! }.should be_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 integers and strings parts' do
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 => '1', 'date-parts' => [[1950]]}).to_json.should == '{"date-parts":[[1950]],"season":"1"}'
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 open and closed ranges' do
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