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.
@@ -3,6 +3,8 @@ module CSL
3
3
  class Style < Node
4
4
  types << CSL::Info << CSL::Locale
5
5
 
6
+ include InheritableNameOptions
7
+
6
8
  @default = :apa
7
9
 
8
10
  @root = '/usr/local/share/csl/styles'.freeze
@@ -14,9 +16,9 @@ module CSL
14
16
  include Loader
15
17
 
16
18
  attr_accessor :default
17
-
18
- def load(input = Style.default)
19
- super
19
+
20
+ def load(input = nil)
21
+ super(input || Style.default)
20
22
  end
21
23
  end
22
24
 
@@ -45,8 +47,7 @@ module CSL
45
47
  :independent_parent_link, :independent_parent_link=,
46
48
  :has_independent_parent_link?, :title=, :id=, :has_title?, :has_id?,
47
49
  :published_at, :updated_at, :citation_format, :citation_format=,
48
- :updated_at, :update!, :license, :license=, :default_license?,
49
- :default_license!
50
+ :update!, :license, :license=, :default_license?, :default_license!
50
51
 
51
52
  def initialize(attributes = {})
52
53
  super(attributes, &nil)
@@ -77,6 +78,7 @@ module CSL
77
78
  validate.empty?
78
79
  end
79
80
 
81
+ remove_method :info # generated by struct_children
80
82
  def info
81
83
  children[:info] ||= Info.new
82
84
  end
@@ -114,6 +116,28 @@ module CSL
114
116
  load_related_style_from independent_parent_link
115
117
  end
116
118
 
119
+ def demote_non_dropping_particle
120
+ attributes[:'demote-non-dropping-particle']
121
+ end
122
+ alias demote_particle demote_non_dropping_particle
123
+
124
+ def demote_non_dropping_particle?
125
+ attribute?(:'demote-non-dropping-particle')
126
+ end
127
+ alias demote_particle? demote_non_dropping_particle?
128
+
129
+ def initialize_without_hyphen?
130
+ attribute?(:'initialize-with-hyphen') && !attributes[:'initialize-with-hyphen']
131
+ end
132
+
133
+ def has_page_range_format?
134
+ attribute?(:'page-range-format')
135
+ end
136
+
137
+ def page_range_format
138
+ attributes[:'page-range-format']
139
+ end
140
+
117
141
  private
118
142
 
119
143
  def preamble
@@ -124,7 +148,7 @@ module CSL
124
148
  # TODO try local first
125
149
  Style.load(uri)
126
150
  end
127
-
151
+
128
152
  def added_macro(node)
129
153
  unless node.attribute?(:name)
130
154
  raise ValidationError,
@@ -138,10 +162,10 @@ module CSL
138
162
 
139
163
  macros[node[:name]] = node
140
164
  end
141
-
165
+
142
166
  def deleted_macro(node)
143
167
  macros.delete node[:name]
144
168
  end
145
169
  end
146
170
 
147
- end
171
+ end
@@ -1,15 +1,52 @@
1
1
  module CSL
2
2
  class Style
3
-
3
+
4
4
  class Bibliography < Node
5
-
6
- attr_struct :'hanging-indent', :'second-field-align', :'line-spacing',
7
- :'entry-spacing', :'note-distance', :'subsequent-author-substitute',
8
- :'subsequent-author-substitute-rule', *Schema.attr(:name, :names)
9
-
5
+
6
+ include InheritableNameOptions
7
+
8
+ attr_struct :'subsequent-author-substitute',
9
+ :'subsequent-author-substitute-rule',
10
+ *Schema.attr(:bibliography, :name, :names)
11
+
10
12
  attr_children :sort, :layout
