threetaps-client 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. data/Gemfile +17 -0
  2. data/Gemfile.lock +43 -0
  3. data/LICENSE.txt +20 -0
  4. data/README.rdoc +48 -0
  5. data/Rakefile +68 -0
  6. data/VERSION +1 -0
  7. data/lib/client/client.rb +43 -0
  8. data/lib/client/geocoder_client.rb +42 -0
  9. data/lib/client/posting_client.rb +88 -0
  10. data/lib/client/reference_client.rb +60 -0
  11. data/lib/client/search_client.rb +82 -0
  12. data/lib/client/status_client.rb +72 -0
  13. data/lib/dto/geocoder/geocoder_request.rb +16 -0
  14. data/lib/dto/geocoder/geocoder_response.rb +7 -0
  15. data/lib/dto/posting/create_response.rb +23 -0
  16. data/lib/dto/posting/delete_response.rb +9 -0
  17. data/lib/dto/posting/exists_response.rb +16 -0
  18. data/lib/dto/posting/update_response.rb +9 -0
  19. data/lib/dto/search/best_match_response.rb +20 -0
  20. data/lib/dto/search/count_response.rb +9 -0
  21. data/lib/dto/search/query_request +0 -0
  22. data/lib/dto/search/range_request.rb +23 -0
  23. data/lib/dto/search/range_response.rb +26 -0
  24. data/lib/dto/search/search_request.rb +79 -0
  25. data/lib/dto/search/search_response.rb +37 -0
  26. data/lib/dto/search/summary_request.rb +13 -0
  27. data/lib/dto/search/summary_response.rb +20 -0
  28. data/lib/dto/status/get_status_response.rb +43 -0
  29. data/lib/dto/status/status_update_request.rb +27 -0
  30. data/lib/models/annotations/annotation.rb +21 -0
  31. data/lib/models/annotations/annotation_option.rb +9 -0
  32. data/lib/models/category.rb +26 -0
  33. data/lib/models/location.rb +30 -0
  34. data/lib/models/message.rb +9 -0
  35. data/lib/models/posting.rb +97 -0
  36. data/lib/models/posting_history.rb +8 -0
  37. data/lib/models/source.rb +27 -0
  38. data/lib/struct.rb +16 -0
  39. data/lib/threetaps-client.rb +44 -0
  40. data/spec/client/client_spec.rb +18 -0
  41. data/spec/client/geocoder_client_spec.rb +18 -0
  42. data/spec/client/posting_client_spec.rb +36 -0
  43. data/spec/client/reference_client_spec.rb +37 -0
  44. data/spec/client/search_client_spec.rb +53 -0
  45. data/spec/client/status_client_spec.rb +39 -0
  46. data/spec/dto/geocoder/geocoder_response_spec.rb +14 -0
  47. data/spec/dto/search/search_request_spec.rb +26 -0
  48. data/spec/dto/search/search_response_spec.rb +12 -0
  49. data/spec/spec_helper.rb +29 -0
  50. data/test/client/test_client.rb +11 -0
  51. data/test/client/test_geocoder_client.rb +43 -0
  52. data/test/client/test_posting_client.rb +88 -0
  53. data/test/client/test_reference_client.rb +32 -0
  54. data/test/client/test_search_client.rb +56 -0
  55. data/test/client/test_status_client.rb +49 -0
  56. data/test/dto/geocoder/test_geocoder_request.rb +16 -0
  57. data/test/dto/geocoder/test_geocoder_response.rb +14 -0
  58. data/test/dto/search/test_best_match_response.rb +10 -0
  59. data/test/dto/search/test_range_request.rb +13 -0
  60. data/test/dto/status/test_status_update_request.rb +18 -0
  61. data/test/helper.rb +18 -0
  62. data/test/models/test_posting.rb +28 -0
  63. data/test/test_struct.rb +17 -0
  64. data/test/test_threetaps-client.rb +7 -0
  65. data/threetaps-client.gemspec +153 -0
  66. metadata +266 -0
