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 +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
|