11
-
13
+
14
+ attr_defaults :'line-spacing' => 1, :'entry-spacing' => 1,
15
+ :'subsequent-author-substitute-rule' => 'complete-all'
16
+
17
+ alias sort? has_sort?
18
+
19
+ def bibliography_options
20
+ attributes_for(*Schema.attr(:bibliography))
21
+ end
22
+
23
+ def sort_keys
24
+ return [] unless sort?
25
+ children[:sort].descendants
26
+ end
27
+
28
+ def substitute_subsequent_authors?
29
+ attribute?(:'subsequent-author-substitute')
30
+ end
31
+
32
+ def subsequent_author_substitute
33
+ attributes[:'subsequent-author-substitute'].to_s
34
+ end
35
+
36
+ def subsequent_author_substitute_rule
37
+ attributes[:'subsequent-author-substitute-rule'].to_s
38
+ end
39
+
40
+ def substitute_subsequent_authors_completely?
41
+ return false unless substitute_subsequent_authors?
42
+ subsequent_author_substitute_rule == 'complete-all'
43
+ end
44
+
45
+ def substitute_subsequent_authors_individually?
46
+ return false unless substitute_subsequent_authors?
47
+ subsequent_author_substitute_rule != 'complete-all'
48
+ end
12
49
  end
13
-
50
+
14
51
  end
15
- end
52
+ end
@@ -3,6 +3,8 @@ module CSL
3
3
 
4
4
  class Choose < Node
5
5
 
6
+ alias blocks children
7
+
6
8
  class Block < Node
7
9
  attr_struct :match, *Schema.attr(:conditionals)
8
10
 
@@ -10,7 +12,7 @@ module CSL
10
12
 
11
13
  class << self
12
14
  def matches?(nodename)
13
- nodename.to_s =~ /^if(-else)?|else$/
15
+ nodename === ':if' || nodename === ':elseif' || nodename === ':else'
14
16
  end
15
17
  end
16
18
 
@@ -52,4 +54,4 @@ module CSL
52
54
  end
53
55
 
54
56
  end
55
- end
57
+ end
@@ -1,17 +1,16 @@
1
1
  module CSL
2
2
  class Style
3
-
3
+
4
4
  class Citation < Node
5
-
6
- attr_struct :'cite-group-delimiter', :collapse, :'year-suffix-delimiter',
7
- :'after-collapse-delimiter', :'disambiguate-add-names',
8
- :'disambiguate-add-givenname', :'disambiguate-add-year-suffix',
9
- :'givenname-disambiguation-rule', :'names-delimiter',
10
- *Schema.attr(:names, :name)
11
-
5
+
6
+ include InheritableNameOptions
7
+
8
+ attr_struct(*Schema.attr(:citation, :names, :name))
9
+
12
10
  attr_children :sort, :layout
13
-
11
+
12
+ alias sort? has_sort?
14
13
  end
15
-
14
+
16
15
  end
17
- end
16
+ end
@@ -13,18 +13,25 @@ module CSL
13
13
  # the Group calls a variable (either directly or via a macro), and
14
14
  # b) all variables that are called are empty.
15
15
  class Group < Node
16
- attr_struct(*Schema.attr(:formatting, :affixes, :delimiter))
16
+ attr_struct(*Schema.attr(:formatting, :delimiter))
17
17
 
18
18
  def delimiter
19
19
  attributes.fetch(:delimiter, '')
20
20
  end
21
21
 
22
- private
23
-
24
- def added_child(node)
25
- node.attributes.merge formatting_options
22
+ # Returns only those formatting options applicable to the Group
23
+ # node itself; not those which are transmitted to the enclosed
24
+ # elements.
25
+ #
26
+ # @return [Hash] the node's formatting options
27
+ def formatting_options
28
+ attributes_for :display, *Schema.attr(:affixes)
29
+ end
30
+
31
+ def inheritable_formatting_options
32
+ attributes_for :'text-case', *Schema.attr(:font)
26
33
  end
27
34
  end
28
35
 
29
36
  end
30
- end
37
+ end
@@ -77,4 +77,4 @@ module CSL
77
77
  end
78
78
 
79
79
  end
80
- end
80
+ end
@@ -1,13 +1,13 @@
1
1
  module CSL
2
2
  class Style
3
-
3
+
4
4
  class Layout < Node
