kosapi_client 0.5.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.
Files changed (83) hide show
  1. checksums.yaml +7 -0
  2. data/bin/console +15 -0
  3. data/bin/setup +23 -0
  4. data/lib/kosapi_client.rb +22 -0
  5. data/lib/kosapi_client/api_client.rb +43 -0
  6. data/lib/kosapi_client/configuration.rb +23 -0
  7. data/lib/kosapi_client/entity.rb +19 -0
  8. data/lib/kosapi_client/entity/author.rb +17 -0
  9. data/lib/kosapi_client/entity/base_entity.rb +16 -0
  10. data/lib/kosapi_client/entity/base_person.rb +20 -0
  11. data/lib/kosapi_client/entity/boolean.rb +14 -0
  12. data/lib/kosapi_client/entity/course.rb +34 -0
  13. data/lib/kosapi_client/entity/course_event.rb +20 -0
  14. data/lib/kosapi_client/entity/data_mappings.rb +122 -0
  15. data/lib/kosapi_client/entity/enum.rb +11 -0
  16. data/lib/kosapi_client/entity/exam.rb +25 -0
  17. data/lib/kosapi_client/entity/id.rb +13 -0
  18. data/lib/kosapi_client/entity/link.rb +54 -0
  19. data/lib/kosapi_client/entity/ml_string.rb +42 -0
  20. data/lib/kosapi_client/entity/parallel.rb +20 -0
  21. data/lib/kosapi_client/entity/person.rb +10 -0
  22. data/lib/kosapi_client/entity/result_page.rb +46 -0
  23. data/lib/kosapi_client/entity/student.rb +25 -0
  24. data/lib/kosapi_client/entity/teacher.rb +14 -0
  25. data/lib/kosapi_client/entity/teacher_timetable_slot.rb +16 -0
  26. data/lib/kosapi_client/entity/timetable_slot.rb +16 -0
  27. data/lib/kosapi_client/hash_utils.rb +17 -0
  28. data/lib/kosapi_client/http_client.rb +36 -0
  29. data/lib/kosapi_client/kosapi_client.rb +45 -0
  30. data/lib/kosapi_client/kosapi_response.rb +32 -0
  31. data/lib/kosapi_client/oauth2_http_adapter.rb +36 -0
  32. data/lib/kosapi_client/request_builder.rb +59 -0
  33. data/lib/kosapi_client/request_builder_delegator.rb +52 -0
  34. data/lib/kosapi_client/resource.rb +12 -0
  35. data/lib/kosapi_client/resource/course_events_builder.rb +13 -0
  36. data/lib/kosapi_client/resource/courses_builder.rb +12 -0
  37. data/lib/kosapi_client/resource/exams_builder.rb +13 -0
  38. data/lib/kosapi_client/resource/parallels_builder.rb +20 -0
  39. data/lib/kosapi_client/resource/teachers_builder.rb +16 -0
  40. data/lib/kosapi_client/resource_mapper.rb +20 -0
  41. data/lib/kosapi_client/response_converter.rb +65 -0
  42. data/lib/kosapi_client/response_links.rb +40 -0
  43. data/lib/kosapi_client/response_preprocessor.rb +48 -0
  44. data/lib/kosapi_client/url_builder.rb +24 -0
  45. data/lib/kosapi_client/version.rb +3 -0
  46. data/spec/integration/course_events_spec.rb +13 -0
  47. data/spec/integration/courses_spec.rb +28 -0
  48. data/spec/integration/exams_spec.rb +20 -0
  49. data/spec/integration/parallels_spec.rb +68 -0
  50. data/spec/kosapi_client/api_client_spec.rb +22 -0
  51. data/spec/kosapi_client/configuration_spec.rb +30 -0
  52. data/spec/kosapi_client/entity/base_entity_spec.rb +20 -0
  53. data/spec/kosapi_client/entity/base_person_spec.rb +19 -0
  54. data/spec/kosapi_client/entity/boolean_spec.rb +23 -0
  55. data/spec/kosapi_client/entity/course_event_spec.rb +30 -0
  56. data/spec/kosapi_client/entity/data_mappings_spec.rb +154 -0
  57. data/spec/kosapi_client/entity/enum_spec.rb +20 -0
  58. data/spec/kosapi_client/entity/id_spec.rb +13 -0
  59. data/spec/kosapi_client/entity/link_spec.rb +89 -0
  60. data/spec/kosapi_client/entity/ml_string_spec.rb +52 -0
  61. data/spec/kosapi_client/entity/parallel_spec.rb +18 -0
  62. data/spec/kosapi_client/entity/result_page_spec.rb +42 -0
  63. data/spec/kosapi_client/entity/teacher_timetable_slot_spec.rb +19 -0
  64. data/spec/kosapi_client/entity/timetable_slot_spec.rb +22 -0
  65. data/spec/kosapi_client/hash_utils_spec.rb +20 -0
  66. data/spec/kosapi_client/http_client_spec.rb +30 -0
  67. data/spec/kosapi_client/kosapi_client_spec.rb +57 -0
  68. data/spec/kosapi_client/kosapi_response_spec.rb +96 -0
  69. data/spec/kosapi_client/oauth2_http_adapter_spec.rb +25 -0
  70. data/spec/kosapi_client/request_builder_delegator_spec.rb +72 -0
  71. data/spec/kosapi_client/request_builder_spec.rb +80 -0
  72. data/spec/kosapi_client/resource/courses_builder_spec.rb +20 -0
  73. data/spec/kosapi_client/resource/parallels_builder_spec.rb +49 -0
  74. data/spec/kosapi_client/resource_mapper_spec.rb +33 -0
  75. data/spec/kosapi_client/response_converter_spec.rb +58 -0
  76. data/spec/kosapi_client/response_links_spec.rb +52 -0
  77. data/spec/kosapi_client/response_preprocessor_spec.rb +51 -0
  78. data/spec/kosapi_client/url_builder_spec.rb +44 -0
  79. data/spec/spec_helper.rb +40 -0
  80. data/spec/support/client_helpers.rb +11 -0
  81. data/spec/support/helpers.rb +7 -0
  82. data/spec/support/shared_examples_for_fluent_api.rb +7 -0
  83. metadata +401 -0
