storehouse_client 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in storehouse_client.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Jon Gillies
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,60 @@
1
+ # StorehouseClient
2
+
3
+ This the API client to the Storehouse application.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'storehouse_client'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install storehouse_client
18
+
19
+ ## Usage
20
+
21
+ The storehouse_client is simple to use. Here is a complete working example. Assuming you have a one data source defined in the target Storehouse.
22
+
23
+ ```ruby
24
+ #!/usr/bin/env ruby
25
+
26
+ require 'storehouse_client'
27
+
28
+ # Setup your data source in the web application, change this as required
29
+ data_source_id = 1
30
+
31
+ # Create a new client instance
32
+ sc = StorehouseClient::API.new(url: 'http://localhost:3000', auth_token: 'z0000000000000000000')
33
+
34
+ # Start the export run
35
+ sc.start_run(data_source_id)
36
+
37
+ # Iterate your data source, use a simple counter for the primary key
38
+ count = 0
39
+ File.open('/usr/share/dict/words').each do |line|
40
+
41
+ count += 1
42
+
43
+ sc.add_record(count, line)
44
+
45
+ puts "Added #{line}"
46
+
47
+ end
48
+
49
+ sc.finish_run
50
+ ```
51
+
52
+ See other examples in the 'examples' directory.
53
+
54
+ ## Contributing
55
+
56
+ 1. Fork it
57
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
58
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
59
+ 4. Push to the branch (`git push origin my-new-feature`)
60
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,157 @@
1
+ require 'storehouse_client/version'
2
+ require 'yaml'
3
+ require 'crack'
4
+ require 'json'
5
+ require 'rest-client'
6
+ require 'digest'
7
+
8
+ module StorehouseClient
9
+
10
+
11
+ class API
12
+
13
+ YAML::ENGINE.yamler = 'syck'
14
+
15
+ attr_reader :run_id, :data_source_id, :record_count, :error, :record_count, :duration
16
+
17
+ def initialize(args)
18
+
19
+ @error = nil
20
+ @url = args.fetch(:url) { raise 'You must provide :url' }
21
+ @api_version = args.fetch(:api_version) { 1 }
22
+ @auth_token = args.fetch(:auth_token) { raise 'You must provide :auth_token' }
23
+ @record_count = 0
24
+ @duration = nil
25
+
26
+ @resource = RestClient::Resource.new @url
27
+
28
+ end
29
+
30
+ def error?
31
+ !@error.nil?
32
+ end
33
+
34
+ def data_sources
35
+ get ("data_sources.json?auth_token=#{@auth_token}")
36
+ end
37
+
38
+ def start_run(data_source_id)
39
+
40
+ @data_source_id = data_source_id
41
+
42
+ run = {}
43
+ run['export_run'] = {}
44
+ run['export_run']['data_source_id'] = @data_source_id
45
+ run['export_run']['started_at'] = Time.now
46
+
47
+ r = post("api/#{@api_version}/export_runs?auth_token=#{@auth_token}", run)
48
+
49
+ return nil if error?
50
+
51
+ @run_id = r['response']['id']
52
+
53
+ self
54
+ end
55
+
56
+ def finish_run
57
+
58
+ run = {}
59
+ run['export_run'] = {}
60
+ run['export_run']['finished_at'] = Time.now.to_s
61
+ run['export_run']['record_count'] = @record_count
62
+
63
+ r = put("api/#{@api_version}/export_runs/#{@run_id}?auth_token=#{@auth_token}", run)
64
+
65
+ return nil if error?
66
+
67
+ @duration = r['response']['duration']
68
+
69
+ self
70
+ end
71
+
72
+ def add_record(primary_key, data)
73
+
74
+ # primary_key must be a string
75
+
76
+ e = {}
77
+ e['export_record'] = {}
78
+ e['export_record']['blob_attributes'] = {}
79
+ e['export_record']['blob_attributes']['data'] = data
80
+ e['export_record']['blob_attributes']['checksum'] = Digest::SHA256.hexdigest(data.to_json)
81
+ e['export_record']['record_size'] = data.to_json.length
82
+ e['export_record']['checksum'] = e['export_record']['blob_attributes']['checksum']
83
+ e['export_record']['primary_key'] = primary_key.to_s # Ensure primary key is a string
84
+ e['export_record']['data_source_id'] = @data_source_id
85
+ e['export_record']['export_run_id'] = @run_id
86
+
87
+ post("api/#{@api_version}/export_records/?auth_token=#{@auth_token}", e)
88
+
89
+ return nil if error?
90
+
91
+ @record_count += 1
92
+
93
+ self
94
+ end
95
+
96
+ private
97
+
98
+ def post(path, data)
99
+ begin
100
+ result = @resource[path].post data.to_json, content_type: :json, accept: :json
101
+ rescue RestClient::Unauthorized => @error
102
+ return nil
103
+ rescue RestClient::UnprocessableEntity => @error
104
+ return nil
105
+ rescue RestClient::ResourceNotFound => @error
106
+ return nil
107
+ end
108
+
109
+ parse_result result
110
+ end
111
+
112
+ def put(path, data)
113
+ begin
114
+ result = @resource[path].put data.to_json, content_type: :json, accept: :json
115
+ rescue RestClient::Unauthorized => @error
116
+ return nil
117
+ rescue RestClient::UnprocessableEntity => @error
118
+ return nil
119
+ rescue RestClient::ResourceNotFound => @error
120
+ return nil
121
+ end
122
+
123
+ parse_result result
124
+ end
125
+
126
+ def get(path)
127
+ begin
128
+ result = @resource[path].get content_type: :json, accept: :json
129
+ rescue RestClient::Unauthorized => @error
130
+ return nil
131
+ rescue RestClient::ResourceNotFound => @error
132
+ return nil
133
+ end
134
+
135
+ parse_result result
136
+ end
137
+
138
+ def parse_result(result)
139
+ # Go figure? When the gem is installed, the Crack::JSON will return "invalid json string" WTF?
140
+ # So fall back to JSON.parse if that happens?
141
+ begin
142
+ r = Crack::JSON.parse(result)
143
+ rescue Crack::ParseError
144
+ r = JSON.parse(result)
145
+ rescue Exception => @error
146
+ end
147
+
148
+ r
149
+ end
150
+
151
+ def get_run(run_id)
152
+ get("api/#{@api_version}/export_runs/#{run_id}?auth_token=#{@auth_token}")
153
+ end
154
+
155
+ end
156
+
157
+ end
@@ -0,0 +1,9 @@
1
+ module StorehouseClient
2
+ VERSION = '0.0.8'
3
+ AUTHORS = ['Jon Gillies']
4
+ EMAIL = %w(supercoder@gmail.com)
5
+ DESCRIPTION = %q{This the API client to the Storehouse application.}
6
+ SUMMARY = %q{API client to the Storehouse}
7
+ HOMEPAGE = 'https://github.com/jongillies/storehouse'
8
+ VERSION_BANNER = "#{self.name} #{self::VERSION} #{self::SUMMARY} (c) 2013 #{self::AUTHORS.join(', ')}"
9
+ end
@@ -0,0 +1,154 @@
1
+ require 'spec_helper'
2
+ require 'storehouse_client'
3
+
4
+ describe 'Initializing the class' do
5
+
6
+ it 'should fail with no options' do
7
+ expect { StorehouseClient::API.new({}) }.to raise_error
8
+ end
9
+
10
+ it 'should fail without the :url option' do
11
+ expect { StorehouseClient::API.new(auth_token: 'z0000000000000000000') }.to raise_error
12
+ end
13
+
14
+ it 'should fail without the :auth_token option' do
15
+ expect { StorehouseClient::API.new(url: 'http://localhost:3000') }.to raise_error
16
+ end
17
+
18
+ it 'should succeed with the proper options' do
19
+ expect { StorehouseClient::API.new(url: 'http://localhost:3000', auth_token: 'z0000000000000000000') }.not_to raise_error
20
+ end
21
+
22
+ end
23
+
24
+ describe 'Fail me' do
25
+
26
+ it 'should fail with an invalid auth_token' do
27
+ sc = StorehouseClient::API.new(url: 'http://localhost:3000', auth_token: 'z00000000000000000xxxx')
28
+
29
+ sc.start_run(1)
30
+
31
+ sc.error.http_code.should eq(401)
32
+
33
+ end
34
+
35
+ it 'should fail with an invalid data_source_id' do
36
+ sc = StorehouseClient::API.new(url: 'http://localhost:3000', auth_token: 'z0000000000000000000')
37
+
38
+ sc.start_run(100)
39
+
40
+ sc.error.http_code.should eq(422)
41
+
42
+ end
43
+
44
+ it 'should fail with a duplicate record' do
45
+ sc = StorehouseClient::API.new(url: 'http://localhost:3000', auth_token: 'z0000000000000000000')
46
+
47
+ sc.start_run(1)
48
+
49
+ text = RandomText.new.output(10).capitalize + '.'
50
+
51
+ sc.add_record(1, text)
52
+ sc.add_record(1, text)
53
+
54
+ sc.error.http_code.should eq(422)
55
+
56
+ end
57
+
58
+ end
59
+
60
+ describe 'Loading data_sources' do
61
+
62
+ it 'should load the data sources' do
63
+ sc = StorehouseClient::API.new(url: 'http://localhost:3000', auth_token: 'z0000000000000000000')
64
+ sc.data_sources.count.should eq(4)
65
+ end
66
+
67
+ end
68
+
69
+ describe 'Starting and Stopping Runs' do
70
+
71
+ it 'should start a run' do
72
+ sc = StorehouseClient::API.new(url: 'http://localhost:3000', auth_token: 'z0000000000000000000')
73
+
74
+ sc.start_run(1)
75
+
76
+ sc.data_source_id.should eq(1)
77
+ end
78
+
79
+ it 'should start and end a run' do
80
+ sc = StorehouseClient::API.new(url: 'http://localhost:3000', auth_token: 'z0000000000000000000')
81
+ sc.start_run(1)
82
+
83
+ sc.finish_run
84
+
85
+ sc.record_count.should eq(0)
86
+ end
87
+
88
+ end
89
+
90
+ describe 'Add records and ensure types are converted properly' do
91
+
92
+ it 'should ensure the primary key is a string' do
93
+ sc = StorehouseClient::API.new(url: 'http://localhost:3000', auth_token: 'z0000000000000000000')
94
+
95
+ sc.start_run(1)
96
+
97
+ text = RandomText.new.output(10).capitalize + '.'
98
+
99
+ sc.add_record(1, text)
100
+
101
+ sc.finish_run
102
+ sc.record_count.should eq(1)
103
+
104
+ end
105
+
106
+ it 'should convert the "data" to JSON if it is not a string' do
107
+ sc = StorehouseClient::API.new(url: 'http://localhost:3000', auth_token: 'z0000000000000000000')
108
+
109
+ sc.start_run(1)
110
+
111
+ hash = { value: 'two', type: 'test stuff', other_thing: 1}
112
+
113
+ sc.add_record(1, hash)
114
+
115
+ sc.finish_run
116
+ sc.record_count.should eq(1)
117
+ end
118
+
119
+ end
120
+
121
+ describe 'Adding Export Records' do
122
+
123
+ it 'should add unique export records' do
124
+
125
+ record_count = 10
126
+ data_source_id = 1
127
+
128
+ sc = StorehouseClient::API.new(url: 'http://localhost:3000', auth_token: 'z0000000000000000000')
129
+
130
+ sc.start_run(data_source_id)
131
+
132
+ record_count.times do |i|
133
+
134
+ text = RandomText.new.output(10).capitalize + '.'
135
+
136
+ sc.add_record(i, text)
137
+
138
+ end
139
+
140
+ sc.finish_run
141
+ sc.record_count.should eq(record_count)
142
+
143
+ end
144
+
145
+ it 'should start and end a run' do
146
+ sc = StorehouseClient::API.new(url: 'http://localhost:3000', auth_token: 'z0000000000000000000')
147
+ sc.start_run(1)
148
+
149
+ sc.finish_run
150
+
151
+ sc.record_count.should eq(0)
152
+ end
153
+
154
+ end
@@ -0,0 +1,19 @@
1
+ require 'spec_helper'
2
+ require 'storehouse_client'
3
+
4
+ describe 'Add one record' do
5
+
6
+ it 'should add one record' do
7
+ sc = StorehouseClient::API.new(url: 'http://localhost:3000', auth_token: 'z0000000000000000000')
8
+
9
+ sc.start_run(1)
10
+
11
+ hash = { value: 'two', type: 'test stuff', other_thing: 1}
12
+
13
+ sc.add_record(1, hash)
14
+
15
+ sc.finish_run
16
+ sc.record_count.should eq(1)
17
+ end
18
+
19
+ end
@@ -0,0 +1,38 @@
1
+ # This file was generated by the `rspec --init` command. Conventionally, all
2
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3
+ # Require this file using `require "spec_helper"` to ensure that it is only
4
+ # loaded once.
5
+ #
6
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
7
+
8
+ require 'lorem'
9
+
10
+ RSpec.configure do |config|
11
+ config.treat_symbols_as_metadata_keys_with_true_values = true
12
+ config.run_all_when_everything_filtered = true
13
+ config.filter_run :focus
14
+
15
+ # Run specs in random order to surface order dependencies. If you find an
16
+ # order dependency and want to debug it, you can fix the order by providing
17
+ # the seed, which is printed after each run.
18
+ # --seed 1234
19
+ config.order = 'random'
20
+ end
21
+
22
+ class RandomText
23
+ def initialize
24
+ @lorem_unit = 'words'
25
+ @max_lorems = 2000
26
+
27
+ @seed_text = Lorem::Base.new(@lorem_unit, @max_lorems).output
28
+
29
+ end
30
+ def output(max_output)
31
+ out = @seed_text.split
32
+ pos = rand(out.length - max_output)
33
+ start_pos = (pos < 0 ? 0 : pos)
34
+ end_pos = (pos + max_output > out.length ? out.length - max_output : pos + max_output)
35
+ return out[start_pos..end_pos].join(" ")
36
+ end
37
+
38
+ end
metadata ADDED
@@ -0,0 +1,118 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: storehouse_client
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.8
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Jon Gillies
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-08-08 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rspec
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: lorem
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: rest-client
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: crack
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :runtime
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ description: This the API client to the Storehouse application.
79
+ email:
80
+ - supercoder@gmail.com
81
+ executables: []
82
+ extensions: []
83
+ extra_rdoc_files: []
84
+ files:
85
+ - Rakefile
86
+ - Gemfile
87
+ - lib/storehouse_client/version.rb
88
+ - lib/storehouse_client.rb
89
+ - spec/client_spec.rb
90
+ - spec/small_test_spec.rb
91
+ - spec/spec_helper.rb
92
+ - README.md
93
+ - LICENSE.txt
94
+ homepage: https://github.com/jongillies/storehouse
95
+ licenses: []
96
+ post_install_message:
97
+ rdoc_options: []
98
+ require_paths:
99
+ - lib
100
+ required_ruby_version: !ruby/object:Gem::Requirement
101
+ none: false
102
+ requirements:
103
+ - - ! '>='
104
+ - !ruby/object:Gem::Version
105
+ version: '0'
106
+ required_rubygems_version: !ruby/object:Gem::Requirement
107
+ none: false
108
+ requirements:
109
+ - - ! '>='
110
+ - !ruby/object:Gem::Version
111
+ version: '0'
112
+ requirements: []
113
+ rubyforge_project:
114
+ rubygems_version: 1.8.23
115
+ signing_key:
116
+ specification_version: 3
117
+ summary: API client to the Storehouse
118
+ test_files: []