fieldhand 0.1.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: a1f8b4934a70d78dda2f03bb151deea7ed553424
4
+ data.tar.gz: f39842d9de77f6a43203f6795ef35836ac5efbff
5
+ SHA512:
6
+ metadata.gz: 6ce68385c9352deabd07c6f60ef904853c934a79d1488a88abbffaed9c1802e59f06437501cc23f79b68bbacc801608c758085753373525e9484d4c0b566c181
7
+ data.tar.gz: 22c515794f85150b621f0a8ef0d7af25505590a707ff86b8972e5751c69cf5a0bc46508cfb53b5d8ebe5458be778d10b9d69c1cfd13e731b92806b1de69e7cec
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2017 Altmetric LLP
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ 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 FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,538 @@
1
+ # Fieldhand [![Build Status](https://travis-ci.org/altmetric/fieldhand.svg?branch=master)](https://travis-ci.org/altmetric/fieldhand)
2
+
3
+ A Ruby library for harvesting metadata from [OAI-PMH](https://www.openarchives.org/OAI/openarchivesprotocol.html) repositories.
4
+
5
+ **Current version:** 0.1.0
6
+ **Supported Ruby versions:** 1.8.7, 1.9.2, 1.9.3, 2.0, 2.1, 2.2
7
+
8
+ ## Usage
9
+
10
+ ```ruby
11
+ require 'fieldhand'
12
+
13
+ repository = Fieldhand::Repository.new('http://example.com/oai')
14
+ repository.identify.name
15
+ #=> "Repository Name"
16
+
17
+ repository.metadata_formats.map { |format| format.prefix }
18
+ #=> ["oai_dc"]
19
+
20
+ repository.sets.map { |set| set.name }
21
+ #=> ["Set A.", "Set B."]
22
+
23
+ repository.records.each do |record|
24
+ # ...
25
+ end
26
+
27
+ repository.get('oai:www.example.com:12345')
28
+ #=> #<Fieldhand::Record: ...>
29
+ ```
30
+
31
+ ## API Documentation
32
+
33
+ * [`Fieldhand::Repository`](#fieldhandrepository)
34
+ * [`.new(uri[, logger])`](#fieldhandrepositorynewuri-logger)
35
+ * [`#identify`](#fieldhandrepositoryidentify)
36
+ * [`#metadata_formats([identifier])`](#fieldhandrepositorymetadata_formatsidentifier)
37
+ * [`#sets`](#fieldhandrepositorysets)
38
+ * [`#records([arguments])`](#fieldhandrepositoryrecordsarguments)
39
+ * [`#identifiers([arguments])`](#fieldhandrepositoryidentifiersarguments)
40
+ * [`#get(identifier[, arguments])`](#fieldhandgetidentifier-arguments)
41
+ * [`Fieldhand::Identify`](#fieldhandidentify)
42
+ * [`#name`](#fieldhandidentifyname)
43
+ * [`#base_url`](#fieldhandidentifybase_url)
44
+ * [`#protocol_version`](#fieldhandidentifyprotocol_version)
45
+ * [`#earliest_datestamp`](#fieldhandidentifyearliest_datestamp)
46
+ * [`#deleted_record`](#fieldhandidentifydeleted_record)
47
+ * [`#granularity`](#fieldhandidentifygranularity)
48
+ * [`#admin_emails`](#fieldhandidentifyadmin_emails)
49
+ * [`#compression`](#fieldhandidentifycompression)
50
+ * [`#descriptions`](#fieldhandidentifydescriptions)
51
+ * [`Fieldhand::MetadataFormat`](#fieldhandmetadataformat)
52
+ * [`#prefix`](#fieldhandmetadataformatprefix)
53
+ * [`#schema`](#fieldhandmetadataformatschema)
54
+ * [`#namespace`](#fieldhandmetadataformatnamespace)
55
+ * [`Fieldhand::Set`](#fieldhandset)
56
+ * [`#spec`](#fieldhandsetspec)
57
+ * [`#name`](#fieldhandsetname)
58
+ * [`#descriptions`](#fieldhandsetdescriptions)
59
+ * [`Fieldhand::Record`](#fieldhandrecord)
60
+ * [`#deleted?`](#fieldhandrecorddeleted)
61
+ * [`#status`](#fieldhandrecordstatus)
62
+ * [`#identifier`](#fieldhandrecordidentifier)
63
+ * [`#datestamp`](#fieldhandrecorddatestamp)
64
+ * [`#sets`](#fieldhandrecordsets)
65
+ * [`#metadata`](#fieldhandrecordmetadata)
66
+ * [`#about`](#fieldhandrecordabout)
67
+ * [`Fieldhand::Header`](#fieldhandheader)
68
+ * [`#deleted?`](#fieldhandheaderdeleted)
69
+ * [`#status`](#fieldhandheaderstatus)
70
+ * [`#identifier`](#fieldhandheaderidentifier)
71
+ * [`#datestamp`](#fieldhandheaderdatestamp)
72
+ * [`#sets`](#fieldhandheadersets)
73
+ * [`Fieldhand::NetworkError`](#fieldhandnetworkerror)
74
+ * [`Fieldhand::ProtocolError`](#fieldhandprotocolerror)
75
+ * [`Fieldhand::BadArgumentError`](#fieldhandbadargumenterror)
76
+ * [`Fieldhand::BadResumptionTokenError`](#fieldhandbadresumptiontokenerror)
77
+ * [`Fieldhand::BadVerbError`](#fieldhandbadverberror)
78
+ * [`Fieldhand::CannotDisseminateFormatError`](#fieldhandcannotdisseminateformaterror)
79
+ * [`Fieldhand::IdDoesNotExistError`](#fieldhandiddoesnotexisterror)
80
+ * [`Fieldhand::NoRecordsMatchError`](#fieldhandnorecordsmatcherror)
81
+ * [`Fieldhand::NoMetadataFormatsError`](#fieldhandnometadataformatserror)
82
+ * [`Fieldhand::NoSetHierarchyError`](#fieldhandnosethierarchyerror)
83
+
84
+ ### `Fieldhand::Repository`
85
+
86
+ A class to represent [an OAI-PMH repository](https://www.openarchives.org/OAI/openarchivesprotocol.html#Repository):
87
+
88
+ > A repository is a network accessible server that can process the 6 OAI-PMH
89
+ > requests [...]. A repository is managed by a data provider to expose metadata
90
+ > to harvesters.
91
+
92
+ #### `Fieldhand::Repository.new(uri[, logger])`
93
+
94
+ ```ruby
95
+ Fieldhand::Repository.new('http://www.example.com/oai')
96
+ Fieldhand::Repository.new(URI('http://www.example.com/oai'))
97
+ Fieldhand::Repository.new('http://www.example.com/oai', Logger.new(STDOUT))
98
+ ```
99
+
100
+ Return a new [`Repository`](#fieldhandrepository) instance accessible at the given `uri` (specified
101
+ either as a [`URI`][URI] or
102
+ something that can be coerced into a `URI` such as a `String`) with an optional
103
+ [`Logger`](http://ruby-doc.org/stdlib/libdoc/logger/rdoc/Logger.html)-compatible
104
+ `logger`.
105
+
106
+ #### `Fieldhand::Repository#identify`
107
+
108
+ ```ruby
109
+ repository.identify
110
+ #=> #<Fieldhand::Identify: ...>
111
+ ```
112
+
113
+ Return an [`Identify`](#fieldhandidentify) for the repository including information such as the repository name, base URL, protocol version, etc.
114
+
115
+ May raise a [`NetworkError`](#fieldhandnetworkerror) if there is a problem contacting the repository or any descendant [`ProtocolError`](#fieldhandprotocolerror) if received in response.
116
+
117
+ #### `Fieldhand::Repository#metadata_formats([identifier])`
118
+
119
+ ```ruby
120
+ repository.metadata_formats
121
+ #=> #<Enumerator: ...>
122
+ repository.metadata_formats('oai:www.example.com:1')
123
+ ```
124
+
125
+ Return an [`Enumerator`][Enumerator] of [`MetadataFormat`](#fieldhandmetadataformat)s available from the repository. Optionally takes an `identifier` that specifies the unique identifier of the item for which available metadata formats are being requested.
126
+
127
+ May raise a [`NetworkError`](#fieldhandnetworkerror) if there is a problem contacting the repository or any descendant [`ProtocolError`](#fieldhandprotocolerror) if received in response.
128
+
129
+ #### `Fieldhand::Repository#sets`
130
+
131
+ ```ruby
132
+ repository.sets
133
+ #=> #<Enumerator: ...>
134
+ ```
135
+
136
+ Return an [`Enumerator`][Enumerator] of [`Set`](#fieldhandset)s that represent the set structure of a repository.
137
+
138
+ May raise a [`NetworkError`](#fieldhandnetworkerror) if there is a problem contacting the repository or any descendant [`ProtocolError`](#fieldhandprotocolerror) if received in response.
139
+
140
+ #### `Fieldhand::Repository#records([arguments])`
141
+
142
+ ```ruby
143
+ repository.records
144
+ repository.records(:metadata_prefix => 'oai_dc', :from => '2001-01-01')
145
+ repository.records(:metadata_prefix => 'oai_dc', :from => Date.new(2001, 1, 1))
146
+ repository.records(:set => 'A', :until => Time.utc(2010, 1, 1, 12, 0))
147
+ ```
148
+
149
+ Return an [`Enumerator`][Enumerator] of all [`Record`](#fieldhandrecord)s harvested from the repository.
150
+
151
+ Optional arguments can be passed as a `Hash` of `arguments` to permit selective harvesting of records based on set membership and/or datestamp:
152
+
153
+ * `:metadata_prefix`: a `String` or [`MetadataFormat`](#fieldhandmetadataformat) to specify the metadata format that should be included in the metadata part of the returned record, defaults to `oai_dc`;
154
+ * `:from`: an optional argument with a `String`, [`Date`][Date] or [`Time`][Time] [UTCdatetime](https://www.openarchives.org/OAI/openarchivesprotocol.html#Dates) value, which specifies a lower bound for datestamp-based selective harvesting;
155
+ * `:until`: an optional argument with a `String`, [`Date`][Date] or [`Time`][Time] [UTCdatetime](https://www.openarchives.org/OAI/openarchivesprotocol.html#Dates) value, which specifies a upper bound for datestamp-based selective harvesting;
156
+ * `:set`: an optional argument with a [set spec](#fieldhandsetspec) value (passed as either a `String` or a [`Set`](#fieldhandset)), which specifies set criteria for selective harvesting;
157
+ * `:resumption_token`: an exclusive argument with a `String` value that is the flow control token returned by a previous request that issued an incomplete list.
158
+
159
+ Note that datetimes should respect the repository's [granularity](#fieldhandidentifygranularity) otherwise they will return a [`BadArgumentError`](#fieldhandbadargumenterror).
160
+
161
+ May raise a [`NetworkError`](#fieldhandnetworkerror) if there is a problem contacting the repository or any descendant [`ProtocolError`](#fieldhandprotocolerror) if received in response.
162
+
163
+ #### `Fieldhand::Repository#identifiers(metadata_prefix[, arguments])`
164
+
165
+ ```ruby
166
+ repository.identifiers
167
+ repository.identifiers(:metadata_prefix => 'oai_dc', :from => '2001-01-01')
168
+ repository.identifiers(:metadata_prefix => 'oai_dc', :from => Date.new(2001, 1, 1))
169
+ repository.identifiers(:set => 'A', :until => Time.utc(2010, 1, 1, 12, 0))
170
+ ```
171
+
172
+ Return an [`Enumerator`][Enumerator] for an abbreviated form of [records](#fieldhandrepositoryrecordsarguments), retrieving only [`Header`](#fieldhandheader)s with the given optional `arguments`.
173
+
174
+ See [`Fieldhand::Repository#records`](#fieldhandrepositoryrecordsarguments) for supported `arguments`.
175
+
176
+ May raise a [`NetworkError`](#fieldhandnetworkerror) if there is a problem contacting the repository or any descendant [`ProtocolError`](#fieldhandprotocolerror) if received in response.
177
+
178
+ #### `Fieldhand::Repository#get(identifier[, arguments])`
179
+
180
+ ```ruby
181
+ repository.get('oai:www.example.com:1')
182
+ repository.get('oai:www.example.com:1', :metadata_prefix => 'oai_dc')
183
+ #=> #<Fieldhand::Record: ...>
184
+ ```
185
+
186
+ Return an individual metadata [`Record`](#fieldhandrecord) from a repository with the given `identifier` and optional `:metadata_prefix` argument (defaults to `oai_dc`).
187
+
188
+ May raise a [`NetworkError`](#fieldhandnetworkerror) if there is a problem contacting the repository or any descendant [`ProtocolError`](#fieldhandprotocolerror) if received in response.
189
+
190
+ ### `Fieldhand::Identify`
191
+
192
+ A class to represent information about a repository as returned from the [`Identify` request](https://www.openarchives.org/OAI/openarchivesprotocol.html#Identify).
193
+
194
+ #### `Fieldhand::Identify#name`
195
+
196
+ ```ruby
197
+ repository.identify.name
198
+ #=> "Repository Name"
199
+ ```
200
+
201
+ Return a human readable name for the repository as a `String`.
202
+
203
+ #### `Fieldhand::Identify#base_url`
204
+
205
+ ```ruby
206
+ repository.identify.base_url
207
+ #=> #<URI::HTTP http://www.example.com/oai>
208
+ ```
209
+
210
+ Returns the [base URL](https://www.openarchives.org/OAI/openarchivesprotocol.html#HTTPRequestFormat) of the repository as a [`URI`][URI].
211
+
212
+ #### `Fieldhand::Identify#protocol_version`
213
+
214
+ ```ruby
215
+ repository.identify.protocol_version
216
+ #=> "2.0"
217
+ ```
218
+
219
+ Returns the version of the OAI-PMH protocol supported by the repository as a `String`.
220
+
221
+ #### `Fieldhand::Identify#earliest_datestamp`
222
+
223
+ ```ruby
224
+ repository.identify.earliest_datestamp
225
+ #=> 2011-01-01 00:00:00 UTC
226
+ repository.identify.earliest_datestamp
227
+ #=> #<Date: 2001-01-01 ((2451911j,0s,0n),+0s,2299161j)>
228
+ ```
229
+
230
+ Returns the guaranteed lower limit of all datestamps recording changes, modifications, or deletions in the repository as a [`Time`][Time] or [`Date`][Date]. Note that the datestamp will be at the finest [granularity](#fieldhandidentifygranularity) supported by the repository.
231
+
232
+ #### `Fieldhand::Identify#deleted_record`
233
+
234
+ ```ruby
235
+ repository.identify.deleted_record
236
+ #=> "persistent"
237
+ ```
238
+
239
+ Returns the manner in which the repository supports the notion of deleted records as a `String`. Legitimate values are `no`; `transient`; `persistent` with meanings defined in [the section on deletion](https://www.openarchives.org/OAI/openarchivesprotocol.html#DeletedRecords).
240
+
241
+ #### `Fieldhand::Identify#granularity`
242
+
243
+ ```ruby
244
+ repository.identify.granularity
245
+ #=> "YYYY-MM-DDThh:mm:ssZ"
246
+ ```
247
+
248
+ Returns the finest [harvesting granularity](https://www.openarchives.org/OAI/openarchivesprotocol.html#Datestamp) supported by the repository as a `String`. The legitimate values are `YYYY-MM-DD` and `YYYY-MM-DDThh:mm:ssZ` with meanings as defined in [ISO 8601](http://www.w3.org/TR/NOTE-datetime).
249
+
250
+ #### `Fieldhand::Identify#admin_emails`
251
+
252
+ ```ruby
253
+ repository.identify.admin_emails
254
+ #=> ["admin@example.com"]
255
+ ```
256
+
257
+ Returns the e-mail addresses of administrators of the repository as an `Array` of `String`s.
258
+
259
+ #### `Fieldhand::Identify#compression`
260
+
261
+ ```ruby
262
+ repository.identify.compression
263
+ #=> ["gzip", "deflate"]
264
+ ```
265
+
266
+ Returns the compression encodings supported by the repository as an `Array` of `String`s. The recommended values are those defined for the Content-Encoding header in Section 14.11 of [RFC 2616](http://www.ietf.org/rfc/rfc2616.txt) describing HTTP 1.1
267
+
268
+ #### `Fieldhand::Identify#descriptions`
269
+
270
+ ```ruby
271
+ repository.identify.descriptions
272
+ #=> [#<Ox::Element...>]
273
+ ```
274
+
275
+ Returns XML elements describing this repository as an `Array` of [`Ox::Element`][Element]s.
276
+
277
+ As descriptions can be in any format, Fieldhand doesn't attempt to parse descriptions but leaves parsing to the client.
278
+
279
+ ### `Fieldhand::MetadataFormat`
280
+
281
+ A class to represent a metadata format available from a repository.
282
+
283
+ #### `Fieldhand::MetadataFormat#prefix`
284
+
285
+ ```ruby
286
+ repository.metadata_formats.first.prefix
287
+ #=> "oai_dc"
288
+ ```
289
+
290
+ Return the prefix of the metadata format to be used when requesting records as a `String`.
291
+
292
+ #### `Fieldhand::MetadataFormat#schema`
293
+
294
+ ```ruby
295
+ repository.metadata_formats.first.schema
296
+ #=> #<URI::HTTP http://www.openarchives.org/OAI/2.0/oai_dc.xsd>
297
+ ```
298
+
299
+ Return the location of an XML Schema describing the format as a [`URI`][URI].
300
+
301
+ #### `Fieldhand::MetadataFormat#namespace`
302
+
303
+ ```ruby
304
+ repository.metadata_formats.first.namespace
305
+ #=> #<URI::HTTP http://www.openarchives.org/OAI/2.0/oai_dc/>
306
+ ```
307
+
308
+ Return the XML Namespace URI for the format as a [`URI`][URI].
309
+
310
+ ### `Fieldhand::Set`
311
+
312
+ A class representing an optional construct for grouping items for the purpose of selective harvesting.
313
+
314
+ #### `Fieldhand::Set#spec`
315
+
316
+ ```ruby
317
+ repository.sets.first.spec
318
+ #=> "A"
319
+ ```
320
+
321
+ Return unique identifier for the set which is also the path from the root of the set hierarchy to the respective node as a `String`.
322
+
323
+ #### `Fieldhand::Set#name`
324
+
325
+ ```ruby
326
+ repository.sets.first.name
327
+ #=> "Set A."
328
+ ```
329
+
330
+ Return a short human-readable `String` naming the set.
331
+
332
+ #### `Fieldhand::Set#descriptions`
333
+
334
+ ```ruby
335
+ repository.sets.first.descriptions
336
+ #=> [#<Ox::Element: ...>]
337
+ ```
338
+
339
+ Return an `Array` of [`Ox::Element`][Element]s of any optional and repeatable containers that may hold community-specific XML-encoded data about the set.
340
+
341
+ ### `Fieldhand::Record`
342
+
343
+ A class representing a [record](https://www.openarchives.org/OAI/openarchivesprotocol.html#Record) from the repository:
344
+
345
+ > A record is metadata expressed in a single format.
346
+
347
+ #### `Fieldhand::Record#deleted?`
348
+
349
+ ```ruby
350
+ repository.records.first.deleted?
351
+ #=> true
352
+ ```
353
+
354
+ Return whether or not a record is [deleted](https://www.openarchives.org/OAI/openarchivesprotocol.html#DeletedRecords) as a `Boolean`.
355
+
356
+ #### `Fieldhand::Record#status`
357
+
358
+ ```ruby
359
+ repository.records.first.status
360
+ #=> "deleted"
361
+ ```
362
+
363
+ Return the optional `status` attribute of the [record's header](https://www.openarchives.org/OAI/openarchivesprotocol.html#header) as a `String` or `nil`.
364
+
365
+ > [A] value of deleted indicates the withdrawal of availability of the specified metadata format for the item, dependent on the repository support for deletions.
366
+
367
+ #### `Fieldhand::Record#identifier`
368
+
369
+ ```ruby
370
+ repository.records.first.identifier
371
+ #=> "oai:www.example.com:1"
372
+ ```
373
+
374
+ Return the [unique identifier](https://www.openarchives.org/OAI/openarchivesprotocol.html#UniqueIdentifier) for this record in the repository.
375
+
376
+ #### `Fieldhand::Record#datestamp`
377
+
378
+ ```ruby
379
+ repository.records.first.datestamp
380
+ #=> 2011-03-03 16:29:24 UTC
381
+ ```
382
+
383
+ Return the date of creation, modification or deletion of the record for the purpose of selective harvesting as a [`Time`][Time] or [`Date`][Date] depending on the [granularity](#fieldhandidentifygranularity) of the repository.
384
+
385
+ #### `Fieldhand::Record#sets`
386
+
387
+ ```ruby
388
+ repository.records.first.sets
389
+ #=> ["A", "B"]
390
+ ```
391
+
392
+ Return an `Array` of `String` [set specs](#fieldhandsetspec) indicating set memberships of this record.
393
+
394
+ #### `Fieldhand::Record#metadata`
395
+
396
+ ```ruby
397
+ repository.records.first.metadata
398
+ #=> #<Ox::Element: ...>
399
+ ```
400
+
401
+ Return a single manifestation of the metadata from a record as [`Ox::Element`][Element]s or `nil` if this is a deleted record.
402
+
403
+ As the metadata can be in [any format supported by the repository](#fieldhandrepositorymetadata_formatsidentifier), Fieldhand doesn't attempt to parse the metadata but leaves parsing to the client.
404
+
405
+ #### `Fieldhand::Record#about`
406
+
407
+ ```ruby
408
+ repository.records.first.about
409
+ #=> [#<Ox::Element: ...>]
410
+ ```
411
+
412
+ Return an `Array` of [`Ox::Element`][Element]s of any optional and repeatable containers holding data about the metadata part of the record.
413
+
414
+ ### `Fieldhand::Header`
415
+
416
+ A class representing the [header](https://www.openarchives.org/OAI/openarchivesprotocol.html#header) of a record:
417
+
418
+ > Contains the unique identifier of the item and properties necessary for selective harvesting. The header consists of
419
+ > the following parts:
420
+ >
421
+ > * the unique identifier -- the unique identifier of an item in a repository;
422
+ > * the datestamp -- the date of creation, modification or deletion of the record for the purpose of selective
423
+ > harvesting.
424
+ > * zero or more setSpec elements -- the set membership of the item for the purpose of selective harvesting.
425
+ > * an optional status attribute with a value of deleted indicates the withdrawal of availability of the specified
426
+ > metadata format for the item, dependent on the repository support for deletions.
427
+
428
+ #### `Fieldhand::Header#deleted?`
429
+
430
+ ```ruby
431
+ repository.identifiers.first.deleted?
432
+ #=> true
433
+ ```
434
+
435
+ Return whether or not a record is [deleted](https://www.openarchives.org/OAI/openarchivesprotocol.html#DeletedRecords) as a `Boolean`.
436
+
437
+ #### `Fieldhand::Header#status`
438
+
439
+ ```ruby
440
+ repository.identifiers.first.status
441
+ #=> "deleted"
442
+ ```
443
+
444
+ Return the optional `status` attribute of the header as a `String` or `nil`.
445
+
446
+ > [A] value of deleted indicates the withdrawal of availability of the specified metadata format for the item, dependent on the repository support for deletions.
447
+
448
+ #### `Fieldhand::Header#identifier`
449
+
450
+ ```ruby
451
+ repository.identifiers.first.identifier
452
+ #=> "oai:www.example.com:1"
453
+ ```
454
+
455
+ Return the [unique identifier](https://www.openarchives.org/OAI/openarchivesprotocol.html#UniqueIdentifier) for this record in the repository.
456
+
457
+ #### `Fieldhand::Header#datestamp`
458
+
459
+ ```ruby
460
+ repository.identifiers.first.datestamp
461
+ #=> 2011-03-03 16:29:24 UTC
462
+ ```
463
+
464
+ Return the date of creation, modification or deletion of the record for the purpose of selective harvesting as a [`Time`][Time] or [`Date`][Date] depending on the [granularity](#fieldhandidentifygranularity) of the repository.
465
+
466
+ #### `Fieldhand::Header#sets`
467
+
468
+ ```ruby
469
+ repository.identifiers.first.sets
470
+ #=> ["A", "B"]
471
+ ```
472
+
473
+ Return an `Array` of `String` [set specs](#fieldhandsetspec) indicating set memberships of this record.
474
+
475
+ ### `Fieldhand::NetworkError`
476
+
477
+ An error (descended from `StandardError`) to represent any network issues encountered during interaction with the repository. Any underlying exception is exposed in Ruby 2.1 onwards through [`Exception#cause`](https://ruby-doc.org/core-2.1.0/Exception.html#method-i-cause).
478
+
479
+ ### `Fieldhand::ProtocolError`
480
+
481
+ The parent error class (descended from `StandardError`) for any errors returned by a repository as defined in the [protocol's Error and Exception Conditions](https://www.openarchives.org/OAI/openarchivesprotocol.html#ErrorConditions).
482
+
483
+ This can be used to rescue all the following child error types.
484
+
485
+ ### `Fieldhand::BadArgumentError`
486
+
487
+ > The request includes illegal arguments, is missing required arguments,
488
+ > includes a repeated argument, or values for arguments have an illegal syntax.
489
+
490
+ ### `Fieldhand::BadResumptionTokenError`
491
+
492
+ > The value of the `resumptionToken` argument is invalid or expired.
493
+
494
+ ### `Fieldhand::BadVerbError`
495
+
496
+ > Value of the `verb` argument is not a legal OAI-PMH verb, the `verb` argument is
497
+ > missing, or the `verb` argument is repeated.
498
+
499
+ ### `Fieldhand::CannotDisseminateFormatError`
500
+
501
+ > The metadata format identified by the value given for the `metadataPrefix`
502
+ > argument is not supported by the item or by the repository.
503
+
504
+ ### `Fieldhand::IdDoesNotExistError`
505
+
506
+ > The value of the `identifier` argument is unknown or illegal in this
507
+ > repository.
508
+
509
+ ### `Fieldhand::NoRecordsMatchError`
510
+
511
+ > The combination of the values of the `from`, `until`, `set` and `metadataPrefix`
512
+ > arguments results in an empty list.
513
+
514
+ ### `Fieldhand::NoMetadataFormatsError`
515
+
516
+ > There are no metadata formats available for the specified item.
517
+
518
+ ### `Fieldhand::NoSetHierarchyError`
519
+
520
+ > The repository does not support sets.
521
+
522
+ [Date]: https://ruby-doc.org/stdlib/libdoc/date/rdoc/Date.html
523
+ [Enumerator]: https://ruby-doc.org/core/Enumerator.html
524
+ [Time]: https://ruby-doc.org/core/Time.html
525
+ [URI]: https://ruby-doc.org/stdlib/libdoc/uri/rdoc/URI.html
526
+ [Element]: http://www.rubydoc.info/github/ohler55/ox/Ox/Element
527
+
528
+ ## Acknowledgements
529
+
530
+ * Example XML responses are taken from [Datacite's OAI-PMH repository](https://oai.datacite.org/).
531
+ * Null device detection is based on the implementation from the [backports](https://github.com/marcandre/backports) gem.
532
+ * Much of the documentation relies on wording from version 2.0 of [The Open Archives Initiative Protocol for Metadata Harvesting](https://www.openarchives.org/OAI/openarchivesprotocol.html).
533
+
534
+ ## License
535
+
536
+ Copyright © 2017 Altmetric LLP
537
+
538
+ Distributed under the MIT License.