storehouse_client 0.0.8

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/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: []