desmos 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,64 @@
1
+ module Desmos
2
+ module Utils
3
+
4
+ # Taken from Rack::Utils, 1.2.1 to remove Rack dependency.
5
+ def escape(s)
6
+ s.to_s.gsub(/([^ a-zA-Z0-9_.-]+)/u) {
7
+ '%'+$1.unpack('H2'*bytesize($1)).join('%').upcase
8
+ }.tr(' ', '+')
9
+ end
10
+ module_function :escape
11
+
12
+ # Params are NOT escaped.
13
+ def traverse_params_hash(hash, result = nil, current_key = nil)
14
+ result ||= { :files => [], :params => [] }
15
+
16
+ hash.keys.sort { |a, b| a.to_s <=> b.to_s }.collect do |key|
17
+ new_key = (current_key ? "#{current_key}[#{key}]" : key).to_s
18
+ case hash[key]
19
+ when Hash
20
+ traverse_params_hash(hash[key], result, new_key)
21
+ when Array
22
+ array_key = "#{new_key}[]"
23
+ hash[key].each do |v|
24
+ result[:params] << [array_key, v.to_s]
25
+ end
26
+ when File
27
+ filename = File.basename(hash[key].path)
28
+ types = MIME::Types.type_for(filename)
29
+ result[:files] << [
30
+ new_key,
31
+ filename,
32
+ types.empty? ? 'application/octet-stream' : types[0].to_s,
33
+ File.expand_path(hash[key].path)
34
+ ]
35
+ else
36
+ result[:params] << [new_key, hash[key].to_s]
37
+ end
38
+ end
39
+ result
40
+ end
41
+ module_function :traverse_params_hash
42
+
43
+ def traversal_to_param_string(traversal, escape = true)
44
+ traversal[:params].collect { |param|
45
+ "#{Desmos::Utils.escape(param[0])}=#{Desmos::Utils.escape(param[1])}"
46
+ }.join('&')
47
+ end
48
+ module_function :traversal_to_param_string
49
+
50
+ # Return the bytesize of String; uses String#size under Ruby 1.8 and
51
+ # String#bytesize under 1.9.
52
+ if ''.respond_to?(:bytesize)
53
+ def bytesize(string)
54
+ string.bytesize
55
+ end
56
+ else
57
+ def bytesize(string)
58
+ string.size
59
+ end
60
+ end
61
+ module_function :bytesize
62
+
63
+ end
64
+ end
@@ -0,0 +1,96 @@
1
+ module Desmos
2
+ class Whiteboard
3
+ include RequestSupport
4
+ attr_accessor :hash, :title, :tutor, :students
5
+
6
+ def self.find(hash)
7
+ new(:hash => hash).get
8
+ end
9
+
10
+ def self.create(options = {})
11
+ new(options).save
12
+ end
13
+
14
+ def initialize(options = {})
15
+ @hash = options[:hash] # optional: The API will generate this if not provided. Must be unique if provided.
16
+ @title = options[:title] # optional
17
+
18
+ # optional: Should be a Desmos::Tutor object
19
+ if options[:tutor] && !(Tutor === options[:tutor])
20
+ raise ArgumentError, ':tutor option must be either of type Desmos::Tutor or NilClass'
21
+ end
22
+ @tutor = options[:tutor]
23
+
24
+ # optional: Should be an Array of Desmos::Student objects
25
+ if options[:students] && (!options[:students].respond_to?(:all?) || !options[:students].all? { |option| Desmos::Student === option })
26
+ raise ArgumentError, ':students option must be either an Array containing object of type Desmos::Student or NilClass'
27
+ end
28
+ @students = options[:students] || []
29
+ end
30
+
31
+ def save
32
+ parsed_response = request!(:whiteboard, :create, request_options)
33
+ if parsed_response.fetch(:success) == 'false'
34
+ raise RequestError, parsed_response[:error_message] unless parsed_response[:error_message] == 'whiteboard already exists'
35
+ else
36
+ self.hash = parsed_response.fetch(:hash)
37
+ end
38
+ add_tutor
39
+ add_students
40
+ self
41
+ end
42
+
43
+ def add_tutor
44
+ if tutor
45
+ parsed_response = request!(:whiteboard, :add_user, tutor.request_options.merge(:whiteboard_hash => hash))
46
+ end
47
+ end
48
+
49
+ def add_students
50
+ unless students.empty?
51
+ students.each do |student|
52
+ add_student(student)
53
+ end
54
+ end
55
+ end
56
+
57
+ def add_student(student)
58
+ parsed_response = request!(:whiteboard, :add_user, student.request_options.merge(:whiteboard_hash => hash))
59
+ end
60
+
61
+ def get
62
+ parsed_response = request!(:whiteboard, :read, :whiteboard_hash => hash)
63
+ if parsed_response[:success] == 'false'
64
+ case parsed_response[:error_message]
65
+ when 'Whiteboard not found'
66
+ raise WhiteboardNotFound, "Whiteboard with HASH=#{hash} could not be found"
67
+ else
68
+ raise RequestError, parsed_response[:error_message]
69
+ end
70
+ else
71
+ build_from_hash(parsed_response)
72
+ end
73
+ end
74
+
75
+ def request_options
76
+ options = {}
77
+ options.merge!(:hash => hash) if hash
78
+ options.merge!(:title => title) if title
79
+ if tutor
80
+ options.merge!(:tutor_name => tutor.name) if tutor.name
81
+ options.merge!(:tutor_id => tutor.id) if tutor.id
82
+ options.merge!(:tutor_hash => tutor.hash) if tutor.hash
83
+ end
84
+ options
85
+ end
86
+
87
+ def build_from_hash(options)
88
+ self.hash = options[:hash]
89
+ self.title = options[:title]
90
+ self.tutor = Tutor.build_from_hash(options[:tutor])
91
+ self.students = options[:students].collect { |student_attributes| Student.new(student_attributes) }
92
+ self
93
+ end
94
+
95
+ end
96
+ end
@@ -0,0 +1,105 @@
1
+ require 'spec_helper'
2
+
3
+ describe Desmos::Configuration, '.domain' do
4
+
5
+ it 'has a domain attribute, that when set will return the domain' do
6
+ Desmos::Configuration.should respond_to(:domain)
7
+ Desmos::Configuration.domain = 'https://example.com'
8
+ Desmos::Configuration.domain.should eql('https://example.com')
9
+ end
10
+
11
+ it 'raises a ConfigurationError if domain is called without having been set' do
12
+ Desmos::Configuration.domain = nil
13
+ lambda { Desmos::Configuration.domain }.should raise_error(Desmos::ConfigurationError, 'Desmos::Configuration.domain is a required configuration value.')
14
+ end
15
+
16
+ it 'adds https:// scheme if none is provided' do
17
+ Desmos::Configuration.domain = 'something.com'
18
+ Desmos::Configuration.domain.should eql('https://something.com')
19
+ end
20
+
21
+ it 'converts a regular http:// scheme to https:// if needed' do
22
+ Desmos::Configuration.domain = 'http://something.com'
23
+ Desmos::Configuration.domain.should eql('https://something.com')
24
+ end
25
+
26
+ end
27
+
28
+ describe Desmos::Configuration, '.version' do
29
+
30
+ it 'has a version attribute, that when set will return the version' do
31
+ Desmos::Configuration.should respond_to(:version)
32
+ Desmos::Configuration.version = 'api_v1'
33
+ Desmos::Configuration.version.should eql('api_v1')
34
+ end
35
+
36
+ it 'raises a ConfigurationError if version is called without having been set' do
37
+ Desmos::Configuration.version = nil
38
+ lambda { Desmos::Configuration.version }.should raise_error(Desmos::ConfigurationError, 'Desmos::Configuration.version is a required configuration value.')
39
+ end
40
+
41
+ it "prepends the version with 'api_v' if that part of the string does not exist" do
42
+ Desmos::Configuration.version = 1
43
+ Desmos::Configuration.version.should eql('api_v1')
44
+ end
45
+
46
+ it "prepends the version with 'api_v' if that part of the string does not exist" do
47
+ Desmos::Configuration.version = '1'
48
+ Desmos::Configuration.version.should eql('api_v1')
49
+ end
50
+
51
+ it "parses out a number if there is one to use as the version" do
52
+ Desmos::Configuration.version = 'this really 4 should not work'
53
+ Desmos::Configuration.version.should eql('api_v4')
54
+ end
55
+
56
+ end
57
+
58
+ describe Desmos::Configuration, '.key' do
59
+
60
+ it 'has a key attributes, that when set will return the key' do
61
+ Desmos::Configuration.should respond_to(:key)
62
+ Desmos::Configuration.key = '133'
63
+ Desmos::Configuration.key.should eql('133')
64
+ end
65
+
66
+ it 'raises a ConfigurationError if key is called without having been set' do
67
+ Desmos::Configuration.key = nil
68
+ lambda { Desmos::Configuration.key }.should raise_error(Desmos::ConfigurationError, 'Desmos::Configuration.key is a required configuration value.')
69
+ end
70
+
71
+ it 'converts whatever is passed in into a String' do
72
+ Desmos::Configuration.key = 133
73
+ Desmos::Configuration.key.should eql('133')
74
+
75
+ Desmos::Configuration.key = true
76
+ Desmos::Configuration.key.should eql('true')
77
+ end
78
+
79
+ end
80
+
81
+ describe Desmos::Configuration, '.secret' do
82
+
83
+ it 'has a secret attribute, that when set will return the secret' do
84
+ Desmos::Configuration.should respond_to(:secret)
85
+ Desmos::Configuration.secret = 'abcde'
86
+ Desmos::Configuration.secret.should eql('abcde')
87
+ end
88
+
89
+ it 'raises a ConfigurationError is secret is called without having been set' do
90
+ Desmos::Configuration.secret = nil
91
+ lambda { Desmos::Configuration.secret }.should raise_error(Desmos::ConfigurationError, 'Desmos::Configuration.secret is a required configuration value.')
92
+ end
93
+
94
+ end
95
+
96
+ describe Desmos::Configuration, '.debug_mode' do
97
+
98
+ it 'has a debug_mode attriubute that defaults to false' do
99
+ Desmos::Configuration.should respond_to(:debug_mode)
100
+ Desmos::Configuration.debug_mode.should eql(false)
101
+ Desmos::Configuration.debug_mode = true
102
+ Desmos::Configuration.debug_mode.should eql(true)
103
+ end
104
+
105
+ end
@@ -0,0 +1,99 @@
1
+ require 'spec_helper'
2
+
3
+ describe Desmos::RequestSupport, '#request!' do
4
+
5
+ before(:each) do
6
+ class_instance = Class.new
7
+ class_instance.send(:include, Desmos::RequestSupport)
8
+ @instance = class_instance.new
9
+
10
+ stub_request(:get, /https\:\/\/api\.tutortrove\.com\/api_v1\/whiteboard\/create/).
11
+ to_return(:status => 200, :body => "{\"success\": \"true\", \"title\": \"Test Session\", \"hash\": \"abcde\"}")
12
+ end
13
+
14
+ it 'makes a request to the Desmos API with the given object, method, and options and returns a response parsed from JSON' do
15
+ response = @instance.request!(:whiteboard, :create, { :title => 'Test Session' })
16
+ response.should eql({
17
+ :success => 'true',
18
+ :hash => 'abcde',
19
+ :title => 'Test Session'
20
+ })
21
+ assert_requested :get, /https\:\/\/api\.tutortrove\.com\/api_v1\/whiteboard\/create/, :times => 1
22
+ end
23
+
24
+ end
25
+
26
+ describe Desmos::RequestSupport, '#make_request' do
27
+
28
+ before(:each) do
29
+ class_instance = Class.new
30
+ class_instance.send(:include, Desmos::RequestSupport)
31
+ @instance = class_instance.new
32
+
33
+ stub_request(:get, /https\:\/\/api\.tutortrove\.com\/api_v1\/whiteboard\/create/)
34
+ end
35
+
36
+ it 'makes a request to the Desmos API with the given object, method, and options and returns a response from Net::HTTP' do
37
+ response = @instance.make_request(:whiteboard, :create, { :title => 'Test Session' })
38
+ response.should be_instance_of(Net::HTTPOK)
39
+ assert_requested :get, /https\:\/\/api\.tutortrove\.com\/api_v1\/whiteboard\/create/, :times => 1
40
+ end
41
+
42
+ end
43
+
44
+ describe Desmos::RequestSupport, '#build_uri' do
45
+
46
+ before(:each) do
47
+ class_instance = Class.new
48
+ class_instance.send(:include, Desmos::RequestSupport)
49
+ @instance = class_instance.new
50
+ end
51
+
52
+ it 'builds a uri for the Desmos API from the given object, method, and options and returns the URI object' do
53
+ uri = @instance.build_uri(:whiteboard, :create, { :title => 'Test Session' })
54
+ uri.should be_instance_of(URI::HTTPS)
55
+ uri.path.should eql('/api_v1/whiteboard/create')
56
+ uri.query.should eql('title=Test+Session')
57
+ uri.host.should eql(Desmos::Configuration.domain.split('://')[1])
58
+ end
59
+
60
+ end
61
+
62
+ describe Desmos::RequestSupport, '#build_http' do
63
+
64
+ before(:each) do
65
+ class_instance = Class.new
66
+ class_instance.send(:include, Desmos::RequestSupport)
67
+ @instance = class_instance.new
68
+ end
69
+
70
+ it 'builds and returns a Net::HTTP instance setup for SSL' do
71
+ http = @instance.build_http(@instance.build_uri(:whiteboard, :create, { :title => 'Test Session' }))
72
+ http.should be_instance_of(Net::HTTP)
73
+ end
74
+
75
+ end
76
+
77
+ describe Desmos::RequestSupport, '#parse_response' do
78
+
79
+ before(:each) do
80
+ class_instance = Class.new
81
+ class_instance.send(:include, Desmos::RequestSupport)
82
+ @instance = class_instance.new
83
+
84
+ stub_request(:get, /https\:\/\/api\.tutortrove\.com\/api_v1\/whiteboard\/create/).
85
+ to_return(:status => 200, :body => "{\"success\": \"true\", \"title\": \"Test Session\", \"hash\": \"abcde\"}")
86
+ end
87
+
88
+ it 'parses the JSON response string into a Hash' do
89
+ response = @instance.make_request(:whiteboard, :create, { :title => 'Test Session', :hash => 'abcde' })
90
+ parsed_response = @instance.parse_response(response)
91
+ parsed_response.should be_instance_of(Hash)
92
+ parsed_response.should eql({
93
+ :success => 'true',
94
+ :title => 'Test Session',
95
+ :hash => 'abcde'
96
+ })
97
+ end
98
+
99
+ end
@@ -0,0 +1,38 @@
1
+ require 'spec_helper'
2
+
3
+ describe Desmos::Student, '.new' do
4
+
5
+ it 'sets the instance variables for the student' do
6
+ student = Desmos::Student.new(
7
+ :id => 1,
8
+ :hash => 'abcde',
9
+ :name => 'Test',
10
+ :last_name => 'Student',
11
+ :family_name => 'StudentName',
12
+ :skype => 'test_student',
13
+ :email => 'test_student@example.com'
14
+ )
15
+ student.id.should eql(1)
16
+ student.hash.should eql('abcde')
17
+ student.type.should eql('student')
18
+ student.name.should eql('Test')
19
+ end
20
+
21
+ it 'requires a name attribute' do
22
+ lambda { Desmos::Student.new(:id => 1) }.should raise_error(ArgumentError, ':name is a required attribute')
23
+ end
24
+
25
+ it 'requires an id attribute' do
26
+ lambda { Desmos::Student.new(:name => 'test') }.should raise_error(ArgumentError, ':id is a required attribute')
27
+ end
28
+
29
+ end
30
+
31
+ describe Desmos::Student, '.build_from_hash' do
32
+
33
+ it 'returns a Desmos::Student object' do
34
+ student = Desmos::Student.build_from_hash(:id => 1, :name => 'test')
35
+ student.should be_instance_of(Desmos::Student)
36
+ end
37
+
38
+ end
@@ -0,0 +1,38 @@
1
+ require 'spec_helper'
2
+
3
+ describe Desmos::Tutor, '.new' do
4
+
5
+ it 'sets the instance variables for the tutor' do
6
+ tutor = Desmos::Tutor.new(
7
+ :id => 1,
8
+ :hash => 'abcde',
9
+ :name => 'Test',
10
+ :last_name => 'Tutor',
11
+ :family_name => 'TutorName',
12
+ :skype => 'test_tutor',
13
+ :email => 'test_tutor@example.com'
14
+ )
15
+ tutor.id.should eql(1)
16
+ tutor.hash.should eql('abcde')
17
+ tutor.type.should eql('tutor')
18
+ tutor.name.should eql('Test')
19
+ end
20
+
21
+ it 'requires a name attribute' do
22
+ lambda { Desmos::Tutor.new(:id => 1) }.should raise_error(ArgumentError, ':name is a required attribute')
23
+ end
24
+
25
+ it 'requires an id attribute' do
26
+ lambda { Desmos::Tutor.new(:name => 'test') }.should raise_error(ArgumentError, ':id is a required attribute')
27
+ end
28
+
29
+ end
30
+
31
+ describe Desmos::Tutor, '.build_from_hash' do
32
+
33
+ it 'returns a Desmos::Tutor object' do
34
+ tutor = Desmos::Tutor.build_from_hash(:id => 1, :name => 'test')
35
+ tutor.should be_instance_of(Desmos::Tutor)
36
+ end
37
+
38
+ end
@@ -0,0 +1,38 @@
1
+ require 'spec_helper'
2
+
3
+ describe Desmos::User, '.new' do
4
+
5
+ it 'sets the instance variables for the tutor' do
6
+ user = Desmos::User.new(
7
+ :id => 1,
8
+ :hash => 'abcde',
9
+ :name => 'Test',
10
+ :last_name => 'User',
11
+ :family_name => 'UserName',
12
+ :skype => 'test_user',
13
+ :email => 'test_user@example.com'
14
+ )
15
+ user.id.should eql(1)
16
+ user.hash.should eql('abcde')
17
+ user.type.should eql('user')
18
+ user.name.should eql('Test')
19
+ end
20
+
21
+ it 'requires a name attribute' do
22
+ lambda { Desmos::User.new(:id => 1) }.should raise_error(ArgumentError, ':name is a required attribute')
23
+ end
24
+
25
+ it 'requires an id attribute' do
26
+ lambda { Desmos::User.new(:name => 'test') }.should raise_error(ArgumentError, ':id is a required attribute')
27
+ end
28
+
29
+ end
30
+
31
+ describe Desmos::User, '.build_from_hash' do
32
+
33
+ it 'returns a Desmos::User object' do
34
+ user = Desmos::User.build_from_hash(:id => 1, :name => 'test')
35
+ user.should be_instance_of(Desmos::User)
36
+ end
37
+
38
+ end