csl 1.0.0.pre1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (77) hide show
  1. data/.document +5 -0
  2. data/.gitignore +8 -0
  3. data/.gitmodules +6 -0
  4. data/.rspec +3 -0
  5. data/.simplecov +2 -0
  6. data/.travis.yml +13 -0
  7. data/.yardopts +2 -0
  8. data/AGPL +662 -0
  9. data/BSDL +29 -0
  10. data/Gemfile +24 -0
  11. data/Guardfile +14 -0
  12. data/README.md +39 -0
  13. data/Rakefile +45 -0
  14. data/csl.gemspec +36 -0
  15. data/cucumber.yml +1 -0
  16. data/features/locales/loading.feature +57 -0
  17. data/features/locales/ordinalize.feature +861 -0
  18. data/features/parser/info.feature +27 -0
  19. data/features/parser/localized_dates.feature +35 -0
  20. data/features/parser/terms.feature +28 -0
  21. data/features/step_definitions/locale_steps.rb +34 -0
  22. data/features/step_definitions/parser_steps.rb +28 -0
  23. data/features/step_definitions/style_steps.rb +16 -0
  24. data/features/style/loading.feature +53 -0
  25. data/features/support/env.rb +8 -0
  26. data/lib/csl.rb +54 -0
  27. data/lib/csl/compatibility.rb +19 -0
  28. data/lib/csl/errors.rb +15 -0
  29. data/lib/csl/extensions.rb +63 -0
  30. data/lib/csl/info.rb +40 -0
  31. data/lib/csl/loader.rb +78 -0
  32. data/lib/csl/locale.rb +393 -0
  33. data/lib/csl/locale/date.rb +48 -0
  34. data/lib/csl/locale/style_options.rb +10 -0
  35. data/lib/csl/locale/term.rb +185 -0
  36. data/lib/csl/node.rb +285 -0
  37. data/lib/csl/parser.rb +92 -0
  38. data/lib/csl/pretty_printer.rb +33 -0
  39. data/lib/csl/schema.rb +109 -0
  40. data/lib/csl/style.rb +53 -0
  41. data/lib/csl/style/bibliography.rb +15 -0
  42. data/lib/csl/style/citation.rb +17 -0
  43. data/lib/csl/style/conditional.rb +11 -0
  44. data/lib/csl/style/date.rb +16 -0
  45. data/lib/csl/style/group.rb +9 -0
  46. data/lib/csl/style/label.rb +14 -0
  47. data/lib/csl/style/layout.rb +10 -0
  48. data/lib/csl/style/macro.rb +9 -0
  49. data/lib/csl/style/names.rb +54 -0
  50. data/lib/csl/style/number.rb +33 -0
  51. data/lib/csl/style/sort.rb +21 -0
  52. data/lib/csl/style/text.rb +10 -0
  53. data/lib/csl/treelike.rb +442 -0
  54. data/lib/csl/version.rb +3 -0
  55. data/spec/csl/info_spec.rb +116 -0
  56. data/spec/csl/locale/date_spec.rb +63 -0
  57. data/spec/csl/locale/style_options_spec.rb +19 -0
  58. data/spec/csl/locale/term_spec.rb +96 -0
  59. data/spec/csl/locale_spec.rb +128 -0
  60. data/spec/csl/node_spec.rb +100 -0
  61. data/spec/csl/parser_spec.rb +92 -0
  62. data/spec/csl/schema_spec.rb +70 -0
  63. data/spec/csl/style/bibliography_spec.rb +7 -0
  64. data/spec/csl/style/citation_spec.rb +7 -0
  65. data/spec/csl/style/conditional_spec.rb +7 -0
  66. data/spec/csl/style/date_spec.rb +11 -0
  67. data/spec/csl/style/group_spec.rb +7 -0
  68. data/spec/csl/style/label_spec.rb +7 -0
  69. data/spec/csl/style/layout_spec.rb +7 -0
  70. data/spec/csl/style/macro_spec.rb +7 -0
  71. data/spec/csl/style/names_spec.rb +23 -0
  72. data/spec/csl/style/number_spec.rb +84 -0
  73. data/spec/csl/style/text_spec.rb +7 -0
  74. data/spec/csl/style_spec.rb +19 -0
  75. data/spec/csl/treelike_spec.rb +151 -0
  76. data/spec/spec_helper.rb +30 -0
  77. 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,11 @@
1
+ module CSL
2
+ class Style
3
+
4
+ class Conditional < Node
5
+
6
+ class Block < Node
7
+ end
8
+ end
9
+
10
+ end
11
+ 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,9 @@
1
+ module CSL
2
+ class Style
3
+
4
+ class Group < Node
5
+ attr_struct *Schema.attr(:affixes, :display, :delimiter)
6
+ end
7
+
8
+ end
9
+ end
@@ -0,0 +1,14 @@
1
+ module CSL
2
+ class Style
3
+
4
+ class Label < Node
5
+
6
+ has_no_children
7
+
8
+ attr_struct :variable, :form, :plural,
9
+ *Schema.attr(:affixes, :font, :textcase, :periods)
10
+
11
+ end
12
+
13
+ end
14
+ end
@@ -0,0 +1,10 @@
1
+ module CSL
2
+ class Style
3
+
4
+ class Layout < Node
5
+ attr_struct *Schema.attr(:affixes, :font, :delimiter)
6
+
7
+ end
8
+
9
+ end
10
+ end
@@ -0,0 +1,9 @@
1
+ module CSL
2
+ class Style
3
+
4
+ class Macro < Node
5
+ attr_struct :name
6
+ end
7
+
8
+ end
9
+ 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