ims_caliper 0.1.1
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 +15 -0
- data/Gemfile +13 -0
- data/Gemfile.lock +16 -0
- data/README.md +16 -0
- data/caliper.gemspec +26 -0
- data/config/locales/en.yml +86 -0
- data/lib/caliper/client.rb +33 -0
- data/lib/caliper/consumer/base.rb +46 -0
- data/lib/caliper/consumer/queue.rb +40 -0
- data/lib/caliper/consumer/socket.rb +132 -0
- data/lib/caliper/defaults.rb +8 -0
- data/lib/caliper/entities/annotation/annotation.rb +29 -0
- data/lib/caliper/entities/annotation/bookmark_annotation.rb +17 -0
- data/lib/caliper/entities/annotation/highlight_annotation.rb +18 -0
- data/lib/caliper/entities/annotation/shared_annotation.rb +18 -0
- data/lib/caliper/entities/annotation/tag_annotation.rb +17 -0
- data/lib/caliper/entities/annotation/text_position_selector.rb +14 -0
- data/lib/caliper/entities/digital_resource.rb +52 -0
- data/lib/caliper/entities/entity.rb +44 -0
- data/lib/caliper/entities/foaf/agent.rb +12 -0
- data/lib/caliper/entities/generatable.rb +9 -0
- data/lib/caliper/entities/learning_context.rb +21 -0
- data/lib/caliper/entities/lis/course_section.rb +18 -0
- data/lib/caliper/entities/lis/organization.rb +22 -0
- data/lib/caliper/entities/lis/person.rb +12 -0
- data/lib/caliper/entities/outcome/result.rb +23 -0
- data/lib/caliper/entities/reading/epub_chapter.rb +20 -0
- data/lib/caliper/entities/reading/epub_part.rb +20 -0
- data/lib/caliper/entities/reading/epub_sub_chapter.rb +20 -0
- data/lib/caliper/entities/reading/epub_volume.rb +20 -0
- data/lib/caliper/entities/reading/frame.rb +32 -0
- data/lib/caliper/entities/schemadotorg/audio_object.rb +15 -0
- data/lib/caliper/entities/schemadotorg/creative_work.rb +12 -0
- data/lib/caliper/entities/schemadotorg/image_object.rb +15 -0
- data/lib/caliper/entities/schemadotorg/media_object.rb +19 -0
- data/lib/caliper/entities/schemadotorg/software_application.rb +11 -0
- data/lib/caliper/entities/schemadotorg/thing.rb +9 -0
- data/lib/caliper/entities/schemadotorg/video_object.rb +15 -0
- data/lib/caliper/entities/schemadotorg/web_page.rb +11 -0
- data/lib/caliper/entities/session.rb +26 -0
- data/lib/caliper/entities/software_application.rb +19 -0
- data/lib/caliper/entities/targetable.rb +12 -0
- data/lib/caliper/entities/web_page.rb +13 -0
- data/lib/caliper/event/.shared.rb.swp +0 -0
- data/lib/caliper/event/annotation_event.rb +14 -0
- data/lib/caliper/event/event.rb +68 -0
- data/lib/caliper/event/media_event.rb +19 -0
- data/lib/caliper/event/navigation_event.rb +23 -0
- data/lib/caliper/event/outcome_event.rb +20 -0
- data/lib/caliper/event/session_event.rb +21 -0
- data/lib/caliper/event/view_event.rb +20 -0
- data/lib/caliper/options.rb +18 -0
- data/lib/caliper/profiles/annotation_profile.rb +61 -0
- data/lib/caliper/profiles/profile.rb +46 -0
- data/lib/caliper/profiles/reading_profile.rb +36 -0
- data/lib/caliper/profiles/session_profile.rb +29 -0
- data/lib/caliper/request/event_store_envelope.rb +9 -0
- data/lib/caliper/request/event_store_requestor.rb +41 -0
- data/lib/caliper/request/http_requestor.rb +42 -0
- data/lib/caliper/sensor.rb +37 -0
- data/lib/caliper/stats/atomic_wrapper.rb +86 -0
- data/lib/caliper/stats/statistic.rb +104 -0
- data/lib/caliper/stats/statistics.rb +45 -0
- data/lib/caliper/stats/statistics_map.rb +39 -0
- data/lib/caliper/validators/error_message.rb +43 -0
- data/lib/caliper/validators/event_validator.rb +37 -0
- data/lib/caliper/validators/event_validator_context.rb +16 -0
- data/lib/caliper/validators/property_type_check.rb +14 -0
- data/lib/caliper/validators/session_login_event_validator.rb +103 -0
- data/lib/caliper/validators/session_logout_event_validator.rb +102 -0
- data/lib/caliper/validators/time_check.rb +30 -0
- data/lib/caliper/version.rb +4 -0
- data/lib/caliper.rb +17 -0
- data/spec/lib/client_spec.rb +35 -0
- data/spec/lib/consumer/base_spec.rb +28 -0
- data/spec/lib/consumer/queue_spec.rb +16 -0
- data/spec/lib/event/annotation_spec.rb +12 -0
- data/spec/lib/event/bookmarked_spec.rb +17 -0
- data/spec/lib/event/commented_spec.rb +19 -0
- data/spec/lib/event/highlighted_spec.rb +18 -0
- data/spec/lib/event/navigation_spec.rb +15 -0
- data/spec/lib/event/shared_spec.rb +18 -0
- data/spec/lib/event/tagged_spec.rb +17 -0
- data/spec/lib/event/used_spec.rb +15 -0
- data/spec/lib/event/viewed_spec.rb +15 -0
- data/spec/spec_helper.rb +26 -0
- data/test/caliper/events/session_login_event_test.rb +58 -0
- data/test/caliper/events/session_logout_event_test.rb +55 -0
- data/test/caliper/events/session_timeout_event_test.rb +55 -0
- data/test/caliper/request/http_requestor_test.rb +59 -0
- data/test/caliper/test_event.rb +53 -0
- data/test/caliper/test_utils.rb +198 -0
- data/test/fixtures/caliper_session_login_event.json +71 -0
- data/test/fixtures/caliper_session_logout_event.json +52 -0
- data/test/fixtures/caliper_session_timeout_event.json +52 -0
- data/test/fixtures/event_store_payload.json +85 -0
- metadata +165 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
ZDI0ZGY4YjFhMTE3M2NkYWMxNGNiMDA5OGViMWMzZjcwYzNmZTdkNQ==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
ODk5NGZlMTBiZjdjZTM0N2U0ZjZhMDFhY2VlZWFjYWNhNDNjMjE2MQ==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
MTA3OTY1NjE2ZTMxNTQ1ODFiYzI4MWYzMmQ3ODJiZjM5MGRiN2FkZjRiMTQ3
|
10
|
+
OTUzNDJjZjMwMzUyNGRiNDY3MGViN2UwMWM5OGJlMjg0YTNjNmI5NTBlMzAx
|
11
|
+
ODg1ODVlZWIyZWY5NjUwNzMwZTJjMGI2YmM5ODA5OGU4OTUxMTI=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
ZjNmNzBjZjg3ZTYwYjQ3YWZhODNiM2RlMWNhOGM0N2Y1ZTY0MzJlMTA4NmUz
|
14
|
+
NmFmNWEwNWVmOTAzZTVlZWYwYmIyZDNiNDc2NDlkMDlkNDdhNDc5OGZmYTA0
|
15
|
+
ZmQ4YWNlNDVjOGUyNDJkOTNlYzU0NWU1NGZiOThmZTUxZWRkNWM=
|
data/Gemfile
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
source "https://rubygems.org"
|
2
|
+
|
3
|
+
# Declare your gem's dependencies in open_data_export.gemspec.
|
4
|
+
# Bundler will treat runtime dependencies like base dependencies, and
|
5
|
+
# development dependencies will be added by default to the :development group.
|
6
|
+
|
7
|
+
# the atomic lib
|
8
|
+
gem 'atomic', '~> 1.1.99'
|
9
|
+
|
10
|
+
# translation and localization
|
11
|
+
gem 'i18n'
|
12
|
+
|
13
|
+
gem 'test-unit'
|
data/Gemfile.lock
ADDED
data/README.md
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
caliper-ruby
|
2
|
+
===================
|
3
|
+
|
4
|
+
caliper-ruby is a Ruby client for [Caliper](http://www.imsglobal.org) that provides a Ruby implementation of the Caliper Sensor API
|
5
|
+
|
6
|
+
## generate the Ruby Gem
|
7
|
+
|
8
|
+
gem build caliper.gemspec
|
9
|
+
|
10
|
+
=============
|
11
|
+
Use Ruby Style Guide:
|
12
|
+
|
13
|
+
|
14
|
+
https://github.com/styleguide/ruby
|
15
|
+
|
16
|
+
https://github.com/bbatsov/ruby-style-guide
|
data/caliper.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
$:.push File.expand_path("../lib", __FILE__)
|
2
|
+
|
3
|
+
require 'caliper/version'
|
4
|
+
Gem::Specification.new do |g|
|
5
|
+
g.name = "ims_caliper"
|
6
|
+
g.version = Caliper::VERSION
|
7
|
+
g.authors = ["Anthus Williams", "Zhen Qian"]
|
8
|
+
g.email = ["aj@instructure.com", "zqian@umich.edu"]
|
9
|
+
g.homepage = "https://github.com/IMSGlobal/caliper-ruby"
|
10
|
+
g.summary = "Caliper Sensor API"
|
11
|
+
g.description = "This is the implementation of IMSGlobal Caliper in Ruby"
|
12
|
+
g.license = "http://www.imsglobal.org/copyright.html"
|
13
|
+
|
14
|
+
#g.files = Dir["{app,config,db,lib}/**/*", "Rakefile"]
|
15
|
+
g.files = `git ls-files`.split($\)
|
16
|
+
g.executables = g.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
17
|
+
g.test_files = g.files.grep(%r{^(test|spec|features)/})
|
18
|
+
g.require_path = 'lib'
|
19
|
+
|
20
|
+
#g.add_dependency "activesupport", '~> 0'
|
21
|
+
#g.add_development_dependency "rspec", '~> 0'
|
22
|
+
#g.add_development_dependency "simplecov", '~> 0'
|
23
|
+
#g.add_development_dependency "simplecov-rcov", '~> 0'
|
24
|
+
#g.add_development_dependency "mocha", '~> 0'
|
25
|
+
#g.add_development_dependency 'atomic', '~> 1.1.99'
|
26
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
en:
|
2
|
+
actions:
|
3
|
+
annotation:
|
4
|
+
attached: "attached"
|
5
|
+
bookmarked: "bookmarked"
|
6
|
+
classified: "classified"
|
7
|
+
commented: "commented"
|
8
|
+
described: "described"
|
9
|
+
highlighted: "highlighted"
|
10
|
+
identified: "identified"
|
11
|
+
liked: "liked"
|
12
|
+
linked: "linked"
|
13
|
+
questioned: "questioned"
|
14
|
+
ranked: "ranked"
|
15
|
+
recommended: "recommended"
|
16
|
+
replied: "replied"
|
17
|
+
shared: "shared"
|
18
|
+
subscribed: "subscribed"
|
19
|
+
tagged: "tagged"
|
20
|
+
|
21
|
+
assessment:
|
22
|
+
paused: "paused"
|
23
|
+
restarted: "restarted"
|
24
|
+
started: "started"
|
25
|
+
submitted: "submitted"
|
26
|
+
|
27
|
+
item.completed: "completed"
|
28
|
+
item.skipped: "skipped"
|
29
|
+
item.started: "started"
|
30
|
+
item.reviewed: "reviewed"
|
31
|
+
item.viewed: "viewed"
|
32
|
+
|
33
|
+
assignable:
|
34
|
+
abandoned: "abandoned"
|
35
|
+
activated: "activated"
|
36
|
+
completed: "completed"
|
37
|
+
deactivated: "deactivated"
|
38
|
+
hid: "hid"
|
39
|
+
reviewed: "reviewed"
|
40
|
+
showed: "showed"
|
41
|
+
started: "started"
|
42
|
+
|
43
|
+
item:
|
44
|
+
downloaded: "downloaded"
|
45
|
+
uploaded: "uploaded"
|
46
|
+
|
47
|
+
|
48
|
+
media:
|
49
|
+
accessibility:
|
50
|
+
disabledClosedCaptioning: "disabled closed captioning"
|
51
|
+
enabledClosedCaptioning: "enabled closed captioning"
|
52
|
+
audio:
|
53
|
+
changedVolume: "changed volume"
|
54
|
+
muted: "muted"
|
55
|
+
unmuted: "unmuted"
|
56
|
+
playback:
|
57
|
+
changedSpeed: "changed speed"
|
58
|
+
ended: "ended"
|
59
|
+
forwardedTo: " forwarded to"
|
60
|
+
jumpedTo: "jumped to"
|
61
|
+
paused: "paused"
|
62
|
+
resumed: "resumed"
|
63
|
+
rewindedTo: "rewinded to"
|
64
|
+
started: "started"
|
65
|
+
viewer:
|
66
|
+
changedResolution: "changed resolution"
|
67
|
+
changedSize: "changed viewer size"
|
68
|
+
enteredFullScreen: "entered full screen"
|
69
|
+
openedPopout: "opened popout"
|
70
|
+
exitedFullScreen: "exited full screen"
|
71
|
+
closedPopout: "closed popout"
|
72
|
+
|
73
|
+
navigation:
|
74
|
+
navigatedTo: "navigated to"
|
75
|
+
|
76
|
+
outcome:
|
77
|
+
graded: "graded"
|
78
|
+
|
79
|
+
reading:
|
80
|
+
searched: "searched"
|
81
|
+
viewed: "viewed"
|
82
|
+
|
83
|
+
session:
|
84
|
+
loggedIn: "logged in"
|
85
|
+
loggedOut: "logged out"
|
86
|
+
timedOut: "timed out"
|
@@ -0,0 +1,33 @@
|
|
1
|
+
|
2
|
+
module Caliper
|
3
|
+
class Client
|
4
|
+
attr_accessor :api_key, :options, :stats
|
5
|
+
def initialize(key, opts = {})
|
6
|
+
if opts[:consumer]
|
7
|
+
opts[:consumer] = Object.const_get(opts[:consumer]) if opts[:consumer].is_a?(String)
|
8
|
+
opts[:consumer] = opts[:consumer].new(key, opts) if opts[:consumer].respond_to?(:new)
|
9
|
+
raise ArgumentError, "Expecting Caliper::Consumer but got #{opts[:consumer].class.to_s}" unless opts[:consumer].is_a?(Caliper::Consumer::Base)
|
10
|
+
end
|
11
|
+
@consumer = opts[:consumer] || Caliper::Consumer::Socket.new(key, opts)
|
12
|
+
end
|
13
|
+
|
14
|
+
def measure(event, timestamp=nil)
|
15
|
+
raise ArgumentError, "Expecting Caliper::Event but got #{event.class.to_s}" unless event.is_a?(Caliper::Event::Base)
|
16
|
+
#todo ensure timestamp is iso8601
|
17
|
+
timestamp ||= Time.now
|
18
|
+
action = event.action
|
19
|
+
# returned json will serialize nil contexts as []
|
20
|
+
learning_context = event.learning_context ? event.learning_context : nil
|
21
|
+
activity_context = event.activity_context ? event.activity_context : nil
|
22
|
+
|
23
|
+
@consumer.measure(action, learning_context, activity_context, timestamp)
|
24
|
+
end
|
25
|
+
|
26
|
+
def describe(entity, timestamp=nil)
|
27
|
+
raise ArgumentError, "Expecting Caliper::Entity but got #{entity.class.to_s}" unless entity.is_a?(Caliper::Entity::Base)
|
28
|
+
#todo ensure timestamp is iso8601
|
29
|
+
timestamp ||= Time.now
|
30
|
+
@consumer.describe(entity.type, entity.id, entity.properties, Time.now)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Caliper
|
2
|
+
module Consumer
|
3
|
+
class Base
|
4
|
+
attr_reader :api_key
|
5
|
+
|
6
|
+
def initialize(key, opts = {})
|
7
|
+
@api_key = key
|
8
|
+
@options = validate_options(opts)
|
9
|
+
end
|
10
|
+
|
11
|
+
def describe(type, id, props, timestamp); end
|
12
|
+
|
13
|
+
def measure(action, learning_context, activity_context, timestamp); end
|
14
|
+
|
15
|
+
def with_debug?
|
16
|
+
@options[:debug] || false
|
17
|
+
end
|
18
|
+
|
19
|
+
def with_ssl?
|
20
|
+
@options[:ssl] || false
|
21
|
+
end
|
22
|
+
|
23
|
+
def on_error(error)
|
24
|
+
if with_debug?
|
25
|
+
#todo: log if debug
|
26
|
+
end
|
27
|
+
|
28
|
+
if @options[:on_error]
|
29
|
+
@options[:on_error].call(error)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def validate_options(opts)
|
34
|
+
hsh = {}
|
35
|
+
hsh[:debug] = opts[:debug] ? true : false
|
36
|
+
hsh[:ssl] = opts[:ssl] ? true : false
|
37
|
+
if opts[:on_error]
|
38
|
+
raise ArgumentError, "on_error option should be callable" unless opts[:on_error].is_a?(Proc)
|
39
|
+
hsh[:on_error] = opts[:on_error]
|
40
|
+
end
|
41
|
+
hsh
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Caliper
|
2
|
+
module Consumer
|
3
|
+
class Queue < Base
|
4
|
+
attr_reader :max_queue_size, :batch_size
|
5
|
+
|
6
|
+
def initialize(key, opts = {})
|
7
|
+
super
|
8
|
+
@queue = []
|
9
|
+
end
|
10
|
+
|
11
|
+
def validate_options(opts)
|
12
|
+
hsh = super
|
13
|
+
@max_queue_size = hsh[:max_queue_size] = opts[:max_queue_size].to_i
|
14
|
+
@batch_size = hsh[:batch_size] = opts[:batch_size].to_i
|
15
|
+
hsh
|
16
|
+
end
|
17
|
+
|
18
|
+
def measure(action, learning_context, activity_context, timestamp)
|
19
|
+
enqueue OpenStruct.new(api_key: @api_key, action: action, learning_context: learning_context, activity_context: activity_context, timestamp: timestamp, proc_name: "measure")
|
20
|
+
end
|
21
|
+
|
22
|
+
def describe(type, id, properties, timestamp)
|
23
|
+
enqueue OpenStruct.new(api_key: @api_key, entity_type: type, entity_id: id, properties: properties, timestamp: timestamp, proc_name: "describe")
|
24
|
+
end
|
25
|
+
|
26
|
+
def enqueue(item)
|
27
|
+
if item.proc_name == "measure"
|
28
|
+
flush_measure(item)
|
29
|
+
elsif item.proc_name == "describe"
|
30
|
+
flush_describe(item)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def flush_measure(item); end
|
35
|
+
|
36
|
+
def flush_describe(item); end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,132 @@
|
|
1
|
+
require 'socket'
|
2
|
+
require 'openssl'
|
3
|
+
require "active_support"
|
4
|
+
|
5
|
+
module Caliper
|
6
|
+
module Consumer
|
7
|
+
class Socket < Queue
|
8
|
+
attr_reader :socket
|
9
|
+
|
10
|
+
def initialize(key, opts = {})
|
11
|
+
super
|
12
|
+
end
|
13
|
+
|
14
|
+
def validate_options(opts)
|
15
|
+
hsh = super(opts)
|
16
|
+
hsh[:timeout] = opts[:timeout] || 0.5
|
17
|
+
hsh[:host] = opts[:host] || "localhost"
|
18
|
+
hsh[:port] = opts[:port] || ( hsh[:ssl] ? 443 : 80 )
|
19
|
+
hsh[:max_response_size] = opts[:max_response_size] || 2048
|
20
|
+
hsh
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def flush_describe(item)
|
26
|
+
socket = init_socket
|
27
|
+
return unless socket
|
28
|
+
|
29
|
+
send_request( socket, describe_body( @options[:host], ActiveSupport::JSON.encode(item)) )
|
30
|
+
end
|
31
|
+
|
32
|
+
def flush_measure(item)
|
33
|
+
socket = init_socket
|
34
|
+
return unless socket
|
35
|
+
|
36
|
+
send_request( socket, measure_body( @options[:host], ActiveSupport::JSON.encode(item)) )
|
37
|
+
end
|
38
|
+
|
39
|
+
# both describe_body and measure_body hardcode a URL as is the case with caliper-php
|
40
|
+
# todo: make this configurable
|
41
|
+
def describe_body(host, content)
|
42
|
+
<<-STR.gsub(/^ {10}/,'')
|
43
|
+
PUT /v1/describe HTTP/1.1/
|
44
|
+
Host: #{host}
|
45
|
+
Content-Type: application/json
|
46
|
+
Accept: application\json
|
47
|
+
Content-length: #{content.length}
|
48
|
+
|
49
|
+
#{content}
|
50
|
+
STR
|
51
|
+
end
|
52
|
+
|
53
|
+
def measure_body(host, content)
|
54
|
+
<<-STR.gsub(/^ {10}/,'')
|
55
|
+
PUT /v1/learningevent HTTP/1.1/
|
56
|
+
Host: #{host}
|
57
|
+
Content-Type: application/json
|
58
|
+
Accept: application\json
|
59
|
+
Content-length: #{content.length}
|
60
|
+
|
61
|
+
#{content}
|
62
|
+
STR
|
63
|
+
end
|
64
|
+
|
65
|
+
def init_socket
|
66
|
+
# if socket has failed, don't keep trying to connect on future events
|
67
|
+
return if @socket_failed
|
68
|
+
begin
|
69
|
+
s = TCPSocket.new(@options[:host], @options[:port])
|
70
|
+
if with_ssl?
|
71
|
+
s = OpenSSL::SSL::SSLSocket.new(s)
|
72
|
+
s.sync_close
|
73
|
+
s.connect
|
74
|
+
end
|
75
|
+
rescue SocketError => e
|
76
|
+
on_error(e)
|
77
|
+
@socket_failed = true
|
78
|
+
return
|
79
|
+
end
|
80
|
+
s
|
81
|
+
end
|
82
|
+
|
83
|
+
def send_request(socket, body, with_retries = 1)
|
84
|
+
written = 0
|
85
|
+
closed = false
|
86
|
+
while !closed && bytes_written < body.bytesize
|
87
|
+
begin
|
88
|
+
bytes_written = socket.write(body[bytes_written..-1])
|
89
|
+
if bytes_written.zero?
|
90
|
+
closed = true
|
91
|
+
else
|
92
|
+
written += bytes_written
|
93
|
+
end
|
94
|
+
rescue SocketError => e
|
95
|
+
on_error(e)
|
96
|
+
closed = true
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
if closed
|
101
|
+
socket.close
|
102
|
+
# attempt to retry connection up to with_retries times
|
103
|
+
unless with_retries.zero?
|
104
|
+
socket = init_socket
|
105
|
+
return send_request(socket, body, with_retries - 1) if socket
|
106
|
+
end
|
107
|
+
return false
|
108
|
+
end
|
109
|
+
|
110
|
+
success = true
|
111
|
+
|
112
|
+
# if debug is enabled, wait for response
|
113
|
+
if with_debug?
|
114
|
+
r = parse_response(socket.read(@options[:max_response_size]))
|
115
|
+
unless r.status == 200
|
116
|
+
#todo build exception and send it to on_error
|
117
|
+
success = false
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
return success
|
122
|
+
end
|
123
|
+
|
124
|
+
def parse_response(resp)
|
125
|
+
contents = resp.split("\n")
|
126
|
+
status = contents.first.split(" ")
|
127
|
+
OpenStruct.new(:status => (status.length > 1 ? status[1] : nil), :message => contents.last)
|
128
|
+
end
|
129
|
+
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require_relative '../../entities/entity'
|
2
|
+
require_relative '../../entities/schemadotorg/thing'
|
3
|
+
|
4
|
+
module Caliper
|
5
|
+
module Entities
|
6
|
+
module Annotation
|
7
|
+
module AnnotationType
|
8
|
+
ANNOTATION = "http://purl.imsglobal.org/caliper/v1/Annotation"
|
9
|
+
BOOKMARK_ANNOTATION = "http://purl.imsglobal.org/caliper/v1/BookmarkAnnotation"
|
10
|
+
HIGHLIGHT_ANNOTATION = "http://purl.imsglobal.org/caliper/v1/HighlightAnnotation"
|
11
|
+
SHARED_ANNOTATION = "http://purl.imsglobal.org/caliper/v1/SharedAnnotation"
|
12
|
+
TAG_ANNOTATION = "http://purl.imsglobal.org/caliper/v1/TagAnnotation"
|
13
|
+
end
|
14
|
+
|
15
|
+
## implement the interface Thing
|
16
|
+
class Annotation < Entity
|
17
|
+
include Caliper::Entities::SchemaDotOrg::Thing
|
18
|
+
attr_accessor :target,
|
19
|
+
:type
|
20
|
+
|
21
|
+
def initialize
|
22
|
+
super
|
23
|
+
type = AnnotationType::ANNOTATION
|
24
|
+
target = ''
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require_relative 'annotation'
|
2
|
+
|
3
|
+
module Caliper
|
4
|
+
module Entities
|
5
|
+
module Annotation
|
6
|
+
class Bookmark < Annotation
|
7
|
+
attr_accessor :type,
|
8
|
+
:bookmark_notes
|
9
|
+
|
10
|
+
def initialize(action)
|
11
|
+
super
|
12
|
+
@type = AnnotationType::BOOKMARK_ANNOTATION
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require_relative 'annotation'
|
2
|
+
|
3
|
+
module Caliper
|
4
|
+
module Entities
|
5
|
+
module Annotation
|
6
|
+
class HighlightAnnotation < Annotation
|
7
|
+
attr_accessor :type,
|
8
|
+
:bookmark_notes
|
9
|
+
|
10
|
+
def initialize()
|
11
|
+
super
|
12
|
+
@type = AnnotationType::HIGHLIGHT_ANNOTATION
|
13
|
+
@bookmark_notes = ''
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require_relative 'annotation'
|
2
|
+
|
3
|
+
module Caliper
|
4
|
+
module Entities
|
5
|
+
module Annotation
|
6
|
+
class SharedAnnotation < Annotation
|
7
|
+
attr_accessor :with_agents, # list of Agent object
|
8
|
+
:type
|
9
|
+
|
10
|
+
def initialize()
|
11
|
+
super
|
12
|
+
@type = AnnotationType::SHARED_ANNOTATION
|
13
|
+
@with_agents = ''
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require_relative 'Annotation'
|
2
|
+
|
3
|
+
module Caliper
|
4
|
+
module Entities
|
5
|
+
module Annotation
|
6
|
+
class TagAnnotation < Annotation
|
7
|
+
attr_accessor :type,
|
8
|
+
:tags
|
9
|
+
|
10
|
+
def initialize()
|
11
|
+
super
|
12
|
+
@type = AnnotationType::TAG_ANNOTATION
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
|
2
|
+
# An Selector which describes a range of text based on its start and end positions
|
3
|
+
# Defined by: http://www.w3.org/ns/oa#d4e667
|
4
|
+
|
5
|
+
module Caliper
|
6
|
+
module Entities
|
7
|
+
module Annotation
|
8
|
+
class TextPositionSelector
|
9
|
+
attr_accessor :start,
|
10
|
+
:end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require "json"
|
2
|
+
require_relative 'entity'
|
3
|
+
|
4
|
+
# Public: Caliper representation of a CreativeWork (https://schema.org/CreativeWork)
|
5
|
+
# We add learning specific attributes, including a list of
|
6
|
+
# LearningObjective learning objectives and a list of
|
7
|
+
# String keywords
|
8
|
+
#
|
9
|
+
# Examples
|
10
|
+
#
|
11
|
+
|
12
|
+
module Caliper
|
13
|
+
module Entities
|
14
|
+
module DigitalResourceType
|
15
|
+
ASSIGNABLE_DIGITAL_RESOURCE = "http://purl.imsglobal.org/caliper/v1/AssignableDigitalResource"
|
16
|
+
EPUB_CHAPTER = "http://www.idpf.org/epub/vocab/structure/#chapter"
|
17
|
+
EPUB_PART = "http://www.idpf.org/epub/vocab/structure/#part"
|
18
|
+
EPUB_SUB_CHAPTER = "http://www.idpf.org/epub/vocab/structure/#subchapter"
|
19
|
+
EPUB_VOLUME = "http://www.idpf.org/epub/vocab/structure/#volume"
|
20
|
+
FRAME = "http://purl.imsglobal.org/caliper/v1/Frame"
|
21
|
+
MEDIA_LOCATION = "http://purl.imsglobal.org/caliper/v1/MediaLocation"
|
22
|
+
MEDIA_OBJECT = "http://purl.imsglobal.org/caliper/v1/MediaObject"
|
23
|
+
READING = "http://www.idpf.org/epub/vocab/structure"
|
24
|
+
WEB_PAGE = "http://purl.imsglobal.org/caliper/v1/WebPage"
|
25
|
+
end
|
26
|
+
class DigitalResource < Entity
|
27
|
+
attr_accessor :type,
|
28
|
+
:object_types, # list of String
|
29
|
+
:learning_objectives, # a list of learning objectives
|
30
|
+
:keywords,
|
31
|
+
:is_part_of,
|
32
|
+
:date_published
|
33
|
+
|
34
|
+
# Public:
|
35
|
+
def to_json(*a)
|
36
|
+
{
|
37
|
+
"type" => @type,
|
38
|
+
"objectTypes" => @object_types,
|
39
|
+
"learningObjective" => @learning_objectives,
|
40
|
+
"keywords" => @keywords,
|
41
|
+
"isPartOf" => @is_part_of,
|
42
|
+
"datePublished" => @date_published
|
43
|
+
}.to_json(*a)
|
44
|
+
end
|
45
|
+
|
46
|
+
def initialize()
|
47
|
+
super
|
48
|
+
@type = EntityType::DIGITAL_RESOURCE
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require "json"
|
2
|
+
|
3
|
+
##
|
4
|
+
## The base Caliper Entity. Analogous to a schema.org Thing.
|
5
|
+
##
|
6
|
+
module Caliper
|
7
|
+
module Entities
|
8
|
+
module EntityType
|
9
|
+
AGENT = "http://purl.imsglobal.org/caliper/v1/Agent"
|
10
|
+
ATTEMPT = "http://purl.imsglobal.org/caliper/v1/Attempt"
|
11
|
+
DIGITAL_RESOURCE = "http://purl.imsglobal.org/caliper/v1/DigitalResource"
|
12
|
+
ENTITY = "http://purl.imsglobal.org/caliper/v1/Entity"
|
13
|
+
GENERATED = "http://purl.imsglobal.org/caliper/v1/Generated"
|
14
|
+
LEARNING_OBJECTIVE = "http://purl.imsglobal.org/caliper/v1/LearningObjective"
|
15
|
+
LIS_PERSON = "http://purl.imsglobal.org/caliper/v1/lis/Person"
|
16
|
+
LIS_ORGANIZATION = "http://purl.imsglobal.org/caliper/v1/lis/Organization"
|
17
|
+
RESULT = "http://purl.imsglobal.org/caliper/v1/Result"
|
18
|
+
SESSION = "http://purl.imsglobal.org/caliper/v1/Session"
|
19
|
+
SOFTWARE_APPLICATION = "http://purl.imsglobal.org/caliper/v1/SoftwareApplication"
|
20
|
+
TARGET = "http://purl.imsglobal.org/caliper/v1/Target"
|
21
|
+
VIEW = "http://purl.imsglobal.org/caliper/v1/View"
|
22
|
+
end
|
23
|
+
|
24
|
+
class Entity
|
25
|
+
attr_accessor :id,
|
26
|
+
:type,
|
27
|
+
:name,
|
28
|
+
:description,
|
29
|
+
:properties,
|
30
|
+
:date_created,
|
31
|
+
:date_modified
|
32
|
+
|
33
|
+
def initialize()
|
34
|
+
@id = ""
|
35
|
+
@type = EntityType::ENTITY
|
36
|
+
@name = ""
|
37
|
+
@description = ""
|
38
|
+
@properties = ""
|
39
|
+
@date_created = Time.now.utc
|
40
|
+
@date_modified = Time.now.utc
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
# The generatable interface marks an object type that is created or generated as a result of an action.
|
2
|
+
# The interface allows Caliper to catch errors at compile time for instances of the marked class rather
|
3
|
+
# than at runtime if a marker annotation was defined instead.
|
4
|
+
module Caliper
|
5
|
+
module Entities
|
6
|
+
module Generatable
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|