sul_orcid_client 0.1.0 → 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0b75e419476e1943481450cb767b3f580fb25a16c4ca96cde068cd1176000972
4
- data.tar.gz: 784a82cb26eaa7f27137bf108a47e4c5d9584588e8c9b98dcabd2902674d7fc1
3
+ metadata.gz: 94e61c08976837c4f5fc946beca72656f4443258eace1a0c22c0d40884cb6e10
4
+ data.tar.gz: 8186d27f99e87462626a57aaa858abd33b8746615fde51148a2a9a3db76b67b1
5
5
  SHA512:
6
- metadata.gz: 0e47f1d153ae2dd5afcc676daf545f541d3e4c05ca9e89b0233f8ef1ef9bab896bbc6db6cb8a93c3f311de2fcecf2a48cfeb24cd7eb96e68ac2c587af742401c
7
- data.tar.gz: e7390bd10097109537407e1ce9550a58e85213a066b8bf41280e6bf8c23c23c00d7b1e27953ae17f096f6da3aa0c365cb6a62d9e2cba59bf906983691f29357b
6
+ metadata.gz: 1a814db636b2df5ee2294fac3e1303b63d43a868ad4a044a93f9c27e7f7b300a8eeb00b596cc10d6eefa6ac10433a7ceb989c16fccb92b0f3c9f00ec986af979
7
+ data.tar.gz: eebc8350317753b68e6cd0d748f90710f4cf7bf50d716d97cadb7021faa1484884d5e6970c62a8b9da025ecee955539152a1908d6a2397273f89af9cc052d500
data/.rubocop/custom.yml CHANGED
@@ -53,5 +53,33 @@ RSpec/MultipleExpectations:
53
53
  Enabled: false
54
54
  RSpec/ExampleLength:
55
55
  Enabled: false
56
-
57
-
56
+ Capybara/MatchStyle: # new in 2.17
57
+ Enabled: true
58
+ FactoryBot/AssociationStyle: # new in 2.23
59
+ Enabled: true
60
+ FactoryBot/FactoryAssociationWithStrategy: # new in 2.23
61
+ Enabled: true
62
+ FactoryBot/FactoryNameStyle: # new in 2.16
63
+ Enabled: true
64
+ FactoryBot/RedundantFactoryOption: # new in 2.23
65
+ Enabled: true
66
+ RSpec/BeEmpty: # new in 2.20
67
+ Enabled: true
68
+ RSpec/ContainExactly: # new in 2.19
69
+ Enabled: true
70
+ RSpec/DuplicatedMetadata: # new in 2.16
71
+ Enabled: true
72
+ RSpec/IndexedLet: # new in 2.20
73
+ Enabled: true
74
+ RSpec/MatchArray: # new in 2.19
75
+ Enabled: true
76
+ RSpec/PendingWithoutReason: # new in 2.16
77
+ Enabled: true
78
+ RSpec/RedundantAround: # new in 2.19
79
+ Enabled: true
80
+ RSpec/SkipBlockInsideExample: # new in 2.19
81
+ Enabled: true
82
+ RSpec/Rails/MinitestAssertions: # new in 2.17
83
+ Enabled: true
84
+ RSpec/Rails/TravelAround: # new in 2.19
85
+ Enabled: true
data/.rubocop.yml CHANGED
@@ -4,6 +4,8 @@ inherit_mode:
4
4
 
5
5
  require:
6
6
  - standard
7
+ - standard-custom
8
+ - standard-performance
7
9
  - rubocop-performance
8
10
  - rubocop-rspec
9
11
 
data/Gemfile.lock CHANGED
@@ -1,8 +1,9 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- sul_orcid_client (0.1.0)
4
+ sul_orcid_client (0.2.0)
5
5
  activesupport (>= 4.2, < 8)
6
+ cocina-models (~> 0.90)
6
7
  faraday
7
8
  faraday-retry
8
9
  oauth2
@@ -19,12 +20,54 @@ GEM
19
20
  addressable (2.8.4)
20
21
  public_suffix (>= 2.0.2, < 6.0)
21
22
  ast (2.4.2)
