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.
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
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.7
data/.simplecov ADDED
@@ -0,0 +1,8 @@
1
+ require 'simplecov-rcov'
2
+
3
+ SimpleCov.start 'rails' do
4
+ add_filter 'module_info.rb'
5
+ coverage_dir 'artifacts'
6
+ formatter SimpleCov::Formatter::RcovFormatter
7
+ minimum_coverage 100
8
+ end
data/.yardopts ADDED
@@ -0,0 +1 @@
1
+ --no-private --protected lib/**/*.rb -m markdown
data/CHANGES.md ADDED
@@ -0,0 +1,58 @@
1
+ # 0.4.0 (2021-08-19)
2
+
3
+ - Rename to `BerkeleyLibrary::TIND` in prep for move to GitHub
4
+
5
+ # 0.3.3 (2021-08-05)
6
+
7
+ - Send a custom `User-Agent` header to deal with new TIND firewall rules.
8
+
9
+ # 0.3.2 (2021-07-29)
10
+
11
+ - Loosen `spec.required_ruby_version` to support Ruby 3.x
12
+
13
+ # 0.3.1 (2021-05-17)
14
+
15
+ - `API#get` now raises an `APIException` with a simulated '404 Not Found'
16
+ status if `UCBLIT::TIND::Config.base_uri` is not set, or is blank.
17
+
18
+ # 0.3.0 (2021-05-11)
19
+
20
+ - Extracts `MARCExtensions` into a separate gem,
21
+ [`ucblit-marc`](https://git.lib.berkeley.edu/lap/ucblit-marc/edit).
22
+
23
+ # 0.2.4 (2021-05-06)
24
+
25
+ - `API#get` now raises an `APIException` with a simulated '401 Unauthorized' status
26
+ if `UCBLIT::TIND::Config.api_key` is not set.
27
+
28
+ # 0.2.3 (2021-05-04)
29
+
30
+ - `UCBLIT::TIND::Export`:
31
+ - new method `#exporter_for` returns a `UCBLIT::TIND::Exporter` but doesn't
32
+ export immediately.
33
+ - `#export` now raises `NoResultsError` if no records are returned.
34
+
35
+ - `UCBLIT::TIND::Exporter` exposes an `any_results?` method that returns false if
36
+ there are no results to export.
37
+
38
+ # 0.2.2 (2021-05-03)
39
+
40
+ - `UCBLIT::TIND::API::Search` now gracefully returns an empty result when it gets the 500 Internal
41
+ Server Error that TIND thinks is an acceptable empty search result, instead of raising an exception.
42
+
43
+ # 0.2.1 (2021-04-02)
44
+
45
+ - `bin/tind-export` script now supports passing an environment file on the command line with the
46
+ `-e` option; `-e` with no arguments reads from `.env` in the current working directory.
47
+ - Table metrics (font size, line height, max column width etc.) can now be customized
48
+ with environment variables (see [`UCBLIT::TIND::Export::Config`](lib/berkeley_library/tind/export/config.rb))
49
+
50
+ # 0.2.0 (2021-03-31)
51
+
52
+ - Columns in exported OpenOffice / LibreOffice that should not be edited are now marked
53
+ in red but **not** protected.
54
+ - API key configuration has moved from `UCBLIT::TIND::API` to `UCBLIT::TIND::Config`.
55
+
56
+ # 0.1.0 (2021-03-12)
57
+
58
+ - Initial prerelease
data/Dockerfile ADDED
@@ -0,0 +1,57 @@
1
+ # =============================================================================
2
+ # Target: base
3
+
4
+ FROM ruby:2.7-alpine AS base
5
+
6
+ RUN apk --no-cache --update upgrade && \
7
+ apk --no-cache add \
8
+ bash \
9
+ ca-certificates \
10
+ git \
11
+ libc6-compat \
12
+ openssl \
13
+ tzdata \
14
+ xz-libs \
15
+ && rm -rf /var/cache/apk/*
16
+
17
+ WORKDIR /opt/app
18
+
19
+ # =============================================================================
20
+ # Target: development
21
+ #
22
+
23
+ FROM base AS development
24
+
25
+ # Install system packages needed to build gems with C extensions.
26
+ RUN apk --update --no-cache add \
27
+ build-base \
28
+ coreutils \
29
+ git \
30
+ && rm -rf /var/cache/apk/*
31
+
32
+ # The base image ships bundler 1.17.2, but we want something more recent
33
+ RUN gem install bundler -v 2.1.4
34
+
35
+ # Copy codebase to WORKDIR. Unlike application projects, for a gem project
36
+ # we need to do this before running `bundle install`, in order for the gem
37
+ # we're building to be able to "install" itself.
38
+ COPY . .
39
+
40
+ # Install gems.
41
+ RUN bundle install --path=/usr/local/bundle
42
+
43
+ # =============================================================================
44
+ # Target: production
45
+
46
+ FROM base AS production
47
+
48
+ # Copy the built codebase from the dev stage
49
+ COPY --from=development /opt/app /opt/app
50
+ COPY --from=development /usr/local/bundle /usr/local/bundle
51
+
52
+ # Sanity-check that everything was installed correctly and still runs in the
53
+ # slimmed-down production image.
54
+ RUN bundle config set deployment 'true'
55
+ RUN bundle install --local --path=/usr/local/bundle
56
+
57
+ CMD ['bundle', 'exec', 'rake']
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/Jenkinsfile ADDED
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env groovy
2
+
3
+ dockerComposePipeline(
4
+ commands: [
5
+ 'bundle exec rake coverage',
6
+ 'bundle exec rake rubocop',
7
+ 'bundle exec rake bundle:audit',
8
+ 'bundle exec rake gem'
9
+ ],
10
+ artifacts: [
11
+ junit: 'artifacts/rspec/**/*.xml',
12
+ html : [
13
+ 'Code Coverage': 'artifacts/rcov',
14
+ 'RuboCop' : 'artifacts/rubocop'
15
+ ],
16
+ raw : ['artifacts/**/*.gem']
17
+ ]
18
+ )
data/LICENSE.md ADDED
@@ -0,0 +1,21 @@
1
+ # The MIT License (MIT)
2
+
3
+ Copyright © 2021 The Regents of the University of California
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a
6
+ copy of this software and associated documentation files (the “Software”),
7
+ to deal in the Software without restriction, including without limitation
8
+ the rights to use, copy, modify, merge, publish, distribute, sublicense,
9
+ and/or sell copies of the Software, and to permit persons to whom the
10
+ Software is furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21
+ DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,73 @@
1
+ # BerkeleyLibrary::TIND
2
+
3
+ [![Build Status](https://github.com/BerkeleyLibrary/tind/actions/workflows/build.yml/badge.svg?branch=main)](https://github.com/BerkeleyLibrary/tind/actions/workflows/build.yml)
4
+ [![Gem Version](https://img.shields.io/gem/v/berkeley_library-tind.svg)](https://github.com/BerkeleyLibrary/tind/releases)
5
+
6
+ Utility gem for working with the TIND DA digital archive.
7
+
8
+ ## Configuration
9
+
10
+ To access the TIND API, you will need to set:
11
+
12
+ 1. the base URL for your TIND installation (e.g. `https://digicoll.lib.berkeley.edu/`)
13
+ 2. the TIND API key (see the "[API Token Generator](https://docs.tind.io/article/2xaplzx9cn-api-token-generator)"
14
+ article on [`docs.tind.io`](https://docs.tind.io). TIND's code and
15
+ docs are inconsistent in their use of "token" and "key". The UI calls
16
+ it a "key", so that's the term we use here.)
17
+
18
+ These can be set directly, via accessors in the `BerkeleyLibrary::TIND::Config` module;
19
+ if they are not set, a value will be read from the environment, and if no
20
+ value is present in the environment and Rails is loaded, from the Rails
21
+ application configuration (`Rails.application.config`).
22
+
23
+ | Value | Config | ENV | Rails |
24
+ | --- | --- | --- | --- |
25
+ | TIND base URI | `:base_uri` | `LIT_TIND_BASE_URL` | `:tind_base_uri` |
26
+ | API key | `:api_key` | `LIT_TIND_API_KEY` | `:tind_api_key` |
27
+
28
+ **Note:** The TIND base URI can be set either as a string or as a `URI`
29
+ object, but will always be returned as a `URI` object, and an invalid
30
+ string setting will raise `URI::InvalidURIError`.
31
+
32
+ ## Command-line tool: `tind-export`
33
+
34
+ The `tind-export` command allows you to list TIND collections, or to
35
+ export a TIND collection from the command line. (If the gem is installed,
36
+ `tind-export` should be in your `$PATH`. If you've cloned the gem source,
37
+ you can invoke it with `bin/tind-export` from the project root directory.)
38
+
39
+ Examples:
40
+
41
+ 1. list collections
42
+
43
+ ```sh
44
+ tind-export --list-collections
45
+ ```
46
+
47
+ 2. export a collection as an OpenOffice/LibreOffice spreadsheet
48
+
49
+ ```sh
50
+ tind-export -o lincoln-papers.ods 'Abraham Lincoln Papers'
51
+ ```
52
+
53
+ 3. export a collection as an OpenOffice/LibreOffice spreadsheet in exploded XML format,
54
+ where `lincoln-papers` is a directory
55
+
56
+ ```sh
57
+ tind-export -f ODS -o lincoln-papers 'Abraham Lincoln Papers'
58
+ ```
59
+
60
+ (Note that OpenOffice itself and many other tools get confused by the extra text
61
+ nodes in the pretty-printed files and won't read them properly; this feature
62
+ is mostly for debugging.)
63
+
64
+ 4. export a collection as CSV, to standard output
65
+
66
+ ```sh
67
+ tind-export -f CSV 'Abraham Lincoln Papers'
68
+ ```
69
+
70
+ For the full list of options, type `tind-export --help`. Note that you can set
71
+ the TIND base URL and API key either via the environment, as above, or as options
72
+ passed to the `tind-export` command. If both an explicit option and an environment
73
+ variable are set for either, the explicit option takes precedence.
data/Rakefile ADDED
@@ -0,0 +1,20 @@
1
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('Gemfile', __dir__)
2
+ require 'bundler/setup' # Set up gems listed in the Gemfile.
3
+
4
+ # ------------------------------------------------------------
5
+ # Application code
6
+
7
+ File.expand_path('lib', __dir__).tap do |lib|
8
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
9
+ end
10
+
11
+ # ------------------------------------------------------------
12
+ # CI
13
+
14
+ ENV['RAILS_ENV'] = 'test' if ENV['CI']
15
+
16
+ # ------------------------------------------------------------
17
+ # Custom tasks
18
+
19
+ desc 'Run tests, check test coverage, check code style, check for vulnerabilities, build gem'
20
+ task default: %i[coverage rubocop bundle:audit gem]
@@ -0,0 +1,50 @@
1
+ File.expand_path('lib', __dir__).tap do |lib|
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ end
4
+
5
+ ruby_version = '>= 2.7'
6
+
7
+ require 'berkeley_library/tind/module_info'
8
+
9
+ Gem::Specification.new do |spec|
10
+ spec.name = BerkeleyLibrary::TIND::ModuleInfo::NAME
11
+ spec.author = BerkeleyLibrary::TIND::ModuleInfo::AUTHOR
12
+ spec.email = BerkeleyLibrary::TIND::ModuleInfo::AUTHOR_EMAIL
13
+ spec.summary = BerkeleyLibrary::TIND::ModuleInfo::SUMMARY
14
+ spec.description = BerkeleyLibrary::TIND::ModuleInfo::DESCRIPTION
15
+ spec.license = BerkeleyLibrary::TIND::ModuleInfo::LICENSE
16
+ spec.version = BerkeleyLibrary::TIND::ModuleInfo::VERSION
17
+ spec.homepage = BerkeleyLibrary::TIND::ModuleInfo::HOMEPAGE
18
+
19
+ spec.files = `git ls-files -z`.split("\x0")
20
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
21
+ spec.require_paths = ['lib']
22
+ spec.executables << 'tind-export'
23
+
24
+ spec.required_ruby_version = ruby_version
25
+
26
+ spec.add_dependency 'berkeley_library-logging', '~> 0.2'
27
+ spec.add_dependency 'berkeley_library-marc', '~> 0.2'
28
+ spec.add_dependency 'ice_nine', '~> 0.11'
29
+ spec.add_dependency 'marc', '~> 1.0'
30
+ spec.add_dependency 'rchardet', '~> 1.8'
31
+ spec.add_dependency 'rest-client', '~> 2.1'
32
+ spec.add_dependency 'rubyzip', '~> 2.3'
33
+ spec.add_dependency 'typesafe_enum', '~> 0.3'
34
+
35
+ spec.add_development_dependency 'bundle-audit', '~> 0.1'
36
+ spec.add_development_dependency 'ci_reporter_rspec', '~> 1.0'
37
+ spec.add_development_dependency 'colorize', '~> 0.8'
38
+ spec.add_development_dependency 'dotenv', '~> 2.7'
39
+ spec.add_development_dependency 'listen', '>= 3.0.5', '< 3.2'
40
+ spec.add_development_dependency 'rake', '~> 13.0'
41
+ spec.add_development_dependency 'roo', '~> 2.8'
42
+ spec.add_development_dependency 'rspec', '~> 3.10'
43
+ spec.add_development_dependency 'rubocop', '= 1.11'
44
+ spec.add_development_dependency 'rubocop-rake', '~> 0.5'
45
+ spec.add_development_dependency 'rubocop-rspec', '~> 2.2'
46
+ spec.add_development_dependency 'ruby-prof', '~> 0.17.0'
47
+ spec.add_development_dependency 'simplecov', '~> 0.21'
48
+ spec.add_development_dependency 'simplecov-rcov', '~> 0.2'
49
+ spec.add_development_dependency 'webmock', '~> 3.12'
50
+ end
data/bin/tind-export ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ begin
4
+ # This should work if (1) the gem is installed, or
5
+ # (2) we're in development and used `bundle exec`
6
+ require 'berkeley_library/tind'
7
+ rescue LoadError
8
+ # If we're in development, `require 'bundler/setup'`
9
+ # is roughly equivalent to `bundle exec`
10
+ require 'bundler/setup'
11
+ require 'berkeley_library/tind'
12
+ end
13
+
14
+ BerkeleyLibrary::TIND::Export::ExportCommand.new(*ARGV).execute!
@@ -0,0 +1,15 @@
1
+ services:
2
+ gem:
3
+ build:
4
+ context: .
5
+ target: development
6
+ ports:
7
+ - target: 3000
8
+ published: 3000
9
+ restart: always
10
+ volumes:
11
+ # Note that this mounts the *entire* repo directory (including
12
+ # files ignored in .dockerignore when building the image)
13
+ - ./:/opt/app
14
+
15
+ version: "3.7"
@@ -0,0 +1,3 @@
1
+ require 'marc_extensions'
2
+
3
+ Dir.glob(File.expand_path('tind/*.rb', __dir__)).sort.each(&method(:require))
@@ -0,0 +1 @@
1
+ Dir.glob(File.expand_path('api/*.rb', __dir__)).sort.each(&method(:require))
@@ -0,0 +1,132 @@
1
+ require 'stringio'
2
+ require 'open-uri'
3
+
4
+ require 'berkeley_library/util/uris'
5
+ require 'berkeley_library/util/logging'
6
+ require 'berkeley_library/tind/config'
7
+ require 'berkeley_library/tind/api/api_exception'
8
+
9
+ module BerkeleyLibrary
10
+ module TIND
11
+ module API
12
+ class << self
13
+ include BerkeleyLibrary::Util
14
+ include BerkeleyLibrary::Logging
15
+
16
+ # Gets the TIND API key.
17
+ # @return [String, nil] the TIND API key, or `nil` if not set.
18
+ def api_key
19
+ BerkeleyLibrary::TIND::Config.api_key
20
+ end
21
+
22
+ # Gets the value to send in the User-Agent header
23
+ # @return [String] the user agent
24
+ def user_agent
25
+ BerkeleyLibrary::TIND::Config.user_agent
26
+ end
27
+
28
+ # Gets the API base URI.
29
+ # @return [URI] the API base URI
30
+ def api_base_uri
31
+ return if Config.blank?((base_uri = Config.base_uri))
32
+
33
+ URIs.append(base_uri, '/api/v1')
34
+ end
35
+
36
+ # Gets the URI for the specified API endpoint.
37
+ # @param endpoint [Symbol, String] the endpoint (e.g. `:search` or `:collection`)
38
+ # @return [URI] the URI for the specified endpoint
39
+ # @raise [API::BaseURINotSet] if the TIND base URI is not set
40
+ def uri_for(endpoint)
41
+ return if Config.blank?(api_base_uri)
42
+
43
+ URIs.append(api_base_uri, endpoint)
44
+ end
45
+
46
+ # Makes a GET request.
47
+ #
48
+ # @overload get(endpoint, **params)
49
+ # Makes a GET request to the specified endpoint with the specified parameters,
50
+ # and returns the response body as a string. Example:
51
+ #
52
+ # ```ruby
53
+ # marc_xml = API.get(:search, c: 'The Bancroft Library')
54
+ # XMLReader.new(marc_xml).each { |record| ... }
55
+ # ```
56
+ #
57
+ # @param endpoint [Symbol] the API endpoint, e.g. `:search` or `:collection`
58
+ # @param **params [Hash] the query parameters
59
+ # @return [String] the response body
60
+ # @overload get(endpoint, **params, &block)
61
+ # Makes a GET request to the specified endpoint with the specified parameters,
62
+ # and yields an `IO` that streams the response body. Example:
63
+ #
64
+ # ```ruby
65
+ # API.get(:search, c: 'The Bancroft Library') do |body|
66
+ # XMLReader.new(body).each { |record| ... }
67
+ # end
68
+ # ```
69
+ #
70
+ # @param endpoint [Symbol, String] the API endpoint, e.g. `:search` or `:collections`
71
+ # @param **params [Hash] the query parameters
72
+ # @yieldparam body [IO] the response body, as an IO stream
73
+ def get(endpoint, **params, &block)
74
+ endpoint_uri = uri_for(endpoint)
75
+ raise BaseURINotSet.new(endpoint, params) if Config.blank?(endpoint_uri)
76
+
77
+ logger.debug(format_request(endpoint_uri, params))
78
+
79
+ body = do_get(endpoint_uri, params)
80
+ return body unless block_given?
81
+
82
+ stream_response_body(body, &block)
83
+ end
84
+
85
+ # Returns a formatted string version of the request, suitable for
86
+ # logging or error messages.
87
+ #
88
+ # @param uri [URI, String] the URI
89
+ # @param params [Hash, nil] the query parameters
90
+ # @param method [String] the request method
91
+ def format_request(uri, params = nil, method = 'GET')
92
+ query_string = format_query(params)
93
+ uri = URIs.append(uri, '?', query_string) if query_string
94
+
95
+ "#{method} #{uri}"
96
+ end
97
+
98
+ def format_query(params)
99
+ return unless params
100
+ return URI.encode_www_form(params.to_hash) if params.respond_to?(:to_hash)
101
+
102
+ raise ArgumentError, "Argument #{params.inspect} does not appear to be a set of query parameters"
103
+ end
104
+
105
+ private
106
+
107
+ def do_get(endpoint_uri, params)
108
+ raise APIKeyNotSet.new(endpoint_uri, params) if Config.blank?(api_key)
109
+
110
+ begin
111
+ URIs.get(endpoint_uri, params, {
112
+ 'Authorization' => "Token #{api_key}",
113
+ 'User-Agent' => user_agent
114
+ })
115
+ rescue RestClient::RequestFailed => e
116
+ raise APIException.wrap(e, url: endpoint_uri, params: params)
117
+ end
118
+ end
119
+
120
+ # TODO: make real body streaming work
121
+ def stream_response_body(body)
122
+ yield StringIO.new(body)
123
+ rescue StandardError => e
124
+ # We don't log the full stack trace here as we assume the block will do that
125
+ logger.warn("Error yielding response body: #{e}: body was: #{body}")
126
+ raise
127
+ end
128
+ end
129
+
130
+ end
131
+ end
132
+ end