citeproc-ruby 0.0.6 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (186) hide show
  1. checksums.yaml +7 -0
  2. data/.coveralls.yml +1 -0
  3. data/.document +4 -0
  4. data/.gitignore +10 -0
  5. data/.rspec +3 -0
  6. data/.simplecov +4 -0
  7. data/.travis.yml +17 -0
  8. data/.yardopts +2 -0
  9. data/AGPL +662 -0
  10. data/BSDL +29 -0
  11. data/Gemfile +42 -0
  12. data/Guardfile +14 -0
  13. data/README.md +32 -76
  14. data/Rakefile +60 -0
  15. data/citeproc-ruby.gemspec +46 -0
  16. data/cucumber.yml +1 -0
  17. data/features/bibliography.feature +25 -0
  18. data/features/name_options.feature +37 -0
  19. data/features/names.feature +192 -0
  20. data/features/renderer.feature +74 -0
  21. data/features/sort.feature +50 -0
  22. data/features/step_definitions/renderer.rb +80 -0
  23. data/features/support/env.rb +33 -0
  24. data/features/support/hooks.rb +10 -0
  25. data/lib/citeproc/ruby.rb +32 -0
  26. data/lib/citeproc/ruby/engine.rb +122 -0
  27. data/lib/citeproc/ruby/format.rb +303 -0
  28. data/lib/citeproc/ruby/formats/default.rb +25 -0
  29. data/lib/citeproc/ruby/formats/html.rb +221 -0
  30. data/lib/citeproc/ruby/renderer.rb +140 -0
  31. data/lib/citeproc/ruby/renderer/choose.rb +106 -0
  32. data/lib/citeproc/ruby/renderer/date.rb +90 -0
  33. data/lib/citeproc/ruby/renderer/format.rb +129 -0
  34. data/lib/citeproc/ruby/renderer/group.rb +34 -0
  35. data/lib/citeproc/ruby/renderer/history.rb +40 -0
  36. data/lib/citeproc/ruby/renderer/label.rb +66 -0
  37. data/lib/citeproc/ruby/renderer/layout.rb +20 -0
  38. data/lib/citeproc/ruby/renderer/locale.rb +26 -0
  39. data/lib/citeproc/ruby/renderer/macro.rb +20 -0
  40. data/lib/citeproc/ruby/renderer/names.rb +401 -0
  41. data/lib/citeproc/ruby/renderer/number.rb +41 -0
  42. data/lib/citeproc/ruby/renderer/observer.rb +44 -0
  43. data/lib/citeproc/ruby/renderer/state.rb +96 -0
  44. data/lib/citeproc/ruby/renderer/text.rb +62 -0
  45. data/lib/citeproc/ruby/sort.rb +82 -0
  46. data/lib/citeproc/ruby/version.rb +5 -0
  47. data/spec/citeproc/ruby/engine_spec.rb +94 -0
  48. data/spec/citeproc/ruby/formats/default_spec.rb +159 -0
  49. data/spec/citeproc/ruby/formats/html_spec.rb +162 -0
  50. data/spec/citeproc/ruby/renderer/choose_spec.rb +293 -0
  51. data/spec/citeproc/ruby/renderer/date_spec.rb +173 -0
  52. data/spec/citeproc/ruby/renderer/group_spec.rb +88 -0
  53. data/spec/citeproc/ruby/renderer/history_spec.rb +38 -0
  54. data/spec/citeproc/ruby/renderer/label_spec.rb +225 -0
  55. data/spec/citeproc/ruby/renderer/layout_spec.rb +41 -0
  56. data/spec/citeproc/ruby/renderer/macro_spec.rb +31 -0
  57. data/spec/citeproc/ruby/renderer/names_spec.rb +396 -0
  58. data/spec/citeproc/ruby/renderer/number_spec.rb +120 -0
  59. data/spec/citeproc/ruby/renderer/text_spec.rb +120 -0
  60. data/spec/citeproc/ruby/renderer_spec.rb +65 -0
  61. data/spec/fixtures/items.rb +80 -0
  62. data/{resource/locale → spec/fixtures/locales}/locales-en-US.xml +2 -11
  63. data/{resource/locale → spec/fixtures/locales}/locales-fr-FR.xml +77 -66
  64. data/{resource/style → spec/fixtures/styles}/apa.csl +5 -5
  65. data/spec/spec_helper.rb +67 -14
  66. metadata +121 -211
  67. data/lib/citeproc.rb +0 -100
  68. data/lib/citeproc/bibliography.rb +0 -57
  69. data/lib/citeproc/data.rb +0 -149
  70. data/lib/citeproc/date.rb +0 -133
  71. data/lib/citeproc/formatter.rb +0 -38
  72. data/lib/citeproc/item.rb +0 -53
  73. data/lib/citeproc/name.rb +0 -284
  74. data/lib/citeproc/processor.rb +0 -166
  75. data/lib/citeproc/selector.rb +0 -61
  76. data/lib/citeproc/variable.rb +0 -82
  77. data/lib/citeproc/version.rb +0 -3
  78. data/lib/csl/locale.rb +0 -223
  79. data/lib/csl/node.rb +0 -72
  80. data/lib/csl/nodes.rb +0 -1418
  81. data/lib/csl/renderer.rb +0 -88
  82. data/lib/csl/sort.rb +0 -61
  83. data/lib/csl/style.rb +0 -110
  84. data/lib/csl/term.rb +0 -124
  85. data/lib/extensions/core.rb +0 -43
  86. data/lib/plugins/filters/bibtex.rb +0 -12
  87. data/lib/plugins/formats/default.rb +0 -134
  88. data/lib/plugins/formats/html.rb +0 -67
  89. data/lib/support/attributes.rb +0 -99
  90. data/lib/support/compatibility.rb +0 -83
  91. data/lib/support/tree.rb +0 -80
  92. data/resource/locale/locales-af-ZA.xml +0 -305
  93. data/resource/locale/locales-ar-AR.xml +0 -306
  94. data/resource/locale/locales-bg-BG.xml +0 -305
  95. data/resource/locale/locales-ca-AD.xml +0 -305
  96. data/resource/locale/locales-cs-CZ.xml +0 -305
  97. data/resource/locale/locales-da-DK.xml +0 -305
  98. data/resource/locale/locales-de-AT.xml +0 -304
  99. data/resource/locale/locales-de-CH.xml +0 -304
  100. data/resource/locale/locales-de-DE.xml +0 -332
  101. data/resource/locale/locales-el-GR.xml +0 -305
  102. data/resource/locale/locales-en-GB.xml +0 -304
  103. data/resource/locale/locales-es-ES.xml +0 -305
  104. data/resource/locale/locales-et-EE.xml +0 -304
  105. data/resource/locale/locales-eu.xml +0 -305
  106. data/resource/locale/locales-fa-IR.xml +0 -304
  107. data/resource/locale/locales-fi-FI.xml +0 -304
  108. data/resource/locale/locales-fr-CA.xml +0 -306
  109. data/resource/locale/locales-he-IL.xml +0 -304
  110. data/resource/locale/locales-hu-HU.xml +0 -305
  111. data/resource/locale/locales-is-IS.xml +0 -304
  112. data/resource/locale/locales-it-IT.xml +0 -305
  113. data/resource/locale/locales-ja-JP.xml +0 -305
  114. data/resource/locale/locales-kh-KH.xml +0 -303
  115. data/resource/locale/locales-km-KH.xml +0 -304
  116. data/resource/locale/locales-ko-KR.xml +0 -305
  117. data/resource/locale/locales-mn-MN.xml +0 -306
  118. data/resource/locale/locales-nb-NO.xml +0 -304
  119. data/resource/locale/locales-nl-NL.xml +0 -304
  120. data/resource/locale/locales-nn-NO.xml +0 -304
  121. data/resource/locale/locales-pl-PL.xml +0 -305
  122. data/resource/locale/locales-pt-BR.xml +0 -304
  123. data/resource/locale/locales-pt-PT.xml +0 -305
  124. data/resource/locale/locales-ro-RO.xml +0 -305
  125. data/resource/locale/locales-ru-RU.xml +0 -306
  126. data/resource/locale/locales-sk-SK.xml +0 -304
  127. data/resource/locale/locales-sl-SI.xml +0 -305
  128. data/resource/locale/locales-sr-RS.xml +0 -305
  129. data/resource/locale/locales-sv-SE.xml +0 -305
  130. data/resource/locale/locales-th-TH.xml +0 -304
  131. data/resource/locale/locales-tr-TR.xml +0 -305
  132. data/resource/locale/locales-uk-UA.xml +0 -306
  133. data/resource/locale/locales-vi-VN.xml +0 -305
  134. data/resource/locale/locales-zh-CN.xml +0 -304
  135. data/resource/locale/locales-zh-TW.xml +0 -305
  136. data/resource/schema/csl-categories.rnc +0 -39
  137. data/resource/schema/csl-data.rnc +0 -98
  138. data/resource/schema/csl-terms.rnc +0 -106
  139. data/resource/schema/csl-types.rnc +0 -39
  140. data/resource/schema/csl-variables.rnc +0 -182
  141. data/resource/schema/csl.rnc +0 -941
  142. data/resource/style/bibtex.csl +0 -177
  143. data/resource/style/chicago-annotated-bibliography.csl +0 -513
  144. data/resource/style/chicago-author-date-basque.csl +0 -707
  145. data/resource/style/chicago-author-date-de.csl +0 -394
  146. data/resource/style/chicago-author-date-listing.csl +0 -434
  147. data/resource/style/chicago-author-date.csl +0 -425
  148. data/resource/style/chicago-dated-note-biblio-no-ibid.csl +0 -472
  149. data/resource/style/chicago-fullnote-bibliography-bb.csl +0 -928
  150. data/resource/style/chicago-fullnote-bibliography-delimiter-fixes.csl +0 -972
  151. data/resource/style/chicago-fullnote-bibliography-no-ibid-delimiter-fixes.csl +0 -963
  152. data/resource/style/chicago-fullnote-bibliography-no-ibid.csl +0 -785
  153. data/resource/style/chicago-fullnote-bibliography.csl +0 -803
  154. data/resource/style/chicago-library-list.csl +0 -511
  155. data/resource/style/chicago-note-biblio-no-ibid.csl +0 -514
  156. data/resource/style/chicago-note-bibliography.csl +0 -530
  157. data/resource/style/chicago-note.csl +0 -388
  158. data/resource/style/chicago-quick-copy.csl +0 -685
  159. data/resource/style/ieee.csl +0 -299
  160. data/resource/style/mla-notes.csl +0 -796
  161. data/resource/style/mla-underline.csl +0 -175
  162. data/resource/style/mla-url.csl +0 -214
  163. data/resource/style/mla.csl +0 -394
  164. data/resource/style/vancouver-brackets.csl +0 -256
  165. data/resource/style/vancouver-superscript-bracket-only-year.csl +0 -165
  166. data/resource/style/vancouver-superscript.csl +0 -256
  167. data/resource/style/vancouver.csl +0 -256
  168. data/spec/citeproc/bibliography_spec.rb +0 -45
  169. data/spec/citeproc/citeproc_spec.rb +0 -80
  170. data/spec/citeproc/date_spec.rb +0 -89
  171. data/spec/citeproc/formatter_spec.rb +0 -101
  172. data/spec/citeproc/item_spec.rb +0 -71
  173. data/spec/citeproc/name_spec.rb +0 -30
  174. data/spec/citeproc/processor_spec.rb +0 -61
  175. data/spec/citeproc/selector_spec.rb +0 -82
  176. data/spec/citeproc/variable_spec.rb +0 -69
  177. data/spec/csl/locale_spec.rb +0 -208
  178. data/spec/csl/node_spec.rb +0 -25
  179. data/spec/csl/nodes_spec.rb +0 -145
  180. data/spec/csl/style_spec.rb +0 -62
  181. data/spec/csl/term_spec.rb +0 -56
  182. data/spec/fixtures/dates.yaml +0 -80
  183. data/spec/fixtures/names.yaml +0 -115
  184. data/spec/fixtures/nodes.yaml +0 -245
  185. data/spec/support/attributes_spec.rb +0 -39
  186. data/spec/support/tree_spec.rb +0 -163
