csl 1.0.0.pre1 → 1.0.0.pre2

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -6,3 +6,4 @@ Gemfile.lock
6
6
  /.yardoc
7
7
  /.rbx
8
8
  *.rbc
9
+ *.gem
@@ -10,4 +10,13 @@ rvm:
10
10
  - 1.8.7
11
11
  - ree
12
12
  notifications:
13
- email: false
13
+ email:
14
+ recipients:
15
+ - i@nukshuk.io
16
+ on_success: change
17
+ on_failure: always
18
+ matrix:
19
+ allow_failures:
20
+ rvm:
21
+ - rbx-18mode
22
+ - rbx-19mode
data/Rakefile CHANGED
@@ -39,7 +39,7 @@ task :release do |t|
39
39
  system "gem build csl.gemspec"
40
40
  system "git tag #{CSL::VERSION}"
41
41
  system "git push --tags"
42
- system "gem push csl-#{CSL::VERSION}"
42
+ system "gem push csl-#{CSL::VERSION}.gem"
43
43
  end
44
44
 
45
45
  task :default => [:spec, :cucumber]
@@ -854,6 +854,115 @@ Feature: Converting numbers to ordinals using CSL locales
854
854
  | 21:e |
855
855
  # | 101:e |
856
856
  # | 1001:e |
857
+ # | 301:e |
858
+ | 21:e |
859
+ | 21:e |
860
+ # | 1001:e |
861
+
862
+ @v1.0.1 @locale @ordinals @i18n @gender @lang:pl
863
+ Scenario: Gendered Swedish CSL 1.0.1 locales
864
+ Given the locale:
865
+ """
866
+ <?xml version="1.0" encoding="utf-8"?>
867
+ <locale xmlns="http://purl.org/net/xbiblio/csl" version="1.0.1" xml:lang="sv">
868
+ <terms>
869
+ <term name="ordinal-00">:e</term>
870
+
871
+ <term name="ordinal-01">:a</term>
872
+ <term name="ordinal-01" gender-form="masculine">:e</term>
873
+ <term name="ordinal-01" gender-form="feminine">:a</term>
874
+
875
+ <term name="ordinal-02">:a</term>
876
+ <term name="ordinal-02" gender-form="masculine">:e</term>
877
+ <term name="ordinal-02" gender-form="feminine">:a</term>
878
+
879
+ <term name="ordinal-11">:e</term>
880
+ <term name="ordinal-11" gender-form="feminine">:e</term>
881
+ <term name="ordinal-12">:e</term>
882
+ <term name="ordinal-12" gender-form="feminine">:e</term>
883
+
884
+ <term name="ordinal-21">:e</term>
885
+ <term name="ordinal-21" gender-form="feminine">:e</term>
886
+ <term name="ordinal-22">:e</term>
887
+ <term name="ordinal-22" gender-form="feminine">:e</term>
888
+
889
+ <term name="ordinal-31">:e</term>
890
+ <term name="ordinal-32">:e</term>
891
+
892
+ <term name="ordinal-41">:e</term>
893
+ <term name="ordinal-42">:e</term>
894
+
895
+ <term name="ordinal-51">:e</term>
896
+ <term name="ordinal-52">:e</term>
897
+
898
+ <term name="ordinal-61">:e</term>
899
+ <term name="ordinal-62">:e</term>
900
+
901
+ <term name="ordinal-71">:e</term>
902
+ <term name="ordinal-72">:e</term>
903
+
904
+ <term name="ordinal-81">:e</term>
905
+ <term name="ordinal-82">:e</term>
906
+
907
+ <term name="ordinal-91">:e</term>
908
+ <term name="ordinal-92">:e</term>
909
+ </terms>
910
+ </locale>
911
+ """
912
+ When I ordinalize these numbers:
913
+ | num | form | gender | number |
914
+ | 0 | | | |
915
+ | 1 | | | |
916
+ | 2 | | | |
917
+ | 3 | | | |
918
+ | 4 | | | |
919
+ | 5 | | | |
920
+ | 6 | | | |
921
+ | 7 | | | |
922
+ | 8 | | | |
923
+ | 9 | | | |
924
+ | 10 | | | |
925
+ | 1 | | feminine | |
926
+ | 1 | | masculine | |
927
+ | 2 | | feminine | |
928
+ | 2 | | masculine | |
929
+ | 23 | | | |
930
+ | 999 | | | |
931
+ | 11 | | | |
932
+ | 11 | | feminine | |
933
+ | 11 | | masculine | |
934
+ | 21 | | | |
935
+ # | 101 | | | |
936
+ # | 1001 | | feminine | |
937
+ # | 301 | | | |
938
+ | 21 | | masculine | singular |
939
+ | 21 | | masculine | plural |
940
+ # | 1001 | | masculine | |
941
+ Then the ordinals should be:
942
+ | ordinal |
943
+ | 0:e |
944
+ | 1:a |
945
+ | 2:a |
946
+ | 3:e |
947
+ | 4:e |
948
+ | 5:e |
949
+ | 6:e |
950
+ | 7:e |
951
+ | 8:e |
952
+ | 9:e |
953
+ | 10:e |
954
+ | 1:a |
955
+ | 1:e |
956
+ | 2:a |
957
+ | 2:e |
958
+ | 23:e |
959
+ | 999:e |
960
+ | 11:e |
961
+ | 11:e |
962
+ | 11:e |
963
+ | 21:e |
964
+ # | 101:e |
965
+ # | 1001:e |
857
966
  # | 301:e |