5
5
  attr_struct(*Schema.attr(:affixes, :font, :delimiter))
6
-
6
+
7
7
  def delimiter
8
8
  attributes.fetch(:delimiter, '')
9
9
  end
10
10
  end
11
-
11
+
12
12
  end
13
- end
13
+ end
@@ -1,12 +1,17 @@
1
+ # encoding: utf-8
2
+
1
3
  module CSL
2
4
  class Style
3
5
 
4
6
  class Names < Node
7
+ extend InheritsNameOptions
5
8
 
6
- attr_struct :variable, *Schema.attr(:names, :delimiter, :affixes, :font)
9
+ attr_struct :variable, *Schema.attr(:delimiter, :affixes, :font)
7
10
 
8
11
  attr_children :name, :'et-al', :label, :substitute
9
12
 
13
+ inherits :names_options
14
+
10
15
  alias labels label
11
16
 
12
17
  def initialize(attributes = {})
@@ -16,8 +21,10 @@ module CSL
16
21
  yield self if block_given?
17
22
  end
18
23
 
19
- def delimiter
20
- attributes.fetch(:delimiter, '')
24
+ def delimiter(node = nil, style = nil)
25
+ attributes.fetch(:delimiter) do
26
+ inherited_names_options(node, style)[:delimiter] || ''
27
+ end
21
28
  end
22
29
 
23
30
  def has_variable?
@@ -32,15 +39,20 @@ module CSL
32
39
 
33
40
 
34
41
  class Name < Node
42
+ extend InheritsNameOptions
35
43
 
36
44
  attr_struct :form, *Schema.attr(:name, :affixes, :font, :delimiter)
37
45
 
38
- attr_defaults :form => 'long', :delimiter => ', ',
39
- :'delimiter-precedes-last' => 'contextual', :initialize => true,
40
- :'sort-separator' => ', '
46
+ # Having default attributes makes inheritance really difficult.
47
+ #
48
+ # attr_defaults :form => 'long', :delimiter => ', ',
49
+ # :'delimiter-precedes-last' => 'contextual', :initialize => true,
50
+ # :'sort-separator' => ', '
41
51
 
42
52
  attr_children :'name-part'
43
53
 
54
+ inherits :name_options
55
+
44
56
  alias parts name_part
45
57
 
46
58
  def initialize(attributes = {})
@@ -50,17 +62,29 @@ module CSL
50
62
  yield self if block_given?
51
63
  end
52
64
 
65
+ def count?
66
+ attribute?(:form) && attributes[:form] == 'count'
67
+ end
68
+
69
+ def name_options
70
+ attributes_for :form, :initialize, :'initialize-with', :'sort-separator'
71
+ end
53
72
 
54
- def initialize?
55
- attributes[:initialize].to_s !~ /^false$/i
73
+ def initialize_without_hyphen?
74
+ !root? && root.respond_to?(:initialize_without_hyphen?) &&
75
+ root.initialize_without_hyphen?
56
76
  end
57
77
 
58
78
  def et_al
59
- parent && parent.et_al
79
+ @et_al || parent && parent.et_al
80
+ end
81
+
82
+ def et_al=(et_al)
83
+ @et_al = et_al
60
84
  end
61
85
 
62
86
  # @param names [#to_i, Enumerable] the list of names (or its length)
63
- # @return [Boolean] whether or not the should be truncate
87
+ # @return [Boolean] whether or not the list should be truncated
64
88
  def truncate?(names, subsequent = false)
65
89
  names = names.length if names.respond_to?(:length)
66
90
  limit = truncate_when(subsequent)
@@ -79,35 +103,60 @@ module CSL
79
103
 
80
104
  def truncate_when(subsequent = false)
81
105
  if subsequent && attribute?(:'et-al-subsequent-min')
82
- attribute[:'et-al-subsequent-min'].to_i
106
+ attributes[:'et-al-subsequent-min'].to_i
83
107
  else
84
- attribute[:'et-al-min'].to_i
108
+ attributes[:'et-al-min'].to_i
85
109
  end