@@ -0,0 +1,22 @@
1
+ require 'spec_helper'
2
+
3
+ describe KOSapiClient::ApiClient do
4
+ subject(:client) { KOSapiClient::ApiClient.new }
5
+
6
+ it 'responds to api resource methods' do
7
+ expect(client).to respond_to :course_events
8
+ end
9
+
10
+ it 'creates default builder when no custom builder is defined' do
11
+ builder = client.create_builder(:foo)
12
+ expect(builder).to be_an_instance_of KOSapiClient::RequestBuilder
13
+ end
14
+
15
+ it 'creates custom builder for resource when defined' do
16
+ class KOSapiClient::Resource::FooBarBuilder < KOSapiClient::RequestBuilder; end
17
+
18
+ builder = client.create_builder(:foo_bar)
19
+ expect(builder).to be_an_instance_of KOSapiClient::Resource::FooBarBuilder
20
+ end
21
+
22
+ end
@@ -0,0 +1,30 @@
1
+ require 'spec_helper'
2
+
3
+ describe KOSapiClient::Configuration do
4
+
5
+ subject(:configuration) { KOSapiClient::Configuration.new }
6
+
7
+ it 'stores client_id' do
8
+ configuration.client_id = 'foo'
9
+ expect(configuration.client_id).to eq 'foo'
10
+ end
11
+
12
+ it 'stores client_secret' do
13
+ configuration.client_secret = 'bar'
14
+ expect(configuration.client_secret).to eq 'bar'
15
+ end
16
+
17
+ describe '#credentials' do
18
+
19
+ it 'returns OAUTH credentials when set' do
20
+ configuration.client_id = 'foo'
21
+ configuration.client_secret = 'bar'
22
+ expect(configuration.credentials).to eq({client_id: 'foo', client_secret: 'bar'})
23
+ end
24
+
25
+ it 'returns empty hash when no credentials set' do
26
+ expect(configuration.credentials).to eq({})
27
+ end
28
+
29
+ end
30
+ end
@@ -0,0 +1,20 @@
1
+ require 'spec_helper'
2
+
3
+ describe KOSapiClient::Entity::BaseEntity do
4
+ let(:attributes) { {atom_id: 'urn:cvut:kos:courseevent:220200484405',
5
+ atom_title: 'This is a title',
6
+ atom_updated: '2010-05-13T09:12:58.0',
7
+ atom_author: {atom_name: 'pochova'},
8
+ atom_link: {rel: 'self', href: 'courseEvents/220200484405/'}
9
+ } }
10
+
11
+
12
+ it 'parses basic attributes' do
13
+ entity = KOSapiClient::Entity::BaseEntity.parse(attributes)
14
+
15
+ expect(entity.id).to eq 'urn:cvut:kos:courseevent:220200484405'
16
+ expect(entity.title).to eq 'This is a title'
17
+ expect(entity.link).to be_an_instance_of KOSapiClient::Entity::Link
18
+ expect(entity.author).to be_an_instance_of KOSapiClient::Entity::Author
19
+ end
20
+ end
@@ -0,0 +1,19 @@
1
+ require 'spec_helper'
2
+
3
+ describe KOSapiClient::Entity::BasePerson do
4
+
5
+ describe '#full_name' do
6
+
7
+ it 'returns whole name with titles' do
8
+ person = described_class.parse(first_name: 'Foo', last_name: 'Bar', titles_pre: 'Ing.', titles_post: 'Ph.D.')
9
+ expect(person.full_name).to eq 'Ing. Foo Bar Ph.D.'
10
+ end
11
+
12
+ it 'skips title if not set' do
13
+ person = described_class.parse(first_name: 'Foo', last_name: 'Bar', titles_pre: 'Ing.')
14
+ expect(person.full_name).to eq 'Ing. Foo Bar'
15
+ end
16
+
17
+ end
18
+
19
+ end
@@ -0,0 +1,23 @@
1
+ require 'spec_helper'
2
+
3
+ describe KOSapiClient::Entity::Boolean do
4
+
5
+ describe '.parse' do
6
+
7
+ subject(:boolean) { described_class }
8
+
9
+ it 'parses true string to true' do
10
+ expect(boolean.parse('true')).to be true
11
+ end
12
+
13
+ it 'parses false string to false' do
14
+ expect(boolean.parse('false')).to be false
15
+ end
16
+
17
+ it 'throws error with invalid string' do
18
+ expect { boolean.parse('invalid') }.to raise_error(RuntimeError)
19
+ end
20
+
21
+ end
22
+
23
+ end
@@ -0,0 +1,30 @@
1
+ require 'spec_helper'
2
+
3
+ describe KOSapiClient::Entity::CourseEvent do
4
+ let('course_event_input') { {atom_id: 'urn:cvut:kos:courseevent:220200484405',
5
+ atom_updated: '2010-05-13T09:12:58.0',
6
+ atom_author: {atom_name: 'pochova'},
7
+ atom_link: {rel: 'self', xlink_href: 'courseEvents/220200484405/'},
8
+ capacity: '70',
9
+ course: {__content__: 'Computer Structure and Architecture',
10
+ xlink_href: 'courses/BI-SAP/'},
11
+ end_date: '2010-05-18T14:01:00',
12
+ name: {__content__: 'test1 oprava', xml_lang: 'cs'},
13
+ occupied: '50',
14
+ room: {__content__: 'TK:PU1', xlink_href: 'rooms/TK:PU1/'},
15
+ semester: {__content__: 'Summer 2009/2010', xlink_href: 'semesters/B092/'},
16
+ signin_deadline: '2010-05-17',
17
+ start_date: '2010-05-18T14:00:00',
18
+ type: ['courseEvent', 'xml']} }
19
+
20
+ it 'parses provided data' do
21
+ course_event = KOSapiClient::Entity::CourseEvent.parse(course_event_input)
22
+ expect(course_event.capacity).to eq 70
23
+ expect(course_event.course).to be_an_instance_of(KOSapiClient::Entity::Link)
24
+ end
25
+
26
+ it 'parses base attributes' do
27
+ course_event = KOSapiClient::Entity::CourseEvent.parse(course_event_input)
28
+ expect(course_event.id).to eq 'urn:cvut:kos:courseevent:220200484405'
29
+ end
30
+ end
@@ -0,0 +1,154 @@
1
+ require 'spec_helper'
2
+
3
+ describe KOSapiClient::Entity::DataMappings do
4
+
5
+ let(:dummy_class) { Class.new { include KOSapiClient::Entity::DataMappings } }
6
+ let(:derived_class) { Class.new(dummy_class) }
7
+ let(:dummy_instance) { dummy_class.new }
8
+
9
+ it 'defines .parse class method' do
10
+ expect(dummy_class).to respond_to(:parse)
11
+ end
12
+
13
+ it 'defines .map_data class method' do
14
+ expect(dummy_class).to respond_to(:map_data)
15
+ end
16
+
17
+ describe '.parse' do
18
+
19
+ it 'parses to string by default' do
20
+ dummy_class.map_data :foo
21
+ parsed = dummy_class.parse({foo: 'bar'})
22
+ expect(parsed).to be_an_instance_of(dummy_class)
23
+ expect(parsed.foo).to eq 'bar'
24
+ end
25
+
26
+ it 'parses integer type' do
27
+ dummy_class.map_data :foo, Integer
28
+ parsed = dummy_class.parse({foo: '1'})
29
+ expect(parsed.foo).to eq 1
30
+ end
31
+
32
+ it 'parses array of types' do
33
+ dummy_class.map_data :foo, [Integer]
34
+ parsed = dummy_class.parse({foo: %w(5 7 11)})
35
+ expect(parsed.foo).to eq [5, 7, 11]
36
+ end
37
+
38
+ it 'parses single item as array when set' do
39
+ dummy_class.map_data :foo, [Integer]
40
+ parsed = dummy_class.parse({foo: '11'})
41
+ expect(parsed.foo).to eq [11]
42
+ end
43
+
44
+ it 'parses custom types' do
45
+ dummy_class.map_data :foo, KOSapiClient::Entity::Enum
46
+ parsed = dummy_class.parse({foo: 'bar'})
47
+ expect(parsed.foo).to eq :bar
48
+ end
49
+
50
+ it 'throws error when required attribute is missing' do
51
+ dummy_class.map_data :foo, String, required: true
52
+ expect { dummy_class.parse({}) }.to raise_error(RuntimeError)
53
+ end
54
+
55
+ it 'sets attribute to nil when not required attribute is missing' do
56
+ dummy_class.map_data :foo, String
57
+ parsed = dummy_class.parse({})
58
+ expect(parsed.foo).to be_nil
59
+ end
60
+
61
+ it 'throws error on type without parse method' do
62
+ dummy_class.map_data :foo, Object
63
+ expect{ dummy_class.parse({foo: 'bar'}) }.to raise_error(RuntimeError)
64
+ end
65
+
66
+ it 'accepts context hash' do
67
+ dummy_class.map_data :foo, KOSapiClient::Entity::Enum
68
+ context = {}
69
+ parsed = dummy_class.parse({foo: 'bar'}, context)
70
+ expect(parsed.foo).to eq :bar
71
+ end
72
+
73
+ it 'parses nil collection as empty array' do
74
+ dummy_class.map_data :foo, [Integer]
75
+ parsed = dummy_class.parse({ })
76
+ expect(parsed.foo).to eq []
77
+ end
78
+
79
+ end
80
+
81
+ describe '.map_data' do
82
+
83
+ it 'maps parent attributes' do
84
+ dummy_class.map_data :foo
85
+ derived_class.map_data :bar
86
+ instance = derived_class.parse({foo: '123', bar: '456'})
87
+ expect(instance).to respond_to(:foo, :bar)
88
+ end
89
+
90
+ it 'does not map child attributes' do
91
+ dummy_class.map_data :foo
92
+ derived_class.map_data :bar
93
+ instance = dummy_class.parse({foo: '123', bar: '456'})
94
+ expect(instance).to respond_to(:foo)
95
+ expect(instance).not_to respond_to(:bar)
96
+ end
97
+
98
+
99
+ it 'supports namespace configuration' do
100
+ dummy_class.map_data :foo, String, namespace: :bar
101
+ instance = dummy_class.parse({bar_foo: '123', bar: '456'})
102
+ expect(instance.foo).to eq '123'
103
+ end
104
+
105
+ it 'supports source element name configuration' do
106
+ dummy_class.map_data :foo, String, element: :bar
107
+ instance = dummy_class.parse({bar: '123'})
108
+ expect(instance.foo).to eq '123'
109
+ end
110
+
111
+ end
112
+
113
+ describe '#to_hash' do
114
+
115
+ it 'converts mapped attributes to a hash' do
116
+ dummy_class.map_data :foo
117
+ instance = dummy_class.parse({foo: 'bar'})
118
+ expect(instance.to_hash).to eq({foo: 'bar'})
119
+ end
120
+
121
+ it 'converts class hierarchy attributes to a hash' do
122
+ dummy_class.map_data :foo
123
+ derived_class.map_data :bar
124
+ instance = derived_class.parse({foo: '123', bar: '456'})
125
+ expect(instance.to_hash).to eq({foo: '123', bar: '456'})
126
+ end
127
+
128
+ it 'converts array to a hash' do
129
+ dummy_class.map_data :foo, [Integer]
130
+ instance = dummy_class.parse({foo: %w(123 456)})
131
+ expect(instance.to_hash).to eq({foo: [123, 456]})
132
+ end
133
+
134
+ it 'converts nested instances' do
135
+ dummy_class.map_data :foo
136
+ instance = dummy_class.new()
137
+ instance2 = dummy_class.new()
138
+ instance.foo = instance2
139
+ instance2.foo = 'bar'
140
+ expect(instance.to_hash).to eq({foo: {foo: 'bar'}})
141
+ end
142
+
143
+ it 'converts array of nested instances' do
144
+ dummy_class.map_data :foo
145
+ instance = dummy_class.new()
146
+ instance2 = dummy_class.new()
147
+ instance.foo = [instance2]
148
+ instance2.foo = 'bar'
149
+ expect(instance.to_hash).to eq({foo: [{foo: 'bar'}]})
150
+ end
151
+
152
+ end
153
+
154
+ end
@@ -0,0 +1,20 @@
1
+ require 'spec_helper'
2
+
3
+ describe KOSapiClient::Entity::Enum do
4
+
5
+ Enum = KOSapiClient::Entity::Enum
6
+
7
+ describe '.parse' do
8
+
9
+ it 'parses a string to a symbol' do
10
+ res = Enum.parse('foo')
11
+ expect(res).to eq :foo
12
+ end
13
+
14
+ it 'downcases the string before converting to a symbol' do
15
+ res = Enum.parse('FOO')
16
+ expect(res).to eq :foo
17
+ end
18
+
19
+ end
20
+ end
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+
3
+ describe KOSapiClient::Entity::Id do
4
+
5
+ describe '.parse' do
6
+
7
+ it 'parses id from string' do
8
+ id = described_class.parse('urn:cvut:kos:parallel:10160605')
9
+ expect(id).to eq '10160605'
10
+ end
11
+ end
12
+
13
+ end
@@ -0,0 +1,89 @@
1
+ require 'spec_helper'
2
+
3
+ describe KOSapiClient::Entity::Link do
4
+
5
+ Link = KOSapiClient::Entity::Link
6
+
7
+ let(:client) { instance_double(KOSapiClient::HTTPClient) }
8
+ subject(:link) { Link.parse({href: 'http://example.com/foo/bar/42', __content__: 'Example Site', rel: 'next'}) }
9
+ let(:result) { double(:result, foo: :bar) }
10
+ before(:example) { link.inject_client(client) }
11
+
12
+ describe '.parse' do
13
+
14
+ it 'can be parsed from a hash' do
15
+ expect(link.link_href).to eq 'http://example.com/foo/bar/42'
16
+ expect(link.link_title).to eq 'Example Site'
17
+ expect(link.link_rel).to eq 'next'
18
+ end
19
+
20
+ end
21
+
22
+ describe '#initialize' do
23
+
24
+ it 'encodes href URL' do
25
+ href = 'parallels?query=(lastUpdatedDate%3E=2014-07-01T00:00:00;lastUpdatedDate%3C=2014-07-10T00:00:00)&offset=10&limit=10'
26
+ link = Link.new(nil, href, nil)
27
+ expect(link.link_href).to eq 'parallels?query=(lastUpdatedDate%3E=2014-07-01T00:00:00%3BlastUpdatedDate%3C=2014-07-10T00:00:00)&offset=10&limit=10'
28
+ end
29
+
30
+ end
31
+
32
+ describe '#link_id' do
33
+
34
+ it 'returns last href segment' do
35
+ expect(link.link_id).to eq '42'
36
+ end
37
+
38
+ end
39
+
40
+ describe '#follow' do
41
+
42
+ it 'throws error when not http client set' do
43
+ link.inject_client(nil)
44
+ expect { link.follow }.to raise_error(RuntimeError)
45
+ end
46
+
47
+ it 'calls http client with href' do
48
+ expect(client).to receive(:send_request).with(:get, 'http://example.com/foo/bar/42')
49
+ link.follow
50
+ end
51
+
52
+ end
53
+
54
+ describe '#method_missing?' do
55
+
56
+ it 'calls follow when method not defined' do
57
+ expect(link).to receive(:follow)
58
+ expect { link.foo }.to raise_error(NoMethodError)
59
+ end
60
+
61
+ it 'delegates missing methods to returned object' do
62
+ expect(result).to receive(:foo).and_return(:bar)
63
+ allow(link).to receive(:follow).and_return(result)
64
+ expect(link.foo).to eq :bar
65
+ end
66
+
67
+ it 'caches returned object' do
68
+ expect(link).to receive(:follow).once.and_return(result)
69
+ 2.times { link.foo }
70
+ end
71
+
72
+ end
73
+
74
+ describe '#respond_to_missing?' do
75
+
76
+ it 'responds to target object methods' do
77
+ allow(link).to receive(:follow).and_return(double(foo: :bar))
78
+ expect(link).to respond_to(:foo)
79
+ end
80
+ end
81
+
82
+ describe '#to_hash' do
83
+ it 'converts link attributes to hash' do
84
+ expect(link.to_hash).to eq({href: 'http://example.com/foo/bar/42', title: 'Example Site', rel: 'next'})
85
+ end
86
+
87
+ end
88
+
89
+ end
@@ -0,0 +1,52 @@
1
+ require 'spec_helper'
2
+
3
+ describe KOSapiClient::Entity::MLString do
4
+
5
+ MLString = described_class
6
+
7
+ def translations
8
+ @translations || {en: 'Lorem Ipsum', cs: 'Foo'}
9
+ end
10
+
11
+ let(:mlstring) { MLString.new(translations) }
12
+
13
+ describe '.parse' do
14
+
15
+ it 'parses itself from a hash' do
16
+ str = MLString.parse({xml_lang: :en, __content__: 'Lorem Ipsum'})
17
+ expect(str.translations).to eq({en: 'Lorem Ipsum'})
18
+ end
19
+
20
+ end
21
+
22
+ describe '#to_s' do
23
+
24
+ it 'returns translation specified in parameter when present' do
25
+ expect(mlstring.to_s(:cs)).to eq 'Foo'
26
+ end
27
+
28
+ it 'returns nil when specified language not present' do
29
+ expect(mlstring.to_s(:sk)).to be_nil
30
+ end
31
+
32
+ it 'returns translation in default language when language not specified' do
33
+ expect(mlstring.to_s).to eq 'Lorem Ipsum'
34
+ end
35
+
36
+ it 'returns first translation when default default language not present' do
37
+ @translations = {cs: 'Foo', sk: 'Bar'}
38
+ expect(mlstring.to_s).to eq 'Foo'
39
+ end
40
+
41
+ end
42
+
43
+ describe 'default language' do
44
+
45
+ it 'can set default language in initialize' do
46
+ str = MLString.new(translations, :cs)
47
+ expect(str.to_s).to eq 'Foo'
48
+ end
49
+
50
+ end
51
+
52
+ end