csl 1.0.0.pre1
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.
- data/.document +5 -0
- data/.gitignore +8 -0
- data/.gitmodules +6 -0
- data/.rspec +3 -0
- data/.simplecov +2 -0
- data/.travis.yml +13 -0
- data/.yardopts +2 -0
- data/AGPL +662 -0
- data/BSDL +29 -0
- data/Gemfile +24 -0
- data/Guardfile +14 -0
- data/README.md +39 -0
- data/Rakefile +45 -0
- data/csl.gemspec +36 -0
- data/cucumber.yml +1 -0
- data/features/locales/loading.feature +57 -0
- data/features/locales/ordinalize.feature +861 -0
- data/features/parser/info.feature +27 -0
- data/features/parser/localized_dates.feature +35 -0
- data/features/parser/terms.feature +28 -0
- data/features/step_definitions/locale_steps.rb +34 -0
- data/features/step_definitions/parser_steps.rb +28 -0
- data/features/step_definitions/style_steps.rb +16 -0
- data/features/style/loading.feature +53 -0
- data/features/support/env.rb +8 -0
- data/lib/csl.rb +54 -0
- data/lib/csl/compatibility.rb +19 -0
- data/lib/csl/errors.rb +15 -0
- data/lib/csl/extensions.rb +63 -0
- data/lib/csl/info.rb +40 -0
- data/lib/csl/loader.rb +78 -0
- data/lib/csl/locale.rb +393 -0
- data/lib/csl/locale/date.rb +48 -0
- data/lib/csl/locale/style_options.rb +10 -0
- data/lib/csl/locale/term.rb +185 -0
- data/lib/csl/node.rb +285 -0
- data/lib/csl/parser.rb +92 -0
- data/lib/csl/pretty_printer.rb +33 -0
- data/lib/csl/schema.rb +109 -0
- data/lib/csl/style.rb +53 -0
- data/lib/csl/style/bibliography.rb +15 -0
- data/lib/csl/style/citation.rb +17 -0
- data/lib/csl/style/conditional.rb +11 -0
- data/lib/csl/style/date.rb +16 -0
- data/lib/csl/style/group.rb +9 -0
- data/lib/csl/style/label.rb +14 -0
- data/lib/csl/style/layout.rb +10 -0
- data/lib/csl/style/macro.rb +9 -0
- data/lib/csl/style/names.rb +54 -0
- data/lib/csl/style/number.rb +33 -0
- data/lib/csl/style/sort.rb +21 -0
- data/lib/csl/style/text.rb +10 -0
- data/lib/csl/treelike.rb +442 -0
- data/lib/csl/version.rb +3 -0
- data/spec/csl/info_spec.rb +116 -0
- data/spec/csl/locale/date_spec.rb +63 -0
- data/spec/csl/locale/style_options_spec.rb +19 -0
- data/spec/csl/locale/term_spec.rb +96 -0
- data/spec/csl/locale_spec.rb +128 -0
- data/spec/csl/node_spec.rb +100 -0
- data/spec/csl/parser_spec.rb +92 -0
- data/spec/csl/schema_spec.rb +70 -0
- data/spec/csl/style/bibliography_spec.rb +7 -0
- data/spec/csl/style/citation_spec.rb +7 -0
- data/spec/csl/style/conditional_spec.rb +7 -0
- data/spec/csl/style/date_spec.rb +11 -0
- data/spec/csl/style/group_spec.rb +7 -0
- data/spec/csl/style/label_spec.rb +7 -0
- data/spec/csl/style/layout_spec.rb +7 -0
- data/spec/csl/style/macro_spec.rb +7 -0
- data/spec/csl/style/names_spec.rb +23 -0
- data/spec/csl/style/number_spec.rb +84 -0
- data/spec/csl/style/text_spec.rb +7 -0
- data/spec/csl/style_spec.rb +19 -0
- data/spec/csl/treelike_spec.rb +151 -0
- data/spec/spec_helper.rb +30 -0
- metadata +192 -0
@@ -0,0 +1,33 @@
|
|
1
|
+
module CSL
|
2
|
+
class Style
|
3
|
+
|
4
|
+
class Number < Node
|
5
|
+
attr_struct :form, *Schema.attr(:affixes, :display, :font, :textcase)
|
6
|
+
|
7
|
+
|
8
|
+
# @return [Boolean] whether or not the number's format is set to
|
9
|
+
# :numeric; also returns true if the number's form attribute is not
|
10
|
+
# set or nil.
|
11
|
+
def numeric?
|
12
|
+
!attribute?(:form) || attributes.form.to_sym == :numeric
|
13
|
+
end
|
14
|
+
|
15
|
+
# @return [Boolean] whether or not the number's format is set to :ordinal
|
16
|
+
def ordinal?
|
17
|
+
attribute?(:form) && attributes.form.to_sym == :ordinal
|
18
|
+
end
|
19
|
+
|
20
|
+
# @return [Boolean] whether or not the number's format is set to :'long-ordinal'
|
21
|
+
def long_ordinal?
|
22
|
+
attribute?(:form) && attributes.form.to_sym == :'long-ordinal'
|
23
|
+
end
|
24
|
+
|
25
|
+
# @return [Boolean] whether or not the number's format is set to :roman
|
26
|
+
def roman?
|
27
|
+
attribute?(:form) && attributes.form.to_sym == :roman
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module CSL
|
2
|
+
|
3
|
+
class Sort < Node
|
4
|
+
|
5
|
+
attr_children :key
|
6
|
+
|
7
|
+
alias keys key
|
8
|
+
|
9
|
+
def initialize(attributes = {})
|
10
|
+
super(attributes)
|
11
|
+
children[:key] = []
|
12
|
+
|
13
|
+
yield self if block_given?
|
14
|
+
end
|
15
|
+
|
16
|
+
class Key < Node
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
data/lib/csl/treelike.rb
ADDED
@@ -0,0 +1,442 @@
|
|
1
|
+
module CSL
|
2
|
+
|
3
|
+
module Treelike
|
4
|
+
|
5
|
+
attr_accessor :parent
|
6
|
+
attr_reader :children
|
7
|
+
attr_writer :nodename
|
8
|
+
|
9
|
+
protected :parent=
|
10
|
+
|
11
|
+
def self.included(base)
|
12
|
+
base.extend(ClassMethods)
|
13
|
+
end
|
14
|
+
|
15
|
+
# @eturn [String] the node's name.
|
16
|
+
def nodename
|
17
|
+
@nodename ||= self.class.name.split(/::/)[-1].gsub(/([[:lower:]])([[:upper:]])/, '\1-\2').downcase
|
18
|
+
end
|
19
|
+
|
20
|
+
def each_child
|
21
|
+
if block_given?
|
22
|
+
children.each(&Proc.new)
|
23
|
+
self
|
24
|
+
else
|
25
|
+
enum_for :each_child
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def delete_children(*nodes)
|
30
|
+
nodes.each do |node|
|
31
|
+
delete_child node
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Deletes child nodes that are equal to the passed-in node. Returns all
|
36
|
+
# deleted children. If no children were deleted, returns nil. If the
|
37
|
+
# optional block is given, returns the result block if no children were
|
38
|
+
# deleted.
|
39
|
+
def delete_child(child)
|
40
|
+
deleted = children.delete child
|
41
|
+
|
42
|
+
case
|
43
|
+
when deleted.nil? && block_given?
|
44
|
+
yield
|
45
|
+
when deleted.nil?
|
46
|
+
nil
|
47
|
+
else
|
48
|
+
[*deleted].each do |node|
|
49
|
+
node.parent = nil
|
50
|
+
|
51
|
+
deleted_child node
|
52
|
+
node.deleted_from self
|
53
|
+
end
|
54
|
+
|
55
|
+
deleted
|
56
|
+
end
|
57
|
+
rescue => e
|
58
|
+
# TODO rollback
|
59
|
+
raise e
|
60
|
+
end
|
61
|
+
|
62
|
+
def add_children(*nodes)
|
63
|
+
nodes.each do |node|
|
64
|
+
add_child node
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def add_child(node)
|
69
|
+
node.unlink
|
70
|
+
|
71
|
+
node.parent = self
|
72
|
+
children << node
|
73
|
+
|
74
|
+
added_child node
|
75
|
+
node.added_to self
|
76
|
+
|
77
|
+
node
|
78
|
+
rescue => e
|
79
|
+
# TODO rollback
|
80
|
+
raise e
|
81
|
+
end
|
82
|
+
|
83
|
+
def <<(node)
|
84
|
+
add_child node
|
85
|
+
self
|
86
|
+
end
|
87
|
+
|
88
|
+
# Returns the first immediate child node whose nodename matches the
|
89
|
+
# passed-in name or pattern; returns nil there is no match.
|
90
|
+
def find_child_by_name(name)
|
91
|
+
children.detect do |child|
|
92
|
+
name === child.nodename
|
93
|
+
end
|
94
|
+
end
|
95
|
+
alias > find_child_by_name
|
96
|
+
|
97
|
+
# Returns all immediate child nodes whose nodename matches the passed-in
|
98
|
+
# name or pattern; returns an empty array if there is no match.
|
99
|
+
def find_children_by_name(name)
|
100
|
+
children.select do |child|
|
101
|
+
name === child.nodename
|
102
|
+
end
|
103
|
+
end
|
104
|
+
alias >> find_children_by_name
|
105
|
+
|
106
|
+
# Returns true if the node has child nodes; false otherwise.
|
107
|
+
def has_children?
|
108
|
+
!empty?
|
109
|
+
end
|
110
|
+
|
111
|
+
def empty?
|
112
|
+
children.empty?
|
113
|
+
end
|
114
|
+
|
115
|
+
# Unlinks the node and all its children from its parent node. Returns
|
116
|
+
# the old parent node or nil.
|
117
|
+
def unlink
|
118
|
+
return nil if root?
|
119
|
+
|
120
|
+
other = parent
|
121
|
+
other.delete_child self
|
122
|
+
|
123
|
+
self.parent = nil
|
124
|
+
|
125
|
+
other
|
126
|
+
end
|
127
|
+
|
128
|
+
def each_sibling
|
129
|
+
if block_given?
|
130
|
+
unless root?
|
131
|
+
parent.children.each do |node|
|
132
|
+
yield node unless node.equal?(self)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
self
|
137
|
+
else
|
138
|
+
enum_for :each_sibling
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def siblings
|
143
|
+
@siblings = each_sibling.to_a
|
144
|
+
end
|
145
|
+
|
146
|
+
def each_descendant
|
147
|
+
if block_given?
|
148
|
+
each_child do |child|
|
149
|
+
yield child
|
150
|
+
child.each_descendant(&Proc.new)
|
151
|
+
end
|
152
|
+
|
153
|
+
self
|
154
|
+
else
|
155
|
+
enum_for :each_descendant
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
# Returns all descendants of the node. See #descendants1 for a memoized
|
160
|
+
# version.
|
161
|
+
def descendants
|
162
|
+
@descendants = each_descendant.to_a
|
163
|
+
end
|
164
|
+
|
165
|
+
def each_ancestor
|
166
|
+
if block_given?
|
167
|
+
p = parent
|
168
|
+
|
169
|
+
until p.nil?
|
170
|
+
yield p
|
171
|
+
p = p.parent
|
172
|
+
end
|
173
|
+
|
174
|
+
self
|
175
|
+
else
|
176
|
+
enum_for :each_ancestor
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
# Returns this node's ancestors as an array.
|
181
|
+
def ancestors
|
182
|
+
@ancestors = each_ancestor.to_a
|
183
|
+
end
|
184
|
+
|
185
|
+
# Returns the node's current depth in the tree.
|
186
|
+
def depth
|
187
|
+
@depth = ancestors.length
|
188
|
+
end
|
189
|
+
|
190
|
+
# Returns the root node.
|
191
|
+
def root
|
192
|
+
@root = root? ? self : parent.root!
|
193
|
+
end
|
194
|
+
|
195
|
+
# Returns true if the node is a root node, or false.
|
196
|
+
def root?
|
197
|
+
parent.nil?
|
198
|
+
end
|
199
|
+
|
200
|
+
|
201
|
+
# Add memoized methods. When processing citations, styles will
|
202
|
+
# typically remain stable; therefore cite processors may opt
|
203
|
+
# to use memoized versions of the following methods. These
|
204
|
+
# versions are marked with an exclamation mark as a reminder
|
205
|
+
# that the return values are cached and potentially outdated.
|
206
|
+
%w{ ancestors descendants siblings root depth }.each do |name|
|
207
|
+
ivar = "@#{name}"
|
208
|
+
define_method("#{name}!") do
|
209
|
+
instance_variable_get(ivar) || send(name)
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
protected
|
214
|
+
|
215
|
+
# @abstract
|
216
|
+
# Called after the node was added to another node.
|
217
|
+
def added_to(node)
|
218
|
+
end
|
219
|
+
|
220
|
+
# @abstract
|
221
|
+
# Called when the node was deleted from an other node.
|
222
|
+
def deleted_from(node)
|
223
|
+
end
|
224
|
+
|
225
|
+
private
|
226
|
+
|
227
|
+
# @abstract
|
228
|
+
# Called when the passed-in node was added to this node as a child.
|
229
|
+
def added_child(node)
|
230
|
+
end
|
231
|
+
|
232
|
+
# @abstract
|
233
|
+
# Called when the passed-in node was deleted from this node's child nodes.
|
234
|
+
def deleted_child(node)
|
235
|
+
end
|
236
|
+
|
237
|
+
|
238
|
+
module ClassMethods
|
239
|
+
|
240
|
+
# Returns a new instance of an Array or Struct to manage the Node's
|
241
|
+
# children. This method is called automatically by the Node's
|
242
|
+
# constructor.
|
243
|
+
def create_children
|
244
|
+
if const?(:Children)
|
245
|
+
const_get(:Children).new
|
246
|
+
else
|
247
|
+
[]
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
def constantize_nodename(name)
|
252
|
+
klass = name.to_s.capitalize.gsub(/(\w)-(\w)/) { [$1, $2.upcase].join }
|
253
|
+
|
254
|
+
case
|
255
|
+
when respond_to?(:constantize)
|
256
|
+
constantize(klass)
|
257
|
+
when const_defined?(klass)
|
258
|
+
const_get(klass)
|
259
|
+
else
|
260
|
+
nil
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
|
265
|
+
private
|
266
|
+
|
267
|
+
# Creates a Struct for the passed-in child node names that will be
|
268
|
+
# used internally by the Node to manage its children. The Struct
|
269
|
+
# will be automatically initialized and is used similarly to the
|
270
|
+
# standard Array that normally holds the child nodes. The benefit of
|
271
|
+
# using the Struct is that all child nodes are accessible by name and
|
272
|
+
# need not be looked up; this improves performance, however, note that
|
273
|
+
# a node defining it's children that way can only contain nodes of the
|
274
|
+
# given types.
|
275
|
+
#
|
276
|
+
# This method also generates accessors for each child.
|
277
|
+
def attr_children(*names)
|
278
|
+
|
279
|
+
names.each do |name|
|
280
|
+
name = name.to_sym
|
281
|
+
reader = name.to_s.downcase.tr('-', '_')
|
282
|
+
writer = "set_child_#{reader}"
|
283
|
+
|
284
|
+
|
285
|
+
define_method(reader) do
|
286
|
+
children[name]
|
287
|
+
end unless method_defined?(reader)
|
288
|
+
|
289
|
+
unless method_defined?(writer)
|
290
|
+
define_method(writer) do |value|
|
291
|
+
begin
|
292
|
+
klass = self.class.constantize_nodename(name)
|
293
|
+
|
294
|
+
if klass
|
295
|
+
value = klass.new(value)
|
296
|
+
else
|
297
|
+
# try to force convert value
|
298
|
+
value = (value.is_a?(String) ? TextNode : Node).new(value)
|
299
|
+
value.nodename = name.to_s
|
300
|
+
end
|
301
|
+
|
302
|
+
rescue => e
|
303
|
+
raise ArgumentError, "failed to convert #{value.inspect} to node: #{e.message}"
|
304
|
+
end unless value.respond_to?(:nodename)
|
305
|
+
|
306
|
+
children << value
|
307
|
+
end
|
308
|
+
|
309
|
+
alias_method :"#{reader}=", writer
|
310
|
+
|
311
|
+
end
|
312
|
+
end
|
313
|
+
|
314
|
+
const_set(:Children, Struct.new(*names) {
|
315
|
+
|
316
|
+
# 1.8 Compatibility
|
317
|
+
@keys = members.map(&:to_sym).freeze
|
318
|
+
|
319
|
+
class << self
|
320
|
+
attr_reader :keys
|
321
|
+
end
|
322
|
+
|
323
|
+
def initialize(attrs = {})
|
324
|
+
super(*attrs.symbolize_keys.values_at(*keys))
|
325
|
+
end
|
326
|
+
|
327
|
+
# @return [<Symbol>] a list of symbols representing the names/keys
|
328
|
+
# of the attribute variables.
|
329
|
+
def keys
|
330
|
+
self.class.keys
|
331
|
+
end
|
332
|
+
|
333
|
+
alias original_each each
|
334
|
+
|
335
|
+
# Iterates through all children. Nil values are skipped and Arrays
|
336
|
+
# expanded.
|
337
|
+
def each
|
338
|
+
if block_given?
|
339
|
+
original_each do |node|
|
340
|
+
if node.kind_of?(Array)
|
341
|
+
node.select { |n| !n.nil? }.each(&Proc.new)
|
342
|
+
else
|
343
|
+
yield node unless node.nil?
|
344
|
+
end
|
345
|
+
end
|
346
|
+
else
|
347
|
+
to_enum
|
348
|
+
end
|
349
|
+
end
|
350
|
+
|
351
|
+
def empty?
|
352
|
+
all?(&:nil?)
|
353
|
+
end
|
354
|
+
|
355
|
+
# Adds the node as a child node. Raises ValidationError if none
|
356
|
+
# of the Struct members matches the node's name. If there is
|
357
|
+
# already a node set with this node name, the node will be pushed
|
358
|
+
# to an array for that name.
|
359
|
+
def push(node)
|
360
|
+
unless node.respond_to?(:nodename) && keys.include?(node.nodename.to_sym)
|
361
|
+
raise ValidationError, "not allowed to add #{node.inspect} to #{inspect}"
|
362
|
+
end
|
363
|
+
|
364
|
+
current = self[node.nodename]
|
365
|
+
case current
|
366
|
+
when Array
|
367
|
+
current.push(node)
|
368
|
+
when nil
|
369
|
+
self[node.nodename] = node
|
370
|
+
else
|
371
|
+
self[node.nodename] = [current, node]
|
372
|
+
end
|
373
|
+
|
374
|
+
self
|
375
|
+
end
|
376
|
+
|
377
|
+
alias << push
|
378
|
+
|
379
|
+
# Delete items from self that are equal to node. If any items are
|
380
|
+
# found, returns the deleted items. If the items is not found,
|
381
|
+
# returns nil. If the optional code block is given, returns the
|
382
|
+
# result og block if the item is not found.
|
383
|
+
def delete(node)
|
384
|
+
return nil unless node.respond_to?(:nodename)
|
385
|
+
|
386
|
+
deleted = resolve(node.nodename)
|
387
|
+
if deleted.kind_of?(Array)
|
388
|
+
deleted = deleted.delete(node)
|
389
|
+
else
|
390
|
+
if deleted == node
|
391
|
+
self[node.nodename] = nil
|
392
|
+
else
|
393
|
+
deleted = nil
|
394
|
+
end
|
395
|
+
end
|
396
|
+
|
397
|
+
if deleted.nil? && block_given?
|
398
|
+
yield
|
399
|
+
else
|
400
|
+
deleted
|
401
|
+
end
|
402
|
+
end
|
403
|
+
|
404
|
+
def fetch(name, default = nil)
|
405
|
+
if block_given?
|
406
|
+
resolve(name) || yield(key)
|
407
|
+
else
|
408
|
+
resolve(name) || default
|
409
|
+
end
|
410
|
+
end
|
411
|
+
|
412
|
+
private
|
413
|
+
|
414
|
+
def resolve(nodename)
|
415
|
+
keys.include?(nodename.to_sym) && send(nodename)
|
416
|
+
end
|
417
|
+
})
|
418
|
+
end
|
419
|
+
|
420
|
+
# Turns the Node into a leaf-node.
|
421
|
+
def has_no_children
|
422
|
+
undef_method :add_child
|
423
|
+
undef_method :added_child
|
424
|
+
undef_method :add_children
|
425
|
+
undef_method :<<
|
426
|
+
|
427
|
+
undef_method :delete_child
|
428
|
+
undef_method :deleted_child
|
429
|
+
undef_method :delete_children
|
430
|
+
|
431
|
+
private :children
|
432
|
+
|
433
|
+
define_method(:has_children?) do
|
434
|
+
false
|
435
|
+
end
|
436
|
+
|
437
|
+
end
|
438
|
+
|
439
|
+
end
|
440
|
+
|
441
|
+
end
|
442
|
+
end
|