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
@@ -0,0 +1,27 @@
1
+ Feature: Parse CSL info elements
2
+ As a hacker of CSL styles
3
+ I want to be able to parse CSL info strings
4
+
5
+ Scenario: A typical style info element
6
+ When I parse the CSL string
7
+ """
8
+ <info>
9
+ <title>American Medical Association</title>
10
+ <id>http://www.zotero.org/styles/ama</id>
11
+ <link href="http://www.zotero.org/styles/ama" rel="self"/>
12
+ <author>
13
+ <name>Julian Onions</name>
14
+ <email>julian.onions@gmail.com</email>
15
+ </author>
16
+ <category citation-format="numeric"/>
17
+ <category field="medicine"/>
18
+ <updated/>
19
+ <summary>The American Medical Association style as used in JAMA.</summary>
20
+ <link href="http://www.samford.edu/schools/pharmacy/dic/amaquickref07.pdf" rel="documentation"/>
21
+ <rights>This work is licensed under a Creative Commons Attribution-Share Alike 3.0 License: http://creativecommons.org/licenses/by-sa/3.0/</rights>
22
+ </info>
23
+ """
24
+ Then the nodename should be "info"
25
+ And the title should be "American Medical Association"
26
+ And the author name should be "Julian Onions"
27
+ And the author email should be "julian.onions@gmail.com"
@@ -0,0 +1,35 @@
1
+ Feature: Parse CSL localized date elements
2
+ As a hacker of CSL styles
3
+ I want to be able to parse CSL localized date strings
4
+
5
+ Scenario: A text date
6
+ When I parse the CSL string in the Locale scope
7
+ """
8
+ <date form="text">
9
+ <date-part name="month" suffix=" "/>
10
+ <date-part name="day" form="numeric-leading-zeros" suffix=", "/>
11
+ <date-part name="year"/>
12
+ </date>
13
+ """
14
+ Then the nodename should be "date"
15
+ And the attribute "form" should be "text"
16
+ And the node should have 3 parts
17
+ And text? should be "true"
18
+ And the part number 1 should have the attribute "name" set to "month"
19
+
20
+ Scenario: A numeric date
21
+ When I parse the CSL string in the Locale scope
22
+ """
23
+ <date form="numeric">
24
+ <date-part name="month" form="numeric-leading-zeros" suffix="/"/>
25
+ <date-part name="day" form="numeric-leading-zeros" suffix="/"/>
26
+ <date-part name="year"/>
27
+ </date>
28
+ """
29
+ Then the nodename should be "date"
30
+ And the attribute "form" should be "numeric"
31
+ And the node should have 3 parts
32
+ And text? should be "false"
33
+ And numeric? should be "true"
34
+ And the part number 3 should have the attribute "name" set to "year"
35
+
@@ -0,0 +1,28 @@
1
+ Feature: Parse CSL localized terms
2
+ As a hacker of CSL styles
3
+ I want to be able to parse CSL localized terms
4
+
5
+ Scenario: A few standard terms
6
+ When I parse the CSL string
7
+ """
8
+ <terms>
9
+ <term name="accessed">accessed</term>
10
+ <term name="and">and</term>
11
+ <term name="and others">and others</term>
12
+ <term name="anonymous">anonymous</term>
13
+ <term name="anonymous" form="short">anon.</term>
14
+ <term name="circa">circa</term>
15
+ <term name="circa" form="short">c.</term>
16
+ <term name="cited">cited</term>
17
+ <term name="edition">
18
+ <single>edition</single>
19
+ <multiple>editions</multiple>
20
+ </term>
21
+ </terms>
22
+ """
23
+ Then the nodename should be "terms"
24
+ And the node should have 9 terms
25
+ And the term number 1 should have the attribute "name" set to "accessed"
26
+ And the term number 2 should be a textnode
27
+ And the term number 9 should have the attribute "name" set to "edition"
28
+ And the term number 9 should not be a textnode
@@ -0,0 +1,34 @@
1
+ Given /^the(?: following)? locale:?$/ do |string|
2
+ @csl = CSL::Locale.load(string)
3
+ end
4
+
5
+ When /^I load the locale from the string$/ do |string|
6
+ @csl = CSL::Locale.load(string)
7
+ end
8
+
9
+ When /^I ordinalize the number (\d+)(?: using the (long) form(?: and (feminine|masculine) gender))?$/ do |num, form, gender|
10
+ @ordinal = @locale.ordinalize(num, :form => form, :gender => gender)
11
+ end
12
+
13
+ Then /^the ordinal should (?:be|equal) "([^"]*)"$/ do |ord|
14
+ @ordinal.should == ord
15
+ end
16
+
17
+ When /^I ordinalize these numbers:?$/ do |table|
18
+ @ordinals = table.rows.map do |row|
19
+ num, form, gender, number = *row
20
+ @csl.ordinalize(num, :form => form, :gender => gender, :number => number)
21
+ end
22
+ end
23
+
24
+ Then /^the ordinals should (?:be|equal):?$/ do |table|
25
+ @ordinals.join(' ').should == table.rows.flatten.join(' ')
26
+ end
27
+
28
+ Then /^the locale should should have (\d+) terms$/ do |num|
29
+ @csl.terms.length.should == num.to_i
30
+ end
31
+
32
+ Then /^the (\w+[\?!]?) of the term "([^"]*)" should be "([^"]*)"$/ do |method, name, expected|
33
+ @csl.terms.detect { |t| t.name == name }.send(method).should == expected
34
+ end
@@ -0,0 +1,28 @@
1
+
2
+ When /^I parse the CSL string(?: in the (\w+) scope)?$/ do |scope, string|
3
+ @csl = CSL.parse string, CSL.const_get(scope || 'Node')
4
+ end
5
+
6
+ Then /^(?:the )?(\w+[\?!]?) should be "([^"]*)"$/ do |name, expected|
7
+ @csl.send(name).to_s.should == expected
8
+ end
9
+
10
+ Then /^the (\w+) (\w+) should be "([^"]*)"$/ do |outer, inner, expected|
11
+ @csl.send(outer).send(inner).to_s.should == expected
12
+ end
13
+
14
+ Then /^the attribute "([^"]*)" should be "([^"]*)"$/ do |name, expected|
15
+ @csl[name.to_sym].should == expected
16
+ end
17
+
18
+ Then /^the node should have (\d+) (\w+)$/ do |length, name|
19
+ @csl.send(name).length.should == length.to_i
20
+ end
21
+
22
+ Then /^the (\w+) number (\d+) should have the attribute "([^"]*)" set to "([^"]*)"$/ do |name, offset, attribute, expected|
23
+ @csl.send("#{name}s")[offset.to_i - 1][attribute.to_sym].should == expected
24
+ end
25
+
26
+ Then /^the (\w+) number (\d+) should( not)? be a (\w+)$/ do |name, offset, negate, predicate|
27
+ @csl.send("#{name}s")[offset.to_i - 1].send("#{predicate}?").should == negate.nil?
28
+ end
@@ -0,0 +1,16 @@
1
+
2
+ When /^I load the style from the string$/ do |string|
3
+ @csl = CSL::Style.load string
4
+ end
5
+
6
+ Then /^the locale (\d+) should should have (\d+) terms?$/ do |locale, term|
7
+ @csl.locales[locale.to_i - 1].terms.length.should == term.to_i
8
+ end
9
+
10
+ Then /^the locale (\d+) (\w+\??) should be "([^"]*)"$/ do |locale, method, expected|
11
+ @csl.locales[locale.to_i - 1].send(method).to_s.should == expected
12
+ end
13
+
14
+ Then /^the style should have (\d+) contributors$/ do |num|
15
+ @csl.info.contributors.length.should == num.to_i
16
+ end
@@ -0,0 +1,53 @@
1
+ Feature: Loading CSL Style
2
+ As a hacker of CSL styles
3
+ I want to be able to parse CSL styles
4
+
5
+ Scenario: Loading a style from a string
6
+ When I load the style from the string
7
+ """
8
+ <?xml version="1.0" encoding="utf-8"?>
9
+ <style xmlns="http://purl.org/net/xbiblio/csl" class="in-text" version="1.0" demote-non-dropping-particle="never">
10
+ <info>
11
+ <title>American Psychological Association 6th Edition</title>
12
+ <id>http://www.zotero.org/styles/apa</id>
13
+ <link href="http://www.zotero.org/styles/apa" rel="self"/>
14
+ <link href="http://owl.english.purdue.edu/owl/resource/560/01/" rel="documentation"/>
15
+ <author>
16
+ <name>Simon Kornblith</name>
17
+ <email>simon@simonster.com</email>
18
+ </author>
19
+ <contributor>
20
+ <name>Bruce D'Arcus</name>
21
+ </contributor>
22
+ <contributor>
23
+ <name>Curtis M. Humphrey</name>
24
+ </contributor>
25
+ <contributor>
26
+ <name>Richard Karnesky</name>
27
+ <email>karnesky+zotero@gmail.com</email>
28
+ <uri>http://arc.nucapt.northwestern.edu/Richard_Karnesky</uri>
29
+ </contributor>
30
+ <contributor>
31
+ <name>Sebastian Karcher</name>
32
+ </contributor>
33
+ <category field="psychology"/>
34
+ <category field="generic-base"/>
35
+ <category citation-format="author-date"/>
36
+ <updated>2010-01-27T20:08:03+00:00</updated>
37
+ <rights>This work is licensed under a Creative Commons Attribution-Share Alike 3.0 License: http://creativecommons.org/licenses/by-sa/3.0/</rights>
38
+ </info>
39
+ <locale xml:lang="en">
40
+ <terms>
41
+ <term name="translator" form="short">
42
+ <single>trans.</single>
43
+ <multiple>trans.</multiple>
44
+ </term>
45
+ </terms>
46
+ </locale>
47
+ </style>
48
+ """
49
+ Then the info title should be "American Psychological Association 6th Edition"
50
+ And the locale 1 should should have 1 term
51
+ And the locale 1 language should be "en"
52
+ And the locale 1 region should be "US"
53
+ And the style should have 4 contributors
@@ -0,0 +1,8 @@
1
+ begin
2
+ require 'simplecov'
3
+ require 'debugger'
4
+ rescue LoadError
5
+ # ignore
6
+ end
7
+
8
+ require 'csl'
data/lib/csl.rb ADDED
@@ -0,0 +1,54 @@
1
+
2
+ require 'enumerator'
3
+ require 'forwardable'
4
+ require 'open-uri'
5
+ require 'singleton'
6
+ require 'set'
7
+
8
+ require 'csl/version'
9
+
10
+ require 'csl/compatibility'
11
+ require 'csl/extensions'
12
+ require 'csl/errors'
13
+
14
+ require 'csl/schema'
15
+
16
+ require 'csl/pretty_printer'
17
+ require 'csl/loader'
18
+ require 'csl/parser'
19
+ require 'csl/treelike'
20
+ require 'csl/node'
21
+
22
+ require 'csl/info'
23
+
24
+ require 'csl/locale'
25
+ require 'csl/locale/date'
26
+ require 'csl/locale/term'
27
+ require 'csl/locale/style_options'
28
+
29
+ require 'csl/style'
30
+ require 'csl/style/bibliography'
31
+ require 'csl/style/citation'
32
+ require 'csl/style/conditional'
33
+ require 'csl/style/date'
34
+ require 'csl/style/group'
35
+ require 'csl/style/label'
36
+ require 'csl/style/layout'
37
+ require 'csl/style/macro'
38
+ require 'csl/style/names'
39
+ require 'csl/style/number'
40
+ require 'csl/style/text'
41
+
42
+ module CSL
43
+
44
+ module_function
45
+
46
+ def parse(*arguments)
47
+ Parser.instance.parse(*arguments)
48
+ end
49
+
50
+ def parse!(*arguments)
51
+ Parser.instance.parse!(*arguments)
52
+ end
53
+
54
+ end
@@ -0,0 +1,19 @@
1
+
2
+ class Symbol
3
+ include Comparable
4
+
5
+ def <=>(other)
6
+ return unless other.kind_of? Symbol
7
+ to_s <=> other.to_s
8
+ end
9
+ end unless Symbol.is_a?(Comparable)
10
+
11
+ class Module
12
+ if RUBY_VERSION < '1.9'
13
+ alias const? const_defined?
14
+ else
15
+ def const?(name)
16
+ const_defined?(name, false)
17
+ end
18
+ end
19
+ end
data/lib/csl/errors.rb ADDED
@@ -0,0 +1,15 @@
1
+ module CSL
2
+
3
+ class Error < StandardError
4
+ attr_reader :original
5
+
6
+ def initialize(message, original = $!)
7
+ @original = original
8
+ super(message)
9
+ end
10
+ end
11
+
12
+ class ParseError < Error; end
13
+ class ValidationError < Error; end
14
+
15
+ end
@@ -0,0 +1,63 @@
1
+
2
+ # Some methods in this file are taken from ActiveSupport
3
+ # and are copyright (c) 2005-2010 David Heinemeier Hansson.
4
+ # They are loaded only if ActiveSupport is not present.
5
+
6
+ module CSL
7
+ module Extensions
8
+
9
+ # ActiveSupport Fallback
10
+ module SymbolizeKeys
11
+ def symbolize_keys
12
+ inject({}) do |options, (key, value)|
13
+ options[(key.to_sym rescue key) || key] = value
14
+ options
15
+ end
16
+ end
17
+
18
+ def symbolize_keys!
19
+ replace(symbolize_keys)
20
+ end
21
+
22
+ end
23
+
24
+ # ActiveSupport Fallback
25
+ module StringifyKeys
26
+ def stringify_keys
27
+ inject({}) do |options, (key, value)|
28
+ options[(key.to_s rescue key) || key] = value
29
+ options
30
+ end
31
+ end
32
+
33
+ def stringify_keys!
34
+ replace(symbolize_keys)
35
+ end
36
+ end
37
+
38
+ module Nesting
39
+ def nesting
40
+ name.split(/::/).inject([]) { |ns, n| ns << (ns[-1] || Object).const_get(n) }
41
+ end
42
+ end
43
+
44
+ module Blank
45
+ def blank?
46
+ nil? || respond_to?(:empty?) && empty?
47
+ end
48
+ end
49
+ end
50
+ end
51
+
52
+ class Hash
53
+ include CSL::Extensions::SymbolizeKeys unless method_defined?(:symbolize_keys)
54
+ include CSL::Extensions::StringifyKeys unless method_defined?(:stringify_keys)
55
+ end
56
+
57
+ class Module
58
+ include CSL::Extensions::Nesting
59
+ end
60
+
61
+ class Object
62
+ include CSL::Extensions::Blank unless method_defined?(:blank?)
63
+ end
data/lib/csl/info.rb ADDED
@@ -0,0 +1,40 @@
1
+ module CSL
2
+
3
+ class Info < Node
4
+
5
+ attr_children :author, :category, :contributor, :id, :issn, :eissn,
6
+ :issnl, :link, :published, :rights, :summary, :title, :'title-short',
7
+ :updated, :'link-dependent-style'
8
+
9
+ alias contributors contributor
10
+
11
+
12
+ class Contributor < Node
13
+ attr_children :name, :email, :uri
14
+ end
15
+
16
+ class Author < Node
17
+ attr_children :name, :email, :uri
18
+ end
19
+
20
+ class Translator < Node
21
+ attr_children :name, :email, :uri
22
+ end
23
+
24
+ class Link < TextNode
25
+ attr_struct :href, :rel
26
+ end
27
+
28
+ class DependentStyle < TextNode
29
+ attr_struct :href, :rel
30
+ end
31
+
32
+
33
+ class Category < TextNode
34
+ attr_struct :field, :'citation-format'
35
+ end
36
+
37
+ end
38
+
39
+
40
+ end
data/lib/csl/loader.rb ADDED
@@ -0,0 +1,78 @@
1
+ module CSL
2
+ #
3
+ # Mixin used by Locale and Style to load assets either from disk or from
4
+ # the network. Classes including the Loader module are expected to provide
5
+ # appropriate root, prefix and extension values and a parse method that
6
+ # will be passed the contents of the asset data.
7
+ #
8
+ module Loader
9
+
10
+ attr_accessor :root, :prefix, :extension
11
+
12
+ # call-seq:
13
+ # Style.load(:apa) -> style
14
+ # Style.load('chicago-author.csl') -> style
15
+ # Locale.load('en') -> locale
16
+ # Locale.load('http://example.com/de.xml') -> locale
17
+ #
18
+ # Resolves the passed-in path/name or string and loads the asset data.
19
+ # The data will be passed on to the #parse method of the base class.
20
+ # Typically, this will return a new instance of the class.
21
+ def load(input)
22
+ case
23
+ when input.respond_to?(:read)
24
+ data = input.read
25
+ when input.to_s =~ /^\s*</
26
+ data = input
27
+ else
28
+
29
+ case
30
+ when File.exists?(input)
31
+ location = input
32
+ when File.exists?(extend_name(input))
33
+ location = extend_name(input)
34
+ when File.exists?(extend_path(input))
35
+ location = extend_path(input)
36
+ else
37
+ location = input
38
+ end
39
+
40
+ Kernel.open(location, 'r:UTF-8') do |io|
41
+ data = io.read
42
+ end
43
+ end
44
+
45
+ parse(data)
46
+
47
+ rescue => e
48
+ raise ParseError, "failed to load #{input.inspect}: #{e.message}"
49
+ end
50
+
51
+ # Extends the passed-in string to a full path.
52
+ def extend_path(string)
53
+ File.join(root.to_s, extend_name(string))
54
+ end
55
+
56
+ # Extends the passed-in string to a style/locale name, by prefixing and
57
+ # appending the default name prefix and extension.
58
+ def extend_name(string)
59
+ if File.extname(string).empty?
60
+ name = [string, extension].compact.join
61
+ else
62
+ name = string.to_s.dup
63
+ end
64
+
65
+ unless name.start_with?(prefix.to_s)
66
+ name = [prefix, name].join
67
+ end
68
+
69
+ name
70
+ end
71
+
72
+ # The base class is exepcted to redefine the #parse method.
73
+ def parse(data)
74
+ raise 'Not Implemented'
75
+ end
76
+ end
77
+
78
+ end