citeproc-ruby 2.1.8 → 2.2.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: 310c28ad4f8db98a36c203d79fc7b8e5aa51367371f81daf6d4d6b03dc97888c
4
- data.tar.gz: f2b7597549a33ca318635d0b54d1ff49179938e50f2b7f25c3cf596221519d05
3
+ metadata.gz: 1caf4a2b5f09b04fd3e6b5a8e7fbaf4c1e8e5b45d4c3c7ce8856eb79990f74ee
4
+ data.tar.gz: 38b1c2eeff222fb886cf2a95c146835fe72bdcb64aef5fd4bf8034c2113792d6
5
5
  SHA512:
6
- metadata.gz: 6151f0f5f16d34b77c07627116baca5294ef8090a69051e0f353f521d63ad6a41cbf805e8bbc7679bfc8cec67f0fdb566b166fbab1c41adb472a6e3ccf53e45e
7
- data.tar.gz: cc1e8d512be419a3e1ee6d46b7d3a5a79c9adb4b9a74796557abef3f93ea7d5221382565fdfcb1a54aaae4ae7bc4038cdc3a58c4169317d00ab81bcb701248c5
6
+ metadata.gz: cc45e7b4b001ce4caa03c7b16a039ffc0e141e99ee30758ffe230201f4671c7a3b6da05b342a503583f4f6668231bb22cad4780c688417d1e57b04bcbbc2278d
7
+ data.tar.gz: f2d8c8bc3919d4973335447ce04850902459ec625c236cdbdee02a9a285a9cbbbdd933ccc147edaf5032386900b39ed101680911411e8dd6a616e19a0d9bc748
data/.document CHANGED
@@ -1,4 +1,5 @@
1
1
  lib/**/*.rb
2
2
  -
3
3
  AGPL
4
+ BSDL
4
5
  README.md
@@ -10,23 +10,23 @@ jobs:
10
10
  build:
11
11
  runs-on: ubuntu-latest
12
12
  env:
13
- BUNDLE_WITHOUT: debug:extra
13
+ BUNDLE_WITHOUT: debug
14
14
  strategy:
15
+ fail-fast: false
15
16
  matrix:
16
17
  ruby-version:
18
+ - '4.0'
17
19
  - '3.4'
18
20
  - '3.3'
19
- - '3.2'
20
- - '3.1'
21
21
  steps:
22
- - uses: actions/checkout@v4
22
+ - uses: actions/checkout@v7
23
23
  - uses: ruby/setup-ruby@v1
24
24
  with:
25
25
  ruby-version: ${{ matrix.ruby-version }}
26
26
  bundler-cache: true
27
27
  - run: bundle exec rake
28
28
  - name: Upload coverage results
29
- if: matrix.ruby-version == '3.3'
29
+ if: matrix.ruby-version == '3.4'
30
30
  continue-on-error: true
31
31
  uses: coverallsapp/github-action@v2
32
32
  with:
data/Gemfile CHANGED
@@ -18,14 +18,10 @@ end
18
18
  group :optional do
19
19
  gem 'edtf'
20
20
  gem 'chronic'
21
- end
22
-
23
- group :extra do
24
- gem 'yard', platforms: :mri
25
- gem 'redcarpet', platforms: :mri
21
+ gem 'ffi-icu'
26
22
  end
27
23
 
28
24
  group :coverage do
29
- gem 'simplecov', require: false
25
+ gem 'simplecov', '>= 1.3', require: false
30
26
  gem 'simplecov-lcov', require: false
31
27
  end
data/README.md CHANGED
@@ -113,12 +113,6 @@ Alternatively, you can `gem install csl-styles` to install all official CSL
113
113
  styles and locales. To make the styles and locales available, simply
114
114
  `require 'csl/styles`.
115
115
 
116
- Compatibility
117
- -------------
118
- The cite processor and the CSL API libraries have been developed for MRI,
119
- Rubinius, and JRuby. Please note that we try to support only Ruby versions
120
- 1.9.3 and upwards.
121
-
122
116
  Development