@@ -0,0 +1,41 @@
1
+ module CiteProc
2
+ module Ruby
3
+
4
+ class Renderer
5
+
6
+ # @param item [CiteProc::CitationItem]
7
+ # @param node [CSL::Style::Number]
8
+ # @return [String]
9
+ def render_number(item, node)
10
+ return '' unless node.has_variable?
11
+
12
+ variable = item.data[node.variable]
13
+ return variable.to_s unless variable && variable.numeric?
14
+
15
+ numbers = variable.tokenize
16
+
17
+ case
18
+ when node.ordinal? || node.long_ordinal?
19
+ options = node.attributes_for :form
20
+ # TODO lookup term of variable to check gender
21
+
22
+ numbers.map! do |num|
23
+ num =~ /^\d+$/ ? ordinalize(num, options) : num
24
+ end
25
+
26
+ when node.roman?
27
+ numbers.map! do |num|
28
+ num =~ /^\d+$/ ? romanize(num) : num
29
+ end
30
+
31
+ else
32
+ # nothing
33
+ end
34
+
35
+ numbers.join('')
36
+ end
37
+
38
+ end
39
+
40
+ end
41
+ end
@@ -0,0 +1,44 @@
1
+ module CiteProc
2
+ module Ruby
3
+
4
+ class Renderer
5
+
6
+ class ItemObserver
7
+ attr_accessor :history, :item
8
+
9
+ def initialize(item, history = {})
10
+ @item, @history = item, history
11
+ end
12
+
13
+ def start
14
+ item.add_observer(self)
15
+ self
16
+ end
17
+
18
+ def stop
19
+ item.delete_observer(self)
20
+ self
21
+ end
22
+
23
+ def update(method, key, value)
24
+ history[key] = value if method == :read
25
+ end
26
+
27
+ def skip?
28
+ !history.empty? && history.values.all?(&:nil?)
29
+ end
30
+
31
+ def accessed
32
+ history.select { |key, value| !value.nil? }.keys
33
+ end
34
+
35
+ def clear!
36
+ history.clear
37
+ self
38
+ end
39
+ end
40
+
41
+ end
42
+
43
+ end
44
+ end
@@ -0,0 +1,96 @@
1
+ module CiteProc
2
+ module Ruby
3
+ class Renderer
4
+
5
+ def citation_mode?
6
+ state.mode == 'citation'
7
+ end
8
+
9
+ def bibliography_mode?
10
+ state.mode == 'bibliography'
11
+ end
12
+
13
+ def sort_mode?
14
+ state.mode == 'key'
15
+ end
16
+
17
+ def substitution_mode?
18
+ !state.substitute.nil?
19
+ end
20
+
21
+ def style
22
+ return unless state.node && !state.node.root? &&
23
+ state.node.root.is_a?(CSL::Style)
24
+
25
+ state.node.root
26
+ end
27
+
28
+ class State
29
+ include Observable
30
+
31
+ attr_reader :history, :node, :item, :authors, :substitute
32
+
33
+ def initialize
34
+ @history, @authors = History.new(self, 3), []
35
+ end
36
+
37
+ def store!(item, node)
38
+ @item, @node = item, node
39
+ ensure
40
+ changed
41
+ end
42
+
43
+ def store_authors!(authors)
44
+ @authors << authors
45
+ ensure
46
+ changed
47
+ end
48
+
49
+ def clear!(result = nil)
50
+ memories = conserve(result)
51
+ @item, @node, @substitute, @authors, @names = nil, nil, nil, [], nil
52
+ ensure
53
+ changed
54
+ notify_observers :clear!, memories.delete(:mode), memories
55
+ end
56
+
57
+ def mode
58
+ node && node.nodename
59
+ end
60
+
61
+ def substitute!(names)
62
+ @substitute = names
63
+ end
64
+
65
+ def clear_substitute!(backup = nil)
66
+ @substitute = backup
67
+ end
68
+
69
+ def previous_authors
70
+ past = history.recall(mode)
71
+ return unless past && !past.empty?
72
+
73
+ past[:authors]
74
+ end
75
+
76
+ def rendered_names?
77
+ @names
78
+ end
79
+
80
+ def rendered_names!
81
+ @names = true
82
+ end
83
+
84
+ def conserve(result = nil)
85
+ {
86
+ :mode => mode,
87
+ :item => item,
88
+ :authors => authors,
89
+ :result => result
90
+ }
91
+ end
92
+ end
93
+
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,62 @@
1
+ module CiteProc
2
+ module Ruby
3
+
4
+ class Renderer
5
+
6
+ # @param item [CiteProc::CitationItem]
7
+ # @param node [CSL::Style::Text]
8
+ # @return [String]
9
+ def render_text(item, node)
10
+ case
11
+ when node.has_variable?
12
+
13
+ if node.variable == 'locator'
14
+
15
+ # Subtle: when there is no locator we also look
16
+ # in item.data; there should be no locator there
17
+ # either but the read access will be noticed by
18
+ # observers (if any).
19
+ text = item.locator || item.data[:locator].to_s
20
+
21
+ else
22
+ text = item.data.variable(node.variable, node.variable_options).to_s
23
+
24
+ # Check for abbreviations or short-form fallbacks!
25
+ context, was_short_form = node.variable.split(/-short/, 2)
26
+
27
+ if was_short_form || node[:form] == 'short'
28
+ if text.empty?
29
+ text = item.data.variable(context, node.variable_options).to_s
30
+ end
31
+
32
+ text = abbreviate(context, text) || text
33
+ end
34
+ end
35
+
36
+
37
+ case
38
+ when node.variable == 'page'
39
+ format_page_range!(text, node.page_range_format)
40
+
41
+ when node.variable == 'page-first' && text.empty?
42
+ text = item.data[:'page'].to_s[/\d+/].to_s
43
+
44
+ end
45
+
46
+ text
47
+
48
+ when node.has_macro?
49
+ render item, node.macro
50
+
51
+ when node.has_term?
52
+ translate node[:term], node.attributes_for(:plural, :form)
53
+
54
+ else
55
+ node.value.to_s
56
+ end
57
+ end
58
+
59
+ end
60
+
61
+ end
62
+ end
@@ -0,0 +1,82 @@
1
+ module CiteProc
2
+ module Ruby
3
+
4
+ module SortItems
5
+
6
+ def sort!(items, keys)
7
+ return itmes unless !keys.nil? && !keys.empty?
8
+
9
+ # TODO refactor
10
+ if items.is_a?(CitationData)
11
+ items.sort! do |a, b|
12
+ compare_items_by_keys(a.data, b.data, keys)
13
+ end
14
+ else
15
+ items.sort! do |a, b|
16
+ compare_items_by_keys(a, b, keys)
17
+ end
18
+ end
19
+ end
20
+
21
+ # @returns [-1, 0, 1, nil]
22
+ def compare_items_by_keys(a, b, keys)
23
+ result = 0
24
+
25
+ keys.each do |key|
26
+ result = compare_items_by_key(a, b, key)
27
+ return result unless result.zero?
28
+ end
29
+
30
+ result
31
+ end
32
+
33
+ # @returns [-1, 0, 1, nil]
34
+ def compare_items_by_key(a, b, key)
35
+ if key.macro?
36
+ result = compare_items(*renderer.render_sort(a, b, key.macro, key))
37
+
38
+ else
39
+ va, vb = a[key.variable], b[key.variable]
40
+
41
+ # Return early if one side is nil. In this
42
+ # case ascending/descending is irrelevant!
43
+ return 1 if va.nil? || va.empty?
44
+ return -1 if vb.nil? || va.empty?
45
+
46
+ result = case CiteProc::Variable.types[key.variable]
47
+ when :names
48
+ node = CSL::Style::Name.new(key.name_options)
49
+ node.all_names_as_sort_order!
50
+
51
+ compare_items(*renderer.render_sort(va, vb, node, key))
52
+
53
+ when :date
54
+ va <=> vb
55
+ when :number
56
+ va <=> vb
57
+ else
58
+ compare_items(va, vb)
59
+ end
60
+ end
61
+
62
+ result = -result unless key.ascending?
63
+ result
64
+ end
65
+
66
+ def compare_items(a, b)
67
+ if sort_case_sensitively?
68
+ a <=> b
69
+ else
70
+ a.to_s.downcase <=> b.to_s.downcase
71
+ end
72
+ end
73
+
74
+ def sort_case_sensitively?
75
+ return false unless processor && processor.options
76
+ processor.options[:sort_case_sensitively]
77
+ end
78
+
79
+ end
80
+
81
+ end
82
+ end
@@ -0,0 +1,5 @@
1
+ module CiteProc
2
+ module Ruby
3
+ VERSION = '1.0.0'
4
+ end
5
+ end
@@ -0,0 +1,94 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require 'spec_helper'
4
+
5
+ module CiteProc
6
+ module Ruby
7
+
8
+ describe 'The CiteProc-Ruby Engine' do
9
+ let(:cp) { CiteProc::Processor.new :style => 'apa', :format => 'text' }
10
+ let(:engine) { cp.engine }
11
+
12
+ it 'registers itself as "citeproc-ruby"' do
13
+ CiteProc::Engine.available.should include('citeproc-ruby')
14
+ end
15
+
16
+ it 'is the default engine' do
17
+ CiteProc::Engine.default.should equal(CiteProc::Ruby::Engine)
18
+ engine.should be_a(CiteProc::Ruby::Engine)
19
+ end
20
+
21
+ describe '#bibliography' do
22
+
23
+ describe 'when there are no items in the processor' do
24
+ it 'returns an empty bibliography for any selector' do
25
+ cp.bibliography().should be_empty
26
+ cp.bibliography(:all => {}).should be_empty
27
+ cp.bibliography(:none => {}).should be_empty
28
+ end
29
+ end
30
+
31
+ end
32
+
33
+ describe '#render' do
34
+
35
+ describe 'when there are no items in the processor' do
36
+ end
37
+
38
+ describe 'when there are items in the processor' do
39
+ before(:each) do
40
+ cp << items(:grammatology).data
41
+ cp << items(:knuth1968).data
42
+ cp << items(:difference).data
43
+ end
44
+
45
+ it 'renders the reference for the given id' do
46
+ cp.render(:bibliography, :id => 'grammatology').should == ['Derrida, J. (1976). Of Grammatology (corrected ed.). Baltimore: Johns Hopkins University Press.']
47
+ cp.render(:citation, :id => 'grammatology', :locator => '3-4').should == '(Derrida, 1976, pp. 3-4)'
48
+ cp.render(:bibliography, :id => 'knuth1968').should == ['Knuth, D. (1968). The art of computer programming (Vol. 1). Boston: Addison-Wesley.']
49
+
50
+ node = cp.engine.style.macros['author']
51
+ (node > 'names' > 'name')[:initialize] = 'false'
52
+
53
+ cp.engine.format = 'html'
54
+ cp.render(:bibliography, :id => 'knuth1968').should == ['Knuth, Donald. (1968). <i>The art of computer programming</i> (Vol. 1). Boston: Addison-Wesley.']
55
+
56
+ cp.render(:citation, :id => 'knuth1968', :locator => '23').should == '(Knuth, 1968, p. 23)'
57
+ end
58
+
59
+ it 'overrides locales if the processor option is set' do
60
+ cp.render(:bibliography, :id => 'difference').should == ['Derrida, J. (1967). L’écriture et la différence (1st ed.). Paris: Éditions du Seuil.']
61
+
62
+ cp.options[:allow_locale_overrides] = true
63
+ cp.render(:bibliography, :id => 'difference').should == ['Derrida, J. (1967). L’écriture et la différence (1ʳᵉ éd.). Paris: Éditions du Seuil.']
64
+ end
65
+ end
66
+ end
67
+
68
+ describe '#process' do
69
+ describe 'when there are no items in the processor' do
70
+ end
71
+
72
+ describe 'when there are items in the processor' do
73
+ before(:each) do
74
+ cp << items(:grammatology).data
75
+ cp << items(:knuth1968).data
76
+ end
77
+
78
+ it 'renders the citation for the given id' do
79
+ cp.process(:id => 'knuth1968', :locator => '23').should == '(Knuth, 1968, p. 23)'
80
+ end
81
+
82
+ it 'combines and sorts multiple cite items' do
83
+ cp.process([
84
+ {:id => 'knuth1968', :locator => '23'},
85
+ {:id => 'grammatology', :locator => '11-14'}
86
+ ]).should == '(Derrida, 1976, pp. 11-14; Knuth, 1968, p. 23)'
87
+ end
88
+ end
89
+ end
90
+
91
+ end
92
+
93
+ end
94
+ end
@@ -0,0 +1,159 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ module CiteProc
6
+ module Ruby
7
+
8
+ describe 'Formats::Text#apply' do
9
+ let(:format) { Format.load 'text' }
10
+ let(:node) { CSL::Style::Text.new }
11
+
12
+ it 'returns an empty string if input is nil' do
13
+ format.apply(nil, node).should == ''
14
+ end
15
+
16
+ it 'returns the string unchanged if empty' do
17
+ input = ''
18
+ format.apply(input, node).should be_equal(input)
19
+ input.should == ''
20
+ end
21
+
22
+ it 'returns the string unchanged if node is nil' do
23
+ input = 'foo'
24
+ format.apply(input, nil).should be_equal(input)
25
+ input.should == 'foo'
26
+ end
27
+
28
+ it 'supports localized quotes' do
29
+ locale = double(:locale)
30
+ locale.stub(:punctuation_in_quotes?).and_return(true)
31
+ locale.stub(:quote).and_return('bar')
32
+
33
+ node[:quotes] = true
34
+
35
+ format.apply('foo', node, locale).should == 'bar'
36
+ end
37
+
38
+ it 'disregards localized closing quotes when squeezing affixes' do
39
+ locale = double(:locale)
40
+ locale.stub(:punctuation_in_quotes?).and_return(true)
41
+ locale.stub(:quote) { |t| '"' << t << '"' }
42
+ locale.stub(:t) { |t| t == 'close-quote' ? '"' : "'" }
43
+
44
+ node[:quotes] = true
45
+ node[:suffix] = '.'
46
+
47
+ format.apply('foo', node, locale).should == '"foo."'
48
+ format.apply("'foo'", node, locale).should == "\"'foo.'\""
49
+ end
50
+
51
+ describe 'text-case formats' do
52
+ it 'supports lowercase' do
53
+ node[:'text-case'] = 'lowercase'
54
+ format.apply('Foo BAR', node).should == 'foo bar'
55
+ end
56
+
57
+ it 'supports lowercase for non-ascii letters' do
58
+ node[:'text-case'] = 'lowercase'
59
+ format.apply('SCHÖN!', node).should == 'schön!'
60
+ end
61
+
62
+ it 'supports uppercase' do
63
+ node[:'text-case'] = 'uppercase'
64
+ format.apply('Foo BAR', node).should == 'FOO BAR'
65
+ end
66
+
67
+ it 'supports uppercase for non-ascii letters' do
68
+ node[:'text-case'] = 'uppercase'
69
+ format.apply('schön!', node).should == 'SCHÖN!'
70
+ end
71
+
72
+ it 'does not alter the original string' do
73
+ node[:'text-case'] = 'lowercase'
74
+ input = 'fooBar'
75
+
76
+ format.apply(input, node).should == 'foobar'
77
+ input.should == 'fooBar'
78
+ end
79
+
80
+ it 'supports capitalize-first' do
81
+ node[:'text-case'] = 'capitalize-first'
82
+
83
+ format.apply('foo bar', node).should == 'Foo bar'
84
+ format.apply('Foo bar', node).should == 'Foo bar'
85
+ format.apply('!foo bar', node).should == '!Foo bar'
86
+ format.apply('én foo bar', node).should == 'Én foo bar'
87
+ end
88
+
89
+ it 'supports capitalize-all' do
90
+ node[:'text-case'] = 'capitalize-all'
91
+
92
+ format.apply('foo bar', node).should == 'Foo Bar'
93
+ format.apply('!foo bar', node).should == '!Foo Bar'
94
+ format.apply('én foo bar', node).should == 'Én Foo Bar'
95
+ end
96
+
97
+ it 'supports sentence case' do
98
+ node[:'text-case'] = 'sentence'
99
+
100
+ format.apply('FOO bar', node).should == 'Foo bar'
101
+ format.apply('foo Bar BAR', node).should == 'Foo Bar Bar'
102
+ format.apply('én Foo bar', node).should == 'Én Foo bar'
103
+ end
104
+
105
+ it 'supports title case' do
106
+ node[:'text-case'] = 'title'
107
+
108
+ format.apply('The adventures of Huckleberry Finn', node).should == 'The Adventures of Huckleberry Finn'
109
+ format.apply("This IS a pen that is a smith pencil", node).should == 'This IS a Pen That Is a Smith Pencil'
110
+ #format.apply('of mice and men', node).should == 'Of Mice And Men'
111
+ end
112
+ end
113
+
114
+ describe 'strip-periods' do
115
+ before { node[:'strip-periods'] = true }
116
+
117
+ it 'strips all periods from the output' do
118
+ format.apply('hello there...! how.are.you?', node).should == 'hello there! howareyou?'
119
+ format.apply('foo bar!', node).should == 'foo bar!'
120
+ end
121
+
122
+ it 'does not strip periods from affixes' do
123
+ node[:prefix] = '...('
124
+ node[:suffix] = ').'
125
+
126
+ format.apply('foo.bar.', node).should == '...(foobar).'
127
+ end
128
+ end
129
+
130
+ describe 'affixes' do
131
+ it 'are added after text formats have been applied' do
132
+ node[:prefix] = 'foo'
133
+ node[:suffix] = 'ooo'
134
+ node[:'text-case'] = 'uppercase'
135
+
136
+ format.apply('ooo', node).should == 'fooOOOooo'
137
+ end
138
+
139
+ it 'drop squeezable characters at start/end' do
140
+ node[:suffix] = ' '
141
+
142
+ format.apply('foo', node).should == 'foo '
143
+ format.apply('foo ', node).should == 'foo '
144
+
145
+ node[:suffix] = '. '
146
+ format.apply('foo', node).should == 'foo. '
147
+ format.apply('foo.', node).should == 'foo. '
148
+ format.apply('foo?', node).should == 'foo? '
149
+
150
+ node[:prefix] = '.'
151
+ format.apply('foo', node).should == '.foo. '
152
+ format.apply('.foo', node).should == '.foo. '
153
+ format.apply(',foo', node).should == '.,foo. '
154
+ end
155
+ end
156
+ end
157
+
158
+ end
159
+ end