23
+ attr_extras (7.1.0)
22
24
  byebug (11.1.3)
25
+ cocina-models (0.90.0)
26
+ activesupport
27
+ deprecation
28
+ dry-struct (~> 1.0)
29
+ dry-types (~> 1.1)
30
+ edtf
31
+ equivalent-xml
32
+ jsonpath
33
+ nokogiri
34
+ openapi3_parser
35
+ openapi_parser (>= 0.11.1, < 1.0)
36
+ rss
37
+ super_diff
38
+ thor
39
+ zeitwerk (~> 2.1)
40
+ commonmarker (0.23.9)
23
41
  concurrent-ruby (1.2.2)
24
42
  crack (0.4.5)
25
43
  rexml
44
+ deprecation (1.1.0)
45
+ activesupport
26
46
  diff-lcs (1.5.0)
27
47
  docile (1.4.0)
48
+ dry-core (1.0.0)
49
+ concurrent-ruby (~> 1.0)
50
+ zeitwerk (~> 2.6)
51
+ dry-inflector (1.0.0)
52
+ dry-logic (1.5.0)
53
+ concurrent-ruby (~> 1.0)
54
+ dry-core (~> 1.0, < 2)
55
+ zeitwerk (~> 2.6)
56
+ dry-struct (1.6.0)
57
+ dry-core (~> 1.0, < 2)
58
+ dry-types (>= 1.7, < 2)
59
+ ice_nine (~> 0.11)
60
+ zeitwerk (~> 2.6)
61
+ dry-types (1.7.1)
62
+ concurrent-ruby (~> 1.0)
63
+ dry-core (~> 1.0)
64
+ dry-inflector (~> 1.0)
65
+ dry-logic (~> 1.4)
66
+ zeitwerk (~> 2.6)
67
+ edtf (3.1.1)
68
+ activesupport (>= 3.0, < 8.0)
69
+ equivalent-xml (0.6.0)
70
+ nokogiri (>= 1.4.3)
28
71
  faraday (2.7.10)
29
72
  faraday-net_http (>= 2.0, < 3.1)
30
73
  ruby2_keywords (>= 0.0.4)
@@ -35,12 +78,20 @@ GEM
35
78
  hashie (5.0.0)
36
79
  i18n (1.14.1)
37
80
  concurrent-ruby (~> 1.0)
81
+ ice_nine (0.11.2)
38
82
  json (2.6.3)
83
+ jsonpath (1.1.3)
84
+ multi_json
39
85
  jwt (2.7.1)
40
86
  language_server-protocol (3.17.0.3)
41
87
  lint_roller (1.1.0)
42
88
  minitest (5.18.1)
89
+ multi_json (1.15.0)
43
90
  multi_xml (0.6.0)
91
+ nokogiri (1.15.3-x86_64-darwin)
92
+ racc (~> 1.4)
93
+ nokogiri (1.15.3-x86_64-linux)
94
+ racc (~> 1.4)
44
95
  oauth2 (2.0.9)
45
96
  faraday (>= 0.17.3, < 3.0)
46
97
  jwt (>= 1.0, < 3.0)
@@ -48,10 +99,16 @@ GEM
48
99
  rack (>= 1.2, < 4)
49
100
  snaky_hash (~> 2.0)
50
101
  version_gem (~> 1.1)
102
+ openapi3_parser (0.9.2)
103
+ commonmarker (~> 0.17)
104
+ openapi_parser (0.15.0)
105
+ optimist (3.0.1)
51
106
  parallel (1.23.0)
52
107
  parser (3.2.2.3)
53
108
  ast (~> 2.4.1)
54
109
  racc
110
+ patience_diff (1.2.0)
111
+ optimist (~> 3.0)
55
112
  public_suffix (5.0.3)
56
113
  racc (1.7.1)
57
114
  rack (3.0.8)
@@ -72,6 +129,8 @@ GEM
72
129
  diff-lcs (>= 1.2.0, < 2.0)
73
130
  rspec-support (~> 3.12.0)
74
131
  rspec-support (3.12.1)
132
+ rss (0.2.9)
133
+ rexml
75
134
  rubocop (1.52.1)
