citeproc 1.0.0.pre12 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.simplecov +4 -0
- data/AGPL +1 -1
- data/BSDL +2 -2
- data/Gemfile +39 -19
- data/README.md +123 -14
- data/Rakefile +22 -8
- data/cucumber.yml +1 -1
- data/features/step_definitions/processor.rb +59 -0
- data/features/support/env.rb +45 -2
- data/lib/citeproc.rb +8 -8
- data/lib/citeproc/abbreviate.rb +5 -4
- data/lib/citeproc/assets.rb +109 -109
- data/lib/citeproc/attributes.rb +11 -11
- data/lib/citeproc/bibliography.rb +107 -71
- data/lib/citeproc/citation_data.rb +175 -150
- data/lib/citeproc/compatibility.rb +5 -108
- data/lib/citeproc/date.rb +23 -12
- data/lib/citeproc/engine.rb +9 -4
- data/lib/citeproc/errors.rb +6 -6
- data/lib/citeproc/extensions.rb +66 -66
- data/lib/citeproc/item.rb +60 -2
- data/lib/citeproc/names.rb +103 -24
- data/lib/citeproc/number.rb +27 -8
- data/lib/citeproc/processor.rb +31 -41
- data/lib/citeproc/selector.rb +132 -126
- data/lib/citeproc/utilities.rb +6 -6
- data/lib/citeproc/variable.rb +5 -4
- data/lib/citeproc/version.rb +1 -1
- data/spec/citeproc/assets_spec.rb +17 -15
- data/spec/citeproc/bibliography_spec.rb +17 -17
- data/spec/citeproc/citation_data_spec.rb +90 -90
- data/spec/citeproc/engine_spec.rb +3 -4
- data/spec/citeproc/item_spec.rb +76 -68
- data/spec/citeproc/names_spec.rb +187 -148
- data/spec/citeproc/processor_spec.rb +119 -115
- data/spec/citeproc/selector_spec.rb +87 -78
- data/spec/citeproc/variable_spec.rb +30 -30
- data/spec/fixtures/locales/locales-en-US.xml +304 -0
- data/spec/spec_helper.rb +32 -1
- data/tasks/testsuite.rb +209 -0
- metadata +19 -87
- data/.gitignore +0 -6
- data/.travis.yml +0 -21
- data/citeproc.gemspec +0 -40
@@ -1,219 +1,244 @@
|
|
1
1
|
module CiteProc
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
3
|
+
# A {CitationItem} consititues the main input elements to CiteProc's
|
4
|
+
# processing methods. In order to be processed correctly, an item must
|
5
|
+
# have a valid {#id} attribute used to retrieve the correpsonding {Item}
|
6
|
+
# containing the actual bibliographic data.
|
7
|
+
class CitationItem
|
8
|
+
|
9
|
+
extend Forwardable
|
10
|
+
include Attributes
|
11
|
+
include Comparable
|
12
|
+
|
13
|
+
@labels = [
|
14
|
+
:book, :chapter, :column, :figure, :folio, :issue, :line, :note, :opus,
|
15
|
+
:page, :paragraph, :part, :section, :'sub-verbo', :verse, :volume
|
16
|
+
].freeze
|
17
|
+
|
18
|
+
class << self
|
19
|
+
attr_reader :labels
|
20
|
+
end
|
10
21
|
|
11
|
-
|
12
|
-
|
13
|
-
:page, :paragraph, :part, :section, :'sub-verbo', :verse, :volume
|
14
|
-
].freeze
|
22
|
+
# @!attribute id
|
23
|
+
# @return [Symbol,String] the id of the corresponding resource
|
15
24
|
|
16
|
-
|
17
|
-
|
18
|
-
|
25
|
+
# @!attribute locator
|
26
|
+
# @return [String] a string identifying a page number or similar to mark
|
27
|
+
# a location or range within the resource
|
19
28
|
|
20
|
-
|
21
|
-
|
29
|
+
# @!attribute label
|
30
|
+
# Labels indicate whether the current locator is to a page, a chapter,
|
31
|
+
# or other subdivision of the target resource. Valid labels are defined
|
32
|
+
# by {.labels}.
|
33
|
+
# @return [Symbol,String] the label type
|
22
34
|
|
23
|
-
|
24
|
-
|
25
|
-
|
35
|
+
# @!attribute suppress_author
|
36
|
+
# @return [Boolean] whether or not author names will not be included
|
37
|
+
# in the citation output for this cite
|
26
38
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
39
|
+
# @!attribute author_only
|
40
|
+
# This optional parameter provides a means for certain demanding styles
|
41
|
+
# that require the processor output to be divided between the main text
|
42
|
+
# and a footnote.
|
43
|
+
# @return [Boolean] whether or not only the author name will be included
|
44
|
+
# in the citation output for this cite
|
32
45
|
|
33
|
-
|
34
|
-
|
35
|
-
# in the citation output for this cite
|
46
|
+
# @!attribute prefix
|
47
|
+
# @return [String] a string to print before cites produced for this item
|
36
48
|
|
37
|
-
|
38
|
-
|
39
|
-
# that require the processor output to be divided between the main text
|
40
|
-
# and a footnote.
|
41
|
-
# @return [Boolean] whether or not only the author name will be included
|
42
|
-
# in the citation output for this cite
|
49
|
+
# @!attribute suffix
|
50
|
+
# @return [String] a string to print after cites produced for this item
|
43
51
|
|
44
|
-
|
45
|
-
|
52
|
+
attr_predicates :id, :locator, :page, :label, :'suppress-author',
|
53
|
+
:'author-only', :prefix, :suffix
|
46
54
|
|
47
|
-
|
48
|
-
|
55
|
+
# Attributes added by processor
|
56
|
+
attr_predicates :sortkeys, :postion, :'first-reference-note-number',
|
57
|
+
:'near-note', :unsorted
|
49
58
|
|
50
|
-
|
51
|
-
:'author-only', :prefix, :suffix
|
59
|
+
attr_accessor :data
|
52
60
|
|
53
|
-
|
54
|
-
|
55
|
-
:'near-note', :unsorted
|
61
|
+
def_delegators :@data, :suppressed?, :suppress!,
|
62
|
+
:language, :english?, :en?
|
56
63
|
|
57
|
-
|
64
|
+
def initialize(attributes = nil)
|
65
|
+
merge(attributes)
|
66
|
+
yield self if block_given?
|
67
|
+
end
|
58
68
|
|
59
|
-
|
60
|
-
|
61
|
-
|
69
|
+
def initialize_copy(other)
|
70
|
+
@attributes = other.attributes.deep_copy
|
71
|
+
end
|
62
72
|
|
63
|
-
|
64
|
-
|
65
|
-
|
73
|
+
def <=>(other)
|
74
|
+
return unless other.respond_to?(:data)
|
75
|
+
data <=> other.data
|
76
|
+
end
|
66
77
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
78
|
+
# @return [String] a human-readable representation of the citation item
|
79
|
+
def inspect
|
80
|
+
"#<CiteProc::CitationItem #{[id, locator].compact.map(&:inspect).join(', ')}>"
|
81
|
+
end
|
71
82
|
|
72
|
-
|
83
|
+
end
|
73
84
|
|
74
85
|
|
75
86
|
|
76
87
|
|
77
|
-
|
88
|
+
class CitationData
|
78
89
|
|
79
|
-
|
80
|
-
|
90
|
+
extend Forwardable
|
91
|
+
include Enumerable
|
81
92
|
|
82
|
-
|
83
|
-
|
84
|
-
|
93
|
+
@defaults = {
|
94
|
+
:footnote => 0
|
95
|
+
}.freeze
|
85
96
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
97
|
+
@rb2cp = {
|
98
|
+
:id => 'citationID',
|
99
|
+
:items => 'citationItems',
|
100
|
+
:sorted_items => 'sortedItems',
|
101
|
+
:footnote => 'noteIndex',
|
102
|
+
:options => 'properties'
|
103
|
+
}
|
93
104
|
|
94
|
-
|
95
|
-
|
105
|
+
@cp2rb = @rb2cp.invert.freeze
|
106
|
+
@rb2cp.freeze
|
96
107
|
|
97
|
-
|
98
|
-
|
99
|
-
|
108
|
+
class << self
|
109
|
+
attr_reader :defaults, :cp2rb, :rb2cp
|
110
|
+
end
|
100
111
|
|
101
|
-
|
112
|
+
attr_accessor :id
|
102
113
|
|
103
|
-
|
114
|
+
attr_reader :items, :options, :sorted_items
|
104
115
|
|
105
|
-
|
116
|
+
alias properties options
|
106
117
|
|
107
|
-
|
118
|
+
def_delegators :@items, :length, :empty?, :[]
|
108
119
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
120
|
+
# Some delegators should return self
|
121
|
+
[:push, :<<, :unshift, :concat].each do |m|
|
122
|
+
define_method(m) do |*arguments|
|
123
|
+
names.send(m, *arguments)
|
124
|
+
self
|
125
|
+
end
|
126
|
+
end
|
116
127
|
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
128
|
+
def initialize(attributes = nil, options = {})
|
129
|
+
@options = CitationData.defaults.merge(options)
|
130
|
+
@items, @sorted_items = [], []
|
131
|
+
merge(attributes)
|
132
|
+
end
|
122
133
|
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
134
|
+
def initialize_copy(other)
|
135
|
+
@options = other.options.dup
|
136
|
+
@items = other.items.map(&:dup)
|
137
|
+
@sorted_items = other.items.map(&:dup)
|
138
|
+
@id = other.id.dup if other.processed?
|
139
|
+
end
|
129
140
|
|
130
141
|
def merge(other)
|
131
142
|
return self if other.nil?
|
132
143
|
|
133
144
|
case other
|
134
145
|
when String, /^\s*\{/
|
135
|
-
other =
|
146
|
+
other = JSON.parse(other, :symbolize_names => true)
|
136
147
|
when Hash
|
137
|
-
|
138
|
-
|
139
|
-
|
148
|
+
# do nothing
|
149
|
+
when Array
|
150
|
+
other = { :items => other }
|
140
151
|
when Attributes
|
141
152
|
other = other.to_hash
|
142
|
-
|
143
|
-
|
153
|
+
else
|
154
|
+
raise ParseError, "failed to merge citation data and #{other.inspect}"
|
144
155
|
end
|
145
156
|
|
146
|
-
|
157
|
+
other = convert_from_citeproc(other)
|
147
158
|
|
148
|
-
|
149
|
-
|
159
|
+
items.concat(Array(other.delete(:items)).map { |i| CitationItem.create!(i) })
|
160
|
+
sorted_items.concat(Array(other.delete(:sorted_items)))
|
150
161
|
|
151
|
-
|
152
|
-
|
162
|
+
properties = other.delete(:options)
|
163
|
+
options.merge!(convert_from_citeproc(Hash[properties])) unless properties.nil?
|
153
164
|
|
154
|
-
|
165
|
+
@id = other[:id] if other.has_key?(:id)
|
155
166
|
|
156
167
|
self
|
157
168
|
end
|
158
169
|
|
159
|
-
|
170
|
+
alias update merge
|
160
171
|
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
end
|
172
|
+
def each
|
173
|
+
if block_given?
|
174
|
+
if sorted?
|
175
|
+
sorted_items.each(&Proc.new)
|
176
|
+
else
|
177
|
+
items.each(&Proc.new)
|
178
|
+
end
|
169
179
|
|
170
|
-
|
171
|
-
|
172
|
-
|
180
|
+
self
|
181
|
+
else
|
182
|
+
to_enum
|
183
|
+
end
|
184
|
+
end
|
173
185
|
|
174
|
-
|
175
|
-
|
176
|
-
|
186
|
+
def processed?
|
187
|
+
!!id
|
188
|
+
end
|
177
189
|
|
178
|
-
|
179
|
-
|
180
|
-
|
190
|
+
def sorted?
|
191
|
+
!sorted_items.empty?
|
192
|
+
end
|
181
193
|
|
182
|
-
|
183
|
-
|
194
|
+
def sort!(&block)
|
195
|
+
@sorted_items = items.sort(&block)
|
196
|
+
self
|
197
|
+
end
|
184
198
|
|
185
|
-
|
186
|
-
|
199
|
+
def index
|
200
|
+
options[:footnote]
|
201
|
+
end
|
187
202
|
|
188
|
-
|
203
|
+
def footnote?
|
204
|
+
options[:footnote] > 0
|
205
|
+
end
|
189
206
|
|
190
|
-
|
191
|
-
|
207
|
+
def to_citeproc
|
208
|
+
cp = {}
|
192
209
|
|
193
|
-
|
194
|
-
|
195
|
-
end
|
210
|
+
cp[CitationData.rb2cp[:items]] = items.map(&:to_citeproc)
|
211
|
+
cp[CitationData.rb2cp[:options]] = { CitationData.rb2cp[:footnote] => index }
|
196
212
|
|
197
|
-
|
213
|
+
cp[CitationData.rb2cp[:id]] = id if processed?
|
198
214
|
|
199
|
-
|
200
|
-
|
201
|
-
"#<CiteProc::CitationData items=[#{length}]>"
|
202
|
-
end
|
215
|
+
cp
|
216
|
+
end
|
203
217
|
|
204
|
-
|
218
|
+
def to_json
|
219
|
+
::JSON.dump(to_citeproc)
|
220
|
+
end
|
205
221
|
|
206
|
-
|
207
|
-
hash = hash.symbolize_keys
|
222
|
+
alias to_s to_json
|
208
223
|
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
224
|
+
# @return [String] a human-readable representation of the citation data
|
225
|
+
def inspect
|
226
|
+
"#<CiteProc::CitationData items=[#{length}]>"
|
227
|
+
end
|
228
|
+
|
229
|
+
private
|
230
|
+
|
231
|
+
def convert_from_citeproc(hash)
|
232
|
+
hash = hash.symbolize_keys
|
213
233
|
|
214
|
-
|
215
|
-
|
234
|
+
CitationData.cp2rb.each do |cp, rb|
|
235
|
+
cp = cp.to_sym
|
236
|
+
hash[rb] = hash.delete(cp) if hash.has_key?(cp)
|
237
|
+
end
|
238
|
+
|
239
|
+
hash
|
240
|
+
end
|
216
241
|
|
217
|
-
|
242
|
+
end
|
218
243
|
|
219
|
-
end
|
244
|
+
end
|
@@ -1,91 +1,5 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
2
|
|
3
|
-
unless Symbol.is_a?(Comparable)
|
4
|
-
class Symbol
|
5
|
-
include Comparable
|
6
|
-
|
7
|
-
def =~(pattern)
|
8
|
-
to_s =~ pattern
|
9
|
-
end
|
10
|
-
|
11
|
-
def <=>(other)
|
12
|
-
return nil unless other.is_a?(Symbol)
|
13
|
-
to_s <=> other.to_s
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
if RUBY_VERSION < '1.9'
|
21
|
-
require 'enumerator'
|
22
|
-
|
23
|
-
$KCODE = 'u'
|
24
|
-
require 'jcode'
|
25
|
-
|
26
|
-
module CiteProc
|
27
|
-
|
28
|
-
def to_unicode(string)
|
29
|
-
string.gsub(/\\?u([\da-f]{4})/i) { |m| [$1.to_i(16)].pack('U') }
|
30
|
-
end
|
31
|
-
|
32
|
-
def ruby_18
|
33
|
-
yield
|
34
|
-
end
|
35
|
-
|
36
|
-
def ruby_19
|
37
|
-
false
|
38
|
-
end
|
39
|
-
|
40
|
-
begin
|
41
|
-
require 'oniguruma'
|
42
|
-
|
43
|
-
def oniguruma
|
44
|
-
Oniguruma::ORegexp.new(yield, :syntax => Oniguruma::SYNTAX_JAVA, :encoding => Oniguruma::ENCODING_UTF8)
|
45
|
-
end
|
46
|
-
|
47
|
-
def oniguruma?
|
48
|
-
true
|
49
|
-
end
|
50
|
-
rescue LoadError
|
51
|
-
def oniguruma
|
52
|
-
false
|
53
|
-
end
|
54
|
-
alias oniguruma? oniguruma
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
# Remove the 'id' and 'type' methods in Ruby 1.8
|
59
|
-
class Object
|
60
|
-
undef_method :id
|
61
|
-
undef_method :type
|
62
|
-
end
|
63
|
-
|
64
|
-
else
|
65
|
-
|
66
|
-
module CiteProc
|
67
|
-
def to_unicode(string)
|
68
|
-
string
|
69
|
-
end
|
70
|
-
|
71
|
-
def ruby_18
|
72
|
-
false
|
73
|
-
end
|
74
|
-
|
75
|
-
def ruby_19
|
76
|
-
yield
|
77
|
-
end
|
78
|
-
|
79
|
-
def oniguruma
|
80
|
-
Regexp.new(yield)
|
81
|
-
end
|
82
|
-
|
83
|
-
def oniguruma?
|
84
|
-
true
|
85
|
-
end
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
3
|
#
|
90
4
|
# Robust unicode upcase/downcase
|
91
5
|
#
|
@@ -94,13 +8,9 @@ if RUBY_PLATFORM =~ /java/i
|
|
94
8
|
require 'java'
|
95
9
|
|
96
10
|
puts java.lang.System.getProperty('file.encoding')
|
97
|
-
|
11
|
+
|
98
12
|
module CiteProc
|
99
|
-
|
100
|
-
def jruby
|
101
|
-
yield
|
102
|
-
end
|
103
|
-
|
13
|
+
|
104
14
|
def upcase(string)
|
105
15
|
java.lang.String.new(string).to_upper_case(java.util.Locale::ENGLISH).to_s
|
106
16
|
end
|
@@ -108,23 +18,11 @@ if RUBY_PLATFORM =~ /java/i
|
|
108
18
|
def downcase(string)
|
109
19
|
java.lang.String.new(string).to_lower_case(java.util.Locale::ENGLISH).to_s
|
110
20
|
end
|
111
|
-
|
112
|
-
# def oniguruma
|
113
|
-
# Regexp.new(yield)
|
114
|
-
# end
|
115
|
-
#
|
116
|
-
# def oniguruma?
|
117
|
-
# true
|
118
|
-
# end
|
119
21
|
end
|
120
22
|
|
121
23
|
else
|
122
24
|
|
123
|
-
module CiteProc
|
124
|
-
|
125
|
-
def jruby
|
126
|
-
false
|
127
|
-
end
|
25
|
+
module CiteProc
|
128
26
|
|
129
27
|
begin
|
130
28
|
require 'unicode'
|
@@ -157,7 +55,7 @@ else
|
|
157
55
|
|
158
56
|
def downcase(string)
|
159
57
|
ActiveSupport::Multibyte::Chars.new(string).downcase.to_s
|
160
|
-
end
|
58
|
+
end
|
161
59
|
rescue LoadError
|
162
60
|
|
163
61
|
def upcase(string)
|
@@ -174,6 +72,5 @@ else
|
|
174
72
|
end
|
175
73
|
|
176
74
|
module CiteProc
|
177
|
-
module_function :
|
178
|
-
:to_unicode, :upcase, :downcase
|
75
|
+
module_function :upcase, :downcase
|
179
76
|
end
|