puree 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +18 -0
- data/CHANGELOG.md +34 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +232 -0
- data/Rakefile +1 -0
- data/lib/puree.rb +12 -0
- data/lib/puree/collection.rb +80 -0
- data/lib/puree/dataset.rb +273 -0
- data/lib/puree/date.rb +61 -0
- data/lib/puree/journal.rb +13 -0
- data/lib/puree/map.rb +48 -0
- data/lib/puree/organisation.rb +13 -0
- data/lib/puree/person.rb +13 -0
- data/lib/puree/project.rb +13 -0
- data/lib/puree/publication.rb +13 -0
- data/lib/puree/publisher.rb +13 -0
- data/lib/puree/resource.rb +124 -0
- data/lib/puree/version.rb +3 -0
- data/puree.gemspec +24 -0
- data/spec/collection.rb +27 -0
- data/spec/dataset.rb +73 -0
- data/spec/spec_helper.rb +12 -0
- metadata +114 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 589862f38fbdf73c8255cfd00e51191fbbdde42a
|
4
|
+
data.tar.gz: 146680ea5def8f36b7a4bc377413949e2c244de4
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 9728d190508de23b7b08e3fb0094700f9ec190b40573d32dd8740fad263fca7447b3ff169b89eff6831dc2cf933a3cc2224e6947601610d31c203ffff615018e
|
7
|
+
data.tar.gz: 470051d32055bbd820d7e44a3d931a48419a087cad860a8522c890c8e58a16321fbe60167609f25d528c38b7c8813ae764df6f037c5b4315d61c48c2abeac85f
|
data/.gitignore
ADDED
data/CHANGELOG.md
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# Change Log
|
2
|
+
All notable changes to this project will be documented in this file.
|
3
|
+
This project adheres to [Semantic Versioning](http://semver.org/).
|
4
|
+
|
5
|
+
## 0.6.0 - 2016-05-06
|
6
|
+
### Added
|
7
|
+
- API map factored out of Resource.
|
8
|
+
- Collections (journal, organisation, person, project, publication, publisher).
|
9
|
+
- Resource classes with HTTParty metadata (journal, organisation, person, project, publication, publisher).
|
10
|
+
|
11
|
+
## 0.5.0 - 2016-04-29
|
12
|
+
### Added
|
13
|
+
- Refactoring ctor.
|
14
|
+
- Populate resource metadata from get and assignment.
|
15
|
+
- Dataset collection.
|
16
|
+
- RSpec tests for dataset collection.
|
17
|
+
|
18
|
+
## 0.4.0 - 2016-04-27
|
19
|
+
### Added
|
20
|
+
- Date normalisation and conversion to ISO8601.
|
21
|
+
|
22
|
+
## 0.3.0 - 2016-04-26
|
23
|
+
### Added
|
24
|
+
- Yard documentation.
|
25
|
+
- Simplification of public interface method names.
|
26
|
+
|
27
|
+
## 0.2.0 - 2016-04-25
|
28
|
+
### Added
|
29
|
+
- RSpec tests for datasets.
|
30
|
+
|
31
|
+
## 0.1.0 - 2016-04-21
|
32
|
+
### Added
|
33
|
+
- Working product supports datasets.
|
34
|
+
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2016 Adrian Albin-Clark
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,232 @@
|
|
1
|
+
# Purée
|
2
|
+
|
3
|
+
A Ruby client for the Pure Research Information System API.
|
4
|
+
|
5
|
+
|
6
|
+
## Installation
|
7
|
+
|
8
|
+
Add this line to your application's Gemfile:
|
9
|
+
|
10
|
+
gem 'puree'
|
11
|
+
|
12
|
+
And then execute:
|
13
|
+
|
14
|
+
$ bundle
|
15
|
+
|
16
|
+
Or install it yourself as:
|
17
|
+
|
18
|
+
$ gem install puree
|
19
|
+
|
20
|
+
## Usage
|
21
|
+
```ruby
|
22
|
+
endpoint = 'http://example.com/ws/rest'
|
23
|
+
```
|
24
|
+
|
25
|
+
Dataset.
|
26
|
+
|
27
|
+
```ruby
|
28
|
+
d = Puree::Dataset.new
|
29
|
+
|
30
|
+
# Get metadata using ID
|
31
|
+
d.get id: 12345678,
|
32
|
+
endpoint: endpoint,
|
33
|
+
username: username,
|
34
|
+
password: password
|
35
|
+
|
36
|
+
# Get metadata using UUID
|
37
|
+
d.get uuid: 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx',
|
38
|
+
endpoint: endpoint,
|
39
|
+
username: username,
|
40
|
+
password: password
|
41
|
+
|
42
|
+
# Filter metadata into simple data structures
|
43
|
+
d.title
|
44
|
+
d.description
|
45
|
+
d.keyword
|
46
|
+
d.person
|
47
|
+
d.temporal
|
48
|
+
d.geographical
|
49
|
+
d.file
|
50
|
+
d.publication
|
51
|
+
d.available
|
52
|
+
d.access
|
53
|
+
d.doi
|
54
|
+
|
55
|
+
# Combine metadata into one simple data structure
|
56
|
+
d.metadata
|
57
|
+
|
58
|
+
# Access HTTParty functionality
|
59
|
+
d.response # HTTParty object
|
60
|
+
d.response.body # XML
|
61
|
+
d.response.code
|
62
|
+
d.response.message
|
63
|
+
d.response.headers # hash
|
64
|
+
```
|
65
|
+
|
66
|
+
Collection.
|
67
|
+
|
68
|
+
```ruby
|
69
|
+
c = Puree::Collection.new(resource_type: :dataset)
|
70
|
+
|
71
|
+
# Get minimal datasets, optionally specifying a quantity (default is 20)
|
72
|
+
c.get endpoint: endpoint,
|
73
|
+
username: username,
|
74
|
+
password: password,
|
75
|
+
qty: 100000
|
76
|
+
|
77
|
+
# Get UUIDs for datasets
|
78
|
+
uuids = c.uuid
|
79
|
+
|
80
|
+
# Get metadata using UUID
|
81
|
+
datasets = []
|
82
|
+
uuids.each do |uuid|
|
83
|
+
d = Puree::Dataset.new
|
84
|
+
d.get endpoint: endpoint,
|
85
|
+
username: username,
|
86
|
+
password: password,
|
87
|
+
uuid: uuid
|
88
|
+
datasets << d.metadata
|
89
|
+
end
|
90
|
+
```
|
91
|
+
|
92
|
+
|
93
|
+
## Dataset data structures
|
94
|
+
|
95
|
+
### available
|
96
|
+
Date made available. If year is present, month and day will have data or an empty string.
|
97
|
+
|
98
|
+
```ruby
|
99
|
+
{
|
100
|
+
"year"=>"2016",
|
101
|
+
"month"=>"2",
|
102
|
+
"day"=>"4"
|
103
|
+
}
|
104
|
+
```
|
105
|
+
|
106
|
+
### file
|
107
|
+
An array of files.
|
108
|
+
|
109
|
+
```ruby
|
110
|
+
[
|
111
|
+
{
|
112
|
+
"name"=>"foo.csv",
|
113
|
+
"mime"=>"application/octet-stream",
|
114
|
+
"size"=>"1616665158",
|
115
|
+
"url"=>"http://example.com/ws/rest/files/12345678/foo.csv",
|
116
|
+
"title"=>"foo.csv",
|
117
|
+
"license"=>{
|
118
|
+
"name"=>"CC BY-NC",
|
119
|
+
"url"=>"http://creativecommons.org/licenses/by-nc/4.0/"
|
120
|
+
}
|
121
|
+
},
|
122
|
+
]
|
123
|
+
```
|
124
|
+
|
125
|
+
### person
|
126
|
+
Contains an array of internal persons and an array of external persons.
|
127
|
+
|
128
|
+
```ruby
|
129
|
+
{
|
130
|
+
"internal"=>[
|
131
|
+
{
|
132
|
+
"name"=>{
|
133
|
+
"first"=>"Stan",
|
134
|
+
"last"=>"Laurel"
|
135
|
+
},
|
136
|
+
"role"=>"Creator",
|
137
|
+
"uuid"=>"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx"
|
138
|
+
},
|
139
|
+
],
|
140
|
+
"external"=>[
|
141
|
+
]
|
142
|
+
}
|
143
|
+
```
|
144
|
+
|
145
|
+
### publication
|
146
|
+
An array of related publications.
|
147
|
+
|
148
|
+
```ruby
|
149
|
+
[
|
150
|
+
{
|
151
|
+
"type"=>"Journal article",
|
152
|
+
"title"=>"An interesting title",
|
153
|
+
"uuid"=>"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx"
|
154
|
+
},
|
155
|
+
]
|
156
|
+
```
|
157
|
+
|
158
|
+
### temporal
|
159
|
+
Date range. If year is present, month and day will have data or an empty string.
|
160
|
+
|
161
|
+
```ruby
|
162
|
+
{
|
163
|
+
"start"=>{
|
164
|
+
"year"=>"2005",
|
165
|
+
"month"=>"5",
|
166
|
+
"day"=>"10"
|
167
|
+
},
|
168
|
+
"end"=>{
|
169
|
+
"year"=>"2011",
|
170
|
+
"month"=>"9",
|
171
|
+
"day"=>"18"
|
172
|
+
}
|
173
|
+
}
|
174
|
+
```
|
175
|
+
|
176
|
+
|
177
|
+
## Utilities
|
178
|
+
|
179
|
+
### Convert date to ISO 8601 format.
|
180
|
+
|
181
|
+
```ruby
|
182
|
+
Puree::Date.iso d.available
|
183
|
+
```
|
184
|
+
```ruby
|
185
|
+
{
|
186
|
+
"year"=>"2016",
|
187
|
+
"month"=>"4",
|
188
|
+
"day"=>"18"
|
189
|
+
}
|
190
|
+
```
|
191
|
+
becomes
|
192
|
+
|
193
|
+
```ruby
|
194
|
+
"2016-04-18"
|
195
|
+
```
|
196
|
+
|
197
|
+
|
198
|
+
## API coverage
|
199
|
+
Version
|
200
|
+
|
201
|
+
```ruby
|
202
|
+
5.5.1
|
203
|
+
```
|
204
|
+
|
205
|
+
Resource metadata
|
206
|
+
|
207
|
+
```ruby
|
208
|
+
:dataset
|
209
|
+
```
|
210
|
+
|
211
|
+
Resource metadata (single hash only)
|
212
|
+
|
213
|
+
```ruby
|
214
|
+
:journal
|
215
|
+
:organisation
|
216
|
+
:person
|
217
|
+
:project
|
218
|
+
:publication
|
219
|
+
:publisher
|
220
|
+
```
|
221
|
+
|
222
|
+
Collections (for obtaining identifiers)
|
223
|
+
|
224
|
+
```ruby
|
225
|
+
:dataset
|
226
|
+
:journal
|
227
|
+
:organisation
|
228
|
+
:person
|
229
|
+
:project
|
230
|
+
:publication
|
231
|
+
:publisher
|
232
|
+
```
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/lib/puree.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'httparty'
|
2
|
+
require 'puree/date'
|
3
|
+
require 'puree/map'
|
4
|
+
require 'puree/resource'
|
5
|
+
require 'puree/dataset'
|
6
|
+
require 'puree/journal'
|
7
|
+
require 'puree/organisation'
|
8
|
+
require 'puree/person'
|
9
|
+
require 'puree/project'
|
10
|
+
require 'puree/publication'
|
11
|
+
require 'puree/publisher'
|
12
|
+
require 'puree/collection'
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module Puree
|
2
|
+
|
3
|
+
# Collection resource
|
4
|
+
#
|
5
|
+
class Collection < Resource
|
6
|
+
|
7
|
+
def initialize(resource_type: nil)
|
8
|
+
super(resource_type)
|
9
|
+
@uuids = []
|
10
|
+
end
|
11
|
+
|
12
|
+
# Get
|
13
|
+
#
|
14
|
+
# @param endpoint [String]
|
15
|
+
# @param username [String]
|
16
|
+
# @param password [String]
|
17
|
+
# @param qty [Integer]
|
18
|
+
# @return [HTTParty::Response]
|
19
|
+
def get(endpoint:nil, username:nil, password:nil, qty:nil)
|
20
|
+
# strip any trailing slash
|
21
|
+
@endpoint = endpoint.sub(/(\/)+$/, '')
|
22
|
+
@auth = Base64::strict_encode64(username + ':' + password)
|
23
|
+
|
24
|
+
@options = {
|
25
|
+
latest_api: true,
|
26
|
+
resource_type: @resource_type.to_sym,
|
27
|
+
rendering: :system,
|
28
|
+
qty: qty
|
29
|
+
}
|
30
|
+
headers = {
|
31
|
+
'Accept' => 'application/xml',
|
32
|
+
'Authorization' => 'Basic ' + @auth
|
33
|
+
}
|
34
|
+
query = {}
|
35
|
+
query['rendering'] = @options[:rendering]
|
36
|
+
if @options[:qty]
|
37
|
+
query['window.size'] = @options[:qty]
|
38
|
+
end
|
39
|
+
|
40
|
+
@response = HTTParty.get(url, query: query, headers: headers)
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
# Array of UUIDs
|
45
|
+
#
|
46
|
+
# @return [Array<String>]
|
47
|
+
def uuid
|
48
|
+
collect_uuid
|
49
|
+
@uuids
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
|
57
|
+
def collect_uuid
|
58
|
+
response_name = service_response_name
|
59
|
+
resp = @response[response_name]['result']['renderedItem']
|
60
|
+
arr = []
|
61
|
+
if resp.is_a?(Array)
|
62
|
+
arr = resp
|
63
|
+
else
|
64
|
+
arr << resp
|
65
|
+
end
|
66
|
+
arr.each do |a|
|
67
|
+
tableRows = a['div']['table']['tbody']['tr']
|
68
|
+
tableRows.each do |row|
|
69
|
+
if row['th'] === 'UUID'
|
70
|
+
uuid = row['td']
|
71
|
+
@uuids << uuid
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
@@ -0,0 +1,273 @@
|
|
1
|
+
module Puree
|
2
|
+
|
3
|
+
# Dataset resource
|
4
|
+
#
|
5
|
+
class Dataset < Resource
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
super(:dataset)
|
9
|
+
end
|
10
|
+
|
11
|
+
# Title
|
12
|
+
#
|
13
|
+
# @return [Array<String>]
|
14
|
+
def title
|
15
|
+
data = node 'title'
|
16
|
+
if !data.nil? && !data.empty?
|
17
|
+
data = data['localizedString']["__content__"]
|
18
|
+
data.is_a?(Array) ? data : data.split(',')
|
19
|
+
else
|
20
|
+
[]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# Keyword
|
25
|
+
#
|
26
|
+
# @return [Array<String>]
|
27
|
+
def keyword
|
28
|
+
data = node 'keywordGroups'
|
29
|
+
if !data.nil? && !data.empty?
|
30
|
+
data = data['keywordGroup']['keyword']['userDefinedKeyword']['freeKeyword']
|
31
|
+
data.is_a?(Array) ? data : data.split(',')
|
32
|
+
else
|
33
|
+
[]
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Description
|
38
|
+
#
|
39
|
+
# @return [Array<String>]
|
40
|
+
def description
|
41
|
+
data = node 'descriptions'
|
42
|
+
if !data.nil? && !data.empty?
|
43
|
+
data = data['classificationDefinedField']['value']['localizedString']['__content__'].tr("\n", '')
|
44
|
+
data.is_a?(Array) ? data : data.split(',')
|
45
|
+
else
|
46
|
+
[]
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# Person, internal and external
|
51
|
+
#
|
52
|
+
# @return [Hash<Array, Array>]
|
53
|
+
def person
|
54
|
+
data = node('persons')
|
55
|
+
persons = {}
|
56
|
+
if !data.nil? && !data.empty?
|
57
|
+
data = data['dataSetPersonAssociation']
|
58
|
+
else
|
59
|
+
return persons
|
60
|
+
end
|
61
|
+
internal_persons = []
|
62
|
+
external_persons = []
|
63
|
+
case data
|
64
|
+
when Array
|
65
|
+
data.each do |d|
|
66
|
+
person = generic_person d
|
67
|
+
if d.key? 'person'
|
68
|
+
person['uuid'] = d['person']['uuid']
|
69
|
+
internal_persons << person
|
70
|
+
end
|
71
|
+
if d.key? 'externalPerson'
|
72
|
+
person['uuid'] = d['externalPerson']['uuid']
|
73
|
+
external_persons << person
|
74
|
+
end
|
75
|
+
end
|
76
|
+
when Hash
|
77
|
+
person = generic_person data
|
78
|
+
if data.key? 'person'
|
79
|
+
person['uuid'] = data['person']['uuid']
|
80
|
+
internal_persons << person
|
81
|
+
end
|
82
|
+
if data.key? 'externalPerson'
|
83
|
+
person['uuid'] = data['externalPerson']['uuid']
|
84
|
+
external_persons << person
|
85
|
+
end
|
86
|
+
end
|
87
|
+
persons['internal'] = internal_persons
|
88
|
+
persons['external'] = external_persons
|
89
|
+
persons
|
90
|
+
end
|
91
|
+
|
92
|
+
# Publication
|
93
|
+
#
|
94
|
+
# @return [Array<Hash>]
|
95
|
+
def publication
|
96
|
+
data = node('relatedPublications')
|
97
|
+
publications = []
|
98
|
+
if !data.nil? && !data.empty?
|
99
|
+
# convert to array
|
100
|
+
data_arr = []
|
101
|
+
if data['relatedContent'].is_a?(Array)
|
102
|
+
data_arr = data['relatedContent']
|
103
|
+
else
|
104
|
+
data_arr[0] = data['relatedContent']
|
105
|
+
end
|
106
|
+
data_arr.each do |d|
|
107
|
+
o = {}
|
108
|
+
o['type'] = d['typeClassification']
|
109
|
+
o['title'] = d['title']
|
110
|
+
o['uuid'] = d['uuid']
|
111
|
+
publications << o
|
112
|
+
end
|
113
|
+
end
|
114
|
+
publications
|
115
|
+
end
|
116
|
+
|
117
|
+
# Date made available
|
118
|
+
#
|
119
|
+
# @return [Hash]
|
120
|
+
def available
|
121
|
+
data = node('dateMadeAvailable')
|
122
|
+
Puree::Date.normalise(data)
|
123
|
+
end
|
124
|
+
|
125
|
+
# Geographical coverage
|
126
|
+
#
|
127
|
+
# @return [Array<String>]
|
128
|
+
def geographical
|
129
|
+
data = node 'geographicalCoverage'
|
130
|
+
if !data.nil? && !data.empty?
|
131
|
+
data = data['localizedString']["__content__"]
|
132
|
+
data.is_a?(Array) ? data : data.split(',')
|
133
|
+
else
|
134
|
+
[]
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
# Temporal coverage
|
139
|
+
#
|
140
|
+
# @return [Hash]
|
141
|
+
def temporal
|
142
|
+
data = {}
|
143
|
+
data['start'] = {}
|
144
|
+
data['end'] = {}
|
145
|
+
start_date = temporal_coverage_start_date
|
146
|
+
if !start_date.nil? && !start_date.empty?
|
147
|
+
data['start'] = start_date
|
148
|
+
end
|
149
|
+
end_date = temporal_coverage_end_date
|
150
|
+
if !end_date.nil? && !end_date.empty?
|
151
|
+
data['end'] = end_date
|
152
|
+
end
|
153
|
+
data
|
154
|
+
end
|
155
|
+
|
156
|
+
# Open access permission
|
157
|
+
#
|
158
|
+
# @return [String]
|
159
|
+
def access
|
160
|
+
data = node 'openAccessPermission'
|
161
|
+
!data.nil? && !data.empty? ? data['term']['localizedString']["__content__"] : ''
|
162
|
+
end
|
163
|
+
|
164
|
+
|
165
|
+
# Supporting file
|
166
|
+
#
|
167
|
+
# @return [Array<Hash>]
|
168
|
+
def file
|
169
|
+
data = node 'documents'
|
170
|
+
|
171
|
+
docs = []
|
172
|
+
if !data.nil? && !data.empty?
|
173
|
+
# convert to array
|
174
|
+
data_arr = []
|
175
|
+
if data['document'].is_a?(Array)
|
176
|
+
data_arr = data['document']
|
177
|
+
else
|
178
|
+
data_arr << data['document']
|
179
|
+
end
|
180
|
+
|
181
|
+
data_arr.each do |d|
|
182
|
+
doc = {}
|
183
|
+
# doc['id'] = d['id']
|
184
|
+
doc['name'] = d['fileName']
|
185
|
+
doc['mime'] = d['mimeType']
|
186
|
+
doc['size'] = d['size']
|
187
|
+
doc['url'] = d['url']
|
188
|
+
doc['title'] = d['title']
|
189
|
+
# doc['createdDate'] = doc['createdDate']
|
190
|
+
# doc['visibleOnPortalDate'] = doc['visibleOnPortalDate']
|
191
|
+
# doc['limitedVisibility'] = doc['limitedVisibility']
|
192
|
+
|
193
|
+
license = {}
|
194
|
+
if d['documentLicense']
|
195
|
+
license_name = d['documentLicense']['term']['localizedString']['__content__']
|
196
|
+
license['name'] = license_name
|
197
|
+
license_url = d['documentLicense']['description']['localizedString']['__content__']
|
198
|
+
license['url'] = license_url
|
199
|
+
doc['license'] = license
|
200
|
+
end
|
201
|
+
docs << doc
|
202
|
+
|
203
|
+
end
|
204
|
+
end
|
205
|
+
docs
|
206
|
+
end
|
207
|
+
|
208
|
+
# Digital Object Identifier
|
209
|
+
#
|
210
|
+
# @return [String]
|
211
|
+
def doi
|
212
|
+
data = node 'doi'
|
213
|
+
!data.nil? && !data.empty? ? data['doi'] : ''
|
214
|
+
end
|
215
|
+
|
216
|
+
# def state
|
217
|
+
# # useful?
|
218
|
+
# data = node 'startedWorkflows'
|
219
|
+
# !data.empty? ? data['startedWorkflow']['state'] : ''
|
220
|
+
# end
|
221
|
+
|
222
|
+
# All metadata
|
223
|
+
#
|
224
|
+
# @return [Hash]
|
225
|
+
def metadata
|
226
|
+
o = {}
|
227
|
+
o['title'] = title
|
228
|
+
o['description'] = description
|
229
|
+
o['keyword'] = keyword
|
230
|
+
o['person'] = person
|
231
|
+
o['temporal'] = temporal
|
232
|
+
o['geographical'] = geographical
|
233
|
+
o['file'] = file
|
234
|
+
o['publication'] = publication
|
235
|
+
o['available'] = available
|
236
|
+
o['access'] = access
|
237
|
+
o['doi'] = doi
|
238
|
+
o
|
239
|
+
end
|
240
|
+
|
241
|
+
private
|
242
|
+
|
243
|
+
# Assembles basic information about a person
|
244
|
+
#
|
245
|
+
# @param generic_data [Hash]
|
246
|
+
# @return [Hash]
|
247
|
+
def generic_person(generic_data)
|
248
|
+
person = {}
|
249
|
+
name = {}
|
250
|
+
name['first'] = generic_data['name']['firstName']
|
251
|
+
name['last'] = generic_data['name']['lastName']
|
252
|
+
person['name'] = name
|
253
|
+
person['role'] = generic_data['personRole']['term']['localizedString']["__content__"]
|
254
|
+
person
|
255
|
+
end
|
256
|
+
|
257
|
+
# Temporal coverage start date
|
258
|
+
#
|
259
|
+
# @return [Hash]
|
260
|
+
def temporal_coverage_start_date
|
261
|
+
data = node('temporalCoverageStartDate')
|
262
|
+
!data.nil? && !data.empty? ? Puree::Date.normalise(data) : {}
|
263
|
+
end
|
264
|
+
|
265
|
+
# Temporal coverage end date
|
266
|
+
#
|
267
|
+
# @return [Hash]
|
268
|
+
def temporal_coverage_end_date
|
269
|
+
data = node('temporalCoverageEndDate')
|
270
|
+
!data.nil? && !data.empty? ? Puree::Date.normalise(data) : {}
|
271
|
+
end
|
272
|
+
end
|
273
|
+
end
|
data/lib/puree/date.rb
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
module Puree
|
2
|
+
|
3
|
+
module Date
|
4
|
+
|
5
|
+
# Converts a date with three components (year, month, day) to ISO8601 format
|
6
|
+
#
|
7
|
+
# @param data [Hash]
|
8
|
+
# @return [String]
|
9
|
+
def self.iso(data)
|
10
|
+
iso_date = ''
|
11
|
+
year = data['year']
|
12
|
+
month = data['month']
|
13
|
+
day = data['day']
|
14
|
+
if !year.empty?
|
15
|
+
iso_date << year
|
16
|
+
else
|
17
|
+
iso_date
|
18
|
+
end
|
19
|
+
if !month.empty?
|
20
|
+
# Add leading zero to convert to ISO 8601
|
21
|
+
if month.length < 2
|
22
|
+
month.insert(0, '0')
|
23
|
+
end
|
24
|
+
iso_date << '-' + month
|
25
|
+
else
|
26
|
+
iso_date
|
27
|
+
end
|
28
|
+
if !day.empty?
|
29
|
+
# Add leading zero to convert to ISO 8601
|
30
|
+
if day.length < 2
|
31
|
+
day.insert(0, '0')
|
32
|
+
end
|
33
|
+
iso_date << '-' + day
|
34
|
+
end
|
35
|
+
iso_date
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
# Forces a date to have three components (year, month, day)
|
41
|
+
#
|
42
|
+
# @param data [Hash]
|
43
|
+
# @return [Hash]
|
44
|
+
def self.normalise(data)
|
45
|
+
if !data.nil? && !data.empty?
|
46
|
+
date = {}
|
47
|
+
year = data['year']
|
48
|
+
month = data['month']
|
49
|
+
day = data['day']
|
50
|
+
date['year'] = year ? year : ''
|
51
|
+
date['month'] = month ? month : ''
|
52
|
+
date['day'] = day ? day : ''
|
53
|
+
date
|
54
|
+
else
|
55
|
+
{}
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
data/lib/puree/map.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
module Puree
|
2
|
+
|
3
|
+
class Map
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@convention = %w(
|
7
|
+
journal
|
8
|
+
organisation
|
9
|
+
person
|
10
|
+
project
|
11
|
+
publication
|
12
|
+
publisher
|
13
|
+
)
|
14
|
+
|
15
|
+
@api_map = {
|
16
|
+
resource_type: {
|
17
|
+
dataset: {
|
18
|
+
service: 'datasets',
|
19
|
+
response: 'GetDataSetsResponse'
|
20
|
+
}
|
21
|
+
}
|
22
|
+
}
|
23
|
+
|
24
|
+
add_convention
|
25
|
+
end
|
26
|
+
|
27
|
+
# Pure API map
|
28
|
+
#
|
29
|
+
# @return [Hash]
|
30
|
+
def get
|
31
|
+
@api_map
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def add_convention
|
38
|
+
@convention.each do |c|
|
39
|
+
resource_type = {}
|
40
|
+
resource_type[:service] = c
|
41
|
+
resource_type[:response] = 'Get' + c.capitalize + 'Response'
|
42
|
+
@api_map[:resource_type][c.to_sym] = resource_type
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
data/lib/puree/person.rb
ADDED
@@ -0,0 +1,124 @@
|
|
1
|
+
module Puree
|
2
|
+
|
3
|
+
# Abstract base class for resources.
|
4
|
+
#
|
5
|
+
class Resource
|
6
|
+
|
7
|
+
def initialize(resource_type)
|
8
|
+
@resource_type = resource_type
|
9
|
+
@api_map = Puree::Map.new.get
|
10
|
+
end
|
11
|
+
|
12
|
+
# Get
|
13
|
+
#
|
14
|
+
# @param endpoint [String]
|
15
|
+
# @param username [String]
|
16
|
+
# @param password [String]
|
17
|
+
# @param uuid [String]
|
18
|
+
# @param id [String]
|
19
|
+
# @return [HTTParty::Response]
|
20
|
+
def get(endpoint:nil, username:nil, password:nil, uuid:nil, id:nil)
|
21
|
+
# strip any trailing slash
|
22
|
+
@endpoint = endpoint.sub(/(\/)+$/, '')
|
23
|
+
@auth = Base64::strict_encode64(username + ':' + password)
|
24
|
+
|
25
|
+
@options = {
|
26
|
+
latest_api: true,
|
27
|
+
resource_type: @resource_type.to_sym,
|
28
|
+
rendering: :xml_long,
|
29
|
+
uuid: uuid,
|
30
|
+
id: id,
|
31
|
+
}
|
32
|
+
headers = {
|
33
|
+
'Accept' => 'application/xml',
|
34
|
+
'Authorization' => 'Basic ' + @auth
|
35
|
+
}
|
36
|
+
query = {}
|
37
|
+
query['rendering'] = @options[:rendering]
|
38
|
+
if @options[:uuid]
|
39
|
+
query['uuids.uuid'] = @options[:uuid]
|
40
|
+
else
|
41
|
+
if @options[:id]
|
42
|
+
query['pureInternalIds.id'] = @options[:id]
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
@response = HTTParty.get(url, query: query, headers: headers)
|
47
|
+
|
48
|
+
if get_data?
|
49
|
+
response_name = service_response_name
|
50
|
+
content = @response.parsed_response[response_name]['result']['content']
|
51
|
+
set_content(content)
|
52
|
+
end
|
53
|
+
@response
|
54
|
+
end
|
55
|
+
|
56
|
+
# Response, if get method has been called
|
57
|
+
#
|
58
|
+
# @return [HTTParty::Response]
|
59
|
+
# @return [Nil]
|
60
|
+
def response
|
61
|
+
@response ? @response : nil
|
62
|
+
end
|
63
|
+
|
64
|
+
# Set content
|
65
|
+
#
|
66
|
+
# @param content [Hash]
|
67
|
+
def set_content(content)
|
68
|
+
if !content.nil? && !content.empty?
|
69
|
+
@content = content
|
70
|
+
else
|
71
|
+
@content = {}
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# Content
|
76
|
+
#
|
77
|
+
# @return [Hash]
|
78
|
+
def content
|
79
|
+
@content ? @content : {}
|
80
|
+
end
|
81
|
+
|
82
|
+
|
83
|
+
|
84
|
+
private
|
85
|
+
|
86
|
+
|
87
|
+
|
88
|
+
# Node
|
89
|
+
#
|
90
|
+
# @return [Hash]
|
91
|
+
def node(name)
|
92
|
+
@content ? @content[name] : {}
|
93
|
+
end
|
94
|
+
|
95
|
+
# Is there any data after get?
|
96
|
+
#
|
97
|
+
# @return [Boolean]
|
98
|
+
def get_data?
|
99
|
+
response_name = service_response_name
|
100
|
+
@response.parsed_response[response_name]['count'] != '0' ? true : false
|
101
|
+
end
|
102
|
+
|
103
|
+
def service_name
|
104
|
+
resource_type = @options[:resource_type]
|
105
|
+
@api_map[:resource_type][resource_type][:service]
|
106
|
+
end
|
107
|
+
|
108
|
+
def service_response_name
|
109
|
+
resource_type = @options[:resource_type]
|
110
|
+
@api_map[:resource_type][resource_type][:response]
|
111
|
+
end
|
112
|
+
|
113
|
+
def url
|
114
|
+
service = service_name
|
115
|
+
if @options[:latest_api] === false
|
116
|
+
service_api_mode = service
|
117
|
+
else
|
118
|
+
service_api_mode = service + '.current'
|
119
|
+
end
|
120
|
+
@endpoint + '/' + service_api_mode
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
124
|
+
end
|
data/puree.gemspec
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'puree/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "puree"
|
8
|
+
spec.version = Puree::VERSION
|
9
|
+
spec.authors = ["Adrian Albin-Clark"]
|
10
|
+
spec.email = ["a.albin-clark@lancaster.ac.uk"]
|
11
|
+
spec.summary = %q{A client for the Pure Research Information System API.}
|
12
|
+
spec.description = %q{Consumes the Pure Research Information System API and facilitates post-processing of metadata into simple data structures.}
|
13
|
+
spec.homepage = "https://github.com/lulibrary/puree.git"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_runtime_dependency 'httparty', '~> 0'
|
22
|
+
spec.add_development_dependency "bundler", "~> 1.5"
|
23
|
+
spec.add_development_dependency 'rake', '~> 0'
|
24
|
+
end
|
data/spec/collection.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Collection' do
|
4
|
+
|
5
|
+
it '#new' do
|
6
|
+
p = Puree::Collection.new(resource_type: :dataset)
|
7
|
+
expect(p).to be_an_instance_of Puree::Collection
|
8
|
+
end
|
9
|
+
|
10
|
+
describe 'data retrieval' do
|
11
|
+
before(:all) do
|
12
|
+
endpoint = ENV['PURE_ENDPOINT']
|
13
|
+
username = ENV['PURE_USERNAME']
|
14
|
+
password = ENV['PURE_PASSWORD']
|
15
|
+
@p = Puree::Collection.new(resource_type: :dataset)
|
16
|
+
@p.get endpoint: endpoint,
|
17
|
+
username: username,
|
18
|
+
password: password
|
19
|
+
end
|
20
|
+
|
21
|
+
it '#UUID' do
|
22
|
+
expect(@p.uuid).to be_an_instance_of(Array)
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
data/spec/dataset.rb
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Dataset' do
|
4
|
+
|
5
|
+
it '#new' do
|
6
|
+
p = Puree::Dataset.new
|
7
|
+
expect(p).to be_an_instance_of Puree::Dataset
|
8
|
+
end
|
9
|
+
|
10
|
+
describe 'data retrieval' do
|
11
|
+
before(:all) do
|
12
|
+
endpoint = ENV['PURE_ENDPOINT']
|
13
|
+
username = ENV['PURE_USERNAME']
|
14
|
+
password = ENV['PURE_PASSWORD']
|
15
|
+
uuid = ENV['PURE_DATASET_UUID']
|
16
|
+
@p = Puree::Dataset.new
|
17
|
+
@p.get endpoint: endpoint,
|
18
|
+
username: username,
|
19
|
+
password: password,
|
20
|
+
uuid: uuid
|
21
|
+
end
|
22
|
+
|
23
|
+
it '#title' do
|
24
|
+
expect(@p.title).to be_an_instance_of(Array)
|
25
|
+
end
|
26
|
+
|
27
|
+
it '#keyword' do
|
28
|
+
expect(@p.keyword).to be_an_instance_of(Array)
|
29
|
+
end
|
30
|
+
|
31
|
+
it '#description' do
|
32
|
+
expect(@p.description).to be_an_instance_of(Array)
|
33
|
+
end
|
34
|
+
|
35
|
+
it '#person' do
|
36
|
+
expect(@p.person).to be_an_instance_of(Hash)
|
37
|
+
end
|
38
|
+
|
39
|
+
it '#publication' do
|
40
|
+
expect(@p.publication).to be_an_instance_of(Array)
|
41
|
+
end
|
42
|
+
|
43
|
+
it '#available' do
|
44
|
+
expect(@p.available).to be_an_instance_of(Hash)
|
45
|
+
end
|
46
|
+
|
47
|
+
it '#geographical' do
|
48
|
+
expect(@p.geographical).to be_an_instance_of(Array)
|
49
|
+
end
|
50
|
+
|
51
|
+
it '#temporal' do
|
52
|
+
expect(@p.temporal).to be_an_instance_of(Hash)
|
53
|
+
end
|
54
|
+
|
55
|
+
it '#access' do
|
56
|
+
expect(@p.access).to be_an_instance_of(String)
|
57
|
+
end
|
58
|
+
|
59
|
+
it '#file' do
|
60
|
+
expect(@p.file).to be_an_instance_of(Array)
|
61
|
+
end
|
62
|
+
|
63
|
+
it '#doi' do
|
64
|
+
expect(@p.doi).to be_an_instance_of(String)
|
65
|
+
end
|
66
|
+
|
67
|
+
it '#metadata' do
|
68
|
+
expect(@p.metadata).to be_an_instance_of(Hash)
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'httparty'
|
2
|
+
require 'puree/date'
|
3
|
+
require 'puree/map'
|
4
|
+
require 'puree/resource'
|
5
|
+
require 'puree/dataset'
|
6
|
+
require 'puree/journal'
|
7
|
+
require 'puree/organisation'
|
8
|
+
require 'puree/person'
|
9
|
+
require 'puree/project'
|
10
|
+
require 'puree/publication'
|
11
|
+
require 'puree/publisher'
|
12
|
+
require 'puree/collection'
|
metadata
ADDED
@@ -0,0 +1,114 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: puree
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.6.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Adrian Albin-Clark
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-05-06 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: httparty
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.5'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.5'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
description: Consumes the Pure Research Information System API and facilitates post-processing
|
56
|
+
of metadata into simple data structures.
|
57
|
+
email:
|
58
|
+
- a.albin-clark@lancaster.ac.uk
|
59
|
+
executables: []
|
60
|
+
extensions: []
|
61
|
+
extra_rdoc_files: []
|
62
|
+
files:
|
63
|
+
- ".gitignore"
|
64
|
+
- CHANGELOG.md
|
65
|
+
- Gemfile
|
66
|
+
- LICENSE.txt
|
67
|
+
- README.md
|
68
|
+
- Rakefile
|
69
|
+
- lib/puree.rb
|
70
|
+
- lib/puree/collection.rb
|
71
|
+
- lib/puree/dataset.rb
|
72
|
+
- lib/puree/date.rb
|
73
|
+
- lib/puree/journal.rb
|
74
|
+
- lib/puree/map.rb
|
75
|
+
- lib/puree/organisation.rb
|
76
|
+
- lib/puree/person.rb
|
77
|
+
- lib/puree/project.rb
|
78
|
+
- lib/puree/publication.rb
|
79
|
+
- lib/puree/publisher.rb
|
80
|
+
- lib/puree/resource.rb
|
81
|
+
- lib/puree/version.rb
|
82
|
+
- puree.gemspec
|
83
|
+
- spec/collection.rb
|
84
|
+
- spec/dataset.rb
|
85
|
+
- spec/spec_helper.rb
|
86
|
+
homepage: https://github.com/lulibrary/puree.git
|
87
|
+
licenses:
|
88
|
+
- MIT
|
89
|
+
metadata: {}
|
90
|
+
post_install_message:
|
91
|
+
rdoc_options: []
|
92
|
+
require_paths:
|
93
|
+
- lib
|
94
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
95
|
+
requirements:
|
96
|
+
- - ">="
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: '0'
|
99
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
requirements: []
|
105
|
+
rubyforge_project:
|
106
|
+
rubygems_version: 2.2.2
|
107
|
+
signing_key:
|
108
|
+
specification_version: 4
|
109
|
+
summary: A client for the Pure Research Information System API.
|
110
|
+
test_files:
|
111
|
+
- spec/collection.rb
|
112
|
+
- spec/dataset.rb
|
113
|
+
- spec/spec_helper.rb
|
114
|
+
has_rdoc:
|