858
967
  | 21:e |
859
968
  | 21:e |
@@ -8,33 +8,33 @@ Feature: Loading CSL Style
8
8
  <?xml version="1.0" encoding="utf-8"?>
9
9
  <style xmlns="http://purl.org/net/xbiblio/csl" class="in-text" version="1.0" demote-non-dropping-particle="never">
10
10
  <info>
11
- <title>American Psychological Association 6th Edition</title>
12
- <id>http://www.zotero.org/styles/apa</id>
13
- <link href="http://www.zotero.org/styles/apa" rel="self"/>
14
- <link href="http://owl.english.purdue.edu/owl/resource/560/01/" rel="documentation"/>
15
- <author>
16
- <name>Simon Kornblith</name>
17
- <email>simon@simonster.com</email>
18
- </author>
19
- <contributor>
20
- <name>Bruce D'Arcus</name>
21
- </contributor>
22
- <contributor>
23
- <name>Curtis M. Humphrey</name>
24
- </contributor>
25
- <contributor>
26
- <name>Richard Karnesky</name>
27
- <email>karnesky+zotero@gmail.com</email>
28
- <uri>http://arc.nucapt.northwestern.edu/Richard_Karnesky</uri>
29
- </contributor>
30
- <contributor>
31
- <name>Sebastian Karcher</name>
32
- </contributor>
33
- <category field="psychology"/>
34
- <category field="generic-base"/>
35
- <category citation-format="author-date"/>
36
- <updated>2010-01-27T20:08:03+00:00</updated>
37
- <rights>This work is licensed under a Creative Commons Attribution-Share Alike 3.0 License: http://creativecommons.org/licenses/by-sa/3.0/</rights>
11
+ <title>American Psychological Association 6th Edition</title>
12
+ <id>http://www.zotero.org/styles/apa</id>
13
+ <link href="http://www.zotero.org/styles/apa" rel="self"/>
14
+ <link href="http://owl.english.purdue.edu/owl/resource/560/01/" rel="documentation"/>
15
+ <author>
16
+ <name>Simon Kornblith</name>
17
+ <email>simon@simonster.com</email>
18
+ </author>
19
+ <contributor>
20
+ <name>Bruce D'Arcus</name>
21
+ </contributor>
22
+ <contributor>
23
+ <name>Curtis M. Humphrey</name>
24
+ </contributor>
25
+ <contributor>
26
+ <name>Richard Karnesky</name>
27
+ <email>karnesky+zotero@gmail.com</email>
28
+ <uri>http://arc.nucapt.northwestern.edu/Richard_Karnesky</uri>
29
+ </contributor>
30
+ <contributor>
31
+ <name>Sebastian Karcher</name>
32
+ </contributor>
33
+ <category field="psychology"/>
34
+ <category field="generic-base"/>
35
+ <category citation-format="author-date"/>
36
+ <updated>2010-01-27T20:08:03+00:00</updated>
37
+ <rights>This work is licensed under a Creative Commons Attribution-Share Alike 3.0 License: http://creativecommons.org/licenses/by-sa/3.0/</rights>
38
38
  </info>
