nesstar_rest_api_client 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.
- data/LICENSE +0 -0
- data/README.md +28 -0
- data/lib/nesstar-api.rb +14 -0
- data/lib/nesstar-api/category.rb +22 -0
- data/lib/nesstar-api/nesstar-object.rb +36 -0
- data/lib/nesstar-api/rest-client.rb +57 -0
- data/lib/nesstar-api/server.rb +30 -0
- data/lib/nesstar-api/study.rb +118 -0
- data/lib/nesstar-api/tabulation.rb +14 -0
- data/lib/nesstar-api/variable-container.rb +20 -0
- data/lib/nesstar-api/variable-group.rb +25 -0
- data/lib/nesstar-api/variable.rb +43 -0
- metadata +56 -0
data/LICENSE
ADDED
File without changes
|
data/README.md
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# Nesstar API for Ruby
|
2
|
+
|
3
|
+
This is Nesstar REST API client written in Ruby. It represents the REST endpoints as plain old Ruby objects.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
```
|
8
|
+
$ rake install
|
9
|
+
```
|
10
|
+
|
11
|
+
## Getting started
|
12
|
+
|
13
|
+
Connect to a server like this:
|
14
|
+
|
15
|
+
```
|
16
|
+
server = NesstarAPI.get_server "http://my-instance-of-nesstar-rest-api.com"
|
17
|
+
```
|
18
|
+
|
19
|
+
From a server object you can list studies or load individual studies by ID:
|
20
|
+
|
21
|
+
```
|
22
|
+
studies = server.get_studies
|
23
|
+
my_study = server.get_study "my-study-id"
|
24
|
+
```
|
25
|
+
|
26
|
+
## Documentation
|
27
|
+
|
28
|
+
Run `rake docs` to build the documentation. The documentation will appear in the `docs` folder.
|
data/lib/nesstar-api.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'nesstar-api/rest-client.rb'
|
2
|
+
require 'nesstar-api/server.rb'
|
3
|
+
|
4
|
+
##
|
5
|
+
# This module is the starting point. Use this to get an instance of a server.
|
6
|
+
module NesstarAPI
|
7
|
+
|
8
|
+
##
|
9
|
+
# Gets a server identified by a URL
|
10
|
+
def self.get_server(url)
|
11
|
+
RestClient.instance.init url
|
12
|
+
Server.new
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'nesstar-api/nesstar-object.rb'
|
2
|
+
|
3
|
+
##
|
4
|
+
# A category in a variable.
|
5
|
+
#
|
6
|
+
# Categories have a name, a label, and a frequency
|
7
|
+
class Category < NesstarObject
|
8
|
+
attr_reader :name, :label, :frequency
|
9
|
+
|
10
|
+
def initialize(data)
|
11
|
+
@label = data['label']
|
12
|
+
@value = data['value']
|
13
|
+
@frequency = data['frequency']
|
14
|
+
@missing = data['missing'] == 'true'
|
15
|
+
end
|
16
|
+
|
17
|
+
##
|
18
|
+
# Returns true if this category is missing
|
19
|
+
def missing?
|
20
|
+
@missing
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'nesstar-api/rest-client.rb'
|
2
|
+
|
3
|
+
##
|
4
|
+
# A parent class for all Nesstar objects.
|
5
|
+
class NesstarObject
|
6
|
+
|
7
|
+
private
|
8
|
+
|
9
|
+
def load_metadata
|
10
|
+
path = "#{self.class.name.downcase}/#{@id}"
|
11
|
+
@@data ||= get_values path
|
12
|
+
end
|
13
|
+
|
14
|
+
def metadata
|
15
|
+
load_metadata
|
16
|
+
end
|
17
|
+
|
18
|
+
def get_values(path)
|
19
|
+
RestClient.instance.get_values path
|
20
|
+
end
|
21
|
+
|
22
|
+
def get_binary(path, &block)
|
23
|
+
RestClient.instance.get_binary(path, &block)
|
24
|
+
end
|
25
|
+
|
26
|
+
def dig(hash, *path)
|
27
|
+
if hash.nil?
|
28
|
+
nil
|
29
|
+
elsif path.length == 1
|
30
|
+
hash[path.pop.to_s]
|
31
|
+
elsif hash.respond_to?(:keys)
|
32
|
+
key = path.shift.to_s
|
33
|
+
dig(hash[key], *path)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'net/http'
|
3
|
+
require 'uri'
|
4
|
+
require 'singleton'
|
5
|
+
|
6
|
+
class RestClient
|
7
|
+
include Singleton
|
8
|
+
|
9
|
+
def init(url)
|
10
|
+
unless url =~ /\//
|
11
|
+
url = url + '/'
|
12
|
+
end
|
13
|
+
@@url = url
|
14
|
+
end
|
15
|
+
|
16
|
+
def get_values(path)
|
17
|
+
uri = get_uri(path)
|
18
|
+
response = Net::HTTP.get_response uri
|
19
|
+
if response.is_a? Net::HTTPServerError
|
20
|
+
raise ServerError, parse_server_error(response.body)
|
21
|
+
end
|
22
|
+
json = JSON.parse response.body
|
23
|
+
|
24
|
+
json['payload']
|
25
|
+
end
|
26
|
+
|
27
|
+
def get_binary(path)
|
28
|
+
uri = get_uri(path)
|
29
|
+
Net::HTTP.start(uri.host, uri.port) do | http |
|
30
|
+
response = http.get(uri.request_uri)
|
31
|
+
if response.is_a? Net::HTTPServerError
|
32
|
+
raise ServerError, parse_server_error(response.body)
|
33
|
+
end
|
34
|
+
yield(response.body)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def get_uri(path)
|
41
|
+
url = @@url + path
|
42
|
+
URI.parse url
|
43
|
+
end
|
44
|
+
|
45
|
+
def parse_server_error(error)
|
46
|
+
begin
|
47
|
+
json = JSON.parse(error)
|
48
|
+
error = json['error']
|
49
|
+
"#{error['type']}: #{error['message']}"
|
50
|
+
rescue JSON::ParserError
|
51
|
+
"Fatal: Unknown server error occurred"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
class ServerError < StandardError
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'nesstar-api/nesstar-object.rb'
|
2
|
+
require 'nesstar-api/study.rb'
|
3
|
+
|
4
|
+
##
|
5
|
+
# Represents the server.
|
6
|
+
class Server < NesstarObject
|
7
|
+
|
8
|
+
##
|
9
|
+
# Get a list of studies on the server.
|
10
|
+
def get_studies
|
11
|
+
json_studies = get_values "studies"
|
12
|
+
json_studies.collect do | study |
|
13
|
+
Study.new study
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
##
|
18
|
+
# Get a particular study identified by its ID.
|
19
|
+
def get_study(id)
|
20
|
+
json = get_values "study/#{id}"
|
21
|
+
if json
|
22
|
+
study_id = dig(json, :ID)
|
23
|
+
name = dig(json, :stdyDscr, :citation, :titlStmt, :titl)
|
24
|
+
abstract = dig(json, :stdyDscr, :stdyInfo, :abstract)
|
25
|
+
|
26
|
+
Study.new({'id' => study_id, 'name' => name, 'abstract' => abstract})
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
require 'tempfile'
|
2
|
+
require 'nesstar-api/nesstar-object'
|
3
|
+
require 'nesstar-api/variable'
|
4
|
+
require 'nesstar-api/variable-group'
|
5
|
+
require 'nesstar-api/variable-container'
|
6
|
+
require 'nesstar-api/tabulation'
|
7
|
+
|
8
|
+
## Represents a study
|
9
|
+
class Study < NesstarObject
|
10
|
+
attr_reader :id, :name, :abstract
|
11
|
+
|
12
|
+
include VariableContainer
|
13
|
+
|
14
|
+
NSDSTAT = "NSDSTAT"
|
15
|
+
SAS = "SAS"
|
16
|
+
SPSS = "SPSS"
|
17
|
+
SPSSPORT = "SPSSPORT"
|
18
|
+
STATA = "STATA"
|
19
|
+
STATA6 = "STATA6"
|
20
|
+
STATA7 = "STATA7"
|
21
|
+
|
22
|
+
def initialize(data)
|
23
|
+
@id = data['id']
|
24
|
+
@name = data['name']
|
25
|
+
@abstract = data['abstract']
|
26
|
+
@last_update = data['updatedTimeStamp']
|
27
|
+
end
|
28
|
+
|
29
|
+
##
|
30
|
+
# Returns a cross tabulation on this study
|
31
|
+
#
|
32
|
+
# The options parameter holds the following data:
|
33
|
+
#
|
34
|
+
# * +breakVars+ - A list of variable objects
|
35
|
+
# * +msrVar+ - The measure variable, if any
|
36
|
+
# * +msrType+ - A list of measure types to use. Valid types are MEAN, MEDIAN, STDDEV, MIN, MAX, SUM, COUNT, CI95MIN, CI95MAX, CI99MIN, CI99MAX, Q1, Q3, WHISKER_LO, WHISKER_HI, SUM_SQUARES, SE_MEAN
|
37
|
+
# * +casesubset+ - A subset expression to limit the categories to include. Documentation on expressions is found here: http://nesstar-dev.nsd.uib.no/javadoc/com.nesstar/nesstar-api/0.6.5/com/nesstar/api/subset/CaseSubset.html#compile
|
38
|
+
def tabulate(options)
|
39
|
+
path = "study/#{@id}/tabulate/"
|
40
|
+
query_string = prepare_query_string_for_tabulation options
|
41
|
+
|
42
|
+
if query_string.length > 0
|
43
|
+
path += "?" + query_string.join('&')
|
44
|
+
end
|
45
|
+
|
46
|
+
tabulation = get_values path
|
47
|
+
Tabulation.new tabulation, options
|
48
|
+
end
|
49
|
+
|
50
|
+
def correlate
|
51
|
+
end
|
52
|
+
|
53
|
+
def regress
|
54
|
+
end
|
55
|
+
|
56
|
+
##
|
57
|
+
# Downloads the study (or parts of it) in different file formats.
|
58
|
+
#
|
59
|
+
# The file will be a zip file containing one or more files depending on the requested format.
|
60
|
+
#
|
61
|
+
# The +format+ parameter should be one of the constants in this class.
|
62
|
+
#
|
63
|
+
# To only download some variables, supply a list of the variables you wish.
|
64
|
+
#
|
65
|
+
# The download can be further refined using a case subset. See http://nesstar-dev.nsd.uib.no/javadoc/com.nesstar/nesstar-api/0.6.5/com/nesstar/api/subset/CaseSubset.html#compile for more information.
|
66
|
+
def download(format, variables = [], case_subset = nil)
|
67
|
+
path = "study/#{@id}/download"
|
68
|
+
|
69
|
+
query_string = ["format=" + format]
|
70
|
+
query_string += collect_list(variables, "var", :id)
|
71
|
+
query_string.push("caseSubset=" + case_subset) unless case_subset.nil?
|
72
|
+
|
73
|
+
path += "?" + query_string.join('&')
|
74
|
+
|
75
|
+
get_binary(path) do | data |
|
76
|
+
if block_given?
|
77
|
+
yield(data)
|
78
|
+
else
|
79
|
+
file = Tempfile.new("#{@name}.#{format}")
|
80
|
+
file.write(data)
|
81
|
+
file.close
|
82
|
+
return file
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
private
|
88
|
+
|
89
|
+
def get_variable_group_type
|
90
|
+
'variable-groups'
|
91
|
+
end
|
92
|
+
|
93
|
+
def get_rest_type
|
94
|
+
'study'
|
95
|
+
end
|
96
|
+
|
97
|
+
def prepare_query_string_for_tabulation(options)
|
98
|
+
query_string = []
|
99
|
+
|
100
|
+
query_string += collect_list(options['breakVars'], 'breakVar', :id)
|
101
|
+
query_string += collect_list(options['msrType'], 'msrType')
|
102
|
+
query_string.push "msrVar=#{options['msrVar'].id}" unless options['mrsVar'].nil?
|
103
|
+
query_string.push(options['casesubset']) unless options['casesubset'].nil?
|
104
|
+
|
105
|
+
query_string
|
106
|
+
end
|
107
|
+
|
108
|
+
def collect_list(list, name, attribute = nil)
|
109
|
+
if list.nil?
|
110
|
+
[]
|
111
|
+
else
|
112
|
+
list.collect { | obj |
|
113
|
+
value = attribute.nil? ? obj : obj.send(attribute)
|
114
|
+
"#{name}=#{value}"
|
115
|
+
}
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
##
|
2
|
+
# Represents a tabulation run on a +Study+.
|
3
|
+
class Tabulation
|
4
|
+
attr_reader :data, :variables, :measure, :measure_types, :case_subset
|
5
|
+
|
6
|
+
def initialize(data, input)
|
7
|
+
@data = data['data']
|
8
|
+
@variables = input['breakVars']
|
9
|
+
@measure = input['msrVar']
|
10
|
+
@measure_types = input['msrType']
|
11
|
+
@case_subset = input['casesubset']
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module VariableContainer
|
2
|
+
|
3
|
+
##
|
4
|
+
# Gets a list of variables.
|
5
|
+
def get_variables
|
6
|
+
json_variables = get_values "#{get_rest_type}/#{@id}/variables"
|
7
|
+
json_variables.collect do | variable_json |
|
8
|
+
Variable.new variable_json
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
##
|
13
|
+
# Gets a list of variable groups.
|
14
|
+
def get_variable_groups
|
15
|
+
json_variable_groups = get_values "#{get_rest_type}/#{@id}/#{get_variable_group_type}"
|
16
|
+
json_variable_groups.collect do | variable_group_json |
|
17
|
+
VariableGroup.new variable_group_json
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'nesstar-api/nesstar-object.rb'
|
2
|
+
require 'nesstar-api/variable-container.rb'
|
3
|
+
|
4
|
+
##
|
5
|
+
# Represents a group of variables in a +Study+.
|
6
|
+
class VariableGroup < NesstarObject
|
7
|
+
include VariableContainer
|
8
|
+
|
9
|
+
attr_reader :id, :name
|
10
|
+
|
11
|
+
def initialize(data)
|
12
|
+
@id = data['id']
|
13
|
+
@name = data['name']
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def get_variable_group_type
|
19
|
+
'child-groups'
|
20
|
+
end
|
21
|
+
|
22
|
+
def get_rest_type
|
23
|
+
'variable-group'
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'nesstar-api/nesstar-object.rb'
|
2
|
+
require 'nesstar-api/category.rb'
|
3
|
+
|
4
|
+
##
|
5
|
+
# Represents a variable in a +Study+.
|
6
|
+
class Variable < NesstarObject
|
7
|
+
attr_reader :id, :name, :label
|
8
|
+
|
9
|
+
def initialize(data, eager = false)
|
10
|
+
@id = data['id']
|
11
|
+
@name = data['name']
|
12
|
+
@label = data['label']
|
13
|
+
if eager
|
14
|
+
load_metadata
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
##
|
19
|
+
# Indicates whether the variable is discrete.
|
20
|
+
def discrete?
|
21
|
+
metadata['intrvl'] == 'discrete'
|
22
|
+
end
|
23
|
+
|
24
|
+
##
|
25
|
+
# Indicates whether the variable is continuous.
|
26
|
+
def continuous?
|
27
|
+
metadata['intrvl'] == 'continuous'
|
28
|
+
end
|
29
|
+
|
30
|
+
##
|
31
|
+
# Indicates whether this is a weight variable
|
32
|
+
def weighted?
|
33
|
+
metadata['wgt']
|
34
|
+
end
|
35
|
+
|
36
|
+
##
|
37
|
+
# Returns a list of categories in this variable
|
38
|
+
def get_categories
|
39
|
+
metadata['catgry'].collect do | category |
|
40
|
+
Category.new category
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
metadata
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: nesstar_rest_api_client
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Ricco Førgaard
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-11-18 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description:
|
15
|
+
email: ricco@fiskeben.dk
|
16
|
+
executables: []
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files: []
|
19
|
+
files:
|
20
|
+
- lib/nesstar-api.rb
|
21
|
+
- lib/nesstar-api/variable.rb
|
22
|
+
- lib/nesstar-api/category.rb
|
23
|
+
- lib/nesstar-api/variable-group.rb
|
24
|
+
- lib/nesstar-api/server.rb
|
25
|
+
- lib/nesstar-api/variable-container.rb
|
26
|
+
- lib/nesstar-api/study.rb
|
27
|
+
- lib/nesstar-api/tabulation.rb
|
28
|
+
- lib/nesstar-api/rest-client.rb
|
29
|
+
- lib/nesstar-api/nesstar-object.rb
|
30
|
+
- LICENSE
|
31
|
+
- README.md
|
32
|
+
homepage: http://www.nesstar.com
|
33
|
+
licenses: []
|
34
|
+
post_install_message:
|
35
|
+
rdoc_options: []
|
36
|
+
require_paths:
|
37
|
+
- lib
|
38
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
44
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
45
|
+
none: false
|
46
|
+
requirements:
|
47
|
+
- - ! '>='
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '0'
|
50
|
+
requirements: []
|
51
|
+
rubyforge_project:
|
52
|
+
rubygems_version: 1.8.23
|
53
|
+
signing_key:
|
54
|
+
specification_version: 3
|
55
|
+
summary: Client for Nesstar REST API
|
56
|
+
test_files: []
|