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