csl 2.3.0 → 2.5.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c0f6649dcc754264a3546a210a92cc4dd50ed8910ef011d61c0db3818cb1c576
4
- data.tar.gz: 85ebc13c82b78cfefd1898c1e44380acea10fead06a1ac7bb4a34dc09b51d77b
3
+ metadata.gz: e483c629270cabba02a203aba157f855f758ee6a479bd3fe609749dbbc5ca4dd
4
+ data.tar.gz: b12ab1cfcb7d80659cd248d490f1ed5a55c628c6c9ef007207a97046a9788c54
5
5
  SHA512:
6
- metadata.gz: 1934e44e5893b200dc7ca55d522c3fc0024a0510e2a8d918bc5596f5249adad6c0357cae926ff2d47087404f9d3d58767a8448833d017bd47fbfcb8700922db6
7
- data.tar.gz: cab29314253dd59ef4f669e3e649d6bf562eaa9799b8c6384e48a6d20bbc091b4d9a10079929ef960be2997c3879c775eb34c04faf73014693a3c0a0a0e6a080
6
+ metadata.gz: 3a7ab825b430ba85795216742d476bccab2bab9d38f038f383d0c496b61cd0ffdd1d4f17cd2119e87f011b99a509fd06b8a0869f7734904a8705287117867881
7
+ data.tar.gz: d5e3fe727078cfd20acbfd7ca3de9ae1d1dc59cd8f259cf90f69245e139f10460553ede8a96f76e7850d105e5542dea3bf78c17cce3a630b1fafa6e03fd9cae2
@@ -80,10 +80,11 @@ module CSL
80
80
  return unless has_ordinals?
81
81
 
82
82
  options = Term.specialize(options)
83
+ form, options = options[:form], options.except(:form)
83
84
  number = number.to_i.abs
84
85
 
85
86
  # try to match long-ordinals first
86
- if options.delete(:form).to_s =~ /^long/i
87
+ if form.to_s =~ /^long/i
87
88
  ordinal = lookup_long_ordinal_for number, options
88
89
  return ordinal unless ordinal.nil?
89
90
  end
@@ -94,9 +95,9 @@ module CSL
94
95
  ordinal = send algorithm, number, options
95
96
  return ordinal unless ordinal.nil?
96
97
 
97
- # fallback to non-gendered version
98
- if options.delete(:'gender-form')
99
- ordinal = send algorithm, number, options
98
+ # fallback to neuter
99
+ if options.key?(:'gender-form')
100
+ ordinal = send algorithm, number, options.merge(:'gender-form' => nil)
100
101
  end
101
102
 
102
103
  ordinal
@@ -342,14 +343,14 @@ module CSL
342
343
 
343
344
  def singularize
344
345
  return text if textnode?
345
- children.single.to_s
346
+ children.single&.text.to_s.strip
346
347
  end
347
348
 
348
349
  alias singular singularize
349
350
 
350
351
  def pluralize
351
352
  return text if textnode?
352
- children.multiple.to_s
353
+ children.multiple&.text.to_s.strip
353
354
  end
354
355
 
355
356
  alias plural pluralize
data/lib/csl/locale.rb CHANGED
@@ -55,7 +55,7 @@ module CSL
55
55
  error = nil
56
56
 
57
57
  candidates.each do |candidate|
58
- return super(candidate)
58
+ return super(candidate).tap { |locale| locale.requested = tag }
59
59
  rescue ParseError => e
60
60
  error ||= e
61
61
  end
@@ -119,6 +119,10 @@ module CSL
119
119
 
120
120
  attr_accessor :region, :script
121
121
 
122
+ # @return [String, nil] the IETF tag the locale was loaded for;
123
+ # this differs from the locale's own tag if the locale is a fallback
124
+ attr_accessor :requested
125
+
122
126
  alias_child :metadata, :info
123
127
  alias_child :dates, :date
124
128
  alias_child :options, :style_options
@@ -171,6 +175,7 @@ module CSL
171
175
  def initialize_copy(other)
172
176
  @parent, @ancestors, @descendants, @siblings, @root, @depth = nil
173
177
  initialize(other.attributes.to_hash.merge(:lang => other.to_s))