86
110
  end
87
111
 
88
112
  def truncate_at(subsequent = false)
89
113
  if subsequent && attribute?(:'et-al-subsequent-use-first')
90
- attribute[:'et-al-subsequent-use-first'].to_i
114
+ attributes.fetch(:'et-al-subsequent-use-first', 1).to_i
91
115
  else
92
- attribute[:'et-al-use-first'].to_i
116
+ attributes.fetch(:'et-al-use-first', 1).to_i
93
117
  end
94
118
  end
95
119
 
120
+ def truncate_at!(at)
121
+ attributes[:'et-al-use-first'] = at.to_i
122
+ self
123
+ end
124
+
125
+ def truncate_when!(pos)
126
+ attributes[:'et-al-min'] = pos.to_i
127
+ self
128
+ end
129
+
130
+ def truncate_subsequent_at!(at)
131
+ attributes[:'et-al-subsequent-use-first'] = at.to_i
132
+ self
133
+ end
134
+
135
+ def truncate_subsequent_when!(pos)
136
+ attributes[:'et-al-subsequent-min'] = pos.to_i
137
+ self
138
+ end
139
+
96
140
  # @return [String] the delimiter between family and given names
97
141
  # in sort order
98
142
  def sort_separator
99
- attributes[:'sort-separator'].to_s
143
+ attributes[:'sort-separator'] || ', '
100
144
  end
101
145
 
102
146
  # @return [String] the delimiter between names
103
147
  def delimiter
104
- attributes[:delimiter].to_s
148
+ attributes[:delimiter] || ', '
105
149
  end
106
150
 
107
151
  def name_as_sort_order?
108
152
  attribute?(:'name-as-sort-order')
109
153
  end
110
154
 
155
+ def name_as_sort_order_at?(position)
156
+ return false unless name_as_sort_order?
157
+ all_names_as_sort_order? || position == 1 && first_name_as_sort_order?
158
+ end
159
+
111
160
  def name_as_sort_order
112
161
  attributes[:'name-as-sort-order'].to_s
113
162
  end
@@ -115,14 +164,91 @@ module CSL
115
164
  alias sort_order name_as_sort_order
116
165
 
117
166
  def first_name_as_sort_order?
118
- attributes[:'name-as-sort-order'].to_s =~ /^first$/i
167
+ !!(attributes[:'name-as-sort-order'].to_s =~ /^first$/i)
119
168
  end
120
169
 
121
170
  def all_names_as_sort_order?
