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