76
135
  json (~> 2.3)
77
136
  parallel (~> 1.10)
@@ -106,17 +165,23 @@ GEM
106
165
  snaky_hash (2.0.1)
107
166
  hashie
108
167
  version_gem (~> 1.1, >= 1.1.1)
109
- standard (1.29.0)
168
+ standard (1.30.1)
110
169
  language_server-protocol (~> 3.17.0.2)
111
170
  lint_roller (~> 1.0)
112
171
  rubocop (~> 1.52.0)
113
172
  standard-custom (~> 1.0.0)
114
173
  standard-performance (~> 1.1.0)
115
- standard-custom (1.0.1)
174
+ standard-custom (1.0.2)
116
175
  lint_roller (~> 1.0)
176
+ rubocop (~> 1.50)
117
177
  standard-performance (1.1.1)
118
178
  lint_roller (~> 1.1)
119
179
  rubocop-performance (~> 1.18.0)
180
+ super_diff (0.10.0)
181
+ attr_extras (>= 6.2.4)
182
+ diff-lcs
183
+ patience_diff
184
+ thor (1.2.2)
120
185
  tzinfo (2.0.6)
121
186
  concurrent-ruby (~> 1.0)
122
187
  unicode-display_width (2.4.2)
@@ -138,7 +203,7 @@ DEPENDENCIES
138
203
  rspec (~> 3.0)
139
204
  rubocop-rspec
140
205
  simplecov
141
- standard (~> 1.29.0)
206
+ standard
142
207
  sul_orcid_client!
143
208
  vcr
144
209
  webmock
