csl 1.0.2 → 1.1.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.
@@ -21,6 +21,28 @@ module CSL
21
21
 
22
22
  alias each each_child
23
23
 
24
+ # @example
25
+ # terms.store(term)
26
+ # terms.store('book', ['book', 'books'])
27
+ # terms.store('book', 'bk', :form => 'short')
28
+ #
29
+ # Shorthand method to stores a new term translations.
30
+ #
31
+ # @param [Term, String] the term; or the the term's name
32
+ # @param [String] the term's translation
33
+ # @param [Hash] additional term attributes
34
+ #
35
+ # @return [self]
36
+ def store(term, translation = nil, options = nil)
37
+ unless term.is_a?(Term)
38
+ term = Term.new(:name => term)
39
+ term.attributes.merge(options) unless options.nil?
40
+ term.set(*translation)
41
+ end
42
+
43
+ self << term
44
+ end
45
+
24
46
  # If a style uses a term in a form that is undefined, there is a
25
47
  # fallback to other forms: "verb-short" first falls back to "verb",
26
48
  # "symbol" first falls back to "short", and "verb" and "short" both
@@ -151,7 +173,7 @@ module CSL
151
173
  delete_children tmp
152
174
  end
153
175
 
154
- private
176
+ protected
155
177
 
156
178
  # @!attribute [r] registry
157
179
  # @return [Hash] a private registry to map term names to the respective
@@ -163,6 +185,8 @@ module CSL
163
185
  # term objects for quick ordinal look-up
164
186
  attr_reader :ordinals
165
187
 
188
+ private
189
+
166
190
  def added_child(term)
167
191
  raise ValidationError, "failed to register term #{term.inspect}: name attribute missing" unless
168
192
  term.attribute?(:name)
@@ -214,7 +238,7 @@ module CSL
214
238
 
215
239
  def specialize(options)
216
240
  specialized = {}
217
-
241
+
218
242
  options.each do |key, value|
219
243
  key = key.to_sym
220
244
 
@@ -330,6 +354,21 @@ module CSL
330
354
 
331
355
  alias plural pluralize
332
356
 
357
+ alias singular= single=
358
+ alias plural= multiple=
359
+
360
+ def set(singular, plural = nil)
361
+ if plural.nil?
362
+ self.text = singular
363
+ else
364
+ self.single = singular
365
+ self.multiple = plural
366
+ end
367
+
368
+ self
369
+ end
370
+
371
+
333
372
  # @!method masculine?
334
373
  # @return [Boolean] whether or not the term is masculine
335
374
 
@@ -0,0 +1,44 @@
1
+ module CSL
2
+ module InheritableNameOptions
3
+ def inheritable_name_options
4
+ options = attributes_for(*Schema.attr(:name))
5
+
6
+ if attribute?(:'name-delimiter')
7
+ options[:delimiter] = attributes[:'name-delimiter']
8
+ end
9
+
10
+ if attribute?(:'name-form')
11
+ options[:form] = attributes[:'name-form']
12
+ end
13
+
14
+ options
15
+ end
16
+
17
+ def inheritable_names_options
18
+ return {} unless attribute? :'names-delimiter'
19
+ { :delimiter => attributes[:'names-delimiter'] }
20
+ end
21
+ end
22
+
23
+ module InheritsNameOptions
24
+ def inherits(name)
25
+ inheritable_options = "inheritable_#{name}".to_sym
26
+
27
+ define_method("inherited_#{name}") do |node, style|
28
+ options = {}
29
+
30
+ if node.respond_to?(inheritable_options)
31
+ options = node.send(inheritable_options).merge(options)
32
+ end
33
+
34
+ style ||= root
35
+
36
+ if !root? && style.respond_to?(inheritable_options)
37
+ options = style.send(inheritable_options).merge(options)
38
+ end
39
+
40
+ options
41
+ end
42
+ end
43
+ end
44
+ end
@@ -137,8 +137,10 @@ module CSL
137
137
  attr_reader :keys
138
138
  end
139
139
 
140
- def initialize(attrs = {})
141
- super(*attrs.symbolize_keys.values_at(*keys))
140
+ CSL.silence_warnings do
141
+ def initialize(attrs = {})
142
+ super(*attrs.symbolize_keys.values_at(*keys))
143
+ end
142
144
  end
143
145
 
144
146
  # @return [<Symbol>] a list of symbols representing the names/keys
