tin_can_api 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +24 -0
  3. data/.rspec +2 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE.txt +22 -0
  6. data/README.md +80 -0
  7. data/Rakefile +12 -0
  8. data/lib/tin_can_api/about.rb +15 -0
  9. data/lib/tin_can_api/activity.rb +41 -0
  10. data/lib/tin_can_api/activity_definition.rb +139 -0
  11. data/lib/tin_can_api/agent.rb +44 -0
  12. data/lib/tin_can_api/agent_account.rb +33 -0
  13. data/lib/tin_can_api/attachment.rb +64 -0
  14. data/lib/tin_can_api/client.rb +402 -0
  15. data/lib/tin_can_api/context.rb +54 -0
  16. data/lib/tin_can_api/context_activities.rb +102 -0
  17. data/lib/tin_can_api/documents/activity_profile_document.rb +15 -0
  18. data/lib/tin_can_api/documents/agent_profile_document.rb +15 -0
  19. data/lib/tin_can_api/documents/document.rb +20 -0
  20. data/lib/tin_can_api/documents/state_document.rb +15 -0
  21. data/lib/tin_can_api/enum.rb +42 -0
  22. data/lib/tin_can_api/errors.rb +9 -0
  23. data/lib/tin_can_api/group.rb +37 -0
  24. data/lib/tin_can_api/interaction_component.rb +32 -0
  25. data/lib/tin_can_api/interaction_type.rb +58 -0
  26. data/lib/tin_can_api/lrs_response.rb +14 -0
  27. data/lib/tin_can_api/query_result_format.rb +6 -0
  28. data/lib/tin_can_api/remote_lrs.rb +15 -0
  29. data/lib/tin_can_api/result.rb +45 -0
  30. data/lib/tin_can_api/score.rb +39 -0
  31. data/lib/tin_can_api/statement.rb +53 -0
  32. data/lib/tin_can_api/statement_ref.rb +31 -0
  33. data/lib/tin_can_api/statements/statements_base.rb +70 -0
  34. data/lib/tin_can_api/statements_query.rb +42 -0
  35. data/lib/tin_can_api/statements_query_v095.rb +42 -0
  36. data/lib/tin_can_api/statements_result.rb +17 -0
  37. data/lib/tin_can_api/sub_statement.rb +19 -0
  38. data/lib/tin_can_api/tcapi_version.rb +27 -0
  39. data/lib/tin_can_api/verb.rb +35 -0
  40. data/lib/tin_can_api/version.rb +4 -0
  41. data/lib/tin_can_api.rb +37 -0
  42. data/spec/fixtures/about.json +10 -0
  43. data/spec/fixtures/statement.json +33 -0
  44. data/spec/spec_helper.rb +106 -0
  45. data/spec/support/helpers.rb +43 -0
  46. data/spec/tin_can_api/activity_definition_spec.rb +37 -0
  47. data/spec/tin_can_api/activity_spec.rb +23 -0
  48. data/spec/tin_can_api/agent_account_spec.rb +13 -0
  49. data/spec/tin_can_api/agent_spec.rb +24 -0
  50. data/spec/tin_can_api/attachment_spec.rb +26 -0
  51. data/spec/tin_can_api/client_spec.rb +44 -0
  52. data/spec/tin_can_api/context_activities_spec.rb +57 -0
  53. data/spec/tin_can_api/context_spec.rb +32 -0
  54. data/spec/tin_can_api/group_spec.rb +15 -0
  55. data/spec/tin_can_api/interaction_component_spec.rb +18 -0
  56. data/spec/tin_can_api/result_spec.rb +26 -0
  57. data/spec/tin_can_api/score_spec.rb +12 -0
  58. data/spec/tin_can_api/statement_ref_spec.rb +19 -0
  59. data/spec/tin_can_api/statement_spec.rb +57 -0
  60. data/spec/tin_can_api/sub_statement_spec.rb +30 -0
  61. data/spec/tin_can_api/verb_spec.rb +17 -0
  62. data/tin_can_api.gemspec +30 -0
  63. metadata +238 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: d896c743e9aa76b46e6e9ae50850de428a5839a6
