wit_ruby 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,143 @@
1
+ ## client.rb
2
+ ## Facilitates the secure connection between the Wit servers and ruby application.
3
+ ## Quite confusing as Net::HTTP and Net::HTTPs is a messy library.
4
+ ## Do look it up if you need more help understanding!
5
+
6
+ module Wit
7
+ module REST
8
+ ## Wit::Session::Client class holds the authentication parameters and
9
+ ## handles making the HTTP requests to the Wit API. These methods should be
10
+ ## internally called and never called directly from the user.
11
+
12
+ ## An example call to instantiate client is done like this with defaults:
13
+ ##
14
+ ## => @client = Wit::Session:Client.new
15
+ ##
16
+ class Client
17
+
18
+ ## Default settings for the client connection to the Wit api.
19
+ DEFAULTS = {
20
+ :token => ENV["WIT_AI_TOKEN"],
21
+ :addr => 'api.wit.ai',
22
+ :port => 443,
23
+ :use_ssl => true,
24
+ :ssl_verify_peer => true,
25
+ :ssl_ca_file => File.dirname(__FILE__) + '/../../../conf/cacert.pem',
26
+ :timeout => 30,
27
+ :proxy_addr => nil,
28
+ :proxy_port => nil,
29
+ :proxy_user => nil,
30
+ :proxy_pass => nil,
31
+ :retry_limit => 1,
32
+ }
33
+
34
+ ## Allows for the reading of the last request, last response, and the
35
+ ## current session.
36
+ attr_reader :last_req, :last_response, :session, :last_result
37
+
38
+ ## Initialize the new instance with either the default parameters or
39
+ ## given parameters.
40
+ ## Token is either the set token in ENV["WIT_AI_TOKEN"] or given in the
41
+ ## options.
42
+ def initialize(options = {})
43
+ ## Token is overidden if given in set params.
44
+ @params = DEFAULTS.merge options
45
+ @auth_token = @params[:token].strip
46
+ setup_conn
47
+ setup_session
48
+ end
49
+
50
+
51
+ ## Change the given auth token.
52
+ def change_auth(new_auth)
53
+ @auth_token = new_auth.strip
54
+ end
55
+
56
+ ## Defines each REST method for the given client. GET, PUT, POST and DELETE
57
+ [:get, :put, :post, :delete].each do |rest_method|
58
+ ## Get the given class for Net::HTTP depending on the current method.
59
+ method_rest_class = Net::HTTP.const_get rest_method.to_s.capitalize
60
+
61
+ ## Define the actual method for Wit::Session:Client
62
+ define_method rest_method do |path|#|path, params|
63
+ request = method_rest_class.new path, {"Authorization" => "Bearer #{@auth_token}"}
64
+ #request.set_form_data(params)#params if [:post, :put].include?(rest_method)
65
+ return connect_send(request)
66
+ end
67
+ end
68
+
69
+ ## Takes in a body and path and creates a net/http class and uses it to call a request to API
70
+ def request_from_result(rest, path, body)
71
+ method_rest_class = Net::HTTP.const_get rest.capitalize
72
+ refresh_request = method_rest_class.new path, {"Authorization" => "Bearer #{@auth_token}"}
73
+ refresh_request.set_form_data(body) unless body == nil
74
+ ## Connect and send it to the API server.
75
+ return connect_send(refresh_request)
76
+ end
77
+
78
+ #################################
79
+ private
80
+
81
+ ## Setup the session that allows for calling of
82
+ def setup_session
83
+ @session = Wit::REST::Session.new(self)
84
+ end
85
+
86
+ ## Used to setup a connection using Net::HTTP object when making requests
87
+ ## to the API.
88
+ def setup_conn
89
+
90
+ ## Setup connection through the @conn instance variable and proxy if
91
+ ## if given.
92
+ @conn = Net::HTTP.new(@params[:addr], @params[:port],
93
+ @params[:proxy_addr], @params[:proxy_port],
94
+ @params[:proxy_user], @params[:proxy_pass]
95
+ )
96
+ setup_ssl
97
+ ## Set timeouts
98
+ @conn.open_timeout = @params[:timeout]
99
+ @conn.read_timeout = @params[:timeout]
100
+ end
101
+
102
+ ## Setup SSL for the given connection in @conn.
103
+ def setup_ssl
104
+ @conn.use_ssl = @params[:use_ssl]
105
+ if @params[:ssl_verify_peer]
106
+ @conn.verify_mode = OpenSSL::SSL::VERIFY_PEER
107
+ @conn.ca_file = @params[:ssl_ca_file]
108
+ else
109
+ @conn.verify_mode = OpenSSL::SSL::VERIFY_NONE
110
+ end
111
+ end
112
+
113
+ ## Connect and send the given request to Wit server.
114
+ def connect_send(request)
115
+ ## Set the last request parameter
116
+ @last_req = request
117
+ ## Set the retries if necessary to send again.
118
+ left_retries = @params[:retry_limit]
119
+ ## Start sending request
120
+ begin
121
+ ## Save last response and depending on the response, return back the
122
+ ## given body as a hash.
123
+ response = @conn.request request
124
+ @last_response = response
125
+ case response.code
126
+ when "200" then save_result_and_return(request, response)
127
+ when "401" then raise Unauthorized, "Incorrect token or not set. Set ENV[\"WIT_AI_TOKEN\"] or pass into the options parameter as :token"
128
+ #else raise BadResponse, "response code: #{response.status}"
129
+ end
130
+
131
+ end
132
+ end
133
+
134
+ ## Save it into the instance last_result and return it.
135
+ def save_result_and_return(request, response)
136
+ @last_result = Wit::REST::Result.new(MultiJson.load(response.body), request.method, request.path, request.body)
137
+ return @last_result
138
+ end
139
+
140
+
141
+ end
142
+ end
143
+ end
@@ -0,0 +1,49 @@
1
+ ## result.rb
2
+ ## Specifies class that handles the results given from each RESTful API call.
3
+
4
+
5
+ module Wit
6
+ module REST
7
+ class Result
8
+
9
+
10
+ ## Instantiates with a given hash.
11
+ def initialize(resultHash, requestRest=nil, requestPath=nil, requestBody=nil)
12
+ @originalHash = resultHash
13
+ @requestRest = requestRest
14
+ @requestPath = requestPath
15
+ @requestBody = requestBody
16
+ end
17
+
18
+ ## Returns the orginalHash instance variable.
19
+ def hash
20
+ return @originalHash
21
+ end
22
+
23
+ ## Returns the REST code from the given request
24
+ def restCode
25
+ return @requestRest
26
+ end
27
+ ## Returns the request's body
28
+ def body
29
+ return @requestBody
30
+ end
31
+
32
+ ## Returns the request's path
33
+ def path
34
+ return @requestPath
35
+ end
36
+
37
+
38
+ ## Checks if the method is one of the keys in the hash.
39
+ ## If it is then we can return the given value.
40
+ ## If not, then raise a NoMethodError.
41
+ def method_missing(possible_key, *args, &block)
42
+ @originalHash.has_key?(possible_key.to_s) ? @originalHash[possible_key.to_s] : super
43
+ end
44
+
45
+
46
+
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,94 @@
1
+ ## session.rb
2
+ ## Handles all the neccesary methods to do certain API RESTful calls.
3
+ ## Documentation from Wit for these methods - https://wit.ai/docs/api
4
+
5
+ module Wit
6
+ module REST
7
+ class Session
8
+ ## Initialize with the given client.
9
+ def initialize(client)
10
+ @client = client
11
+ end
12
+ ## GET - extracted meaning form a sentence
13
+ def send_message(message)
14
+ return @client.get("/message?q=#{message}")
15
+ end
16
+
17
+ ## POST - extract meaning from a audio file
18
+ ## Do check the certain documentation of what the specific audio file
19
+ ## should be.
20
+ def send_sound_message(sound)
21
+ end
22
+
23
+ ## GET - returns stored message for specific id.
24
+ ## TODO - possibly renaming as it is ambigious compared to send_message.
25
+ def get_message(message_id)
26
+
27
+ end
28
+
29
+ ## GET - returns either a list of intents if no id is given.
30
+ ## - returns the specific intent of the id given.
31
+ def get_intent(intent_id = nil)
32
+ end
33
+
34
+ ## TODO - look into corpus
35
+
36
+ ## GET - returns a list of available entities given this instance with the
37
+ ## given token if no id is given.
38
+ ## - returns the specific entity and its parameters with a given id.
39
+ ## TODO - notify Wit.ai to fix their documentations as there is a wrong
40
+ ## - description.
41
+ def entities(entity_id = nil)
42
+
43
+ end
44
+
45
+ ## POST - creates a new entity with the given attributes.
46
+ def create_entity(new_entity)
47
+ end
48
+
49
+ ## PUT - updates a given entity with the specific entity id.
50
+ def update_entity(entity_id)
51
+ end
52
+
53
+ ## DELETE - deletes the given entity with the entity id.
54
+ def delete_entity(entity_id)
55
+ end
56
+
57
+ ## POST - adds the possible value into the list of values for the given
58
+ ## - entity with the id.
59
+ def add_value(entity_id, new_value)
60
+
61
+ end
62
+
63
+ ## DELETE - deletes the value from the list of values in the entity with
64
+ ## - with the given value.
65
+ def delete_value(entity_id, delete_value)
66
+
67
+ end
68
+
69
+ ## POST - adds a new expression to the value of the entity.
70
+ def add_expression(entity_id, value, new_expression)
71
+
72
+ end
73
+
74
+ ## DELETE - deleetes the expression in the value of the entity.
75
+ def delete_expression(entity_id, value, expression)
76
+
77
+ end
78
+
79
+ ## Used to refresh the results from the given results.
80
+ def refresh_results(result)
81
+ ## Call client with refresh results method
82
+ return @client.request_from_result(result.restCode, result.path, result.body)
83
+ end
84
+
85
+ ## Used to refresh the last response given from the last request.
86
+ def refresh_last
87
+ last_result = @client.last_result
88
+ return @client.request_from_result(last_result.restCode, last_result.path, last_result.body)
89
+ end
90
+
91
+
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,3 @@
1
+ module Wit
2
+ VERSION = "0.0.1"
3
+ end
data/lib/wit_ruby.rb ADDED
@@ -0,0 +1,9 @@
1
+ require 'net/http'
2
+ require 'net/https'
3
+ require 'multi_json'
4
+
5
+
6
+ require "wit_ruby/version"
7
+ require "wit_ruby/rest/client"
8
+ require "wit_ruby/rest/session"
9
+ require "wit_ruby/rest/result"
@@ -0,0 +1,15 @@
1
+
2
+ require 'coveralls'
3
+ Coveralls.wear!
4
+
5
+ require 'wit_ruby'
6
+ require 'pry'
7
+
8
+ require 'webmock/rspec'
9
+ require 'vcr'
10
+
11
+ #VCR config
12
+ VCR.configure do |c|
13
+ c.cassette_library_dir = 'spec/fixtures/wit_cassettes'
14
+ c.hook_into :webmock
15
+ end
@@ -0,0 +1,63 @@
1
+ ## client_spec.rb
2
+ ## Test the functionalities of lib/wit_ruby/rest/client.rb
3
+
4
+ require 'spec_helper'
5
+
6
+ describe Wit::REST::Client do
7
+ let(:rand_auth) {"someAuth"}
8
+ let(:another_auth) {"someOtherAuth"}
9
+ let(:new_host) {"api.fakewit.ai"}
10
+ let(:new_port) {132}
11
+ let(:new_proxy) {"localhost"}
12
+ let(:new_proxy_port) {241}
13
+ let(:new_timeout) {rand(30)}
14
+ let(:new_ssl_path) {"some/ssl/path"}
15
+
16
+ it "should create a new client instance given some auth token" do
17
+ #pending("Need to instantiate the given client with a given token.")
18
+ @client = Wit::REST::Client.new(token: rand_auth)
19
+ expect(@client.instance_variable_get("@auth_token")).to eql(rand_auth)
20
+ end
21
+
22
+ it "should have the proper default connection parameters" do
23
+ @client = Wit::REST::Client.new(token: rand_auth)
24
+ @conn = @client.instance_variable_get("@conn")
25
+ expect(@conn.address).to eql("api.wit.ai")
26
+ expect(@conn.use_ssl?).to be_true
27
+
28
+ end
29
+
30
+ it "should allow the change of the current instance's auth token" do
31
+ #pending("Change the instance auth token to another")
32
+ @client = Wit::REST::Client.new(token: rand_auth)
33
+ @client.change_auth(another_auth)
34
+ expect(@client.instance_variable_get("@auth_token")).to eql(another_auth)
35
+ end
36
+
37
+ it "should allow for change of the default options and accept proxy" do
38
+ @client = Wit::REST::Client.new(token: rand_auth, addr: new_host,
39
+ port: new_port, ssl_ca_file: new_ssl_path, timeout: new_timeout,
40
+ proxy_addr: new_proxy, proxy_port: new_proxy_port)
41
+ @conn = @client.instance_variable_get("@conn")
42
+ expect(@conn.address).to eql(new_host)
43
+ expect(@conn.port).to eql(new_port)
44
+ expect(@conn.proxy?).to be_true
45
+ expect(@conn.proxy_address).to eql(new_proxy)
46
+ expect(@conn.proxy_port).to eql(new_proxy_port)
47
+ expect(@conn.open_timeout).to eql(new_timeout)
48
+ expect(@conn.read_timeout).to eql(new_timeout)
49
+ expect(@conn.ca_file).to eql(new_ssl_path)
50
+
51
+ end
52
+
53
+ it "should setup a session parameter to properly wrap API with commands" do
54
+ @client = Wit::REST::Client.new(token: rand_auth)
55
+ expect(@client.instance_variable_get("@session")).to be_true
56
+ end
57
+
58
+
59
+ it "should be able to do an API call when given a result object" do
60
+ @client = Wit::REST::Client.new(token: rand_auth)
61
+ expect(@client).to respond_to(:request_from_result)
62
+ end
63
+ end
@@ -0,0 +1,38 @@
1
+ ## result_spec.rb
2
+ ## Tests functionalities of lib/wit_ruby/rest/result.rb
3
+ require 'spec_helper'
4
+
5
+ describe Wit::REST::Result do
6
+ let(:randHash) {{"a" => "a", "b" => "b"}}
7
+ let(:rand_path) {"rand_path"}
8
+ let(:rand_body) {"rand_body"}
9
+ let(:rest_code) {"post"}
10
+ let(:result) {Wit::REST::Result.new(randHash, rest_code, rand_path, rand_body)}
11
+
12
+
13
+ it "should have an instance of the original hash" do
14
+ expect(result.hash).to eql(randHash)
15
+ end
16
+
17
+ it "should raise an error for a method that is not in the attributes of the hash" do
18
+ expect{result.random_method}.to raise_error(NoMethodError)
19
+ end
20
+
21
+ it ".method_missing(name, *args, &block" do
22
+ expect(result).to respond_to(:method_missing)
23
+ end
24
+
25
+ it "should not raise any errors for the given keys in a hash" do
26
+ randHash.each_key do |key|
27
+ expect{result.send(key)}.not_to raise_error
28
+ end
29
+ end
30
+
31
+
32
+ it "should have an optional parameters to store the original request's body and pth" do
33
+ expect(result.restCode).to eql(rest_code)
34
+ expect(result.path).to eql(rand_path)
35
+ expect(result.body).to eql(rand_body)
36
+ end
37
+
38
+ end
@@ -0,0 +1,120 @@
1
+ ## session_spec.rb
2
+ ## Used to test lib/wit_ruby/rest/session_spec.rb
3
+
4
+ require 'spec_helper'
5
+
6
+ describe Wit::REST::Session do
7
+ let(:auth) {"randomAuth"}
8
+ let(:randClient) {"randomClient"}
9
+ let(:message) {"Hi"}
10
+ let(:randSession) {Wit::REST::Session.new(randClient)}
11
+ let(:session) {Wit::REST::Client.new.session}
12
+
13
+
14
+ ## Testing for method response
15
+ describe "Default attributes and method definitions" do
16
+ it "should have a client instance variable" do
17
+ randSession.instance_variable_get("@client").should be_eql randClient
18
+ end
19
+
20
+ it '.send_message(message)' do
21
+ randSession.should respond_to(:send_message)
22
+ end
23
+
24
+ it ".send_sound_message(soundwave)" do
25
+ randSession.should respond_to(:send_sound_message)
26
+ end
27
+
28
+ it ".get_message(message_id)" do
29
+ randSession.should respond_to(:get_message)
30
+ end
31
+
32
+ it "get_intent(intent_id = nil)" do
33
+ randSession.should respond_to(:get_intent)
34
+ end
35
+
36
+ it ".entities(entity_id = nil)" do
37
+ randSession.should respond_to(:entities)
38
+ end
39
+
40
+ it ".create_entity(new_entity)" do
41
+ randSession.should respond_to(:create_entity)
42
+ end
43
+
44
+ it ".update_entity(entity_id)" do
45
+ randSession.should respond_to(:update_entity)
46
+ end
47
+
48
+ it ".delete_entity(entity_id)" do
49
+ randSession.should respond_to(:delete_entity)
50
+ end
51
+
52
+ it ".add_value(entity_id, new_value)" do
53
+ randSession.should respond_to(:add_value)
54
+ end
55
+
56
+ it ".delete_value(entity_id, delete_value)" do
57
+ randSession.should respond_to(:delete_value)
58
+ end
59
+
60
+ it ".add_expression(entity_id, value, new_expression)" do
61
+ randSession.should respond_to(:add_expression)
62
+ end
63
+
64
+ it ".delete_expression(entity_id, value, expression)" do
65
+ randSession.should respond_to(:delete_expression)
66
+ end
67
+ end
68
+
69
+
70
+
71
+ ################# Functionalities with API mockup ###########################
72
+
73
+ describe "Sending message" do
74
+ let(:result) {session.send_message(message)}
75
+ let(:result_hash){result.hash}
76
+
77
+ before do
78
+ VCR.insert_cassette 'message', record: :new_episodes
79
+ end
80
+ after do
81
+ VCR.eject_cassette
82
+ end
83
+
84
+ it "should return an object of class Result" do
85
+ expect(result.class).to eql(Wit::REST::Result)
86
+ end
87
+
88
+ it "should have a message id method" do
89
+ expect(result.msg_id).to eql(result.hash["msg_id"])
90
+ end
91
+
92
+
93
+
94
+
95
+ describe "caching" do
96
+ ## Use webmock to disable the network connection after the api request
97
+ ## We use the simple sending message method for testing.
98
+ before do
99
+ @results = session.send_message(message)
100
+ stub_request(:any, /api.wit.ai/).to_timeout
101
+ end
102
+
103
+
104
+
105
+ it "must be able refresh and resend the call to the API given the result class" do
106
+ expect{session.refresh_results(@results)}.to raise_error(Timeout::Error)
107
+ end
108
+
109
+ it "should be able to refresh the last result" do
110
+ expect{session.refresh_last}.to raise_error(Timeout::Error)
111
+ end
112
+
113
+
114
+
115
+ end
116
+
117
+ end
118
+
119
+
120
+ end
data/wit_ruby.gemspec ADDED
@@ -0,0 +1,35 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'wit_ruby/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "wit_ruby"
8
+ spec.version = Wit::VERSION
9
+ spec.authors = ["Gavin Ching"]
10
+ spec.email = ["gavinchingy@gmail.com"]
11
+ spec.description = %q{Provides a Ruby interface with the Wit.ai API.}
12
+ spec.summary = %q{Provides a Ruby interface with the Wit.ai API.}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.required_ruby_version = ">= 1.8.7"
22
+ spec.add_development_dependency "bundler", "~> 1.3"
23
+ spec.add_dependency('multi_json', '>= 1.3.0')
24
+ spec.add_development_dependency "rake"
25
+ spec.add_development_dependency "rspec"
26
+ spec.add_development_dependency "rspec-nc"
27
+ spec.add_development_dependency "guard"
28
+ spec.add_development_dependency "guard-rspec"
29
+ spec.add_development_dependency "pry"
30
+ spec.add_development_dependency "pry-remote"
31
+ spec.add_development_dependency "pry-nav"
32
+ spec.add_development_dependency "coveralls"
33
+ spec.add_development_dependency "webmock"
34
+ spec.add_development_dependency "vcr"
35
+ end