csl 2.2.1 → 2.4.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 +4 -4
- data/README.md +58 -44
- data/lib/csl/compatibility.rb +7 -30
- data/lib/csl/info.rb +0 -12
- data/lib/csl/loader.rb +11 -2
- data/lib/csl/locale/term.rb +5 -4
- data/lib/csl/locale.rb +105 -34
- data/lib/csl/node.rb +17 -21
- data/lib/csl/parser.rb +1 -2
- data/lib/csl/pretty_printer.rb +1 -1
- data/lib/csl/style/label.rb +1 -1
- data/lib/csl/style/names.rb +2 -2
- data/lib/csl/style.rb +14 -5
- data/lib/csl/treelike.rb +19 -14
- data/lib/csl/version.rb +1 -1
- data/lib/csl.rb +0 -1
- metadata +4 -13
- data/.document +0 -5
- data/.github/workflows/ci.yml +0 -33
- data/.gitignore +0 -13
- data/.yardopts +0 -2
- data/AGPL +0 -662
- data/Gemfile +0 -32
- data/Rakefile +0 -61
- data/csl.gemspec +0 -45
- data/cucumber.yml +0 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c70f967fbf46ada97d0c2b3164d3fc1b843d24d6125f1c6364d2d7f408c5fa7e
|
|
4
|
+
data.tar.gz: 59d241370ed43b45a191e938ebbe20b51ed74419a503feb0c71e37d2770facd3
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ee00896662db7e3f7ccdc6644f208428a392ad2a66ae09ad93bb37ac4a6366915d9f4cea1cb274526466e8a0441f6c40afdfcbf953735e2d6a744587f41f6777
|
|
7
|
+
data.tar.gz: 2807a5c96c581af1a9314d75b5b24b09e461c6fbf956b475d9bde1f8c1f7a6bc420095a9af6380ee7879129b80f6dc0ce1505dcd555dafdff7355b89e09979cc
|
data/README.md
CHANGED
|
@@ -1,48 +1,56 @@
|
|
|
1
1
|
CSL-Ruby
|
|
2
2
|
========
|
|
3
3
|
CSL-Ruby provides a Ruby parser and a comprehensive API for the
|
|
4
|
-
[Citation Style Language](
|
|
5
|
-
format to describe the formatting
|
|
4
|
+
[Citation Style Language](https://citationstyles.org) (CSL),
|
|
5
|
+
an XML-based format to describe the formatting
|
|
6
|
+
of citations, notes and bibliographies.
|
|
6
7
|
|
|
7
8
|
Styles and Locales
|
|
8
9
|
------------------
|
|
9
|
-
You can load CSL styles and locales
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
You can load CSL styles and locales
|
|
11
|
+
by passing a respective XML string, file name, or URL.
|
|
12
|
+
You can also load styles and locales by name
|
|
13
|
+
if the corresponding files are installed
|
|
14
|
+
in your local styles and locale directories.
|
|
12
15
|
By default, CSL-Ruby looks for CSL styles and locale files in
|
|
13
16
|
|
|
14
17
|
/usr/local/share/csl/styles
|
|
15
18
|
/usr/local/share/csl/locales
|
|
16
19
|
|
|
17
|
-
You can change these locations
|
|
18
|
-
`CSL::Locale.root` respectively.
|
|
20
|
+
You can change these locations
|
|
21
|
+
by changing the value of `CSL::Style.root` and `CSL::Locale.root` respectively.
|
|
19
22
|
|
|
20
|
-
Alternatively, you can `gem install csl-styles`
|
|
21
|
-
|
|
22
|
-
|
|
23
|
+
Alternatively, you can `gem install csl-styles`
|
|
24
|
+
to install all official CSL styles and locales.
|
|
25
|
+
To make the styles and locales available,
|
|
26
|
+
simply `require 'csl/styles'`.
|
|
23
27
|
|
|
24
28
|
Usage
|
|
25
29
|
-----
|
|
26
|
-
CSL-Ruby is broadly aimed at two very different usage scenarios:
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
30
|
+
CSL-Ruby is broadly aimed at two very different usage scenarios:
|
|
31
|
+
on the one hand,
|
|
32
|
+
you can use the parser to load existing styles and locales
|
|
33
|
+
and manipulate, query or otherwise work with them using a dedicated API:
|
|
34
|
+
that is to say,
|
|
35
|
+
you do not have to resort to XML-related methods of access,
|
|
36
|
+
but can make use of a large set of library methods which are specific to CSL.
|
|
37
|
+
This is useful, primarily, for citation processors like
|
|
38
|
+
[CiteProc-Ruby](https://github.com/inukshuk/citeproc-ruby).
|
|
39
|
+
|
|
40
|
+
On the other hand,
|
|
41
|
+
CSL-Ruby makes it easy to create new styles and locales using Ruby;
|
|
42
|
+
this is useful, for example,
|
|
43
|
+
if you need to change or adapt styles on-the-fly
|
|
44
|
+
or for writing an interactive style editor.
|
|
45
|
+
|
|
46
|
+
To get you started, here are a few usage examples;
|
|
47
|
+
for the full set of available features, please consult the
|
|
48
|
+
[API documentation](https://rubydoc.info/gems/csl/).
|
|
41
49
|
|
|
42
50
|
require 'csl'
|
|
43
51
|
|
|
44
52
|
# Load a style from the Zotero style repository
|
|
45
|
-
jps = CSL::Style.load '
|
|
53
|
+
jps = CSL::Style.load 'https://www.zotero.org/styles/american-journal-of-political-science'
|
|
46
54
|
|
|
47
55
|
# Query style information
|
|
48
56
|
jps.title #-> "American Journal of Political Science"
|
|
@@ -53,7 +61,7 @@ available features, please consult the
|
|
|
53
61
|
jps.valid? #-> true
|
|
54
62
|
|
|
55
63
|
# Load another style
|
|
56
|
-
amc = CSL::Style.load '
|
|
64
|
+
amc = CSL::Style.load 'https://www.zotero.org/styles/applied-mathematics-and-computation'
|
|
57
65
|
|
|
58
66
|
amc.independent? #-> false
|
|
59
67
|
|
|
@@ -68,9 +76,9 @@ available features, please consult the
|
|
|
68
76
|
# Load a locally installed style
|
|
69
77
|
apa = CSL::Style.load :apa
|
|
70
78
|
|
|
71
|
-
# Fetch the a macro
|
|
72
|
-
authors = apa.macros['
|
|
73
|
-
#-> #<CSL::Style::
|
|
79
|
+
# Fetch the first child of a macro
|
|
80
|
+
authors = apa.macros['author-bib'].children[0]
|
|
81
|
+
#-> #<CSL::Style::Group delimiter=" " children=[2]>
|
|
74
82
|
|
|
75
83
|
# Load a locally installed locale
|
|
76
84
|
fr = CSL::Locale.load :fr
|
|
@@ -82,7 +90,7 @@ available features, please consult the
|
|
|
82
90
|
|
|
83
91
|
# Ordinalize a number
|
|
84
92
|
fr.ordinalize 42 #=> "42ᵉ"
|
|
85
|
-
fr.ordinalize 3, form: 'long'
|
|
93
|
+
fr.ordinalize 3, form: 'long' #=> "troisième"
|
|
86
94
|
|
|
87
95
|
# Create a new style
|
|
88
96
|
style = CSL::Style.new
|
|
@@ -101,11 +109,12 @@ available features, please consult the
|
|
|
101
109
|
|
|
102
110
|
Dependencies
|
|
103
111
|
------------
|
|
104
|
-
CSL-Ruby was written with portability in mind.
|
|
105
|
-
will use [Nokogiri
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
to
|
|
112
|
+
CSL-Ruby was written with portability in mind.
|
|
113
|
+
For performance reasons it will use [Nokogiri](https://nokogiri.org)
|
|
114
|
+
for XML parsing and validation if available;
|
|
115
|
+
however, CSL-Ruby will fallback to REXML from the Ruby standard library.
|
|
116
|
+
In order to use Nokogiri,
|
|
117
|
+
simply `gem install nokogiri` or add it to your Gemfile.
|
|
109
118
|
|
|
110
119
|
Development
|
|
111
120
|
-----------
|
|
@@ -114,28 +123,33 @@ You can check out a copy of the latest code using Git:
|
|
|
114
123
|
|
|
115
124
|
$ git clone https://github.com/inukshuk/csl-ruby.git
|
|
116
125
|
|
|
117
|
-
To get started,
|
|
126
|
+
To get started,
|
|
127
|
+
install the development dependencies and run all tests:
|
|
118
128
|
|
|
119
129
|
$ cd csl-ruby
|
|
120
130
|
$ bundle install
|
|
121
131
|
$ rake
|
|
122
132
|
|
|
123
|
-
If you've found a bug or have a question,
|
|
133
|
+
If you've found a bug or have a question,
|
|
134
|
+
please open an issue on the
|
|
124
135
|
[issue tracker](https://github.com/inukshuk/csl-ruby/issues).
|
|
125
|
-
Or, for extra credit, clone the CSL-Ruby repository,
|
|
126
|
-
example, fix the bug and submit a pull request.
|
|
136
|
+
Or, for extra credit, clone the CSL-Ruby repository,
|
|
137
|
+
write a failing example, fix the bug and submit a pull request.
|
|
127
138
|
|
|
128
139
|
Credits
|
|
129
140
|
-------
|
|
130
141
|
Thanks to Rintze M. Zelle, Sebastian Karcher, Frank G. Bennett, Jr.,
|
|
131
|
-
and Bruce D'Arcus of CSL and citeproc-js fame
|
|
142
|
+
and Bruce D'Arcus of CSL and citeproc-js fame
|
|
143
|
+
for their support!
|
|
132
144
|
|
|
133
|
-
Thanks to Google and the Berkman Center at Harvard University
|
|
134
|
-
this project as part of
|
|
145
|
+
Thanks to Google and the Berkman Center at Harvard University
|
|
146
|
+
for supporting this project as part of
|
|
147
|
+
[Google Summer of Code](https://developers.google.com/open-source/soc/).
|
|
135
148
|
|
|
136
149
|
Copyright
|
|
137
150
|
---------
|
|
138
|
-
Copyright 2009-
|
|
151
|
+
Copyright 2009-2026 Sylvester Keil.
|
|
152
|
+
All rights reserved.
|
|
139
153
|
|
|
140
154
|
Copyright 2012 President and Fellows of Harvard College.
|
|
141
155
|
|
data/lib/csl/compatibility.rb
CHANGED
|
@@ -10,12 +10,8 @@ module CSL
|
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
class Module
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
else
|
|
16
|
-
def const?(name)
|
|
17
|
-
const_defined?(name, false)
|
|
18
|
-
end
|
|
13
|
+
def const?(name)
|
|
14
|
+
const_defined?(name, false)
|
|
19
15
|
end
|
|
20
16
|
end
|
|
21
17
|
|
|
@@ -26,30 +22,11 @@ end unless Struct.instance_methods.include?(:__class__)
|
|
|
26
22
|
module CSL
|
|
27
23
|
module_function
|
|
28
24
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
& & < < > > ' ' " "
|
|
33
|
-
}].freeze
|
|
34
|
-
|
|
35
|
-
def encode_xml_text(string)
|
|
36
|
-
string.gsub(/[&<>]/) { |match|
|
|
37
|
-
XML_ENTITY_SUBSTITUTION[match]
|
|
38
|
-
}
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
def encode_xml_attr(string)
|
|
42
|
-
string.gsub(/[&<>'"]/) { |match|
|
|
43
|
-
XML_ENTITY_SUBSTITUTION[match]
|
|
44
|
-
}.inspect
|
|
45
|
-
end
|
|
46
|
-
else
|
|
47
|
-
def encode_xml_text(string)
|
|
48
|
-
string.encode(string.encoding, :xml => :text)
|
|
49
|
-
end
|
|
25
|
+
def encode_xml_text(string)
|
|
26
|
+
string.encode(string.encoding, :xml => :text)
|
|
27
|
+
end
|
|
50
28
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
end
|
|
29
|
+
def encode_xml_attr(string)
|
|
30
|
+
string.encode(string.encoding, :xml => :attr)
|
|
54
31
|
end
|
|
55
32
|
end
|
data/lib/csl/info.rb
CHANGED
|
@@ -85,18 +85,6 @@ module CSL
|
|
|
85
85
|
end
|
|
86
86
|
end
|
|
87
87
|
|
|
88
|
-
# Ruby 1.8 still has Object#id methods so the attr_children generator
|
|
89
|
-
# may not have created those; since #id is deprecated in 1.8.7 we're
|
|
90
|
-
# forcing the override anyway. Live dangerously!
|
|
91
|
-
remove_method :id
|
|
92
|
-
|
|
93
|
-
# @return [Id] the id text node
|
|
94
|
-
def id
|
|
95
|
-
children[:id]
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
alias id= set_child_id
|
|
99
|
-
|
|
100
88
|
def self_link!
|
|
101
89
|
return unless has_id?
|
|
102
90
|
self.self_link = id
|
data/lib/csl/loader.rb
CHANGED
|
@@ -9,6 +9,12 @@ module CSL
|
|
|
9
9
|
# Base classes are exepcted to define a #parse method.
|
|
10
10
|
module Loader
|
|
11
11
|
|
|
12
|
+
class << self
|
|
13
|
+
attr_accessor :allow_remote
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
@allow_remote = true
|
|
17
|
+
|
|
12
18
|
attr_accessor :root, :prefix, :extension
|
|
13
19
|
|
|
14
20
|
# @example
|
|
@@ -82,8 +88,11 @@ module CSL
|
|
|
82
88
|
location = input
|
|
83
89
|
end
|
|
84
90
|
|
|
85
|
-
|
|
86
|
-
|
|
91
|
+
if location =~ /\A\w+:\/\//
|
|
92
|
+
raise 'loading from URLs is disabled' unless Loader.allow_remote
|
|
93
|
+
URI.open(location, 'r:UTF-8') { |io| io.read }
|
|
94
|
+
else
|
|
95
|
+
File.open(location, 'r:UTF-8') { |io| io.read }
|
|
87
96
|
end
|
|
88
97
|
end
|
|
89
98
|
rescue => e
|
data/lib/csl/locale/term.rb
CHANGED
|
@@ -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
|
|
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
|
|
98
|
-
if options.
|
|
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
|
data/lib/csl/locale.rb
CHANGED
|
@@ -15,7 +15,7 @@ module CSL
|
|
|
15
15
|
@extension = '.xml'.freeze
|
|
16
16
|
@prefix = 'locales-'.freeze
|
|
17
17
|
|
|
18
|
-
@tag_pattern =
|
|
18
|
+
@tag_pattern = /\A(?:[a-z]{2,3}(-[a-z]{4})?(-[a-z]{2})?|-[a-z]{2})\z/i
|
|
19
19
|
|
|
20
20
|
# Default languages/regions.
|
|
21
21
|
# Auto-detection is based on these lists.
|
|
@@ -40,10 +40,27 @@ module CSL
|
|
|
40
40
|
attr_accessor :default
|
|
41
41
|
attr_reader :languages, :regions, :scripts
|
|
42
42
|
|
|
43
|
+
# Loads the locale. For IETF tags without a locale file, falls
|
|
44
|
+
# back to the language's primary dialect and to the default locale.
|
|
43
45
|
def load(input = nil)
|
|
44
46
|
input ||= Locale.default
|
|
45
|
-
|
|
46
|
-
|
|
47
|
+
|
|
48
|
+
# Drop extensions and private-use subtags (e.g. "-x-...")
|
|
49
|
+
tag = input.to_s.sub(/-[a-z0-9]-.*\z/i, '')
|
|
50
|
+
return super(input) unless tag =~ @tag_pattern
|
|
51
|
+
|
|
52
|
+
tag = normalize(tag)
|
|
53
|
+
candidates = [tag, normalize(tag.split('-')[0]), Locale.default].uniq
|
|
54
|
+
|
|
55
|
+
error = nil
|
|
56
|
+
|
|
57
|
+
candidates.each do |candidate|
|
|
58
|
+
return super(candidate).tap { |locale| locale.requested = tag }
|
|
59
|
+
rescue ParseError => e
|
|
60
|
+
error ||= e
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
raise error
|
|
47
64
|
end
|
|
48
65
|
|
|
49
66
|
# Normalizes an IETF tag; adds default language, region, script.
|
|
@@ -102,6 +119,10 @@ module CSL
|
|
|
102
119
|
|
|
103
120
|
attr_accessor :region, :script
|
|
104
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
|
+
|
|
105
126
|
alias_child :metadata, :info
|
|
106
127
|
alias_child :dates, :date
|
|
107
128
|
alias_child :options, :style_options
|
|
@@ -154,6 +175,7 @@ module CSL
|
|
|
154
175
|
def initialize_copy(other)
|
|
155
176
|
@parent, @ancestors, @descendants, @siblings, @root, @depth = nil
|
|
156
177
|
initialize(other.attributes.to_hash.merge(:lang => other.to_s))
|
|
178
|
+
@requested = other.requested
|
|
157
179
|
end
|
|
158
180
|
|
|
159
181
|
def added_to(node)
|
|
@@ -249,8 +271,9 @@ module CSL
|
|
|
249
271
|
# de.ordinalize(13)
|
|
250
272
|
# #-> "13."
|
|
251
273
|
#
|
|
252
|
-
#
|
|
253
|
-
#
|
|
274
|
+
# fr = Locale.load('fr')
|
|
275
|
+
# fr.ordinalize(1, :'gender-form' => 'feminine')
|
|
276
|
+
# #-> "1ʳᵉ"
|
|
254
277
|
#
|
|
255
278
|
# @note
|
|
256
279
|
# For CSL 1.0 (and older) locales that do not define an "ordinal-00"
|
|
@@ -262,8 +285,9 @@ module CSL
|
|
|
262
285
|
# @param options [Hash] formatting options
|
|
263
286
|
#
|
|
264
287
|
# @option options [:short,:long] :form (:short) which ordinals form to use
|
|
265
|
-
# @option options [
|
|
266
|
-
# 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)
|
|
267
291
|
#
|
|
268
292
|
# @raise [ArgumentError] if number cannot be converted to an integer
|
|
269
293
|
#
|
|
@@ -283,8 +307,7 @@ module CSL
|
|
|
283
307
|
|
|
284
308
|
# @return [Boolean] true when the option limit-day-ordinals-to-day-1 is true
|
|
285
309
|
def limit_day_ordinals?
|
|
286
|
-
|
|
287
|
-
!!(options[:'limit-day-ordinals-to-day-1'].to_s =~ /^true$/i)
|
|
310
|
+
has_options? && options.boolean_attribute(:'limit-day-ordinals-to-day-1')
|
|
288
311
|
end
|
|
289
312
|
|
|
290
313
|
def limit_day_ordinals!
|
|
@@ -297,8 +320,7 @@ module CSL
|
|
|
297
320
|
|
|
298
321
|
# @return [Boolean] true when the option punctuation-in-quote is true
|
|
299
322
|
def punctuation_in_quote?
|
|
300
|
-
|
|
301
|
-
!!(options[:'punctuation-in-quote'].to_s =~ /^true$/i)
|
|
323
|
+
has_options? && options.boolean_attribute(:'punctuation-in-quote')
|
|
302
324
|
end
|
|
303
325
|
alias punctuation_in_quotes? punctuation_in_quote?
|
|
304
326
|
|
|
@@ -382,13 +404,13 @@ module CSL
|
|
|
382
404
|
|
|
383
405
|
# @returns [Boolean] whether or not the Locale is the default locale
|
|
384
406
|
def default?
|
|
385
|
-
|
|
407
|
+
default_tag?(language, script, region)
|
|
386
408
|
end
|
|
387
409
|
|
|
388
410
|
# @return [Boolean] whehter or not the Locale's region is the default
|
|
389
411
|
# region for its language
|
|
390
412
|
def default_region?
|
|
391
|
-
|
|
413
|
+
default_region_for?(language, region)
|
|
392
414
|
end
|
|
393
415
|
|
|
394
416
|
# @return [Boolean] whether or not the Locale's language is the default
|
|
@@ -397,11 +419,25 @@ module CSL
|
|
|
397
419
|
language && language == Locale.languages[region]
|
|
398
420
|
end
|
|
399
421
|
|
|
422
|
+
# Whether or not the passed-in locale (e.g., an in-style locale)
|
|
423
|
+
# matches this locale. This is the case for universal locales and
|
|
424
|
+
# for locales of the language this locale was requested for.
|
|
400
425
|
def like?(other)
|
|
401
426
|
return false unless other.is_a? Locale
|
|
402
427
|
return true if other.universal?
|
|
403
428
|
|
|
404
|
-
|
|
429
|
+
requested_language == other.language
|
|
430
|
+
end
|
|
431
|
+
|
|
432
|
+
# @return [Symbol, nil] the language this locale was requested for
|
|
433
|
+
def requested_language
|
|
434
|
+
requested.nil? ? language : requested.split('-')[0].to_sym
|
|
435
|
+
end
|
|
436
|
+
|
|
437
|
+
# @return [Boolean] whether or not the locale was loaded as a
|
|
438
|
+
# fallback for a different locale
|
|
439
|
+
def fallback?
|
|
440
|
+
!requested.nil? && requested != to_s
|
|
405
441
|
end
|
|
406
442
|
|
|
407
443
|
def universal?
|
|
@@ -444,44 +480,76 @@ module CSL
|
|
|
444
480
|
# de-DE will come before de-AT even though the alphabetical order
|
|
445
481
|
# would be different).
|
|
446
482
|
#
|
|
483
|
+
# Fallback locales are compared as the locale they were requested
|
|
484
|
+
# for (see #requested); locale data (terms, dates, and options) is
|
|
485
|
+
# not compared.
|
|
486
|
+
#
|
|
447
487
|
# @param other [Locale] the locale used for comparison
|
|
448
488
|
# @return [1,0,-1,nil] the result of the comparison
|
|
449
489
|
def <=>(other)
|
|
490
|
+
return nil unless other.is_a?(Locale)
|
|
491
|
+
compare(identity, other.identity)
|
|
492
|
+
end
|
|
493
|
+
|
|
494
|
+
# @return [String] the Locale's IETF tag
|
|
495
|
+
def to_s
|
|
496
|
+
[language, script, region].compact.join('-')
|
|
497
|
+
end
|
|
498
|
+
|
|
499
|
+
# @return [String] a string representation of the Locale
|
|
500
|
+
def inspect
|
|
501
|
+
"#<#{self.class.name} #{to_s}>"
|
|
502
|
+
end
|
|
503
|
+
|
|
504
|
+
protected
|
|
505
|
+
|
|
506
|
+
# @return [Array<Symbol, nil>] language, script, and region of the
|
|
507
|
+
# locale or, for fallback locales, of the requested tag
|
|
508
|
+
def identity
|
|
509
|
+
return [language, script, region] unless fallback?
|
|
510
|
+
|
|
511
|
+
language, *rs = requested.split('-').map(&:to_sym)
|
|
512
|
+
region, script = rs.reverse
|
|
513
|
+
|
|
514
|
+
[language, script, region]
|
|
515
|
+
end
|
|
516
|
+
|
|
517
|
+
private
|
|
518
|
+
|
|
519
|
+
# Compares two locale identities (see #identity).
|
|
520
|
+
def compare(a, b)
|
|
521
|
+
language, script, region = a
|
|
522
|
+
other_language, other_script, other_region = b
|
|
523
|
+
|
|
450
524
|
case
|
|
451
|
-
when
|
|
452
|
-
|
|
453
|
-
when
|
|
454
|
-
script <=> other.script
|
|
455
|
-
when default?
|
|
525
|
+
when [language, region] == [other_language, other_region]
|
|
526
|
+
script <=> other_script
|
|
527
|
+
when default_tag?(*a)
|
|
456
528
|
-1
|
|
457
|
-
when
|
|
529
|
+
when default_tag?(*b)
|
|
458
530
|
1
|
|
459
|
-
when language ==
|
|
531
|
+
when language == other_language
|
|
460
532
|
case
|
|
461
|
-
when
|
|
533
|
+
when default_region_for?(language, region)
|
|
462
534
|
-1
|
|
463
|
-
when
|
|
535
|
+
when default_region_for?(other_language, other_region)
|
|
464
536
|
1
|
|
465
537
|
else
|
|
466
|
-
region.to_s <=>
|
|
538
|
+
region.to_s <=> other_region.to_s
|
|
467
539
|
end
|
|
468
540
|
else
|
|
469
|
-
language.to_s <=>
|
|
541
|
+
language.to_s <=> other_language.to_s
|
|
470
542
|
end
|
|
471
543
|
end
|
|
472
544
|
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
[language, script, region].compact.join('-')
|
|
545
|
+
def default_tag?(language, script, region)
|
|
546
|
+
[language, script, region].compact.join('-') == Locale.default
|
|
476
547
|
end
|
|
477
548
|
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
"#<#{self.class.name} #{to_s}>"
|
|
549
|
+
def default_region_for?(language, region)
|
|
550
|
+
region && region == Locale.regions[language]
|
|
481
551
|
end
|
|
482
552
|
|
|
483
|
-
private
|
|
484
|
-
|
|
485
553
|
alias original_locale_attribute_assignments attribute_assignments
|
|
486
554
|
|
|
487
555
|
def attribute_assignments
|
|
@@ -493,7 +561,7 @@ module CSL
|
|
|
493
561
|
end
|
|
494
562
|
|
|
495
563
|
def preamble
|
|
496
|
-
Schema.preamble
|
|
564
|
+
Schema.preamble
|
|
497
565
|
end
|
|
498
566
|
|
|
499
567
|
# @param other [Locale] an other locale whose options should be merged
|
|
@@ -532,6 +600,9 @@ module CSL
|
|
|
532
600
|
def merge_terms(other)
|
|
533
601
|
return self unless other.has_terms?
|
|
534
602
|
|
|
603
|
+
# Ordinals are replaced as a set
|
|
604
|
+
terms.drop_ordinals if has_terms? && other.terms.has_ordinals?
|
|
605
|
+
|
|
535
606
|
other.each_term do |term|
|
|
536
607
|
store term.deep_copy
|
|
537
608
|
end
|
data/lib/csl/node.rb
CHANGED
|
@@ -131,8 +131,7 @@ module CSL
|
|
|
131
131
|
def attr_struct(*attributes)
|
|
132
132
|
const_set(:Attributes, Struct.new(*attributes) {
|
|
133
133
|
|
|
134
|
-
|
|
135
|
-
@keys = attributes.map(&:to_sym).freeze
|
|
134
|
+
@keys = members.freeze
|
|
136
135
|
|
|
137
136
|
class << self
|
|
138
137
|
attr_reader :keys
|
|
@@ -169,13 +168,10 @@ module CSL
|
|
|
169
168
|
end
|
|
170
169
|
|
|
171
170
|
def fetch(key, default = nil)
|
|
172
|
-
value =
|
|
171
|
+
value = send(:'[]', key) if keys.include?(key.to_sym)
|
|
172
|
+
return value unless value.nil?
|
|
173
173
|
|
|
174
|
-
|
|
175
|
-
value || yield(key)
|
|
176
|
-
else
|
|
177
|
-
value || default
|
|
178
|
-
end
|
|
174
|
+
block_given? ? yield(key) : default
|
|
179
175
|
end
|
|
180
176
|
|
|
181
177
|
# Merges the current with the passed-in attributes.
|
|
@@ -308,6 +304,17 @@ module CSL
|
|
|
308
304
|
attributes.fetch(name, false)
|
|
309
305
|
end
|
|
310
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
|
+
|
|
311
318
|
# @param [[String]] names list of attribute names
|
|
312
319
|
# @return [Boolean] true if the node contains attributes for all
|
|
313
320
|
# passed-in names; false otherwise.
|
|
@@ -467,11 +474,11 @@ module CSL
|
|
|
467
474
|
end
|
|
468
475
|
|
|
469
476
|
def strip_periods?
|
|
470
|
-
|
|
477
|
+
boolean_attribute(:'strip-periods')
|
|
471
478
|
end
|
|
472
479
|
|
|
473
480
|
def quotes?
|
|
474
|
-
|
|
481
|
+
boolean_attribute(:quotes)
|
|
475
482
|
end
|
|
476
483
|
|
|
477
484
|
|
|
@@ -574,17 +581,6 @@ module CSL
|
|
|
574
581
|
CSL.encode_xml_text text.to_s.strip
|
|
575
582
|
end
|
|
576
583
|
|
|
577
|
-
# TextNodes quack like a string.
|
|
578
|
-
# def_delegators :to_s, *String.instance_methods(false).reject do |m|
|
|
579
|
-
# m.to_s =~ /^\W|!$|(?:^(?:hash|eql?|to_s|length|size|inspect)$)/
|
|
580
|
-
# end
|
|
581
|
-
#
|
|
582
|
-
# String.instance_methods(false).select { |m| m.to_s =~ /!$/ }.each do |m|
|
|
583
|
-
# define_method(m) do
|
|
584
|
-
# content.send(m) if content.respond_to?(m)
|
|
585
|
-
# end
|
|
586
|
-
# end
|
|
587
|
-
|
|
588
584
|
def initialize(argument = '')
|
|
589
585
|
case
|
|
590
586
|
when argument.respond_to?(:each_pair)
|
data/lib/csl/parser.rb
CHANGED
|
@@ -12,8 +12,7 @@ module CSL
|
|
|
12
12
|
:nokogiri => lambda { |source|
|
|
13
13
|
Nokogiri::XML::Document.parse(source, nil, nil,
|
|
14
14
|
Nokogiri::XML::ParseOptions::DEFAULT_XML |
|
|
15
|
-
Nokogiri::XML::ParseOptions::NOBLANKS
|
|
16
|
-
Nokogiri::XML::ParseOptions::NOENT)
|
|
15
|
+
Nokogiri::XML::ParseOptions::NOBLANKS)
|
|
17
16
|
},
|
|
18
17
|
:default => lambda { |source|
|
|
19
18
|
REXML::Document.new(source, :compress_whitespace => :all, :ignore_whitespace_nodes => :all)
|
data/lib/csl/pretty_printer.rb
CHANGED
data/lib/csl/style/label.rb
CHANGED