dencity 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +13 -0
- data/.rspec +2 -0
- data/.rubocop.yml +139 -0
- data/.travis.yml +4 -0
- data/Gemfile +4 -0
- data/README.md +164 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/dencity.gemspec +38 -0
- data/example_script.rb +152 -0
- data/lib/dencity.rb +18 -0
- data/lib/dencity/client.rb +162 -0
- data/lib/dencity/client/analysis.rb +91 -0
- data/lib/dencity/client/search.rb +20 -0
- data/lib/dencity/client/structure.rb +158 -0
- data/lib/dencity/error.rb +18 -0
- data/lib/dencity/related_file.rb +2 -0
- data/lib/dencity/request.rb +46 -0
- data/lib/dencity/response.rb +18 -0
- data/lib/dencity/version.rb +4 -0
- data/lib/faraday/raise_http_exception.rb +45 -0
- metadata +180 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 15c325015a579f5731901814dd2e70d850f436e0
|
4
|
+
data.tar.gz: aa12fc419b0af227e1991337bf9828165beb0420
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: dcc65b80b293093023dab072673e5a925e3f997213f879f97d2c6a139966f2f0710f0f080110e72229041a6a38e4d2c3f8fe1dcd99e7e326337865e2272b206f
|
7
|
+
data.tar.gz: 88a940ed12da942654fb532e880b69dda1714ae15494a21898dd4c2673b5ad34f41a1f62d11889c2b771ab290be24e6a712bd56cce1fbf8f0ba5fd84427c77b0
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,139 @@
|
|
1
|
+
AllCops:
|
2
|
+
Exclude:
|
3
|
+
- 'measures/**/*'
|
4
|
+
- 'spec/files/**/measures/**/*'
|
5
|
+
- '**/measure.rb'
|
6
|
+
- 'spec/files/mongoid/models/**/*'
|
7
|
+
- 'spec/files/pat_project/data_point_*/**/*'
|
8
|
+
- 'spec/files/pat_project/run/**/*'
|
9
|
+
- 'spec/files/mongo_pat1/run/**/*'
|
10
|
+
|
11
|
+
# ==================== Linters ====================
|
12
|
+
Lint/AmbiguousOperator:
|
13
|
+
Enabled: true
|
14
|
+
|
15
|
+
Lint/BlockAlignment:
|
16
|
+
Enabled: true
|
17
|
+
|
18
|
+
Lint/ParenthesesAsGroupedExpression:
|
19
|
+
Enabled: true
|
20
|
+
|
21
|
+
Lint/RequireParentheses:
|
22
|
+
Enabled: true
|
23
|
+
|
24
|
+
# Offense count: 1
|
25
|
+
Lint/UnreachableCode:
|
26
|
+
Enabled: false
|
27
|
+
|
28
|
+
# Offense count: 51
|
29
|
+
Lint/UselessAssignment:
|
30
|
+
Enabled: true
|
31
|
+
|
32
|
+
# ==================== Styles / Metrics====================
|
33
|
+
# Offense count: 4
|
34
|
+
Metrics/BlockNesting:
|
35
|
+
Max: 4
|
36
|
+
|
37
|
+
# Offense count: 18
|
38
|
+
# Configuration parameters: CountComments.
|
39
|
+
Metrics/ClassLength:
|
40
|
+
Max: 500
|
41
|
+
|
42
|
+
# Offense count: 27
|
43
|
+
Metrics/CyclomaticComplexity:
|
44
|
+
Max: 48
|
45
|
+
|
46
|
+
# Offense count: 974
|
47
|
+
Metrics/LineLength:
|
48
|
+
Max: 1200
|
49
|
+
|
50
|
+
# Offense count: 87
|
51
|
+
# Configuration parameters: CountComments.
|
52
|
+
Metrics/MethodLength:
|
53
|
+
Max: 350
|
54
|
+
|
55
|
+
# Offense count: 1
|
56
|
+
# Configuration parameters: CountKeywordArgs.
|
57
|
+
Metrics/ParameterLists:
|
58
|
+
Max: 8
|
59
|
+
|
60
|
+
# ==================== Disabled on Purpose ====================
|
61
|
+
# Offense count: 3
|
62
|
+
Style/AccessorMethodName:
|
63
|
+
Enabled: true
|
64
|
+
|
65
|
+
# Need to allow indented case statements
|
66
|
+
# Offense count: 9
|
67
|
+
# Configuration parameters: IndentWhenRelativeTo, SupportedStyles, IndentOneStep.
|
68
|
+
Style/CaseIndentation:
|
69
|
+
Enabled: false
|
70
|
+
|
71
|
+
# Offense count: 18
|
72
|
+
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
73
|
+
Style/ClassAndModuleChildren:
|
74
|
+
Enabled: false
|
75
|
+
|
76
|
+
# Offense count: 2
|
77
|
+
Style/ClassVars:
|
78
|
+
Enabled: false
|
79
|
+
|
80
|
+
# Offense count: 42
|
81
|
+
Style/Documentation:
|
82
|
+
Enabled: false
|
83
|
+
|
84
|
+
# Offense count: 1
|
85
|
+
Style/EachWithObject:
|
86
|
+
Enabled: false
|
87
|
+
|
88
|
+
# Offense count: 2
|
89
|
+
# Configuration parameters: AllowedVariables.
|
90
|
+
Style/GlobalVars:
|
91
|
+
Enabled: false
|
92
|
+
|
93
|
+
# Offense count: 7
|
94
|
+
# Configuration parameters: MinBodyLength.
|
95
|
+
Style/GuardClause:
|
96
|
+
Enabled: true
|
97
|
+
|
98
|
+
# Offense count: 17
|
99
|
+
# Configuration parameters: MaxLineLength.
|
100
|
+
Style/IfUnlessModifier:
|
101
|
+
Enabled: false
|
102
|
+
|
103
|
+
# Do NOT enable. For some reason this is catchy any next which I feel are okay.
|
104
|
+
# Offense count: 18
|
105
|
+
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
106
|
+
Style/Next:
|
107
|
+
Enabled: false
|
108
|
+
|
109
|
+
# Do NOT enable this because it appears $? is different than $CHILD_STATUS.
|
110
|
+
# Offense count: 7
|
111
|
+
# Cop supports --auto-correct.
|
112
|
+
Style/SpecialGlobalVars:
|
113
|
+
Enabled: false
|
114
|
+
|
115
|
+
# More Changes per DLM -- pulled from https://github.com/bbatsov/rubocop/blob/master/config/enabled.yml
|
116
|
+
Style/RedundantReturn:
|
117
|
+
Description: 'Do not use return where it is not required.'
|
118
|
+
StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-explicit-return'
|
119
|
+
Enabled: false
|
120
|
+
|
121
|
+
Style/NumericLiterals:
|
122
|
+
Description: 'Add underscores to large numeric literals to improve readability.'
|
123
|
+
StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#underscores-in-numerics'
|
124
|
+
Enabled: false
|
125
|
+
|
126
|
+
Lint/UnusedBlockArgument:
|
127
|
+
Description: 'Checks for unused block arguments.'
|
128
|
+
StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#underscore-unused-vars'
|
129
|
+
Enabled: false
|
130
|
+
|
131
|
+
Lint/UnusedMethodArgument:
|
132
|
+
Description: 'Checks for unused method arguments.'
|
133
|
+
StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#underscore-unused-vars'
|
134
|
+
Enabled: false
|
135
|
+
|
136
|
+
Lint/UselessAssignment:
|
137
|
+
Description: 'Checks for useless assignment to a local variable.'
|
138
|
+
StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#underscore-unused-vars'
|
139
|
+
Enabled: false
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,164 @@
|
|
1
|
+
# Dencity Gem
|
2
|
+
|
3
|
+
This gem is an API client for DEnCity.org.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'dencity'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install dencity
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
|
24
|
+
### Connect to DEnCity
|
25
|
+
|
26
|
+
Without authentication:
|
27
|
+
|
28
|
+
```ruby
|
29
|
+
dencity_client = Dencity.connect
|
30
|
+
```
|
31
|
+
|
32
|
+
On a different host (for development purposes):
|
33
|
+
|
34
|
+
```ruby
|
35
|
+
dencity_client = Dencity.connect({host_name: <host_name>})
|
36
|
+
```
|
37
|
+
|
38
|
+
With authentication:
|
39
|
+
```ruby
|
40
|
+
dencity_client = Dencity.connect({username: <username>, password: <password>})
|
41
|
+
```
|
42
|
+
|
43
|
+
To authenticate an existing connection:
|
44
|
+
```ruby
|
45
|
+
dencity_client.login(<username>, <password>)
|
46
|
+
```
|
47
|
+
|
48
|
+
To authenticate using stored credentials in ~/.dencity/config.yml, call the login method without arguments. The gem will generate the config.yml for you to fill out.
|
49
|
+
```ruby
|
50
|
+
dencity_client.login
|
51
|
+
```
|
52
|
+
|
53
|
+
### Search
|
54
|
+
The search method accepts 3 optional parameters: *filters*, *return_only*, and *page*. *filters* is used to narrow the search results. The format is an array of hashes containing 3 keys: name, value, and operator. The list of operators is as follows:
|
55
|
+
- = - *Equal to* operator accepts string or number values.
|
56
|
+
- ne - *Not equal to* operator accepts string or number values.
|
57
|
+
- lt - *Less than* operator accepts number values.
|
58
|
+
- lte - *Less than or equal to* operator accepts number values.
|
59
|
+
- gt - *Greater than* operator accepts number values.
|
60
|
+
- gte - *Greater than or equal to* operator accepts number values.
|
61
|
+
- exists - *Exists* operator is used to return structure records where the specified metadatum exists in the structure record metadata. The value key can be left blank or nil for this operator.
|
62
|
+
- in - *In* operator accepts an array of values (strings or numbers).
|
63
|
+
- nin - * Not in* operator accepts an array of values (strings or numbers).
|
64
|
+
|
65
|
+
If *filters* is nil, all results will be returned.
|
66
|
+
|
67
|
+
The *return_only* parameter limits the data within each structure record to be returned. All fields specified in the filters will be returned as well as the fields listed in the *return_only* array. If *return_only* is nil, all fields will be returned.
|
68
|
+
|
69
|
+
Since only 100 results are return per call, the *page* parameter allows you to step through the result set. With each search call, the total number of results as well as total number of pages are returned. You can use that information to make additional calls. The *page* parameter is 0-based: set ```page=0``` to retrieve the first page of results. If *page* is nil, the first page of results will be returned by default.
|
70
|
+
|
71
|
+
Example:
|
72
|
+
```ruby
|
73
|
+
filters = []
|
74
|
+
filters << { name: 'building_area', value: 2800, operator: 'lt' }
|
75
|
+
filters << { name: 'building_type', value: ['Community Center'], operator: 'in' }
|
76
|
+
return_only = ['related_files']
|
77
|
+
page = 3
|
78
|
+
results = dencity_client.search(filters, return_only, page)
|
79
|
+
```
|
80
|
+
|
81
|
+
### Retrieve an Analysis
|
82
|
+
There are two methods of retrieving an analysis: by ID, or by name + userID.
|
83
|
+
|
84
|
+
Retrieve an analysis by ID:
|
85
|
+
```ruby
|
86
|
+
analysis = dencity_client.retrieve_analysis_by_id(<id>)
|
87
|
+
```
|
88
|
+
Retrieve by analysis name and userID:
|
89
|
+
```ruby
|
90
|
+
analysis = dencity_client.retrieve_analysis_by_name(<analysis_name>, <user_id>)
|
91
|
+
```
|
92
|
+
You have access to your own user_id from the response object returned once you login to DEnCity, or from your account page on DEnCity.org.
|
93
|
+
|
94
|
+
### Upload an Analysis
|
95
|
+
First load an analysis from a json file, then upload to DEnCity.org.
|
96
|
+
```ruby
|
97
|
+
analysis = dencity_client.load_analysis(<json_file_path>)
|
98
|
+
analysis_response = analysis.push
|
99
|
+
```
|
100
|
+
To catch the response and ensure that the analysis was uploaded to DEnCity.org correctly, you may want to use a begin-end block:
|
101
|
+
```ruby
|
102
|
+
analysis = dencity_client.load_analysis(<json_file_path>)
|
103
|
+
begin
|
104
|
+
analysis_response = analysis.push
|
105
|
+
rescue StandardError => e
|
106
|
+
printf "%-40s %s\n", 'Upload Analysis', 'FAIL'
|
107
|
+
puts e
|
108
|
+
else
|
109
|
+
printf "%-40s %s\n", 'Upload Analysis', 'SUCCESS'
|
110
|
+
puts analysis_response
|
111
|
+
end
|
112
|
+
```
|
113
|
+
When uploading an analysis, the combination of user_id and user_defined_id will be checked.
|
114
|
+
If an analysis with the same user_id and user_defined_id already exists on DEnCity.org, it will be updated; otherwise, a new analysis will be created.
|
115
|
+
|
116
|
+
### Upload a Structure
|
117
|
+
To upload a structure, you will need an analysis_id. You can also specify a user_defined_id to identify your structure for future retrieving.
|
118
|
+
```ruby
|
119
|
+
structure = dencity_client.load_structure(<analysis_id>, <user_defined_id> <json_file_path>)
|
120
|
+
structure_response = structure.push
|
121
|
+
```
|
122
|
+
When uploading a structure, the combination of user_id and user_defined_id will be checked.
|
123
|
+
If a structure with the same user_id and user_defined_id already exists on DEnCity.org, it will be updated; otherwise, a new structure will be created.
|
124
|
+
|
125
|
+
### Bulk Structures Upload
|
126
|
+
Each time a structure is loaded, it is appended to the structures array defined on the Dencity Client: ```dencity_client.structures```. You can bulk upload all structures to DenCity.org:
|
127
|
+
```ruby
|
128
|
+
dencity_client.bulk_upload_structures
|
129
|
+
```
|
130
|
+
|
131
|
+
### Upload a file
|
132
|
+
Files can be attached to an uploaded structure. You will need to pass in the filepath as well as the desired filename on DEnCity.org. If no filename is specified, the file's current name will be used.
|
133
|
+
|
134
|
+
```ruby
|
135
|
+
response = structure.upload_file(<file_path>, <file_name>)
|
136
|
+
```
|
137
|
+
|
138
|
+
### Delete an uploaded file
|
139
|
+
Uploaded files can also be deleted from DEncity.org:
|
140
|
+
```ruby
|
141
|
+
response = structure.delete_file(<file_name>)
|
142
|
+
```
|
143
|
+
|
144
|
+
### Additional Examples
|
145
|
+
|
146
|
+
You can also do simple GETs using the dencity_get method.
|
147
|
+
|
148
|
+
Get all analyses:
|
149
|
+
```ruby
|
150
|
+
response = dencity_client.dencity_get('analyses')
|
151
|
+
```
|
152
|
+
Get structure by ID:
|
153
|
+
```ruby
|
154
|
+
response = dencity_client.dencity_get('structures/<structure_id>')
|
155
|
+
```
|
156
|
+
|
157
|
+
The file example_script.rb contains many usage examples.
|
158
|
+
|
159
|
+
## Development
|
160
|
+
|
161
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
162
|
+
|
163
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
164
|
+
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'dencity'
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require 'irb'
|
14
|
+
IRB.start
|
data/bin/setup
ADDED
data/dencity.gemspec
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'dencity/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'dencity'
|
8
|
+
spec.version = Dencity::VERSION
|
9
|
+
spec.authors = %w(kflemin nlong)
|
10
|
+
spec.email = ['katherine.fleming@nrel.gov']
|
11
|
+
|
12
|
+
spec.summary = 'Client library for DEnCity.org.'
|
13
|
+
# spec.description = %q{}
|
14
|
+
spec.homepage = 'https://github.com/NREL/dencity-gem'
|
15
|
+
|
16
|
+
# Prevent pushing this gem to RubyGems.org by setting 'allowed_push_host', or
|
17
|
+
# delete this section to allow pushing this gem to any host.
|
18
|
+
if spec.respond_to?(:metadata)
|
19
|
+
spec.metadata['allowed_push_host'] = "TODO: Set to 'http://mygemserver.com'"
|
20
|
+
else
|
21
|
+
fail 'RubyGems 2.0 or newer is required to protect against public '\
|
22
|
+
'gem pushes.'
|
23
|
+
end
|
24
|
+
|
25
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
26
|
+
spec.bindir = 'exe'
|
27
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
28
|
+
spec.require_paths = ['lib']
|
29
|
+
|
30
|
+
spec.add_development_dependency 'bundler', '~> 1.10'
|
31
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
32
|
+
spec.add_development_dependency 'rspec'
|
33
|
+
spec.add_dependency('faraday')
|
34
|
+
spec.add_dependency('faraday_middleware')
|
35
|
+
spec.add_dependency('multi_json')
|
36
|
+
spec.add_dependency('parallel')
|
37
|
+
spec.add_dependency('hashie')
|
38
|
+
end
|
data/example_script.rb
ADDED
@@ -0,0 +1,152 @@
|
|
1
|
+
require 'dencity'
|
2
|
+
|
3
|
+
d = Dencity.connect(host_name: 'http://localhost:3000/')
|
4
|
+
|
5
|
+
# to login using stored credentials:
|
6
|
+
# begin
|
7
|
+
# login = d.login
|
8
|
+
# rescue StandardError => e
|
9
|
+
# printf "%-40s %s\n", 'Login', 'FAIL'
|
10
|
+
# puts e
|
11
|
+
# else
|
12
|
+
# printf "%-40s %s\n", 'Login', 'SUCCESS'
|
13
|
+
# puts login
|
14
|
+
# end
|
15
|
+
|
16
|
+
puts '****** SEARCH ********'
|
17
|
+
filters = []
|
18
|
+
filters << { name: 'building_area', value: 2737.26, operator: 'lt' }
|
19
|
+
filters << { name: 'building_type', value: ['Community Center'], operator: 'in' }
|
20
|
+
return_only = ['related_files']
|
21
|
+
page = 0 # pages are 0-based
|
22
|
+
begin
|
23
|
+
results = d.search(filters, return_only, page)
|
24
|
+
rescue StandardError => e
|
25
|
+
printf "%-40s %s\n", 'Search', 'FAIL'
|
26
|
+
puts e
|
27
|
+
else
|
28
|
+
printf "%-40s %s\n", 'Search', 'SUCCESS'
|
29
|
+
end
|
30
|
+
# puts "RESULTS: #{results}"
|
31
|
+
puts "Total number of pages in results set: #{results.total_pages}"
|
32
|
+
puts "Number of results: #{results.results.size}"
|
33
|
+
|
34
|
+
puts '******** GET ANALYSIS BY NAME & USER_ID *********'
|
35
|
+
begin
|
36
|
+
analysis = d.retrieve_analysis_by_name('test_analysis', '53a3656d986ffba2c5000001')
|
37
|
+
rescue StandardError => e
|
38
|
+
printf "%-40s %s\n", 'Retrieve Analysis', 'FAIL'
|
39
|
+
puts e
|
40
|
+
else
|
41
|
+
printf "%-40s %s\n", 'Retrieve Analysis', 'SUCCESS'
|
42
|
+
end
|
43
|
+
|
44
|
+
puts '******** GET ANALYSIS BY ID ************'
|
45
|
+
begin
|
46
|
+
analysis = d.retrieve_analysis_by_id(analysis.id)
|
47
|
+
rescue StandardError => e
|
48
|
+
printf "%-40s %s\n", 'Retrieve Analysis', 'FAIL'
|
49
|
+
puts e
|
50
|
+
else
|
51
|
+
printf "%-40s %s\n", 'Retrieve Analysis', 'SUCCESS'
|
52
|
+
end
|
53
|
+
|
54
|
+
puts '********* GET ANALYSES *************'
|
55
|
+
begin
|
56
|
+
analyses = d.dencity_get('analyses')
|
57
|
+
rescue StandardError => e
|
58
|
+
printf "%-40s %s\n", 'Get Analyses', 'FAIL'
|
59
|
+
puts e
|
60
|
+
else
|
61
|
+
printf "%-40s %s\n", 'Get Analyses', 'SUCCESS'
|
62
|
+
# puts analyses
|
63
|
+
end
|
64
|
+
|
65
|
+
puts '********* LOGIN ************'
|
66
|
+
begin
|
67
|
+
login = d.login('nicholas.long@nrel.gov', 'testing123')
|
68
|
+
rescue StandardError => e
|
69
|
+
printf "%-40s %s\n", 'Login', 'FAIL'
|
70
|
+
puts e
|
71
|
+
else
|
72
|
+
printf "%-40s %s\n", 'Login', 'SUCCESS'
|
73
|
+
puts login
|
74
|
+
end
|
75
|
+
|
76
|
+
puts '********* Upload ANALYSIS **********'
|
77
|
+
|
78
|
+
analysis = d.load_analysis('./spec/data/analysis.json')
|
79
|
+
begin
|
80
|
+
a_response = analysis.push
|
81
|
+
rescue StandardError => e
|
82
|
+
printf "%-40s %s\n", 'Upload Analysis', 'FAIL'
|
83
|
+
puts e
|
84
|
+
else
|
85
|
+
printf "%-40s %s\n", 'Upload Analysis', 'SUCCESS'
|
86
|
+
puts a_response
|
87
|
+
end
|
88
|
+
|
89
|
+
puts '********* Upload STRUCTURE *********'
|
90
|
+
structure = d.load_structure(analysis.analysis.id, 'testing!', './spec/data/structure.json')
|
91
|
+
puts "STRUCTURE: #{structure}"
|
92
|
+
begin
|
93
|
+
s_response = structure.push
|
94
|
+
rescue StandardError => e
|
95
|
+
printf "%-40s %s\n", 'Upload Structure', 'FAIL'
|
96
|
+
puts e
|
97
|
+
else
|
98
|
+
printf "%-40s %s\n", 'Upload Structure', 'SUCCESS'
|
99
|
+
puts s_response
|
100
|
+
end
|
101
|
+
|
102
|
+
puts '******* Upload RELATED FILE *******'
|
103
|
+
begin
|
104
|
+
response = structure.upload_file('./spec/data/related_file.txt', 'test-related-file.txt')
|
105
|
+
rescue StandardError => e
|
106
|
+
printf "%-40s %s\n", 'Upload RelatedFile', 'FAIL'
|
107
|
+
puts e
|
108
|
+
else
|
109
|
+
printf "%-40s %s\n", 'Upload RelatedFile', 'SUCCESS'
|
110
|
+
puts response
|
111
|
+
end
|
112
|
+
|
113
|
+
puts '********** GET STRUCTURE *************'
|
114
|
+
begin
|
115
|
+
new_structure = d.dencity_get("structures/#{structure.structure.id}")
|
116
|
+
rescue StandardError => e
|
117
|
+
printf "%-40s %s\n", 'Retrieve Structure', 'FAIL'
|
118
|
+
puts e
|
119
|
+
else
|
120
|
+
printf "%-40s %s\n", 'Retrieve Structure', 'SUCCESS'
|
121
|
+
end
|
122
|
+
puts new_structure
|
123
|
+
|
124
|
+
puts '******* Delete a RELATED FILE *******'
|
125
|
+
begin
|
126
|
+
response = structure.delete_file('test-related-file.txt')
|
127
|
+
rescue StandardError => e
|
128
|
+
printf "%-40s %s\n", 'Delete File', 'FAIL'
|
129
|
+
puts e
|
130
|
+
else
|
131
|
+
printf "%-40s %s\n", 'Delete File', 'SUCCESS'
|
132
|
+
puts response
|
133
|
+
end
|
134
|
+
|
135
|
+
puts '********** BULK UPLOAD ***********'
|
136
|
+
d.load_structure(analysis.analysis.id, 'testing_bulk_1', './spec/data/structure.json')
|
137
|
+
d.load_structure(analysis.analysis.id, 'testing_bulk_2', './spec/data/structure.json')
|
138
|
+
d.load_structure(analysis.analysis.id, 'testing_bulk_3', './spec/data/structure.json')
|
139
|
+
|
140
|
+
puts "structures: #{d.structures.size}"
|
141
|
+
begin
|
142
|
+
b_response = d.bulk_upload_structures
|
143
|
+
rescue StandardError => e
|
144
|
+
printf "%-40s %s\n", 'Upload Structure', 'FAIL'
|
145
|
+
puts e
|
146
|
+
else
|
147
|
+
printf "%-40s %s\n", 'Upload Structure', 'SUCCESS'
|
148
|
+
puts b_response
|
149
|
+
end
|
150
|
+
|
151
|
+
puts '******* LOGOUT *******'
|
152
|
+
d.logout
|
data/lib/dencity.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'dencity/version'
|
2
|
+
require_relative 'dencity/client'
|
3
|
+
require_relative 'dencity/response'
|
4
|
+
require_relative 'dencity/error'
|
5
|
+
|
6
|
+
require 'multi_json'
|
7
|
+
require 'hashie'
|
8
|
+
require 'faraday'
|
9
|
+
require 'faraday_middleware'
|
10
|
+
require 'parallel'
|
11
|
+
|
12
|
+
# Main module
|
13
|
+
module Dencity
|
14
|
+
# initialize / connect
|
15
|
+
def self.connect(options = {})
|
16
|
+
Dencity::Client.new(options)
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,162 @@
|
|
1
|
+
require_relative 'request'
|
2
|
+
require_relative 'client/search'
|
3
|
+
require_relative 'client/analysis'
|
4
|
+
require_relative 'client/structure'
|
5
|
+
require_relative '../faraday/raise_http_exception'
|
6
|
+
|
7
|
+
require 'fileutils'
|
8
|
+
require 'yaml'
|
9
|
+
|
10
|
+
module Dencity
|
11
|
+
# API Client class
|
12
|
+
class Client
|
13
|
+
# connection options
|
14
|
+
attr_accessor :options
|
15
|
+
attr_accessor :analysis
|
16
|
+
attr_accessor :structures
|
17
|
+
|
18
|
+
include Request
|
19
|
+
include Dencity::Search
|
20
|
+
|
21
|
+
# connect to DEnCity (unauthenticated)
|
22
|
+
def initialize(options = {})
|
23
|
+
puts 'Initializing...'
|
24
|
+
defaults = {
|
25
|
+
username: nil,
|
26
|
+
password: nil,
|
27
|
+
host_name: 'https://dencity.org',
|
28
|
+
user_agent: "DEnCity Ruby Client #{Dencity::VERSION}".freeze,
|
29
|
+
logging: nil
|
30
|
+
}
|
31
|
+
|
32
|
+
@options = Hashie::Mash.new(defaults.merge(options))
|
33
|
+
# connection to site
|
34
|
+
@connection = connect
|
35
|
+
|
36
|
+
@default_number_threads = 4
|
37
|
+
|
38
|
+
# initialize analysis and structures
|
39
|
+
# array of structures
|
40
|
+
@structures = []
|
41
|
+
@analysis = nil
|
42
|
+
end
|
43
|
+
|
44
|
+
# for authenticated actions
|
45
|
+
def login(username = nil, password = nil)
|
46
|
+
# check config.yml
|
47
|
+
if !username.nil? && !password.nil?
|
48
|
+
@options.username = username
|
49
|
+
@options.password = password
|
50
|
+
else
|
51
|
+
# load login info from config file
|
52
|
+
config_path = File.expand_path('~') + '/.dencity'
|
53
|
+
config_name = 'config.yml'
|
54
|
+
if File.exist?(config_path + '/' + config_name)
|
55
|
+
puts "loading config settings from #{config_path + '/' + config_name}"
|
56
|
+
|
57
|
+
config = YAML.load_file(config_path + '/' + config_name)
|
58
|
+
puts "HEY! #{Hashie::Mash.new(config).inspect}"
|
59
|
+
puts "CONFIG: #{config.inspect}"
|
60
|
+
@options.username = config[:username]
|
61
|
+
@options.password = config[:password]
|
62
|
+
@options.host_name = config[:host_name]
|
63
|
+
|
64
|
+
else
|
65
|
+
# location of template file
|
66
|
+
FileUtils.mkdir_p(config_path)
|
67
|
+
puts default_yaml
|
68
|
+
File.open(config_path + '/' + config_name, 'w') do |file|
|
69
|
+
file << default_yaml.to_yaml
|
70
|
+
end
|
71
|
+
fail "******** Please fill in user credentials in #{config_path}/#{config_name} file. DO NOT COMMIT THIS FILE. **********"
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
@connection = connect
|
77
|
+
post('api/login')
|
78
|
+
end
|
79
|
+
|
80
|
+
def logout
|
81
|
+
# @cookie = nil
|
82
|
+
@options.username = nil
|
83
|
+
@options.password = nil
|
84
|
+
@connection = nil
|
85
|
+
end
|
86
|
+
|
87
|
+
def connected?
|
88
|
+
@connection != nil
|
89
|
+
end
|
90
|
+
|
91
|
+
# load structure
|
92
|
+
def load_structure(analysis_id = nil, user_defined_id = nil, path = nil)
|
93
|
+
@structures << Dencity::Structure.new(analysis_id, user_defined_id, path, @connection)
|
94
|
+
@structures.last
|
95
|
+
end
|
96
|
+
|
97
|
+
# bulk upload structures
|
98
|
+
def bulk_upload_structures(number_of_threads = @default_number_threads)
|
99
|
+
Parallel.each(@structures, number_of_threads: number_of_threads) do |structure|
|
100
|
+
structure.push
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# load analysis
|
105
|
+
# this function is needed to pass @connection at least
|
106
|
+
def load_analysis(path = nil)
|
107
|
+
@analysis = Dencity::Analysis.new(path, @connection)
|
108
|
+
end
|
109
|
+
|
110
|
+
# retrieve analysis
|
111
|
+
# must pass in @connection
|
112
|
+
def retrieve_analysis_by_name(name, user_id)
|
113
|
+
@analysis = Dencity::Analysis.new(nil, @connection)
|
114
|
+
@analysis.retrieve_by_name(name, user_id)
|
115
|
+
end
|
116
|
+
|
117
|
+
# retrieve analysis by ID
|
118
|
+
# must pass in @connection
|
119
|
+
def retrieve_analysis_by_id(id)
|
120
|
+
@analysis = Dencity::Analysis.new(nil, @connection)
|
121
|
+
@analysis.retrieve_by_id(id)
|
122
|
+
end
|
123
|
+
|
124
|
+
# generic GET action to retrieve from DEnCity
|
125
|
+
# example paths: 'analyses', 'structures/<structure_id>'
|
126
|
+
def dencity_get(path)
|
127
|
+
get(path)
|
128
|
+
end
|
129
|
+
|
130
|
+
private
|
131
|
+
|
132
|
+
def connect(raw = false)
|
133
|
+
options = set_options
|
134
|
+
puts "CONNECTING TO: #{@options.host_name}, USER: #{@options.username}"
|
135
|
+
Faraday::Connection.new(options) do |c|
|
136
|
+
c.use FaradayMiddleware::Mashify unless raw
|
137
|
+
# basic auth
|
138
|
+
c.basic_auth(@options.username, @options.password) unless @options.username.nil? || @options.password.nil?
|
139
|
+
c.use FaradayMiddleware::RaiseHttpException
|
140
|
+
c.response :json, content_type: /\bjson$/
|
141
|
+
c.response :logger if @logging
|
142
|
+
c.adapter Faraday.default_adapter
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
def set_options
|
147
|
+
{ headers: {
|
148
|
+
'Accept' => 'application/json; charset=utf-8',
|
149
|
+
'User-Agent' => @options.user_agent,
|
150
|
+
# 'Cookie' => @options.cookie,
|
151
|
+
# 'X-CSRF-Token' => @options.access_token
|
152
|
+
}.reject { |_k, v| v.nil? },
|
153
|
+
ssl: { verify: false },
|
154
|
+
url: @options.host_name
|
155
|
+
}
|
156
|
+
end
|
157
|
+
|
158
|
+
def default_yaml
|
159
|
+
settings = { host_name: 'http://localhost:3000', username: 'ENTER_DENCITY_USERNAME', password: 'ENTER_DENCITY_PASSWORD' }
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
module Dencity
|
2
|
+
# Analysis methods
|
3
|
+
class Analysis
|
4
|
+
include Request
|
5
|
+
|
6
|
+
attr_accessor :analysis
|
7
|
+
attr_accessor :measure_definitions
|
8
|
+
|
9
|
+
# initialize
|
10
|
+
def initialize(path = nil, connection)
|
11
|
+
# for analysis, user_defined_id is created in @analysis (not a separate variable)
|
12
|
+
@analysis = Hashie::Mash.new
|
13
|
+
@measure_definitions = Hashie::Mash.new
|
14
|
+
|
15
|
+
@connection = connection
|
16
|
+
|
17
|
+
# initialize with JSON
|
18
|
+
unless path.nil?
|
19
|
+
load_from_file(path)
|
20
|
+
end
|
21
|
+
|
22
|
+
@upload_retries = nil
|
23
|
+
end
|
24
|
+
|
25
|
+
# get analysis by id
|
26
|
+
def retrieve_by_id(id)
|
27
|
+
response = get("api/analyses/#{id}")
|
28
|
+
@analysis = Hashie::Mash.new(response) unless response.error?
|
29
|
+
response
|
30
|
+
end
|
31
|
+
|
32
|
+
# get analysis by name and user_id
|
33
|
+
def retrieve_by_name(name, user_id)
|
34
|
+
data = { name: name, user_id: user_id }
|
35
|
+
response = get('api/retrieve_analysis', data)
|
36
|
+
@analysis = Hashie::Mash.new(response) unless response.error?
|
37
|
+
response
|
38
|
+
end
|
39
|
+
|
40
|
+
# load analysis from JSON file
|
41
|
+
def load_from_file(path)
|
42
|
+
return unless File.exist?(path)
|
43
|
+
json_data = File.read(path)
|
44
|
+
load_raw_json(json_data)
|
45
|
+
end
|
46
|
+
|
47
|
+
# load analysis from raw JSON
|
48
|
+
def load_raw_json(json_data)
|
49
|
+
temp = Hashie::Mash.new(MultiJson.load(json_data))
|
50
|
+
@analysis = temp.analysis ? temp.analysis : Hashie::Mash.new
|
51
|
+
@measure_definitions = temp.measure_definitions ? temp.measure_definitions : Hashie::Mash.new
|
52
|
+
end
|
53
|
+
|
54
|
+
def push
|
55
|
+
begin
|
56
|
+
@upload_retries ||= 0
|
57
|
+
|
58
|
+
response = post('api/analysis', format_analysis)
|
59
|
+
@analysis.id = response.analysis.id if (response.analysis && response.analysis.id)
|
60
|
+
return response if response
|
61
|
+
rescue StandardError => se
|
62
|
+
# Decide if we should fail based on number of retries
|
63
|
+
if @upload_retries < 3
|
64
|
+
|
65
|
+
raise 'could not upload'
|
66
|
+
else
|
67
|
+
# or here: @upload_retries = nil
|
68
|
+
return se
|
69
|
+
end
|
70
|
+
end
|
71
|
+
rescue => e
|
72
|
+
@upload_retries += 1
|
73
|
+
sleep 2
|
74
|
+
retry
|
75
|
+
ensure
|
76
|
+
# always do this
|
77
|
+
# verify that this is only called if the retry is not triggered
|
78
|
+
@upload_retries = nil
|
79
|
+
end
|
80
|
+
|
81
|
+
private
|
82
|
+
|
83
|
+
# format analysis for uploading
|
84
|
+
def format_analysis
|
85
|
+
data_hash = Hashie::Mash.new
|
86
|
+
data_hash.analysis = @analysis
|
87
|
+
data_hash.measure_definitions = @measure_definitions
|
88
|
+
MultiJson.dump(data_hash)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Dencity
|
2
|
+
# Search methods
|
3
|
+
module Search
|
4
|
+
# filters: array of hashes with keys: name, value, operator
|
5
|
+
# return_only: array of metadata to return
|
6
|
+
# If blank, all metadata will be returned
|
7
|
+
# for iterating over results set (100 per page)
|
8
|
+
def search(filters = [{ name: 'building_type', value: 'Office', operator: '=' }], return_only = [], page = 0)
|
9
|
+
# must have 1 filter or search won't work
|
10
|
+
object = {}
|
11
|
+
object['filters'] = filters
|
12
|
+
object['return_only'] = return_only unless return_only.nil?
|
13
|
+
object['page'] = page
|
14
|
+
|
15
|
+
data = MultiJson.dump(object)
|
16
|
+
puts "DATA: #{data}"
|
17
|
+
post('api/search', data)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,158 @@
|
|
1
|
+
module Dencity
|
2
|
+
# Structure methods
|
3
|
+
class Structure
|
4
|
+
include Request
|
5
|
+
|
6
|
+
attr_accessor :analysis_id
|
7
|
+
attr_accessor :user_defined_id
|
8
|
+
attr_accessor :structure
|
9
|
+
attr_accessor :measure_instances
|
10
|
+
|
11
|
+
# initialize
|
12
|
+
def initialize(analysis_id = nil, user_defined_id = nil, path = nil, connection)
|
13
|
+
@analysis_id = analysis_id
|
14
|
+
@user_defined_id = user_defined_id
|
15
|
+
@structure = Hashie::Mash.new
|
16
|
+
@measure_instances = Hashie::Mash.new
|
17
|
+
|
18
|
+
@connection = connection
|
19
|
+
|
20
|
+
# initialize with json file
|
21
|
+
unless path.nil?
|
22
|
+
load_from_file(path)
|
23
|
+
end
|
24
|
+
|
25
|
+
@upload_retries = nil
|
26
|
+
end
|
27
|
+
|
28
|
+
def push
|
29
|
+
begin
|
30
|
+
@upload_retries ||= 0
|
31
|
+
|
32
|
+
response = post('api/structure', format_structure)
|
33
|
+
@structure.id = response['id'] if response['id']
|
34
|
+
return response if response
|
35
|
+
rescue StandardError => se
|
36
|
+
# Decide if we should fail based on number of retries
|
37
|
+
if @upload_retries < 3
|
38
|
+
|
39
|
+
raise 'could not upload'
|
40
|
+
else
|
41
|
+
# or here: @upload_retries = nil
|
42
|
+
return se
|
43
|
+
end
|
44
|
+
end
|
45
|
+
rescue => e
|
46
|
+
@upload_retries += 1
|
47
|
+
sleep 2
|
48
|
+
retry
|
49
|
+
ensure
|
50
|
+
# always do this
|
51
|
+
# verify that this is only called if the retry is not triggered
|
52
|
+
@upload_retries = nil
|
53
|
+
end
|
54
|
+
|
55
|
+
# load structure from json file into a mash
|
56
|
+
def load_from_file(path)
|
57
|
+
return unless File.exist?(path)
|
58
|
+
json_data = File.read(path)
|
59
|
+
load_raw_json(json_data)
|
60
|
+
end
|
61
|
+
|
62
|
+
# load structure from raw json
|
63
|
+
def load_raw_json(json_data)
|
64
|
+
temp = Hashie::Mash.new(MultiJson.load(json_data))
|
65
|
+
@structure = temp.structure ? temp.structure : Hashie::Mash.new
|
66
|
+
@measure_instances = temp.measure_instances ? temp.measure_instances : Hashie::Mash.new
|
67
|
+
# these could be set in the file
|
68
|
+
@analysis_id = temp.structure.analysis_id if temp.structure.analysis_id
|
69
|
+
@user_defined_id = temp.structure.user_defined_id if temp.structure.user_defined_id
|
70
|
+
|
71
|
+
return true
|
72
|
+
end
|
73
|
+
|
74
|
+
# upload file
|
75
|
+
def upload_file(path, file_name = nil)
|
76
|
+
fail 'No Structure ID defined for structure. Can\'t upload file' if @structure.id.nil?
|
77
|
+
|
78
|
+
file = File.open(path, 'rb')
|
79
|
+
the_file = Base64.strict_encode64(file.read)
|
80
|
+
file.close
|
81
|
+
|
82
|
+
# file_data param
|
83
|
+
file_data = {}
|
84
|
+
file_data['file_name'] = file_name.nil? ? File.basename(path) : file_name
|
85
|
+
file_data['file'] = the_file
|
86
|
+
|
87
|
+
data = Hashie::Mash.new
|
88
|
+
data.structure_id = @structure.id
|
89
|
+
data.file_data = file_data
|
90
|
+
|
91
|
+
push_file('api/related_file', MultiJson.dump(data))
|
92
|
+
end
|
93
|
+
|
94
|
+
# delete an uploaded file
|
95
|
+
# if structure_id is nil, will use @structure.id
|
96
|
+
def delete_file(file_name)
|
97
|
+
fail 'No Structure ID defined for structure. Can\'t delete file' if @structure.id.nil?
|
98
|
+
|
99
|
+
data = Hashie::Mash.new
|
100
|
+
data.structure_id = @structure.id
|
101
|
+
data.file_name = file_name
|
102
|
+
|
103
|
+
push_file('api/remove_file', MultiJson.dump(data))
|
104
|
+
end
|
105
|
+
|
106
|
+
# push file w/ retry
|
107
|
+
def push_file(path, data)
|
108
|
+
begin
|
109
|
+
@upload_retries ||= 0
|
110
|
+
response = post(path, data)
|
111
|
+
return response if response
|
112
|
+
rescue StandardError => se
|
113
|
+
# Decide if we should fail based on number of retries
|
114
|
+
if @upload_retries < 3
|
115
|
+
if path.include? 'remove'
|
116
|
+
raise 'could not delete file'
|
117
|
+
else
|
118
|
+
raise 'could not upload file'
|
119
|
+
end
|
120
|
+
else
|
121
|
+
return se
|
122
|
+
end
|
123
|
+
end
|
124
|
+
rescue => e
|
125
|
+
@upload_retries += 1
|
126
|
+
sleep 2
|
127
|
+
retry
|
128
|
+
ensure
|
129
|
+
# verify that this is only called if the retry is not triggered
|
130
|
+
@upload_retries = nil
|
131
|
+
end
|
132
|
+
|
133
|
+
private
|
134
|
+
|
135
|
+
# formats structure parameters for posting
|
136
|
+
def format_structure
|
137
|
+
# generate name/value pairs for structure metadata
|
138
|
+
formatted_meta = []
|
139
|
+
@structure.each do |k, v|
|
140
|
+
formatted_meta << { name: k, value: v } unless %w(id user_defined_id analysis_id).include?(k)
|
141
|
+
end
|
142
|
+
new_struct = Hashie::Mash.new
|
143
|
+
new_struct.metadata = formatted_meta
|
144
|
+
|
145
|
+
# TODO: what if it's already in the structure hash?
|
146
|
+
# add user_defined_id to structure
|
147
|
+
new_struct.user_defined_id = @user_defined_id
|
148
|
+
new_struct.analysis_id = @analysis_id
|
149
|
+
|
150
|
+
data_hash = Hashie::Mash.new
|
151
|
+
data_hash.structure = new_struct
|
152
|
+
data_hash.measure_instances = @measure_instances ? @measure_instances : []
|
153
|
+
|
154
|
+
# convert to json
|
155
|
+
MultiJson.dump(data_hash)
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Dencity
|
2
|
+
class Error < StandardError; end
|
3
|
+
|
4
|
+
# For 400's
|
5
|
+
class BadRequest < Error; end
|
6
|
+
|
7
|
+
# For 401's
|
8
|
+
class Unauthorized < Error; end
|
9
|
+
|
10
|
+
# For 404's.
|
11
|
+
class NotFound < Error; end
|
12
|
+
|
13
|
+
# For 406's.
|
14
|
+
class NotAcceptable < Error; end
|
15
|
+
|
16
|
+
# For 500's
|
17
|
+
class InternalServerError < Error; end
|
18
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Dencity
|
2
|
+
# Request module
|
3
|
+
module Request
|
4
|
+
# Perform an HTTP GET request (options should not be in JSON)
|
5
|
+
def get(path, options = {}, raw = false,
|
6
|
+
unformatted = false, no_response_wrapper = false)
|
7
|
+
request(:get, path, options, raw, unformatted, no_response_wrapper)
|
8
|
+
end
|
9
|
+
|
10
|
+
# Perform an HTTP POST request (options should be in JSON already)
|
11
|
+
def post(path, options = {}, raw = false,
|
12
|
+
unformatted = false, no_response_wrapper = false)
|
13
|
+
request(:post, path, options, raw, unformatted, no_response_wrapper)
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
# Perform an HTTP request
|
19
|
+
def request(method, path, options, raw = false,
|
20
|
+
unformatted = false, no_response_wrapper = false)
|
21
|
+
response = @connection.send(method) do |request|
|
22
|
+
path = formatted_path(path) unless unformatted
|
23
|
+
puts "PATH: #{path}"
|
24
|
+
|
25
|
+
case method
|
26
|
+
when :get, :delete
|
27
|
+
request.url(path, options)
|
28
|
+
when :post, :put
|
29
|
+
request.path = path
|
30
|
+
request.body = options unless options.empty?
|
31
|
+
end
|
32
|
+
|
33
|
+
request.headers['Content-Type'] = 'application/json'
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
return response if raw
|
38
|
+
return response.body if no_response_wrapper
|
39
|
+
Response.create(response.body, response.status)
|
40
|
+
end
|
41
|
+
|
42
|
+
def formatted_path(path)
|
43
|
+
[path, 'json'].compact.join('.')
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# Response Format
|
2
|
+
|
3
|
+
module Dencity
|
4
|
+
# Response module
|
5
|
+
module Response
|
6
|
+
def self.create(response_hash, status)
|
7
|
+
if response_hash.class.name == 'Array'
|
8
|
+
data = Hashie::Mash.new
|
9
|
+
data.data = response_hash
|
10
|
+
else
|
11
|
+
data = response_hash.dup rescue response_hash
|
12
|
+
end
|
13
|
+
data.extend(self)
|
14
|
+
data.status = status
|
15
|
+
data
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'faraday'
|
2
|
+
|
3
|
+
# Yeah, this is almost a carbon copy of the way the Instagram gem does it.
|
4
|
+
# But screw it. It's open source, and it works. :P
|
5
|
+
|
6
|
+
module FaradayMiddleware
|
7
|
+
class RaiseHttpException < Faraday::Middleware
|
8
|
+
def call(env)
|
9
|
+
@app.call(env).on_complete do |response|
|
10
|
+
case response[:status].to_i
|
11
|
+
when 400
|
12
|
+
fail Dencity::BadRequest, error_message_400(response)
|
13
|
+
when 401
|
14
|
+
fail Dencity::Unauthorized, error_message_400(response)
|
15
|
+
when 404
|
16
|
+
fail Dencity::NotFound, error_message_400(response)
|
17
|
+
when 406
|
18
|
+
fail Dencity::NotAcceptable, error_message_400(response)
|
19
|
+
when 500
|
20
|
+
fail Dencity::InternalServerError, error_message_500(response, 'Internal Server Error.')
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def initialize(app)
|
26
|
+
super app
|
27
|
+
@parser = nil
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def error_message_400(response)
|
33
|
+
"#{response[:method].to_s.upcase} #{response[:url]}: #{response[:status]} #{error_body(response[:body])}"
|
34
|
+
end
|
35
|
+
|
36
|
+
def error_body(body)
|
37
|
+
return unless !body.nil? && !body.empty? && body.is_a?(String)
|
38
|
+
body = ::MultiJson.load(body)
|
39
|
+
end
|
40
|
+
|
41
|
+
def error_message_500(response, body = nil)
|
42
|
+
"#{response[:method].to_s.upcase} #{response[:url]}: #{[response[:status].to_s + ':', body].compact.join(' ')}"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
metadata
ADDED
@@ -0,0 +1,180 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: dencity
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- kflemin
|
8
|
+
- nlong
|
9
|
+
autorequire:
|
10
|
+
bindir: exe
|
11
|
+
cert_chain: []
|
12
|
+
date: 2016-01-29 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: bundler
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - ~>
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: '1.10'
|
21
|
+
type: :development
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ~>
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: '1.10'
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: rake
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - ~>
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: '10.0'
|
35
|
+
type: :development
|
36
|
+
prerelease: false
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - ~>
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '10.0'
|
42
|
+
- !ruby/object:Gem::Dependency
|
43
|
+
name: rspec
|
44
|
+
requirement: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - '>='
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '0'
|
49
|
+
type: :development
|
50
|
+
prerelease: false
|
51
|
+
version_requirements: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - '>='
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '0'
|
56
|
+
- !ruby/object:Gem::Dependency
|
57
|
+
name: faraday
|
58
|
+
requirement: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - '>='
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '0'
|
63
|
+
type: :runtime
|
64
|
+
prerelease: false
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
- !ruby/object:Gem::Dependency
|
71
|
+
name: faraday_middleware
|
72
|
+
requirement: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - '>='
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
type: :runtime
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - '>='
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '0'
|
84
|
+
- !ruby/object:Gem::Dependency
|
85
|
+
name: multi_json
|
86
|
+
requirement: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - '>='
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: '0'
|
91
|
+
type: :runtime
|
92
|
+
prerelease: false
|
93
|
+
version_requirements: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - '>='
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: '0'
|
98
|
+
- !ruby/object:Gem::Dependency
|
99
|
+
name: parallel
|
100
|
+
requirement: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
102
|
+
- - '>='
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '0'
|
105
|
+
type: :runtime
|
106
|
+
prerelease: false
|
107
|
+
version_requirements: !ruby/object:Gem::Requirement
|
108
|
+
requirements:
|
109
|
+
- - '>='
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: '0'
|
112
|
+
- !ruby/object:Gem::Dependency
|
113
|
+
name: hashie
|
114
|
+
requirement: !ruby/object:Gem::Requirement
|
115
|
+
requirements:
|
116
|
+
- - '>='
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
version: '0'
|
119
|
+
type: :runtime
|
120
|
+
prerelease: false
|
121
|
+
version_requirements: !ruby/object:Gem::Requirement
|
122
|
+
requirements:
|
123
|
+
- - '>='
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
126
|
+
description:
|
127
|
+
email:
|
128
|
+
- katherine.fleming@nrel.gov
|
129
|
+
executables: []
|
130
|
+
extensions: []
|
131
|
+
extra_rdoc_files: []
|
132
|
+
files:
|
133
|
+
- .gitignore
|
134
|
+
- .rspec
|
135
|
+
- .rubocop.yml
|
136
|
+
- .travis.yml
|
137
|
+
- Gemfile
|
138
|
+
- README.md
|
139
|
+
- Rakefile
|
140
|
+
- bin/console
|
141
|
+
- bin/setup
|
142
|
+
- dencity.gemspec
|
143
|
+
- example_script.rb
|
144
|
+
- lib/dencity.rb
|
145
|
+
- lib/dencity/client.rb
|
146
|
+
- lib/dencity/client/analysis.rb
|
147
|
+
- lib/dencity/client/search.rb
|
148
|
+
- lib/dencity/client/structure.rb
|
149
|
+
- lib/dencity/error.rb
|
150
|
+
- lib/dencity/related_file.rb
|
151
|
+
- lib/dencity/request.rb
|
152
|
+
- lib/dencity/response.rb
|
153
|
+
- lib/dencity/version.rb
|
154
|
+
- lib/faraday/raise_http_exception.rb
|
155
|
+
homepage: https://github.com/NREL/dencity-gem
|
156
|
+
licenses: []
|
157
|
+
metadata:
|
158
|
+
allowed_push_host: 'TODO: Set to ''http://mygemserver.com'''
|
159
|
+
post_install_message:
|
160
|
+
rdoc_options: []
|
161
|
+
require_paths:
|
162
|
+
- lib
|
163
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
164
|
+
requirements:
|
165
|
+
- - '>='
|
166
|
+
- !ruby/object:Gem::Version
|
167
|
+
version: '0'
|
168
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
169
|
+
requirements:
|
170
|
+
- - '>='
|
171
|
+
- !ruby/object:Gem::Version
|
172
|
+
version: '0'
|
173
|
+
requirements: []
|
174
|
+
rubyforge_project:
|
175
|
+
rubygems_version: 2.0.3
|
176
|
+
signing_key:
|
177
|
+
specification_version: 4
|
178
|
+
summary: Client library for DEnCity.org.
|
179
|
+
test_files: []
|
180
|
+
has_rdoc:
|