csl 1.0.0.pre1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (77) hide show
  1. data/.document +5 -0
  2. data/.gitignore +8 -0
  3. data/.gitmodules +6 -0
  4. data/.rspec +3 -0
  5. data/.simplecov +2 -0
  6. data/.travis.yml +13 -0
  7. data/.yardopts +2 -0
  8. data/AGPL +662 -0
  9. data/BSDL +29 -0
  10. data/Gemfile +24 -0
  11. data/Guardfile +14 -0
  12. data/README.md +39 -0
  13. data/Rakefile +45 -0
  14. data/csl.gemspec +36 -0
  15. data/cucumber.yml +1 -0
  16. data/features/locales/loading.feature +57 -0
  17. data/features/locales/ordinalize.feature +861 -0
  18. data/features/parser/info.feature +27 -0
  19. data/features/parser/localized_dates.feature +35 -0
  20. data/features/parser/terms.feature +28 -0
  21. data/features/step_definitions/locale_steps.rb +34 -0
  22. data/features/step_definitions/parser_steps.rb +28 -0
  23. data/features/step_definitions/style_steps.rb +16 -0
  24. data/features/style/loading.feature +53 -0
  25. data/features/support/env.rb +8 -0
  26. data/lib/csl.rb +54 -0
  27. data/lib/csl/compatibility.rb +19 -0
  28. data/lib/csl/errors.rb +15 -0
  29. data/lib/csl/extensions.rb +63 -0
  30. data/lib/csl/info.rb +40 -0
  31. data/lib/csl/loader.rb +78 -0
  32. data/lib/csl/locale.rb +393 -0
  33. data/lib/csl/locale/date.rb +48 -0
  34. data/lib/csl/locale/style_options.rb +10 -0
  35. data/lib/csl/locale/term.rb +185 -0
  36. data/lib/csl/node.rb +285 -0
  37. data/lib/csl/parser.rb +92 -0
  38. data/lib/csl/pretty_printer.rb +33 -0
  39. data/lib/csl/schema.rb +109 -0
  40. data/lib/csl/style.rb +53 -0
  41. data/lib/csl/style/bibliography.rb +15 -0
  42. data/lib/csl/style/citation.rb +17 -0
  43. data/lib/csl/style/conditional.rb +11 -0
  44. data/lib/csl/style/date.rb +16 -0
  45. data/lib/csl/style/group.rb +9 -0
  46. data/lib/csl/style/label.rb +14 -0
  47. data/lib/csl/style/layout.rb +10 -0
  48. data/lib/csl/style/macro.rb +9 -0
  49. data/lib/csl/style/names.rb +54 -0
  50. data/lib/csl/style/number.rb +33 -0
  51. data/lib/csl/style/sort.rb +21 -0
  52. data/lib/csl/style/text.rb +10 -0
  53. data/lib/csl/treelike.rb +442 -0
  54. data/lib/csl/version.rb +3 -0
  55. data/spec/csl/info_spec.rb +116 -0
  56. data/spec/csl/locale/date_spec.rb +63 -0
  57. data/spec/csl/locale/style_options_spec.rb +19 -0
  58. data/spec/csl/locale/term_spec.rb +96 -0
  59. data/spec/csl/locale_spec.rb +128 -0
  60. data/spec/csl/node_spec.rb +100 -0
  61. data/spec/csl/parser_spec.rb +92 -0
  62. data/spec/csl/schema_spec.rb +70 -0
  63. data/spec/csl/style/bibliography_spec.rb +7 -0
  64. data/spec/csl/style/citation_spec.rb +7 -0
  65. data/spec/csl/style/conditional_spec.rb +7 -0
  66. data/spec/csl/style/date_spec.rb +11 -0
  67. data/spec/csl/style/group_spec.rb +7 -0
  68. data/spec/csl/style/label_spec.rb +7 -0
  69. data/spec/csl/style/layout_spec.rb +7 -0
  70. data/spec/csl/style/macro_spec.rb +7 -0
  71. data/spec/csl/style/names_spec.rb +23 -0
  72. data/spec/csl/style/number_spec.rb +84 -0
  73. data/spec/csl/style/text_spec.rb +7 -0
  74. data/spec/csl/style_spec.rb +19 -0
  75. data/spec/csl/treelike_spec.rb +151 -0
  76. data/spec/spec_helper.rb +30 -0
  77. 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
@@ -0,0 +1,10 @@
1
+ module CSL
2
+ class Style
3
+
4
+ class Text < Node
5
+ attr_struct :macro, :term, :form, :plural, :value,
6
+ *Schema.attr(:affixes, :display, :font, :quotes, :periods, :textcase)
7
+ end
8
+
9
+ end
10
+ end
@@ -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