geostock 0.0.2

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/.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