178
+ @requested = other.requested
174
179
  end
175
180
 
176
181
  def added_to(node)
@@ -266,8 +271,9 @@ module CSL
266
271
  # de.ordinalize(13)
267
272
  # #-> "13."
268
273
  #
269
- # de.ordinalize(3, :form => :long, :gender => :feminine)
270
- # #-> "dritte"
274
+ # fr = Locale.load('fr')
275
+ # fr.ordinalize(1, :'gender-form' => 'feminine')
276
+ # #-> "1ʳᵉ"
271
277
  #
272
278
  # @note
273
279
  # For CSL 1.0 (and older) locales that do not define an "ordinal-00"
@@ -279,8 +285,12 @@ module CSL
279
285
  # @param options [Hash] formatting options
280
286
  #
281
287
  # @option options [:short,:long] :form (:short) which ordinals form to use
282
- # @option options [:feminine,:masculine,:neutral] :gender (:neutral)
283
- # which ordinals gender-form to use
288
+ # @option options ['feminine','masculine',nil] :'gender-form' (nil)
289
+ # which ordinals gender-form to use; falls back to the neuter
290
+ # ordinals (without gender-form)
291
+ # @option options [String] :noun the name of the term accompanied by
292
+ # the ordinal (e.g., "edition" or "month-01"); the ordinal uses the
293
+ # gender of the term unless a gender-form is given
284
294
  #
285
295
  # @raise [ArgumentError] if number cannot be converted to an integer
286
296
  #
@@ -290,6 +300,12 @@ module CSL
290
300
  number.respond_to?(:to_i)
291
301
 
292
302
  number = number.to_i
303
+
304
+ noun = terms.lookup(options[:noun]) if options.key?(:noun)
305
+ if noun&.gendered? && !options.key?(:'gender-form')
306
+ options = options.merge(:'gender-form' => noun.gender)
307
+ end
308
+
293
309
  ordinal = terms.ordinalize number, options
294
310
 
295
311
  return number.to_s if ordinal.nil?
@@ -300,8 +316,7 @@ module CSL
300
316
 
301
317
  # @return [Boolean] true when the option limit-day-ordinals-to-day-1 is true
302
318
  def limit_day_ordinals?
303
- return false unless has_options? && options.attribute?(:'limit-day-ordinals-to-day-1')
304
- !!(options[:'limit-day-ordinals-to-day-1'].to_s =~ /^true$/i)
319
+ has_options? && options.boolean_attribute(:'limit-day-ordinals-to-day-1')
305
320
  end
306
321
 
307
322
  def limit_day_ordinals!
@@ -314,8 +329,7 @@ module CSL
314
329
 
315
330
  # @return [Boolean] true when the option punctuation-in-quote is true
316
331
  def punctuation_in_quote?
317
- return false unless has_options? && options.attribute?(:'punctuation-in-quote')
318
- !!(options[:'punctuation-in-quote'].to_s =~ /^true$/i)
332
+ has_options? && options.boolean_attribute(:'punctuation-in-quote')
319
333
  end
320
334
  alias punctuation_in_quotes? punctuation_in_quote?
321
335
 
@@ -399,13 +413,13 @@ module CSL
399
413
 
400
414
  # @returns [Boolean] whether or not the Locale is the default locale
401
415
  def default?
402
- to_s == Locale.default
416
+ default_tag?(language, script, region)
403
417
  end
404
418
 
405
419
  # @return [Boolean] whehter or not the Locale's region is the default
406
420
  # region for its language
407
421
  def default_region?
408
- region && region == Locale.regions[language]
422
+ default_region_for?(language, region)
409
423
  end
410
424
 
411
425
  # @return [Boolean] whether or not the Locale's language is the default
@@ -414,11 +428,25 @@ module CSL
414
428
  language && language == Locale.languages[region]
415
429
  end
416
430
 
431
+ # Whether or not the passed-in locale (e.g., an in-style locale)
432
+ # matches this locale. This is the case for universal locales and
433
+ # for locales of the language this locale was requested for.
417
434
  def like?(other)
418
435
  return false unless other.is_a? Locale
419
436
  return true if other.universal?
420
437
 