39
39
  <locale xml:lang="en">
40
40
  <terms>
data/lib/csl.rb CHANGED
@@ -29,7 +29,7 @@ require 'csl/locale/style_options'
29
29
  require 'csl/style'
30
30
  require 'csl/style/bibliography'
31
31
  require 'csl/style/citation'
32
- require 'csl/style/conditional'
32
+ require 'csl/style/choose'
33
33
  require 'csl/style/date'
34
34
  require 'csl/style/group'
35
35
  require 'csl/style/label'
@@ -51,4 +51,12 @@ module CSL
51
51
  Parser.instance.parse!(*arguments)
52
52
  end
53
53
 
54
+ def validate(node)
55
+ Schema.validate(node)
56
+ end
57
+
58
+ def valid?(node)
59
+ Schema.valid?(node)
60
+ end
61
+
54
62
  end
@@ -17,3 +17,7 @@ class Module
17
17
  end
18
18
  end
19
19
  end
20
+
21
+ class Struct
22
+ alias_method :__class__, :class
23
+ end unless Struct.instance_methods.include?(:__class__)
@@ -9,7 +9,10 @@ module CSL
9
9
  end
10
10
  end
11
11
 
12
- class ParseError < Error; end
13
- class ValidationError < Error; end
12
+ class ParseError < Error
13
+ end
14
+
15
+ class ValidationError < Error
16
+ end
14
17
 
15
18
  end
@@ -2,9 +2,9 @@ module CSL
2
2
 
3
3
  class Info < Node
4
4
 
5
- attr_children :author, :category, :contributor, :id, :issn, :eissn,
6
- :issnl, :link, :published, :rights, :summary, :title, :'title-short',
7
- :updated, :'link-dependent-style'
5
+ attr_children :title, :'title-short', :id, :issn, :eissn, :issnl,
6
+ :link, :author, :contributor, :category, :published, :summary,
7
+ :updated, :rights, :'link-dependent-style'
8
8
 
9
9
  alias contributors contributor
10
10
 
@@ -21,7 +21,7 @@ module CSL
21
21
  attr_children :name, :email, :uri
22
22
  end
23
23
 
24
- class Link < TextNode
24
+ class Link < Node
25
25
  attr_struct :href, :rel
26
26
  end
27
27
 
@@ -30,10 +30,37 @@ module CSL
30
30
  end
31
31
 
32
32
 
33
- class Category < TextNode
33
+ class Category < Node
34
34
  attr_struct :field, :'citation-format'
35
35
  end
36
+
37
+ class Id < TextNode
38
+ end
39
+
40
+ class Name < TextNode
41
+ end
42
+
43
+ class Email < TextNode
44
+ end
45
+
46
+ class Title < TextNode
47
+ end
48
+
49
+ class ShortTitle < TextNode
50
+ end
51
+
52
+ class Summary < TextNode
53
+ end
36
54
 
55
+ class Rights < TextNode
56
+ end
57
+
58
+ class Uri < TextNode
59
+ end
60
+
61
+ class Updated < TextNode
62
+ end
63
+
37
64
  end
38
65
 
39
66
 
@@ -25,9 +25,9 @@ module CSL
25
25
  when input.to_s =~ /^\s*</
26
26
  data = input
27
27
  else
28
-
28
+
29
29
  case
30
- when File.exists?(input)
30
+ when File.exists?(input.to_s)
31
31
  location = input
32
32
  when File.exists?(extend_name(input))
33
33
  location = extend_name(input)
@@ -56,7 +56,7 @@ module CSL
56
56
  # Extends the passed-in string to a style/locale name, by prefixing and
57
57
  # appending the default name prefix and extension.
58
58
  def extend_name(string)
59
- if File.extname(string).empty?
59
+ if File.extname(string.to_s).empty?
60
60
  name = [string, extension].compact.join
61
61
  else
62
62
  name = string.to_s.dup
@@ -37,7 +37,7 @@ module CSL
37
37
  attr_reader :languages, :regions
38
38
 
39
39
  def parse(data)
40
- node = CSL.parse!(data)
40
+ node = CSL.parse!(data, self)
41
41
 
42
42
  raise ParseError, "root node is not a locale: #{node.inspect}" unless
