geostock 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in geostock.gemspec
4
+ gemspec
5
+
6
+
7
+ gem 'ruby-hmac', require: 'hmac-sha2'
8
+ gem 'rspec'
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require 'bundler/gem_tasks'
data/geostock.gemspec ADDED
@@ -0,0 +1,20 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "geostock/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "geostock"
7
+ s.version = GeoStock::VERSION
8
+ s.authors = ["CHIKURA Shinsaku"]
9
+ s.email = ["chsh@thinq.jp"]
10
+ s.homepage = ""
11
+ s.summary = %q{GeoStock API for Ruby}
12
+ s.description = %q{GeoStock API for Ruby}
13
+
14
+ s.rubyforge_project = "geostock"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+ end
data/lib/geostock.rb ADDED
@@ -0,0 +1,7 @@
1
+ require 'geostock/version'
2
+ require 'geostock/api'
3
+ require 'geostock/util'
4
+
5
+ module GeoStock
6
+ # Your code goes here...
7
+ end
@@ -0,0 +1,132 @@
1
+ require 'json'
2
+ require 'base64'
3
+ require 'net/http'
4
+ require 'uri'
5
+ require 'hmac'
6
+ require 'hmac-sha2'
7
+ require 'cgi'
8
+
9
+ module GeoStock
10
+ class API
11
+ REQUEST_EXPIRATION_TIME = 10 * 60 # 10 minutes
12
+ REQUEST_URI_BASE = 'http://geostock.jp/api'
13
+
14
+ def initialize(api_key, api_secret)
15
+ raise "API_KEY must be present." if api_key.nil?
16
+ raise "API_SECRET must be present." if api_secret.nil?
17
+ @api_token = api_key
18
+ @api_secret_token = api_secret
19
+ end
20
+
21
+ def collections
22
+ get :collections, refresh: 1
23
+ end
24
+
25
+ def update_poi(col_name, value)
26
+ update_pois col_name, value
27
+ end
28
+ def update_pois(col_name, value)
29
+ post(:update_pois, col_name => value)
30
+ end
31
+
32
+ def delete_poi(value)
33
+ delete_pois(value)
34
+ end
35
+ def delete_pois(value)
36
+ post(:update_pois, value)
37
+ end
38
+
39
+ def get_poi(col_name, uid)
40
+ get :get, col: col_name, id: uid
41
+ end
42
+ def get_all_pois(col_name)
43
+ get :get_all, col: col_name
44
+ end
45
+
46
+ def create_collection(col_name)
47
+ create_collections col_name
48
+ end
49
+ def create_collections(*col_names)
50
+ col_names = [col_names].flatten
51
+ post(:update_collections, col_names)
52
+ end
53
+ def update_collection(value)
54
+ update_collections(value)
55
+ end
56
+ def update_collections(value)
57
+ post(:update_collections, value)
58
+ end
59
+ def delete_collection(col_name)
60
+ delete_collections(col_name)
61
+ end
62
+ def delete_collections(*col_names)
63
+ col_names = [col_names].flatten
64
+ post(:delete_collections, col_names)
65
+ end
66
+
67
+ private
68
+ def sign_request(value)
69
+ text = b64encode(generate_json(value))
70
+ cur = (Time.now.utc.to_i / REQUEST_EXPIRATION_TIME)
71
+ d = HMAC::SHA256.new(@api_secret_token)
72
+ d.update text
73
+ d.update cur.to_s
74
+ [d.hexdigest, text].join('.')
75
+ end
76
+ def b64encode(text)
77
+ Base64.encode64(text).tr('+/', '-_').gsub(/\n/, '')
78
+ end
79
+ def b64decode(text)
80
+ Base64.decode64(text.tr('-_', '+/').gsub(/\n/, ''))
81
+ end
82
+ def generate_json(value)
83
+ JSON.generate value
84
+ end
85
+
86
+ CMD2PATH = {
87
+ delete_collections: 'collections/delete',
88
+ update_collections: 'collections/update',
89
+ delete_pois: 'pois/delete',
90
+ update_pois: 'pois/update',
91
+ collections: 'collections'
92
+ }
93
+ def post(cmd, value)
94
+ params = { signed_request: sign_request(value)}
95
+ path = CMD2PATH[cmd]
96
+ raise "Unknown cmd:#{cmd}" unless path
97
+ uri = URI.parse("#{url_base}/#{path}")
98
+ post_to(uri, params)
99
+ end
100
+ def post_to(uri, params)
101
+ query_string = params_to_query(params)
102
+ resp = Net::HTTP.start(uri.host, uri.port) do |http|
103
+ http.send(:post, uri.path, query_string)
104
+ end
105
+ rb = JSON.parse(resp.body)
106
+ raise "Response body must be Hash or Array. (#{rb.class})" unless (rb.is_a?(Hash) || rb.is_a?(Array))
107
+ GeoStock::Response.from(rb, code: resp.code, message: rb.is_a?(Hash) ? rb['message'] : nil)
108
+ end
109
+ def get(cmd, params = {})
110
+ uri = URI.parse("#{url_base}/#{cmd}")
111
+ get_from(uri, params)
112
+ end
113
+ def get_from(uri, params = {})
114
+ query_string = params_to_query(params)
115
+ resp = Net::HTTP.start(uri.host, uri.port) do |http|
116
+ path = "#{uri.path}?#{query_string}"
117
+ http.send(:get, path)
118
+ end
119
+ rb = JSON.parse(resp.body)
120
+ raise "Response body must be Hash or Array. (#{rb.class})" unless (rb.is_a?(Hash) || rb.is_a?(Array))
121
+ GeoStock::Response.from(rb, code: resp.code, message: rb.is_a?(Hash) ? rb['message'] : nil)
122
+ end
123
+ def url_base
124
+ "#{REQUEST_URI_BASE}/#{@api_token}"
125
+ end
126
+ def params_to_query(params)
127
+ params.map do |key,value|
128
+ "#{CGI.escape(key.to_s)}=#{CGI.escape(value.to_s)}"
129
+ end.join("&")
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,34 @@
1
+
2
+ module GeoStock
3
+ module Response
4
+ def self.from(value, opts = {})
5
+ case value
6
+ when Hash then ResponseHash.from(value, opts)
7
+ when Array then ResponseArray.from(value, opts)
8
+ else raise "Unexpected class. (#{value.class})"
9
+ end
10
+ end
11
+ end
12
+ class ResponseHash < Hash
13
+ attr_accessor :code, :message
14
+ def self.from(value, opts)
15
+ h = new
16
+ value.each do |k, v|
17
+ h[k] = v
18
+ end
19
+ h.code = opts[:code]
20
+ h.message = opts[:message]
21
+ h
22
+ end
23
+ end
24
+ class ResponseArray < Array
25
+ attr_accessor :code, :message
26
+ def self.from(value, opts)
27
+ a = new
28
+ a.push *value
29
+ a.code = opts[:code]
30
+ a.message = opts[:message]
31
+ a
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,3 @@
1
+ module GeoStock
2
+ VERSION = "0.0.2"
3
+ end
@@ -0,0 +1,76 @@
1
+ # -*- coding: UTF-8 -*-
2
+
3
+ require "spec_helper"
4
+
5
+ describe GeoStock::API do
6
+
7
+ before(:each) do
8
+ @api_token = ENV['GEOSTOCK_API_TOKEN']
9
+ @api_secret_token = ENV['GEOSTOCK_API_SECRET']
10
+ GeoStock::API::REQUEST_URI_BASE = ENV['GEOSTOCK_API_REQUEST_BASE']
11
+ @api = GeoStock::API.new @api_token, @api_secret_token
12
+ @api.delete_collections 'hello', 'world'
13
+ end
14
+
15
+ after(:each) do
16
+ @api.delete_collections 'hello', 'world'
17
+ end
18
+
19
+ it 'should manipulate collections' do
20
+ @api.collections.should == []
21
+ @api.create_collections 'hello', 'world'
22
+ @api.collections.should == ['hello', 'world']
23
+ @api.delete_collections 'hello'
24
+ @api.collections.should == ['world']
25
+ @api.delete_collections 'world'
26
+ @api.collections.should == []
27
+ end
28
+
29
+ it 'should manipulate pois.' do
30
+ @api = GeoStock::API.new @api_token, @api_secret_token
31
+ @api.create_collection 'world'
32
+ @api.update_pois 'world', [
33
+ {uid: '123', ll: '38.111234,138.44555', attrs: {
34
+ url: 'http://www.yahoo.co.jp/',
35
+ title: 'ほんじゃまか',
36
+ desc: '解説文'
37
+ }
38
+ }
39
+ ]
40
+ @api.update_pois 'world', [
41
+ {uid: '124', ll: '38.111234,138.445551', attrs: {
42
+ url: 'http://www.yahoo.co.jp/',
43
+ title: 'メロン',
44
+ desc: 'くだもの'
45
+ }
46
+ }
47
+ ]
48
+ poi_not_found = @api.get_poi('world', '125')
49
+ poi_not_found.code.should == '404'
50
+ poi_data = @api.get_poi('world', '124')
51
+ poi_data.should == {
52
+ 'uid' =>'124',
53
+ 'attrs' => { 'url' => 'http://www.yahoo.co.jp/',
54
+ 'title' => 'メロン',
55
+ 'desc' => 'くだもの'
56
+ },
57
+ 'll' => '38.111234,138.445551'
58
+ }
59
+
60
+ pois = @api.get_all_pois('world')
61
+ pois.should == [
62
+ {'uid' => '123', 'll' => '38.111234,138.44555', 'attrs' => {
63
+ 'url' => 'http://www.yahoo.co.jp/',
64
+ 'title' => 'ほんじゃまか',
65
+ 'desc' => '解説文'
66
+ }
67
+ },
68
+ {'uid' => '124', 'll' => '38.111234,138.445551', 'attrs' => {
69
+ 'url' => 'http://www.yahoo.co.jp/',
70
+ 'title' => 'メロン',
71
+ 'desc' => 'くだもの'
72
+ }
73
+ }
74
+ ]
75
+ end
76
+ end
@@ -0,0 +1,8 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+
4
+ require 'geostock' # and any other gems you need
5
+
6
+ RSpec.configure do |config|
7
+ # some (optional) config here
8
+ end
metadata ADDED
@@ -0,0 +1,59 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: geostock
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - CHIKURA Shinsaku
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-07-31 00:00:00.000000000 +09:00
13
+ default_executable:
14
+ dependencies: []
15
+ description: GeoStock API for Ruby
16
+ email:
17
+ - chsh@thinq.jp
18
+ executables: []
19
+ extensions: []
20
+ extra_rdoc_files: []
21
+ files:
22
+ - .gitignore
23
+ - Gemfile
24
+ - Rakefile
25
+ - geostock.gemspec
26
+ - lib/geostock.rb
27
+ - lib/geostock/api.rb
28
+ - lib/geostock/util.rb
29
+ - lib/geostock/version.rb
30
+ - spec/lib/geostock/api_spec.rb
31
+ - spec/spec_helper.rb
32
+ has_rdoc: true
33
+ homepage: ''
34
+ licenses: []
35
+ post_install_message:
36
+ rdoc_options: []
37
+ require_paths:
38
+ - lib
39
+ required_ruby_version: !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ! '>='
43
+ - !ruby/object:Gem::Version
44
+ version: '0'
45
+ required_rubygems_version: !ruby/object:Gem::Requirement
46
+ none: false
47
+ requirements:
48
+ - - ! '>='
49
+ - !ruby/object:Gem::Version
50
+ version: '0'
51
+ requirements: []
52
+ rubyforge_project: geostock
53
+ rubygems_version: 1.6.2
54
+ signing_key:
55
+ specification_version: 3
56
+ summary: GeoStock API for Ruby
57
+ test_files:
58
+ - spec/lib/geostock/api_spec.rb
59
+ - spec/spec_helper.rb