csl 1.0.0.pre1
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.gitignore +8 -0
- data/.gitmodules +6 -0
- data/.rspec +3 -0
- data/.simplecov +2 -0
- data/.travis.yml +13 -0
- data/.yardopts +2 -0
- data/AGPL +662 -0
- data/BSDL +29 -0
- data/Gemfile +24 -0
- data/Guardfile +14 -0
- data/README.md +39 -0
- data/Rakefile +45 -0
- data/csl.gemspec +36 -0
- data/cucumber.yml +1 -0
- data/features/locales/loading.feature +57 -0
- data/features/locales/ordinalize.feature +861 -0
- data/features/parser/info.feature +27 -0
- data/features/parser/localized_dates.feature +35 -0
- data/features/parser/terms.feature +28 -0
- data/features/step_definitions/locale_steps.rb +34 -0
- data/features/step_definitions/parser_steps.rb +28 -0
- data/features/step_definitions/style_steps.rb +16 -0
- data/features/style/loading.feature +53 -0
- data/features/support/env.rb +8 -0
- data/lib/csl.rb +54 -0
- data/lib/csl/compatibility.rb +19 -0
- data/lib/csl/errors.rb +15 -0
- data/lib/csl/extensions.rb +63 -0
- data/lib/csl/info.rb +40 -0
- data/lib/csl/loader.rb +78 -0
- data/lib/csl/locale.rb +393 -0
- data/lib/csl/locale/date.rb +48 -0
- data/lib/csl/locale/style_options.rb +10 -0
- data/lib/csl/locale/term.rb +185 -0
- data/lib/csl/node.rb +285 -0
- data/lib/csl/parser.rb +92 -0
- data/lib/csl/pretty_printer.rb +33 -0
- data/lib/csl/schema.rb +109 -0
- data/lib/csl/style.rb +53 -0
- data/lib/csl/style/bibliography.rb +15 -0
- data/lib/csl/style/citation.rb +17 -0
- data/lib/csl/style/conditional.rb +11 -0
- data/lib/csl/style/date.rb +16 -0
- data/lib/csl/style/group.rb +9 -0
- data/lib/csl/style/label.rb +14 -0
- data/lib/csl/style/layout.rb +10 -0
- data/lib/csl/style/macro.rb +9 -0
- data/lib/csl/style/names.rb +54 -0
- data/lib/csl/style/number.rb +33 -0
- data/lib/csl/style/sort.rb +21 -0
- data/lib/csl/style/text.rb +10 -0
- data/lib/csl/treelike.rb +442 -0
- data/lib/csl/version.rb +3 -0
- data/spec/csl/info_spec.rb +116 -0
- data/spec/csl/locale/date_spec.rb +63 -0
- data/spec/csl/locale/style_options_spec.rb +19 -0
- data/spec/csl/locale/term_spec.rb +96 -0
- data/spec/csl/locale_spec.rb +128 -0
- data/spec/csl/node_spec.rb +100 -0
- data/spec/csl/parser_spec.rb +92 -0
- data/spec/csl/schema_spec.rb +70 -0
- data/spec/csl/style/bibliography_spec.rb +7 -0
- data/spec/csl/style/citation_spec.rb +7 -0
- data/spec/csl/style/conditional_spec.rb +7 -0
- data/spec/csl/style/date_spec.rb +11 -0
- data/spec/csl/style/group_spec.rb +7 -0
- data/spec/csl/style/label_spec.rb +7 -0
- data/spec/csl/style/layout_spec.rb +7 -0
- data/spec/csl/style/macro_spec.rb +7 -0
- data/spec/csl/style/names_spec.rb +23 -0
- data/spec/csl/style/number_spec.rb +84 -0
- data/spec/csl/style/text_spec.rb +7 -0
- data/spec/csl/style_spec.rb +19 -0
- data/spec/csl/treelike_spec.rb +151 -0
- data/spec/spec_helper.rb +30 -0
- metadata +192 -0
data/lib/csl/parser.rb
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
module CSL
|
2
|
+
#
|
3
|
+
# A relatively straightforward XML parser that parses CSL using either
|
4
|
+
# Nokogiri or REXML.
|
5
|
+
#
|
6
|
+
class Parser
|
7
|
+
include Singleton
|
8
|
+
|
9
|
+
attr_accessor :parser
|
10
|
+
|
11
|
+
@engines = {
|
12
|
+
:nokogiri => lambda { |source|
|
13
|
+
Nokogiri::XML::Document.parse(source, nil, nil,
|
14
|
+
Nokogiri::XML::ParseOptions::DEFAULT_XML | Nokogiri::XML::ParseOptions::NOBLANKS)
|
15
|
+
},
|
16
|
+
:default => lambda { |source|
|
17
|
+
REXML::Document.new(source, :compress_whitespace => :all, :ignore_whitespace_nodes => :all)
|
18
|
+
}
|
19
|
+
}
|
20
|
+
|
21
|
+
class << self
|
22
|
+
attr_reader :engines
|
23
|
+
end
|
24
|
+
|
25
|
+
def initialize
|
26
|
+
require 'nokogiri'
|
27
|
+
@parser = Parser.engines[:nokogiri]
|
28
|
+
rescue LoadError
|
29
|
+
require 'rexml/document'
|
30
|
+
@parser = Parser.engines[:default]
|
31
|
+
end
|
32
|
+
|
33
|
+
def parse(*arguments)
|
34
|
+
parse!(*arguments)
|
35
|
+
rescue
|
36
|
+
nil
|
37
|
+
end
|
38
|
+
|
39
|
+
def parse!(source, scope = Node)
|
40
|
+
root = parser[source].children.detect { |child| !comment?(child) }
|
41
|
+
parse_tree root, scope
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def parse_node(node, scope = Node)
|
47
|
+
attributes, text = parse_attributes(node), parse_text(node)
|
48
|
+
|
49
|
+
if text
|
50
|
+
n = TextNode.create node.name, attributes
|
51
|
+
n.text = text
|
52
|
+
n
|
53
|
+
else
|
54
|
+
scope.create node.name, attributes
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def parse_attributes(node)
|
59
|
+
Hash[*node.attributes.map { |n, a|
|
60
|
+
[n.to_sym, a.respond_to?(:value) ? a.value : a.to_s]
|
61
|
+
}.flatten]
|
62
|
+
end
|
63
|
+
|
64
|
+
def parse_tree(node, scope = Node)
|
65
|
+
return nil if node.nil?
|
66
|
+
|
67
|
+
root = parse_node node, scope
|
68
|
+
|
69
|
+
node.children.each do |child|
|
70
|
+
root << parse_tree(child, scope) unless comment?(child)
|
71
|
+
end unless root.textnode?
|
72
|
+
|
73
|
+
root
|
74
|
+
end
|
75
|
+
|
76
|
+
def parse_text(node)
|
77
|
+
if node.respond_to?(:has_text?)
|
78
|
+
node.has_text? && node.text
|
79
|
+
else
|
80
|
+
child = node.children[0]
|
81
|
+
child && child.respond_to?(:text?) && child.text? && child.text
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def comment?(node)
|
86
|
+
node.respond_to?(:comment?) && node.comment? ||
|
87
|
+
node.respond_to?(:node_type) && [:comment, :xmldecl].include?(node.node_type)
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module CSL
|
2
|
+
module PrettyPrinter
|
3
|
+
|
4
|
+
def tags
|
5
|
+
raise 'not implemened by base class'
|
6
|
+
end
|
7
|
+
|
8
|
+
def to_xml
|
9
|
+
tags.flatten.join
|
10
|
+
end
|
11
|
+
|
12
|
+
def pretty_print
|
13
|
+
pp(tags).join("\n")
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def tabwidth
|
19
|
+
2
|
20
|
+
end
|
21
|
+
|
22
|
+
def pp(tags, level = 0)
|
23
|
+
tags.map do |tag|
|
24
|
+
if tag.respond_to?(:map)
|
25
|
+
pp tag, level + 1
|
26
|
+
else
|
27
|
+
' ' * (level * tabwidth) + tag.to_s
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
data/lib/csl/schema.rb
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
module CSL
|
2
|
+
|
3
|
+
class Schema
|
4
|
+
|
5
|
+
@version = '1.0.1'.freeze
|
6
|
+
@namespace = 'http://purl.org/net/xbiblio/csl'.freeze
|
7
|
+
@preamble = '<?xml version="1.0" encoding="utf-8"?>'.freeze
|
8
|
+
|
9
|
+
@types = %w{ article article-journal article-magazine article-newspaper
|
10
|
+
bill book broadcast chapter entry entry-dictionary entry-encyclopedia
|
11
|
+
figure graphic interview legal_case legislation manuscript map
|
12
|
+
motion_picture musical_score pamphlet paper-conference patent
|
13
|
+
personal_communication post post-weblog report review review-book song
|
14
|
+
speech thesis treaty webpage }.map(&:to_sym).freeze
|
15
|
+
|
16
|
+
@variables = Hash.new { |h,k| h.fetch(k.to_sym, nil) }.merge({
|
17
|
+
:date => %w{
|
18
|
+
accessed container event-date issued original-date submitted
|
19
|
+
},
|
20
|
+
|
21
|
+
:names => %w{
|
22
|
+
author collection-editor composer container-author recipient editor
|
23
|
+
editorial-director illustrator interviewer original-author translator
|
24
|
+
},
|
25
|
+
|
26
|
+
:number => %w{
|
27
|
+
chapter-number collection-number edition issue number number-of-pages
|
28
|
+
number-of-volumes volume
|
29
|
+
},
|
30
|
+
|
31
|
+
:text => %w{
|
32
|
+
abstract annote archive archive_location archive-place authority
|
33
|
+
call-number citation-label citation-number collection-title
|
34
|
+
container-title container-title-short dimensions DOI event event-place
|
35
|
+
first-reference-note-number genre ISBN ISSN jurisdiction keyword
|
36
|
+
locator medium note original-publisher original-publisher-place
|
37
|
+
original-title page page-first PMID PMCID publisher publisher-place
|
38
|
+
references section source status title title-short URL version
|
39
|
+
year-suffix
|
40
|
+
}
|
41
|
+
})
|
42
|
+
|
43
|
+
@variables.each_value { |v| v.map!(&:to_sym).freeze }
|
44
|
+
|
45
|
+
@categories = Hash.new { |h,k| h.fetch(k.to_sym, nil) }.merge(
|
46
|
+
Hash[*@variables.keys.map { |k| @variables[k].map { |n| [n,k] } }.flatten]
|
47
|
+
).freeze
|
48
|
+
|
49
|
+
@variables[:name] = @variables[:names]
|
50
|
+
@variables[:dates] = @variables[:date]
|
51
|
+
@variables[:numbers] = @variables[:number]
|
52
|
+
|
53
|
+
@variables[:all] = @variables[:any] =
|
54
|
+
[:date,:names,:text,:number].reduce([]) { |s,a| s.concat(@variables[a]) }.sort
|
55
|
+
|
56
|
+
@variables.freeze
|
57
|
+
|
58
|
+
@attributes = Hash.new { |h,k| h.fetch(k.to_sym, nil) }.merge({
|
59
|
+
:affixes => %w{
|
60
|
+
prefix suffix
|
61
|
+
},
|
62
|
+
:delimiter => %w{
|
63
|
+
delimiter
|
64
|
+
},
|
65
|
+
:display => %w{
|
66
|
+
block left-margin right-inline indent
|
67
|
+
},
|
68
|
+
:font => %w{
|
69
|
+
font-style font-variant font-weight text-decoration vertical-align
|
70
|
+
},
|
71
|
+
:quotes => %w{
|
72
|
+
quotes
|
73
|
+
},
|
74
|
+
:periods => %w{
|
75
|
+
strip-periods
|
76
|
+
},
|
77
|
+
:textcase => %w{
|
78
|
+
lowercase uppercase capitalize-first capitalize-all title sentence
|
79
|
+
},
|
80
|
+
:name => %w{
|
81
|
+
name-form name-delimiter and delimiter-precedes-et-al initialize-with
|
82
|
+
delimiter-precedes-last et-al-min etal-use-first et-al-subsequent-min
|
83
|
+
et-al-subsequent-use-first et-al-use-last
|
84
|
+
},
|
85
|
+
:names => %w{
|
86
|
+
names-delimiter
|
87
|
+
}
|
88
|
+
})
|
89
|
+
|
90
|
+
@attributes.each_value { |v| v.map!(&:to_sym).freeze }
|
91
|
+
@attributes.freeze
|
92
|
+
|
93
|
+
|
94
|
+
class << self
|
95
|
+
|
96
|
+
attr_accessor :version, :namespace, :types, :variables, :categories,
|
97
|
+
:attributes, :preamble
|
98
|
+
|
99
|
+
private :new
|
100
|
+
|
101
|
+
def attr(*arguments)
|
102
|
+
attributes.values_at(*arguments).flatten(1)
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
data/lib/csl/style.rb
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
module CSL
|
2
|
+
|
3
|
+
class Style < Node
|
4
|
+
|
5
|
+
@default = :apa
|
6
|
+
|
7
|
+
@root = File.expand_path('../../../vendor/styles', __FILE__).freeze
|
8
|
+
|
9
|
+
@extension = '.csl'.freeze
|
10
|
+
@prefix = ''
|
11
|
+
|
12
|
+
class << self
|
13
|
+
include Loader
|
14
|
+
|
15
|
+
attr_accessor :default
|
16
|
+
|
17
|
+
def parse(data)
|
18
|
+
node = CSL.parse!(data)
|
19
|
+
|
20
|
+
raise ParseError, "root node is not a style: #{node.inspect}" unless
|
21
|
+
node.is_a?(self)
|
22
|
+
|
23
|
+
node
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
attr_defaults :version => Schema.version, :xmlns => Schema.namespace
|
29
|
+
|
30
|
+
attr_struct :xmlns, :version, :'style-class', :'default-locale',
|
31
|
+
:'initialize-with-hyphen', :'page-range-format',
|
32
|
+
:'demote-non-dropping-particle', *Schema.attr(:name, :names)
|
33
|
+
|
34
|
+
attr_children :'style-options', :info, :locale, :macro, :citation,
|
35
|
+
:bibliography
|
36
|
+
|
37
|
+
alias metadata info
|
38
|
+
alias options style_options
|
39
|
+
alias locales locale
|
40
|
+
|
41
|
+
def initialize(attributes = {})
|
42
|
+
super(attributes)
|
43
|
+
|
44
|
+
children[:locale] = []
|
45
|
+
children[:macro] = []
|
46
|
+
|
47
|
+
yield self if block_given?
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module CSL
|
2
|
+
class Style
|
3
|
+
|
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
|
+
|
10
|
+
attr_children :sort, :layout
|
11
|
+
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module CSL
|
2
|
+
class Style
|
3
|
+
|
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
|
+
|
12
|
+
attr_children :sort, :layout
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module CSL
|
2
|
+
class Style
|
3
|
+
|
4
|
+
class Date < Node
|
5
|
+
attr_struct :name, :form, :'range-delimiter', :'date-parts',
|
6
|
+
*Schema.attr(:affixes, :display, :font, :textcase)
|
7
|
+
end
|
8
|
+
|
9
|
+
class DatePart < Node
|
10
|
+
attr_struct :name, :form, :'range-delimiter',
|
11
|
+
*Schema.attr(:affixes, :textcase, :font, :periods)
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module CSL
|
2
|
+
class Style
|
3
|
+
|
4
|
+
class Names < Node
|
5
|
+
|
6
|
+
attr_struct :variable, *Schema.attr(:names)
|
7
|
+
|
8
|
+
attr_children :name, :'et-al', :label, :substitute
|
9
|
+
|
10
|
+
alias labels label
|
11
|
+
|
12
|
+
def initialize(attributes = {})
|
13
|
+
super(attributes)
|
14
|
+
children[:label] = []
|
15
|
+
|
16
|
+
yield self if block_given?
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
class Name < Node
|
23
|
+
|
24
|
+
attr_struct :form, *Schema.attr(:name, :affixes, :font, :delimiter)
|
25
|
+
|
26
|
+
attr_children :'name-part'
|
27
|
+
|
28
|
+
alias parts name_part
|
29
|
+
|
30
|
+
def initialize(attributes = {})
|
31
|
+
super(attributes)
|
32
|
+
children[:'name-part'] = []
|
33
|
+
|
34
|
+
yield self if block_given?
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
class NamePart < Node
|
40
|
+
has_no_children
|
41
|
+
attr_struct :name, *Schema.attr(:textcase, :affixes, :font)
|
42
|
+
end
|
43
|
+
|
44
|
+
class EtAl < Node
|
45
|
+
has_no_children
|
46
|
+
attr_struct :term, *Schema.attr(:affixes, :font)
|
47
|
+
end
|
48
|
+
|
49
|
+
class Substitute < Node
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|