123
117
  -----------
124
118
  The CiteProc-Ruby source code is
data/Rakefile CHANGED
@@ -12,7 +12,7 @@ end
12
12
  $:.unshift(File.join(File.dirname(__FILE__), './lib'))
13
13
  require 'citeproc/ruby/version'
14
14
 
15
- desc 'Run a Pry session with CiteProc-Ruby loaded'
15
+ desc 'Run an IRB session with CiteProc-Ruby loaded'
16
16
  task :console do
17
17
  ARGV.clear
18
18
  require 'irb'
@@ -39,16 +39,9 @@ end
39
39
 
40
40
  task :release do |t|
41
41
  system "gem build citeproc-ruby.gemspec"
42
- system "git tag #{CiteProc::Ruby::VERSION}"
42
+ system "git tag v#{CiteProc::Ruby::VERSION}"
43
43
  system "git push --tags"
44
44
  system "gem push citeproc-ruby-#{CiteProc::Ruby::VERSION}.gem"
45
45
  end
46
46
 
47
47
  task :default => [:spec, :cucumber]
48
-
49
- begin
50
- require 'yard'
51
- YARD::Rake::YardocTask.new
52
- rescue LoadError => e
53
- # ignore
54
- end
@@ -162,7 +162,7 @@ module CiteProc
162
162
  private
163
163
 
164
164
  def content_tag(name, content, options = nil)
165
- opening_tag(name, options) << content << closing_tag(name)
165
+ "#{opening_tag(name, options)}#{content}#{closing_tag(name)}"
166
166
  end
167
167
 
168
168
  def style_for(options)
@@ -177,7 +177,7 @@ module CiteProc
177
177
 
178
178
  return unless !options.empty?
179
179
 
180
- ' ' << options.map { |k, v| [k, v.inspect].join('=') }.join(' ')
180
+ " #{options.map { |k, v| [k, v.inspect].join('=') }.join(' ')}"
181
181
  end
182
182
 
183
183
  def opening_tag(name, options = nil)
@@ -93,7 +93,7 @@ module CiteProc
93
93
  private
94
94
 
95
95
  def content_tag(name, content, options = nil)
96
- opening_tag(name, options) << content << closing_tag(name)
96
+ "#{opening_tag(name, options)}#{content}#{closing_tag(name)}"
97
97
  end
98
98
 
99
99
  def style_for(options)
@@ -108,7 +108,7 @@ module CiteProc
108
108
 
109
109
  return unless !options.empty?
110
110
 
111
- ' ' << options.map { |k, v| [k, v.inspect].join('=') }.join(' ')
111
+ " #{options.map { |k, v| [k, v.inspect].join('=') }.join(' ')}"
112
112
  end
113
113
 
114
114
  def opening_tag(name, options = nil)
@@ -238,7 +238,7 @@ module CiteProc
238
238
  # Strip away some unusual characters to normalize
239
239
  # sort order for names.
240
240
  if sort_mode?
241
- name.family = name.family.to_s.gsub(/[\[\]]|^\W+/, '')
241
+ name.family = name.family.to_s.gsub(/[\[\]]|^[^[:word:]]+/, '')
242
242
  end
243
243
 
244
244
  name.options.merge! node.name_options
@@ -99,26 +99,23 @@ module CiteProc
99
99
  state.clear! result
100
100
  end
101
101
 
102
- def render_sort(a, b, node, key)
102
+ def render_sort(item, node, key)
103
103
  state.store! nil, key
104
104
 
105
105
  original_format = @format
106
106
  @format = Formats::Sort.new
107
107
 
108
- if a.is_a?(CiteProc::Names)
109
- [render_name(a, node), render_name(b, node)]
108
+ if item.is_a?(CiteProc::Names)
109
+ render_name(item, node)
110
110
 
111
111
  else
112
112
  # We need to clear any items that are suppressed
113
113
  # because they were used as substitutes during
114
114
  # rendering for sorting purposes!
