citeproc-ruby 0.0.6 → 1.0.0
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.
- checksums.yaml +7 -0
- data/.coveralls.yml +1 -0
- data/.document +4 -0
- data/.gitignore +10 -0
- data/.rspec +3 -0
- data/.simplecov +4 -0
- data/.travis.yml +17 -0
- data/.yardopts +2 -0
- data/AGPL +662 -0
- data/BSDL +29 -0
- data/Gemfile +42 -0
- data/Guardfile +14 -0
- data/README.md +32 -76
- data/Rakefile +60 -0
- data/citeproc-ruby.gemspec +46 -0
- data/cucumber.yml +1 -0
- data/features/bibliography.feature +25 -0
- data/features/name_options.feature +37 -0
- data/features/names.feature +192 -0
- data/features/renderer.feature +74 -0
- data/features/sort.feature +50 -0
- data/features/step_definitions/renderer.rb +80 -0
- data/features/support/env.rb +33 -0
- data/features/support/hooks.rb +10 -0
- data/lib/citeproc/ruby.rb +32 -0
- data/lib/citeproc/ruby/engine.rb +122 -0
- data/lib/citeproc/ruby/format.rb +303 -0
- data/lib/citeproc/ruby/formats/default.rb +25 -0
- data/lib/citeproc/ruby/formats/html.rb +221 -0
- data/lib/citeproc/ruby/renderer.rb +140 -0
- data/lib/citeproc/ruby/renderer/choose.rb +106 -0
- data/lib/citeproc/ruby/renderer/date.rb +90 -0
- data/lib/citeproc/ruby/renderer/format.rb +129 -0
- data/lib/citeproc/ruby/renderer/group.rb +34 -0
- data/lib/citeproc/ruby/renderer/history.rb +40 -0
- data/lib/citeproc/ruby/renderer/label.rb +66 -0
- data/lib/citeproc/ruby/renderer/layout.rb +20 -0
- data/lib/citeproc/ruby/renderer/locale.rb +26 -0
- data/lib/citeproc/ruby/renderer/macro.rb +20 -0
- data/lib/citeproc/ruby/renderer/names.rb +401 -0
- data/lib/citeproc/ruby/renderer/number.rb +41 -0
- data/lib/citeproc/ruby/renderer/observer.rb +44 -0
- data/lib/citeproc/ruby/renderer/state.rb +96 -0
- data/lib/citeproc/ruby/renderer/text.rb +62 -0
- data/lib/citeproc/ruby/sort.rb +82 -0
- data/lib/citeproc/ruby/version.rb +5 -0
- data/spec/citeproc/ruby/engine_spec.rb +94 -0
- data/spec/citeproc/ruby/formats/default_spec.rb +159 -0
- data/spec/citeproc/ruby/formats/html_spec.rb +162 -0
- data/spec/citeproc/ruby/renderer/choose_spec.rb +293 -0
- data/spec/citeproc/ruby/renderer/date_spec.rb +173 -0
- data/spec/citeproc/ruby/renderer/group_spec.rb +88 -0
- data/spec/citeproc/ruby/renderer/history_spec.rb +38 -0
- data/spec/citeproc/ruby/renderer/label_spec.rb +225 -0
- data/spec/citeproc/ruby/renderer/layout_spec.rb +41 -0
- data/spec/citeproc/ruby/renderer/macro_spec.rb +31 -0
- data/spec/citeproc/ruby/renderer/names_spec.rb +396 -0
- data/spec/citeproc/ruby/renderer/number_spec.rb +120 -0
- data/spec/citeproc/ruby/renderer/text_spec.rb +120 -0
- data/spec/citeproc/ruby/renderer_spec.rb +65 -0
- data/spec/fixtures/items.rb +80 -0
- data/{resource/locale → spec/fixtures/locales}/locales-en-US.xml +2 -11
- data/{resource/locale → spec/fixtures/locales}/locales-fr-FR.xml +77 -66
- data/{resource/style → spec/fixtures/styles}/apa.csl +5 -5
- data/spec/spec_helper.rb +67 -14
- metadata +121 -211
- data/lib/citeproc.rb +0 -100
- data/lib/citeproc/bibliography.rb +0 -57
- data/lib/citeproc/data.rb +0 -149
- data/lib/citeproc/date.rb +0 -133
- data/lib/citeproc/formatter.rb +0 -38
- data/lib/citeproc/item.rb +0 -53
- data/lib/citeproc/name.rb +0 -284
- data/lib/citeproc/processor.rb +0 -166
- data/lib/citeproc/selector.rb +0 -61
- data/lib/citeproc/variable.rb +0 -82
- data/lib/citeproc/version.rb +0 -3
- data/lib/csl/locale.rb +0 -223
- data/lib/csl/node.rb +0 -72
- data/lib/csl/nodes.rb +0 -1418
- data/lib/csl/renderer.rb +0 -88
- data/lib/csl/sort.rb +0 -61
- data/lib/csl/style.rb +0 -110
- data/lib/csl/term.rb +0 -124
- data/lib/extensions/core.rb +0 -43
- data/lib/plugins/filters/bibtex.rb +0 -12
- data/lib/plugins/formats/default.rb +0 -134
- data/lib/plugins/formats/html.rb +0 -67
- data/lib/support/attributes.rb +0 -99
- data/lib/support/compatibility.rb +0 -83
- data/lib/support/tree.rb +0 -80
- data/resource/locale/locales-af-ZA.xml +0 -305
- data/resource/locale/locales-ar-AR.xml +0 -306
- data/resource/locale/locales-bg-BG.xml +0 -305
- data/resource/locale/locales-ca-AD.xml +0 -305
- data/resource/locale/locales-cs-CZ.xml +0 -305
- data/resource/locale/locales-da-DK.xml +0 -305
- data/resource/locale/locales-de-AT.xml +0 -304
- data/resource/locale/locales-de-CH.xml +0 -304
- data/resource/locale/locales-de-DE.xml +0 -332
- data/resource/locale/locales-el-GR.xml +0 -305
- data/resource/locale/locales-en-GB.xml +0 -304
- data/resource/locale/locales-es-ES.xml +0 -305
- data/resource/locale/locales-et-EE.xml +0 -304
- data/resource/locale/locales-eu.xml +0 -305
- data/resource/locale/locales-fa-IR.xml +0 -304
- data/resource/locale/locales-fi-FI.xml +0 -304
- data/resource/locale/locales-fr-CA.xml +0 -306
- data/resource/locale/locales-he-IL.xml +0 -304
- data/resource/locale/locales-hu-HU.xml +0 -305
- data/resource/locale/locales-is-IS.xml +0 -304
- data/resource/locale/locales-it-IT.xml +0 -305
- data/resource/locale/locales-ja-JP.xml +0 -305
- data/resource/locale/locales-kh-KH.xml +0 -303
- data/resource/locale/locales-km-KH.xml +0 -304
- data/resource/locale/locales-ko-KR.xml +0 -305
- data/resource/locale/locales-mn-MN.xml +0 -306
- data/resource/locale/locales-nb-NO.xml +0 -304
- data/resource/locale/locales-nl-NL.xml +0 -304
- data/resource/locale/locales-nn-NO.xml +0 -304
- data/resource/locale/locales-pl-PL.xml +0 -305
- data/resource/locale/locales-pt-BR.xml +0 -304
- data/resource/locale/locales-pt-PT.xml +0 -305
- data/resource/locale/locales-ro-RO.xml +0 -305
- data/resource/locale/locales-ru-RU.xml +0 -306
- data/resource/locale/locales-sk-SK.xml +0 -304
- data/resource/locale/locales-sl-SI.xml +0 -305
- data/resource/locale/locales-sr-RS.xml +0 -305
- data/resource/locale/locales-sv-SE.xml +0 -305
- data/resource/locale/locales-th-TH.xml +0 -304
- data/resource/locale/locales-tr-TR.xml +0 -305
- data/resource/locale/locales-uk-UA.xml +0 -306
- data/resource/locale/locales-vi-VN.xml +0 -305
- data/resource/locale/locales-zh-CN.xml +0 -304
- data/resource/locale/locales-zh-TW.xml +0 -305
- data/resource/schema/csl-categories.rnc +0 -39
- data/resource/schema/csl-data.rnc +0 -98
- data/resource/schema/csl-terms.rnc +0 -106
- data/resource/schema/csl-types.rnc +0 -39
- data/resource/schema/csl-variables.rnc +0 -182
- data/resource/schema/csl.rnc +0 -941
- data/resource/style/bibtex.csl +0 -177
- data/resource/style/chicago-annotated-bibliography.csl +0 -513
- data/resource/style/chicago-author-date-basque.csl +0 -707
- data/resource/style/chicago-author-date-de.csl +0 -394
- data/resource/style/chicago-author-date-listing.csl +0 -434
- data/resource/style/chicago-author-date.csl +0 -425
- data/resource/style/chicago-dated-note-biblio-no-ibid.csl +0 -472
- data/resource/style/chicago-fullnote-bibliography-bb.csl +0 -928
- data/resource/style/chicago-fullnote-bibliography-delimiter-fixes.csl +0 -972
- data/resource/style/chicago-fullnote-bibliography-no-ibid-delimiter-fixes.csl +0 -963
- data/resource/style/chicago-fullnote-bibliography-no-ibid.csl +0 -785
- data/resource/style/chicago-fullnote-bibliography.csl +0 -803
- data/resource/style/chicago-library-list.csl +0 -511
- data/resource/style/chicago-note-biblio-no-ibid.csl +0 -514
- data/resource/style/chicago-note-bibliography.csl +0 -530
- data/resource/style/chicago-note.csl +0 -388
- data/resource/style/chicago-quick-copy.csl +0 -685
- data/resource/style/ieee.csl +0 -299
- data/resource/style/mla-notes.csl +0 -796
- data/resource/style/mla-underline.csl +0 -175
- data/resource/style/mla-url.csl +0 -214
- data/resource/style/mla.csl +0 -394
- data/resource/style/vancouver-brackets.csl +0 -256
- data/resource/style/vancouver-superscript-bracket-only-year.csl +0 -165
- data/resource/style/vancouver-superscript.csl +0 -256
- data/resource/style/vancouver.csl +0 -256
- data/spec/citeproc/bibliography_spec.rb +0 -45
- data/spec/citeproc/citeproc_spec.rb +0 -80
- data/spec/citeproc/date_spec.rb +0 -89
- data/spec/citeproc/formatter_spec.rb +0 -101
- data/spec/citeproc/item_spec.rb +0 -71
- data/spec/citeproc/name_spec.rb +0 -30
- data/spec/citeproc/processor_spec.rb +0 -61
- data/spec/citeproc/selector_spec.rb +0 -82
- data/spec/citeproc/variable_spec.rb +0 -69
- data/spec/csl/locale_spec.rb +0 -208
- data/spec/csl/node_spec.rb +0 -25
- data/spec/csl/nodes_spec.rb +0 -145
- data/spec/csl/style_spec.rb +0 -62
- data/spec/csl/term_spec.rb +0 -56
- data/spec/fixtures/dates.yaml +0 -80
- data/spec/fixtures/names.yaml +0 -115
- data/spec/fixtures/nodes.yaml +0 -245
- data/spec/support/attributes_spec.rb +0 -39
- data/spec/support/tree_spec.rb +0 -163
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
Feature: Rendering CSL nodes
|
|
2
|
+
As a hacker of cite processors
|
|
3
|
+
I want to render citation items
|
|
4
|
+
With selected CSL nodes
|
|
5
|
+
|
|
6
|
+
Scenario: Simple Date Rendering
|
|
7
|
+
Given the following style node:
|
|
8
|
+
"""
|
|
9
|
+
<date variable="issued">
|
|
10
|
+
<date-part name="year"/>
|
|
11
|
+
</date>
|
|
12
|
+
"""
|
|
13
|
+
When I render the following citation items as "text":
|
|
14
|
+
| issued |
|
|
15
|
+
| November 7, 2006 |
|
|
16
|
+
| 2014-01-01 |
|
|
17
|
+
| 1999 |
|
|
18
|
+
Then the results should be:
|
|
19
|
+
| 2006 |
|
|
20
|
+
| 2014 |
|
|
21
|
+
| 1999 |
|
|
22
|
+
|
|
23
|
+
Scenario: Date Group Rendering
|
|
24
|
+
Given the following style node:
|
|
25
|
+
"""
|
|
26
|
+
<group prefix="(" suffix=").">
|
|
27
|
+
<date variable="issued">
|
|
28
|
+
<date-part name="year"/>
|
|
29
|
+
</date>
|
|
30
|
+
<text variable="year-suffix"/>
|
|
31
|
+
</group>
|
|
32
|
+
"""
|
|
33
|
+
When I render the following citation items as "text":
|
|
34
|
+
| issued | year-suffix |
|
|
35
|
+
| November 7, 2006 | |
|
|
36
|
+
| 2014-01-01 | |
|
|
37
|
+
| 1999 | a |
|
|
38
|
+
Then the results should be:
|
|
39
|
+
| (2006). |
|
|
40
|
+
| (2014). |
|
|
41
|
+
| (1999a). |
|
|
42
|
+
|
|
43
|
+
@html @formatting
|
|
44
|
+
Scenario: Formatted Groups
|
|
45
|
+
Given the following style node:
|
|
46
|
+
"""
|
|
47
|
+
<group>
|
|
48
|
+
<group suffix=" " font-weight="bold">
|
|
49
|
+
<!--group formatting is pushed down-->
|
|
50
|
+
<text variable="volume" suffix=","/>
|
|
51
|
+
</group>
|
|
52
|
+
<text variable="page" suffix="," font-weight="bold"/>
|
|
53
|
+
</group>
|
|
54
|
+
"""
|
|
55
|
+
When I render the following citation item as "html":
|
|
56
|
+
| volume | 5 |
|
|
57
|
+
| page | 23 |
|
|
58
|
+
Then the result should be: <b>5</b>, <b>23</b>,
|
|
59
|
+
|
|
60
|
+
Scenario: Page labels
|
|
61
|
+
Given the following style node:
|
|
62
|
+
"""
|
|
63
|
+
<label variable="page"/>
|
|
64
|
+
"""
|
|
65
|
+
When I render the following citation items as "text":
|
|
66
|
+
| page |
|
|
67
|
+
| 23 |
|
|
68
|
+
| |
|
|
69
|
+
| 23, 34 |
|
|
70
|
+
Then the results should be:
|
|
71
|
+
| page |
|
|
72
|
+
| |
|
|
73
|
+
| pages |
|
|
74
|
+
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
Feature: Sorting
|
|
2
|
+
As a hacker of cite processors
|
|
3
|
+
I want to sort citation items
|
|
4
|
+
According to the rules of a CSL style
|
|
5
|
+
|
|
6
|
+
Scenario: Name sorting
|
|
7
|
+
Given the following sort keys:
|
|
8
|
+
"""
|
|
9
|
+
<sort>
|
|
10
|
+
<key variable="author"/>
|
|
11
|
+
</sort>
|
|
12
|
+
"""
|
|
13
|
+
When I sort the following items:
|
|
14
|
+
| author |
|
|
15
|
+
| Edelweis |
|
|
16
|
+
| ANZ-Group |
|
|
17
|
+
| Aardvaark |
|
|
18
|
+
Then the order should be:
|
|
19
|
+
| ID-2 |
|
|
20
|
+
| ID-1 |
|
|
21
|
+
| ID-0 |
|
|
22
|
+
|
|
23
|
+
Scenario: Name sorting macros
|
|
24
|
+
Given the following sort keys:
|
|
25
|
+
"""
|
|
26
|
+
<sort>
|
|
27
|
+
<key macro="author"/>
|
|
28
|
+
</sort>
|
|
29
|
+
"""
|
|
30
|
+
And the following macro:
|
|
31
|
+
"""
|
|
32
|
+
<macro name="author">
|
|
33
|
+
<names variable="author">
|
|
34
|
+
<name name-as-sort-order="all" and="symbol" sort-separator=", "
|
|
35
|
+
initialize-with="." delimiter-precedes-last="never" delimiter=", "/>
|
|
36
|
+
<label form="short" prefix=" (" suffix=".)" text-case="capitalize-first"/>
|
|
37
|
+
<substitute>
|
|
38
|
+
<names variable="editor"/>
|
|
39
|
+
<text value="Anon"/>
|
|
40
|
+
</substitute>
|
|
41
|
+
</names>
|
|
42
|
+
</macro>
|
|
43
|
+
"""
|
|
44
|
+
When I sort the following items:
|
|
45
|
+
| author |
|
|
46
|
+
| ABC |
|
|
47
|
+
| Aaa |
|
|
48
|
+
Then the order should be:
|
|
49
|
+
| ID-1 |
|
|
50
|
+
| ID-0 |
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
|
|
2
|
+
Given(/^the "(.*?)" style's (bibliography|citation) node$/) do |style, mode|
|
|
3
|
+
@node = CSL::Style.load(style).send(mode).layout
|
|
4
|
+
end
|
|
5
|
+
|
|
6
|
+
Given(/^the following style node:$/) do |string|
|
|
7
|
+
@node = CSL.parse!(string, CSL::Style)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
Given(/^the following sort keys:$/) do |string|
|
|
11
|
+
@sort = CSL.parse!(string, CSL::Style)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
Given(/^the following macro:$/) do |string|
|
|
15
|
+
@macro = CSL.parse!(string, CSL::Style)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
When(/^I render the following citation items as "(.*?)":$/) do |format, items|
|
|
19
|
+
r = CiteProc::Ruby::Renderer.new(:format => format)
|
|
20
|
+
|
|
21
|
+
@results = items.hashes.map.with_index do |data, idx|
|
|
22
|
+
i = CiteProc::CitationItem.new(:id => "ID-#{idx}")
|
|
23
|
+
|
|
24
|
+
data[:id] = "ID-#{idx}"
|
|
25
|
+
i.data = CiteProc::Item.new(data)
|
|
26
|
+
|
|
27
|
+
r.render i, @node
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
When(/^I render the following citation item as "(.*?)":$/) do |format, item|
|
|
32
|
+
r = CiteProc::Ruby::Renderer.new(:format => format)
|
|
33
|
+
|
|
34
|
+
i = CiteProc::CitationItem.new(:id => 'ID-1')
|
|
35
|
+
i.data = CiteProc::Item.new(item.rows_hash.merge(:id => 'ID-1'))
|
|
36
|
+
|
|
37
|
+
@result = r.render i, @node
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
When(/^I sort the following items:$/) do |items|
|
|
41
|
+
engine = CiteProc::Ruby::Engine.new
|
|
42
|
+
|
|
43
|
+
@order = items.hashes.map.with_index do |data, idx|
|
|
44
|
+
data[:id] = "ID-#{idx}"
|
|
45
|
+
CiteProc::Item.new(data)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
unless @macro.nil?
|
|
49
|
+
@sort.each_child do |key|
|
|
50
|
+
key.stub(:macro).and_return(@macro)
|
|
51
|
+
key.stub(:macro?).and_return(true)
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
engine.sort! @order, @sort.children
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
Then(/^the results should be:$/) do |expected|
|
|
59
|
+
expected = expected.raw.map(&:first)
|
|
60
|
+
|
|
61
|
+
@results.length.should == expected.length
|
|
62
|
+
|
|
63
|
+
@results.zip(expected).each do |result, expectation|
|
|
64
|
+
result.should == expectation
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
Then(/^the result should be: (.*)$/) do |expected|
|
|
69
|
+
@result.should == expected
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
Then(/^the order should be:$/) do |expected|
|
|
73
|
+
expected = expected.raw.map(&:first)
|
|
74
|
+
|
|
75
|
+
@order.length.should == expected.length
|
|
76
|
+
|
|
77
|
+
@order.zip(expected).each do |order, expectation|
|
|
78
|
+
order['id'].should == expectation
|
|
79
|
+
end
|
|
80
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
begin
|
|
2
|
+
require 'simplecov'
|
|
3
|
+
require 'coveralls' if ENV['CI']
|
|
4
|
+
rescue LoadError
|
|
5
|
+
# ignore
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
begin
|
|
9
|
+
case
|
|
10
|
+
when RUBY_PLATFORM < 'java'
|
|
11
|
+
require 'debug'
|
|
12
|
+
Debugger.start
|
|
13
|
+
when defined?(RUBY_ENGINE) && RUBY_ENGINE == 'rbx'
|
|
14
|
+
require 'rubinius/debugger'
|
|
15
|
+
else
|
|
16
|
+
require 'debugger'
|
|
17
|
+
end
|
|
18
|
+
rescue LoadError
|
|
19
|
+
# ignore
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
require 'cucumber/rspec/doubles'
|
|
23
|
+
require 'citeproc/ruby'
|
|
24
|
+
|
|
25
|
+
module Fixtures
|
|
26
|
+
PATH = File.expand_path('../../../spec/fixtures', __FILE__)
|
|
27
|
+
|
|
28
|
+
Dir[File.join(PATH, '*.rb')].each do |fixture|
|
|
29
|
+
require fixture
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
World(Fixtures)
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
Before do
|
|
2
|
+
@style_root, @locale_root = CSL::Style.root, CSL::Locale.root
|
|
3
|
+
|
|
4
|
+
CSL::Style.root = File.join(Fixtures::PATH, 'styles')
|
|
5
|
+
CSL::Locale.root = File.join(Fixtures::PATH, 'locales')
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
After do
|
|
9
|
+
CSL::Style.root, CSL::Locale.root = @style_root, @locale_root
|
|
10
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
require 'observer'
|
|
2
|
+
|
|
3
|
+
require 'csl'
|
|
4
|
+
require 'citeproc'
|
|
5
|
+
|
|
6
|
+
require 'citeproc/ruby/version'
|
|
7
|
+
|
|
8
|
+
require 'citeproc/ruby/format'
|
|
9
|
+
|
|
10
|
+
require 'citeproc/ruby/formats/default'
|
|
11
|
+
require 'citeproc/ruby/formats/html'
|
|
12
|
+
|
|
13
|
+
require 'citeproc/ruby/renderer'
|
|
14
|
+
|
|
15
|
+
require 'citeproc/ruby/renderer/locale'
|
|
16
|
+
require 'citeproc/ruby/renderer/format'
|
|
17
|
+
require 'citeproc/ruby/renderer/observer'
|
|
18
|
+
require 'citeproc/ruby/renderer/state'
|
|
19
|
+
require 'citeproc/ruby/renderer/history'
|
|
20
|
+
|
|
21
|
+
require 'citeproc/ruby/renderer/text'
|
|
22
|
+
require 'citeproc/ruby/renderer/number'
|
|
23
|
+
require 'citeproc/ruby/renderer/label'
|
|
24
|
+
require 'citeproc/ruby/renderer/date'
|
|
25
|
+
require 'citeproc/ruby/renderer/names'
|
|
26
|
+
require 'citeproc/ruby/renderer/layout'
|
|
27
|
+
require 'citeproc/ruby/renderer/macro'
|
|
28
|
+
require 'citeproc/ruby/renderer/group'
|
|
29
|
+
require 'citeproc/ruby/renderer/choose'
|
|
30
|
+
|
|
31
|
+
require 'citeproc/ruby/sort.rb'
|
|
32
|
+
require 'citeproc/ruby/engine.rb'
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
module CiteProc
|
|
2
|
+
module Ruby
|
|
3
|
+
|
|
4
|
+
class Engine < CiteProc::Engine
|
|
5
|
+
|
|
6
|
+
include SortItems
|
|
7
|
+
|
|
8
|
+
@name = 'citeproc-ruby'.freeze
|
|
9
|
+
@type = 'CSL'.freeze
|
|
10
|
+
@version = CSL::Schema.version
|
|
11
|
+
@priority = 1
|
|
12
|
+
|
|
13
|
+
attr_reader :renderer, :style
|
|
14
|
+
|
|
15
|
+
def_delegators :renderer,
|
|
16
|
+
:format, :format=, :locale, :locale=
|
|
17
|
+
|
|
18
|
+
def initialize(*arguments)
|
|
19
|
+
super(*arguments)
|
|
20
|
+
@renderer = Renderer.new(self)
|
|
21
|
+
|
|
22
|
+
update! unless processor.nil?
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def style=(new_style)
|
|
26
|
+
@style = CSL::Style.load new_style
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def process(data)
|
|
30
|
+
node = style.citation
|
|
31
|
+
|
|
32
|
+
return unless node
|
|
33
|
+
return '' if data.empty?
|
|
34
|
+
|
|
35
|
+
# populate item data
|
|
36
|
+
data.each do |item|
|
|
37
|
+
item.data = processor[item.id].dup
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# TODO implement sort in citation data
|
|
41
|
+
sort!(data, node.sort_keys) unless !node.sort?
|
|
42
|
+
|
|
43
|
+
# TODO citation number (after sorting?)
|
|
44
|
+
|
|
45
|
+
renderer.render_citation data, node
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def append
|
|
49
|
+
raise NotImplementedByEngine
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def bibliography(selector)
|
|
53
|
+
node = style.bibliography
|
|
54
|
+
return unless node
|
|
55
|
+
|
|
56
|
+
selection = processor.data.select do |item|
|
|
57
|
+
selector.matches?(item) && !selector.skip?(item)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
sort!(selection, node.sort_keys) unless selection.empty? || !node.sort?
|
|
61
|
+
|
|
62
|
+
Bibliography.new(node.bibliography_options) do |bib|
|
|
63
|
+
format.bibliography(bib)
|
|
64
|
+
|
|
65
|
+
idx = 1
|
|
66
|
+
|
|
67
|
+
selection.each do |item|
|
|
68
|
+
begin
|
|
69
|
+
bib.push item.id, renderer.render_bibliography(item.cite(idx), node)
|
|
70
|
+
rescue => error
|
|
71
|
+
bib.errors << [item.id.to_s, error]
|
|
72
|
+
ensure
|
|
73
|
+
idx += 1 unless error
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def update_items
|
|
80
|
+
raise NotImplementedByEngine
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def update_uncited_items
|
|
84
|
+
raise NotImplementedByEngine
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# @return [String, Array<String>]
|
|
88
|
+
def render(mode, data)
|
|
89
|
+
case mode
|
|
90
|
+
when :bibliography
|
|
91
|
+
node = style.bibliography
|
|
92
|
+
|
|
93
|
+
data.map do |item|
|
|
94
|
+
item.data = processor[item.id].dup
|
|
95
|
+
renderer.render item, node
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
when :citation
|
|
99
|
+
node = style.citation
|
|
100
|
+
|
|
101
|
+
data.each do |item|
|
|
102
|
+
item.data = processor[item.id].dup
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
renderer.render_citation data, node
|
|
106
|
+
|
|
107
|
+
else
|
|
108
|
+
raise ArgumentError, "cannot render unknown mode: #{mode.inspect}"
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def update!
|
|
114
|
+
renderer.format = processor.options[:format]
|
|
115
|
+
renderer.locale = processor.options[:locale]
|
|
116
|
+
|
|
117
|
+
@style = CSL::Style.load processor.options[:style]
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
module CiteProc
|
|
4
|
+
module Ruby
|
|
5
|
+
|
|
6
|
+
class Format
|
|
7
|
+
|
|
8
|
+
@available = []
|
|
9
|
+
|
|
10
|
+
@squeezable = /^[\s\.,:;!?\)\(\[\]]+$/
|
|
11
|
+
|
|
12
|
+
@stopwords = {
|
|
13
|
+
:en => [
|
|
14
|
+
'about', 'above', 'across', 'afore', 'after', 'against', 'along',
|
|
15
|
+
'alongside', 'amid', 'amidst', 'among', 'amongst', 'anenst', 'apropos',
|
|
16
|
+
'apud', 'around', 'as', 'aside', 'astride', 'at', 'athwart', 'atop',
|
|
17
|
+
'barring', 'before', 'behind', 'below', 'beneath', 'beside', 'besides',
|
|
18
|
+
'between', 'beyond', 'but', 'by', 'circa', 'despite', 'd', 'down', 'during',
|
|
19
|
+
'except', 'for', 'forenenst', 'from', 'given', 'in', 'inside', 'into',
|
|
20
|
+
'lest', 'like', 'modulo' 'near', 'next', 'notwithstanding', 'of', 'off',
|
|
21
|
+
'on', 'onto', 'out', 'over', 'per', 'plus', 'pro', 'qua', 'sans', 'since',
|
|
22
|
+
'than', 'through', 'thru', 'throughout', 'thruout', 'till', 'to', 'toward',
|
|
23
|
+
'towards', 'under', 'underneath', 'until', 'unto', 'up', 'upon', 'versus',
|
|
24
|
+
'vs', 'v', 'via', 'vis-à-vis', 'with', 'within', 'without'
|
|
25
|
+
]
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
class << self
|
|
29
|
+
attr_reader :available, :stopwords
|
|
30
|
+
|
|
31
|
+
def inherited(base)
|
|
32
|
+
Format.available << base
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def load(name = nil)
|
|
36
|
+
return new unless name
|
|
37
|
+
return name if name.is_a?(Format)
|
|
38
|
+
|
|
39
|
+
name = name.to_s.downcase
|
|
40
|
+
|
|
41
|
+
klass = available.detect do |format|
|
|
42
|
+
format.name.split('::')[-1].downcase == name
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
raise(Error, "unknown format: #{name}") unless klass
|
|
46
|
+
|
|
47
|
+
klass.new
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def stopword?(word, locale = :en)
|
|
51
|
+
return unless stopwords.key?(locale)
|
|
52
|
+
stopwords[locale].include?(word.downcase)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def squeezable?(string)
|
|
56
|
+
squeezable === string
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def squeezable
|
|
60
|
+
@squeezable ||= Format.squeezable
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
attr_reader :locale
|
|
65
|
+
|
|
66
|
+
def keys
|
|
67
|
+
@keys ||= (CSL::Schema.attr(:formatting) - [:prefix, :suffix, :display])
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def squeezable?(string)
|
|
71
|
+
self.class.squeezable?(string)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def squeeze_suffix(string, suffix)
|
|
75
|
+
raise ArgumentError unless string.is_a?(::String)
|
|
76
|
+
raise ArgumentError unless suffix.is_a?(::String)
|
|
77
|
+
|
|
78
|
+
return string.dup if suffix.empty?
|
|
79
|
+
return suffix.dup if string.empty?
|
|
80
|
+
|
|
81
|
+
string, stripped = strip(string)
|
|
82
|
+
string, quotes = split_closing_quotes(string)
|
|
83
|
+
|
|
84
|
+
suffix = decode_entities(suffix)
|
|
85
|
+
|
|
86
|
+
suffix = suffix.each_char.drop_while.with_index { |c, i|
|
|
87
|
+
squeezable?(c) && string.end_with?(suffix[0, i + 1])
|
|
88
|
+
}.join('')
|
|
89
|
+
|
|
90
|
+
# Handle special cases like ?. or ;.
|
|
91
|
+
if suffix.start_with?('.') && string.end_with?(';', ',', '!', '?', ':')
|
|
92
|
+
suffix = suffix[1..-1]
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# Handle special cases ;, and :,
|
|
96
|
+
if suffix.start_with?(',') && string.end_with?(';', ':')
|
|
97
|
+
suffix = suffix[1..-1]
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# Handle special cases ,; and :;
|
|
101
|
+
if suffix.start_with?(';') && string.end_with?(',', ':')
|
|
102
|
+
suffix = suffix[1..-1]
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# Handle punctiation-in-quote
|
|
106
|
+
if !quotes.nil? && punctuation_in_quotes?
|
|
107
|
+
if suffix.sub!(/^([\.,])/, '')
|
|
108
|
+
punctuation = ($1).to_s
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
"#{string}#{punctuation}#{quotes}#{stripped}#{suffix}"
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def squeeze_prefix(string, prefix)
|
|
116
|
+
raise ArgumentError unless string.is_a?(::String)
|
|
117
|
+
raise ArgumentError unless prefix.is_a?(::String)
|
|
118
|
+
|
|
119
|
+
prefix = prefix.reverse.each_char.drop_while.with_index { |c, i|
|
|
120
|
+
squeezable?(c) && string.start_with?(prefix[-(i + 1) .. -1])
|
|
121
|
+
}.join('').reverse
|
|
122
|
+
|
|
123
|
+
"#{prefix}#{string}"
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
alias concat squeeze_suffix
|
|
127
|
+
|
|
128
|
+
def join(list, delimiter = nil)
|
|
129
|
+
raise ArgumentError unless list.is_a?(Enumerable)
|
|
130
|
+
return '' if list.length.zero?
|
|
131
|
+
return list[0] if list.length == 1
|
|
132
|
+
|
|
133
|
+
if delimiter.nil? || delimiter.empty?
|
|
134
|
+
list.inject do |m, n|
|
|
135
|
+
concat(m, n)
|
|
136
|
+
end
|
|
137
|
+
else
|
|
138
|
+
list.inject do |m, n|
|
|
139
|
+
concat(concat(m, delimiter), n)
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def bibliography(bibliography, locale = nil)
|
|
145
|
+
bibliography.connector = "\n" * bibliography.entry_spacing
|
|
146
|
+
bibliography
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def apply(input, node, locale = nil)
|
|
150
|
+
return '' if input.nil?
|
|
151
|
+
return input if input.empty? || node.nil?
|
|
152
|
+
|
|
153
|
+
return ArgumentError unless node.respond_to?(:formatting_options)
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
@input, @output, @node, @locale = input, input.dup, node, locale
|
|
157
|
+
|
|
158
|
+
setup!
|
|
159
|
+
|
|
160
|
+
# NB: Layout nodes apply formatting to
|
|
161
|
+
# affixes; all other nodes do not!
|
|
162
|
+
if node.is_a? CSL::Style::Layout
|
|
163
|
+
apply_prefix if options.key?(:prefix)
|
|
164
|
+
apply_suffix if options.key?(:suffix)
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
keys.each do |format|
|
|
168
|
+
if options.key?(format)
|
|
169
|
+
method = "apply_#{format}".tr('-', '_')
|
|
170
|
+
send method if respond_to?(method)
|
|
171
|
+
end
|
|
172
|
+
end unless options.empty?
|
|
173
|
+
|
|
174
|
+
output.gsub!(/\.+/, '') if node.strip_periods?
|
|
175
|
+
|
|
176
|
+
apply_quotes if node.quotes? && !locale.nil?
|
|
177
|
+
|
|
178
|
+
finalize_content!
|
|
179
|
+
|
|
180
|
+
unless node.is_a? CSL::Style::Layout
|
|
181
|
+
apply_prefix if options.key?(:prefix)
|
|
182
|
+
apply_suffix if options.key?(:suffix)
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
apply_display if options.key?(:display)
|
|
186
|
+
|
|
187
|
+
finalize!
|
|
188
|
+
|
|
189
|
+
output
|
|
190
|
+
ensure
|
|
191
|
+
cleanup!
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
def escape_quotes?
|
|
195
|
+
false
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
def close_quote
|
|
199
|
+
locale && locale.t('close-quote') || '"'
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
def close_inner_quote
|
|
203
|
+
locale && locale.t('close-inner-quote') || "'"
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
def split_closing_quotes(string)
|
|
207
|
+
string.split(/([#{close_inner_quote}#{close_quote}]+)$/, 2)
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
def apply_quotes
|
|
211
|
+
output.replace locale.quote(output, escape_quotes?)
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
def apply_text_case
|
|
215
|
+
case options[:'text-case']
|
|
216
|
+
when 'lowercase'
|
|
217
|
+
output.replace CiteProc.downcase output
|
|
218
|
+
|
|
219
|
+
when 'uppercase'
|
|
220
|
+
output.replace CiteProc.upcase output
|
|
221
|
+
|
|
222
|
+
when 'capitalize-first'
|
|
223
|
+
output.sub!(/^([^\p{L}]*)(\p{Ll})/) { "#{$1}#{CiteProc.upcase($2)}" }
|
|
224
|
+
|
|
225
|
+
when 'capitalize-all'
|
|
226
|
+
output.gsub!(/\b(\p{Ll})/) { CiteProc.upcase($1) }
|
|
227
|
+
|
|
228
|
+
when 'sentence'
|
|
229
|
+
output.sub!(/^([^\p{L}]*)(\p{Ll})/) { "#{$1}#{CiteProc.upcase($2)}" }
|
|
230
|
+
output.gsub!(/\b(\p{Lu})(\p{Lu}+)\b/) { "#{$1}#{CiteProc.downcase($2)}" }
|
|
231
|
+
|
|
232
|
+
when 'title'
|
|
233
|
+
return if locale && locale.language != :en
|
|
234
|
+
|
|
235
|
+
# TODO add support for stop words consisting of multiple words
|
|
236
|
+
#output.gsub!(/\b(\p{Lu})(\p{Lu}+)\b/) { "#{$1}#{CiteProc.downcase($2)}" }
|
|
237
|
+
|
|
238
|
+
# TODO exceptions: first, last word; followed by colon
|
|
239
|
+
output.gsub!(/\b(\p{Ll})(\p{L}+)\b/) do |word|
|
|
240
|
+
if Format.stopword?(word)
|
|
241
|
+
word
|
|
242
|
+
else
|
|
243
|
+
"#{CiteProc.upcase($1)}#{$2}"
|
|
244
|
+
end
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
end
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
def punctuation_in_quotes?
|
|
251
|
+
!locale.nil? && locale.punctuation_in_quotes?
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
def apply_prefix
|
|
255
|
+
output.replace(squeeze_prefix(output, prefix))
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
def apply_suffix
|
|
259
|
+
output.replace(squeeze_suffix(output, suffix))
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
def prefix
|
|
263
|
+
options[:prefix].to_s
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
def suffix
|
|
267
|
+
options[:suffix].to_s
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
def strip(string)
|
|
271
|
+
string
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
protected
|
|
275
|
+
|
|
276
|
+
attr_reader :input, :output, :node
|
|
277
|
+
|
|
278
|
+
def options
|
|
279
|
+
@options ||= @node.formatting_options
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
def finalize!
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
def finalize_content!
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
def setup!
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
def decode_entities(string)
|
|
292
|
+
string.gsub(/&#x([0-9a-f]);/i) do
|
|
293
|
+
[Integer("0x#{$1}")].pack('U')
|
|
294
|
+
end
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
def cleanup!
|
|
298
|
+
@input, @output, @node, @options = nil
|
|
299
|
+
end
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
end
|
|
303
|
+
end
|