421
- language == other.language
438
+ requested_language == other.language
439
+ end
440
+
441
+ # @return [Symbol, nil] the language this locale was requested for
442
+ def requested_language
443
+ requested.nil? ? language : requested.split('-')[0].to_sym
444
+ end
445
+
446
+ # @return [Boolean] whether or not the locale was loaded as a
447
+ # fallback for a different locale
448
+ def fallback?
449
+ !requested.nil? && requested != to_s
422
450
  end
423
451
 
424
452
  def universal?
@@ -461,44 +489,76 @@ module CSL
461
489
  # de-DE will come before de-AT even though the alphabetical order
462
490
  # would be different).
463
491
  #
492
+ # Fallback locales are compared as the locale they were requested
493
+ # for (see #requested); locale data (terms, dates, and options) is
494
+ # not compared.
495
+ #
464
496
  # @param other [Locale] the locale used for comparison
465
497
  # @return [1,0,-1,nil] the result of the comparison
466
498
  def <=>(other)
499
+ return nil unless other.is_a?(Locale)
500
+ compare(identity, other.identity)
501
+ end
502
+
503
+ # @return [String] the Locale's IETF tag
504
+ def to_s
505
+ [language, script, region].compact.join('-')
506
+ end
507
+
508
+ # @return [String] a string representation of the Locale
509
+ def inspect
510
+ "#<#{self.class.name} #{to_s}>"
511
+ end
512
+
513
+ protected
514
+
515
+ # @return [Array<Symbol, nil>] language, script, and region of the
516
+ # locale or, for fallback locales, of the requested tag
517
+ def identity
518
+ return [language, script, region] unless fallback?
519
+
520
+ language, *rs = requested.split('-').map(&:to_sym)
521
+ region, script = rs.reverse
522
+
523
+ [language, script, region]
524
+ end
525
+
526
+ private
527
+
528
+ # Compares two locale identities (see #identity).
529
+ def compare(a, b)
530
+ language, script, region = a
531
+ other_language, other_script, other_region = b
532
+
467
533
  case
468
- when !other.is_a?(Locale)
469
- nil
470
- when [language, region] == [other.language, other.region]
471
- script <=> other.script
472
- when default?
534
+ when [language, region] == [other_language, other_region]
535
+ script <=> other_script
536
+ when default_tag?(*a)
473
537
  -1
474
- when other.default?
538
+ when default_tag?(*b)
475
539
  1
476
- when language == other.language
540
+ when language == other_language
477
541
  case
478
- when default_region?
542
+ when default_region_for?(language, region)
479
543
  -1
480
- when other.default_region?
544
+ when default_region_for?(other_language, other_region)
481
545
  1
482
546
  else
483
- region.to_s <=> other.region.to_s
547
+ region.to_s <=> other_region.to_s
484
548
  end
485
549
  else
486
- language.to_s <=> other.language.to_s
550
+ language.to_s <=> other_language.to_s
487
551
  end
488
552
  end
489
553
 
490
- # @return [String] the Locale's IETF tag
491
- def to_s
492
- [language, script, region].compact.join('-')
554
+ def default_tag?(language, script, region)
555
+ [language, script, region].compact.join('-') == Locale.default
493
556
  end
494
557
 
495
- # @return [String] a string representation of the Locale
496
- def inspect
497
- "#<#{self.class.name} #{to_s}>"
558
+ def default_region_for?(language, region)
559
+ region && region == Locale.regions[language]
498
560
  end
499
561
 
500
- private
501
-
502
562
  alias original_locale_attribute_assignments attribute_assignments
503
563
 
504
564
  def attribute_assignments
@@ -549,6 +609,9 @@ module CSL
549
609
  def merge_terms(other)
550
610
  return self unless other.has_terms?
551
611
 
612
+ # Ordinals are replaced as a set
613
+ terms.drop_ordinals if has_terms? && other.terms.has_ordinals?
614
+
552
615
  other.each_term do |term|
553
616
  store term.deep_copy
554
617
  end
data/lib/csl/node.rb CHANGED
@@ -168,13 +168,10 @@ module CSL
168
168
  end
169
169
 
170
170
  def fetch(key, default = nil)
