csl 1.0.2 → 1.1.0

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