desmos 0.1.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.
@@ -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