171
- value = keys.include?(key.to_sym) && send(:'[]', key)
171
+ value = send(:'[]', key) if keys.include?(key.to_sym)
172
+ return value unless value.nil?
172
173
 
173
- if block_given?
174
- value || yield(key)
175
- else
176
- value || default
177
- end
174
+ block_given? ? yield(key) : default
178
175
  end
179
176
 
180
177
  # Merges the current with the passed-in attributes.
@@ -307,6 +304,17 @@ module CSL
307
304
  attributes.fetch(name, false)
308
305
  end
309
306
 
307
+ # @param name [Symbol] the name of an xsd:boolean attribute
308
+ # @param default [Boolean] the value if the attribute is not set
309
+ # @return [Boolean] the value of the boolean attribute
310
+ def boolean_attribute(name, default = false)
311
+ case attributes.fetch(name, nil).to_s
312
+ when 'true', '1' then true
313
+ when 'false', '0' then false
314
+ else default
315
+ end
316
+ end
317
+
310
318
  # @param [[String]] names list of attribute names
311
319
  # @return [Boolean] true if the node contains attributes for all
312
320
  # passed-in names; false otherwise.
@@ -466,11 +474,11 @@ module CSL
466
474
  end
467
475
 
468
476
  def strip_periods?
469
- attribute?(:'strip-periods') && !!(attributes[:'strip-periods'].to_s =~ /^true$/i)
477
+ boolean_attribute(:'strip-periods')
470
478
  end
471
479
 
472
480
  def quotes?
473
- attribute?(:'quotes') && !!(attributes[:'quotes'].to_s =~ /^true$/i)
481
+ boolean_attribute(:quotes)
474
482
  end
475
483
 
476
484
 
@@ -573,17 +581,6 @@ module CSL
573
581
  CSL.encode_xml_text text.to_s.strip
574
582
  end
575
583
 
576
- # TextNodes quack like a string.
577
- # def_delegators :to_s, *String.instance_methods(false).reject do |m|
578
- # m.to_s =~ /^\W|!$|(?:^(?:hash|eql?|to_s|length|size|inspect)$)/
579
- # end
580
- #
581
- # String.instance_methods(false).select { |m| m.to_s =~ /!$/ }.each do |m|
582
- # define_method(m) do
583
- # content.send(m) if content.respond_to?(m)
584
- # end
585
- # end
586
-
587
584
  def initialize(argument = '')
588
585
  case
589
586
  when argument.respond_to?(:each_pair)
@@ -25,6 +25,10 @@ module CSL
25
25
  children[:sort].sort_keys
26
26
  end
27
27
 
28
+ def second_field_align?
29
+ attribute?(:'second-field-align')
30
+ end
31
+
28
32
  def substitute_subsequent_authors?
29
33
  attribute?(:'subsequent-author-substitute')
30
34
  end
@@ -64,6 +64,49 @@ module CSL
64
64
  def has_overrides?
65
65
  localized? && has_parts?
66
66
  end
67
+
68
+ # Localized dates use the date parts of the locale's date in the
69
+ # same form, filtered by the date-parts attribute; the date parts of
70
+ # this date override their attributes, except for the affixes.
71
+ #
72
+ # @param locale [CSL::Locale]
73
+ # @raise [CSL::Error] if the locale has no date in the same form
74
+ # @return [Array<CSL::Style::DatePart, CSL::Locale::DatePart>]
75
+ # the date parts to use
76
+ def parts_for(locale)
77
+ return parts unless localized?
78
+
79
+ filter = parts_filter
80
+
81
+ localized_date_for(locale).parts
82
+ .select { |part| filter.include?(part.name) }
83
+ .map { |part| override(part) }
84
+ end
85
+
86
+ # @param locale [CSL::Locale]
87
+ # @raise [CSL::Error] if the locale has no date in the same form
88
+ # @return [String] the delimiter to use
89
+ def delimiter_for(locale)
90
+ localized? ? localized_date_for(locale).delimiter : delimiter
91
+ end
92
+
93
+ private
94
+
95
+ def localized_date_for(locale)
96
+ locale.each_date.detect { |date| date.form == form } or
97
+ raise Error, "no localized date for form #{form} found"
98
+ end
99
+
100
+ # @return [CSL::Locale::DatePart] the part or a copy
101
+ # with the attributes of the matching date part
102
+ def override(part)
103
+ override = parts.detect { |p| p.name == part.name }
104
+ return part if override.nil?
105
+
106
+ copy = part.deep_copy
107
+ copy.merge! override.attributes.to_hash.except(:prefix, :suffix)
108
+ copy
109
+ end
67
110
  end