4
+ data.tar.gz: 10d4216bb0f21b333a23791c63ff8807f0b95dff
5
+ SHA512:
6
+ metadata.gz: 236685666c862527a6cd11a365d8f1eef97bf079fbb8cc3b225ec99ce0412561366922ab25bdf0138a01cd29fb267f08c2b113190b71e0c69eedea7b3f482764
7
+ data.tar.gz: 1ac0a3b83e6aa3fca486a082ada827703db11dc88311eedf17089303388d1c9820a250f5c88590da9661e45fc9889f13cf73c6292afb9b15fa4fca89dc31f7f2
data/.gitignore ADDED
@@ -0,0 +1,24 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
15
+
16
+ # RubyMine
17
+ .idea/*
18
+
19
+ # rvm
20
+ .ruby-version
21
+ .ruby-gemset
22
+
23
+
24
+ examples
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in tin_can_api.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Paul Coleman
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,80 @@
1
+ # TinCanApi
2
+
3
+ A Ruby library for implementing Tin Can API (Experience API).
4
+
5
+ For more information about the Tin Can API visit:
6
+
7
+ http://tincanapi.com/
8
+
9
+ ## Warning
10
+
11
+ Please regard this as alpha software. It was created to solve an urgent problem and has not been fully tested in a live environment.
12
+
13
+ ## Installation
14
+
15
+ Add this line to your application's Gemfile:
16
+
17
+ ```ruby
18
+ gem 'tin_can_api'
19
+ ```
20
+
21
+ And then execute:
22
+
23
+ $ bundle
24
+
25
+ Or install it yourself as:
26
+
27
+ $ gem install tin_can_api
28
+
29
+ ## Usage
30
+
31
+ Create a client using basic auth
32
+ ```ruby
33
+ client = TinCanApi::Client.new do |c|
34
+ c.end_point = 'https://some.endpoint.com'
35
+ c.user_name = 'user'
36
+ c.password = 'password'
37
+ end
38
+ ```
39
+
40
+ Connect to the 'about' endpoint to get version information
41
+
42
+ ```ruby
43
+ # use the client from above
44
+ response = client.about
45
+ # check if it is successful
46
+ if response.success
47
+ # access the TinCanApi::About instance
48
+ response.content
49
+ end
50
+ ```
51
+
52
+ Create a statement
53
+
54
+ ```ruby
55
+ agent = TinCanApi::Agent.new(mbox: 'mailto:info@tincanapi.com')
56
+ verb = TinCanApi::Verb.new(id: 'http://adlnet.gov/expapi/verbs/attempted')
57
+ activity = TinCanApi::Activity.new(id: 'http://pwcoleman.github.com/TinCanRuby')
58
+
59
+ statement = TinCanApi::Statement.new do |s|
60
+ s.actor = agent
61
+ s.verb = verb
62
+ s.object = activity
63
+ end
64
+
65
+ response = client.save_statement(statement)
66
+ if response.success
67
+ # access the statement
68
+ response.content
69
+ end
70
+ ```
71
+
72
+ For more API calls check out the TinCanApi::Client class
73
+
74
+ ## Contributing
75
+
76
+ 1. Fork it ( https://github.com/pwcoleman/tin_can_api/fork )
77
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
78
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
79
+ 4. Push to the branch (`git push origin my-new-feature`)
80
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task default: :spec
7
+
8
+ task :console do
9
+ exec "irb -r tin_can_api -I ./lib"
10
+ end
11
+
12
+
@@ -0,0 +1,15 @@
1
+ # encoding: utf-8
2
+ module TinCanApi
3
+ class About
4
+ attr_accessor :versions, :extensions
5
+
6
+ def initialize(options={})
7
+ json = options.fetch(:json, nil)
8
+ if json
9
+ attributes = JSON.parse(json)
10
+ @versions = attributes['version'] if attributes['version']
11
+ @extensions = attributes['extensions'] if attributes['extensions']
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,41 @@
1
+ # encoding: utf-8
2
+ module TinCanApi
3
+ # Activity model class
4
+ class Activity
5
+
6
+ attr_accessor :object_type, :definition
7
+ attr_reader :id
8
+
9
+ def initialize(options={}, &block)
10
+ @object_type = 'Activity'
11
+ json = options.fetch(:json, nil)
12
+ if json
13
+ attributes = JSON.parse(json)
14
+ self.id = Addressable::URI.parse(attributes['id']) if attributes['id']
15
+ self.definition = ActivityDefinition.new(json: attributes['definition'].to_json) if attributes['definition']
16
+ else
17
+ self.id = options.fetch(:id, nil)
18
+ self.definition = options.fetch(:definition, nil)
19
+ if block_given?
20
+ block[self]
21
+ end
22
+ end
23
+ end
24
+
25
+ def id=(value)
26
+ if value.is_a?(String)
27
+ @id = Addressable::URI.parse(value)
28
+ else
29
+ @id = value
30
+ end
31
+ end
32
+
33
+ def serialize(version)
34
+ node = {}
35
+ node['id'] = id.to_s if id
36
+ node['definition'] = definition.serialize(version) if definition
37
+ node
38
+ end
39
+
40
+ end
41
+ end
@@ -0,0 +1,139 @@
1
+ # encoding: utf-8
2
+ module TinCanApi
3
+ # Activity Definition model class
4
+ class ActivityDefinition
5
+ include TinCanApi::InteractionType
6
+
7
+ attr_accessor :name, :description, :extensions, :interaction_type, :correct_responses_pattern
8
+ attr_accessor :choices, :scale, :source, :target, :steps
9
+ attr_reader :type, :more_info
10
+
11
+ def initialize(options={}, &block)
12
+ json = options.fetch(:json, nil)
13
+ if json
14
+ attributes = JSON.parse(json)
15
+ self.type = attributes['type'] if attributes['type']
16
+ self.more_info = attributes['moreInfo'] if attributes['moreInfo']
17
+ self.name = attributes['name'] if attributes['name']
18
+ self.description = attributes['description'] if attributes['description']
19
+ self.extensions = attributes['extensions'] if attributes['extensions']
20
+ self.interaction_type = attributes['interactionType'] if attributes['interactionType']
21
+
22
+ if attributes['correctResponsesPattern']
23
+ self.correct_responses_pattern = []
24
+ attributes['correctResponsesPattern'].each do |pattern|
25
+ correct_responses_pattern << pattern
26
+ end
27
+ end
28
+
29
+ if attributes['choices']
30
+ self.choices = []
31
+ attributes['choices'].each do |choice|
32
+ choices << InteractionComponent.new(choice.to_json)
33
+ end
34
+ end
35
+
36
+ if attributes['scale']
37
+ self.scale = []
38
+ attributes['scale'].each do |element|
39
+ scale << InteractionComponent.new(element.to_json)
40
+ end
41
+ end
42
+
43
+ if attributes['source']
44
+ self.source = []
45
+ attributes['source'].each do |element|
46
+ source << InteractionComponent.new(element.to_json)
47
+ end
48
+ end
49
+
50
+ if attributes['target']
51
+ self.target = []
52
+ attributes['target'].each do |element|
53
+ target << InteractionComponent.new(element.to_json)
54
+ end
55
+ end
56
+
57
+ if attributes['steps']
58
+ self.steps = []
59
+ attributes['steps'].each do |element|
60
+ steps << InteractionComponent.new(element.to_json)
61
+ end
62
+ end
63
+
64
+ else
65
+ self.name = options.fetch(:name, nil)
66
+ self.description = options.fetch(:description, nil)
67
+ self.extensions = options.fetch(:extensions, nil)
68
+ self.interaction_type = options.fetch(:interaction_type, nil)
69
+ self.correct_responses_pattern = options.fetch(:correct_responses_pattern, nil)
70
+ self.choices = options.fetch(:choices, nil)
71
+ self.scale = options.fetch(:scale, nil)
72
+ self.source = options.fetch(:source, nil)
73
+ self.target = options.fetch(:target, nil)
74
+ self.type = options.fetch(:type, nil)
75
+ self.more_info = options.fetch(:more_info, nil)
76
+
77
+ if block_given?
78
+ block[self]
79
+ end
80
+ end
81
+ end
82
+
83
+ def type=(value)
84
+ if value.is_a?(String)
85
+ @type = Addressable::URI.parse(value)
86
+ else
87
+ @type = value
88
+ end
89
+ end
90
+
91
+ def more_info=(value)
92
+ if value.is_a?(String)
93
+ @more_info = Addressable::URI.parse(value)
94
+ else
95
+ @more_info = value
96
+ end
97
+ end
98
+
99
+ def serialize(version)
100
+ node = {}
101
+ node['name'] = name if name
102
+ node['description'] = description if description
103
+ node['type'] = type.to_s if type
104
+ node['moreInfo'] = more_info.to_s if more_info
105
+ node['extensions'] = extensions if extensions
106
+ if interaction_type
107
+ node['interactionType'] = interaction_type.to_s
108
+ case interaction_type
109
+ when TinCanApi::InteractionType::CHOICE.to_s, TinCanApi::InteractionType::SEQUENCING.to_s
110
+ if choices && choices.any?
111
+ node['choices'] = choices.map {|element| element.serialize(version)}
112
+ end
113
+ when TinCanApi::InteractionType::LIKERT.to_s
114
+ if scale && scale.any?
115
+ node['scale'] = scale.map {|element| element.serialize(version)}
116
+ end
117
+ when TinCanApi::InteractionType::MATCHING.to_s
118
+ if source && source.any?
119
+ node['source'] = source.map {|element| element.serialize(version)}
120
+ end
121
+ if target && target.any?
122
+ node['target'] = target.map {|element| element.serialize(version)}
123
+ end
124
+ when TinCanApi::InteractionType::PERFORMANCE.to_s
125
+ if steps && steps.any?
126
+ node['steps'] = steps.map {|element| element.serialize(version)}
127
+ end
128
+ end
129
+ end
130
+
131
+ if correct_responses_pattern && correct_responses_pattern.any?
132
+ node['correctResponsesPattern'] = correct_responses_pattern.map {|element| element}
133
+ end
134
+
135
+ node
136
+ end
137
+
138
+ end
139
+ end
@@ -0,0 +1,44 @@
1
+ # encoding: utf-8
2
+ require 'tin_can_api/tcapi_version'
3
+ module TinCanApi
4
+ # Agent model class
5
+ class Agent
6
+
7
+ attr_accessor :name, :mbox, :mbox_sha1_sum, :open_id, :account, :object_type
8
+
9
+ def initialize(options={}, &block)
10
+ @object_type = 'Agent'
11
+ json = options.fetch(:json, nil)
12
+ if json
13
+ attributes = JSON.parse(json)
14
+ self.name = attributes['name'] if attributes['name']
15
+ self.mbox = attributes['mbox'] if attributes['mbox']
16
+ self.mbox_sha1_sum = attributes['mbox_sha1sum'] if attributes['mbox_sha1sum']
17
+ self.open_id = attributes['openid'] if attributes['openid']
18
+ self.account = AgentAccount.new(json: attributes['account'].to_json) if attributes['account']
19
+ else
20
+ self.name = options.fetch(:name, nil)
21
+ self.mbox = options.fetch(:mbox, nil)
22
+ self.mbox_sha1_sum = options.fetch(:mbox_sha1_sum, nil)
23
+ self.open_id = options.fetch(:open_id, nil)
24
+ self.account = options.fetch(:account, nil)
25
+
26
+ if block_given?
27
+ block[self]
28
+ end
29
+ end
30
+ end
31
+
32
+ def serialize(version)
33
+ node = {}
34
+ node['objectType'] = object_type
35
+ node['name'] = name if name
36
+ node['mbox'] = mbox if mbox
37
+ node['mbox_sha1sum'] = mbox_sha1_sum if mbox_sha1_sum
38
+ node['openid'] = open_id if open_id
39
+ node['account'] = account.serialize(version) if account
40
+ node
41
+ end
42
+
43
+ end
44
+ end
@@ -0,0 +1,33 @@
1
+ # encoding: utf-8
2
+ require 'json'
3
+ module TinCanApi
4
+ # Agent Account model class
5
+ class AgentAccount
6
+
7
+ attr_accessor :home_page, :name
8
+
9
+ def initialize(options={}, &block)
10
+ json = options.fetch(:json, nil)
11
+ if json
12
+ attributes = JSON.parse(json)
13
+ self.name = attributes['name'] if attributes['name']
14
+ self.home_page = attributes['homePage'] if attributes['homePage']
15
+ else
16
+ self.home_page = options.fetch(:home_page, nil)
17
+ self.name =options.fetch(:name, nil)
18
+
19
+ if block_given?
20
+ block[self]
21
+ end
22
+ end
23
+ end
24
+
25
+ def serialize(version)
26
+ node = {}
27
+ node['name'] = name if name
28
+ node['homePage'] = home_page if home_page
29
+ node
30
+ end
31
+
32
+ end
33
+ end
@@ -0,0 +1,64 @@
1
+ # encoding: utf-8
2
+ module TinCanApi
3
+ # Attachment Class
4
+ class Attachment
5
+
6
+ attr_accessor :display, :description, :content_type, :length, :sha2
7
+ attr_reader :usage_type, :file_url
8
+
9
+ def initialize(options={}, &block)
10
+ json = options.fetch(:json, nil)
11
+ if json
12
+ attributes = JSON.parse(json)
13
+ self.usage_type = attributes['usageType'] if attributes['usageType']
14
+ self.display = attributes['display'] if attributes['display']
15
+ self.description = attributes['description'] if attributes['description']
16
+ self.content_type = attributes['contentType'] if attributes['contentType']
17
+ self.length = attributes['length'] if attributes['length']
18
+ self.sha2 = attributes['sha2'] if attributes['sha2']
19
+ self.file_url = attributes['fileUrl'] if attributes['fileUrl']
20
+ else
21
+ self.usage_type = options.fetch(:usage_type, nil)
22
+ self.display = options.fetch(:display, nil)
23
+ self.description = options.fetch(:description, nil)
24
+ self.content_type = options.fetch(:content_type, nil)
25
+ self.length = options.fetch(:length, nil)
26
+ self.sha2 = options.fetch(:sha2, nil)
27
+ self.file_url = options.fetch(:file_url, nil)
28
+
29
+ if block_given?
30
+ block[self]
31
+ end
32
+ end
33
+ end
34
+
35
+ def usage_type=(value)
36
+ if value.is_a?(String)
37
+ @usage_type = Addressable::URI.parse(value)
38
+ else
39
+ @usage_type = value
40
+ end
41
+ end
42
+
43
+ def file_url=(value)
44
+ if value.is_a?(String)
45
+ @file_url = Addressable::URI.parse(value)
46
+ else
47
+ @file_url = value
48
+ end
49
+ end
50
+
51
+ def serialize(version)
52
+ node = {}
53
+ node['usageType'] = usage_type.to_s if usage_type
54
+ node['display'] = display if display
55
+ node['description'] = description if description
56
+ node['contentType'] = content_type if content_type
57
+ node['length'] = length if length
58
+ node['sha2'] = sha2 if sha2
59
+ node['fileUrl'] = file_url.to_s if file_url
60
+ node
61
+ end
62
+
63
+ end
64
+ end