data/Gemfile ADDED
@@ -0,0 +1,17 @@
1
+ source "http://rubygems.org"
2
+ gem "supermodel", "~> 0.1.4"
3
+ gem "curb", "~> 0.7.9"
4
+ gem "activesupport", "~> 3.0.0"
5
+ # Add dependencies required to use your gem here.
6
+ # Example:
7
+ # gem "activesupport", ">= 2.3.5"
8
+
9
+ # Add dependencies to develop your gem here.
10
+ # Include everything needed to run rake, tests, features, etc.
11
+ group :development do
12
+ gem "shoulda", ">= 0"
13
+ gem "bundler", "~> 1.0.0"
14
+ gem "jeweler", "~> 1.5.2"
15
+ gem "rcov", ">= 0"
16
+ gem "rspec"
17
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,43 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ activemodel (3.0.3)
5
+ activesupport (= 3.0.3)
6
+ builder (~> 2.1.2)
7
+ i18n (~> 0.4)
8
+ activesupport (3.0.3)
9
+ builder (2.1.2)
10
+ curb (0.7.12)
11
+ diff-lcs (1.1.2)
12
+ git (1.2.5)
13
+ i18n (0.5.0)
14
+ jeweler (1.5.2)
15
+ bundler (~> 1.0.0)
16
+ git (>= 1.2.5)
17
+ rake
18
+ rake (0.8.7)
19
+ rcov (0.9.9)
20
+ rspec (2.3.0)
21
+ rspec-core (~> 2.3.0)
22
+ rspec-expectations (~> 2.3.0)
23
+ rspec-mocks (~> 2.3.0)
24
+ rspec-core (2.3.1)
25
+ rspec-expectations (2.3.0)
26
+ diff-lcs (~> 1.1.2)
27
+ rspec-mocks (2.3.0)
28
+ shoulda (2.11.3)
29
+ supermodel (0.1.4)
30
+ activemodel (>= 3.0.0.beta)
31
+
32
+ PLATFORMS
33
+ ruby
34
+
35
+ DEPENDENCIES
36
+ activesupport (~> 3.0.0)
37
+ bundler (~> 1.0.0)
38
+ curb (~> 0.7.9)
39
+ jeweler (~> 1.5.2)
40
+ rcov
41
+ rspec
42
+ shoulda
43
+ supermodel (~> 0.1.4)
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 marat
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,48 @@
1
+ = threetaps-client
2
+
3
+ == Installation
4
+
5
+ == Usage
6
+
7
+ === Search
8
+
9
+ To perform a search you need to
10
+ 1. create SearchRequest object and fill its attributes
11
+
12
+ request = SearchRequest.new
13
+
14
+ request.rpp = 10
15
+
16
+ request.text = "porsche"
17
+
18
+ 2. create SearchClient object
19
+
20
+ client = SearchClient.new
21
+
22
+ 3. call search method on client with request as a parameter and get an SearchResponse object.
23
+
24
+ response = client.search(request)
25
+
26
+ 4. now you can operate with search results:
27
+
28
+ postings = response.results
29
+
30
+ quantity = response.num_results
31
+
32
+ execution_time = response.exec_time_ms
33
+
34
+ == Contributing to threetaps-client
35
+
36
+ * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
37
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
38
+ * Fork the project
39
+ * Start a feature/bugfix branch
40
+ * Commit and push until you are happy with your contribution
41
+ * Make sure to add tests for it. This is important so we don't break it in a future version unintentionally.
42
+ * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
43
+
44
+ == Copyright
45
+
46
+ Copyright (c) 2011 3taps.com. See LICENSE.txt for
47
+ further details.
48
+
data/Rakefile ADDED
@@ -0,0 +1,68 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+ require 'rake'
11
+
12
+ require 'jeweler'
13
+ Jeweler::Tasks.new do |gem|
14
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
15
+ gem.name = "threetaps-client"
16
+ gem.homepage = "https://github.com/3taps/3taps-Ruby-Client"
17
+ gem.license = "MIT"
18
+ gem.summary = %Q{A Ruby gem for accessing the 3taps API}
19
+ gem.description = %Q{A Ruby gem for accessing the 3taps API. See more at http://developers.3taps.net}
20
+ gem.email = "developers@3taps.com"
21
+ gem.authors = ["3taps.com"]
22
+ # Include your dependencies below. Runtime dependencies are required when using your gem,
23
+ # and development dependencies are only needed for development (ie running rake tasks, tests, etc)
24
+ # gem.add_runtime_dependency 'jabber4r', '> 0.1'
25
+ # gem.add_development_dependency 'rspec', '> 1.2.3'
26
+ end
27
+ Jeweler::RubygemsDotOrgTasks.new
28
+
29
+ require 'rspec/core'
30
+ require 'rspec/core/rake_task'
31
+ RSpec::Core::RakeTask.new(:spec) do |spec|
32
+ spec.rspec_opts = ['--color']
33
+ spec.pattern = FileList['spec/**/*_spec.rb']
34
+ end
35
+
36
+ RSpec::Core::RakeTask.new(:rcov) do |spec|
37
+ spec.pattern = 'spec/**/*_spec.rb'
38
+ spec.rcov = true
39
+ end
40
+
41
+ task :default => :spec
42
+
43
+ # Run the unit tests
44
+ desc "Run all unit tests"
45
+
46
+ require 'rake/testtask'
47
+ Rake::TestTask.new(:test) do |test|
48
+ test.libs << 'lib' << 'test'
49
+ test.pattern = 'test/**/test_*.rb'
50
+ test.verbose = true
51
+ end
52
+
53
+ require 'rcov/rcovtask'
54
+ Rcov::RcovTask.new(:rcovtest) do |test|
55
+ test.libs << 'test'
56
+ test.pattern = 'test/**/test_*.rb'
57
+ test.verbose = true
58
+ end
59
+
60
+ require 'rake/rdoctask'
61
+ Rake::RDocTask.new do |rdoc|
62
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
63
+
64
+ rdoc.rdoc_dir = 'rdoc'
65
+ rdoc.title = "threetaps-client #{version}"
66
+ rdoc.rdoc_files.include('README*')
67
+ rdoc.rdoc_files.include('lib/**/*.rb')
68
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.5.1
@@ -0,0 +1,43 @@
1
+ # Base class for 3taps API client classes.
2
+ class Client
3
+ DEFAULT_URL = 'http://3taps.net'
4
+ DEFAULT_API_PORT = 80
5
+ # Initializes Client class with +baseUrl+ and +port+ parameters. By default
6
+ # DEFAULT_URL and DEFAULT_API_PORT are used. Examples:
7
+ # Client.new
8
+ # Client.new("http://3taps.com", 8080)
9
+ def initialize(baseUrl = DEFAULT_URL, port = DEFAULT_API_PORT)
10
+ @baseURL = baseUrl
11
+ @port = port
12
+ end
13
+
14
+ # Executes GET request on URL and port with +path+ and +params+ parameters.
15
+ # Example:
16
+ #
17
+ # execute_get("/search", "data=data")
18
+ def execute_get( path, params = nil )
19
+ address = params.nil? ? path : path + '?' + params
20
+ request = Curl::Easy.new("#{@baseURL}:#{@port}" + address)
21
+ begin
22
+ request.perform
23
+ rescue
24
+ "Some Error with Request."
25
+ end
26
+ request.body_str
27
+ end
28
+
29
+ # Executes POST request on URL and port with +path+ and +params+ parameters.
30
+ # Example:
31
+ #
32
+ # execute_post("search", "data=data")
33
+ def execute_post( path, params = nil )
34
+ c = Curl::Easy.http_post("#{@baseURL}:#{@port}/#{path}", params)
35
+ c.body_str
36
+ end
37
+
38
+ private
39
+
40
+ def decode(data)
41
+ ActiveSupport::JSON.decode(data)
42
+ end
43
+ end
@@ -0,0 +1,42 @@
1
+ # Class GeocoderClient represents server request of geocoding API (calculate
2
+ # the location to use for a posting based on location-specific details within
3
+ # the posting such as a street address or a latitude and longitude value).
4
+ #
5
+ # Its methods are used to query API with appropriate requests:
6
+ # geocode(requests) - returns array of responses
7
+ #
8
+ # Example:
9
+ #
10
+ # client = GeocoderClient.new
11
+ # request = GeocoderRequest.new
12
+ # request.latitude = '37.77493'
13
+ # request.longitude = '-122.41942'
14
+ #
15
+ # response = client.geocode(request)
16
+ #
17
+ # response.first.code # => "CAZ"
18
+ # response.first.latitude # => 39.77493
19
+ # response.first.longitude # => -122.41942
20
+
21
+ class GeocoderClient < Client
22
+
23
+ # Method geocode sends geocode request to Geocode API.
24
+ # Takes array of GeocoderRequest objects as +requests+ parameter.
25
+ #
26
+ # Examples:
27
+ #
28
+ # request = GeocoderRequest.new
29
+ # client.geocode(request) # => [GeocoderResponse]
30
+ #
31
+ # requests = [GeocoderRequest.new, GeocoderRequest.new]
32
+ # client.geocode(requests) # => [GeocoderResponse, GeocoderResponse]
33
+ #
34
+ def geocode(geocoder_requests)
35
+ geocoder_requests = [geocoder_requests] unless geocoder_requests.is_a? Array
36
+ params = "data=["
37
+ params << geocoder_requests.collect{|request| "#{request.to_params}"}.join(',')
38
+ params << "]"
39
+ response = execute_post('geocoder/geocode', params)
40
+ GeocoderResponse.from_array(decode(response))
41
+ end
42
+ end
@@ -0,0 +1,88 @@
1
+ # The PostingClient class allows clients to use 3taps Posting API to store and
2
+ # retrieve postings in the 3taps system.
3
+ #
4
+ # Its methods are used to query API with appropriate requests:
5
+ # client = PostingClient.new
6
+ # client.get_posting(post_key) # => returns a single Posting object
7
+ # client.create_posting(postings) # => returns array of CreateResponse objects
8
+ # client.update_posting(postings) # => returns array of UpdateResponse objects
9
+ # client.delete_posting(post_keys) # => returns array of DeleteResponse objects
10
+ # client.exists_posting(posting) # => returns array of ExistsResponse objects
11
+ class PostingClient < Client
12
+
13
+ # Retrieves an information about a single posting.
14
+ #
15
+ # Example
16
+ # client = PostingClient.new
17
+ # client.get_posting("...postKey string...") => Posting object
18
+ #
19
+ def get_posting(post_key)
20
+ response = execute_get("/posting/get/" + post_key)
21
+ Posting.new(decode(response))
22
+ end
23
+
24
+ # Method +create_posting+ saves a single new posting and multiple new postings in 3taps.
25
+ #
26
+ # Examples
27
+ # client = PostingClient.new
28
+ # client.update_posting([posting1, posting2]) #=> Array of CreateResponse objects
29
+ #
30
+ # client = PostingClient.new
31
+ # client.update_posting(posting2) #=> Array with single CreateResponse object
32
+ #
33
+ def create_posting(postings)
34
+ postings = [postings] unless postings.is_a? Array
35
+ data = "["
36
+ data << postings.collect{|posting| posting.to_json}.join(',')
37
+ data << "]"
38
+ params = "posts=#{data}"
39
+ response = execute_post("/posting/create", params)
40
+ CreateResponse.from_array(decode(response))
41
+ end
42
+
43
+ # Method +update_posting+ updates a single posting and multiple postings on 3taps.
44
+ #
45
+ # Examples:
46
+ # client = PostingClient.new
47
+ # client.update_posting([posting1, posting2]) #=> Array of UpdateResponse objects
48
+ #
49
+ # client = PostingClient.new
50
+ # client.update_posting(posting) #=> Array with single UpdateResponse object
51
+ #
52
+ def update_posting(postings)
53
+ postings = [postings] unless postings.is_a? Array
54
+ data = "["
55
+ data << postings.collect{|posting| posting.to_json_for_update}.join(',')
56
+ data << "]"
57
+ params = "data=#{data}"
58
+ response = execute_post("posting/update", params)
59
+ UpdateResponse.from_hash(decode(response))
60
+ end
61
+
62
+ # Method +delete_posting+ deletes a single posting and multiple postings from 3taps.
63
+ #
64
+ # Examples:
65
+ # client = PostingClient.new
66
+ # response = client.delete_posting(...Array of postKeys strings...) # => Array of DeleteResponse objects
67
+ #
68
+ # client = PostingClient.new
69
+ # key = some_posting.postKey
70
+ # response = client.delete_posting(key) # => Array with single DeleteResponse object
71
+ #
72
+ def delete_posting(post_keys)
73
+ post_keys = [post_keys] unless post_keys.is_a? Array
74
+ params = "data=['#{post_keys.join("','")}']"
75
+ response = execute_post("posting/delete", params)
76
+ DeleteResponse.from_hash(decode(response))
77
+ end
78
+
79
+ # NOT USED
80
+ #
81
+ # Returns information on the existence of postings.
82
+ #
83
+ def exists_posting(posting)
84
+ params = "ids=#{posting}"
85
+ response = execute_post("/posting/exists", params)
86
+ ExistsResponse.from_array(decode(response))
87
+ end
88
+ end
@@ -0,0 +1,60 @@
1
+ # Class ReferenceClient represents server request of reference API (provides a
2
+ # mechanism for accessing the standard "reference information" used by the
3
+ # 3taps system, including locations, categories, and sources).
4
+ #
5
+ # Its methods are used to query API with appropriate requests:
6
+ # client = ReferenceClient.new
7
+ # client.get_categories # => returns array of Category objects
8
+ # client.get_category(code) # => returns Category object
9
+ # client.get_locations # => returns array of Location objects
10
+ # client.get_sources # => returns array of Source objects
11
+
12
+ class ReferenceClient < Client
13
+
14
+ # Method +get_categories+ returns the 3taps categories.
15
+ #
16
+ # Example:
17
+ #
18
+ # client = ReferenceClient.new
19
+ # client.get_categories # => Array of Category
20
+ #
21
+ def get_categories
22
+ response = execute_get("/reference/category")
23
+ File.new("newfile", "w+") << response
24
+ Category.from_array(decode(response))
25
+ end
26
+
27
+ # Method +get_category+ returns a single category by passing in the category code.
28
+ # Takes value of code objects as +String+ parameter.
29
+ #
30
+ # Example:
31
+ #
32
+ # client.get_category('NYC') # => Categoty
33
+ #
34
+ def get_category(code)
35
+ response = execute_get("/reference/category/" + code)
36
+ Category.from_hash(decode(response)[0])
37
+ end
38
+
39
+ # Method +get_locations+ returns the 3taps locations.
40
+ #
41
+ # Example:
42
+ #
43
+ # client.get_locations # => Array of Location
44
+ #
45
+ def get_locations
46
+ response = execute_get("/reference/location")
47
+ Location.from_array(decode(response))
48
+ end
49
+
50
+ # Method +get_sources+ returns the 3taps sources.
51
+ #
52
+ # Example:
53
+ #
54
+ # client.get_sources # => Array of Source
55
+ #
56
+ def get_sources
57
+ response = execute_get("/reference/source")
58
+ Source.from_array(decode(response))
59
+ end
60
+ end
@@ -0,0 +1,82 @@
1
+ # The SearchClient class allows clients to query 3taps Search API for data,
2
+ # and data about data.
3
+ #
4
+ # Its methods are used to query API with appropriate requests:
5
+ # client = SearchClient.new
6
+ # client.search(search_request) # => returns array of SearchResponse objects
7
+ # client.range(range_request) # => returns array of RangeResponse objects
8
+ # client.summary(summary_request) # => returns array of SummaryResponse objects
9
+ # client.count(search_request) # => returns array of CountResponse objects
10
+ # client.best_match(keywords) # => returns array of BestMatchResponse objects
11
+ class SearchClient < Client
12
+
13
+ # Method +search+ searches 3taps for postings. Example:
14
+ #
15
+ # request = SearchRequest.new
16
+ # client = SearchClient.new
17
+ # client.search(request) # => SearchResponse
18
+ #
19
+ def search(search_request)
20
+ response = execute_get("/search", search_request.query_params)
21
+ SearchResponse.new(decode(response))
22
+ end
23
+
24
+ # Method +range+ returns the minium and maximum values currently in 3taps for
25
+ # the given fields that match the given Common Search Criteria inside of the
26
+ # RangeResponse object. The purpose of the range method is to provide
27
+ # developers with sensible values for range-based UI filters.
28
+ #
29
+ # Examples:
30
+ #
31
+ # request = RangeRequest.new
32
+ # client = SearchClient.new(request)
33
+ # client.range(request) # => RangeResponse
34
+ #
35
+ def range(range_request)
36
+ response = execute_get("/search/range", range_request.query_params)
37
+ RangeResponse.from_array(decode(response))
38
+ end
39
+
40
+ # Method +summary+ returns the total number of postings found in 3taps, across
41
+ # the given dimension, that match the given Common Search Criteria parameters
42
+ # inside of the SummaryResponse object. Searching for "text=toyota" across
43
+ # "dimension=source" would return a list of all sources in 3taps, along with
44
+ # the number of postings matching the search "text=toyota" in that source.
45
+ # You may currently search across dimensions source, category, and location.
46
+ #
47
+ # Examples:
48
+ #
49
+ # request = SummaryRequest.new
50
+ # client = SearchClient.new
51
+ # client.summary(request) # => SummaryResponse
52
+ #
53
+ def summary(summary_request)
54
+ response = execute_get("/search/summary", summary_request.query_params)
55
+ SummaryResponse.from_hash(decode(response))
56
+ end
57
+
58
+ # Method +count+ returns the total number of postings that match the given
59
+ # Common Search Criteria represented by SearchRequest. Example:
60
+ #
61
+ # request = SearchRequest.new
62
+ # client = SearchClient.new
63
+ # client.count(request) # => CountResponse
64
+ #
65
+ def count(search_request)
66
+ response = execute_get("/search/count", search_request.query_params)
67
+ CountResponse.new(decode(response))
68
+ end
69
+
70
+ # Method +best_match+ returns the 3taps category associated with the keywords,
71
+ # along with the number of postings in that category. Example:
72
+ #
73
+ # keywords = "iPad,Apple,iPhone"
74
+ # client = SearchClient.new
75
+ # client.best_match(keywords) # => BestMatchResponse
76
+ #
77
+ def best_match(keywords)
78
+ response = execute_get("/search/best-match", "keywords=#{keywords}")
79
+ BestMatchResponse.from_hash(decode(response))
80
+ end
81
+
82
+ end
@@ -0,0 +1,72 @@
1
+ # The StatusClient class provides access to the Status API.
2
+ #
3
+ # The Status API provides access to the status of postings, both inside and
4
+ # outside of the 3taps system. The Status API is built upon the assumption that
5
+ # most postings can be globally identified using two pieces of data: the source
6
+ # and the externalID. Since we can globally identify a posting, we can share the
7
+ # status of postings between various systems.
8
+ #
9
+ # For example, if a posting has been
10
+ # "sent" to the Posting API by an external source, that external source can
11
+ # optionally send a status of "sent" to the Status API. Once the Posting API has
12
+ # processed and saved the posting, it can send the status of "saved" to the
13
+ # Status API. Later, if somebody looks up the posting in the Status API, they
14
+ # will see both of these events (sent and saved), along with the time that they
15
+ # occurred, and any relevant attributes (postKey, errors, etc). Having this
16
+ # information available allows 3taps and sources to provide maximum visibility
17
+ # into their processes so that both can improve data yield.
18
+ #
19
+ # Class StatusClient provides access to the status API of postings
20
+ # server response returns the status of postings, if a posting has been "sent" to the Posting API by an
21
+ # external source, that external source can optionally send a status of "sent" the Status API.
22
+ #
23
+ # Its methods are used to query API with appropriate requests:
24
+ # client = StatusClient .new
25
+ # client.update_status(postings) # => returns Message
26
+ # client.get_status(postings) # => returns array of GetStatusResponse objects
27
+ # client.system_status # => returns Message
28
+ #
29
+ class StatusClient < Client
30
+ #
31
+ # Method +update_status+ send in status events for postings. Example:
32
+ #
33
+ # client = StatusClient.new
34
+ # request = StatusUpdateRequest.new
35
+ # client.update_status(request) # => Message
36
+ #
37
+ def update_status(postings)
38
+ postings = [postings] unless postings.is_a? Array
39
+ params ='events=['
40
+ params << postings.collect{|posting| "{#{posting.status.to_params}, #{posting.to_json_for_status_client}}" unless posting.status.event.empty?}.join(',')
41
+ params << "]"
42
+ response = execute_post("status/update", params)
43
+ Message.from_hash(decode(response))
44
+ end
45
+ #
46
+ # Method +get_status+ get status history for postings. Example:
47
+ #
48
+ # client = SearchClient.new
49
+ # postings = Posting.new
50
+ # response = client.get_status(postings) # => Array of GetStatusResponse
51
+ #
52
+ def get_status(postings)
53
+ postings = [postings] unless postings.is_a? Array
54
+ data = "["
55
+ data << postings.collect{|posting| "{#{posting.to_json_for_status_client}}"}.join(',')
56
+ data << "]"
57
+ params = "ids=#{data}"
58
+ response = execute_post("status/get", params)
59
+ GetStatusResponse.from_array(decode(response))
60
+ end
61
+ #
62
+ # Method +system_status+ get the current system status. Example:
63
+ #
64
+ # client = StatusClient.new
65
+ # response = client.system_status # => Message
66
+ #
67
+ def system_status
68
+ response = execute_get("/status/system")
69
+ Message.from_hash(decode(response))
70
+ end
71
+
72
+ end
@@ -0,0 +1,16 @@
1
+ class GeocoderRequest < Struct.new(:latitude, :longitude, :country, :state, :city, :locality, :postal, :text)
2
+
3
+ def to_params
4
+ result = []
5
+ result << "\"latitude\":#{CGI.escape latitude}" unless latitude.nil?
6
+ result << "\"longitude\":#{CGI.escape longitude}" unless longitude.nil?
7
+ result << "\"country\":\"#{CGI.escape country}\"" unless country.nil?
8
+ result << "\"state\":\"#{CGI.escape state}\"" unless state.nil?
9
+ result << "\"city\":\"#{CGI.escape city}\"" unless city.nil?
10
+ result << "\"locality\":\"#{CGI.escape locality}\"" unless locality.nil?
11
+ result << "\"postal\":\"#{CGI.escape postal}\"" unless postal.nil?
12
+ result << "\"tex\":\"#{CGI.escape text}\"" unless text.nil?
13
+ '{' + result.join(", ") + '}'
14
+ end
15
+
16
+ end
@@ -0,0 +1,7 @@
1
+ class GeocoderResponse < Struct.new(:code, :latitude, :longitude)
2
+ def self.from_array(array)
3
+ array.collect do |geocode|
4
+ from_hash(:code => geocode[0], :latitude => geocode[1], :longitude => geocode[2])
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,23 @@
1
+ # Class CreateResponse represents server response on +create+ Posting API
2
+ # request. Server response is sent to +from_array+ method which creates objects
3
+ # with attributes +postKey+, +error+ accessible via getters:
4
+ #
5
+ # response = RangeResponse.from_array(...)
6
+ # response.postKey # => String
7
+ # response.post_key # => String
8
+ # response.error # => String
9
+ #
10
+ class CreateResponse < Struct.new(:postKey, :error) do
11
+ def post_key
12
+ postKey
13
+ end
14
+ end
15
+
16
+ # Method +from_array+ creates an array of CreateResponse objects from a given
17
+ # array of JSON hashes.
18
+ def self.from_array(array)
19
+ array.collect do |element|
20
+ CreateResponse.new(element)
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,9 @@
1
+ # Class DeleteResponse represents server response on +delete+ Posting API
2
+ # request. Server response is sent to +from_hash+ method which creates object
3
+ # with attribute +success+ accessible via getter:
4
+ #
5
+ # response = DeleteResponse.from_hash("success" => "true")
6
+ # response.success # => true
7
+ #
8
+ class DeleteResponse < Struct.new(:success)
9
+ end
@@ -0,0 +1,16 @@
1
+ # NOT USED
2
+ #
3
+ # Class ExistsResponse represents server response on +exists+ Posting API
4
+ # request. Server response is sent to +from_hash+ method which creates object
5
+ # with attribute +success+ accessible via getter:
6
+ #
7
+ # response = ExistsResponse.from_hash("success" => "true")
8
+ # response.success # => true
9
+ #
10
+ class ExistsResponse
11
+ attr_accessor :exists, :postKey, :error
12
+
13
+ def self.from_array(json)
14
+ json
15
+ end
16
+ end
@@ -0,0 +1,9 @@
1
+ # Class UpdateResponse represents server response on +update+ Posting API
2
+ # request. Server response is sent to +from_hash+ method which creates object
3
+ # with attribute +success+ accessible via getter:
4
+ #
5
+ # response = UpdateResponse.from_hash("success" => "true")
6
+ # response.success # => true
7
+ #
8
+ class UpdateResponse < Struct.new(:success)
9
+ end