data/README.md CHANGED
@@ -1,8 +1,12 @@
1
1
  [![Gem Version](https://badge.fury.io/rb/sul_orcid_client.svg)](https://badge.fury.io/rb/sul_orcid_client)
2
2
  [![CircleCI](https://dl.circleci.com/status-badge/img/gh/sul-dlss/orcid_client/tree/main.svg?style=svg)](https://dl.circleci.com/status-badge/redirect/gh/sul-dlss/orcid_client/tree/main)
3
+ [![Maintainability](https://api.codeclimate.com/v1/badges/5f53521299eeec2f9346/maintainability)](https://codeclimate.com/github/sul-dlss/orcid_client/maintainability)
4
+ [![Test Coverage](https://api.codeclimate.com/v1/badges/5f53521299eeec2f9346/test_coverage)](https://codeclimate.com/github/sul-dlss/orcid_client/test_coverage)
3
5
 
4
- # sul_orcid_client
5
- API client for accessing ORCID API.
6
+ # orcid_client
7
+ API client for accessing ORCID API and for mapping to ORCID works.
8
+
9
+ Note: the *gem* name is `sul_orcid_client`; the git repo's name is `orcid_client`.
6
10
 
7
11
  ## Installation
8
12
 
@@ -0,0 +1,89 @@
1
+ class SulOrcidClient
2
+ # Maps a Cocina Contributor to an Orcid Contributor.
3
+
4
+ class ContributorMapper
5
+ def self.map(contributor:)
6
+ new(contributor: contributor).map
7
+ end
8
+
9
+ # @param [Cocina::Models::Contributor] contributor to map
10
+ def initialize(contributor:)
11
+ @contributor = contributor
12
+ end
13
+
14
+ def map
15
+ return unless cited?
16
+
17
+ {
18
+ "credit-name": map_credit_name,
19
+ "contributor-orcid": map_orcid,
20
+ "contributor-attributes": map_attributes
21
+ }.compact
22
+ end
23
+
24
+ private
25
+
26
+ attr_reader :contributor
27
+
28
+ def cited?
29
+ contributor.note.none? { |note| note.type == "citation status" && note.value == "false" }
30
+ end
31
+
32
+ def map_credit_name
33
+ value = if contributor.name.first&.structuredValue.present?
34
+ name_from_structured_value(contributor.name.first.structuredValue)
35
+ else
36
+ contributor.name.first&.value
37
+ end
38
+
39
+ return unless value
40
+
41
+ {
42
+ value: value
43
+ }
44
+ end
45
+
46
+ def name_from_structured_value(structured_value)
47
+ forename = structured_value.find { |name_part| name_part.type == "forename" }&.value
48
+ surname = structured_value.find { |name_part| name_part.type == "surname" }&.value
49
+ [forename, surname].join(" ")
50
+ end
51
+
52
+ def map_orcid
53
+ identifier = contributor.identifier.find { |identifier| ["ORCID", "ROR"].include?(identifier.type) }
54
+
55
+ return unless identifier
56
+
57
+ {
58
+ uri: URI.join(identifier.source.uri, identifier.value).to_s,
59
+ path: identifier.value,
60
+ host: (identifier.type == "ORCID") ? "orcid.org" : "ror.org"
61
+ }
62
+ end
63
+
64
+ def map_attributes
65
+ {
66
+ "contributor-role": map_role
67
+ }.compact.presence
68
+ end
69
+
70
+ MARC_RELATOR_MAP = {
71
+ "aut" => "Author",
72
+ "cmp" => "Author",
73
+ "ctb" => "Author",
74
+ "cre" => "Author",
75
+ "edt" => "Editor",
76
+ "rth" => "Principal investigator"
77
+ }
78
+
79
+ def map_role
80
+ role = contributor.role.find do |role|
81
+ role.source&.code == "marcrelator" && MARC_RELATOR_MAP.key?(role.code)
82
+ end
83
+
84
+ return unless role
85
+
86
+ MARC_RELATOR_MAP[role.code]
87
+ end
88
+ end
89
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class SulOrcidClient
4
- VERSION = "0.1.0"
4
+ VERSION = "0.2.0"
5
5
  end
@@ -0,0 +1,176 @@
1
+ class SulOrcidClient
2
+ # Maps a Cocina Description to an Orcid Work.
3
+
4
+ # Note that this mapping is currently based on a description generated
5
+ # from an H2 work. However, it could be extended to more completely map descriptions.
6
+ class WorkMapper
7
+ # Error raised by WorkMapper
8
+ class WorkMapperError < StandardError; end
9
+
10
+ def self.map(description:, doi: nil)
11
+ new(description: description, doi: doi).map
12
+ end
13
+
14
+ # @param [Cocina::Models::Description] description to map
15
+ # @param [String] doi from identification.doi
16
+ def initialize(description:, doi: nil)
17
+ @description = description
18
+ @doi = doi
19
+ end
20
+
21
+ def map
22
+ {
23
+ title: map_title,
24
+ "short-description": map_short_description,
25
+ citation: map_citation,
26
+ type: map_type,
27
+ "publication-date": map_publication_date,
28
+ "external-ids": map_external_ids,
29
+ url: description.purl,
30
+ contributors: map_contributors,
31
+ "language-code": "en",
32
+ country: {
33
+ value: "US"
34
+ }
35
+ }.compact
36
+ end
37
+
38
+ private
39
+
40
+ attr_reader :description, :doi
41
+
42
+ def map_title
43
+ title = description.title.first&.value
44
+ raise WorkMapperError, "Title not mapped" unless title
45
+
46
+ {
47
+ title: {
48
+ value: title.truncate(500) # ORCID has a max length for this field
49
+ }
50
+ }
51
+ end
52
+
53
+ def map_short_description
54
+ description.note.find { |note| note.type == "abstract" }&.value
55
+ end
56
+
57
+ def map_citation
58
+ citation = description.note.find { |note| note.type == "preferred citation" }&.value
59
+ return unless citation
60
+
61
+ {
62
+ "citation-type": "formatted-unspecified",
63
+ "citation-value": citation
64
+ }
65
+ end
66
+
67
+ def map_external_ids
68
+ {"external-id":
69
+ [
70
+ map_external_id("uri", description.purl, description.purl)
71
+ ].tap do |ids|
72
+ ids << map_external_id("doi", doi, "https://doi.org/#{doi}") if doi
73
+ end}
74
+ end
75
+
76
+ def map_external_id(type, value, url)
77
+ {
78
+ "external-id-type": type,
79
+ "external-id-value": value,
80
+ "external-id-url": {
81
+ value: url
82
+ },
83
+ "external-id-relationship": "self"
84
+ }
85
+ end
86
+
87
+ def map_publication_date
88
+ date = event_value("publication") || event_value("deposit")
89
+ return unless date
90
+
91
+ year, month, day = parse_date(date)
92
+ return unless year
93
+
94
+ {
95
+ year: {
96
+ value: year
97
+ }
98
+ }.tap do |publication_date|
99
+ publication_date[:month] = {value: month} if month
100
+ publication_date[:day] = {value: day} if month && day
101
+ end
102
+ end
103
+
104
+ def parse_date(date)
105
+ matcher = date.match(/(\d{4})-?(\d{2})?-?(\d{2})?/)
106
+ return [nil, nil, nil] unless matcher
107
+
108
+ matcher[1..3]
109
+ end
110
+
111
+ def event_value(type)
112
+ description&.event&.find { |event| event.type == type }&.date&.first&.value
113
+ end
114
+
115
+ H2_TERM_MAP = {
116
+ "Data" => "data-set",
117
+ "Software/Code" => "software",
118
+ "Article" => "journal-article",
119
+ "Book" => "book",
120
+ "Book chapter" => "book-chapter",
121
+ "Code" => "software",
122
+ "Conference session" => "lecture-speech",
123
+ "Course/instructional materials" => "manual",
124
+ "Database" => "data-set",
125
+ "Dramatic performance" => "artistic-performance",
126
+ "Geospatial data" => "data-set",
127
+ "Journal/periodical issue" => "journal-issue",
128
+ "Performance" => "artistic-performance",
129
+ "Poetry reading" => "artistic-performance",
130
+ "Poster" => "conference-poster",
131
+ "Preprint" => "preprint",
132
+ "Presentation recording" => "lecture-speech",
133
+ "Questionnaire" => "research-technique",
134
+ "Report" => "report",
135
+ "Software" => "software",
136
+ "Speech" => "lecture-speech",
137
+ "Statistical model" => "research-technique",
138
+ "Syllabus" => "manual",
139
+ "Tabular data" => "data-set",
140
+ "Technical report" => "report",
141
+ "Text corpus" => "data-set",
142
+ "Thesis" => "dissertation-thesis",
143
+ "Working paper" => "working-paper"
144
+ }
145
+
146
+ def map_type
147
+ # See https://info.orcid.org/ufaqs/what-work-types-does-orcid-support/
148
+ # For now, only mapping H2 terms; if there is not an H2 term, using "other".
149
+
150
+ h2_form = description.form.find { |form| form.source&.value == "Stanford self-deposit resource types" }
151
+ return "other" unless h2_form
152
+
153
+ map_h2_resource_types(h2_form)
154
+ end
155
+
156
+ def map_h2_resource_types(form)
157
+ # Try to match subtypes first, then type
158
+ subtype_terms = form.structuredValue.select { |term| term.type == "subtype" }.map(&:value)
159
+ type_term = form.structuredValue.find { |term| term.type == "type" }&.value
160
+ matching_term = (subtype_terms + [type_term]).find { |term| H2_TERM_MAP.key?(term) }
161
+ return "other" unless matching_term
162
+
163
+ H2_TERM_MAP[matching_term]
164
+ end
165
+
166
+ def map_contributors
167
+ contributors = description.contributor.map do |contributor|
168
+ ContributorMapper.map(contributor: contributor)
169
+ end.compact.presence
170
+ return unless contributors
171
+ {
172
+ contributor: contributors
173
+ }
174
+ end
175
+ end
176
+ end
@@ -33,7 +33,7 @@ class SulOrcidClient
33
33
  self
34
34
  end
35
35
 
36
- delegate :fetch_works, :fetch_work, :fetch_name, :search, :add_work, :delete_work, to: :instance
36
+ delegate :fetch_works, :fetch_work, :fetch_name, :search, :add_work, :update_work, :delete_work, to: :instance
37
37
  end
38
38
 
39
39
  attr_accessor :base_url, :base_public_url, :base_auth_url, :client_id, :client_secret
@@ -124,6 +124,22 @@ class SulOrcidClient
124
124
  end
125
125
  end
126
126
 
127
+ # Update an existing work for a researcher.
128
+ # @param [String] orcidid an ORCiD ID for the researcher
129
+ # @param [Hash] work a work in correct data structure for ORCID work
130
+ # @param [String] token an ORCiD API access token
131
+ # @param [String] put_code the PUT code
132
+ # @return [Boolean] true if update succeeded
133
+ # @raise [RuntimeError] if the API response status is not successful
134
+ def update_work(orcidid:, work:, token:, put_code:)
135
+ response = conn_with_token(token).put("/v3.0/#{base_orcidid(orcidid)}/work/#{put_code}",
136
+ work.merge({"put-code" => put_code}).to_json,
137
+ "Content-Type" => "application/vnd.orcid+json")
138
+
139
+ raise "ORCID.org API returned #{response.status} when updating #{put_code} for #{orcidid}" unless response.status == 200
140
+ true
141
+ end
142
+
127
143
  # Delete a work
128
144
  # @param [string] ORCID ID for the researcher
129
145
  # @param [string] put-code
@@ -32,6 +32,7 @@ Gem::Specification.new do |spec|
32
32
  spec.require_paths = ["lib"]
33
33
 
34
34
  spec.add_dependency "activesupport", ">= 4.2", "< 8"
35
+ spec.add_dependency "cocina-models", "~> 0.90"
35
36
  spec.add_dependency "faraday"
36
37
  spec.add_dependency "faraday-retry"
37
38
  spec.add_dependency "oauth2"
@@ -41,7 +42,7 @@ Gem::Specification.new do |spec|
41
42
  spec.add_development_dependency "rspec", "~> 3.0"
42
43
  spec.add_development_dependency "rubocop-rspec"
43
44
  spec.add_development_dependency "simplecov"
44
- spec.add_development_dependency "standard", "~> 1.29.0" # Pinning until https://github.com/standardrb/standard-custom/pull/5
45
+ spec.add_development_dependency "standard"
45
46
  spec.add_development_dependency "vcr"
46
47
  spec.add_development_dependency "webmock"
47
48
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sul_orcid_client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter Mangiafico
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2023-07-13 00:00:00.000000000 Z
12
+ date: 2023-07-14 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport
@@ -31,6 +31,20 @@ dependencies:
31
31
  - - "<"
32
32
  - !ruby/object:Gem::Version
33
33
  version: '8'
34
+ - !ruby/object:Gem::Dependency
35
+ name: cocina-models
36
+ requirement: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.90'
41
+ type: :runtime
42
+ prerelease: false
43
+ version_requirements: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '0.90'
34
48
  - !ruby/object:Gem::Dependency
35
49
  name: faraday
36
50
  requirement: !ruby/object:Gem::Requirement
@@ -147,16 +161,16 @@ dependencies:
147
161
  name: standard
148
162
  requirement: !ruby/object:Gem::Requirement
149
163
  requirements:
150
- - - "~>"
164
+ - - ">="
151
165
  - !ruby/object:Gem::Version
152
- version: 1.29.0
166
+ version: '0'
153
167
  type: :development
154
168
  prerelease: false
155
169
  version_requirements: !ruby/object:Gem::Requirement
156
170
  requirements:
157
- - - "~>"
171
+ - - ">="
158
172
  - !ruby/object:Gem::Version
159
- version: 1.29.0
173
+ version: '0'
160
174
  - !ruby/object:Gem::Dependency
161
175
  name: vcr
162
176
  requirement: !ruby/object:Gem::Requirement
@@ -203,7 +217,9 @@ files:
203
217
  - README.md
204
218
  - Rakefile
205
219
  - lib/sul_orcid_client.rb
220
+ - lib/sul_orcid_client/contributor_mapper.rb
206
221
  - lib/sul_orcid_client/version.rb
222
+ - lib/sul_orcid_client/work_mapper.rb
207
223
  - sul_orcid_client.gemspec
208
224
  homepage: https://github.com/sul-dlss/sul_orcid_client
209
225
  licenses: []