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.
Files changed (45) hide show
  1. checksums.yaml +7 -0
  2. data/.simplecov +4 -0
  3. data/AGPL +1 -1
  4. data/BSDL +2 -2
  5. data/Gemfile +39 -19
  6. data/README.md +123 -14
  7. data/Rakefile +22 -8
  8. data/cucumber.yml +1 -1
  9. data/features/step_definitions/processor.rb +59 -0
  10. data/features/support/env.rb +45 -2
  11. data/lib/citeproc.rb +8 -8
  12. data/lib/citeproc/abbreviate.rb +5 -4
  13. data/lib/citeproc/assets.rb +109 -109
  14. data/lib/citeproc/attributes.rb +11 -11
  15. data/lib/citeproc/bibliography.rb +107 -71
  16. data/lib/citeproc/citation_data.rb +175 -150
  17. data/lib/citeproc/compatibility.rb +5 -108
  18. data/lib/citeproc/date.rb +23 -12
  19. data/lib/citeproc/engine.rb +9 -4
  20. data/lib/citeproc/errors.rb +6 -6
  21. data/lib/citeproc/extensions.rb +66 -66
  22. data/lib/citeproc/item.rb +60 -2
  23. data/lib/citeproc/names.rb +103 -24
  24. data/lib/citeproc/number.rb +27 -8
  25. data/lib/citeproc/processor.rb +31 -41
  26. data/lib/citeproc/selector.rb +132 -126
  27. data/lib/citeproc/utilities.rb +6 -6
  28. data/lib/citeproc/variable.rb +5 -4
  29. data/lib/citeproc/version.rb +1 -1
  30. data/spec/citeproc/assets_spec.rb +17 -15
  31. data/spec/citeproc/bibliography_spec.rb +17 -17
  32. data/spec/citeproc/citation_data_spec.rb +90 -90
  33. data/spec/citeproc/engine_spec.rb +3 -4
  34. data/spec/citeproc/item_spec.rb +76 -68
  35. data/spec/citeproc/names_spec.rb +187 -148
  36. data/spec/citeproc/processor_spec.rb +119 -115
  37. data/spec/citeproc/selector_spec.rb +87 -78
  38. data/spec/citeproc/variable_spec.rb +30 -30
  39. data/spec/fixtures/locales/locales-en-US.xml +304 -0
  40. data/spec/spec_helper.rb +32 -1
  41. data/tasks/testsuite.rb +209 -0
  42. metadata +19 -87
  43. data/.gitignore +0 -6
  44. data/.travis.yml +0 -21
  45. data/citeproc.gemspec +0 -40
@@ -44,12 +44,8 @@ module CiteProc
44
44
 
45
45
  # Class instance variables
46
46
 
47
- @romanesque = CiteProc.oniguruma {
48
- '^[\p{Latin}\p{Greek}\p{Cyrillic}\p{Hebrew}\p{Armenian}\p{Georgian}\p{Common}]*$'
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
- *String.instance_methods(false).reject { |m| m =~ /^\W|!$|to_s|replace|first|last/ }
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'] = true
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'] = false
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] = :short
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] = :long
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, given].compact.join(' ')
319
+ [family, initials].compact.join(' ')
276
320
  when !short_form?
277
321
  case
278
322
  when !sort_order?
279
- [[given, dropping_particle, particle, family].compact_join(' '),
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(' '), [given,
327
+ [[particle, family].compact_join(' '), [initials,
284
328
  dropping_particle].compact_join(' '), suffix].compact_join(comma)
285
329
 
286
330
  else
287
- [family, [given, dropping_particle, particle].compact_join(' '),
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
- attr_reader :sort_prefix
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 < 2
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! }.join(' and ')
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
@@ -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
- MAX_ROMAN = 5000
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
- class << self
15
- def pluralize?(string)
16
- /\S\s*[,&-]\s*\S|\df/ === string
17
- end
18
-
19
- # @param number [#to_i] the number to convert
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
- end
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
@@ -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-js',
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.to_sym]
38
+ items[id.to_s]
58
39
  end
59
40
 
60
41
  def []=(id, item)
61
- items[id.to_sym] = Item(item)
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
- items[item.to_sym] = item
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.flatten(1).each do |argument|
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.to_sym, Item(item)
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.name.inspect} locale=#{locale.name.inspect} items=[#{items.length}]>"
109
+ "#<CiteProc::Processor style=#{options[:style].inspect} locale=#{options[:locale].inspect} items=[#{items.length}]>"
119
110
  end
120
-
121
111
  end
122
112
  end
@@ -1,128 +1,134 @@
1
1
 
2
2
  module CiteProc
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
- case key
32
- when :all, :any, :none
33
- @type = key
34
- @conditions.merge!(conditions)
35
-
36
- when :select, :include, :exclude
37
- @type = Selector.cp2rb[key.to_s]
38
- @conditions.merge!(conditions)
39
-
40
- when :skip, :quash
41
- @skip_conditions.merge!(conditions)
42
-
43
- else
44
- raise TypeError, "failed to create selector from #{key.inspect}"
45
- end
46
- end
47
- end
48
- end
49
-
50
- end
51
-
52
- def initialize_copy(other)
53
- @type = other.type
54
- @conditions = other.conditions.deep_copy
55
- @skip_conditions = other.skip_conditions.deep_copy
56
- @custom_matcher = other
57
- end
58
-
59
- def type=(type)
60
- raise TypeError, "failed to set selector type to #{type.inspect}" unless
61
- type.respond_to(:to_sym) && Selector.types.include?(type.to_sym)
62
-
63
- @type = type.to_sym
64
- end
65
-
66
- def empty?
67
- type.nil? && skip_conditions.empty?
68
- end
69
-
70
- def custom_matcher?
71
- defined?(@custom_matcher)
72
- end
73
-
74
- alias ruby? custom_matcher?
75
-
76
- def matches?(item)
77
- if custom_matcher?
78
- custom_matcher.call(item)
79
- else
80
- conditions.each_pair.send(matcher) do |field, value|
81
- item[field].to_s == value.to_s
82
- end
83
- end
84
- end
85
-
86
- def skip?(item)
87
- if custom_matcher?
88
- false # skips are ignored for custom matchers
89
- else
90
- skip_conditions.each_pair.all? do |field, value|
91
- item[field].to_s == value.to_s
92
- end
93
- end
94
- end
95
-
96
- def to_proc
97
- Proc.new { |item| matches?(item) && !skip?(item) }
98
- end
99
-
100
- def to_citeproc
101
- return nil if empty? || custom_matcher?
102
-
103
- cp = {}
104
- cp[Selector.rb2cp[type]] = conditions.map do |field, value|
105
- { 'field' => field.to_s, 'value' => value.to_s }
106
- end unless conditions.empty?
107
-
108
- cp['quash'] = skip_conditions.map do |field, value|
109
- { 'field' => field.to_s, 'value' => value.to_s }
110
- end unless skip_conditions.empty?
111
-
112
- cp
113
- end
114
-
115
- def to_json
116
- MultiJson.encode(to_citeproc)
117
- end
118
-
119
- private
120
-
121
- def matcher
122
- Selector.matcher[type] || :all?
123
- end
124
-
125
-
126
- end
127
-
128
- end
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