csl 1.0.0.pre1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|