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 ADDED
File without changes
@@ -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.
@@ -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: []