lusi_api 0.1.11
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/.gitignore +58 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +235 -0
- data/Rakefile +8 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/lusi_api.rb +5 -0
- data/lib/lusi_api/calendar.rb +234 -0
- data/lib/lusi_api/core/api.rb +190 -0
- data/lib/lusi_api/core/code.rb +101 -0
- data/lib/lusi_api/core/exceptions.rb +47 -0
- data/lib/lusi_api/core/lookup.rb +612 -0
- data/lib/lusi_api/core/util.rb +102 -0
- data/lib/lusi_api/core/xml.rb +168 -0
- data/lib/lusi_api/country.rb +111 -0
- data/lib/lusi_api/course.rb +1300 -0
- data/lib/lusi_api/enrolment.rb +247 -0
- data/lib/lusi_api/organisation.rb +291 -0
- data/lib/lusi_api/person/staff.rb +115 -0
- data/lib/lusi_api/person/student.rb +551 -0
- data/lib/lusi_api/service_account.rb +121 -0
- data/lib/lusi_api/service_method.rb +52 -0
- data/lib/lusi_api/version.rb +5 -0
- data/lib/lusi_api/vle.rb +329 -0
- data/lusi_api.gemspec +36 -0
- metadata +182 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: da1c5f2df15cb658a48d858532d3189d951e7141
|
4
|
+
data.tar.gz: 2e7dfb970b80eeb666c169f72fa563776f21683c
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: cfbb149d9f00d6c8e1b7d8c4b6a0fafaaca45346ad007113a0ad795ab48215461959d26dcc2618ce940a6a6c277421cc4378ca539e1e86d514e312d065388e4f
|
7
|
+
data.tar.gz: 64a05269d80fe562a4eba9b51b917da2eb63697f0af0021a64b16d84eb42454756f0380e67c43dd72d7cf967233d1116a4213bdf2699bdd7bdfd8b5612ecce59
|
data/.gitignore
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
# IntelliJ files
|
2
|
+
.idea/
|
3
|
+
*.iml
|
4
|
+
*.iws
|
5
|
+
|
6
|
+
# Created by https://www.gitignore.io/api/ruby
|
7
|
+
|
8
|
+
### Ruby ###
|
9
|
+
*.gem
|
10
|
+
*.rbc
|
11
|
+
/.config
|
12
|
+
/coverage/
|
13
|
+
/InstalledFiles
|
14
|
+
/pkg/
|
15
|
+
/spec/reports/
|
16
|
+
/spec/examples.txt
|
17
|
+
/test/tmp/
|
18
|
+
/test/version_tmp/
|
19
|
+
/tmp/
|
20
|
+
|
21
|
+
# Used by dotenv library to load environment variables.
|
22
|
+
.env
|
23
|
+
|
24
|
+
## Specific to RubyMotion:
|
25
|
+
.dat*
|
26
|
+
.repl_history
|
27
|
+
build/
|
28
|
+
*.bridgesupport
|
29
|
+
build-iPhoneOS/
|
30
|
+
build-iPhoneSimulator/
|
31
|
+
|
32
|
+
## Specific to RubyMotion (use of CocoaPods):
|
33
|
+
#
|
34
|
+
# We recommend against adding the Pods directory to your .gitignore. However
|
35
|
+
# you should judge for yourself, the pros and cons are mentioned at:
|
36
|
+
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
|
37
|
+
#
|
38
|
+
# vendor/Pods/
|
39
|
+
|
40
|
+
## Documentation cache and generated files:
|
41
|
+
/.yardoc/
|
42
|
+
/_yardoc/
|
43
|
+
/doc/
|
44
|
+
/rdoc/
|
45
|
+
|
46
|
+
## Environment normalization:
|
47
|
+
/.bundle/
|
48
|
+
/vendor/bundle
|
49
|
+
/lib/bundler/man/
|
50
|
+
|
51
|
+
# for a library or gem, you might want to ignore these files since the code is
|
52
|
+
# intended to run in multiple environments; otherwise, check them in:
|
53
|
+
Gemfile.lock
|
54
|
+
.ruby-version
|
55
|
+
.ruby-gemset
|
56
|
+
|
57
|
+
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
|
58
|
+
.rvmrc
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2016 lbaajh
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,235 @@
|
|
1
|
+
# LusiApi
|
2
|
+
|
3
|
+
A Ruby client for Lancaster University's LUSI API for student record management.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'lusi_api'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install lusi_api
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
### Basic usage
|
24
|
+
|
25
|
+
Create an API instance with your LUSI account credentials:
|
26
|
+
|
27
|
+
```ruby
|
28
|
+
require 'lusi_api'
|
29
|
+
|
30
|
+
api = LUSI::API::Core::API.new(api_user: 'Your LUSI username', api_password: 'Your LUSI password')
|
31
|
+
```
|
32
|
+
|
33
|
+
Then pass this as the first argumnent of the ```get_instance``` factory methods of the API data classes.
|
34
|
+
|
35
|
+
### Common classes
|
36
|
+
|
37
|
+
All LUSI API classes are subclasses of ```LUSI::API::Core::Object.```
|
38
|
+
|
39
|
+
Entities with identity are subclasses of ```LUSI::API::Core::ObjectWithID.``` Instances use the LUSI ID for equality and
|
40
|
+
hashing.
|
41
|
+
|
42
|
+
Properties consisting of an id/name pair are instances of ```LUSI::API::Core::Code.```
|
43
|
+
|
44
|
+
### Lookup
|
45
|
+
|
46
|
+
The LUSI web API frequently provides codes to represent linked or embedded objects (for example, the department a
|
47
|
+
student is affiliated with). To assist with resolving codes to objects, the LUSI API provides the
|
48
|
+
```LUSI::API::Core::Lookup``` module.
|
49
|
+
|
50
|
+
#### LookupTable
|
51
|
+
|
52
|
+
The ```LUSI::API::Core::Lookup::LookupTable``` class extends Ruby's ```Hash``` so that failed key lookups trigger an
|
53
|
+
attempt to read the value from an external data source by calling the ```get_value(key)``` method.
|
54
|
+
|
55
|
+
Subclasses implement ```get_value``` to perform the key lookup in the data source. If the lookup succeeds, the
|
56
|
+
corresponding value should be returned. If it fails, ```LUSI::API::Core::Lookup::LookupError``` should be raised.
|
57
|
+
|
58
|
+
If ```get_value``` returns a value, this value is added to the lookup table hash and returned as the result of the
|
59
|
+
lookup. If ```LookupError``` is raised, the usual ```Hash``` handling of a failed lookup is invoked (default value or
|
60
|
+
code block).
|
61
|
+
|
62
|
+
#### LUSILookupTable
|
63
|
+
|
64
|
+
The ```LUSI::API::Core::Lookup::LUSILookupTable``` class extends ```LookupTable``` to retrieve data from the LUSI web
|
65
|
+
API when a key lookup fails.
|
66
|
+
|
67
|
+
```ruby
|
68
|
+
require 'lusi_api/core/lookup'
|
69
|
+
|
70
|
+
# The API class of the objects to be added to the lookup table
|
71
|
+
result_class = LUSI::API::Core::Code
|
72
|
+
|
73
|
+
# Positional arguments to the result class' get_instance method
|
74
|
+
args = ['arg1', 'arg2']
|
75
|
+
|
76
|
+
# Keyword arguments to the result class' get_instance method
|
77
|
+
kwargs = { arg1: 'value1', arg2: 'value2' }
|
78
|
+
|
79
|
+
# The parameter of the result_class' get_instance method used as the search condition
|
80
|
+
param = 'identity'
|
81
|
+
|
82
|
+
# The attribute of the result_class instance supplying the key value
|
83
|
+
# This may be a String or Symbol (the name of the attribute) or a Proc (accepting the result_class instance as its
|
84
|
+
# single argument and returning the key value). If not specified, the result_class instance is expected to have an
|
85
|
+
# attribute named 'identity' which supplies the key value.
|
86
|
+
# NameError is raised if the attribute lookup fails.
|
87
|
+
key_attribute = 'object_id'
|
88
|
+
|
89
|
+
begin
|
90
|
+
lookup = LUSI::API::Core::Lookup::LUSILookupTable(api, result_class, *args,
|
91
|
+
key_attribute: key_attribute,
|
92
|
+
param: param,
|
93
|
+
**kwargs)
|
94
|
+
rescue NameError
|
95
|
+
# The key attribute lookup failed
|
96
|
+
end
|
97
|
+
```
|
98
|
+
|
99
|
+
Some lookup tables (for example, academic weeks, countries) can be populated from a single call to the LUSI web API.
|
100
|
+
```LUSILookupTable``` provides the ```load``` method to support this.
|
101
|
+
|
102
|
+
A lookup table which supports bulk loading should include the constructor parameter ```loadable: true``` and may
|
103
|
+
specify an optional hash of default parameter values for the ```load``` method:
|
104
|
+
|
105
|
+
```ruby
|
106
|
+
begin
|
107
|
+
lookup = LUSI::API::Core::Lookup::LUSILookupTable(api, result_class, ...,
|
108
|
+
loadable: true,
|
109
|
+
load_params: {})
|
110
|
+
end
|
111
|
+
```
|
112
|
+
|
113
|
+
|
114
|
+
### Exceptions
|
115
|
+
|
116
|
+
All exceptions thrown by the LUSI API are subclasses of ```LUSI::API::Core::APIError.```
|
117
|
+
|
118
|
+
The exception hiearchy is:
|
119
|
+
```
|
120
|
+
APIError
|
121
|
+
APICallError
|
122
|
+
APITimeoutError
|
123
|
+
APIResponseError
|
124
|
+
APIContentError
|
125
|
+
APIPermissionError
|
126
|
+
```
|
127
|
+
|
128
|
+
Methods which interact with the LUSI web API, such as the ```get_instance``` method of the data classes, should
|
129
|
+
rescue at least ```LUSI::API::Core::APIError``` to handle network problems.
|
130
|
+
|
131
|
+
```ruby
|
132
|
+
begin
|
133
|
+
result = SomeClass.get_instance(api)
|
134
|
+
rescue LUSI::API::Core::APITimeoutError
|
135
|
+
# Subclass of APICallError
|
136
|
+
# Raised when the LUSI API does not respond within the timeout period
|
137
|
+
rescue LUSI::API::Core::APICallError
|
138
|
+
# Subclass of APIError
|
139
|
+
# Raised when there is a general problem with the LUSI API call (e.g. network error)
|
140
|
+
rescue LUSI::API::Core::APIContentError
|
141
|
+
# Subclass of APIResponseError
|
142
|
+
# Raised when there is a problem parsing the XML response from the LUSI API
|
143
|
+
rescue LUSI::API::Core::APIPermissionError
|
144
|
+
# Subclass of APIResponseError
|
145
|
+
# Raised when the LUSI account does not have permission to call the requested API method
|
146
|
+
rescue LUSI::API::Core::APIError
|
147
|
+
# Raised when any other problem occurs
|
148
|
+
end
|
149
|
+
```
|
150
|
+
|
151
|
+
### Calendar module
|
152
|
+
|
153
|
+
The ```LUSI::API::Calendar``` module provides the classes ```Week``` and ```Year``` to represent LUSI academic week and
|
154
|
+
year objects. Both classes extend ```LUSI::API::Core::Code.```
|
155
|
+
|
156
|
+
#### Year
|
157
|
+
|
158
|
+
Years in LUSI are objects with an 6-digit zero-padded identity code derived from the year: 000nnn
|
159
|
+
where nnn = year - 1900.
|
160
|
+
|
161
|
+
e.g. 2016 = 2016 - 1900 = 000116
|
162
|
+
|
163
|
+
```ruby
|
164
|
+
require 'lusi_api/calendar'
|
165
|
+
|
166
|
+
# Get an array of all years in LUSI
|
167
|
+
all_years = LUSI::API::Calendar::Year.get_instance(api, lookup)
|
168
|
+
year_2016 = all_years.select { |year| year.identity == '000116' }
|
169
|
+
|
170
|
+
# Year properties
|
171
|
+
puts <<EOF
|
172
|
+
Identity: #{year_2016.identity}
|
173
|
+
Description: #{year_2016.description}
|
174
|
+
Full year description: #{year_2016.full_year}
|
175
|
+
EOF
|
176
|
+
```
|
177
|
+
|
178
|
+
#### Week
|
179
|
+
|
180
|
+
```ruby
|
181
|
+
require 'lusi_api/calendar'
|
182
|
+
|
183
|
+
# Get an array of all weeks in LUSI
|
184
|
+
all_weeks = LUSI::API::Calendar::Week.get_instance(api, lookup)
|
185
|
+
|
186
|
+
# Get an array of all weeks for a specific year
|
187
|
+
# year may be a year identity string or a LUSI::API::Calendar::Year instance
|
188
|
+
year_weeks = LUSI::API::Calendar::Week.get_instance(api, lookup, year_identity: '000116')
|
189
|
+
|
190
|
+
# Get the current academic week
|
191
|
+
current_week = LUSI::API::Calendar::Week.current_academic_week(api)
|
192
|
+
|
193
|
+
# Week properties
|
194
|
+
# - monday_date is an instance of DateTime
|
195
|
+
# - year is an instance of LUSI::API::Calendar::Year
|
196
|
+
puts <<EOF
|
197
|
+
Identity: #{current_week.identity}
|
198
|
+
Description: #{current_week.description}
|
199
|
+
Academic timetable week ID: #{current_week.att_identity}
|
200
|
+
Monday date: #{current_week.monday_date}
|
201
|
+
Term: #{current_week.term}
|
202
|
+
Year: #{current_week.year}
|
203
|
+
EOF
|
204
|
+
```
|
205
|
+
|
206
|
+
|
207
|
+
### Country module
|
208
|
+
|
209
|
+
### Course module
|
210
|
+
|
211
|
+
### Enrolment module
|
212
|
+
|
213
|
+
### Organisation module
|
214
|
+
|
215
|
+
### Person module
|
216
|
+
|
217
|
+
### Service account module
|
218
|
+
|
219
|
+
### Service method module
|
220
|
+
|
221
|
+
## Development
|
222
|
+
|
223
|
+
After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
224
|
+
|
225
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
226
|
+
|
227
|
+
## Contributing
|
228
|
+
|
229
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/lusi_api.
|
230
|
+
|
231
|
+
|
232
|
+
## License
|
233
|
+
|
234
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
235
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
task :default => :spec
|
3
|
+
|
4
|
+
# YARD::Rake::YardocTask.new do |t|
|
5
|
+
# t.files = ['lib/**/*.rb'] # optional
|
6
|
+
# t.options = ['--any', '--extra', '--opts', '--private', '--protected'] # optional
|
7
|
+
# t.stats_options = ['--list-undoc'] # optional
|
8
|
+
# end
|
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "lusi_api"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start
|
data/bin/setup
ADDED
@@ -0,0 +1,234 @@
|
|
1
|
+
require 'lusi_api/core/code'
|
2
|
+
require 'lusi_api/core/util'
|
3
|
+
require 'lusi_api/core/xml'
|
4
|
+
|
5
|
+
|
6
|
+
module LUSI
|
7
|
+
module API
|
8
|
+
module Calendar
|
9
|
+
|
10
|
+
|
11
|
+
# Represents an academic week in the LUSI API
|
12
|
+
class Week < LUSI::API::Core::Code
|
13
|
+
|
14
|
+
# @!attribute [rw] att_identity
|
15
|
+
# @return [Integer, nil] the academic timetable (ATT) week identity
|
16
|
+
attr_accessor :att_identity
|
17
|
+
|
18
|
+
# @!attribute [rw] monday_date
|
19
|
+
# @return [DateTime, nil] the Monday starting the week
|
20
|
+
attr_accessor :monday_date
|
21
|
+
|
22
|
+
# @!attribute [rw] term
|
23
|
+
# @return [String, nil] The term/period the week is in
|
24
|
+
attr_accessor :term
|
25
|
+
|
26
|
+
# @!attribute [rw] year
|
27
|
+
# @return [LUSI::API::Calendar::Year, nil] the academic year containing the week
|
28
|
+
attr_accessor :year
|
29
|
+
|
30
|
+
# Returns a Week instance for the current academic week
|
31
|
+
# @param api [LUSI::API::Core::API] the LUSI API instance
|
32
|
+
# @param lookup [LUSI::API::Core::Lookup::LookupService, nil] the lookup service for object resolution
|
33
|
+
# @return [LUSI::API::Calendar::Week] the current academic week
|
34
|
+
# @yield [obj] Passes the Week instance to the block
|
35
|
+
# @yieldparam obj [LUSI::API::Calendar::Week] the Week instance
|
36
|
+
def self.get_current_academic_week(api = nil, lookup = nil)
|
37
|
+
xml = api.call('LUSIReference', 'General.asmx', 'GetCurrentAcademicWeek')
|
38
|
+
obj = new(LUSI::API::Core::XML.xml_at(xml, 'xmlns:Week'), lookup)
|
39
|
+
yield(obj) if block_given?
|
40
|
+
obj
|
41
|
+
end
|
42
|
+
|
43
|
+
# Returns Week instances for all or one specific academic year
|
44
|
+
# @param api [LUSI::API::Core::API] the LUSI API instance
|
45
|
+
# @param lookup [LUSI::API::Core::Lookup::LookupService, nil] the lookup service for object resolution
|
46
|
+
# @param use_lookup [Boolean] if true, use the lookup service to identify instances before trying the API
|
47
|
+
# @param year [LUSI::API::Calendar::Year, String, nil] the academic year required (all defined weeks if nil)
|
48
|
+
# @return [Array<LUSI::API::Calendar::Week>] the selected acadmic weeks
|
49
|
+
# @yield [obj] Passes the Week instance to the block
|
50
|
+
# @yieldparam obj [LUSI::API::Calendar::Week] the Week instance
|
51
|
+
def self.get_instance(api = nil, lookup = nil, use_lookup: true, year_identity: nil)
|
52
|
+
# Search the lookup service
|
53
|
+
if lookup and use_lookup
|
54
|
+
week = lookup.lookup(:week, year_identity)
|
55
|
+
if week
|
56
|
+
yield(week) if block_given?
|
57
|
+
return week
|
58
|
+
end
|
59
|
+
end
|
60
|
+
# Search the API
|
61
|
+
super(api, lookup, 'LUSIReference', 'General.asmx', 'GetWeeks', 'xmlns:Week', year_identity: year_identity)
|
62
|
+
end
|
63
|
+
|
64
|
+
# Initialises a new Week instance
|
65
|
+
# @param (see LUSI::API::Core::Code#initialize)
|
66
|
+
# @param att_identity [Integer, nil] the default academic timetable (ATT) identity
|
67
|
+
# @param monday_date [DateTime, nil] the default Monday week-start date
|
68
|
+
# @param term [String, nil] the default term
|
69
|
+
# @param year [LUSI::API::Calendar::Year, nil] the default academic year
|
70
|
+
# @return [void]
|
71
|
+
def initialize(xml = nil, lookup = nil, term: nil, monday_date: nil, year: nil, att_identity: nil, **kwargs)
|
72
|
+
super(xml, lookup, **kwargs)
|
73
|
+
@att_identity = LUSI::API::Core::XML.xml_int_at(xml, 'xmlns:ATTIdentity', att_identity)
|
74
|
+
@monday_date = LUSI::API::Core::XML.xml_datetime_at(xml, 'xmlns:MondayDate', monday_date)
|
75
|
+
@term = LUSI::API::Core::XML.xml_content_at(xml, 'xmlns:Term', term)
|
76
|
+
@year = LUSI::API::Core::XML.lookup(xml, lookup, :year, 'xmlns:Year/xmlns:Identity', year)
|
77
|
+
end
|
78
|
+
|
79
|
+
protected
|
80
|
+
|
81
|
+
def self.get_instance_params(**kwargs)
|
82
|
+
year = kwargs[:year_identity] || ''
|
83
|
+
year = year.identity if year.is_a?(Year)
|
84
|
+
params = super(**kwargs)
|
85
|
+
params[:YearIdentity] = year || ''
|
86
|
+
params
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
|
91
|
+
|
92
|
+
# Represents an academic year in the LUSI API
|
93
|
+
class Year < LUSI::API::Core::Code
|
94
|
+
|
95
|
+
extend LUSI::API::Core::Util
|
96
|
+
|
97
|
+
# @!attribute [rw] full_year
|
98
|
+
# @return [String, nil] the full text description of the academic year
|
99
|
+
attr_accessor :full_year
|
100
|
+
|
101
|
+
# @!attribute [rw] lookup
|
102
|
+
# @return [LUSI::API::Core::Lookup::LookupService, nil] the lookup service for object resolution
|
103
|
+
attr_accessor :lookup
|
104
|
+
|
105
|
+
# Returns a Year instance for the current academic year
|
106
|
+
# @param api [LUSI::API::Core::API] the LUSI API instance
|
107
|
+
# @param lookup [LUSI::API::Core::Lookup::LookupService, nil] the lookup service for object resolution
|
108
|
+
# @return [LUSI::API::Calendar::Year] the current academic year
|
109
|
+
# @yield [obj] Passes the Year instance to the block
|
110
|
+
# @yieldparam obj [LUSI::API::Calendar::Year] the Year instance
|
111
|
+
def self.get_current_academic_year(api = nil, lookup = nil)
|
112
|
+
xml = api.call('LUSIReference', 'General.asmx', 'GetCurrentAcademicYear')
|
113
|
+
obj = new(LUSI::API::Core::XML.xml_at(xml, 'xmlns:Year'), lookup)
|
114
|
+
yield(obj) if block_given?
|
115
|
+
obj
|
116
|
+
end
|
117
|
+
|
118
|
+
# Returns selected or all defined year instances
|
119
|
+
# @param api [LUSI::API::Core::API] the LUSI API instance
|
120
|
+
# @param lookup [LUSI::API::Core::Lookup::LookupService, nil] the lookup service for object resolution
|
121
|
+
# Remaining positional parameters are years or year identities of the required years
|
122
|
+
# @param use_lookup [Boolean] if true, use the lookup service to identify instances before trying the API
|
123
|
+
# @return [Array<LUSI::API::Calendar::Year>, nil] the defined year instances
|
124
|
+
# @yield [obj] Passes the Year instance to the block
|
125
|
+
# @yieldparam obj [LUSI::API::Calendar::Year] the Year instance
|
126
|
+
def self.get_instance(api = nil, lookup = nil, *years, use_lookup: true, **kwargs)
|
127
|
+
results = nil
|
128
|
+
# Search the lookup service if required
|
129
|
+
if lookup && use_lookup
|
130
|
+
year_lookup = lookup.service(:year)
|
131
|
+
results = year_lookup.values if year_lookup
|
132
|
+
end
|
133
|
+
# Search the API if required
|
134
|
+
results = super(api, lookup, 'LUSIReference', 'General.asmx', 'GetYears', 'xmlns:Year') if results.nil?
|
135
|
+
# Return the results
|
136
|
+
if results.nil? || years.nil? || years.empty?
|
137
|
+
# No results or no filtering required
|
138
|
+
results
|
139
|
+
else
|
140
|
+
# Return the year instances for the specified years
|
141
|
+
years = years.map { |year| lusi_year_identity(year) }
|
142
|
+
results.select { |result| years.include?(result.identity) }
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
# Initialises a new Year instance
|
147
|
+
# @param (see LUSI::API::Core::Code#initialize)
|
148
|
+
# @param full_year [String, nil] the full text description of the academic year
|
149
|
+
# @return [void]
|
150
|
+
def initialize(xml = nil, lookup = nil, full_year: nil, **kwargs)
|
151
|
+
super(xml, lookup, **kwargs)
|
152
|
+
self.full_year = LUSI::API::Core::XML.xml_content_at(xml, 'xmlns:FullYear', full_year)
|
153
|
+
# Store the lookup service for year arithmetic operations
|
154
|
+
self.lookup = lookup
|
155
|
+
end
|
156
|
+
|
157
|
+
# Returns the year instance n years after this one
|
158
|
+
# @param years [Integer] the number of years to add to the instance's year
|
159
|
+
# @return [LUSI::API::Calendar::Year] the year instance
|
160
|
+
def +(years = 0)
|
161
|
+
self.offset(years)
|
162
|
+
end
|
163
|
+
|
164
|
+
# Returns the year instance n years before this one
|
165
|
+
# @param years [Integer] the number of years to subtract from the instance's year
|
166
|
+
# @return [LUSI::API::Calendar::Year] the year instance
|
167
|
+
def -(years = 0)
|
168
|
+
self.offset(-years)
|
169
|
+
end
|
170
|
+
|
171
|
+
# Returns the year instance immediately following this one
|
172
|
+
# @return [LUSI::API::Calendar::Year] the year instance
|
173
|
+
def next(count = 1)
|
174
|
+
count = count.to_i
|
175
|
+
if count == 1
|
176
|
+
self.offset(1)
|
177
|
+
else
|
178
|
+
result = []
|
179
|
+
(1..count).each { |offset| result.push(self.offset(offset)) }
|
180
|
+
result
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
# Returns the year instance n years after/before this one
|
185
|
+
# @param years [Integer] the number of years to add to the instance's year
|
186
|
+
# @return [LUSI::API::Calendar::Year] the year instance
|
187
|
+
def offset(years = 0)
|
188
|
+
return self if years == 0
|
189
|
+
year = self.class.lusi_year(self, self.lookup, as_instance: true, offset: years)
|
190
|
+
end
|
191
|
+
|
192
|
+
# Returns the year instance immediately preceding this one
|
193
|
+
# @return [LUSI::API::Calendar::Year] the year instance
|
194
|
+
def previous(count = 1)
|
195
|
+
count = count.to_i
|
196
|
+
if count == 1
|
197
|
+
self.offset(-1)
|
198
|
+
else
|
199
|
+
result = []
|
200
|
+
(1..count).each { |offset| result.push(self.offset(-offset)) }
|
201
|
+
result
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
# Returns a list of year instances around (immediately preceding and following) this one
|
206
|
+
# @param from [Integer, Range] the starting offset relative to the current year
|
207
|
+
# @param to [Integer] the ending offset relative to the current year
|
208
|
+
# @return [Array<LUSI::API::Calendar::Year>] the year instances
|
209
|
+
def range(from = nil, to = nil)
|
210
|
+
from = (from..to) unless from.is_a?(Range)
|
211
|
+
result = []
|
212
|
+
from.each { |offset| result.push(self.offset(offset)) }
|
213
|
+
result
|
214
|
+
end
|
215
|
+
|
216
|
+
# Returns a string representation of the Year instance
|
217
|
+
# @return [String] the string representation of the Year instance
|
218
|
+
def to_s
|
219
|
+
self.full_year
|
220
|
+
end
|
221
|
+
|
222
|
+
protected
|
223
|
+
|
224
|
+
# Returns an empty parameter hash for the LUSI API call
|
225
|
+
def self.get_instance_params(**kwargs)
|
226
|
+
{}
|
227
|
+
end
|
228
|
+
|
229
|
+
end
|
230
|
+
|
231
|
+
|
232
|
+
end
|
233
|
+
end
|
234
|
+
end
|