citeproc 1.0.0.pre12 → 1.0.0
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.
- 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
data/lib/citeproc/names.rb
CHANGED
@@ -44,12 +44,8 @@ module CiteProc
|
|
44
44
|
|
45
45
|
# Class instance variables
|
46
46
|
|
47
|
-
@romanesque =
|
48
|
-
|
49
|
-
} || CiteProc.ruby_18 {
|
50
|
-
# @todo improve fallback range
|
51
|
-
/^[a-zA-Zäöüéè\s[:punct:]]*$/u
|
52
|
-
}
|
47
|
+
@romanesque =
|
48
|
+
/^[\p{Latin}\p{Greek}\p{Cyrillic}\p{Hebrew}\p{Armenian}\p{Georgian}\p{Common}]*$/
|
53
49
|
|
54
50
|
# Default formatting options
|
55
51
|
@defaults = {
|
@@ -57,6 +53,8 @@ module CiteProc
|
|
57
53
|
:'name-as-sort-order' => false,
|
58
54
|
:'demote-non-dropping-particle' => :never,
|
59
55
|
:'sort-separator' => ', ',
|
56
|
+
:initialize => true,
|
57
|
+
:'initialize-with-hyphen' => true,
|
60
58
|
:'initialize-with' => nil
|
61
59
|
}.freeze
|
62
60
|
|
@@ -75,6 +73,8 @@ module CiteProc
|
|
75
73
|
# @return the name's formatting options
|
76
74
|
attr_reader :options
|
77
75
|
|
76
|
+
attr_reader :sort_prefix
|
77
|
+
|
78
78
|
attr_predicates :'comma-suffix', :'static-ordering', :multi, *@parts
|
79
79
|
|
80
80
|
# Aliases
|
@@ -92,8 +92,9 @@ module CiteProc
|
|
92
92
|
end
|
93
93
|
|
94
94
|
# Names quack sorta like a String
|
95
|
-
def_delegators :to_s, :=~, :===,
|
96
|
-
|
95
|
+
def_delegators :to_s, :=~, :===, *String.instance_methods(false).reject { |m|
|
96
|
+
m.to_s =~ /^[\W_]|[!=_]$|^(to_s|inspect|replace|first|last|dup|clone)$/
|
97
|
+
}
|
97
98
|
|
98
99
|
# Delegate bang! methods to each field's value
|
99
100
|
String.instance_methods(false).each do |m|
|
@@ -126,12 +127,24 @@ module CiteProc
|
|
126
127
|
end
|
127
128
|
|
128
129
|
|
130
|
+
# Resets the object's options to the default settings.
|
131
|
+
# @return [self]
|
132
|
+
def reset!
|
133
|
+
@options = Name.defaults.dup
|
134
|
+
end
|
135
|
+
|
136
|
+
# Returns a copy of the name object with all options
|
137
|
+
# reset to their default settings.
|
138
|
+
# @return [Name] a copy of the name with default options
|
139
|
+
def reset
|
140
|
+
dup.reset!
|
141
|
+
end
|
142
|
+
|
129
143
|
# @return [Boolean] whether or not the Name looks like it belongs to a person
|
130
144
|
def personal?
|
131
145
|
!empty? && !literal?
|
132
146
|
end
|
133
147
|
|
134
|
-
|
135
148
|
# A name is `romanesque' if it contains only romanesque characters. This
|
136
149
|
# should be the case for the majority of names written in latin- or
|
137
150
|
# greek-based script. It will be false, for example, for names written
|
@@ -173,15 +186,15 @@ module CiteProc
|
|
173
186
|
|
174
187
|
# Sets the name to use sort-order. The reverse of {#display_order!}.
|
175
188
|
# @return [self]
|
176
|
-
def sort_order!
|
177
|
-
options[:'name-as-sort-order'] =
|
189
|
+
def sort_order!(toggle = true)
|
190
|
+
options[:'name-as-sort-order'] = !!toggle
|
178
191
|
self
|
179
192
|
end
|
180
193
|
|
181
194
|
# Sets the name to use display-order. The reverse of {#sort_order!}.
|
182
195
|
# @return [self]
|
183
|
-
def display_order!
|
184
|
-
options[:'name-as-sort-order'] =
|
196
|
+
def display_order!(toggle = true)
|
197
|
+
options[:'name-as-sort-order'] = !toggle
|
185
198
|
self
|
186
199
|
end
|
187
200
|
|
@@ -200,7 +213,7 @@ module CiteProc
|
|
200
213
|
# Use short form for printing the name
|
201
214
|
# @return [self]
|
202
215
|
def short_form!
|
203
|
-
options[:form] =
|
216
|
+
options[:form] = 'short'
|
204
217
|
self
|
205
218
|
end
|
206
219
|
|
@@ -212,7 +225,7 @@ module CiteProc
|
|
212
225
|
# Use long form for printing the name
|
213
226
|
# @return [self]
|
214
227
|
def long_form!
|
215
|
-
options[:form] =
|
228
|
+
options[:form] = 'long'
|
216
229
|
self
|
217
230
|
end
|
218
231
|
|
@@ -221,6 +234,33 @@ module CiteProc
|
|
221
234
|
!!options[:'initialize-with'] && personal? && romanesque?
|
222
235
|
end
|
223
236
|
|
237
|
+
def initialize_with
|
238
|
+
options[:'initialize-with'].to_s
|
239
|
+
end
|
240
|
+
|
241
|
+
def initialize_existing_only?
|
242
|
+
options[:initialize].to_s == 'false'
|
243
|
+
end
|
244
|
+
|
245
|
+
def initialize_without_hyphen?
|
246
|
+
!options[:'initialize-with-hyphen']
|
247
|
+
end
|
248
|
+
|
249
|
+
def initialize_without_hyphen!
|
250
|
+
options[:'initialize-with-hyphen'] = false
|
251
|
+
end
|
252
|
+
|
253
|
+
def initials
|
254
|
+
case
|
255
|
+
when !initials?
|
256
|
+
given
|
257
|
+
when initialize_existing_only?
|
258
|
+
existing_initials_of given
|
259
|
+
else
|
260
|
+
initials_of given
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
224
264
|
def demote_non_dropping_particle?
|
225
265
|
always_demote_non_dropping_particle? ||
|
226
266
|
!!(sort_order? && options[:'demote-non-dropping-particle'] =~ /^sort(-only)?$/i)
|
@@ -266,31 +306,36 @@ module CiteProc
|
|
266
306
|
sort_order_downcase <=> other.sort_order_downcase
|
267
307
|
end
|
268
308
|
|
269
|
-
# @return [String] the name formatted according to the current options
|
270
309
|
def to_s
|
310
|
+
[given, family].compact_join(' ')
|
311
|
+
end
|
312
|
+
|
313
|
+
# @return [String] the name formatted according to the current options
|
314
|
+
def format
|
271
315
|
case
|
272
316
|
when literal?
|
273
317
|
literal.to_s
|
274
318
|
when static_order?
|
275
|
-
[family,
|
319
|
+
[family, initials].compact.join(' ')
|
276
320
|
when !short_form?
|
277
321
|
case
|
278
322
|
when !sort_order?
|
279
|
-
[[
|
323
|
+
[[initials, dropping_particle, particle, family].compact_join(' '),
|
280
324
|
suffix].compact_join(comma_suffix? ? comma : ' ')
|
281
325
|
|
282
326
|
when !demote_particle?
|
283
|
-
[[particle, family].compact_join(' '), [
|
327
|
+
[[particle, family].compact_join(' '), [initials,
|
284
328
|
dropping_particle].compact_join(' '), suffix].compact_join(comma)
|
285
329
|
|
286
330
|
else
|
287
|
-
[family, [
|
331
|
+
[family, [initials, dropping_particle, particle].compact_join(' '),
|
288
332
|
suffix].compact_join(comma)
|
289
333
|
end
|
290
334
|
else
|
291
335
|
[particle, family].compact_join(' ')
|
292
336
|
end
|
293
337
|
end
|
338
|
+
alias print format
|
294
339
|
|
295
340
|
# @return [Array<String>] an ordered array of formatted name parts to be used for sorting
|
296
341
|
def sort_order
|
@@ -326,8 +371,42 @@ module CiteProc
|
|
326
371
|
|
327
372
|
private
|
328
373
|
|
329
|
-
|
374
|
+
def filter_key(key)
|
375
|
+
key = key.to_s.tr('_', '-')
|
376
|
+
key = 'non-dropping-particle' if key == 'particle'
|
377
|
+
super key
|
378
|
+
end
|
379
|
+
|
380
|
+
def initials_of(string)
|
381
|
+
string = string.dup
|
382
|
+
|
383
|
+
string.gsub!(/([[:upper:]])[^[:upper:]\s-]*\s*/, "\\1#{initialize_with}")
|
384
|
+
|
385
|
+
initialize_hyphen!(string)
|
330
386
|
|
387
|
+
string.strip!
|
388
|
+
string
|
389
|
+
end
|
390
|
+
|
391
|
+
def initialize_hyphen!(string)
|
392
|
+
if initialize_without_hyphen?
|
393
|
+
string.tr!('-', '')
|
394
|
+
else
|
395
|
+
string.gsub!(/\s*-/, '-')
|
396
|
+
end
|
397
|
+
end
|
398
|
+
|
399
|
+
def existing_initials_of(string)
|
400
|
+
string = string.dup
|
401
|
+
|
402
|
+
string.gsub!(/([[:upper:]])([[:upper:]])/, '\1 \2')
|
403
|
+
string.gsub!(/\b([[:upper:]])\b[^[:alpha:]-]*/, "\\1#{initialize_with}")
|
404
|
+
|
405
|
+
initialize_hyphen!(string)
|
406
|
+
|
407
|
+
string.strip!
|
408
|
+
string
|
409
|
+
end
|
331
410
|
end
|
332
411
|
|
333
412
|
|
@@ -483,7 +562,7 @@ module CiteProc
|
|
483
562
|
@value << Name.new(value)
|
484
563
|
when value.respond_to?(:to_s)
|
485
564
|
begin
|
486
|
-
@value.concat Namae.parse!(value.to_s)
|
565
|
+
@value.concat Namae.parse!(value.to_s).map { |n| Name.new n }
|
487
566
|
rescue
|
488
567
|
raise TypeError, $!.message
|
489
568
|
end
|
@@ -635,7 +714,7 @@ module CiteProc
|
|
635
714
|
case
|
636
715
|
when truncate?
|
637
716
|
[names[0...max_names].join(delimiter), options[:'et-al']].join(truncated_delimiter)
|
638
|
-
when length <
|
717
|
+
when length < 3
|
639
718
|
names.join(last_delimiter)
|
640
719
|
else
|
641
720
|
[names[0...-1].join(delimiter), names[-1]].join(last_delimiter)
|
@@ -644,7 +723,7 @@ module CiteProc
|
|
644
723
|
|
645
724
|
# @return [String] the names in a BibTeX-compatible format
|
646
725
|
def to_bibtex
|
647
|
-
map { |n| n.dup.sort_order
|
726
|
+
map { |n| n.dup.sort_order!.format }.join(' and ')
|
648
727
|
end
|
649
728
|
|
650
729
|
# @return [Array<Hash>] the list of names converted to hash objects
|
data/lib/citeproc/number.rb
CHANGED
@@ -1,8 +1,10 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
1
3
|
module CiteProc
|
2
4
|
# A CiteProc Variable used for numeric values.
|
3
5
|
class Number < Variable
|
4
6
|
|
5
|
-
|
7
|
+
MAX_ROMAN = 5000
|
6
8
|
|
7
9
|
FACTORS = [
|
8
10
|
['m', 1000], ['cm', 900], ['d', 500], ['cd', 400],
|
@@ -11,12 +13,12 @@ module CiteProc
|
|
11
13
|
['i', 1]
|
12
14
|
].freeze
|
13
15
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
16
|
+
class << self
|
17
|
+
def pluralize?(string)
|
18
|
+
/\S[\s,&–-]\S|\df/ === string
|
19
|
+
end
|
20
|
+
|
21
|
+
# @param number [#to_i] the number to convert
|
20
22
|
# @return [String] roman equivalent of the passed-in number
|
21
23
|
def romanize(number)
|
22
24
|
number, roman = number.to_i, ''
|
@@ -30,7 +32,24 @@ module CiteProc
|
|
30
32
|
|
31
33
|
roman
|
32
34
|
end
|
33
|
-
|
35
|
+
end
|
36
|
+
|
37
|
+
def <=>(other)
|
38
|
+
case
|
39
|
+
when other.nil?
|
40
|
+
1
|
41
|
+
when numeric?
|
42
|
+
if other.respond_to?(:to_i)
|
43
|
+
to_i <=> other.to_i
|
44
|
+
else
|
45
|
+
nil
|
46
|
+
end
|
47
|
+
when other.is_a?(Variable) || other.is_a?(String)
|
48
|
+
to_s <=> other.to_s
|
49
|
+
else
|
50
|
+
nil
|
51
|
+
end
|
52
|
+
end
|
34
53
|
end
|
35
54
|
|
36
55
|
end
|
data/lib/citeproc/processor.rb
CHANGED
@@ -1,33 +1,32 @@
|
|
1
|
-
|
2
1
|
module CiteProc
|
3
|
-
|
2
|
+
|
4
3
|
class Processor
|
5
4
|
extend Forwardable
|
6
5
|
|
7
6
|
include Abbreviate
|
8
7
|
include Converters
|
9
|
-
|
8
|
+
|
10
9
|
@defaults = {
|
11
10
|
:locale => 'en-US',
|
12
11
|
:style => 'chicago-author-date',
|
13
|
-
:engine => 'citeproc-
|
14
|
-
:format => 'html'
|
12
|
+
:engine => 'citeproc-ruby',
|
13
|
+
:format => 'html',
|
14
|
+
:sort_case_sensitivity => false,
|
15
|
+
:allow_locale_overrides => false
|
15
16
|
}.freeze
|
16
17
|
|
17
18
|
class << self
|
18
19
|
attr_reader :defaults
|
19
20
|
end
|
20
21
|
|
21
|
-
attr_reader :options, :items
|
22
|
+
attr_reader :options, :items, :data
|
22
23
|
attr_writer :engine
|
23
24
|
|
24
|
-
def_delegators :@locale, :language, :region
|
25
|
-
|
26
25
|
def_delegators :@items, :key?, :value?, :has_key?, :has_value?,
|
27
26
|
:include?, :member?, :length, :empty?
|
28
|
-
|
27
|
+
|
29
28
|
def initialize(options = {})
|
30
|
-
@options, @items = Processor.defaults.merge(options), {}
|
29
|
+
@options, @items, @data = Processor.defaults.merge(options), {}, []
|
31
30
|
yield self if block_given?
|
32
31
|
end
|
33
32
|
|
@@ -35,46 +34,34 @@ module CiteProc
|
|
35
34
|
@engine ||= Engine.autodetect(options).new(self)
|
36
35
|
end
|
37
36
|
|
38
|
-
def style
|
39
|
-
@style || load_style
|
40
|
-
end
|
41
|
-
|
42
|
-
def locale
|
43
|
-
@locale || load_locale
|
44
|
-
end
|
45
|
-
|
46
|
-
def load_style(new_style = nil)
|
47
|
-
options[:style] = new_style unless new_style.nil?
|
48
|
-
@style = Style.open(options[:style])
|
49
|
-
end
|
50
|
-
|
51
|
-
def load_locale(new_locale = nil)
|
52
|
-
options[:locale] = new_locale unless new_locale.nil?
|
53
|
-
@locale = Locale.open(options[:locale])
|
54
|
-
end
|
55
|
-
|
56
37
|
def [](id)
|
57
|
-
items[id.
|
38
|
+
items[id.to_s]
|
58
39
|
end
|
59
40
|
|
60
41
|
def []=(id, item)
|
61
|
-
|
42
|
+
item = Item(item)
|
43
|
+
item.id = id.to_s
|
44
|
+
|
45
|
+
register(items)
|
62
46
|
end
|
63
|
-
|
47
|
+
|
64
48
|
def register(item)
|
65
49
|
item = Item(item)
|
66
|
-
|
50
|
+
|
51
|
+
data << item
|
52
|
+
items[item.id.to_s] = item
|
53
|
+
|
67
54
|
rescue => e
|
68
55
|
raise "failed to register item #{item.inspect}: #{e.message}"
|
69
56
|
end
|
70
|
-
|
57
|
+
|
71
58
|
def <<(item)
|
72
59
|
register(item)
|
73
60
|
self
|
74
61
|
end
|
75
|
-
|
62
|
+
|
76
63
|
def update(*arguments)
|
77
|
-
arguments.
|
64
|
+
arguments.each do |argument|
|
78
65
|
case argument
|
79
66
|
when Item
|
80
67
|
register(argument)
|
@@ -82,8 +69,8 @@ module CiteProc
|
|
82
69
|
argument.each { |item| register(item) }
|
83
70
|
when Hash
|
84
71
|
argument.each do |id, item|
|
85
|
-
id, item = id.
|
86
|
-
|
72
|
+
id, item = id.to_s, Item(item)
|
73
|
+
|
87
74
|
if items.key?(id) && block_given?
|
88
75
|
items[id] = yield items[id], item
|
89
76
|
else
|
@@ -94,12 +81,12 @@ module CiteProc
|
|
94
81
|
raise "failed to register items #{argument.inspect}"
|
95
82
|
end
|
96
83
|
end
|
97
|
-
|
84
|
+
|
98
85
|
self
|
99
86
|
ensure
|
100
87
|
# notify engine
|
101
88
|
end
|
102
|
-
|
89
|
+
alias import update
|
103
90
|
|
104
91
|
|
105
92
|
def process(*arguments)
|
@@ -114,9 +101,12 @@ module CiteProc
|
|
114
101
|
engine.bibliography(Selector.new(*arguments, &block))
|
115
102
|
end
|
116
103
|
|
104
|
+
def render(mode, *arguments)
|
105
|
+
engine.render(mode, CitationData.new(arguments.flatten(1)))
|
106
|
+
end
|
107
|
+
|
117
108
|
def inspect
|
118
|
-
"#<CiteProc::Processor style=#{style.
|
109
|
+
"#<CiteProc::Processor style=#{options[:style].inspect} locale=#{options[:locale].inspect} items=[#{items.length}]>"
|
119
110
|
end
|
120
|
-
|
121
111
|
end
|
122
112
|
end
|
data/lib/citeproc/selector.rb
CHANGED
@@ -1,128 +1,134 @@
|
|
1
1
|
|
2
2
|
module CiteProc
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
3
|
+
|
4
|
+
class Selector
|
5
|
+
|
6
|
+
@types = [:all, :any, :none].freeze
|
7
|
+
@matcher = Hash[*@types.zip([:all?, :any?, :none?]).flatten].freeze
|
8
|
+
|
9
|
+
@rb2cp = Hash[*(@types + [:skip]).zip(%w{
|
10
|
+
select include exclude quash
|
11
|
+
}).flatten]
|
12
|
+
|
13
|
+
@cp2rb = @rb2cp.invert.freeze
|
14
|
+
@rb2cp.freeze
|
15
|
+
|
16
|
+
class << self
|
17
|
+
attr_reader :types, :matcher, :rb2cp, :cp2rb
|
18
|
+
end
|
19
|
+
|
20
|
+
attr_reader :type, :conditions, :skip_conditions, :custom_matcher
|
21
|
+
|
22
|
+
def initialize(attributes = nil)
|
23
|
+
@conditions, @skip_conditions = {}, {}
|
24
|
+
|
25
|
+
if block_given?
|
26
|
+
@type = :ruby
|
27
|
+
|
28
|
+
else
|
29
|
+
unless attributes.nil? || attributes.empty?
|
30
|
+
attributes.symbolize_keys.each_pair do |key, conditions|
|
31
|
+
conditions = convert_conditions(conditions) if conditions.is_a?(Array)
|
32
|
+
|
33
|
+
case key
|
34
|
+
when :all, :any, :none
|
35
|
+
@type = key
|
36
|
+
@conditions.merge!(conditions)
|
37
|
+
|
38
|
+
when :select, :include, :exclude
|
39
|
+
@type = Selector.cp2rb[key.to_s]
|
40
|
+
@conditions.merge!(conditions)
|
41
|
+
|
42
|
+
when :skip, :quash
|
43
|
+
@skip_conditions.merge!(conditions)
|
44
|
+
|
45
|
+
else
|
46
|
+
raise TypeError, "failed to create selector from #{key.inspect}"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def initialize_copy(other)
|
54
|
+
@type = other.type
|
55
|
+
@conditions = other.conditions.deep_copy
|
56
|
+
@skip_conditions = other.skip_conditions.deep_copy
|
57
|
+
@custom_matcher = other
|
58
|
+
end
|
59
|
+
|
60
|
+
def type=(type)
|
61
|
+
raise TypeError, "failed to set selector type to #{type.inspect}" unless
|
62
|
+
type.respond_to(:to_sym) && Selector.types.include?(type.to_sym)
|
63
|
+
|
64
|
+
@type = type.to_sym
|
65
|
+
end
|
66
|
+
|
67
|
+
def empty?
|
68
|
+
type.nil? && skip_conditions.empty?
|
69
|
+
end
|
70
|
+
|
71
|
+
def custom_matcher?
|
72
|
+
defined?(@custom_matcher)
|
73
|
+
end
|
74
|
+
|
75
|
+
alias ruby? custom_matcher?
|
76
|
+
|
77
|
+
def matches?(item)
|
78
|
+
if custom_matcher?
|
79
|
+
custom_matcher.call(item)
|
80
|
+
else
|
81
|
+
conditions.each_pair.send(matcher) do |field, value|
|
82
|
+
item[field].to_s == value.to_s
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def skip?(item)
|
88
|
+
if custom_matcher? || skip_conditions.empty?
|
89
|
+
false # skips are ignored for custom matchers
|
90
|
+
else
|
91
|
+
skip_conditions.each_pair.all? do |field, value|
|
92
|
+
item[field].to_s == value.to_s
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def to_proc
|
98
|
+
Proc.new { |item| matches?(item) && !skip?(item) }
|
99
|
+
end
|
100
|
+
|
101
|
+
def to_citeproc
|
102
|
+
return nil if empty? || custom_matcher?
|
103
|
+
|
104
|
+
cp = {}
|
105
|
+
cp[Selector.rb2cp[type]] = conditions.map do |field, value|
|
106
|
+
{ 'field' => field.to_s, 'value' => value.to_s }
|
107
|
+
end unless conditions.empty?
|
108
|
+
|
109
|
+
cp['quash'] = skip_conditions.map do |field, value|
|
110
|
+
{ 'field' => field.to_s, 'value' => value.to_s }
|
111
|
+
end unless skip_conditions.empty?
|
112
|
+
|
113
|
+
cp
|
114
|
+
end
|
115
|
+
|
116
|
+
def to_json
|
117
|
+
::JSON.dump(to_citeproc)
|
118
|
+
end
|
119
|
+
|
120
|
+
private
|
121
|
+
|
122
|
+
def matcher
|
123
|
+
Selector.matcher[type] || :all?
|
124
|
+
end
|
125
|
+
|
126
|
+
# Converts a CiteProc-JS style conditions list into
|
127
|
+
# a conditions Hash.
|
128
|
+
def convert_conditions(conditions)
|
129
|
+
Hash[conditions.map { |c| [c['field'], c['value']] }]
|
130
|
+
end
|
131
|
+
|
132
|
+
end
|
133
|
+
|
134
|
+
end
|