68
111
 
69
112
  class DatePart < Node
@@ -181,8 +181,11 @@ module CSL
181
181
  self
182
182
  end
183
183
 
184
+ # @param names [#to_i, Enumerable] the list of names (or its length)
185
+ # @return [Boolean] whether or not the delimiter will be inserted
186
+ # before et-al
184
187
  def delimiter_precedes_et_al?(names)
185
- names = names.length if names.respond_to?(:length)
188
+ count = names.respond_to?(:length) ? names.length : names.to_i
186
189
 
187
190
  case
188
191
  when delimiter_never_precedes_et_al?
@@ -190,9 +193,9 @@ module CSL
190
193
  when delimiter_always_precedes_et_al?
191
194
  true
192
195
  when delimiter_precedes_et_al_after_inverted_name?
193
- name_as_sort_order_at?(names.to_i)
196
+ inverted_at?(names, count)
194
197
  else
195
- names.to_i > 1
198
+ count > 1
196
199
  end
197
200
  end
198
201
 
@@ -229,7 +232,7 @@ module CSL
229
232
  # be inserted between before et-al depending on the
230
233
  # number of names rendered
231
234
  def delimiter_contextually_precedes_et_al?
232
- return true unless attribute?[:'delimiter-precedes-et-al']
235
+ return true unless attribute?(:'delimiter-precedes-et-al')
233
236
  !!(attributes[:'delimiter-precedes-et-al'].to_s =~ /^contextual/i)
234
237
  end
235
238
 
@@ -253,7 +256,7 @@ module CSL
253
256
  # @return [Boolean] whether or not the delimiter will be inserted between
254
257
  # the penultimate and the last name
255
258
  def delimiter_precedes_last?(names)
256
- names = names.length if names.respond_to?(:length)
259
+ count = names.respond_to?(:length) ? names.length : names.to_i
257
260
 
258
261
  case
259
262
  when !attribute?(:and)
@@ -263,14 +266,9 @@ module CSL
263
266
  when delimiter_always_precedes_last?
264
267
  true
265
268
  when delimiter_precedes_last_after_inverted_name?
266
- if name_as_sort_order?
267
- all_names_as_sort_order? || names.to_i == 2
268
- else
269
- false
270
- end
271
-
269
+ inverted_at?(names, count - 1)
272
270
  else
273
- names.to_i > 2
271
+ count > 2
274
272
  end
275
273
  end
276
274
 
@@ -327,7 +325,7 @@ module CSL
327
325
  end
328
326
 
329
327
  def ellipsis?
330
- attributes[:'et-al-use-last'].to_s =~ /^true$/
328
+ boolean_attribute(:'et-al-use-last')
331
329
  end
332
330
 
333
331
  def ellipsis
@@ -342,6 +340,21 @@ module CSL
342
340
  def connector=(c)
343
341
  attributes[:and] = c
344
342
  end
343
+
344
+ private
345
+
346
+ # @param names [#to_i, Enumerable] the list of names (or its length)
347
+ # @param position [Integer] the position of the name (starting at 1)
348
+ # @return [Boolean] whether or not the name at the position is
349
+ # inverted; names which are not invertible (e.g., literal names)
350
+ # never are
351
+ def inverted_at?(names, position)
352
+ return false unless name_as_sort_order_at?(position)
353
+ return true unless names.is_a?(Enumerable)
354
+
355
+ name = names.to_a[position - 1]
356
+ !name.respond_to?(:invertible?) || name.invertible?
357
+ end
345
358
  end
346
359
 
347
360
  class NamePart < Node
data/lib/csl/style.rb CHANGED
@@ -74,6 +74,15 @@ module CSL
74
74
  @errors = Schema.validate self
75
75
  end
76
76
 