@@ -190,6 +192,7 @@ module CSL
190
192
 
191
193
  self
192
194
  end
195
+ alias merge! merge
193
196
 
194
197
  # @overload values_at(selector, ... )
195
198
  # Returns an array containing the attributes in self according
@@ -231,9 +234,7 @@ module CSL
231
234
 
232
235
  def initialize_copy(other)
233
236
  super
234
- @attributes = self.class.create_attributes(other.attributes)
235
- @children = self.class.create_children
236
- @parent, @ancestors, @descendants, @siblings, @root, @depth = nil
237
+ initialize(other.attributes)
237
238
  end
238
239
 
239
240
  def deep_copy
@@ -246,6 +247,19 @@ module CSL
246
247
  copy
247
248
  end
248
249
 
250
+ def merge!(options)
251
+ attributes.merge!(options)
252
+ self
253
+ end
254
+
255
+ def reverse_merge!(options)
256
+ options.each_pair do |key, value|
257
+ attributes[key] = value unless attribute? key
258
+ end
259
+
260
+ self
261
+ end
262
+
249
263
  # @return [Boolean] whether or not the node has default attributes
250
264
  def has_default_attributes?
251
265
  !default_attributes.empty?
@@ -417,9 +431,41 @@ module CSL
417
431
  }.compact]
418
432
  end
419
433
 
434
+
420
435
  # @return [Hash] the node's formatting options
421
436
  def formatting_options
422
- attributes_for Schema.attr(:formatting)
437
+ options = attributes_for Schema.attr(:formatting)
438
+
439
+ if !root? && parent.respond_to?(:inheritable_formatting_options)
440
+ parent.inheritable_formatting_options.merge(options)
441
+ else
442
+ options
443
+ end
444
+ end
445
+
446
+ # Whether or not page ranges should be formatted when
447
+ # rendering this node.
448
+ #
449
+ # Page ranges must be formatted if the node is part of
450
+ # a {Style} with a page-range-format value.
451
+ #
452
+ # @return [Boolean] whether or not page ranges should
453
+ # be formatted
454
+ def format_page_ranges?
455
+ root.respond_to?(:has_page_range_format?) && root.has_page_range_format?
456
+ end
457
+
458
+ def page_range_format
459
+ return unless format_page_ranges?
460
+ root.page_range_format
461
+ end
462
+
463
+ def strip_periods?
464
+ attribute?(:'strip-periods') && !!(attributes[:'strip-periods'].to_s =~ /^true$/i)
465
+ end
466
+
467
+ def quotes?
468
+ attribute?(:'quotes') && !!(attributes[:'quotes'].to_s =~ /^true$/i)
423
469
  end
424
470
 
425
471
  def <=>(other)
@@ -536,6 +582,8 @@ module CSL
536
582
  true
537
583
  end
538
584
 
585
+ remove_method :empty?
586
+
539
587
  def empty?
540
588
  text.nil? || text.empty?
541
589
  end
@@ -7,21 +7,21 @@ module CSL
7
7
  include Singleton
8
8
 
9
9
  attr_accessor :parser
10
-
10
+
11
11
  @engines = {
12
12
  :nokogiri => lambda { |source|
13
13
  Nokogiri::XML::Document.parse(source, nil, nil,
14
- Nokogiri::XML::ParseOptions::DEFAULT_XML | Nokogiri::XML::ParseOptions::NOBLANKS)
14
+ Nokogiri::XML::ParseOptions::DEFAULT_XML | Nokogiri::XML::ParseOptions::NOBLANKS | Nokogiri::XML::ParseOptions::NOENT)
15
15
  },
16
16
  :default => lambda { |source|
17
17
  REXML::Document.new(source, :compress_whitespace => :all, :ignore_whitespace_nodes => :all)
18
18
  }
19
19
  }
20
-
20
+
21
21
  class << self
22
22
  attr_reader :engines
23
23
  end
24
-
24
+
25
25
  def initialize
26
26
  require 'nokogiri'
27
27
  @parser = Parser.engines[:nokogiri]
@@ -29,23 +29,23 @@ module CSL
29
29
  require 'rexml/document'
30
30
  @parser = Parser.engines[:default]
31
31
  end
32
-
32
+
33
33
  def parse(*arguments)
34
34
  parse!(*arguments)
35
35
  rescue
36
36
  nil
