berkeley_library-tind 0.4.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/.github/workflows/build.yml +18 -0
- data/.gitignore +388 -0
- data/.idea/inspectionProfiles/Project_Default.xml +20 -0
- data/.idea/misc.xml +4 -0
- data/.idea/modules.xml +8 -0
- data/.idea/tind.iml +138 -0
- data/.idea/vcs.xml +6 -0
- data/.rubocop.yml +334 -0
- data/.ruby-version +1 -0
- data/.simplecov +8 -0
- data/.yardopts +1 -0
- data/CHANGES.md +58 -0
- data/Dockerfile +57 -0
- data/Gemfile +3 -0
- data/Jenkinsfile +18 -0
- data/LICENSE.md +21 -0
- data/README.md +73 -0
- data/Rakefile +20 -0
- data/berkeley_library-tind.gemspec +50 -0
- data/bin/tind-export +14 -0
- data/docker-compose.yml +15 -0
- data/lib/berkeley_library/tind.rb +3 -0
- data/lib/berkeley_library/tind/api.rb +1 -0
- data/lib/berkeley_library/tind/api/api.rb +132 -0
- data/lib/berkeley_library/tind/api/api_exception.rb +131 -0
- data/lib/berkeley_library/tind/api/collection.rb +82 -0
- data/lib/berkeley_library/tind/api/date_range.rb +67 -0
- data/lib/berkeley_library/tind/api/format.rb +32 -0
- data/lib/berkeley_library/tind/api/search.rb +100 -0
- data/lib/berkeley_library/tind/config.rb +103 -0
- data/lib/berkeley_library/tind/export.rb +1 -0
- data/lib/berkeley_library/tind/export/column.rb +54 -0
- data/lib/berkeley_library/tind/export/column_group.rb +144 -0
- data/lib/berkeley_library/tind/export/column_group_list.rb +131 -0
- data/lib/berkeley_library/tind/export/column_width_calculator.rb +76 -0
- data/lib/berkeley_library/tind/export/config.rb +154 -0
- data/lib/berkeley_library/tind/export/csv_exporter.rb +29 -0
- data/lib/berkeley_library/tind/export/export.rb +47 -0
- data/lib/berkeley_library/tind/export/export_command.rb +168 -0
- data/lib/berkeley_library/tind/export/export_exception.rb +8 -0
- data/lib/berkeley_library/tind/export/export_format.rb +67 -0
- data/lib/berkeley_library/tind/export/exporter.rb +105 -0
- data/lib/berkeley_library/tind/export/filter.rb +52 -0
- data/lib/berkeley_library/tind/export/no_results_error.rb +7 -0
- data/lib/berkeley_library/tind/export/ods_exporter.rb +138 -0
- data/lib/berkeley_library/tind/export/row.rb +24 -0
- data/lib/berkeley_library/tind/export/row_metrics.rb +18 -0
- data/lib/berkeley_library/tind/export/table.rb +175 -0
- data/lib/berkeley_library/tind/export/table_metrics.rb +116 -0
- data/lib/berkeley_library/tind/marc.rb +1 -0
- data/lib/berkeley_library/tind/marc/xml_reader.rb +144 -0
- data/lib/berkeley_library/tind/module_info.rb +14 -0
- data/lib/berkeley_library/util/arrays.rb +178 -0
- data/lib/berkeley_library/util/logging.rb +1 -0
- data/lib/berkeley_library/util/ods/spreadsheet.rb +170 -0
- data/lib/berkeley_library/util/ods/xml/content_doc.rb +26 -0
- data/lib/berkeley_library/util/ods/xml/document_node.rb +57 -0
- data/lib/berkeley_library/util/ods/xml/element_node.rb +106 -0
- data/lib/berkeley_library/util/ods/xml/loext/table_protection.rb +26 -0
- data/lib/berkeley_library/util/ods/xml/manifest/file_entry.rb +42 -0
- data/lib/berkeley_library/util/ods/xml/manifest/manifest.rb +73 -0
- data/lib/berkeley_library/util/ods/xml/manifest_doc.rb +26 -0
- data/lib/berkeley_library/util/ods/xml/namespace.rb +46 -0
- data/lib/berkeley_library/util/ods/xml/office/automatic_styles.rb +181 -0
- data/lib/berkeley_library/util/ods/xml/office/body.rb +17 -0
- data/lib/berkeley_library/util/ods/xml/office/document_content.rb +98 -0
- data/lib/berkeley_library/util/ods/xml/office/document_styles.rb +39 -0
- data/lib/berkeley_library/util/ods/xml/office/font_face_decls.rb +30 -0
- data/lib/berkeley_library/util/ods/xml/office/scripts.rb +17 -0
- data/lib/berkeley_library/util/ods/xml/office/spreadsheet.rb +37 -0
- data/lib/berkeley_library/util/ods/xml/office/styles.rb +39 -0
- data/lib/berkeley_library/util/ods/xml/style/cell_style.rb +58 -0
- data/lib/berkeley_library/util/ods/xml/style/column_style.rb +36 -0
- data/lib/berkeley_library/util/ods/xml/style/default_style.rb +31 -0
- data/lib/berkeley_library/util/ods/xml/style/family.rb +85 -0
- data/lib/berkeley_library/util/ods/xml/style/font_face.rb +46 -0
- data/lib/berkeley_library/util/ods/xml/style/paragraph_properties.rb +30 -0
- data/lib/berkeley_library/util/ods/xml/style/row_style.rb +37 -0
- data/lib/berkeley_library/util/ods/xml/style/style.rb +44 -0
- data/lib/berkeley_library/util/ods/xml/style/table_cell_properties.rb +40 -0
- data/lib/berkeley_library/util/ods/xml/style/table_column_properties.rb +30 -0
- data/lib/berkeley_library/util/ods/xml/style/table_properties.rb +25 -0
- data/lib/berkeley_library/util/ods/xml/style/table_row_properties.rb +28 -0
- data/lib/berkeley_library/util/ods/xml/style/table_style.rb +27 -0
- data/lib/berkeley_library/util/ods/xml/style/text_properties.rb +52 -0
- data/lib/berkeley_library/util/ods/xml/styles_doc.rb +26 -0
- data/lib/berkeley_library/util/ods/xml/table/named_expressions.rb +17 -0
- data/lib/berkeley_library/util/ods/xml/table/repeatable.rb +38 -0
- data/lib/berkeley_library/util/ods/xml/table/table.rb +193 -0
- data/lib/berkeley_library/util/ods/xml/table/table_cell.rb +46 -0
- data/lib/berkeley_library/util/ods/xml/table/table_column.rb +43 -0
- data/lib/berkeley_library/util/ods/xml/table/table_row.rb +136 -0
- data/lib/berkeley_library/util/ods/xml/text/p.rb +118 -0
- data/lib/berkeley_library/util/paths.rb +111 -0
- data/lib/berkeley_library/util/stringios.rb +30 -0
- data/lib/berkeley_library/util/strings.rb +42 -0
- data/lib/berkeley_library/util/sys_exits.rb +15 -0
- data/lib/berkeley_library/util/times.rb +22 -0
- data/lib/berkeley_library/util/uris.rb +44 -0
- data/lib/berkeley_library/util/uris/appender.rb +162 -0
- data/lib/berkeley_library/util/uris/requester.rb +62 -0
- data/lib/berkeley_library/util/uris/validator.rb +32 -0
- data/rakelib/bundle.rake +8 -0
- data/rakelib/coverage.rake +11 -0
- data/rakelib/gem.rake +54 -0
- data/rakelib/rubocop.rake +18 -0
- data/rakelib/spec.rake +2 -0
- data/spec/.rubocop.yml +40 -0
- data/spec/berkeley_library/tind/api/api_exception_spec.rb +91 -0
- data/spec/berkeley_library/tind/api/api_spec.rb +143 -0
- data/spec/berkeley_library/tind/api/collection_spec.rb +74 -0
- data/spec/berkeley_library/tind/api/date_range_spec.rb +110 -0
- data/spec/berkeley_library/tind/api/format_spec.rb +54 -0
- data/spec/berkeley_library/tind/api/search_spec.rb +364 -0
- data/spec/berkeley_library/tind/config_spec.rb +86 -0
- data/spec/berkeley_library/tind/export/column_group_spec.rb +29 -0
- data/spec/berkeley_library/tind/export/column_spec.rb +43 -0
- data/spec/berkeley_library/tind/export/config_spec.rb +206 -0
- data/spec/berkeley_library/tind/export/export_command_spec.rb +169 -0
- data/spec/berkeley_library/tind/export/export_format_spec.rb +59 -0
- data/spec/berkeley_library/tind/export/export_matcher.rb +112 -0
- data/spec/berkeley_library/tind/export/export_spec.rb +150 -0
- data/spec/berkeley_library/tind/export/exporter_spec.rb +125 -0
- data/spec/berkeley_library/tind/export/row_spec.rb +118 -0
- data/spec/berkeley_library/tind/export/table_spec.rb +322 -0
- data/spec/berkeley_library/tind/marc/xml_reader_spec.rb +93 -0
- data/spec/berkeley_library/util/arrays_spec.rb +340 -0
- data/spec/berkeley_library/util/ods/spreadsheet_spec.rb +124 -0
- data/spec/berkeley_library/util/ods/xml/content_doc_spec.rb +121 -0
- data/spec/berkeley_library/util/ods/xml/manifest/file_entry_spec.rb +27 -0
- data/spec/berkeley_library/util/ods/xml/manifest/manifest_spec.rb +33 -0
- data/spec/berkeley_library/util/ods/xml/office/document_content_spec.rb +60 -0
- data/spec/berkeley_library/util/ods/xml/style/automatic_styles_spec.rb +37 -0
- data/spec/berkeley_library/util/ods/xml/style/family_spec.rb +57 -0
- data/spec/berkeley_library/util/ods/xml/table/table_row_spec.rb +179 -0
- data/spec/berkeley_library/util/ods/xml/table/table_spec.rb +218 -0
- data/spec/berkeley_library/util/paths_spec.rb +90 -0
- data/spec/berkeley_library/util/stringios_spec.rb +34 -0
- data/spec/berkeley_library/util/strings_spec.rb +27 -0
- data/spec/berkeley_library/util/times_spec.rb +39 -0
- data/spec/berkeley_library/util/uris_spec.rb +118 -0
- data/spec/data/collection-names.txt +438 -0
- data/spec/data/collections.json +4827 -0
- data/spec/data/disjoint-records.xml +187 -0
- data/spec/data/record-184453.xml +58 -0
- data/spec/data/record-184458.xml +63 -0
- data/spec/data/record-187888.xml +78 -0
- data/spec/data/records-api-search-cjk-p1.xml +6381 -0
- data/spec/data/records-api-search-cjk-p2.xml +5 -0
- data/spec/data/records-api-search-p1.xml +4506 -0
- data/spec/data/records-api-search-p2.xml +4509 -0
- data/spec/data/records-api-search-p3.xml +4506 -0
- data/spec/data/records-api-search-p4.xml +4509 -0
- data/spec/data/records-api-search-p5.xml +4506 -0
- data/spec/data/records-api-search-p6.xml +2436 -0
- data/spec/data/records-api-search-p7.xml +5 -0
- data/spec/data/records-api-search.xml +234 -0
- data/spec/data/records-manual-search.xml +547 -0
- data/spec/spec_helper.rb +30 -0
- data/test/profile/table_from_records_profile.rb +46 -0
- metadata +585 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
require 'nokogiri'
|
|
2
|
+
require 'berkeley_library/util/ods/xml/document_node'
|
|
3
|
+
require 'berkeley_library/util/ods/xml/office/document_content'
|
|
4
|
+
|
|
5
|
+
module BerkeleyLibrary
|
|
6
|
+
module Util
|
|
7
|
+
module ODS
|
|
8
|
+
module XML
|
|
9
|
+
class ContentDoc < DocumentNode
|
|
10
|
+
|
|
11
|
+
def initialize
|
|
12
|
+
super('content.xml')
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def root_element_node
|
|
16
|
+
document_content
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def document_content
|
|
20
|
+
@document_content ||= Office::DocumentContent.new(doc: doc)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
require 'nokogiri'
|
|
2
|
+
|
|
3
|
+
module BerkeleyLibrary
|
|
4
|
+
module Util
|
|
5
|
+
module ODS
|
|
6
|
+
module XML
|
|
7
|
+
class DocumentNode
|
|
8
|
+
|
|
9
|
+
ENCODING = 'UTF-8'.freeze
|
|
10
|
+
|
|
11
|
+
attr_reader :path
|
|
12
|
+
|
|
13
|
+
# Initializes a new DocumentNode
|
|
14
|
+
# @param path [String] the path to this document in the container
|
|
15
|
+
def initialize(path)
|
|
16
|
+
@path = path
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def to_xml(out = nil, compact: true)
|
|
20
|
+
return write_xml_to_string(compact: compact) unless out
|
|
21
|
+
return write_xml_to_stream(out, compact: compact) if out.respond_to?(:write)
|
|
22
|
+
|
|
23
|
+
write_xml_to_file(out, compact: compact)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def doc
|
|
27
|
+
@doc ||= Nokogiri::XML::Document.new.tap do |doc|
|
|
28
|
+
doc.encoding = ENCODING
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
private
|
|
33
|
+
|
|
34
|
+
def write_xml_to_stream(out, compact:)
|
|
35
|
+
doc.root ||= root_element_node.element
|
|
36
|
+
if compact
|
|
37
|
+
doc.write_to(out, encoding: ENCODING, save_with: 0)
|
|
38
|
+
else
|
|
39
|
+
doc.write_to(out, encoding: ENCODING)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def write_xml_to_string(compact:)
|
|
44
|
+
StringIO.new.tap do |out|
|
|
45
|
+
out.binmode
|
|
46
|
+
write_xml_to_stream(out, compact: compact)
|
|
47
|
+
end.string
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def write_xml_to_file(path, compact:)
|
|
51
|
+
File.open(path, 'wb') { |f| write_xml_to_stream(f, compact: compact) }
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
require 'nokogiri'
|
|
2
|
+
require 'berkeley_library/util/logging'
|
|
3
|
+
require 'berkeley_library/util/ods/xml/namespace'
|
|
4
|
+
|
|
5
|
+
module BerkeleyLibrary
|
|
6
|
+
module Util
|
|
7
|
+
module ODS
|
|
8
|
+
module XML
|
|
9
|
+
class ElementNode
|
|
10
|
+
include BerkeleyLibrary::Logging
|
|
11
|
+
|
|
12
|
+
# @return [Nokogiri::XML::Document] the document containing this element
|
|
13
|
+
attr_reader :doc
|
|
14
|
+
|
|
15
|
+
# @return [Namespace] the namespace for this element
|
|
16
|
+
attr_reader :namespace
|
|
17
|
+
|
|
18
|
+
# @return [String] the name of this element
|
|
19
|
+
attr_reader :element_name
|
|
20
|
+
|
|
21
|
+
# @param namespace [String, Symbol, Namespace] the element namespace
|
|
22
|
+
# @param element_name [String] the element name
|
|
23
|
+
# @param doc [Nokogiri::XML::Document] the document containing this element
|
|
24
|
+
def initialize(namespace, element_name, doc:)
|
|
25
|
+
@namespace = ensure_namespace(namespace)
|
|
26
|
+
@element_name = element_name
|
|
27
|
+
@doc = doc
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def prefix
|
|
31
|
+
namespace.prefix
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def element
|
|
35
|
+
ensure_element!
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Finalize this XML element and prepare for output.
|
|
39
|
+
def ensure_element!
|
|
40
|
+
@element ||= create_element
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# rubocop:disable Style/OptionalArguments
|
|
44
|
+
def set_attribute(namespace = prefix, name, value)
|
|
45
|
+
attr_name = prefixed_attr_name(namespace, name)
|
|
46
|
+
attributes[attr_name] = value.to_s
|
|
47
|
+
end
|
|
48
|
+
# rubocop:enable Style/OptionalArguments
|
|
49
|
+
|
|
50
|
+
# rubocop:disable Style/OptionalArguments
|
|
51
|
+
def clear_attribute(namespace = prefix, name)
|
|
52
|
+
attr_name = prefixed_attr_name(namespace, name)
|
|
53
|
+
attributes.delete(attr_name)
|
|
54
|
+
end
|
|
55
|
+
# rubocop:enable Style/OptionalArguments
|
|
56
|
+
|
|
57
|
+
def add_child(child)
|
|
58
|
+
raise ArgumentError, "Not text or an element: #{child.inspect}" unless child.is_a?(ElementNode) || child.is_a?(String)
|
|
59
|
+
|
|
60
|
+
child.tap { |c| children << c }
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
protected
|
|
64
|
+
|
|
65
|
+
def prefixed_attr_name(ns, name)
|
|
66
|
+
return "xmlns:#{name}" if ns.to_s == 'xmlns'
|
|
67
|
+
|
|
68
|
+
"#{ensure_namespace(ns).prefix}:#{name}"
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def create_element
|
|
72
|
+
doc.create_element("#{prefix}:#{element_name}", attributes).tap do |element|
|
|
73
|
+
children.each do |child|
|
|
74
|
+
next element.add_child(child.element) if child.is_a?(ElementNode)
|
|
75
|
+
|
|
76
|
+
text_node = doc.create_text_node(child.to_s)
|
|
77
|
+
element.add_child(text_node)
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# @return [Hash<String, String>] the attributes, as a map from name to value
|
|
83
|
+
def attributes
|
|
84
|
+
# noinspection RubyYardReturnMatch
|
|
85
|
+
@attributes ||= {}
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# @return [Array<ElementNode>] the child elements
|
|
89
|
+
# TODO: replace this with :each_child and a protected default array
|
|
90
|
+
def children
|
|
91
|
+
@children ||= []
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
private
|
|
95
|
+
|
|
96
|
+
def ensure_namespace(ns)
|
|
97
|
+
return ns if ns.is_a?(Namespace)
|
|
98
|
+
raise ArgumentError, "Not a recognized namespace: #{ns.inspect}" unless (ns_for_prefix = Namespace.for_prefix(ns.to_s.downcase))
|
|
99
|
+
|
|
100
|
+
ns_for_prefix
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
require 'berkeley_library/util/ods/xml/element_node'
|
|
2
|
+
|
|
3
|
+
module BerkeleyLibrary
|
|
4
|
+
module Util
|
|
5
|
+
module ODS
|
|
6
|
+
module XML
|
|
7
|
+
module LOExt
|
|
8
|
+
class TableProtection < ElementNode
|
|
9
|
+
def initialize(doc:)
|
|
10
|
+
super(:loext, 'table-protection', doc: doc)
|
|
11
|
+
|
|
12
|
+
set_default_attributes!
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
private
|
|
16
|
+
|
|
17
|
+
def set_default_attributes!
|
|
18
|
+
set_attribute('select-protected-cells', 'true')
|
|
19
|
+
set_attribute('select-unprotected-cells', 'true')
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
require 'berkeley_library/util/ods/xml/element_node'
|
|
2
|
+
|
|
3
|
+
module BerkeleyLibrary
|
|
4
|
+
module Util
|
|
5
|
+
module ODS
|
|
6
|
+
module XML
|
|
7
|
+
module Manifest
|
|
8
|
+
class FileEntry < XML::ElementNode
|
|
9
|
+
|
|
10
|
+
attr_reader :full_path
|
|
11
|
+
attr_reader :media_type
|
|
12
|
+
attr_reader :manifest
|
|
13
|
+
|
|
14
|
+
def initialize(full_path, media_type = nil, manifest:)
|
|
15
|
+
super(:manifest, 'file-entry', doc: manifest.doc)
|
|
16
|
+
|
|
17
|
+
@full_path = full_path
|
|
18
|
+
@media_type = media_type || media_type_for(full_path)
|
|
19
|
+
@manifest = manifest
|
|
20
|
+
|
|
21
|
+
set_default_attributes!
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
|
|
26
|
+
def media_type_for(path)
|
|
27
|
+
return 'application/vnd.oasis.opendocument.spreadsheet' if path == '/'
|
|
28
|
+
return 'text/xml' if path.end_with?('.xml')
|
|
29
|
+
|
|
30
|
+
raise ArgumentError, "Can't determine media type for path: #{path.inspect}"
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def set_default_attributes!
|
|
34
|
+
set_attribute('full-path', full_path)
|
|
35
|
+
set_attribute('media-type', media_type)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
require 'berkeley_library/util/ods/xml/element_node'
|
|
2
|
+
require 'berkeley_library/util/ods/xml/manifest/file_entry'
|
|
3
|
+
|
|
4
|
+
module BerkeleyLibrary
|
|
5
|
+
module Util
|
|
6
|
+
module ODS
|
|
7
|
+
module XML
|
|
8
|
+
module Manifest
|
|
9
|
+
class Manifest < XML::ElementNode
|
|
10
|
+
REQUIRED_NAMESPACES = [:manifest].freeze
|
|
11
|
+
MANIFEST_VERSION = '1.2'.freeze
|
|
12
|
+
|
|
13
|
+
def initialize(doc:)
|
|
14
|
+
super(:manifest, 'manifest', doc: doc)
|
|
15
|
+
|
|
16
|
+
set_default_attributes!
|
|
17
|
+
add_file_entry(self_file_entry)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def version
|
|
21
|
+
MANIFEST_VERSION
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Adds a document to the manifest
|
|
25
|
+
# @param doc [XML::DocumentNode] the document to add
|
|
26
|
+
def add_entry_for(doc)
|
|
27
|
+
FileEntry.new(doc.path, manifest: self).tap { |e| add_file_entry(e) }
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def add_child(child)
|
|
31
|
+
return add_file_entry(child) if child.is_a?(FileEntry)
|
|
32
|
+
|
|
33
|
+
child.tap { |c| other_children << c }
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def children
|
|
37
|
+
[file_entries, other_children].flatten
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
private
|
|
41
|
+
|
|
42
|
+
def self_file_entry
|
|
43
|
+
FileEntry.new('/', manifest: self).tap do |entry|
|
|
44
|
+
entry.set_attribute('version', version)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def file_entries
|
|
49
|
+
@file_entries ||= []
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def other_children
|
|
53
|
+
@other_children ||= []
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def required_namespaces
|
|
57
|
+
@required_namespaces ||= REQUIRED_NAMESPACES.map { |p| Namespace.for_prefix(p) }
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def add_file_entry(file_entry)
|
|
61
|
+
file_entry.tap { |fe| file_entries << fe }
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def set_default_attributes!
|
|
65
|
+
required_namespaces.each { |ns| set_attribute(:xmlns, ns.prefix, ns.uri) }
|
|
66
|
+
set_attribute('version', version)
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
require 'nokogiri'
|
|
2
|
+
require 'berkeley_library/util/ods/xml/document_node'
|
|
3
|
+
require 'berkeley_library/util/ods/xml/manifest/manifest'
|
|
4
|
+
|
|
5
|
+
module BerkeleyLibrary
|
|
6
|
+
module Util
|
|
7
|
+
module ODS
|
|
8
|
+
module XML
|
|
9
|
+
class ManifestDoc < DocumentNode
|
|
10
|
+
|
|
11
|
+
def initialize
|
|
12
|
+
super('META-INF/manifest.xml')
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def root_element_node
|
|
16
|
+
manifest
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def manifest
|
|
20
|
+
@manifest ||= Manifest::Manifest.new(doc: doc)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
require 'typesafe_enum'
|
|
2
|
+
|
|
3
|
+
module BerkeleyLibrary
|
|
4
|
+
module Util
|
|
5
|
+
module ODS
|
|
6
|
+
module XML
|
|
7
|
+
|
|
8
|
+
class Namespace < TypesafeEnum::Base
|
|
9
|
+
new :CALCEXT, 'urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0'
|
|
10
|
+
new :CHART, 'urn:oasis:names:tc:opendocument:xmlns:chart:1.0'
|
|
11
|
+
new :DR3D, 'urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0'
|
|
12
|
+
new :FIELD, 'urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0'
|
|
13
|
+
new :FO, 'urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0'
|
|
14
|
+
new :FORM, 'urn:oasis:names:tc:opendocument:xmlns:form:1.0'
|
|
15
|
+
new :LOEXT, 'urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0'
|
|
16
|
+
new :MANIFEST, 'urn:oasis:names:tc:opendocument:xmlns:manifest:1.0'
|
|
17
|
+
new :META, 'urn:oasis:names:tc:opendocument:xmlns:meta:1.0'
|
|
18
|
+
new :OF, 'urn:oasis:names:tc:opendocument:xmlns:of:1.2'
|
|
19
|
+
new :OFFICE, 'urn:oasis:names:tc:opendocument:xmlns:office:1.0'
|
|
20
|
+
new :PRESENTATION, 'urn:oasis:names:tc:opendocument:xmlns:presentation:1.0'
|
|
21
|
+
new :SCRIPT, 'urn:oasis:names:tc:opendocument:xmlns:script:1.0'
|
|
22
|
+
new :STYLE, 'urn:oasis:names:tc:opendocument:xmlns:style:1.0'
|
|
23
|
+
new :SVG, 'urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0'
|
|
24
|
+
new :TABLE, 'urn:oasis:names:tc:opendocument:xmlns:table:1.0'
|
|
25
|
+
new :TEXT, 'urn:oasis:names:tc:opendocument:xmlns:text:1.0'
|
|
26
|
+
|
|
27
|
+
def prefix
|
|
28
|
+
key.to_s.downcase
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def uri
|
|
32
|
+
value
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
class << self
|
|
36
|
+
def for_prefix(prefix)
|
|
37
|
+
@by_prefix ||= Namespace.map { |ns| [ns.prefix, ns] }.to_h
|
|
38
|
+
@by_prefix[prefix.to_s]
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
require 'berkeley_library/util/ods/xml/element_node'
|
|
2
|
+
require 'berkeley_library/util/ods/xml/style/cell_style'
|
|
3
|
+
require 'berkeley_library/util/ods/xml/style/column_style'
|
|
4
|
+
require 'berkeley_library/util/ods/xml/style/row_style'
|
|
5
|
+
require 'berkeley_library/util/ods/xml/style/style'
|
|
6
|
+
require 'berkeley_library/util/ods/xml/style/table_style'
|
|
7
|
+
|
|
8
|
+
module BerkeleyLibrary
|
|
9
|
+
module Util
|
|
10
|
+
module ODS
|
|
11
|
+
module XML
|
|
12
|
+
module Office
|
|
13
|
+
class AutomaticStyles < XML::ElementNode
|
|
14
|
+
# ------------------------------------------------------------
|
|
15
|
+
# Initializer
|
|
16
|
+
|
|
17
|
+
def initialize(doc:)
|
|
18
|
+
super(:office, 'automatic-styles', doc: doc)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# ------------------------------------------------------------
|
|
22
|
+
# Accessors
|
|
23
|
+
|
|
24
|
+
def default_style(family)
|
|
25
|
+
first_style = styles_for_family(family).first
|
|
26
|
+
return first_style if first_style
|
|
27
|
+
|
|
28
|
+
add_default_style(family)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# ------------------------------------------------------------
|
|
32
|
+
# Utility methods
|
|
33
|
+
|
|
34
|
+
# TODO: create a Stylesheet class and move most of this to it
|
|
35
|
+
|
|
36
|
+
# rubocop:disable Style/OptionalBooleanParameter
|
|
37
|
+
def add_cell_style(name = nil, protected = false, color = nil, font_weight: nil, wrap: false)
|
|
38
|
+
name ||= next_name_for(:table_cell)
|
|
39
|
+
add_style(Style::CellStyle.new(name, protected, color, font_weight: font_weight, wrap: wrap, styles: self))
|
|
40
|
+
end
|
|
41
|
+
# rubocop:enable Style/OptionalBooleanParameter
|
|
42
|
+
|
|
43
|
+
def add_column_style(name = nil, width = nil)
|
|
44
|
+
name ||= next_name_for(:table_column)
|
|
45
|
+
add_style(Style::ColumnStyle.new(name, width, styles: self))
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def add_row_style(name = nil, height = nil)
|
|
49
|
+
name ||= next_name_for(:table_row)
|
|
50
|
+
add_style(Style::RowStyle.new(name, height, styles: self))
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def add_table_style(name = nil)
|
|
54
|
+
name ||= next_name_for(:table)
|
|
55
|
+
add_style(Style::TableStyle.new(name, styles: self))
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def add_style(style)
|
|
59
|
+
raise ArgumentError, "Not a style: #{style.inspect}" unless style.is_a?(Style::Style)
|
|
60
|
+
|
|
61
|
+
style.tap { |s| add_or_insert_style(s) }
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# rubocop:disable Style/OptionalBooleanParameter
|
|
65
|
+
def find_cell_style(protected = false, color: nil, font_weight: nil, wrap: false)
|
|
66
|
+
styles_for_family(:table_cell).find { |s| [s.protected?, s.color, s.font_weight, s.wrap?] == [protected, color, font_weight, wrap] }
|
|
67
|
+
end
|
|
68
|
+
# rubocop:enable Style/OptionalBooleanParameter
|
|
69
|
+
|
|
70
|
+
def find_column_style(width = nil)
|
|
71
|
+
w = width || Style::ColumnStyle::DEFAULT_WIDTH
|
|
72
|
+
styles_for_family(:table_column).find { |s| s.width == w }
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def find_row_style(height = nil)
|
|
76
|
+
h = height || Style::RowStyle::DEFAULT_HEIGHT
|
|
77
|
+
styles_for_family(:table_row).find { |s| s.height == h }
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# rubocop:disable Style/OptionalBooleanParameter
|
|
81
|
+
def find_or_create_cell_style(protected = false, color: nil, font_weight: nil, wrap: false)
|
|
82
|
+
existing_style = find_cell_style(protected, color: color, font_weight: font_weight, wrap: wrap)
|
|
83
|
+
return existing_style if existing_style
|
|
84
|
+
|
|
85
|
+
add_cell_style(nil, protected, color, font_weight: font_weight, wrap: wrap)
|
|
86
|
+
end
|
|
87
|
+
# rubocop:enable Style/OptionalBooleanParameter
|
|
88
|
+
|
|
89
|
+
def find_or_create_column_style(width = nil)
|
|
90
|
+
existing_style = find_column_style(width)
|
|
91
|
+
return existing_style if existing_style
|
|
92
|
+
|
|
93
|
+
add_column_style(nil, width)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def find_or_create_row_style(height = nil)
|
|
97
|
+
existing_style = find_row_style(height)
|
|
98
|
+
return existing_style if existing_style
|
|
99
|
+
|
|
100
|
+
add_row_style(nil, height)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# ------------------------------------------------------------
|
|
104
|
+
# Public XML::ElementNode overrides
|
|
105
|
+
|
|
106
|
+
def add_child(child)
|
|
107
|
+
child.is_a?(Style::Style) ? add_style(child) : child.tap { |c| other_children << c }
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# ------------------------------------------------------------
|
|
111
|
+
# Protected methods
|
|
112
|
+
|
|
113
|
+
protected
|
|
114
|
+
|
|
115
|
+
# ----------------------------------------
|
|
116
|
+
# Protected XML::ElementNode overrides
|
|
117
|
+
|
|
118
|
+
def children
|
|
119
|
+
[other_children, Style::Family.map { |f| styles_for_family(f) }].flatten
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def create_element
|
|
123
|
+
Style::Family.each { |f| default_style(f) }
|
|
124
|
+
|
|
125
|
+
super
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# ------------------------------------------------------------
|
|
129
|
+
# Private methods
|
|
130
|
+
|
|
131
|
+
private
|
|
132
|
+
|
|
133
|
+
def add_or_insert_style(s)
|
|
134
|
+
styles = styles_for_family(s.family)
|
|
135
|
+
insert_index = styles.find_index do |s1|
|
|
136
|
+
raise ArgumentError, "A #{s.family} style named #{s.style_name} already exists" if s1.style_name == s.style_name
|
|
137
|
+
|
|
138
|
+
s1 > s
|
|
139
|
+
end
|
|
140
|
+
insert_index ? styles.insert(insert_index, s) : styles << s
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def add_default_style(family)
|
|
144
|
+
f = Style::Family.ensure_family(family)
|
|
145
|
+
return add_cell_style if f == Style::Family::TABLE_CELL
|
|
146
|
+
return add_column_style if f == Style::Family::TABLE_COLUMN
|
|
147
|
+
return add_row_style if f == Style::Family::TABLE_ROW
|
|
148
|
+
return add_table_style if f == Style::Family::TABLE
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def next_name_for(family)
|
|
152
|
+
f = Style::Family.ensure_family(family)
|
|
153
|
+
|
|
154
|
+
max_suffix = styles_for_family(f).inject(0) do |max, s|
|
|
155
|
+
next max unless (n = s.style_name).start_with?(f.prefix)
|
|
156
|
+
next max unless (suffix = n[f.prefix.size..]) =~ /^[0-9]+$/
|
|
157
|
+
|
|
158
|
+
[max, suffix.to_i].max
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
"#{f.prefix}#{max_suffix + 1}"
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def styles_for_family(family)
|
|
165
|
+
(styles_by_family[Style::Family.ensure_family(family)] ||= [])
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
def styles_by_family
|
|
169
|
+
@styles_by_family ||= {}
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
def other_children
|
|
173
|
+
@other_children ||= []
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
end
|