clever-ruby 0.3.1 → 0.4.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.
- checksums.yaml +7 -0
- data/.drone.yml +14 -0
- data/.rubocop.yml +4 -0
- data/LICENSE +190 -0
- data/README.md +37 -7
- data/Rakefile +12 -2
- data/clever-ruby.gemspec +17 -13
- data/lib/clever-ruby.rb +87 -61
- data/lib/clever-ruby/api_operations/list.rb +9 -4
- data/lib/clever-ruby/api_operations/page.rb +7 -4
- data/lib/clever-ruby/api_operations/pagelist.rb +6 -3
- data/lib/clever-ruby/api_resource.rb +31 -10
- data/lib/clever-ruby/clever_object.rb +34 -35
- data/lib/clever-ruby/configuration.rb +2 -1
- data/lib/clever-ruby/district.rb +4 -12
- data/lib/clever-ruby/errors/api_connection_error.rb +1 -1
- data/lib/clever-ruby/errors/api_error.rb +1 -1
- data/lib/clever-ruby/errors/authentication_error.rb +1 -1
- data/lib/clever-ruby/errors/clever_error.rb +4 -3
- data/lib/clever-ruby/errors/invalid_request_error.rb +4 -3
- data/lib/clever-ruby/event.rb +6 -5
- data/lib/clever-ruby/json.rb +2 -1
- data/lib/clever-ruby/school.rb +2 -0
- data/lib/clever-ruby/section.rb +2 -0
- data/lib/clever-ruby/student.rb +6 -3
- data/lib/clever-ruby/teacher.rb +2 -0
- data/lib/clever-ruby/util.rb +31 -32
- data/lib/clever-ruby/version.rb +2 -1
- data/test/data/vcr_cassettes/districts.yml +10 -16
- data/test/data/vcr_cassettes/districts_event_pages.yml +627 -62
- data/test/data/vcr_cassettes/districts_events.yml +243 -41
- data/test/data/vcr_cassettes/districts_school_pages.yml +93 -102
- data/test/data/vcr_cassettes/districts_schools.yml +85 -92
- data/test/data/vcr_cassettes/districts_section_pages.yml +3364 -314
- data/test/data/vcr_cassettes/districts_sections.yml +591 -266
- data/test/data/vcr_cassettes/districts_student_pages.yml +1701 -14694
- data/test/data/vcr_cassettes/districts_students.yml +209 -2960
- data/test/data/vcr_cassettes/districts_students_filtered.yml +39 -64
- data/test/data/vcr_cassettes/districts_teacher_pages.yml +455 -202
- data/test/data/vcr_cassettes/districts_teachers.yml +244 -163
- data/test/data/vcr_cassettes/error_handling.yml +36 -52
- data/test/data/vcr_cassettes/schools.yml +20 -29
- data/test/data/vcr_cassettes/schools_optional_attributes.yml +21 -30
- data/test/data/vcr_cassettes/sections.yml +1069 -114
- data/test/data/vcr_cassettes/students.yml +1095 -1296
- data/test/data/vcr_cassettes/teachers.yml +2341 -872
- data/test/integration/api_operations/list_test.rb +16 -15
- data/test/integration/district_test.rb +18 -17
- data/test/integration/error_handling_test.rb +8 -7
- data/test/test_helper.rb +2 -2
- data/test/unit/clever_test.rb +13 -13
- data/test/unit/configuration_test.rb +8 -11
- data/test/unit/event_test.rb +18 -21
- data/test/unit/optional_attributes_test.rb +21 -14
- metadata +99 -55
- data/.travis.yml +0 -9
@@ -1,15 +1,20 @@
|
|
1
1
|
module Clever
|
2
2
|
module APIOperations
|
3
|
+
# A list of API resource instances
|
3
4
|
module List
|
5
|
+
# Class methods for those that include List
|
4
6
|
module ClassMethods
|
5
|
-
def all(filters={})
|
6
|
-
|
7
|
-
|
7
|
+
def all(filters = {})
|
8
|
+
accum = []
|
9
|
+
Clever::APIOperations::PageList.new(url, filters).each do |page|
|
10
|
+
accum += page.all
|
11
|
+
end
|
12
|
+
accum
|
8
13
|
end
|
9
14
|
end
|
10
15
|
|
11
16
|
def self.included(base)
|
12
|
-
base.extend
|
17
|
+
base.extend ClassMethods
|
13
18
|
end
|
14
19
|
end
|
15
20
|
end
|
@@ -1,19 +1,22 @@
|
|
1
1
|
module Clever
|
2
2
|
module APIOperations
|
3
|
+
# Represents a page of data
|
3
4
|
class Page
|
4
5
|
attr_accessor :paging
|
5
|
-
|
6
|
+
|
7
|
+
def initialize(uri, filters = {})
|
6
8
|
@uri = uri
|
7
9
|
@filters = filters
|
8
10
|
|
9
|
-
response = Clever.request
|
10
|
-
@list = Util.convert_to_clever_object
|
11
|
+
response = Clever.request :get, uri, filters
|
12
|
+
@list = Util.convert_to_clever_object response[:data]
|
11
13
|
self.paging = response[:paging]
|
12
14
|
end
|
13
15
|
|
16
|
+
# rubocop:disable TrivialAccessors
|
14
17
|
def all
|
15
18
|
@list
|
16
19
|
end
|
17
20
|
end
|
18
21
|
end
|
19
|
-
end
|
22
|
+
end
|
@@ -1,7 +1,10 @@
|
|
1
1
|
module Clever
|
2
2
|
module APIOperations
|
3
|
+
# Handles paginated requests.
|
4
|
+
# TODO: use rel links
|
5
|
+
# TODO: build functionality elsewhere
|
3
6
|
class PageList
|
4
|
-
def initialize(uri, filters={})
|
7
|
+
def initialize(uri, filters = {})
|
5
8
|
@uri = uri
|
6
9
|
@filters = filters
|
7
10
|
end
|
@@ -10,7 +13,7 @@ module Clever
|
|
10
13
|
current = 0
|
11
14
|
total = 1
|
12
15
|
while current < total
|
13
|
-
page = Page.new
|
16
|
+
page = Page.new @uri, @filters.merge(page: current + 1)
|
14
17
|
|
15
18
|
yield page
|
16
19
|
|
@@ -20,4 +23,4 @@ module Clever
|
|
20
23
|
end
|
21
24
|
end
|
22
25
|
end
|
23
|
-
end
|
26
|
+
end
|
@@ -1,35 +1,56 @@
|
|
1
1
|
module Clever
|
2
|
+
# Superclass of API resources in the Clever API
|
2
3
|
class APIResource < CleverObject
|
3
4
|
def self.url
|
4
5
|
if self == APIResource
|
5
|
-
|
6
|
+
fail NotImplementedError, 'APIResource is an abstract class. You should perform actions '\
|
7
|
+
'on its subclasses (School, Student, etc.)'
|
6
8
|
end
|
7
|
-
shortname =
|
8
|
-
"v1.1/#{CGI.escape
|
9
|
+
shortname = name.split('::')[-1]
|
10
|
+
"v1.1/#{CGI.escape shortname.downcase}s"
|
9
11
|
end
|
10
12
|
|
11
13
|
def url
|
12
|
-
|
13
|
-
|
14
|
+
id = self['id']
|
15
|
+
unless id
|
16
|
+
fail InvalidRequestError.new(
|
17
|
+
"Could not determine which URL to request: #{self.class} instance has " \
|
18
|
+
"invalid ID: #{id.inspect}", 'id')
|
14
19
|
end
|
15
|
-
"#{self.class.url}/#{CGI.escape
|
20
|
+
"#{self.class.url}/#{CGI.escape id}"
|
16
21
|
end
|
17
22
|
|
18
23
|
def refresh
|
19
|
-
response = Clever.request
|
20
|
-
refresh_from
|
24
|
+
response = Clever.request :get, url
|
25
|
+
refresh_from response[:data]
|
21
26
|
self
|
22
27
|
end
|
23
28
|
|
24
29
|
def links
|
25
|
-
response = Clever.request
|
30
|
+
response = Clever.request :get, url
|
26
31
|
response[:links]
|
27
32
|
end
|
28
33
|
|
29
34
|
def self.retrieve(id)
|
30
|
-
instance =
|
35
|
+
instance = new id
|
31
36
|
instance.refresh
|
32
37
|
instance
|
33
38
|
end
|
39
|
+
|
40
|
+
def get_linked_resources(resource_type, filters = {})
|
41
|
+
Util.convert_to_clever_object Clever.request(:get, get_uri(resource_type), filters)[:data]
|
42
|
+
end
|
43
|
+
|
44
|
+
class << self; attr_reader :linked_resources; end
|
45
|
+
def initialize(id)
|
46
|
+
super id
|
47
|
+
|
48
|
+
resources = self.class.linked_resources || []
|
49
|
+
resources.each do |resource|
|
50
|
+
self.class.send :define_method, resource do |filters = {}|
|
51
|
+
get_linked_resources resource.to_s, filters
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
34
55
|
end
|
35
56
|
end
|
@@ -1,45 +1,46 @@
|
|
1
1
|
module Clever
|
2
|
+
# An instance of an APIResource's contents
|
2
3
|
class CleverObject
|
3
4
|
include Enumerable
|
4
5
|
|
5
|
-
|
6
|
+
# TODO: fix this
|
7
|
+
# rubocop:disable ClassVars
|
8
|
+
@@permanent_attributes = Set.new []
|
6
9
|
|
7
10
|
# The default :id method is deprecated and isn't useful to us
|
8
|
-
if method_defined?
|
9
|
-
undef :id
|
10
|
-
end
|
11
|
+
undef :id if method_defined? :id
|
11
12
|
|
12
|
-
def initialize(id=nil)
|
13
|
+
def initialize(id = nil)
|
13
14
|
@values = {}
|
14
15
|
@values[:id] = id if id
|
15
16
|
end
|
16
17
|
|
17
18
|
def self.construct_from(values)
|
18
|
-
obj =
|
19
|
-
obj.refresh_from
|
19
|
+
obj = new values[:id]
|
20
|
+
obj.refresh_from values
|
20
21
|
obj
|
21
22
|
end
|
22
23
|
|
23
|
-
def to_s
|
24
|
-
Clever::JSON.dump
|
24
|
+
def to_s
|
25
|
+
Clever::JSON.dump @values, pretty: true
|
25
26
|
end
|
26
27
|
|
27
|
-
def inspect
|
28
|
-
id_string = (
|
29
|
-
"#<#{self.class}:0x#{
|
28
|
+
def inspect
|
29
|
+
id_string = (respond_to?(:id) && !id.nil?) ? " id=#{id}" : ''
|
30
|
+
"#<#{self.class}:0x#{object_id.to_s(16)}#{id_string}> JSON: " +
|
31
|
+
Clever::JSON.dump(@values, pretty: true)
|
30
32
|
end
|
31
33
|
|
32
|
-
def refresh_from(values, partial=false)
|
33
|
-
|
34
|
+
def refresh_from(values, partial = false)
|
34
35
|
removed = partial ? Set.new : Set.new(@values.keys - values.keys)
|
35
36
|
added = Set.new(values.keys - @values.keys)
|
36
37
|
|
37
38
|
instance_eval do
|
38
|
-
remove_accessors
|
39
|
-
add_accessors
|
39
|
+
remove_accessors removed
|
40
|
+
add_accessors added
|
40
41
|
end
|
41
42
|
removed.each do |k|
|
42
|
-
@values.delete
|
43
|
+
@values.delete k
|
43
44
|
end
|
44
45
|
values.each do |k, v|
|
45
46
|
# Stripe apparently allows you to have nested object types (e.g.
|
@@ -50,12 +51,12 @@ module Clever
|
|
50
51
|
end
|
51
52
|
|
52
53
|
def [](k)
|
53
|
-
k = k.to_sym if k.
|
54
|
+
k = k.to_sym if k.is_a? String
|
54
55
|
@values[k]
|
55
56
|
end
|
56
57
|
|
57
58
|
def []=(k, v)
|
58
|
-
send
|
59
|
+
send :"#{k}=", v
|
59
60
|
end
|
60
61
|
|
61
62
|
def keys
|
@@ -66,8 +67,8 @@ module Clever
|
|
66
67
|
@values.values
|
67
68
|
end
|
68
69
|
|
69
|
-
def to_json
|
70
|
-
Clever::JSON.dump
|
70
|
+
def to_json
|
71
|
+
Clever::JSON.dump @values
|
71
72
|
end
|
72
73
|
|
73
74
|
def as_json(*a)
|
@@ -82,10 +83,8 @@ module Clever
|
|
82
83
|
@values.each(&blk)
|
83
84
|
end
|
84
85
|
|
85
|
-
def ==(
|
86
|
-
if other.respond_to?
|
87
|
-
self.values == other.values
|
88
|
-
end
|
86
|
+
def ==(other)
|
87
|
+
values == other.values if other.respond_to? :values
|
89
88
|
end
|
90
89
|
|
91
90
|
protected
|
@@ -97,10 +96,10 @@ module Clever
|
|
97
96
|
def remove_accessors(keys)
|
98
97
|
metaclass.instance_eval do
|
99
98
|
keys.each do |k|
|
100
|
-
next if @@permanent_attributes.include?
|
99
|
+
next if @@permanent_attributes.include? k
|
101
100
|
k_eq = :"#{k}="
|
102
|
-
remove_method
|
103
|
-
remove_method
|
101
|
+
remove_method k if method_defined? k
|
102
|
+
remove_method k_eq if method_defined? k_eq
|
104
103
|
end
|
105
104
|
end
|
106
105
|
end
|
@@ -108,23 +107,23 @@ module Clever
|
|
108
107
|
def add_accessors(keys)
|
109
108
|
metaclass.instance_eval do
|
110
109
|
keys.each do |k|
|
111
|
-
next if @@permanent_attributes.include?
|
110
|
+
next if @@permanent_attributes.include? k
|
112
111
|
k_eq = :"#{k}="
|
113
112
|
define_method(k) { @values[k] }
|
114
|
-
define_method(k_eq)
|
115
|
-
@values[k] = v
|
116
|
-
end
|
113
|
+
define_method(k_eq) { |v| @values[k] = v }
|
117
114
|
end
|
118
115
|
end
|
119
116
|
end
|
120
117
|
|
121
118
|
def optional_attributes
|
122
|
-
|
119
|
+
fail NotImplementedError 'Please define #optional_attributes as a list of the '\
|
120
|
+
'attributes on this resource that may not be present and thus should return nil' \
|
121
|
+
'instead of raising a NoMethodError.'
|
123
122
|
end
|
124
123
|
|
125
124
|
def method_missing(name, *args)
|
126
|
-
return @values[name] if @values.
|
127
|
-
return nil if optional_attributes.include?
|
125
|
+
return @values[name] if @values.key? name
|
126
|
+
return nil if optional_attributes.include? name
|
128
127
|
super
|
129
128
|
end
|
130
129
|
end
|
data/lib/clever-ruby/district.rb
CHANGED
@@ -1,33 +1,25 @@
|
|
1
1
|
module Clever
|
2
|
+
# District resource
|
2
3
|
class District < APIResource
|
3
4
|
include Clever::APIOperations::List
|
5
|
+
@linked_resources = [:schools, :teachers, :sections, :students, :events]
|
4
6
|
|
5
7
|
def optional_attributes
|
6
8
|
# All of a district's attributes are required.
|
7
9
|
[]
|
8
10
|
end
|
9
11
|
|
10
|
-
[:schools, :teachers, :sections, :students, :events].each do |name|
|
11
|
-
define_method(name) do |filters = {}|
|
12
|
-
get_linked_resources name.to_s, filters
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
12
|
[:school_pages, :teacher_pages, :section_pages, :student_pages, :event_pages].each do |name|
|
17
13
|
define_method(name) do |filters = {}|
|
18
|
-
Clever::APIOperations::PageList.new
|
14
|
+
Clever::APIOperations::PageList.new get_uri(name.to_s.gsub('_page', '')), filters
|
19
15
|
end
|
20
16
|
end
|
21
17
|
|
22
18
|
private
|
23
19
|
|
24
|
-
def get_linked_resources(resource_type, filters={})
|
25
|
-
Util.convert_to_clever_object(Clever.request(:get, get_uri(resource_type), filters)[:data])
|
26
|
-
end
|
27
|
-
|
28
20
|
def get_uri(resource_type)
|
29
21
|
refresh
|
30
|
-
links.
|
22
|
+
links.find { |link| link[:rel] == resource_type }[:uri]
|
31
23
|
end
|
32
24
|
end
|
33
25
|
end
|
@@ -1,11 +1,12 @@
|
|
1
1
|
module Clever
|
2
|
+
# Represents an error outputted bythe Clever API
|
2
3
|
class CleverError < StandardError
|
3
4
|
attr_reader :message
|
4
5
|
attr_reader :http_status
|
5
6
|
attr_reader :http_body
|
6
7
|
attr_reader :json_body
|
7
8
|
|
8
|
-
def initialize(message=nil, http_status=nil, http_body=nil, json_body=nil)
|
9
|
+
def initialize(message = nil, http_status = nil, http_body = nil, json_body = nil)
|
9
10
|
@message = message
|
10
11
|
@http_status = http_status
|
11
12
|
@http_body = http_body
|
@@ -13,8 +14,8 @@ module Clever
|
|
13
14
|
end
|
14
15
|
|
15
16
|
def to_s
|
16
|
-
status_string = @http_status.nil? ?
|
17
|
+
status_string = @http_status.nil? ? '' : "(Status #{@http_status}) "
|
17
18
|
"#{status_string}#{@message}"
|
18
19
|
end
|
19
20
|
end
|
20
|
-
end
|
21
|
+
end
|
@@ -1,10 +1,11 @@
|
|
1
1
|
module Clever
|
2
|
+
# An invalid request to the Clever API
|
2
3
|
class InvalidRequestError < CleverError
|
3
4
|
attr_accessor :param
|
4
5
|
|
5
|
-
def initialize(message, param, http_status=nil, http_body=nil, json_body=nil)
|
6
|
-
super
|
6
|
+
def initialize(message, param, http_status = nil, http_body = nil, json_body = nil)
|
7
|
+
super message, http_status, http_body, json_body
|
7
8
|
@param = param
|
8
9
|
end
|
9
10
|
end
|
10
|
-
end
|
11
|
+
end
|
data/lib/clever-ruby/event.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
module Clever
|
2
|
+
# Event resource
|
2
3
|
class Event < APIResource
|
3
4
|
include Clever::APIOperations::List
|
4
5
|
|
@@ -7,9 +8,9 @@ module Clever
|
|
7
8
|
end
|
8
9
|
|
9
10
|
def object
|
10
|
-
klass = Util.types_to_clever_class
|
11
|
+
klass = Util.types_to_clever_class type_pieces[0]
|
11
12
|
klass ||= CleverObject
|
12
|
-
klass.construct_from
|
13
|
+
klass.construct_from data[:object]
|
13
14
|
end
|
14
15
|
|
15
16
|
def previous_attributes
|
@@ -19,15 +20,15 @@ module Clever
|
|
19
20
|
def action
|
20
21
|
type_pieces[1]
|
21
22
|
end
|
22
|
-
|
23
|
+
|
23
24
|
def self.url
|
24
|
-
|
25
|
+
'v1.1/events'
|
25
26
|
end
|
26
27
|
|
27
28
|
private
|
28
29
|
|
29
30
|
def type_pieces
|
30
|
-
type.split
|
31
|
+
type.split '.'
|
31
32
|
end
|
32
33
|
end
|
33
34
|
end
|