berkeley_library-tind 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (162) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/build.yml +18 -0
  3. data/.gitignore +388 -0
  4. data/.idea/inspectionProfiles/Project_Default.xml +20 -0
  5. data/.idea/misc.xml +4 -0
  6. data/.idea/modules.xml +8 -0
  7. data/.idea/tind.iml +138 -0
  8. data/.idea/vcs.xml +6 -0
  9. data/.rubocop.yml +334 -0
  10. data/.ruby-version +1 -0
  11. data/.simplecov +8 -0
  12. data/.yardopts +1 -0
  13. data/CHANGES.md +58 -0
  14. data/Dockerfile +57 -0
  15. data/Gemfile +3 -0
  16. data/Jenkinsfile +18 -0
  17. data/LICENSE.md +21 -0
  18. data/README.md +73 -0
  19. data/Rakefile +20 -0
  20. data/berkeley_library-tind.gemspec +50 -0
  21. data/bin/tind-export +14 -0
  22. data/docker-compose.yml +15 -0
  23. data/lib/berkeley_library/tind.rb +3 -0
  24. data/lib/berkeley_library/tind/api.rb +1 -0
  25. data/lib/berkeley_library/tind/api/api.rb +132 -0
  26. data/lib/berkeley_library/tind/api/api_exception.rb +131 -0
  27. data/lib/berkeley_library/tind/api/collection.rb +82 -0
  28. data/lib/berkeley_library/tind/api/date_range.rb +67 -0
  29. data/lib/berkeley_library/tind/api/format.rb +32 -0
  30. data/lib/berkeley_library/tind/api/search.rb +100 -0
  31. data/lib/berkeley_library/tind/config.rb +103 -0
  32. data/lib/berkeley_library/tind/export.rb +1 -0
  33. data/lib/berkeley_library/tind/export/column.rb +54 -0
  34. data/lib/berkeley_library/tind/export/column_group.rb +144 -0
  35. data/lib/berkeley_library/tind/export/column_group_list.rb +131 -0
  36. data/lib/berkeley_library/tind/export/column_width_calculator.rb +76 -0
  37. data/lib/berkeley_library/tind/export/config.rb +154 -0
  38. data/lib/berkeley_library/tind/export/csv_exporter.rb +29 -0
  39. data/lib/berkeley_library/tind/export/export.rb +47 -0
  40. data/lib/berkeley_library/tind/export/export_command.rb +168 -0
  41. data/lib/berkeley_library/tind/export/export_exception.rb +8 -0
  42. data/lib/berkeley_library/tind/export/export_format.rb +67 -0
  43. data/lib/berkeley_library/tind/export/exporter.rb +105 -0
  44. data/lib/berkeley_library/tind/export/filter.rb +52 -0
  45. data/lib/berkeley_library/tind/export/no_results_error.rb +7 -0
  46. data/lib/berkeley_library/tind/export/ods_exporter.rb +138 -0
  47. data/lib/berkeley_library/tind/export/row.rb +24 -0
  48. data/lib/berkeley_library/tind/export/row_metrics.rb +18 -0
  49. data/lib/berkeley_library/tind/export/table.rb +175 -0
  50. data/lib/berkeley_library/tind/export/table_metrics.rb +116 -0
  51. data/lib/berkeley_library/tind/marc.rb +1 -0
  52. data/lib/berkeley_library/tind/marc/xml_reader.rb +144 -0
  53. data/lib/berkeley_library/tind/module_info.rb +14 -0
  54. data/lib/berkeley_library/util/arrays.rb +178 -0
  55. data/lib/berkeley_library/util/logging.rb +1 -0
  56. data/lib/berkeley_library/util/ods/spreadsheet.rb +170 -0
  57. data/lib/berkeley_library/util/ods/xml/content_doc.rb +26 -0
  58. data/lib/berkeley_library/util/ods/xml/document_node.rb +57 -0
  59. data/lib/berkeley_library/util/ods/xml/element_node.rb +106 -0
  60. data/lib/berkeley_library/util/ods/xml/loext/table_protection.rb +26 -0
  61. data/lib/berkeley_library/util/ods/xml/manifest/file_entry.rb +42 -0
  62. data/lib/berkeley_library/util/ods/xml/manifest/manifest.rb +73 -0
  63. data/lib/berkeley_library/util/ods/xml/manifest_doc.rb +26 -0
  64. data/lib/berkeley_library/util/ods/xml/namespace.rb +46 -0
  65. data/lib/berkeley_library/util/ods/xml/office/automatic_styles.rb +181 -0
  66. data/lib/berkeley_library/util/ods/xml/office/body.rb +17 -0
  67. data/lib/berkeley_library/util/ods/xml/office/document_content.rb +98 -0
  68. data/lib/berkeley_library/util/ods/xml/office/document_styles.rb +39 -0
  69. data/lib/berkeley_library/util/ods/xml/office/font_face_decls.rb +30 -0
  70. data/lib/berkeley_library/util/ods/xml/office/scripts.rb +17 -0
  71. data/lib/berkeley_library/util/ods/xml/office/spreadsheet.rb +37 -0
  72. data/lib/berkeley_library/util/ods/xml/office/styles.rb +39 -0
  73. data/lib/berkeley_library/util/ods/xml/style/cell_style.rb +58 -0
  74. data/lib/berkeley_library/util/ods/xml/style/column_style.rb +36 -0
  75. data/lib/berkeley_library/util/ods/xml/style/default_style.rb +31 -0
  76. data/lib/berkeley_library/util/ods/xml/style/family.rb +85 -0
  77. data/lib/berkeley_library/util/ods/xml/style/font_face.rb +46 -0
  78. data/lib/berkeley_library/util/ods/xml/style/paragraph_properties.rb +30 -0
  79. data/lib/berkeley_library/util/ods/xml/style/row_style.rb +37 -0
  80. data/lib/berkeley_library/util/ods/xml/style/style.rb +44 -0
  81. data/lib/berkeley_library/util/ods/xml/style/table_cell_properties.rb +40 -0
  82. data/lib/berkeley_library/util/ods/xml/style/table_column_properties.rb +30 -0
  83. data/lib/berkeley_library/util/ods/xml/style/table_properties.rb +25 -0
  84. data/lib/berkeley_library/util/ods/xml/style/table_row_properties.rb +28 -0
  85. data/lib/berkeley_library/util/ods/xml/style/table_style.rb +27 -0
  86. data/lib/berkeley_library/util/ods/xml/style/text_properties.rb +52 -0
  87. data/lib/berkeley_library/util/ods/xml/styles_doc.rb +26 -0
  88. data/lib/berkeley_library/util/ods/xml/table/named_expressions.rb +17 -0
  89. data/lib/berkeley_library/util/ods/xml/table/repeatable.rb +38 -0
  90. data/lib/berkeley_library/util/ods/xml/table/table.rb +193 -0
  91. data/lib/berkeley_library/util/ods/xml/table/table_cell.rb +46 -0
  92. data/lib/berkeley_library/util/ods/xml/table/table_column.rb +43 -0
  93. data/lib/berkeley_library/util/ods/xml/table/table_row.rb +136 -0
  94. data/lib/berkeley_library/util/ods/xml/text/p.rb +118 -0
  95. data/lib/berkeley_library/util/paths.rb +111 -0
  96. data/lib/berkeley_library/util/stringios.rb +30 -0
  97. data/lib/berkeley_library/util/strings.rb +42 -0
  98. data/lib/berkeley_library/util/sys_exits.rb +15 -0
  99. data/lib/berkeley_library/util/times.rb +22 -0
  100. data/lib/berkeley_library/util/uris.rb +44 -0
  101. data/lib/berkeley_library/util/uris/appender.rb +162 -0
  102. data/lib/berkeley_library/util/uris/requester.rb +62 -0
  103. data/lib/berkeley_library/util/uris/validator.rb +32 -0
  104. data/rakelib/bundle.rake +8 -0
  105. data/rakelib/coverage.rake +11 -0
  106. data/rakelib/gem.rake +54 -0
  107. data/rakelib/rubocop.rake +18 -0
  108. data/rakelib/spec.rake +2 -0
  109. data/spec/.rubocop.yml +40 -0
  110. data/spec/berkeley_library/tind/api/api_exception_spec.rb +91 -0
  111. data/spec/berkeley_library/tind/api/api_spec.rb +143 -0
  112. data/spec/berkeley_library/tind/api/collection_spec.rb +74 -0
  113. data/spec/berkeley_library/tind/api/date_range_spec.rb +110 -0
  114. data/spec/berkeley_library/tind/api/format_spec.rb +54 -0
  115. data/spec/berkeley_library/tind/api/search_spec.rb +364 -0
  116. data/spec/berkeley_library/tind/config_spec.rb +86 -0
  117. data/spec/berkeley_library/tind/export/column_group_spec.rb +29 -0
  118. data/spec/berkeley_library/tind/export/column_spec.rb +43 -0
  119. data/spec/berkeley_library/tind/export/config_spec.rb +206 -0
  120. data/spec/berkeley_library/tind/export/export_command_spec.rb +169 -0
  121. data/spec/berkeley_library/tind/export/export_format_spec.rb +59 -0
  122. data/spec/berkeley_library/tind/export/export_matcher.rb +112 -0
  123. data/spec/berkeley_library/tind/export/export_spec.rb +150 -0
  124. data/spec/berkeley_library/tind/export/exporter_spec.rb +125 -0
  125. data/spec/berkeley_library/tind/export/row_spec.rb +118 -0
  126. data/spec/berkeley_library/tind/export/table_spec.rb +322 -0
  127. data/spec/berkeley_library/tind/marc/xml_reader_spec.rb +93 -0
  128. data/spec/berkeley_library/util/arrays_spec.rb +340 -0
  129. data/spec/berkeley_library/util/ods/spreadsheet_spec.rb +124 -0
  130. data/spec/berkeley_library/util/ods/xml/content_doc_spec.rb +121 -0
  131. data/spec/berkeley_library/util/ods/xml/manifest/file_entry_spec.rb +27 -0
  132. data/spec/berkeley_library/util/ods/xml/manifest/manifest_spec.rb +33 -0
  133. data/spec/berkeley_library/util/ods/xml/office/document_content_spec.rb +60 -0
  134. data/spec/berkeley_library/util/ods/xml/style/automatic_styles_spec.rb +37 -0
  135. data/spec/berkeley_library/util/ods/xml/style/family_spec.rb +57 -0
  136. data/spec/berkeley_library/util/ods/xml/table/table_row_spec.rb +179 -0
  137. data/spec/berkeley_library/util/ods/xml/table/table_spec.rb +218 -0
  138. data/spec/berkeley_library/util/paths_spec.rb +90 -0
  139. data/spec/berkeley_library/util/stringios_spec.rb +34 -0
  140. data/spec/berkeley_library/util/strings_spec.rb +27 -0
  141. data/spec/berkeley_library/util/times_spec.rb +39 -0
  142. data/spec/berkeley_library/util/uris_spec.rb +118 -0
  143. data/spec/data/collection-names.txt +438 -0
  144. data/spec/data/collections.json +4827 -0
  145. data/spec/data/disjoint-records.xml +187 -0
  146. data/spec/data/record-184453.xml +58 -0
  147. data/spec/data/record-184458.xml +63 -0
  148. data/spec/data/record-187888.xml +78 -0
  149. data/spec/data/records-api-search-cjk-p1.xml +6381 -0
  150. data/spec/data/records-api-search-cjk-p2.xml +5 -0
  151. data/spec/data/records-api-search-p1.xml +4506 -0
  152. data/spec/data/records-api-search-p2.xml +4509 -0
  153. data/spec/data/records-api-search-p3.xml +4506 -0
  154. data/spec/data/records-api-search-p4.xml +4509 -0
  155. data/spec/data/records-api-search-p5.xml +4506 -0
  156. data/spec/data/records-api-search-p6.xml +2436 -0
  157. data/spec/data/records-api-search-p7.xml +5 -0
  158. data/spec/data/records-api-search.xml +234 -0
  159. data/spec/data/records-manual-search.xml +547 -0
  160. data/spec/spec_helper.rb +30 -0
  161. data/test/profile/table_from_records_profile.rb +46 -0
  162. metadata +585 -0