115
- a_rendered = render a.cite, node
116
- a.suppressed.clear
115
+ rendered = render item.cite, node
116
+ item.suppressed.clear
117
117
 
118
- b_rendered = render b.cite, node
119
- b.suppressed.clear
120
-
121
- [a_rendered, b_rendered]
118
+ rendered
122
119
  end
123
120
 
124
121
  ensure
@@ -1,3 +1,9 @@
1
+ begin
2
+ require 'ffi-icu'
3
+ rescue LoadError
4
+ # ignore
5
+ end
6
+
1
7
  module CiteProc
2
8
  module Ruby
3
9
 
@@ -6,24 +12,30 @@ module CiteProc
6
12
  def sort!(items, keys)
7
13
  return items unless !keys.nil? && !keys.empty?
8
14
 
15
+ # Sort values are computed only once per item
16
+ # and key for the duration of the sort.
17
+ cache = {}.compare_by_identity
18
+
9
19
  # TODO refactor
10
20
  if items.is_a?(CitationData)
11
21
  items.sort! do |a, b|
12
- compare_items_by_keys(a.data, b.data, keys)
22
+ compare_items_by_keys(a.data, b.data, keys, cache)
13
23
  end
14
24
  else
15
25
  items.sort! do |a, b|
16
- compare_items_by_keys(a, b, keys)
26
+ compare_items_by_keys(a, b, keys, cache)
17
27
  end
18
28
  end
19
29
  end
20
30
 
31
+ private
32
+
21
33
  # @returns [-1, 0, 1, nil]
22
- def compare_items_by_keys(a, b, keys)
34
+ def compare_items_by_keys(a, b, keys, cache)
23
35
  result = 0
24
36
 
25
37
  keys.each do |key|
26
- result = compare_items_by_key(a, b, key)
38
+ result = compare_items_by_key(a, b, key, cache)
27
39
  return result unless result.zero?
28
40
  end
29
41
 
@@ -31,52 +43,83 @@ module CiteProc
31
43
  end
32
44
 
33
45
  # @returns [-1, 0, 1, nil]
34
- def compare_items_by_key(a, b, key)
35
- if key.macro?
36
- result = compare_items(*renderer.render_sort(a, b, key.macro, key))
46
+ def compare_items_by_key(a, b, key, cache)
47
+ va, vb = sort_value(a, key, cache), sort_value(b, key, cache)
37
48
 
38
- else
39
- va, vb = a[key.variable], b[key.variable]
40
-
41
- # Return early if one side is nil. In this
42
- # case ascending/descending is irrelevant!
43
- return 1 if va.nil? || va.empty?
44
- return -1 if vb.nil? || vb.empty?
45
-
46
- result = case CiteProc::Variable.types[key.variable]
47
- when :names
48
- node = CSL::Style::Name.new(key.name_options)
49
- node.all_names_as_sort_order!
50
-
51
- compare_items(*renderer.render_sort(va, vb, node, key))
52
-
53
- when :date
54
- va <=> vb
55
- when :number
56
- va <=> vb
57
- else
58
- compare_items(va, vb)
59
- end
60
- end
49
+ # Return early if either side is nil.
50
+ # In this case ascending/descending is irrelevant!
51
+ return 0 if va.nil? && vb.nil?
52
+ return 1 if va.nil?
53
+ return -1 if vb.nil?
61
54
 
55
+ result = va <=> vb
62
56
  result = -result unless key.ascending?
63
57
  result
64
58
  end
65
59
 
66
- def compare_items(a, b)
67
- if sort_case_sensitively?
68
- a <=> b
60
+ def sort_value(item, key, cache)
61
+ values = (cache[item] ||= {})
62
+ values.fetch(key) { values[key] = compute_sort_value(item, key) }
63
+ end
64
+
65
+ def compute_sort_value(item, key)
66
+ if key.macro?
67
+ return sort_key(renderer.render_sort(item, key.macro, key))
68
+ end
69
+
70
+ value = item[key.variable]
71
+ return if value.nil? || value.empty?
72
+
73
+ case CiteProc::Variable.types[key.variable]
74
+ when :names
75
+ node = CSL::Style::Name.new(key.name_options)
76
+ node.all_names_as_sort_order!
77
+
78
+ sort_key(renderer.render_sort(value, node, key))
79
+
80
+ when :date, :number
81
+ value
69
82
  else