43
43
  node.is_a?(self)
@@ -48,6 +48,7 @@ module CSL
48
48
  end
49
49
 
50
50
  attr_defaults :version => Schema.version, :xmlns => Schema.namespace
51
+ attr_struct :xmlns, :version
51
52
 
52
53
  attr_children :'style-options', :info, :date, :terms
53
54
 
@@ -312,6 +313,14 @@ module CSL
312
313
  [number, ordinal.to_s(options)].join
313
314
  end
314
315
 
316
+ def validate
317
+ Schema.validate self
318
+ end
319
+
320
+ def valid?
321
+ validate.empty?
322
+ end
323
+
315
324
  # Locales are sorted first by language, then by region; sort order is
316
325
  # alphabetical with the following exceptions: the default locale is
317
326
  # prioritised; in case of a language match the default region of that
@@ -357,9 +366,17 @@ module CSL
357
366
  private
358
367
 
359
368
  def attribute_assignments
360
- super.push('xml:lang="%s"' % to_s)
369
+ if root?
370
+ super.push('xml:lang="%s"' % to_s)
371
+ else
372
+ 'xml:lang="%s"' % to_s
373
+ end
361
374
  end
362
375
 
376
+ def preamble
377
+ Schema.preamble.dup
378
+ end
379
+
363
380
  # @return [Hash] a valid ordinalize query; the name attribute is a format string
364
381
  def ordinalize_query_for(options)
365
382
  q = { :name => 'ordinal-%02d' }
@@ -4,7 +4,7 @@ module CSL
4
4
  # A localized Date comprises a set of formatting rules for dates.
5
5
  class Date < Node
6
6
 
7
- attr_struct :form, *Schema.attr(:font, :delimiter, :textcase)
7
+ attr_struct :form, :'text-case', *Schema.attr(:font, :delimiter)
8
8
  attr_children :'date-part'
9
9
 
10
10
  alias parts date_part
@@ -32,8 +32,8 @@ module CSL
32
32
  class DatePart < Node
33
33
  has_no_children
34
34
 
35
- attr_struct :name, :form, :'range-delimiter',
36
- *Schema.attr(:affixes, :textcase, :font, :periods)
35
+ attr_struct :name, :form, :'range-delimiter', :'text-case',
36
+ *Schema.attr(:affixes, :font, :periods)
37
37
 
38
38
  %w{ day month year }.each do |part|
39
39
  define_method("#{part}?") do
@@ -147,6 +147,9 @@ module CSL
147
147
  #
148
148
  # @option options [:singular,:plural] :number (:singular) whether to
149
149
  # return the term's singular or plural variant.
150
+ # @option options [Boolean] :plural (false) whether or not to return
151
+ # the term's plural variant (this option, if set, takes precedence
152
+ # over :number).
150
153
  #
151
154
  # @return [String] the term as a string
152
155
  def to_s(options = nil)
@@ -169,12 +172,19 @@ module CSL
169
172
  def pluralize?(options)
170
173
  return false if options.nil?
171
174
 
172
- key = options[:number] || options['number']
175
+ case
176
+ when options.key?(:plural) || options.key?('plural')
177
+ options[:plural] || options['plural']
178
+ when options.key?(:number) || options.key?('number')
179
+ key = options[:number] || options['number']
173
180
 
174
- if key.is_a?(Fixnum) || key.to_s =~ /^[+-]?\d+$/
175
- key.to_i > 1
181
+ if key.is_a?(Fixnum) || key.to_s =~ /^[+-]?\d+$/
182
+ key.to_i > 1
183
+ else
184
+ !key.blank? && key.to_s =~ /^plural/i
185
+ end
176
186
  else
177
- !key.blank? && key.to_s =~ /^plural/i
187
+ false
178
188
  end
179
189
  end
180
190
 
@@ -29,22 +29,27 @@ module CSL
29
29
  end
30
30
 
31
31
  def constantize(name)
32
- types.detect do |t|
33
- t.name.split(/::/)[-1].gsub(/([[:lower:]])([[:upper:]])/, '\1-\2').downcase == name
32
+ klass = types.detect { |t| t.matches?(name) }
33
+
34
+ if klass || !superclass.respond_to?(:constantize)
35
+ klass
36
+ else
37
+ superclass.constantize(name)
34
38
  end