@@ -0,0 +1,121 @@
1
+ require 'spec_helper'
2
+
3
+ require 'rexml/document'
4
+
5
+ module BerkeleyLibrary
6
+ module Util
7
+ module ODS
8
+ module XML
9
+ describe ContentDoc do
10
+ let(:content) { ContentDoc.new }
11
+
12
+ describe :document_content do
13
+ it 'returns a DocumentContent' do
14
+ expect(content.document_content).to be_a(Office::DocumentContent)
15
+ end
16
+ end
17
+
18
+ describe :to_xml do
19
+ attr_reader :doc, :root
20
+
21
+ before(:each) do
22
+ xml_str = content.to_xml
23
+ @doc = REXML::Document.new(xml_str)
24
+ @root = doc.root
25
+ end
26
+
27
+ describe :root do
28
+
29
+ it 'is a <document-content/> element' do
30
+ expect(root).to be_a(REXML::Element)
31
+ expect(root.prefix).to eq('office')
32
+ expect(root.name).to eq('document-content')
33
+ expect(root.namespace).to eq('urn:oasis:names:tc:opendocument:xmlns:office:1.0')
34
+ end
35
+
36
+ it 'includes all namespaces' do
37
+ aggregate_failures('namespaces') do
38
+ Office::DocumentContent::REQUIRED_NAMESPACES.each do |ns|
39
+ expect(root["xmlns:#{ns.prefix}"]).to eq(ns.uri)
40
+ end
41
+ end
42
+ end
43
+
44
+ describe '<scripts/>' do
45
+ it 'includes a <scripts/> element' do
46
+ elem = root.elements[1]
47
+ expect(elem).to be_a(REXML::Element)
48
+ expect(elem.prefix).to eq('office')
49
+ expect(elem.name).to eq('scripts')
50
+ end
51
+ end
52
+
53
+ describe '<font-face-decls/>' do
54
+ attr_reader :decls
55
+
56
+ before(:each) do
57
+ @decls = root.elements[2]
58
+ end
59
+
60
+ it 'includes a <font-face-decls/> element' do
61
+ expect(decls).to be_a(REXML::Element)
62
+ expect(decls.prefix).to eq('office')
63
+ expect(decls.name).to eq('font-face-decls')
64
+ end
65
+
66
+ it 'includes the default font face' do
67
+ face = decls.elements[1]
68
+ expect(face).to be_a(REXML::Element)
69
+ expect(face.prefix).to eq('style')
70
+ expect(face.name).to eq('font-face')
71
+
72
+ expected_face = Style::FontFace::DEFAULT_FONT_FACE
73
+
74
+ expect(face['style:name']).to eq(expected_face)
75
+ expect(face['svg:font-family']).to eq("'#{expected_face}'")
76
+ expect(face['style:font-family-generic']).to eq('swiss')
77
+ end
78
+ end
79
+
80
+ describe '<automatic-styles/>' do
81
+ attr_reader :styles
82
+
83
+ before(:each) do
84
+ @styles = root.elements[3]
85
+ end
86
+
87
+ it 'includes an <automatic-styles/> element' do
88
+ expect(styles).to be_a(REXML::Element)
89
+ expect(styles.prefix).to eq('office')
90
+ expect(styles.name).to eq('automatic-styles')
91
+ end
92
+ end
93
+
94
+ describe '<body/>' do
95
+ attr_reader :body
96
+
97
+ before(:each) do
98
+ @body = root.elements[4]
99
+ end
100
+
101
+ it 'includes a <body/> element' do
102
+ expect(body).to be_a(REXML::Element)
103
+ expect(body.prefix).to eq('office')
104
+ expect(body.name).to eq('body')
105
+ end
106
+
107
+ it 'includes a <spreadsheet/> element' do
108
+ spreadsheet = body.elements[1]
109
+ expect(spreadsheet).to be_a(REXML::Element)
110
+ expect(spreadsheet.prefix).to eq('office')
111
+ expect(spreadsheet.name).to eq('spreadsheet')
112
+ end
113
+ end
114
+ end
115
+
116
+ end
117
+ end
118
+ end
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,27 @@
1
+ require 'spec_helper'
2
+
3
+ module BerkeleyLibrary
4
+ module Util
5
+ module ODS
6
+ module XML
7
+ module Manifest
8
+ describe FileEntry do
9
+ let(:doc) { Nokogiri::XML::Document.new }
10
+ let(:manifest) { Manifest.new(doc: doc) }
11
+
12
+ describe :new do
13
+ it 'guesses the media type' do
14
+ entry = FileEntry.new('foo.xml', manifest: manifest)
15
+ expect(entry.media_type).to eq('text/xml')
16
+ end
17
+
18
+ it 'rejects unknown types' do
19
+ expect { FileEntry.new('foo.bar', manifest: manifest) }.to raise_error(ArgumentError)
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,33 @@
1
+ require 'spec_helper'
2
+
3
+ module BerkeleyLibrary
4
+ module Util
5
+ module ODS
6
+ module XML
7
+ module Manifest
8
+ describe Manifest do
9
+ let(:doc) { Nokogiri::XML::Document.new }
10
+
11
+ attr_reader :manifest
12
+
13
+ before(:each) do
14
+ @manifest = Manifest.new(doc: doc)
15
+ end
16
+
17
+ describe :add_child do
18
+ it 'adds a FileEntry' do
19
+ entry = FileEntry.new('foo.bar', 'foo/bar', manifest: manifest)
20
+ manifest.add_child(entry)
21
+ end
22
+
23
+ it 'adds a non-FileEntry' do
24
+ child = ElementNode.new(:office, 'test', doc: doc)
25
+ manifest.add_child(child)
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,60 @@
1
+ require 'spec_helper'
2
+
3
+ module BerkeleyLibrary
4
+ module Util
5
+ module ODS
6
+ module XML
7
+ module Office
8
+ describe DocumentContent do
9
+ let(:content) { ContentDoc.new }
10
+ let(:doc_content) { content.document_content }
11
+
12
+ # TODO: move to some kind of helper & share w/table_spec
13
+ def doc_content_xml
14
+ xml_str = content.to_xml
15
+ # File.open("tmp/content-#{Time.now.to_i}.xml", 'wb') { |f| f.write(xml_str) }
16
+ rexml_doc = REXML::Document.new(xml_str)
17
+ rexml_doc.root
18
+ end
19
+
20
+ # TODO: move to some kind of helper & share w/table_spec
21
+ def find_table_xml(dc_xml = doc_content_xml, table_index = 1)
22
+ body = dc_xml.elements[4]
23
+ expect(body).to be_a(REXML::Element) # just to be sure
24
+
25
+ spreadsheet = body.elements[1]
26
+ expect(spreadsheet).to be_a(REXML::Element) # just to be sure
27
+
28
+ spreadsheet.elements[table_index]
29
+ end
30
+
31
+ describe :add_table do
32
+
33
+ let(:table_name) { "Table for #{File.basename(__FILE__, '.rb')}" }
34
+
35
+ attr_reader :table
36
+
37
+ before(:each) do
38
+ @table = doc_content.add_table(table_name)
39
+ end
40
+
41
+ it 'creates a table' do
42
+ expect(table).to be_a(XML::Table::Table)
43
+ end
44
+
45
+ it 'adds the table to the XML' do
46
+ table_xml = find_table_xml
47
+ expect(table_xml).to be_a(REXML::Element)
48
+ expect(table_xml.prefix).to eq('table')
49
+ expect(table_xml.name).to eq('table')
50
+
51
+ expect(table_xml['table:name']).to eq(table_name)
52
+ expect(table_xml['table:protected']).to eq('true')
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,37 @@
1
+ require 'spec_helper'
2
+
3
+ module BerkeleyLibrary
4
+ module Util
5
+ module ODS
6
+ module XML
7
+ module Office
8
+ describe AutomaticStyles do
9
+ let(:doc) { Nokogiri::XML::Document.new }
10
+
11
+ attr_reader :styles
12
+
13
+ before(:each) do
14
+ @styles = AutomaticStyles.new(doc: doc)
15
+ end
16
+
17
+ describe :add_child do
18
+ it 'adds a style' do
19
+ protected = false
20
+ color = '#abcdef'
21
+
22
+ style = Style::CellStyle.new('my-style', protected, color, styles: styles)
23
+ styles.add_child(style)
24
+ expect(styles.find_cell_style(protected, color: color)).to be(style)
25
+ end
26
+
27
+ it 'adds a non-style' do
28
+ non_style = XML::Text::P.new('abcdef', doc: doc)
29
+ styles.add_child(non_style)
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,57 @@
1
+ require 'spec_helper'
2
+
3
+ module BerkeleyLibrary
4
+ module Util
5
+ module ODS
6
+ module XML
7
+ module Style
8
+ describe Family do
9
+ describe :ensure_family do
10
+ it "returns a #{Family} as itself" do
11
+ Family.each do |f|
12
+ expect(Family.ensure_family(f)).to be(f)
13
+ end
14
+ end
15
+
16
+ it 'finds a family by key' do
17
+ Family.each do |f|
18
+ variants = [
19
+ f.key.to_s,
20
+ f.key.to_sym,
21
+ f.key.to_s.upcase,
22
+ f.key.to_s.upcase.to_sym,
23
+ f.key.to_s.downcase,
24
+ f.key.to_s.downcase.to_sym
25
+ ]
26
+ variants.each do |k|
27
+ expect(Family.ensure_family(k)).to be(f)
28
+ end
29
+ end
30
+ end
31
+
32
+ it 'finds a family by value' do
33
+ Family.each do |f|
34
+ variants = [
35
+ f.value.to_s,
36
+ f.value.to_sym,
37
+ f.value.to_s.upcase,
38
+ f.value.to_s.upcase.to_sym,
39
+ f.value.to_s.downcase,
40
+ f.value.to_s.downcase.to_sym
41
+ ]
42
+ variants.each do |v|
43
+ expect(Family.ensure_family(v)).to be(f)
44
+ end
45
+ end
46
+ end
47
+
48
+ it 'rejects invalid families' do
49
+ expect { Family.ensure_family(:not_a_family) }.to raise_error(ArgumentError)
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,179 @@
1
+ require 'spec_helper'
2
+
3
+ module BerkeleyLibrary
4
+ module Util
5
+ module ODS
6
+ module XML
7
+ module Table
8
+ describe TableRow do
9
+ let(:content) { ContentDoc.new }
10
+ let(:doc_content) { content.document_content }
11
+ let(:table_name) { "Table for #{File.basename(__FILE__, '.rb')}" }
12
+
13
+ attr_reader :table, :row
14
+
15
+ before(:each) do
16
+ @table = doc_content.add_table(table_name)
17
+ table.add_column('Column 1')
18
+ @row = table.add_row
19
+ end
20
+
21
+ # TODO: move to some kind of helper & share w/table_spec
22
+ def doc_content_xml
23
+ xml_str = content.to_xml
24
+ # File.open("tmp/content-#{Time.now.to_i}.xml", 'wb') { |f| f.write(xml_str) }
25
+ rexml_doc = REXML::Document.new(xml_str)
26
+ rexml_doc.root
27
+ end
28
+
29
+ # TODO: move to some kind of helper & share w/table_spec
30
+ def find_table_xml(dc_xml = doc_content_xml, table_index = 1)
31
+ body = dc_xml.elements[4]
32
+ expect(body).to be_a(REXML::Element) # just to be sure
33
+
34
+ spreadsheet = body.elements[1]
35
+ expect(spreadsheet).to be_a(REXML::Element) # just to be sure
36
+
37
+ spreadsheet.elements[table_index]
38
+ end
39
+
40
+ def find_row_xml(table_xml = find_table_xml, row_index = 2)
41
+ table_xml.elements[row_index, 'table-row']
42
+ end
43
+
44
+ def find_cell_xml(table_xml = find_table_xml, row_index = 2, col_index = 0)
45
+ row_xml = table_xml.elements[row_index, 'table-row']
46
+ cells_xml = row_xml.elements.select { |e| e.name == 'table-cell' }
47
+ cells_xml[col_index]
48
+ end
49
+
50
+ describe :set_value_at do
51
+ it 'sets a value' do
52
+ value = 'Value 0'
53
+ row.set_value_at(0, value)
54
+ expect(table.get_value_at(1, 0)).to eq(value)
55
+
56
+ row_xml = find_row_xml
57
+ cells_xml = row_xml.elements.select { |e| e.name == 'table-cell' }
58
+ expect(cells_xml.size).to eq(2)
59
+
60
+ cell_xml = cells_xml[0]
61
+ p = cell_xml.elements[1, 'p'] # row 1 is header
62
+ expect(p).to be_a(REXML::Element)
63
+ expect(p.prefix).to eq('text')
64
+
65
+ texts = p.texts
66
+ expect(texts.size).to eq(1)
67
+ expect(texts[0].value).to eq(value)
68
+
69
+ dummy_cell_xml = cells_xml[1]
70
+ expected_dummy_cols = Table::MIN_COLUMNS - 1
71
+ expect(dummy_cell_xml['table:number-columns-repeated']).to eq(expected_dummy_cols.to_s)
72
+ end
73
+
74
+ it 'escapes tabs, newlines, and runs of spaces' do
75
+ value_fragments = [
76
+ ' test test ', "\t", 'test ', ' ', ' ', 'test test', "\n", 'test test ', ' '
77
+ ]
78
+ value = value_fragments.join
79
+ row.set_value_at(0, value)
80
+ expect(table.get_value_at(1, 0)).to eq(value)
81
+
82
+ row_xml = find_row_xml
83
+ cells_xml = row_xml.elements.select { |e| e.name == 'table-cell' }
84
+ expect(cells_xml.size).to eq(2)
85
+
86
+ escape_elements = { ' ' => 's', "\t" => 'tab', "\n" => 'line-break' }
87
+
88
+ cell_xml = cells_xml[0]
89
+ p_xml = cell_xml.elements[1, 'p']
90
+
91
+ p_children = p_xml.to_a
92
+ expect(p_children.size).to eq(value_fragments.size)
93
+
94
+ value_fragments.each_with_index do |vf, i|
95
+ expected_element = escape_elements[vf]
96
+ if expected_element
97
+ element = p_children[i]
98
+ expect(element).to be_a(REXML::Element)
99
+ expect(element.name).to eq(expected_element)
100
+ expect(element.prefix).to eq('text')
101
+ else
102
+ text = p_children[i]
103
+ expect(text).to be_a(REXML::Text)
104
+ expect(text.value).to eq(vf)
105
+ end
106
+ end
107
+ end
108
+ end
109
+
110
+ describe :to_xml do
111
+ it 'collapses consecutive nils' do
112
+ (2..7).each { |col| table.add_column("Column #{col}") }
113
+
114
+ row.set_value_at(0, 'Value 0')
115
+ row.set_value_at(2, 'Value 2')
116
+ row.set_value_at(6, 'Value 6')
117
+
118
+ row_xml = find_row_xml
119
+ cells_xml = row_xml.elements.select { |e| e.name == 'table-cell' }
120
+ expect(cells_xml.size).to eq(6)
121
+
122
+ expected_values = ['Value 0', nil, 'Value 2', nil, 'Value 6', nil]
123
+ expected_repeats = [nil, nil, nil, 3, nil, Table::MIN_COLUMNS - 7]
124
+ cells_xml.each_with_index do |cell_xml, i|
125
+ p = cell_xml.elements[1, 'p']
126
+ if (expected_value = expected_values[i])
127
+ expect(p).to be_a(REXML::Element)
128
+ texts = p.texts
129
+ expect(texts.size).to eq(1)
130
+ expect(texts[0].value).to eq(expected_value)
131
+ else
132
+ expect(p).to be_nil
133
+ end
134
+
135
+ num_cols_repeated = cell_xml['table:number-columns-repeated']
136
+ expected_repeat = expected_repeats[i]
137
+ if expected_repeat
138
+ expect(num_cols_repeated).to eq(expected_repeat.to_s)
139
+ else
140
+ expect(num_cols_repeated).to be_nil
141
+ end
142
+ end
143
+ end
144
+ end
145
+
146
+ describe :add_child do
147
+ it 'adds a cell' do
148
+ value = 'Value 0'
149
+ cell = TableCell.new(value, table: table)
150
+ row.add_child(cell)
151
+ expect(table.get_value_at(1, 0)).to eq(value)
152
+ end
153
+
154
+ it 'adds a non-cell child' do
155
+ child = ElementNode.new(:office, 'test', doc: table.doc)
156
+ row.add_child(child)
157
+ end
158
+
159
+ it "fails if there aren't enough columns" do
160
+ column_count = table.column_count
161
+ (0..column_count).each do |col_index|
162
+ value = "Value #{col_index}"
163
+ cell = TableCell.new(value, table: table)
164
+ if col_index < column_count
165
+ expect { row.add_child(cell) }.not_to raise_error
166
+ expect(table.get_value_at(1, col_index)).to eq(value)
167
+ else
168
+ expect { row.add_child(cell) }.to raise_error(ArgumentError)
169
+ expect(table.get_value_at(1, col_index)).to be_nil
170
+ end
171
+ end
172
+ end
173
+ end
174
+ end
175
+ end
176
+ end
177
+ end
178
+ end
179
+ end