puree 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- 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:
|