csl 1.0.0.pre1 → 1.0.0.pre2
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.
- data/.gitignore +1 -0
- data/.travis.yml +10 -1
- data/Rakefile +1 -1
- data/features/locales/ordinalize.feature +109 -0
- data/features/style/loading.feature +27 -27
- data/lib/csl.rb +9 -1
- data/lib/csl/compatibility.rb +4 -0
- data/lib/csl/errors.rb +5 -2
- data/lib/csl/info.rb +32 -5
- data/lib/csl/loader.rb +3 -3
- data/lib/csl/locale.rb +19 -2
- data/lib/csl/locale/date.rb +3 -3
- data/lib/csl/locale/term.rb +14 -4
- data/lib/csl/node.rb +41 -23
- data/lib/csl/parser.rb +15 -2
- data/lib/csl/pretty_printer.rb +11 -9
- data/lib/csl/schema.rb +95 -8
- data/lib/csl/style.rb +16 -5
- data/lib/csl/style/choose.rb +16 -0
- data/lib/csl/style/date.rb +4 -4
- data/lib/csl/style/label.rb +2 -2
- data/lib/csl/style/names.rb +3 -3
- data/lib/csl/style/number.rb +2 -1
- data/lib/csl/style/text.rb +2 -2
- data/lib/csl/version.rb +1 -1
- data/spec/csl/info_spec.rb +20 -1
- data/spec/csl/locale/term_spec.rb +45 -0
- data/spec/csl/node_spec.rb +3 -1
- data/spec/csl/schema_spec.rb +37 -4
- data/spec/csl/style/{conditional_spec.rb → choose_spec.rb} +1 -1
- data/spec/csl/style_spec.rb +4 -2
- data/spec/spec_helper.rb +2 -2
- data/vendor/schema/csl-categories.rng +47 -0
- data/vendor/schema/csl-terms.rng +144 -0
- data/vendor/schema/csl-types.rng +45 -0
- data/vendor/schema/csl-variables.rng +114 -0
- data/vendor/schema/csl.rng +1750 -0
- metadata +16 -14
- data/lib/csl/style/conditional.rb +0 -11
data/lib/csl/parser.rb
CHANGED
@@ -65,7 +65,8 @@ module CSL
|
|
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
|
node.children.each do |child|
|
70
71
|
root << parse_tree(child, scope) unless comment?(child)
|
71
72
|
end unless root.textnode?
|
@@ -86,7 +87,19 @@ module CSL
|
|
86
87
|
node.respond_to?(:comment?) && node.comment? ||
|
87
88
|
node.respond_to?(:node_type) && [:comment, :xmldecl].include?(node.node_type)
|
88
89
|
end
|
89
|
-
|
90
|
+
|
91
|
+
def specialize_scope(root, scope = Node)
|
92
|
+
case root
|
93
|
+
when Style
|
94
|
+
Style
|
95
|
+
when Locale
|
96
|
+
Locale
|
97
|
+
when Info
|
98
|
+
Info
|
99
|
+
else
|
100
|
+
scope
|
101
|
+
end
|
102
|
+
end
|
90
103
|
end
|
91
104
|
|
92
105
|
end
|
data/lib/csl/pretty_printer.rb
CHANGED
@@ -8,9 +8,9 @@ module CSL
|
|
8
8
|
def to_xml
|
9
9
|
tags.flatten.join
|
10
10
|
end
|
11
|
-
|
11
|
+
|
12
12
|
def pretty_print
|
13
|
-
|
13
|
+
preamble << tags.map { |t| pp t }.join("\n")
|
14
14
|
end
|
15
15
|
|
16
16
|
private
|
@@ -19,13 +19,15 @@ module CSL
|
|
19
19
|
2
|
20
20
|
end
|
21
21
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
22
|
+
def preamble
|
23
|
+
''
|
24
|
+
end
|
25
|
+
|
26
|
+
def pp(tag, level = 0)
|
27
|
+
if tag.is_a?(Array)
|
28
|
+
tag.map { |t| pp t, level + 1 }.join("\n")
|
29
|
+
else
|
30
|
+
(' ' * (level * tabwidth)) << tag.to_s
|
29
31
|
end
|
30
32
|
end
|
31
33
|
|
data/lib/csl/schema.rb
CHANGED
@@ -4,7 +4,7 @@ module CSL
|
|
4
4
|
|
5
5
|
@version = '1.0.1'.freeze
|
6
6
|
@namespace = 'http://purl.org/net/xbiblio/csl'.freeze
|
7
|
-
@preamble =
|
7
|
+
@preamble = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n".freeze
|
8
8
|
|
9
9
|
@types = %w{ article article-journal article-magazine article-newspaper
|
10
10
|
bill book broadcast chapter entry entry-dictionary entry-encyclopedia
|
@@ -74,13 +74,11 @@ module CSL
|
|
74
74
|
:periods => %w{
|
75
75
|
strip-periods
|
76
76
|
},
|
77
|
-
:textcase => %w{
|
78
|
-
lowercase uppercase capitalize-first capitalize-all title sentence
|
79
|
-
},
|
80
77
|
:name => %w{
|
81
78
|
name-form name-delimiter and delimiter-precedes-et-al initialize-with
|
82
|
-
delimiter-precedes-last et-al-min
|
83
|
-
et-al-subsequent-use-first et-al-use-last
|
79
|
+
delimiter-precedes-last et-al-min et-al-use-first et-al-subsequent-min
|
80
|
+
et-al-subsequent-use-first et-al-use-last name-as-sort-order
|
81
|
+
sort-separator initialize
|
84
82
|
},
|
85
83
|
:names => %w{
|
86
84
|
names-delimiter
|
@@ -90,6 +88,25 @@ module CSL
|
|
90
88
|
@attributes.each_value { |v| v.map!(&:to_sym).freeze }
|
91
89
|
@attributes.freeze
|
92
90
|
|
91
|
+
@file = File.expand_path('../../../vendor/schema/csl.rng', __FILE__)
|
92
|
+
|
93
|
+
@validators = {
|
94
|
+
:nokogiri => lambda { |schema, style|
|
95
|
+
schema.validate(Nokogiri::XML(style)).map { |e| [e.line, e.message] }
|
96
|
+
},
|
97
|
+
|
98
|
+
:default => lambda { |schema, style|
|
99
|
+
raise ValidationError, "please `gem install nokogiri' for validation support"
|
100
|
+
}
|
101
|
+
}
|
102
|
+
|
103
|
+
begin
|
104
|
+
require 'nokogiri'
|
105
|
+
@validator = @validators[:nokogiri]
|
106
|
+
@schema = Nokogiri::XML::RelaxNG(File.open(@file))
|
107
|
+
rescue LoadError
|
108
|
+
@validator = @validators[:default]
|
109
|
+
end
|
93
110
|
|
94
111
|
class << self
|
95
112
|
|
@@ -102,8 +119,78 @@ module CSL
|
|
102
119
|
attributes.values_at(*arguments).flatten(1)
|
103
120
|
end
|
104
121
|
|
122
|
+
# Validates the passed-in style or list of styles. The style argument(s)
|
123
|
+
# can either be a {Style} object, a style's file handle, XML content
|
124
|
+
# or a valid location (wildcards are supported). The method returns
|
125
|
+
# a list of validation errors; the passed-in style is valid if the
|
126
|
+
# method returns an empty list.
|
127
|
+
#
|
128
|
+
# @example
|
129
|
+
# CSL::Schema.validate(CSL::Style.load(:apa))
|
130
|
+
#
|
131
|
+
# CSL::Schema.validate('my-styles/style.csl')
|
132
|
+
# CSL::Schema.validate('my-styles/*.csl')
|
133
|
+
# CSL::Schema.validate('http://www.example.org/style.csl')
|
134
|
+
#
|
135
|
+
# @param style [Node,String,IO,Array] the style (or a list of styles)
|
136
|
+
# to validate.
|
137
|
+
#
|
138
|
+
# @raise [ArgumentError] if the passed-in argument is not a Style or
|
139
|
+
# a valid style location.
|
140
|
+
# @raise [ValidationError] if the validation process fails
|
141
|
+
#
|
142
|
+
# @return [<<Fixnum,String>>] a list of validation errors
|
143
|
+
def validate(node)
|
144
|
+
case
|
145
|
+
when node.is_a?(Node)
|
146
|
+
validator[schema, node.to_xml]
|
147
|
+
when node.respond_to?(:read)
|
148
|
+
validator[schema, node.read]
|
149
|
+
when node.is_a?(Enumerable) && !node.is_a?(String)
|
150
|
+
node.map { |n| validate(n) }.flatten(1)
|
151
|
+
when node.respond_to?(:to_s)
|
152
|
+
node = node.to_s
|
153
|
+
|
154
|
+
case
|
155
|
+
when node =~ /^\s*</
|
156
|
+
validator[schema, node]
|
157
|
+
when File.exists?(node)
|
158
|
+
validator[schema, File.open(node, 'r:UTF-8')]
|
159
|
+
else
|
160
|
+
glob = Dir.glob(node)
|
161
|
+
|
162
|
+
if glob.empty?
|
163
|
+
validator[schema, Kernel.open(node)]
|
164
|
+
else
|
165
|
+
glob.map { |n| validator[schema, File.open(n, 'r:UTF-8')] }.flatten(1)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
else
|
169
|
+
raise ArgumentError, "failed to validate #{node.inspect}: not a CSL node"
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
# Whether or not the passed-in style (or list of styles) is valid.
|
174
|
+
#
|
175
|
+
# @see validate
|
176
|
+
#
|
177
|
+
# @param style [Style,String,IO,Array] the style (or a list of styles)
|
178
|
+
# to validate.
|
179
|
+
#
|
180
|
+
# @raise [ArgumentError] if the passed-in argument is not a Style or
|
181
|
+
# a valid style location.
|
182
|
+
# @raise [ValidationError] if the validation process fails
|
183
|
+
#
|
184
|
+
# @return [Boolean] whether or not the passed-in style (or styles)
|
185
|
+
# is valid.
|
186
|
+
def valid?(style)
|
187
|
+
validate(style).empty?
|
188
|
+
end
|
189
|
+
|
190
|
+
private
|
191
|
+
|
192
|
+
attr_reader :validators, :validator, :schema
|
105
193
|
end
|
106
194
|
|
107
|
-
end
|
108
|
-
|
195
|
+
end
|
109
196
|
end
|
data/lib/csl/style.rb
CHANGED
@@ -15,24 +15,23 @@ module CSL
|
|
15
15
|
attr_accessor :default
|
16
16
|
|
17
17
|
def parse(data)
|
18
|
-
node = CSL.parse!(data)
|
18
|
+
node = CSL.parse!(data, self)
|
19
19
|
|
20
20
|
raise ParseError, "root node is not a style: #{node.inspect}" unless
|
21
21
|
node.is_a?(self)
|
22
22
|
|
23
23
|
node
|
24
24
|
end
|
25
|
-
|
26
25
|
end
|
27
26
|
|
28
27
|
attr_defaults :version => Schema.version, :xmlns => Schema.namespace
|
29
28
|
|
30
|
-
attr_struct :xmlns, :version, :
|
29
|
+
attr_struct :xmlns, :version, :class, :'default-locale',
|
31
30
|
:'initialize-with-hyphen', :'page-range-format',
|
32
31
|
:'demote-non-dropping-particle', *Schema.attr(:name, :names)
|
33
32
|
|
34
|
-
attr_children :'style-options', :info, :locale, :macro,
|
35
|
-
:bibliography
|
33
|
+
attr_children :'style-options', :info, :locale, :macro,
|
34
|
+
:citation, :bibliography
|
36
35
|
|
37
36
|
alias metadata info
|
38
37
|
alias options style_options
|
@@ -46,8 +45,20 @@ module CSL
|
|
46
45
|
|
47
46
|
yield self if block_given?
|
48
47
|
end
|
48
|
+
|
49
|
+
def validate
|
50
|
+
Schema.validate self
|
51
|
+
end
|
52
|
+
|
53
|
+
def valid?
|
54
|
+
validate.empty?
|
55
|
+
end
|
49
56
|
|
57
|
+
private
|
50
58
|
|
59
|
+
def preamble
|
60
|
+
Schema.preamble.dup
|
61
|
+
end
|
51
62
|
end
|
52
63
|
|
53
64
|
end
|
data/lib/csl/style/date.rb
CHANGED
@@ -2,13 +2,13 @@ module CSL
|
|
2
2
|
class Style
|
3
3
|
|
4
4
|
class Date < Node
|
5
|
-
attr_struct :name, :form, :'range-delimiter', :'date-parts',
|
6
|
-
*Schema.attr(:affixes, :display, :font, :
|
5
|
+
attr_struct :name, :form, :'range-delimiter', :'date-parts', :variable,
|
6
|
+
:'text-case', *Schema.attr(:affixes, :display, :font, :delimiter)
|
7
7
|
end
|
8
8
|
|
9
9
|
class DatePart < Node
|
10
|
-
attr_struct :name, :form, :'range-delimiter',
|
11
|
-
*Schema.attr(:affixes, :
|
10
|
+
attr_struct :name, :form, :'range-delimiter', :'text-case',
|
11
|
+
*Schema.attr(:affixes, :font, :periods)
|
12
12
|
end
|
13
13
|
|
14
14
|
|
data/lib/csl/style/label.rb
CHANGED
data/lib/csl/style/names.rb
CHANGED
@@ -3,7 +3,7 @@ module CSL
|
|
3
3
|
|
4
4
|
class Names < Node
|
5
5
|
|
6
|
-
attr_struct :variable, *Schema.attr(:names)
|
6
|
+
attr_struct :variable, *Schema.attr(:names, :delimiter, :affixes, :display, :font)
|
7
7
|
|
8
8
|
attr_children :name, :'et-al', :label, :substitute
|
9
9
|
|
@@ -30,7 +30,7 @@ module CSL
|
|
30
30
|
def initialize(attributes = {})
|
31
31
|
super(attributes)
|
32
32
|
children[:'name-part'] = []
|
33
|
-
|
33
|
+
|
34
34
|
yield self if block_given?
|
35
35
|
end
|
36
36
|
|
@@ -38,7 +38,7 @@ module CSL
|
|
38
38
|
|
39
39
|
class NamePart < Node
|
40
40
|
has_no_children
|
41
|
-
attr_struct :name, *Schema.attr(:
|
41
|
+
attr_struct :name, :'text-case', *Schema.attr(:affixes, :font)
|
42
42
|
end
|
43
43
|
|
44
44
|
class EtAl < Node
|
data/lib/csl/style/number.rb
CHANGED
@@ -2,7 +2,8 @@ module CSL
|
|
2
2
|
class Style
|
3
3
|
|
4
4
|
class Number < Node
|
5
|
-
attr_struct :
|
5
|
+
attr_struct :variable, :form, :'text-case',
|
6
|
+
*Schema.attr(:affixes, :display, :font)
|
6
7
|
|
7
8
|
|
8
9
|
# @return [Boolean] whether or not the number's format is set to
|
data/lib/csl/style/text.rb
CHANGED
@@ -2,8 +2,8 @@ module CSL
|
|
2
2
|
class Style
|
3
3
|
|
4
4
|
class Text < Node
|
5
|
-
attr_struct :macro, :term, :form, :plural, :
|
6
|
-
*Schema.attr(:affixes, :display, :font, :quotes, :periods
|
5
|
+
attr_struct :variable, :macro, :term, :form, :plural, :'text-case',
|
6
|
+
:value, *Schema.attr(:affixes, :display, :font, :quotes, :periods)
|
7
7
|
end
|
8
8
|
|
9
9
|
end
|
data/lib/csl/version.rb
CHANGED
data/spec/csl/info_spec.rb
CHANGED
@@ -45,9 +45,28 @@ module CSL
|
|
45
45
|
it 'prints the category if present' do
|
46
46
|
Info.new { |i| i.category = 'author' }.to_xml.should == '<info><category>author</category></info>'
|
47
47
|
end
|
48
|
-
|
49
48
|
end
|
50
49
|
|
50
|
+
describe '#pretty_print' do
|
51
|
+
it 'returns an empty info element by default' do
|
52
|
+
subject.pretty_print.should == '<info/>'
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'prints the id indented if present' do
|
56
|
+
Info.new { |i| i.set_child_id 'apa' }.pretty_print.should == "<info>\n <id>apa</id>\n</info>"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
describe '#tags' do
|
61
|
+
it 'returns a list with an empty info element by default' do
|
62
|
+
subject.tags.should == ['<info/>']
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'returns a nested list if id is present' do
|
66
|
+
Info.new { |i| i.set_child_id 'apa' }.tags.should == ['<info>', ['<id>apa</id>'], '</info>']
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
51
70
|
end
|
52
71
|
|
53
72
|
describe Info::Author do
|
@@ -76,6 +76,51 @@ module CSL
|
|
76
76
|
f.matches?(:name => 'edition', :gender => 'feminine').should be_true
|
77
77
|
end
|
78
78
|
end
|
79
|
+
|
80
|
+
describe 'attributes#to_a' do
|
81
|
+
it 'returns an array of all attribute values of underlying struct' do
|
82
|
+
f.attributes.to_a.should == ['edition', nil, 'feminine', nil]
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
describe '#to_s' do
|
88
|
+
it 'returns an empty string by default' do
|
89
|
+
Locale::Term.new.to_s.should == ''
|
90
|
+
end
|
91
|
+
|
92
|
+
describe 'given a simple term' do
|
93
|
+
let(:node) { Locale::Term.new { |t| t.text = 'foo' } }
|
94
|
+
|
95
|
+
it "returns the term's text" do
|
96
|
+
node.to_s.should == node.text
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
describe 'given a compound term' do
|
101
|
+
let(:node) { Locale::Term.new { |t| t.single = 'shoe'; t.multiple = 'shoes' } }
|
102
|
+
|
103
|
+
it "returns the term's singular form by default" do
|
104
|
+
node.to_s.should == node.singularize
|
105
|
+
end
|
106
|
+
|
107
|
+
it "returns the term's plural form when passed :number => :plural" do
|
108
|
+
node.to_s(:number => :plural).should == node.pluralize
|
109
|
+
end
|
110
|
+
|
111
|
+
it "returns the term's plural form when passed :number => 2" do
|
112
|
+
node.to_s(:number => 2).should == node.pluralize
|
113
|
+
end
|
114
|
+
|
115
|
+
it "returns the term's singular form when passed :number => 1" do
|
116
|
+
node.to_s(:number => 1).should == node.singularize
|
117
|
+
end
|
118
|
+
|
119
|
+
it "returns the term's plural form when passed :plural => true" do
|
120
|
+
node.to_s(:plural => true).should == node.pluralize
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
79
124
|
end
|
80
125
|
|
81
126
|
describe '#to_xml' do
|
data/spec/csl/node_spec.rb
CHANGED
@@ -92,9 +92,11 @@ module CSL
|
|
92
92
|
it 'accepts hash and yields itself to the optional block' do
|
93
93
|
TextNode.new(:foo => 'bar') { |n| n.text = 'foo' }.to_xml.should == '<text-node foo="bar">foo</text-node>'
|
94
94
|
end
|
95
|
-
|
96
95
|
end
|
97
96
|
|
97
|
+
describe '#pretty_print' do
|
98
|
+
TextNode.new(:foo => 'bar') { |n| n.text = 'foo' }.pretty_print.should == '<text-node foo="bar">foo</text-node>'
|
99
|
+
end
|
98
100
|
end
|
99
101
|
|
100
102
|
end
|