70
- a.to_s.downcase <=> b.to_s.downcase
83
+ sort_key(value)
71
84
  end
72
85
  end
73
86
 
87
+ def sort_key(string)
88
+ string = string.to_s
89
+
90
+ collator = self.collator
91
+ return collator.collation_key(string) unless collator.nil?
92
+
93
+ folded = string.downcase(:fold)
94
+ key = [folded.unicode_normalize(:nfd).gsub(/\p{Mn}/, ''), folded]
95
+ sort_case_sensitively? ? key << string : key
96
+ end
97
+
98
+ def collator
99
+ return unless defined?(ICU::Collation::Collator)
100
+
101
+ lc = renderer.locale.to_s
102
+ cs = sort_case_sensitively?
103
+
104
+ @collators ||= {}
105
+ @collators[[lc, cs]] ||= create_collator(lc, cs)
106
+ end
107
+
108
+ def create_collator(locale, case_sensitive)
109
+ collator = ICU::Collation::Collator.new(locale)
110
+ collator.case_first = :upper_first
111
+
112
+ # Secondary strength compares letters and diacritics
113
+ # but ignores case; tertiary strength considers case too.
114
+ collator.strength = case_sensitive ? :tertiary : :secondary
115
+
116
+ collator
117
+ end
118
+
74
119
  def sort_case_sensitively?
75
120
  return false unless processor && processor.options
76
121
  processor.options[:sort_case_sensitively]
77
122
  end
78
-
79
123
  end
80
-
81
124
  end
82
125
  end
@@ -1,5 +1,5 @@
1
1
  module CiteProc
2
2
  module Ruby
3
- VERSION = '2.1.8'
3
+ VERSION = '2.2.0'
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: citeproc-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.8
4
+ version: 2.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sylvester Keil
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-12-04 00:00:00.000000000 Z
10
+ date: 2026-10-05 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: citeproc
@@ -58,7 +58,7 @@ dependencies:
58
58
  - !ruby/object:Gem::Version
59
59
  version: '1.0'
60
60
  description: |
61
- CiteProc-Ruby is a Citation Style Language (CSL) 1.0.1 compatible cite
61
+ CiteProc-Ruby is a Citation Style Language (CSL) 1.0.2 compatible cite
62
62
  processor implementation written in pure Ruby.
63
63
  email:
64
64
  - http://sylvester.keil.or.at
@@ -66,7 +66,6 @@ executables: []
66
66
  extensions: []
67
67
  extra_rdoc_files: []
68
68
  files:
69
- - ".codeclimate.yml"
70
69
  - ".document"
71
70
  - ".github/workflows/ci.yml"
72
71
  - ".yardopts"
@@ -110,14 +109,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
110
109
  requirements:
111
110
  - - ">="
112
111
  - !ruby/object:Gem::Version
113
- version: 1.9.3
112
+ version: '3.1'
114
113
  required_rubygems_version: !ruby/object:Gem::Requirement
115
114
  requirements:
116
115
  - - ">="
117
116
  - !ruby/object:Gem::Version
118
117
  version: '0'
119
118
  requirements: []
120
- rubygems_version: 3.7.2
119
+ rubygems_version: 4.0.10
121
120
  specification_version: 4
122
121
  summary: A Citation Style Language (CSL) cite processor
123
122
  test_files: []
data/.codeclimate.yml DELETED
@@ -1,17 +0,0 @@
1
- ---
2
- engines:
3
- duplication:
4
- enabled: true
5
- config:
6
- languages:
7
- - ruby
8
- fixme:
9
- enabled: true
10
- rubocop:
11
- enabled: true
12
- ratings:
13
- paths:
14
- - "**.rb"
15
- exclude_paths:
16
- - features/
17
- - spec/