csl 1.0.0.pre1

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