37
37
  end
38
-
38
+
39
39
  def parse!(source, scope = Node)
40
40
  root = parser[source].children.detect { |child| !skip?(child) }
41
41
  parse_tree root, scope
42
42
  end
43
43
 
44
44
  private
45
-
45
+
46
46
  def parse_node(node, scope = Node)
47
47
  attributes, text = parse_attributes(node), parse_text(node)
48
-
48
+
49
49
  if text
50
50
  n = TextNode.create node.name, attributes
51
51
  n.text = text
@@ -54,26 +54,26 @@ module CSL
54
54
  scope.create node.name, attributes
55
55
  end
56
56
  end
57
-
57
+
58
58
  def parse_attributes(node)
59
59
  Hash[*node.attributes.map { |n, a|
60
60
  [n.to_sym, a.respond_to?(:value) ? a.value : a.to_s]
61
61
  }.flatten]
62
62
  end
63
-
63
+
64
64
  def parse_tree(node, scope = Node)
65
65
  return nil if node.nil?
66
-
66
+
67
67
  root = parse_node node, scope
68
68
  scope = specialize_scope(root, scope)
69
-
69
+
70
70
  node.children.each do |child|
71
71
  root << parse_tree(child, scope) unless comment?(child)
72
72
  end unless root.textnode?
73
-
73
+
74
74
  root
75
75
  end
76
-
76
+
77
77
  def parse_text(node)
78
78
  if node.respond_to?(:has_text?)
79
79
  node.has_text? && node.text
@@ -82,7 +82,7 @@ module CSL
82
82
  child && child.respond_to?(:text?) && child.text? && child.text
83
83
  end
84
84
  end
85
-
85
+
86
86
  def comment?(node)
87
87
  node.respond_to?(:comment?) && node.comment? ||
88
88
  node.respond_to?(:node_type) &&
@@ -103,5 +103,5 @@ module CSL
103
103
  end
104
104
  end
105
105
  end
106
-
107
- end
106
+
107
+ end
@@ -1,17 +1,17 @@
1
1
  module CSL
2
-
2
+
3
3
  class Schema
4
-
4
+
5
5
  @version = '1.0.1'.freeze
6
6
  @major_version = '1.0'.freeze
7
7
 
8
8
  @namespace = 'http://purl.org/net/xbiblio/csl'.freeze
9
9
  @preamble = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n".freeze
10
-
10
+
11
11
  @default_license = 'http://creativecommons.org/licenses/by-sa/3.0/'
12
12
  @default_rights_string =
13
13
  'This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License'
14
-
14
+
15
15
  @types = %w{ article article-journal article-magazine article-newspaper
16
16
  bill book broadcast chapter entry entry-dictionary entry-encyclopedia
17
17
  figure graphic interview legal_case legislation manuscript map
@@ -31,7 +31,7 @@ module CSL
31
31
 
32
32
  :number => %w{
33
33
  chapter-number collection-number edition issue number number-of-pages
34
- number-of-volumes volume
34
+ number-of-volumes volume
35
35
  },
36
36
 
37
37
  :text => %w{
@@ -60,7 +60,7 @@ module CSL
60
60
  [:date,:names,:text,:number].reduce([]) { |s,a| s.concat(@variables[a]) }.sort
61
61
 
62
62
  @variables.freeze
63
-
63
+
64
64
  @attributes = Hash.new { |h,k| h.fetch(k.to_sym, nil) }.merge({
65
65
  :affixes => %w{
66
66
  prefix suffix
@@ -72,13 +72,22 @@ module CSL
72
72
  font-style font-variant font-weight text-decoration vertical-align
73
73
  },
74
74
  :name => %w{
75
- name-form name-delimiter and delimiter-precedes-et-al initialize-with
75
+ and delimiter-precedes-et-al initialize-with
76
76
  delimiter-precedes-last et-al-min et-al-use-first et-al-subsequent-min
77
77
  et-al-subsequent-use-first et-al-use-last name-as-sort-order
78
78
  sort-separator initialize
79
79
  },
80
80
  :names => %w{
81
- names-delimiter
81
+ names-delimiter name-delimiter name-form
82
+ },
83
+ :bibliography => %w{
84
+ hanging-indent second-field-align line-spacing entry-spacing
85
+ },
86
+ :citation => %w{
87
+ disambiguate-add-names disambiguate-add-given-name
88
+ givenname-disambiguation-rule disambiguate-add-year-suffix
89
+ cite-group-delimiter collapse year-suffix-delimiter
90
+ after-collapse-delimiter near-note-distance
82
91
  },
83
92
  :conditionals => %w{
84
93
  disambiguate position
@@ -90,7 +99,7 @@ module CSL
90
99
  variable variable-any variable-all variable-none
91
100
  }
92
101
  })
93
-
102
+
94
103
  @attributes.each_value { |v| v.map!(&:to_sym).freeze }
95
104
 
96
105
  @attributes[:formatting] = [:'text-case', :display].concat(
@@ -103,11 +112,11 @@ module CSL
103
112
  :form => %w{ numeric numeric-leading-zeros ordinal long short }
104
113
  }
105
114
  })
