arbor 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +0 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +34 -0
- data/MIT-LICENSE +20 -0
- data/README.md +48 -0
- data/Rakefile +0 -0
- data/arbor.gemspec +25 -0
- data/doctor.rb +87 -0
- data/lib/arbor/api.rb +42 -0
- data/lib/arbor/client.rb +37 -0
- data/lib/arbor/errors.rb +6 -0
- data/lib/arbor/filter.rb +19 -0
- data/lib/arbor/model/abstract.rb +69 -0
- data/lib/arbor/model/factory.rb +18 -0
- data/lib/arbor/model/no_op_serialiser.rb +9 -0
- data/lib/arbor/model/serialiser.rb +41 -0
- data/lib/arbor/query.rb +24 -0
- data/lib/arbor/serialiser_registry.rb +25 -0
- data/lib/arbor/utils.rb +29 -0
- data/lib/arbor/version.rb +3 -0
- data/lib/arbor.rb +149 -0
- metadata +122 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: ef88472480a661ea860c484d64e75f9884a2d171
|
4
|
+
data.tar.gz: 13885de2ac13295ab06788ece47856b6502cf1af
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a19f952f616fb95da9c16d36bf6a4b67d87bf1051096fedd5bf3c11714bdea34611f2277cab870c369276ecaa2f0a4d9aecd466c1eb8fa8b566ad9635c8adbcd
|
7
|
+
data.tar.gz: ec4b7ba338c051f2d8020bdc4b40e8fc705dc14a3d088aba5724f58fe3eff1e5063c1fa3cfe06fee7218020cf7ce6ad38471794bf2458f9deccc4f6f1a60e00d
|
data/.gitignore
ADDED
File without changes
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
arbor (0.0.1)
|
5
|
+
activesupport (>= 3.0.0)
|
6
|
+
httpi
|
7
|
+
|
8
|
+
GEM
|
9
|
+
remote: https://rubygems.org/
|
10
|
+
specs:
|
11
|
+
activesupport (4.1.5)
|
12
|
+
i18n (~> 0.6, >= 0.6.9)
|
13
|
+
json (~> 1.7, >= 1.7.7)
|
14
|
+
minitest (~> 5.1)
|
15
|
+
thread_safe (~> 0.1)
|
16
|
+
tzinfo (~> 1.1)
|
17
|
+
httpi (2.0.2)
|
18
|
+
rack
|
19
|
+
i18n (0.6.11)
|
20
|
+
json (1.8.1)
|
21
|
+
minitest (5.4.1)
|
22
|
+
rack (1.5.2)
|
23
|
+
rake (10.3.2)
|
24
|
+
thread_safe (0.3.4)
|
25
|
+
tzinfo (1.2.2)
|
26
|
+
thread_safe (~> 0.1)
|
27
|
+
|
28
|
+
PLATFORMS
|
29
|
+
ruby
|
30
|
+
|
31
|
+
DEPENDENCIES
|
32
|
+
arbor!
|
33
|
+
bundler (~> 1.3)
|
34
|
+
rake
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2014 Mike Campbell, Meritec Ltd
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
# Ruby Interface for Arbor API
|
2
|
+
|
3
|
+
A Ruby interface to [Arbor Education API](http://www.arbor-education.com/developers.html).
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
gem install arbor
|
8
|
+
|
9
|
+
## Usage
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
require 'arbor'
|
13
|
+
|
14
|
+
client = Arbor::Client.new("some-school", "user@email.net", "abc123")
|
15
|
+
|
16
|
+
# retrieve all students
|
17
|
+
students = client.query(:students)
|
18
|
+
|
19
|
+
# resources loaded by `query` (listings) are lazily loaded, and will
|
20
|
+
# generate another request for that specific resource when an attribute is
|
21
|
+
# requested which isn't already loaded
|
22
|
+
students.each do |s|
|
23
|
+
# extra requests to /rest-v2/students/<id> (s.href) occur here for each item
|
24
|
+
puts "#{s.person.legal_first_name} #{s.person.legal_last_name}"
|
25
|
+
end
|
26
|
+
|
27
|
+
# use `retrieve` to get a single resource
|
28
|
+
student = client.retrieve(:student, 1)
|
29
|
+
|
30
|
+
# by default, it serialises the API responses in to classes defined for
|
31
|
+
# each resource. you can set your own serialiser for a resource type:
|
32
|
+
Arbor.serialisers.register(:students, MyStudentSerialiser)
|
33
|
+
|
34
|
+
# and/or modify the default serialiser. serialiser classes must respond to
|
35
|
+
# `deserialise` and return a single resource
|
36
|
+
Arbor.serialisers.default_serialiser = MyDefaultSerialiser
|
37
|
+
```
|
38
|
+
|
39
|
+
## Still to do
|
40
|
+
|
41
|
+
- Write tests
|
42
|
+
- Support the other stuff like ordering, paging, changelog etc.
|
43
|
+
- Include an API mixin for the resource classes
|
44
|
+
- RDoc it up
|
45
|
+
|
46
|
+
## Licence
|
47
|
+
|
48
|
+
[MIT License](http://opensource.org/licenses/MIT)
|
data/Rakefile
ADDED
File without changes
|
data/arbor.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'arbor/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "arbor"
|
8
|
+
spec.version = Arbor::VERSION
|
9
|
+
spec.authors = ["Mike Campbell"]
|
10
|
+
spec.email = ["mike.campbell@meritec.co.uk"]
|
11
|
+
spec.description = %q{Interface for the Arbor Education REST API.}
|
12
|
+
spec.summary = %q{Interface for the Arbor Education REST API.}
|
13
|
+
spec.homepage = "http://github.com/meritec/arbor-rb"
|
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.add_dependency "activesupport", ">= 3.0.0"
|
22
|
+
spec.add_dependency "httpi", ">= 2.0.5"
|
23
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
24
|
+
spec.add_development_dependency "rake", "~> 0"
|
25
|
+
end
|
data/doctor.rb
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
# Usage: ruby doctor.rb [HOST=status.github.com[:PORT=443]]
|
2
|
+
require 'rbconfig'
|
3
|
+
require 'net/https'
|
4
|
+
|
5
|
+
if ARGV[0] =~ /^[^-]/
|
6
|
+
host, port = ARGV[0].split(':', 2)
|
7
|
+
else
|
8
|
+
host = 'status.github.com'
|
9
|
+
end
|
10
|
+
port ||= 443
|
11
|
+
|
12
|
+
ruby = File.join(RbConfig::CONFIG['bindir'], RbConfig::CONFIG['ruby_install_name'])
|
13
|
+
ruby_version = RUBY_VERSION
|
14
|
+
if patch = RbConfig::CONFIG['PATCHLEVEL']
|
15
|
+
ruby_version += "-p#{patch}"
|
16
|
+
end
|
17
|
+
puts "%s (%s)" % [ruby, ruby_version]
|
18
|
+
|
19
|
+
openssl_dir = OpenSSL::X509::DEFAULT_CERT_AREA
|
20
|
+
mac_openssl = '/System/Library/OpenSSL' == openssl_dir
|
21
|
+
puts "%s: %s" % [OpenSSL::OPENSSL_VERSION, openssl_dir]
|
22
|
+
[OpenSSL::X509::DEFAULT_CERT_DIR_ENV, OpenSSL::X509::DEFAULT_CERT_FILE_ENV].each do |key|
|
23
|
+
puts "%s=%s" % [key, ENV[key].to_s.inspect]
|
24
|
+
end
|
25
|
+
|
26
|
+
ca_file = ENV[OpenSSL::X509::DEFAULT_CERT_FILE_ENV] || OpenSSL::X509::DEFAULT_CERT_FILE
|
27
|
+
ca_path = (ENV[OpenSSL::X509::DEFAULT_CERT_DIR_ENV] || OpenSSL::X509::DEFAULT_CERT_DIR).chomp('/')
|
28
|
+
|
29
|
+
puts "\nHEAD https://#{host}:#{port}"
|
30
|
+
http = Net::HTTP.new(host, port)
|
31
|
+
http.use_ssl = true
|
32
|
+
|
33
|
+
# Explicitly setting cert_store like this is not needed in most cases but it
|
34
|
+
# seems necessary in edge cases such as when using `verify_callback` in some
|
35
|
+
# combination of Ruby + OpenSSL versions.
|
36
|
+
http.cert_store = OpenSSL::X509::Store.new
|
37
|
+
http.cert_store.set_default_paths
|
38
|
+
|
39
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
40
|
+
failed_cert = failed_cert_reason = nil
|
41
|
+
|
42
|
+
if mac_openssl
|
43
|
+
warn "warning: will not be able show failed certificate info on OS X's OpenSSL"
|
44
|
+
# This drives me absolutely nuts. It seems that on Rubies compiled against OS X's
|
45
|
+
# system OpenSSL, the mere fact of defining a `verify_callback` makes the
|
46
|
+
# cert verification fail for requests that would otherwise be successful.
|
47
|
+
else
|
48
|
+
http.verify_callback = lambda { |verify_ok, store_context|
|
49
|
+
if !verify_ok
|
50
|
+
failed_cert = store_context.current_cert
|
51
|
+
failed_cert_reason = "%d: %s" % [ store_context.error, store_context.error_string ]
|
52
|
+
end
|
53
|
+
verify_ok
|
54
|
+
}
|
55
|
+
end
|
56
|
+
|
57
|
+
user_agent = "net/http #{ruby_version}"
|
58
|
+
req = Net::HTTP::Head.new('/', 'user-agent' => user_agent)
|
59
|
+
|
60
|
+
begin
|
61
|
+
res = http.start { http.request(req) }
|
62
|
+
abort res.inspect if res.code.to_i >= 500
|
63
|
+
puts "OK"
|
64
|
+
rescue Errno::ECONNREFUSED
|
65
|
+
puts "Error: connection refused"
|
66
|
+
exit 1
|
67
|
+
rescue OpenSSL::SSL::SSLError => e
|
68
|
+
puts "#{e.class}: #{e.message}"
|
69
|
+
|
70
|
+
if failed_cert
|
71
|
+
puts "\nThe server presented a certificate that could not be verified:"
|
72
|
+
puts " subject: #{failed_cert.subject}"
|
73
|
+
puts " issuer: #{failed_cert.issuer}"
|
74
|
+
puts " error code %s" % failed_cert_reason
|
75
|
+
end
|
76
|
+
|
77
|
+
ca_file_missing = !File.exist?(ca_file) && !mac_openssl
|
78
|
+
ca_path_empty = Dir["#{ca_path}/*"].empty?
|
79
|
+
|
80
|
+
if ca_file_missing || ca_path_empty
|
81
|
+
puts "\nPossible causes:"
|
82
|
+
puts " `%s' does not exist" % ca_file if ca_file_missing
|
83
|
+
puts " `%s/' is empty" % ca_path if ca_path_empty
|
84
|
+
end
|
85
|
+
|
86
|
+
exit 1
|
87
|
+
end
|
data/lib/arbor/api.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'arbor/model/serialiser'
|
2
|
+
|
3
|
+
module Arbor
|
4
|
+
module API
|
5
|
+
def retrieve(type, id)
|
6
|
+
resource = parse_resource(type)
|
7
|
+
data = get("/rest-v2/#{resource}/#{id}")
|
8
|
+
|
9
|
+
unmarshall_data(data, resource)
|
10
|
+
end
|
11
|
+
|
12
|
+
def query(type, query = nil)
|
13
|
+
resource = parse_resource(type)
|
14
|
+
query_string = query.build_query_string if query
|
15
|
+
|
16
|
+
data = get("/rest-v2/#{resource}?#{query_string}")
|
17
|
+
|
18
|
+
unmarshall_data(data, resource)
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
def unmarshall_data(data, resource)
|
23
|
+
singular_resource = resource.to_s.singularize
|
24
|
+
plural_resource = resource.to_s
|
25
|
+
|
26
|
+
if (res = data[singular_resource])
|
27
|
+
Model::Serialiser.parse_resource(res).tap { |obj|
|
28
|
+
obj.attach_client(self) if obj.respond_to?(:attach_client)
|
29
|
+
obj.lock_attributes = true
|
30
|
+
}
|
31
|
+
elsif data[plural_resource]
|
32
|
+
data[plural_resource].map do |res|
|
33
|
+
Model::Serialiser.parse_resource(res).tap { |obj|
|
34
|
+
obj.attach_client(self) if obj.respond_to?(:attach_client)
|
35
|
+
}
|
36
|
+
end
|
37
|
+
else
|
38
|
+
raise Errors::SerialisationError, "Unexpected root key in API data."
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
data/lib/arbor/client.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'arbor/api'
|
2
|
+
require 'arbor/utils'
|
3
|
+
require 'httpi'
|
4
|
+
require 'json'
|
5
|
+
|
6
|
+
module Arbor
|
7
|
+
class Client
|
8
|
+
include Arbor::API
|
9
|
+
include Arbor::Utils
|
10
|
+
attr_accessor :host, :username, :password, :settings
|
11
|
+
|
12
|
+
def initialize(*args)
|
13
|
+
@settings = args.last.is_a?(Hash) ? args.pop : {}
|
14
|
+
raise ArgumentError, "must supply a subdomain, username and password" if args.length < 3
|
15
|
+
subdomain, @username, @password = args
|
16
|
+
@host = "https://#{subdomain}.uk.arbor.sc"
|
17
|
+
end
|
18
|
+
|
19
|
+
[:get, :post].each do |verb|
|
20
|
+
define_method(verb) do |*args|
|
21
|
+
request = configure_request(*args)
|
22
|
+
response = HTTPI.request(verb, request, settings[:adapter])
|
23
|
+
JSON.parse(response.body.presence || "{}")
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
def configure_request(path, *args)
|
29
|
+
url = "#{host}#{path}"
|
30
|
+
request = HTTPI::Request.new(url, *args)
|
31
|
+
request.headers["Accept"] = "application/json"
|
32
|
+
auth_type = settings[:adapter] == :net_http ? :basic : :digest
|
33
|
+
request.auth.send(auth_type, username, password)
|
34
|
+
request
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/lib/arbor/errors.rb
ADDED
data/lib/arbor/filter.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'arbor/utils'
|
2
|
+
|
3
|
+
module Arbor
|
4
|
+
class Filter
|
5
|
+
include Arbor::Utils
|
6
|
+
attr_accessor :attribute, :operator, :value
|
7
|
+
OPERATORS = [:equals, :from, :to, :after, :before, :search, :in]
|
8
|
+
|
9
|
+
def initialize(attribute, operator, value)
|
10
|
+
@attribute = attribute
|
11
|
+
@operator = validate(operator, OPERATORS)
|
12
|
+
@value = value
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_s
|
16
|
+
"filters.#{attribute}.#{operator}=#{value}"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'arbor/model/serialiser'
|
2
|
+
|
3
|
+
module Arbor
|
4
|
+
module Model
|
5
|
+
class Abstract
|
6
|
+
attr_accessor :api_client, :entity_type, :attribute_names, :attribute_lock
|
7
|
+
|
8
|
+
def initialize(attributes)
|
9
|
+
@attribute_names = []
|
10
|
+
load_attributes(attributes)
|
11
|
+
end
|
12
|
+
|
13
|
+
def method_missing(meth, *args, &block)
|
14
|
+
attribute_lock ? super : begin
|
15
|
+
refresh_data
|
16
|
+
send(meth, *args, &block)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def refresh_data
|
21
|
+
raise "No API client configured for this resource" if api_client.nil?
|
22
|
+
raise "No entity_type set for this resource" if entity_type.nil?
|
23
|
+
raise "No known endpoint for this resource" if href.nil?
|
24
|
+
|
25
|
+
data = api_client.get(href)
|
26
|
+
|
27
|
+
parsed_attributes = Serialiser.parse_attributes(data[entity_type.downcase])
|
28
|
+
load_attributes(parsed_attributes)
|
29
|
+
attach_client(self.api_client)
|
30
|
+
|
31
|
+
@attribute_lock = true
|
32
|
+
end
|
33
|
+
|
34
|
+
def load_attributes(attributes)
|
35
|
+
attributes.each do |name, value|
|
36
|
+
unless self.respond_to?("#{name}=")
|
37
|
+
self.class.instance_eval { define_method(name) { attribute(name) } }
|
38
|
+
self.class.send(:attr_writer, name)
|
39
|
+
end
|
40
|
+
@attribute_names << name
|
41
|
+
self.send("#{name}=", value)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def attribute(name)
|
46
|
+
if instance_variable_defined?("@#{name}")
|
47
|
+
instance_variable_get("@#{name}")
|
48
|
+
else
|
49
|
+
raise Errors::UnknownAttributeError if attribute_lock
|
50
|
+
refresh_data
|
51
|
+
attribute(name)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def attach_client(client)
|
56
|
+
self.api_client = client
|
57
|
+
self.attribute_names.each do |name|
|
58
|
+
if send(name).respond_to?("api_client=")
|
59
|
+
send(name).attach_client(client)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def unlock_attributes
|
65
|
+
@attribute_lock = false
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'arbor/model/abstract'
|
2
|
+
|
3
|
+
module Arbor
|
4
|
+
module Model
|
5
|
+
class Factory
|
6
|
+
def self.create(type = :unknown)
|
7
|
+
class_name = type.to_s.classify
|
8
|
+
|
9
|
+
unless Arbor::Model.const_defined?(class_name)
|
10
|
+
type_class = Class.new(Arbor::Model::Abstract)
|
11
|
+
Arbor::Model.const_set(class_name, type_class)
|
12
|
+
end
|
13
|
+
|
14
|
+
Arbor::Model.const_get(class_name)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'arbor/model/factory'
|
2
|
+
|
3
|
+
module Arbor
|
4
|
+
module Model
|
5
|
+
class Serialiser
|
6
|
+
class << self
|
7
|
+
def deserialise(data)
|
8
|
+
attributes = parse_attributes(data)
|
9
|
+
|
10
|
+
resource = data["entityType"].underscore.to_sym
|
11
|
+
Factory.create(resource).new(attributes)
|
12
|
+
end
|
13
|
+
|
14
|
+
def parse_attributes(attributes)
|
15
|
+
attr_array = attributes.map do |key, value|
|
16
|
+
value = case value
|
17
|
+
when Hash
|
18
|
+
parse_resource(value)
|
19
|
+
when Array
|
20
|
+
value.map { |nr| parse_resource(nr) }
|
21
|
+
else
|
22
|
+
value
|
23
|
+
end
|
24
|
+
[key, value]
|
25
|
+
end
|
26
|
+
|
27
|
+
transform_keys(Hash[attr_array])
|
28
|
+
end
|
29
|
+
|
30
|
+
def parse_resource(r)
|
31
|
+
nested_type = r["entityType"]
|
32
|
+
nested_type ? Arbor.serialisers[nested_type].deserialise(r) : r
|
33
|
+
end
|
34
|
+
|
35
|
+
def transform_keys(hash)
|
36
|
+
Hash[hash.map { |k, v| [k.underscore, v] }]
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/lib/arbor/query.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'uri'
|
2
|
+
require 'arbor/utils'
|
3
|
+
require 'arbor/filter'
|
4
|
+
|
5
|
+
module Arbor
|
6
|
+
class Query
|
7
|
+
include Arbor::Utils
|
8
|
+
|
9
|
+
attr_accessor :filters, :resource
|
10
|
+
|
11
|
+
def initialize(type, filters = [])
|
12
|
+
@resource = parse_resource(type)
|
13
|
+
@filters = filters
|
14
|
+
end
|
15
|
+
|
16
|
+
def build_query_string
|
17
|
+
URI.escape(filters.map(&:to_s).join("&"))
|
18
|
+
end
|
19
|
+
|
20
|
+
def add_filter(*args)
|
21
|
+
@filters << Arbor::Filter.new(*args)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'arbor/model/serialiser'
|
2
|
+
|
3
|
+
module Arbor
|
4
|
+
class SerialiserRegistry
|
5
|
+
attr_accessor :registry, :default_serialiser
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@registry = {}
|
9
|
+
@default_serialiser = Model::Serialiser
|
10
|
+
end
|
11
|
+
|
12
|
+
def register(resource, serialiser)
|
13
|
+
registry[resource] = serialiser
|
14
|
+
end
|
15
|
+
|
16
|
+
def unregister(resource)
|
17
|
+
registry[resource] = nil
|
18
|
+
end
|
19
|
+
|
20
|
+
def get_serialiser(resource)
|
21
|
+
registry[resource] || default_serialiser
|
22
|
+
end
|
23
|
+
alias_method :[], :get_serialiser
|
24
|
+
end
|
25
|
+
end
|
data/lib/arbor/utils.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'active_support/core_ext/string'
|
2
|
+
|
3
|
+
module Arbor
|
4
|
+
module Utils
|
5
|
+
def parse_resource(type)
|
6
|
+
validate(get_resource(type), Arbor::RESOURCES)
|
7
|
+
end
|
8
|
+
|
9
|
+
def get_resource(type)
|
10
|
+
case type
|
11
|
+
when Class
|
12
|
+
type.name.pluralize.underscore.to_sym
|
13
|
+
else
|
14
|
+
type.to_s.pluralize.to_sym
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def validate(choice, options)
|
19
|
+
unless options.include?(choice)
|
20
|
+
raise ArgumentError, "#{choice} is not a valid option: #{options}"
|
21
|
+
end
|
22
|
+
choice
|
23
|
+
end
|
24
|
+
|
25
|
+
def left_pad(array, num)
|
26
|
+
num.times { array.unshift(nil) }
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/arbor.rb
ADDED
@@ -0,0 +1,149 @@
|
|
1
|
+
require 'arbor/client'
|
2
|
+
require 'arbor/query'
|
3
|
+
require 'arbor/serialiser_registry'
|
4
|
+
require 'active_support/inflector'
|
5
|
+
require 'arbor/errors'
|
6
|
+
|
7
|
+
module Arbor
|
8
|
+
class << self
|
9
|
+
def serialisers
|
10
|
+
@serialisers ||= SerialiserRegistry.new
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
RESOURCES = [:academic_calendar_dates, :academic_holidays, :academic_levels,
|
15
|
+
:academic_level_memberships, :academic_level_registration_form_mappings,
|
16
|
+
:academic_level_tutors, :academic_programmes, :academic_programme_instances,
|
17
|
+
:academic_teaching_hours, :academic_units,
|
18
|
+
:academic_unit_automatic_enrolments, :academic_unit_cohorts,
|
19
|
+
:academic_unit_cohort_memberships, :academic_unit_curriculums,
|
20
|
+
:academic_unit_enrolments, :academic_unit_leads, :academic_unit_tags,
|
21
|
+
:academic_working_days, :academic_years, :achievement_levels,
|
22
|
+
:achievement_level_sets, :additional_payment_reasons, :alerts, :allowances,
|
23
|
+
:allowance_amounts, :applications, :application_settings,
|
24
|
+
:application_withdrawal_reasons, :aspects, :aspect_sets, :assessments,
|
25
|
+
:assessment_batches, :assessment_batch_targets, :assessment_derivations,
|
26
|
+
:assessment_derivation_dependants, :assessment_templates,
|
27
|
+
:assessment_template_assessments, :attendance_follow_ups, :attendance_marks,
|
28
|
+
:attendance_patterns, :attendance_pattern_periods, :attendance_records,
|
29
|
+
:attendance_register_types, :attendance_register_type_marks,
|
30
|
+
:awarding_bodies, :awarding_body_staffs, :bank_details, :behaviours,
|
31
|
+
:behavioural_contracts, :behavioural_contract_goals,
|
32
|
+
:behavioural_contract_parties, :behavioural_contract_periods,
|
33
|
+
:behavioural_incidents, :behavioural_incident_actions,
|
34
|
+
:behavioural_incident_behaviours, :behavioural_incident_staff_involvements,
|
35
|
+
:behavioural_incident_student_involvements, :behavioural_notes,
|
36
|
+
:boarding_patterns, :boarding_statuses, :bookable_resource_periods,
|
37
|
+
:business_roles, :business_role_assignments,
|
38
|
+
:business_role_default_user_roles, :calendars, :calendar_entries,
|
39
|
+
:calendar_entry_dates, :calendar_entry_mappings, :calendar_types, :cases,
|
40
|
+
:center_numbers, :check_clearance_levels, :check_types,
|
41
|
+
:child_protection_statuses, :child_protection_status_assignments,
|
42
|
+
:collections, :communication_actions, :communication_tags, :companies,
|
43
|
+
:company_staffs, :consents, :consent_types, :contents, :content_tags,
|
44
|
+
:countries, :court_orders, :court_order_parties, :cover_arrangements,
|
45
|
+
:cover_requirements, :curriculums, :curriculum_evidences, :curriculum_goals,
|
46
|
+
:curriculum_grades, :curriculum_judgements, :curriculum_sections,
|
47
|
+
:curriculum_stages, :curriculum_tiers, :custom_groups,
|
48
|
+
:custom_group_memberships, :dashboards, :dashboard_kpis,
|
49
|
+
:dashboard_sections, :data_check_errors, :data_check_error_related_entities,
|
50
|
+
:data_export_errors, :data_export_error_tags, :data_item_subscriptions,
|
51
|
+
:data_set_subscriptions, :detentions, :detention_sessions,
|
52
|
+
:dietary_requirements, :dietary_requirement_types, :document_html_templates,
|
53
|
+
:document_image_templates, :document_layouts, :education_plans,
|
54
|
+
:education_plan_contributors, :eligibilities, :eligibility_records, :emails,
|
55
|
+
:email_accounts, :email_account_access_permissions, :email_addresses,
|
56
|
+
:email_drafts, :email_mailboxes, :email_parts, :email_recipients,
|
57
|
+
:email_references, :email_senders, :email_statuses, :enrolment_modes,
|
58
|
+
:ethnicities, :event_participants, :event_participant_invitations,
|
59
|
+
:exceptions, :exclusion_reasons, :faculties, :faculty_members, :files,
|
60
|
+
:genders, :grades, :grade_point_scales, :grade_point_scale_level_grade_sets,
|
61
|
+
:grade_sets, :guardians, :guardian_consultations,
|
62
|
+
:guardian_relationship_types, :hearing_tests, :houses, :house_memberships,
|
63
|
+
:house_tutors, :hydrators, :identification_document_types, :identity_cards,
|
64
|
+
:identity_card_readers, :immunizations, :immunization_types,
|
65
|
+
:impairment_categories, :import_records, :in_care_statuses,
|
66
|
+
:in_care_status_assignments, :intake_seasons,
|
67
|
+
:intake_season_applicant_buckets, :intake_season_groups, :item_units, :kpis,
|
68
|
+
:kpi_ranges, :kpi_targets, :kpi_values, :languages, :language_abilities,
|
69
|
+
:layout_object_types, :letters, :letter_drafts, :meals, :meal_patterns,
|
70
|
+
:meal_prices, :meal_provisions, :meal_sessions,
|
71
|
+
:meal_session_register_records, :meal_sittings,
|
72
|
+
:meal_sitting_automatic_attendee_targets, :medical_conditions,
|
73
|
+
:medical_condition_medications, :medical_condition_types, :medical_events,
|
74
|
+
:medical_event_types, :medical_institutions, :medical_institution_staffs,
|
75
|
+
:medical_plans, :medical_relationship_types, :medications, :meetings,
|
76
|
+
:meeting_notes, :meeting_topics, :message_draft_recipients, :model_bases,
|
77
|
+
:motor_vehicles, :motor_vehicle_makes, :nationality_statuses,
|
78
|
+
:next_of_kin_relationships, :notes, :notices, :operations, :pastoral_notes,
|
79
|
+
:pay_scales, :pay_scale_grades, :pay_scale_grade_spinal_points,
|
80
|
+
:pay_scale_spinal_points, :pay_scale_spinal_point_values,
|
81
|
+
:permanent_exclusions, :people, :person_checks, :person_former_names,
|
82
|
+
:person_identification_documents, :person_impairments,
|
83
|
+
:person_nationalities, :person_next_of_kins,
|
84
|
+
:person_professional_qualifications, :person_training_courses,
|
85
|
+
:person_transportation_methods, :point_awards, :point_award_categories,
|
86
|
+
:point_award_scales, :point_award_totals, :positions,
|
87
|
+
:position_business_roles, :postal_addresses, :postal_address_occupancies,
|
88
|
+
:professional_qualification_classes, :professional_qualification_subjects,
|
89
|
+
:professional_qualification_types, :progress_assessment_batches,
|
90
|
+
:progress_assessment_batch_measurement_periods,
|
91
|
+
:progress_assessment_batch_targets, :progress_measurement_periods,
|
92
|
+
:qualification_aspects, :qualification_assessables,
|
93
|
+
:qualification_assessable_instances, :qualification_awards,
|
94
|
+
:qualification_award_level_types, :qualification_award_types,
|
95
|
+
:qualification_centre_assessed_marks,
|
96
|
+
:qualification_element_disallowed_combinations,
|
97
|
+
:qualification_element_relationships, :qualification_element_series_links,
|
98
|
+
:qualification_grades, :qualification_grade_sets,
|
99
|
+
:qualification_incoming_messages, :qualification_learning_units,
|
100
|
+
:qualification_predictions, :qualification_registrations,
|
101
|
+
:qualification_registration_requests, :qualification_request_batches,
|
102
|
+
:qualification_results, :qualification_schemes, :qualification_series,
|
103
|
+
:qualification_special_arrangements,
|
104
|
+
:qualification_special_arrangement_types, :qualification_timetable_sessions,
|
105
|
+
:qualification_timetable_session_types, :qualification_time_windows,
|
106
|
+
:qualification_time_window_collections, :registration_forms,
|
107
|
+
:registration_form_memberships, :registration_form_tutors, :religions,
|
108
|
+
:report_card_batches, :report_card_batch_targets,
|
109
|
+
:report_card_batch_template_variables, :report_card_templates,
|
110
|
+
:report_card_template_sections, :report_subscriptions, :rooms, :room_assets,
|
111
|
+
:room_features, :room_room_assets, :room_room_features, :schools,
|
112
|
+
:school_enrolments, :school_events, :school_event_types, :school_staffs,
|
113
|
+
:school_trips, :schoolworks, :schoolwork_curriculum_goals,
|
114
|
+
:schoolwork_types, :sending_profiles, :sen_events, :sen_event_outcomes,
|
115
|
+
:sen_event_outcome_types, :sen_event_types, :sen_needs, :sen_need_types,
|
116
|
+
:sen_notes, :sen_provisions, :sen_provision_linked_relationships,
|
117
|
+
:sen_provision_types, :sen_statements, :sen_statuses,
|
118
|
+
:sen_status_assignments, :sessions, :session_curriculum_goals,
|
119
|
+
:session_room_asset_requirements, :session_room_feature_requirements,
|
120
|
+
:session_streams, :session_stream_automatic_enrolments,
|
121
|
+
:session_stream_enrolments, :session_stream_leads, :sites,
|
122
|
+
:site_operating_periods, :site_operating_period_exceptions,
|
123
|
+
:site_travel_times, :sms_messages, :sms_message_drafts, :sms_message_parts,
|
124
|
+
:sms_message_statuses, :snippets, :snippet_availabilities, :staffs,
|
125
|
+
:staff_absences, :staff_absence_categories, :staff_attendance_marks,
|
126
|
+
:staff_attendance_records, :staff_contracts, :staff_contract_posts,
|
127
|
+
:staff_contract_post_additional_payments, :staff_contract_post_allowances,
|
128
|
+
:staff_contract_post_end_reasons, :staff_contract_post_rates,
|
129
|
+
:staff_contract_post_salaries, :staff_contract_post_start_reasons,
|
130
|
+
:staff_destinations, :staff_employment_types, :staff_origins,
|
131
|
+
:staff_room_feature_requirements, :staff_working_periods, :students,
|
132
|
+
:student_absence_notes, :student_assessments, :student_assessment_marks,
|
133
|
+
:student_attendance_patterns, :student_guardian_relationships,
|
134
|
+
:student_linked_relationships, :student_linked_relationship_types,
|
135
|
+
:student_medical_relationships, :student_other_school_attendance_records,
|
136
|
+
:student_progress_assessments, :student_progress_assessment_marks,
|
137
|
+
:student_progress_baselines, :student_progress_goals, :student_report_cards,
|
138
|
+
:student_report_card_marks, :student_report_card_sections,
|
139
|
+
:student_room_feature_requirements, :student_schools, :student_schoolworks,
|
140
|
+
:student_schoolwork_marks, :subjects, :superannuation_schemes,
|
141
|
+
:superannuation_scheme_values, :tags, :taggings,
|
142
|
+
:teaching_assistant_allocations, :telephone_calls, :telephone_numbers,
|
143
|
+
:temporary_exclusions, :terms, :timetable_slots, :timetable_slot_staffs,
|
144
|
+
:titles, :training_courses, :training_events, :transportation_methods,
|
145
|
+
:triggers, :unenrolment_reasons, :universities, :university_staffs,
|
146
|
+
:usage_log_entries, :users, :user_defined_fields, :user_defined_records,
|
147
|
+
:user_notifications, :user_roles, :user_role_assignments, :vision_tests,
|
148
|
+
:widgets, :widget_types, :workitems, :workitem_assignments]
|
149
|
+
end
|
metadata
ADDED
@@ -0,0 +1,122 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: arbor
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Mike Campbell
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-09-19 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activesupport
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 3.0.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 3.0.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: httpi
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 2.0.5
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 2.0.5
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: bundler
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ~>
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.3'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.3'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rake
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ~>
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
description: Interface for the Arbor Education REST API.
|
70
|
+
email:
|
71
|
+
- mike.campbell@meritec.co.uk
|
72
|
+
executables: []
|
73
|
+
extensions: []
|
74
|
+
extra_rdoc_files: []
|
75
|
+
files:
|
76
|
+
- .gitignore
|
77
|
+
- Gemfile
|
78
|
+
- Gemfile.lock
|
79
|
+
- MIT-LICENSE
|
80
|
+
- README.md
|
81
|
+
- Rakefile
|
82
|
+
- arbor.gemspec
|
83
|
+
- doctor.rb
|
84
|
+
- lib/arbor.rb
|
85
|
+
- lib/arbor/api.rb
|
86
|
+
- lib/arbor/client.rb
|
87
|
+
- lib/arbor/errors.rb
|
88
|
+
- lib/arbor/filter.rb
|
89
|
+
- lib/arbor/model/abstract.rb
|
90
|
+
- lib/arbor/model/factory.rb
|
91
|
+
- lib/arbor/model/no_op_serialiser.rb
|
92
|
+
- lib/arbor/model/serialiser.rb
|
93
|
+
- lib/arbor/query.rb
|
94
|
+
- lib/arbor/serialiser_registry.rb
|
95
|
+
- lib/arbor/utils.rb
|
96
|
+
- lib/arbor/version.rb
|
97
|
+
homepage: http://github.com/meritec/arbor-rb
|
98
|
+
licenses:
|
99
|
+
- MIT
|
100
|
+
metadata: {}
|
101
|
+
post_install_message:
|
102
|
+
rdoc_options: []
|
103
|
+
require_paths:
|
104
|
+
- lib
|
105
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
106
|
+
requirements:
|
107
|
+
- - '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
111
|
+
requirements:
|
112
|
+
- - '>='
|
113
|
+
- !ruby/object:Gem::Version
|
114
|
+
version: '0'
|
115
|
+
requirements: []
|
116
|
+
rubyforge_project:
|
117
|
+
rubygems_version: 2.3.0
|
118
|
+
signing_key:
|
119
|
+
specification_version: 4
|
120
|
+
summary: Interface for the Arbor Education REST API.
|
121
|
+
test_files: []
|
122
|
+
has_rdoc:
|