77
+ # Merges the style's overrides into the given locale.
78
+ #
79
+ # @param locale [Locale]
80
+ # @return [Locale]
81
+ def localize(locale)
82
+ overrides = locales.sort.reverse.select { |other| locale.like?(other) }
83
+ overrides.empty? ? locale : locale.merge(*overrides)
84
+ end
85
+
77
86
  def valid?
78
87
  validate.empty?
79
88
  end
@@ -127,7 +136,7 @@ module CSL
127
136
  alias demote_particle? demote_non_dropping_particle?
128
137
 
129
138
  def initialize_without_hyphen?
130
- attribute?(:'initialize-with-hyphen') && !attributes[:'initialize-with-hyphen']
139
+ !boolean_attribute(:'initialize-with-hyphen', true)
131
140
  end
132
141
 
133
142
  def has_page_range_format?
data/lib/csl/treelike.rb CHANGED
@@ -33,12 +33,17 @@ module CSL
33
33
  end
34
34
  alias delete delete_children
35
35
 
36
- # Deletes child nodes that are equal to the passed-in node. Returns all
37
- # deleted children. If no children were deleted, returns nil. If the
38
- # optional block is given, returns the result block if no children were
39
- # deleted.
36
+ # Deletes the passed-in child node.
37
+ # Returns the deleted child.
38
+ # If the node is not a child, returns nil or,
39
+ # if the optional block is given, the result of the block.
40
40
  def delete_child(child)
41
- deleted = children.delete child
41
+ deleted = if children.is_a?(Array)
42
+ index = children.index { |node| node.equal?(child) }
43
+ children.delete_at(index) unless index.nil?
44
+ else
45
+ children.delete child
46
+ end
42
47
 
43
48
  case
44
49
  when deleted.nil? && block_given?
@@ -423,18 +428,19 @@ module CSL
423
428
 
424
429
  alias << push
425
430
 
426
- # Delete items from self that are equal to node. If any items are
427
- # found, returns the deleted items. If the items is not found,
428
- # returns nil. If the optional code block is given, returns the
429
- # result og block if the item is not found.
431
+ # Deletes the passed-in node; other, equal nodes are not deleted.
432
+ # Returns the deleted node or nil if the node is not found.
433
+ # If the optional code block is given,
434
+ # returns the result of the block if the node is not found.
430
435
  def delete(node)
431
436
  return nil unless node.respond_to?(:nodename)
432
437
 
433
438
  deleted = resolve(node.nodename)
434
439
  if deleted.kind_of?(Array)
435
- deleted = deleted.delete(node)
440
+ index = deleted.index { |other| other.equal?(node) }
441
+ deleted = index.nil? ? nil : deleted.delete_at(index)
436
442
  else
437
- if deleted == node
443
+ if deleted.equal?(node)
438
444
  self[node.nodename] = nil
439
445
  else
440
446
  deleted = nil
@@ -442,7 +448,7 @@ module CSL
442
448
  end
443
449
 
444
450
  # Delete node from ordered list as well
445
- @order.delete(node)
451
+ @order.delete_if { |other| other.equal?(node) }
446
452
 
447
453
  if deleted.nil? && block_given?
448
454
  yield
data/lib/csl/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module CSL
2
- VERSION = '2.3.0'.freeze
2
+ VERSION = '2.5.0'.freeze
3
3
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: csl
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.3.0
4
+ version: 2.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sylvester Keil
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2026-10-05 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: namae
@@ -112,7 +112,7 @@ description: |
112
112
  an open XML-based language to describe the formatting of citations
113
113
  and bibliographies.
114
114
  email:
115
- - http://sylvester.keil.or.at
115
+ - sylvester@keil.or.at
116
116
  executables: []
117
117
  extensions: []
118
118
  extra_rdoc_files: []
@@ -159,7 +159,10 @@ files:
159
159
  homepage: https://github.com/inukshuk/csl-ruby
160
160
  licenses:
161
161
  - BSD-2-Clause
162
- metadata: {}
162
+ metadata:
163
+ source_code_uri: https://github.com/inukshuk/csl-ruby
164
+ bug_tracker_uri: https://github.com/inukshuk/csl-ruby/issues
165
+ rubygems_mfa_required: 'true'
163
166
  rdoc_options: []
164
167
  require_paths:
165
168
  - lib