berkeley_library-tind 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|