122
- attributes[:'name-as-sort-order'].to_s =~ /^all$/i
171
+ !!(attributes[:'name-as-sort-order'].to_s =~ /^all$/i)
172
+ end
173
+
174
+ def first_name_as_sort_order!
175
+ attributes[:'name-as-sort-order'] = 'first'
176
+ self
177
+ end
178
+
179
+ def all_names_as_sort_order!
180
+ attributes[:'name-as-sort-order'] = 'all'
181
+ self
182
+ end
183
+
184
+ def delimiter_precedes_et_al?(names)
185
+ names = names.length if names.respond_to?(:length)
186
+
187
+ case
188
+ when delimiter_never_precedes_et_al?
189
+ false
190
+ when delimiter_always_precedes_et_al?
191
+ true
192
+ when delimiter_precedes_et_al_after_inverted_name?
193
+ name_as_sort_order_at?(names.to_i)
194
+ else
195
+ names.to_i > 1
196
+ end
197
+ end
198
+
199
+ # @return [Boolean] whether or not the delimmiter should
200
+ # always be inserted before et-al
201
+ def delimiter_always_precedes_et_al?
202
+ !!(attributes[:'delimiter-precedes-et-al'].to_s =~ /^always$/i)
203
+ end
204
+
205
+ # Set the :'delimiter-precedes-et-al' attribute to 'always'.
206
+ # @return [self] self
207
+ def delimiter_always_precedes_et_al!
208
+ attributes[:'delimiter-precedes-et-al'] = 'always'
209
+ self
210
+ end
211
+
212
+ alias delimiter_precedes_et_al! delimiter_always_precedes_et_al!
213
+
214
+
215
+ # @return [Boolean] whether or not the delimiter should
216
+ # never be inserted before et-al
217
+ def delimiter_never_precedes_et_al?
218
+ !!(attributes[:'delimiter-precedes-et-al'].to_s =~ /^never$/i)
219
+ end
220
+
221
+ # Set the :'delimiter-precedes-et-al' attribute to 'never'
222
+ # @return [self] self
223
+ def delimiter_never_precedes_et_al!
224
+ attributes[:'delimiter-precedes-et-al'] = 'never'
225
+ self
226
+ end
227
+
228
+ # @return [Boolean] whether or not the delimtier should
229
+ # be inserted between before et-al depending on the
230
+ # number of names rendered
231
+ def delimiter_contextually_precedes_et_al?
232
+ return true unless attribute?[:'delimiter-precedes-et-al']
233
+ !!(attributes[:'delimiter-precedes-et-al'].to_s =~ /^contextual/i)
234
+ end
235
+
236
+ # Set the :'delimiter-precedes-et-al' attribute to 'contextual'
237
+ # @return [self] self
238
+ def delimiter_contextually_precedes_et_al!
239
+ attributes[:'delimiter-precedes-et-al'] = 'contextual'
240
+ self
241
+ end
242
+
243
+ def delimiter_precedes_et_al_after_inverted_name?
244
+ !!(attributes[:'delimiter-precedes-et-al'].to_s =~ /^after-inverted-name/i)
245
+ end
246
+
247
+ def delimiter_precedes_et_al_after_inverted_name!
248
+ attributes[:'delimiter-precedes-et-al'] = 'after-inverted-name'
249
+ self
123
250
  end
124
251
 
125
-
126
252
  # @param names [#to_i, Enumerable] the list of names (or its length)
127
253
  # @return [Boolean] whether or not the delimiter will be inserted between
128
254
  # the penultimate and the last name
@@ -136,7 +262,7 @@ module CSL
136
262
  false
137
263
  when delimiter_always_precedes_last?
138
264
  true
139
- when delimiter_precedeces_last_after_inverted_name?
265
+ when delimiter_precedes_last_after_inverted_name?
140
266
  if name_as_sort_order?
141
267
  all_names_as_sort_order? || names.to_i == 2
142
268
  else
@@ -180,6 +306,7 @@ module CSL
180
306
  # @return [Boolean] whether or not the should be inserted between the
181
307
  # penultimate and the last name depending on the number of names
182
308
  def delimiter_contextually_precedes_last?
309
+ return true unless attribute?(:'delimiter-precedes-last')
183
310
  !!(attributes[:'delimiter-precedes-last'].to_s =~ /^contextual/i)
184
311
  end
185
312
 
@@ -203,20 +330,32 @@ module CSL
203
330
  attributes[:'et-al-use-last'].to_s =~ /^true$/
204
331
  end
205
332
 
333
+ def ellipsis
334
+ "#{delimiter}… "
335
+ end
336
+
206
337
  def connector
207
338
  c = attributes[:and]
208
339
  c == 'symbol' ? '&' : c
209
340
  end
341
+
342
+ def connector=(c)
343
+ attributes[:and] = c
344
+ end
210
345
  end
211
346
 
212
347
  class NamePart < Node
213
348
  has_no_children
214
349
  attr_struct :name, :'text-case', *Schema.attr(:affixes, :font)
350
+
351
+ def name
352
+ attributes[:name]
353
+ end
215
354
  end
216
355
 
217
356
  class EtAl < Node
218
357
  has_no_children
219
- attr_struct :term, *Schema.attr(:affixes, :font)
358
+ attr_struct :term, :'text-case', *Schema.attr(:affixes, :font)
220
359
 
221
360
  attr_defaults :term => 'et-al'
222
361
  end
@@ -226,4 +365,4 @@ module CSL
226
365
 
227
366
 
228
367
  end
229
- end
368
+ end