35
39
  end
40
+
41
+ # @return [Boolean] whether or not the node's name matches the passed-in name
42
+ def matches?(nodename)
43
+ name.split(/::/)[-1].gsub(/([[:lower:]])([[:upper:]])/, '\1-\2').downcase == nodename
44
+ end
36
45
 
37
46
  # Returns a new node with the passed in name and attributes.
38
47
  def create(name, attributes = {}, &block)
39
48
  klass = constantize(name)
40
49
 
41
- unless klass.nil?
42
- klass.new(attributes, &block)
43
- else
44
- node = new(attributes, &block)
45
- node.nodename = name
46
- node
47
- end
50
+ node = (klass || Node).new(attributes, &block)
51
+ node.nodename = name
52
+ node
48
53
  end
49
54
 
50
55
  def create_attributes(attributes)
@@ -72,11 +77,11 @@ module CSL
72
77
 
73
78
  # 1.8 Compatibility
74
79
  @keys = attributes.map(&:to_sym).freeze
75
-
80
+
76
81
  class << self
77
82
  attr_reader :keys
78
83
  end
79
-
84
+
80
85
  def initialize(attrs = {})
81
86
  super(*attrs.symbolize_keys.values_at(*keys))
82
87
  end
@@ -84,7 +89,7 @@ module CSL
84
89
  # @return [<Symbol>] a list of symbols representing the names/keys
85
90
  # of the attribute variables.
86
91
  def keys
87
- self.class.keys
92
+ __class__.keys
88
93
  end
89
94
 
90
95
  def values
@@ -102,7 +107,7 @@ module CSL
102
107
  end
103
108
 
104
109
  def fetch(key, default = nil)
105
- value = keys.include?(key.to_sym) && send(key)
110
+ value = keys.include?(key.to_sym) && send(:'[]', key)
106
111
 
107
112
  if block_given?
108
113
  value || yield(key)
@@ -120,8 +125,8 @@ module CSL
120
125
  other.respond_to?(:each_pair)
121
126
 
122
127
  other.each_pair do |part, value|
123
- writer = "#{part}="
124
- send(writer, value) if !value.nil? && respond_to?(writer)
128
+ part = part.to_sym
129
+ send(:'[]=', part, value) if !value.nil? && keys.include?(part)
125
130
  end
126
131
 
127
132
  self
@@ -187,6 +192,14 @@ module CSL
187
192
  end
188
193
  alias has_text? textnode?
189
194
 
195
+ def save_to(path, options = {})
196
+ File.open(path, 'w:UTF-8') do |f|
197
+ f << (options[:compact] ? to_xml : pretty_print)
198
+ end
199
+
200
+ self
201
+ end
202
+
190
203
  def <=>(other)
191
204
  [nodename, attributes, children] <=> [other.nodename, other.attributes, other.children]
192
205
  rescue
@@ -200,9 +213,9 @@ module CSL
200
213
  tags = []
201
214
  tags << "<#{[nodename, *attribute_assignments].join(' ')}>"
202
215
 
203
- tags << children.map do |node|
216
+ tags << children.map { |node|
204
217
  node.respond_to?(:tags) ? node.tags : [node.to_s]
205
- end
218
+ }.flatten(1)
206
219
 
207
220
  tags << "</#{nodename}>"
208
221
  tags
@@ -235,8 +248,17 @@ module CSL
235
248
 
236
249
  class << self
237
250
  undef_method :attr_children
251
+
252
+ # @override
253
+ def create(name, attributes = {}, &block)
254
+ klass = constantize(name)
255
+
256
+ node = (klass || TextNode).new(attributes, &block)
257
+ node.nodename = name
258
+ node
259
+ end
238
260
  end
239
-
261
+
240
262
  attr_accessor :text
241
263
  alias to_s text
242
264
 
@@ -269,11 +291,7 @@ module CSL
269
291
  end
270
292
 
271
293
  def tags
272
- tags = []
273
- tags << "<#{attribute_assignments.unshift(nodename).join(' ')}>"
274
- tags << text
275
- tags << "</#{nodename}>"
276
- tags
294
+ ["<#{attribute_assignments.unshift(nodename).join(' ')}>#{text}</#{nodename}>"]
277
295
  end
278
296
 
279
297
  def inspect