engrade 1.0.0
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 +19 -0
- data/.rvmrc +1 -0
- data/Gemfile +4 -0
- data/Guardfile +7 -0
- data/LICENSE.txt +22 -0
- data/README.md +29 -0
- data/Rakefile +9 -0
- data/config/environment.rb.template +4 -0
- data/engrade.gemspec +30 -0
- data/lib/engrade.rb +141 -0
- data/lib/engrade/browser.rb +28 -0
- data/lib/engrade/exceptions.rb +11 -0
- data/lib/engrade/return_types.rb +8 -0
- data/lib/engrade/version.rb +3 -0
- data/spec/engrade_spec.rb +359 -0
- data/spec/factories/assignment_factory.rb +10 -0
- data/spec/factories/classroom_factory.rb +13 -0
- data/spec/factories/response_factory.rb +96 -0
- data/spec/integration_spec.rb +22 -0
- data/spec/spec_helper.rb +26 -0
- metadata +237 -0
data/.gitignore
ADDED
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm use default@engrade
|
data/Gemfile
ADDED
data/Guardfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 TODO: Write your name
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# Engrade::Ruby
|
2
|
+
|
3
|
+
TODO: Write a gem description
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'engrade-ruby'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install engrade-ruby
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
TODO: Write usage instructions here
|
22
|
+
|
23
|
+
## Contributing
|
24
|
+
|
25
|
+
1. Fork it
|
26
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
27
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
28
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
29
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/engrade.gemspec
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'engrade/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "engrade"
|
8
|
+
gem.version = Engrade::VERSION
|
9
|
+
gem.authors = ["Zachary Thompson"]
|
10
|
+
gem.email = ["zgthompson@gmail.com"]
|
11
|
+
gem.description = %q{Basic ruby wrapper for the Engrade API}
|
12
|
+
gem.summary = %q{Utilize the Engrade API easily through Ruby}
|
13
|
+
gem.homepage = ""
|
14
|
+
|
15
|
+
gem.files = `git ls-files`.split($/)
|
16
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
17
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
|
+
gem.require_paths = ["lib"]
|
19
|
+
|
20
|
+
gem.add_runtime_dependency 'rest-client'
|
21
|
+
gem.add_runtime_dependency 'mechanize'
|
22
|
+
gem.add_development_dependency 'webmock'
|
23
|
+
gem.add_development_dependency 'vcr'
|
24
|
+
gem.add_development_dependency 'rake'
|
25
|
+
gem.add_development_dependency 'simplecov'
|
26
|
+
gem.add_development_dependency 'guard'
|
27
|
+
gem.add_development_dependency 'guard-rspec'
|
28
|
+
gem.add_development_dependency 'factory_girl'
|
29
|
+
gem.add_development_dependency 'rb-inotify'
|
30
|
+
end
|
data/lib/engrade.rb
ADDED
@@ -0,0 +1,141 @@
|
|
1
|
+
require 'rest_client'
|
2
|
+
require 'json'
|
3
|
+
require_relative 'engrade/version'
|
4
|
+
require_relative 'engrade/exceptions'
|
5
|
+
require_relative 'engrade/return_types'
|
6
|
+
require_relative 'engrade/browser'
|
7
|
+
|
8
|
+
module Engrade
|
9
|
+
|
10
|
+
###########################
|
11
|
+
# VARIABLES AND CONSTANTS #
|
12
|
+
###########################
|
13
|
+
#
|
14
|
+
@default_params = { :api => 'json' }
|
15
|
+
@browser = Engrade::Browser.new
|
16
|
+
|
17
|
+
def self.base_uri; 'https://api.engrade.com/api/' end
|
18
|
+
|
19
|
+
###########################
|
20
|
+
# GETTERS AND (RE)SETTERS #
|
21
|
+
###########################
|
22
|
+
|
23
|
+
# default_params are included in all post requests
|
24
|
+
def self.default_params; @default_params end
|
25
|
+
|
26
|
+
|
27
|
+
# browser is used to extend the engrade api to allow for the removal of
|
28
|
+
# assignment comments
|
29
|
+
def self.browser; @browser end
|
30
|
+
|
31
|
+
|
32
|
+
def self.reset!
|
33
|
+
@default_params = { :api => 'json' }
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
def self.set_ses(ses)
|
38
|
+
@default_params.store :ses, ses
|
39
|
+
end
|
40
|
+
|
41
|
+
######################
|
42
|
+
# CORE FUNCTIONALITY #
|
43
|
+
######################
|
44
|
+
|
45
|
+
# .post takes merges the default_params with query, a hash of input fields,
|
46
|
+
# and posts them to the api
|
47
|
+
# Example:
|
48
|
+
# Engrade.post({:apitask => 'login', :usr => 'myusername', :pwd => 'secret'})
|
49
|
+
def self.post(query={})
|
50
|
+
response = RestClient.post base_uri, query.merge(@default_params)
|
51
|
+
raise InvalidKey, 'Invalid apikey' if response.match("Invalid apikey")
|
52
|
+
raise MissingTask, 'No apitask specified' if response.match("No apitask specified")
|
53
|
+
raise InvalidTask, 'Invalid apitask' if response.match("Invalid apitask")
|
54
|
+
raise InvalidSession, 'Not logged in' if response.match("Not logged in")
|
55
|
+
response
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
def self.set_apikey(key)
|
60
|
+
@default_params.store :apikey, key
|
61
|
+
end
|
62
|
+
|
63
|
+
|
64
|
+
# .login posts a valid username and password to the api, and stores the
|
65
|
+
# responding session token in default_params
|
66
|
+
def self.login(u, p)
|
67
|
+
response = post :apitask => 'login', :usr => u, :pwd => p
|
68
|
+
raise InvalidLogin, 'Invalid username/password' if response.
|
69
|
+
match(/Invalid (username|password)/)
|
70
|
+
@browser.login u, p
|
71
|
+
@default_params.store :ses, JSON(response)['values']['ses']
|
72
|
+
end
|
73
|
+
|
74
|
+
|
75
|
+
# .classes returns an array of Classroom objects(data structure to represent
|
76
|
+
# classes). if called with a regexp, it will only return the classes whose
|
77
|
+
# name matches that regexp. if called with no argument, it will return all
|
78
|
+
# classes.
|
79
|
+
def self.classes(regexp=nil)
|
80
|
+
classes = teacher_classes
|
81
|
+
classes.select! { |cl| cl['name'].match regexp } if regexp
|
82
|
+
classes.map { |cl| Classroom.new(cl) }
|
83
|
+
end
|
84
|
+
|
85
|
+
|
86
|
+
# .assignments returns an array(of Assignment objects) of every assignment
|
87
|
+
# from the input classes. the classes parameter can be the class id, a
|
88
|
+
# Classroom object, an array of class ids, or an array of Classroom objects.
|
89
|
+
def self.assignments(classes)
|
90
|
+
assignments = []
|
91
|
+
clid_array(classes).each do |clid|
|
92
|
+
(Engrade.gradebook :clid => clid).
|
93
|
+
map { |assn| assignments << Assignment.new(assn) }
|
94
|
+
end
|
95
|
+
assignments
|
96
|
+
end
|
97
|
+
|
98
|
+
|
99
|
+
# .delete takes in an array of Assignment object, or a single Assignment
|
100
|
+
# object and deletes those assignments from the Engrade webpage. it also
|
101
|
+
# removes the comments from those assignments before deleting, because of
|
102
|
+
# a bug in the Engrade system where comments from deleted assignments
|
103
|
+
# reappear when assignment ids are recycled.
|
104
|
+
def self.delete(assignments)
|
105
|
+
assignments = array(assignments)
|
106
|
+
assignments.each do |assn|
|
107
|
+
@browser.remove_comments assn.clid, assn.assnid
|
108
|
+
post :apitask => 'assignment-edit', :clid => assn.clid, :assnid => assn.assnid, :delete => '1'
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
##################
|
113
|
+
# HELPER METHODS #
|
114
|
+
##################
|
115
|
+
|
116
|
+
def self.teacher_classes(query={})
|
117
|
+
JSON(post :apitask => 'teacher-classes')['classes']
|
118
|
+
end
|
119
|
+
|
120
|
+
|
121
|
+
def self.gradebook(query={})
|
122
|
+
response = post({ :apitask => 'gradebook' }.merge query)
|
123
|
+
raise InvalidClassId, 'Invalid class' if response.
|
124
|
+
match("You are not authorized to view this class")
|
125
|
+
JSON(response)['assignments']
|
126
|
+
end
|
127
|
+
|
128
|
+
|
129
|
+
def self.array(input)
|
130
|
+
input = input.instance_of?(Array) ? input : [input]
|
131
|
+
end
|
132
|
+
|
133
|
+
|
134
|
+
def self.clid_array(classes)
|
135
|
+
classes = array(classes)
|
136
|
+
classes.map! { |cl| cl.clid } if classes.first.instance_of? Classroom
|
137
|
+
classes
|
138
|
+
end
|
139
|
+
|
140
|
+
end
|
141
|
+
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'mechanize'
|
2
|
+
|
3
|
+
module Engrade
|
4
|
+
|
5
|
+
class Browser
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@agent
|
9
|
+
end
|
10
|
+
|
11
|
+
def login(u, p)
|
12
|
+
@agent = Mechanize.new
|
13
|
+
form = @agent.get('https://www.engrade.com/user/login.php').forms.first
|
14
|
+
form.usr = u
|
15
|
+
form.pwd = p
|
16
|
+
@agent.submit(form)
|
17
|
+
end
|
18
|
+
|
19
|
+
def remove_comments(clid, assnid)
|
20
|
+
page = @agent.get "https://www.engrade.com/class/assignments/edit.php?assnid=#{assnid}&clid=#{clid}"
|
21
|
+
scores = page.form.fields_with(:name => /^score/)
|
22
|
+
scores.each { |score| score.value = "" }
|
23
|
+
@agent.submit(page.form)
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module Engrade
|
2
|
+
|
3
|
+
class InvalidKey < StandardError; end
|
4
|
+
class InvalidLogin < StandardError; end
|
5
|
+
class InvalidSession < StandardError; end
|
6
|
+
class MissingTask < StandardError; end
|
7
|
+
class InvalidTask < StandardError; end
|
8
|
+
class InvalidClassId < StandardError; end
|
9
|
+
|
10
|
+
end
|
11
|
+
|
@@ -0,0 +1,359 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
|
3
|
+
describe Engrade do
|
4
|
+
|
5
|
+
after :each do
|
6
|
+
Engrade.reset!
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should have base_uri set to engrade api endpoint" do
|
10
|
+
Engrade.base_uri.should eql 'https://api.engrade.com/api/'
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "public method" do
|
14
|
+
|
15
|
+
describe ".default_params" do
|
16
|
+
|
17
|
+
it "should be a Hash" do
|
18
|
+
Engrade.default_params.should be_an_instance_of Hash
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should have :api set to json" do
|
22
|
+
Engrade.default_params[:api].should eql 'json'
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
describe ".set_apikey" do
|
28
|
+
|
29
|
+
it "should set :apikey in default_params" do
|
30
|
+
Engrade.set_apikey 'test'
|
31
|
+
Engrade.default_params[:apikey].should eql 'test'
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
describe ".set_ses" do
|
37
|
+
|
38
|
+
it "should set :ses in default_params" do
|
39
|
+
Engrade.set_ses 'test'
|
40
|
+
Engrade.default_params[:ses].should eql 'test'
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
describe ".reset!" do
|
46
|
+
|
47
|
+
it "should reset default_params to original value" do
|
48
|
+
orig = Engrade.default_params.dup
|
49
|
+
Engrade.set_apikey "12345"
|
50
|
+
Engrade.reset!
|
51
|
+
Engrade.default_params.should eql orig
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
describe ".post" do
|
57
|
+
|
58
|
+
before :each do
|
59
|
+
Engrade.set_apikey ENV['ENG_API']
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should call RestClient.post with query and default_params" do
|
63
|
+
response = build :login
|
64
|
+
RestClient.should_receive(:post).with(Engrade.base_uri, response[:payload]).
|
65
|
+
and_return response[:body]
|
66
|
+
Engrade.post response[:query]
|
67
|
+
end
|
68
|
+
|
69
|
+
context "with valid call" do
|
70
|
+
|
71
|
+
it "should return the result of RestClient.post" do
|
72
|
+
response = build :login
|
73
|
+
RestClient.stub(:post).and_return response[:body]
|
74
|
+
Engrade.post(response[:query]).should eql response[:body]
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
context "when not logged in" do
|
80
|
+
|
81
|
+
it "should raise an InvalidSession error" do
|
82
|
+
RestClient.stub(:post).and_return build(:bad_ses)[:body]
|
83
|
+
expect { Engrade.post :apitask => 'teacher-classes' }.
|
84
|
+
to raise_error Engrade::InvalidSession
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
|
89
|
+
context "with bad apikey" do
|
90
|
+
|
91
|
+
it "should raise an InvalidKey error" do
|
92
|
+
Engrade.set_apikey 'badapi'
|
93
|
+
RestClient.stub(:post).and_return build(:bad_api)[:body]
|
94
|
+
expect { Engrade.post }.to raise_error Engrade::InvalidKey
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
|
99
|
+
context "with no apitask specified" do
|
100
|
+
|
101
|
+
it "should raise a MissingTask error" do
|
102
|
+
RestClient.stub(:post).and_return build(:no_task)[:body]
|
103
|
+
expect { Engrade.post }.to raise_error Engrade::MissingTask
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
107
|
+
|
108
|
+
context "with invalid apitask specified" do
|
109
|
+
|
110
|
+
it "should raise an InvalidTask error" do
|
111
|
+
RestClient.stub(:post).and_return build(:bad_task)[:body]
|
112
|
+
expect { Engrade.post :apitask => 'badtask' }.
|
113
|
+
to raise_error Engrade::InvalidTask
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
119
|
+
|
120
|
+
describe ".login" do
|
121
|
+
|
122
|
+
before :each do
|
123
|
+
Engrade.browser.stub :login
|
124
|
+
end
|
125
|
+
|
126
|
+
it "should call .post with query Hash" do
|
127
|
+
response = build :login
|
128
|
+
Engrade.should_receive(:post).with(response[:query]).
|
129
|
+
and_return response[:body]
|
130
|
+
Engrade.login ENV['ENG_USER'], ENV['ENG_PASS']
|
131
|
+
end
|
132
|
+
|
133
|
+
context "with valid credentials" do
|
134
|
+
|
135
|
+
before :each do
|
136
|
+
@response = build(:login)
|
137
|
+
Engrade.stub(:post).and_return @response[:body]
|
138
|
+
end
|
139
|
+
|
140
|
+
it "should return the session id" do
|
141
|
+
Engrade.login(ENV['ENG_USER'], ENV['ENG_PASS']).
|
142
|
+
should eql @response[:json]['values']['ses']
|
143
|
+
end
|
144
|
+
|
145
|
+
it "should set :ses in the default params" do
|
146
|
+
ses = Engrade.login ENV['ENG_USER'], ENV['ENG_PASS']
|
147
|
+
Engrade.default_params[:ses].should eql ses
|
148
|
+
end
|
149
|
+
|
150
|
+
end
|
151
|
+
|
152
|
+
context "with invalid username" do
|
153
|
+
|
154
|
+
it "should raise InvalidLogin error" do
|
155
|
+
Engrade.stub(:post).and_return build(:login_baduser)[:body]
|
156
|
+
expect { Engrade.login 'baduser', 'anypass' }.to raise_error Engrade::InvalidLogin
|
157
|
+
end
|
158
|
+
|
159
|
+
end
|
160
|
+
|
161
|
+
context "with invalid password" do
|
162
|
+
|
163
|
+
it "should raise InvalidLogin error" do
|
164
|
+
Engrade.stub(:post).and_return build(:login_badpass)[:body]
|
165
|
+
expect { Engrade.login ENV['ENG_USER'], 'badpass' }.to raise_error Engrade::InvalidLogin
|
166
|
+
end
|
167
|
+
|
168
|
+
end
|
169
|
+
|
170
|
+
end
|
171
|
+
|
172
|
+
describe ".classes" do
|
173
|
+
|
174
|
+
before :each do
|
175
|
+
@classes = build(:teacher_classes)[:classes]
|
176
|
+
Engrade.stub(:teacher_classes).and_return @classes
|
177
|
+
end
|
178
|
+
|
179
|
+
|
180
|
+
it "should call .teacher_classes with the proper query" do
|
181
|
+
Engrade.should_receive(:teacher_classes).with(no_args).
|
182
|
+
and_return @classes
|
183
|
+
Engrade.classes
|
184
|
+
end
|
185
|
+
|
186
|
+
|
187
|
+
describe "return value" do
|
188
|
+
|
189
|
+
it "should be an Array" do
|
190
|
+
Engrade.classes.should be_an_instance_of Array
|
191
|
+
end
|
192
|
+
|
193
|
+
it "should contain Classroom objects" do
|
194
|
+
Engrade.classes.first.should be_an_instance_of Engrade::Classroom
|
195
|
+
end
|
196
|
+
|
197
|
+
it "should be filtered when given a string argument" do
|
198
|
+
Engrade.classes.size.should be > Engrade.classes("Sem1").size
|
199
|
+
end
|
200
|
+
|
201
|
+
it "should contain classes that match the string argument" do
|
202
|
+
Engrade.classes("Sem1").first.name.should match "Sem1"
|
203
|
+
end
|
204
|
+
|
205
|
+
end
|
206
|
+
|
207
|
+
end
|
208
|
+
|
209
|
+
describe ".assignments" do
|
210
|
+
|
211
|
+
before :each do
|
212
|
+
@response = build :gradebook
|
213
|
+
Engrade.stub(:gradebook).and_return @response[:assignments]
|
214
|
+
end
|
215
|
+
|
216
|
+
it "should take a class id as input" do
|
217
|
+
expect { Engrade.assignments((build :classroom).clid) }.to_not raise_error
|
218
|
+
end
|
219
|
+
|
220
|
+
it "should take a classroom object as input" do
|
221
|
+
expect { Engrade.assignments(build :classroom) }.to_not raise_error
|
222
|
+
end
|
223
|
+
|
224
|
+
it "should take an array of classroom objects as input" do
|
225
|
+
expect { Engrade.assignments [build(:classroom), build(:classroom)] }.
|
226
|
+
to_not raise_error
|
227
|
+
end
|
228
|
+
|
229
|
+
it "should take an array of clids as input" do
|
230
|
+
expect { Engrade.assignments [(build :classroom).clid, (build :classroom).clid] }.
|
231
|
+
to_not raise_error
|
232
|
+
end
|
233
|
+
|
234
|
+
it "should call .gradebook for each class from input array" do
|
235
|
+
classes = [build(:classroom), build(:classroom)]
|
236
|
+
Engrade.should_receive(:gradebook).exactly(2).times
|
237
|
+
Engrade.assignments classes
|
238
|
+
end
|
239
|
+
|
240
|
+
|
241
|
+
it "should call .gradebook with the appropriate query" do
|
242
|
+
Engrade.should_receive(:gradebook).with @response[:public_query]
|
243
|
+
Engrade.assignments build(:classroom)
|
244
|
+
end
|
245
|
+
|
246
|
+
|
247
|
+
describe "return value" do
|
248
|
+
|
249
|
+
it "should be an Array" do
|
250
|
+
Engrade.assignments(build :classroom).should be_an_instance_of Array
|
251
|
+
end
|
252
|
+
|
253
|
+
it "should contain Assignment objects" do
|
254
|
+
Engrade.assignments(build :classroom).first.
|
255
|
+
should be_an_instance_of Engrade::Assignment
|
256
|
+
end
|
257
|
+
|
258
|
+
it "should contain assigments from all input classes" do
|
259
|
+
Engrade.assignments(build :classroom).size.should be < Engrade.assignments([build(:classroom), build(:classroom)]).size
|
260
|
+
end
|
261
|
+
|
262
|
+
end
|
263
|
+
|
264
|
+
end
|
265
|
+
|
266
|
+
describe ".delete" do
|
267
|
+
|
268
|
+
before :each do
|
269
|
+
Engrade.set_ses ENV['ENG_SES']
|
270
|
+
Engrade.stub :post
|
271
|
+
Engrade.browser.stub :remove_comments
|
272
|
+
end
|
273
|
+
|
274
|
+
it "should accept an array of Assignments as input" do
|
275
|
+
assignments = [build(:assignment), build(:assignment)]
|
276
|
+
expect { Engrade.delete assignments }.to_not raise_error
|
277
|
+
end
|
278
|
+
|
279
|
+
it "should accept a single Assignment as input" do
|
280
|
+
assignment = build :assignment
|
281
|
+
expect { Engrade.delete assignment }.to_not raise_error
|
282
|
+
end
|
283
|
+
|
284
|
+
it "should remove comments of every assignment" do
|
285
|
+
assignments = [build(:assignment), build(:assignment)]
|
286
|
+
Engrade.browser.should_receive(:remove_comments).exactly(2).times
|
287
|
+
Engrade.delete assignments
|
288
|
+
end
|
289
|
+
|
290
|
+
it "should call .post with proper query" do
|
291
|
+
Engrade.should_receive(:post).with build(:delete)[:query]
|
292
|
+
Engrade.delete [build(:assignment)]
|
293
|
+
end
|
294
|
+
|
295
|
+
end
|
296
|
+
|
297
|
+
end
|
298
|
+
|
299
|
+
describe "helper method" do
|
300
|
+
|
301
|
+
|
302
|
+
describe ".teacher_classes" do
|
303
|
+
|
304
|
+
before :each do
|
305
|
+
Engrade.set_apikey ENV['ENG_API']
|
306
|
+
Engrade.set_ses ENV['ENG_SES']
|
307
|
+
@response = build :teacher_classes
|
308
|
+
Engrade.stub :classes
|
309
|
+
end
|
310
|
+
|
311
|
+
it "should call .post with the proper query" do
|
312
|
+
Engrade.should_receive(:post).with(@response[:helper_query]).
|
313
|
+
and_return @response[:body]
|
314
|
+
Engrade.teacher_classes
|
315
|
+
end
|
316
|
+
|
317
|
+
it "should return an array of classes" do
|
318
|
+
Engrade.stub(:post).and_return @response[:body]
|
319
|
+
Engrade.teacher_classes.should eql @response[:classes]
|
320
|
+
end
|
321
|
+
|
322
|
+
end
|
323
|
+
|
324
|
+
describe ".gradebook" do
|
325
|
+
|
326
|
+
before :each do
|
327
|
+
Engrade.set_apikey ENV['ENG_API']
|
328
|
+
Engrade.set_ses ENV['ENG_SES']
|
329
|
+
@response = build :gradebook
|
330
|
+
Engrade.stub :assignments
|
331
|
+
end
|
332
|
+
|
333
|
+
it "should call .post with appropriate query" do
|
334
|
+
Engrade.should_receive(:post).with(@response[:helper_query]).
|
335
|
+
and_return @response[:body]
|
336
|
+
Engrade.gradebook :clid => build(:classroom).clid
|
337
|
+
end
|
338
|
+
|
339
|
+
it "should return an array of assignments" do
|
340
|
+
Engrade.stub(:post).and_return @response[:body]
|
341
|
+
Engrade.gradebook(:clid => build(:classroom).clid).
|
342
|
+
should eql @response[:assignments]
|
343
|
+
end
|
344
|
+
|
345
|
+
context "with bad class id" do
|
346
|
+
|
347
|
+
it "should raise a InvalidClassId error" do
|
348
|
+
Engrade.stub(:post).and_return build(:bad_class)[:body]
|
349
|
+
expect { Engrade.gradebook(:clid => build(:bad_classroom).clid) }.
|
350
|
+
to raise_error Engrade::InvalidClassId
|
351
|
+
end
|
352
|
+
|
353
|
+
end
|
354
|
+
|
355
|
+
end
|
356
|
+
|
357
|
+
end
|
358
|
+
|
359
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'factory_girl'
|
2
|
+
|
3
|
+
FactoryGirl.define do
|
4
|
+
|
5
|
+
factory :login, class:Hash do
|
6
|
+
body "{\"fields\":\"usr pwd remember go\",\"success\":true,\"values\":{\"usr\":\"zgthompson\",\"pwd\":\"secretpass\",\"remember\":null,\"go\":null,\"ses\":\"9426016804785795792n8k42bbalb40m8e58j4n0faa98d03o0958kfmn98019pa\"},\"time\":1363650224}"
|
7
|
+
json { JSON(body) }
|
8
|
+
query { { :usr => ENV['ENG_USER'], :pwd => ENV['ENG_PASS'], :apitask => 'login' } }
|
9
|
+
payload { { :api => 'json', :apikey => ENV['ENG_API'] }.merge query }
|
10
|
+
|
11
|
+
initialize_with { attributes }
|
12
|
+
end
|
13
|
+
|
14
|
+
factory :login_baduser, class:Hash do
|
15
|
+
body "{\"fields\":\"usr pwd remember go\",\"success\":false,\"values\":{\"usr\":\"baduser\",\"pwd\":\"anypass\",\"remember\":null,\"go\":null},\"errors\":{\"usr\":\"Invalid username\"},\"time\":1363653753}"
|
16
|
+
json { JSON(body) }
|
17
|
+
query { { :usr => 'baduser', :pwd => 'anypass', :apitask => 'login' } }
|
18
|
+
payload { { :api => 'json', :apikey => ENV['ENG_API'] }.merge query }
|
19
|
+
|
20
|
+
initialize_with { attributes }
|
21
|
+
end
|
22
|
+
|
23
|
+
factory :login_badpass, class:Hash do
|
24
|
+
body "{\"fields\":\"usr pwd remember go\",\"success\":false,\"values\":{\"usr\":\"zgthompson\",\"pwd\":\"badpass\",\"remember\":null,\"go\":null},\"errors\":{\"pwd\":\"Invalid password\"},\"time\":1363654455}"
|
25
|
+
json { JSON(body) }
|
26
|
+
query { { :usr => 'zgthompson', :pwd => 'badpass', :apitask => 'login' } }
|
27
|
+
payload { { :api => 'json', :apikey => ENV['ENG_API'] }.merge query }
|
28
|
+
|
29
|
+
initialize_with { attributes }
|
30
|
+
end
|
31
|
+
|
32
|
+
factory :bad_api, class:Hash do
|
33
|
+
body "Invalid apikey, please contact Engrade to receive your API key.badapi"
|
34
|
+
query { {} }
|
35
|
+
payload { { :api => 'json', :apikey => 'badapi' } }
|
36
|
+
|
37
|
+
initialize_with { attributes }
|
38
|
+
end
|
39
|
+
|
40
|
+
factory :teacher_classes, class:Hash do
|
41
|
+
body "{\"success\":true,\"classes\":[{\"superid\":\"1000008059883\",\"subid\":\"101\",\"supertype\":\"teacher\",\"subtype\":\"class\",\"auth\":6,\"joined\":1361653042,\"role\":\"Teacher\",\"clid\":\"101\",\"created\":1361653042,\"folder\":3,\"syr\":\"2013-2014\",\"gp\":1,\"gscale\":9,\"weighted\":0,\"showper\":1,\"stusort\":1,\"assnsort\":1,\"round\":1,\"stuview\":1,\"stumail\":0,\"gradelevel\":7,\"subject\":5,\"bb\":0,\"teachmail\":1,\"priteach\":\"1000008059883\",\"name\":\"Biology\",\"code\":null,\"stucount\":6,\"average\":68.3,\"missing\":0,\"failing\":1,\"registered\":0,\"acount\":1,\"stdset\":0,\"updated\":1362535927},{\"superid\":\"1000008059883\",\"subid\":\"5000006291841\",\"supertype\":\"teacher\",\"subtype\":\"class\",\"auth\":6,\"joined\":1363580907,\"role\":\"Teacher\",\"clid\":\"5000006291841\",\"created\":1363580907,\"folder\":3,\"syr\":\"2013-2014\",\"gp\":1,\"gscale\":9,\"weighted\":0,\"showper\":1,\"stusort\":1,\"assnsort\":1,\"round\":1,\"stuview\":1,\"stumail\":0,\"gradelevel\":99,\"subject\":99,\"bb\":0,\"teachmail\":1,\"priteach\":\"1000008059883\",\"name\":\"Chemistry - Sem1\",\"code\":null,\"stucount\":2,\"average\":0,\"missing\":0,\"failing\":0,\"registered\":0,\"acount\":0,\"stdset\":0,\"updated\":1363580917},{\"superid\":\"1000008059883\",\"subid\":\"5000006291845\",\"supertype\":\"teacher\",\"subtype\":\"class\",\"auth\":6,\"joined\":1363580934,\"role\":\"Teacher\",\"clid\":\"5000006291845\",\"created\":1363580934,\"folder\":3,\"syr\":\"2013-2014\",\"gp\":1,\"gscale\":9,\"weighted\":0,\"showper\":1,\"stusort\":1,\"assnsort\":1,\"round\":1,\"stuview\":1,\"stumail\":0,\"gradelevel\":99,\"subject\":99,\"bb\":0,\"teachmail\":1,\"priteach\":\"1000008059883\",\"name\":\"Math - Sem2\",\"code\":null,\"stucount\":2,\"average\":0,\"missing\":0,\"failing\":0,\"registered\":0,\"acount\":0,\"stdset\":0,\"updated\":1363580941}],\"time\":1363655149}"
|
42
|
+
json { JSON(body) }
|
43
|
+
classes { json['classes'] }
|
44
|
+
helper_query { { :apitask => 'teacher-classes' } }
|
45
|
+
payload { { :api => 'json', :apikey => ENV['ENG_API'], :ses => ENV['ENG_SES'] }.merge helper_query }
|
46
|
+
|
47
|
+
initialize_with { attributes }
|
48
|
+
end
|
49
|
+
|
50
|
+
factory :bad_ses, class:Hash do
|
51
|
+
body "{\"success\":false,\"errors\":{\"system\":\"Not logged in\"},\"time\":1363655473}"
|
52
|
+
query { { :apitask => 'teacher-classes' } }
|
53
|
+
payload { { :api => 'json', :apikey => ENV['ENG_API'] }.merge query }
|
54
|
+
initialize_with { attributes }
|
55
|
+
end
|
56
|
+
|
57
|
+
factory :no_task, class:Hash do
|
58
|
+
body "No apitask specified"
|
59
|
+
query { {} }
|
60
|
+
payload { { :api => 'json', :apikey => ENV['ENG_API'] } }
|
61
|
+
initialize_with { attributes }
|
62
|
+
end
|
63
|
+
|
64
|
+
factory :bad_task, class:Hash do
|
65
|
+
body "Invalid apitask"
|
66
|
+
query { { :apitask => 'badtask' } }
|
67
|
+
payload { { :api => 'json', :apikey => ENV['ENG_API'] }.merge query }
|
68
|
+
initialize_with { attributes }
|
69
|
+
end
|
70
|
+
|
71
|
+
factory :gradebook, class:Hash do
|
72
|
+
body "{\"clid\":\"101\",\"created\":1361653042,\"folder\":3,\"syr\":\"2013-2014\",\"gp\":1,\"gscale\":9,\"weighted\":0,\"showper\":1,\"stusort\":1,\"assnsort\":1,\"round\":1,\"stuview\":1,\"stumail\":0,\"gradelevel\":7,\"subject\":5,\"bb\":0,\"teachmail\":1,\"priteach\":\"1000008059883\",\"name\":\"Biology\",\"code\":null,\"stucount\":6,\"average\":69.3,\"missing\":0,\"failing\":1,\"registered\":0,\"acount\":2,\"stdset\":0,\"updated\":1363837018,\"cgs\":[{\"num\":1,\"low\":90,\"grade\":\"A\"},{\"num\":2,\"low\":80,\"grade\":\"B\"},{\"num\":3,\"low\":70,\"grade\":\"C\"},{\"num\":4,\"low\":60,\"grade\":\"D\"},{\"num\":5,\"low\":0,\"grade\":\"F\"}],\"cat\":[{\"num\":1,\"name\":\"Assignments\",\"weight\":null,\"dls\":0}],\"assignments\":[{\"clid\":\"101\",\"assnid\":2,\"created\":1363837018,\"creator\":\"1000008059883\",\"type\":1,\"cat\":1,\"cal\":1,\"bb\":1,\"turnin\":0,\"lastreplier\":0,\"lastreply\":0,\"replies\":0,\"attachments\":0,\"due\":20130320,\"points\":2,\"title\":\"Quiz\",\"gb\":1,\"showstu\":1,\"rubric\":0,\"itemid\":null,\"name\":\"Zachary Thompson\",\"usr\":\"zgthompson\",\"pic\":0},{\"clid\":\"101\",\"assnid\":1,\"created\":1362534970,\"creator\":\"1000008059883\",\"type\":1,\"cat\":1,\"cal\":1,\"bb\":1,\"turnin\":0,\"lastreplier\":0,\"lastreply\":0,\"replies\":0,\"attachments\":0,\"due\":20130305,\"points\":10,\"title\":\"Pop Quiz\",\"gb\":1,\"showstu\":1,\"rubric\":0,\"itemid\":null,\"name\":\"Zachary Thompson\",\"usr\":\"zgthompson\",\"pic\":0}],\"students\":[{\"stuid\":95956,\"num\":1,\"first\":\"George\",\"last\":\"Washington\",\"grade\":\"F\",\"percent\":17,\"missing\":0,\"acount\":2,\"status\":3},{\"stuid\":17406,\"num\":2,\"first\":\"John\",\"last\":\"Adams\",\"grade\":\"B\",\"percent\":83,\"missing\":0,\"acount\":2,\"status\":3},{\"stuid\":12345,\"num\":3,\"first\":\"Bob\",\"last\":\"Barker\",\"grade\":\"B\",\"percent\":83,\"missing\":0,\"acount\":2,\"status\":3},{\"stuid\":13371,\"num\":4,\"first\":\"Mary\",\"last\":\"Popper\",\"grade\":\"B\",\"percent\":83,\"missing\":0,\"acount\":2,\"status\":3},{\"stuid\":12567,\"num\":5,\"first\":\"Mark\",\"last\":\"Zuck\",\"grade\":\"C\",\"percent\":75,\"missing\":0,\"acount\":2,\"status\":3},{\"stuid\":44245,\"num\":6,\"first\":\"Frank\",\"last\":\"Cull\",\"grade\":\"C\",\"percent\":75,\"missing\":0,\"acount\":2,\"status\":3}],\"scores\":[{\"assnid\":1,\"stuid\":12345,\"score\":8},{\"assnid\":1,\"stuid\":12567,\"score\":8},{\"assnid\":1,\"stuid\":13371,\"score\":8},{\"assnid\":1,\"stuid\":17406,\"score\":8},{\"assnid\":1,\"stuid\":44245,\"score\":8},{\"assnid\":1,\"stuid\":95956,\"score\":1},{\"assnid\":2,\"stuid\":12345,\"score\":2},{\"assnid\":2,\"stuid\":12567,\"score\":1},{\"assnid\":2,\"stuid\":13371,\"score\":2},{\"assnid\":2,\"stuid\":17406,\"score\":2},{\"assnid\":2,\"stuid\":44245,\"score\":1},{\"assnid\":2,\"stuid\":95956,\"score\":1}],\"success\":true,\"time\":1363840611}"
|
73
|
+
json { JSON(body) }
|
74
|
+
assignments { json['assignments'] }
|
75
|
+
public_query { { :clid => '101' } }
|
76
|
+
helper_query { { :apitask => 'gradebook', :clid => '101' } }
|
77
|
+
payload { { :api => 'json', :apikey => ENV['ENG_API'], :ses => ENV['ENG_SES'] }.merge helper_query }
|
78
|
+
initialize_with { attributes }
|
79
|
+
end
|
80
|
+
|
81
|
+
factory :bad_class, class:Hash do
|
82
|
+
body "{\"success\":false,\"errors\":{\"system\":\"You are not authorized to view this class\"},\"time\":1363843636}"
|
83
|
+
query { { :apitask => 'gradebook', :clid => '123456' } }
|
84
|
+
payload { { :api => 'json', :apikey => ENV['ENG_API'], :ses => ENV['ENG_SES'] }.merge query }
|
85
|
+
initialize_with { attributes }
|
86
|
+
end
|
87
|
+
|
88
|
+
factory :delete, class:Hash do
|
89
|
+
query { { :apitask => 'assignment-edit', :delete => '1',
|
90
|
+
:clid => '101', :assnid => '1' } }
|
91
|
+
|
92
|
+
initialize_with { attributes }
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
96
|
+
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
|
3
|
+
describe Engrade do
|
4
|
+
|
5
|
+
it "should allow me to delete all my assignments" do
|
6
|
+
Engrade.set_apikey ENV['ENG_API']
|
7
|
+
|
8
|
+
VCR.use_cassette('login') { Engrade.login ENV['ENG_USER'], ENV['ENG_PASS'] }
|
9
|
+
|
10
|
+
VCR.use_cassette('classes') { @classes = Engrade.classes }
|
11
|
+
|
12
|
+
VCR.use_cassette('assignments') { @assignments = Engrade.assignments @classes }
|
13
|
+
|
14
|
+
VCR.use_cassette('delete') { Engrade.delete @assignments }
|
15
|
+
|
16
|
+
VCR.use_cassette('result') { @result = Engrade.assignments @classes }
|
17
|
+
|
18
|
+
@result.should be_empty
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'simplecov'
|
2
|
+
SimpleCov.start
|
3
|
+
|
4
|
+
#we need the actual library file
|
5
|
+
require_relative '../lib/engrade'
|
6
|
+
require_relative '../config/environment'
|
7
|
+
require 'rspec'
|
8
|
+
require 'factory_girl'
|
9
|
+
require 'webmock/rspec'
|
10
|
+
require 'vcr'
|
11
|
+
|
12
|
+
FactoryGirl.find_definitions
|
13
|
+
|
14
|
+
#RSpec config
|
15
|
+
RSpec.configure do |spec|
|
16
|
+
spec.color_enabled = true
|
17
|
+
spec.tty = true
|
18
|
+
spec.include FactoryGirl::Syntax::Methods
|
19
|
+
end
|
20
|
+
|
21
|
+
#VCR config
|
22
|
+
VCR.configure do |c|
|
23
|
+
c.default_cassette_options = { :serialize_with => :json, :preserve_exact_body_bytes => true }
|
24
|
+
c.cassette_library_dir = 'spec/fixtures/engrade_cassettes'
|
25
|
+
c.hook_into :webmock
|
26
|
+
end
|
metadata
ADDED
@@ -0,0 +1,237 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: engrade
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Zachary Thompson
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-03-23 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rest-client
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: mechanize
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: webmock
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: vcr
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: rake
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: simplecov
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ! '>='
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
102
|
+
type: :development
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
- !ruby/object:Gem::Dependency
|
111
|
+
name: guard
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
113
|
+
none: false
|
114
|
+
requirements:
|
115
|
+
- - ! '>='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
none: false
|
122
|
+
requirements:
|
123
|
+
- - ! '>='
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
126
|
+
- !ruby/object:Gem::Dependency
|
127
|
+
name: guard-rspec
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
129
|
+
none: false
|
130
|
+
requirements:
|
131
|
+
- - ! '>='
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: '0'
|
134
|
+
type: :development
|
135
|
+
prerelease: false
|
136
|
+
version_requirements: !ruby/object:Gem::Requirement
|
137
|
+
none: false
|
138
|
+
requirements:
|
139
|
+
- - ! '>='
|
140
|
+
- !ruby/object:Gem::Version
|
141
|
+
version: '0'
|
142
|
+
- !ruby/object:Gem::Dependency
|
143
|
+
name: factory_girl
|
144
|
+
requirement: !ruby/object:Gem::Requirement
|
145
|
+
none: false
|
146
|
+
requirements:
|
147
|
+
- - ! '>='
|
148
|
+
- !ruby/object:Gem::Version
|
149
|
+
version: '0'
|
150
|
+
type: :development
|
151
|
+
prerelease: false
|
152
|
+
version_requirements: !ruby/object:Gem::Requirement
|
153
|
+
none: false
|
154
|
+
requirements:
|
155
|
+
- - ! '>='
|
156
|
+
- !ruby/object:Gem::Version
|
157
|
+
version: '0'
|
158
|
+
- !ruby/object:Gem::Dependency
|
159
|
+
name: rb-inotify
|
160
|
+
requirement: !ruby/object:Gem::Requirement
|
161
|
+
none: false
|
162
|
+
requirements:
|
163
|
+
- - ! '>='
|
164
|
+
- !ruby/object:Gem::Version
|
165
|
+
version: '0'
|
166
|
+
type: :development
|
167
|
+
prerelease: false
|
168
|
+
version_requirements: !ruby/object:Gem::Requirement
|
169
|
+
none: false
|
170
|
+
requirements:
|
171
|
+
- - ! '>='
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: '0'
|
174
|
+
description: Basic ruby wrapper for the Engrade API
|
175
|
+
email:
|
176
|
+
- zgthompson@gmail.com
|
177
|
+
executables: []
|
178
|
+
extensions: []
|
179
|
+
extra_rdoc_files: []
|
180
|
+
files:
|
181
|
+
- .gitignore
|
182
|
+
- .rvmrc
|
183
|
+
- Gemfile
|
184
|
+
- Guardfile
|
185
|
+
- LICENSE.txt
|
186
|
+
- README.md
|
187
|
+
- Rakefile
|
188
|
+
- config/environment.rb.template
|
189
|
+
- engrade.gemspec
|
190
|
+
- lib/engrade.rb
|
191
|
+
- lib/engrade/browser.rb
|
192
|
+
- lib/engrade/exceptions.rb
|
193
|
+
- lib/engrade/return_types.rb
|
194
|
+
- lib/engrade/version.rb
|
195
|
+
- spec/engrade_spec.rb
|
196
|
+
- spec/factories/assignment_factory.rb
|
197
|
+
- spec/factories/classroom_factory.rb
|
198
|
+
- spec/factories/response_factory.rb
|
199
|
+
- spec/integration_spec.rb
|
200
|
+
- spec/spec_helper.rb
|
201
|
+
homepage: ''
|
202
|
+
licenses: []
|
203
|
+
post_install_message:
|
204
|
+
rdoc_options: []
|
205
|
+
require_paths:
|
206
|
+
- lib
|
207
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
208
|
+
none: false
|
209
|
+
requirements:
|
210
|
+
- - ! '>='
|
211
|
+
- !ruby/object:Gem::Version
|
212
|
+
version: '0'
|
213
|
+
segments:
|
214
|
+
- 0
|
215
|
+
hash: -813889549
|
216
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
217
|
+
none: false
|
218
|
+
requirements:
|
219
|
+
- - ! '>='
|
220
|
+
- !ruby/object:Gem::Version
|
221
|
+
version: '0'
|
222
|
+
segments:
|
223
|
+
- 0
|
224
|
+
hash: -813889549
|
225
|
+
requirements: []
|
226
|
+
rubyforge_project:
|
227
|
+
rubygems_version: 1.8.25
|
228
|
+
signing_key:
|
229
|
+
specification_version: 3
|
230
|
+
summary: Utilize the Engrade API easily through Ruby
|
231
|
+
test_files:
|
232
|
+
- spec/engrade_spec.rb
|
233
|
+
- spec/factories/assignment_factory.rb
|
234
|
+
- spec/factories/classroom_factory.rb
|
235
|
+
- spec/factories/response_factory.rb
|
236
|
+
- spec/integration_spec.rb
|
237
|
+
- spec/spec_helper.rb
|