106
-
115
+
107
116
  @values.freeze
108
117
 
109
118
  @file = File.expand_path('../../../vendor/schema/csl.rng', __FILE__)
110
-
119
+
111
120
  @validators = {
112
121
  :nokogiri => lambda { |schema, style|
113
122
  begin
@@ -117,12 +126,12 @@ module CSL
117
126
  [[0, $!.message]]
118
127
  end
119
128
  },
120
-
129
+
121
130
  :default => lambda { |schema, style|
122
131
  raise ValidationError, "please `gem install nokogiri' for validation support"
123
132
  }
124
133
  }
125
-
134
+
126
135
  begin
127
136
  # TODO enable java validator when nokogiri issue is fixed
128
137
  if RUBY_PLATFORM =~ /java/i
@@ -135,19 +144,19 @@ module CSL
135
144
  rescue LoadError
136
145
  @validator = @validators[:default]
137
146
  end
138
-
147
+
139
148
  class << self
140
-
149
+
141
150
  attr_accessor :version, :major_version, :namespace, :types,
142
151
  :variables, :categories, :attributes, :preamble, :values,
143
152
  :default_rights_string, :default_license
144
-
153
+
145
154
  private :new
146
-
155
+
147
156
  def attr(*arguments)
148
157
  attributes.values_at(*arguments).flatten(1)
149
158
  end
150
-
159
+
151
160
  # Validates the passed-in style or list of styles. The style argument(s)
152
161
  # can either be a {Style} object, a style's file handle, XML content
153
162
  # or a valid location (wildcards are supported). The method returns
@@ -172,9 +181,9 @@ module CSL
172
181
  def validate(node)
173
182
  case
174
183
  when node.is_a?(Node)
175
- validator[schema, node.to_xml]
184
+ @validator[@schema, node.to_xml]
176
185
  when node.respond_to?(:read)
177
- validator[schema, node.read]
186
+ @validator[@schema, node.read]
178
187
  when node.is_a?(Enumerable) && !node.is_a?(String)
179
188
  node.map { |n| validate(n) }.flatten(1)
180
189
  when node.respond_to?(:to_s)
@@ -182,23 +191,23 @@ module CSL
182
191
 
183
192
  case
184
193
  when node =~ /^\s*</
185
- validator[schema, node]
194
+ @validator[@schema, node]
186
195
  when File.exists?(node)
187
- validator[schema, File.open(node, 'r:UTF-8')]
196
+ @validator[@schema, File.open(node, 'r:UTF-8')]
188
197
  else
189
198
  glob = Dir.glob(node)
190
-
199
+
191
200
  if glob.empty?
192
- validator[schema, Kernel.open(node)]
201
+ @validator[@schema, Kernel.open(node)]
193
202
  else
194
- glob.map { |n| validator[schema, File.open(n, 'r:UTF-8')] }.flatten(1)
203
+ glob.map { |n| @validator[@schema, File.open(n, 'r:UTF-8')] }.flatten(1)
195
204
  end
196
205
  end
197
206
  else
198
207
  raise ArgumentError, "failed to validate #{node.inspect}: not a CSL node"
199
208
  end
200
209
  end
201
-
210
+
202
211
  # Whether or not the passed-in style (or list of styles) is valid.
203
212
  #
204
213
  # @see validate
@@ -215,11 +224,7 @@ module CSL
215
224
  def valid?(style)
216
225
  validate(style).empty?
217
226
  end
218
-
219
- private
220
-
221
- attr_reader :validators, :validator, :schema
222
227
  end
223
-
224
- end
228
+
229
+ end
225
230
  end