scorm2004-manifest 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (129) hide show
  1. data/.document +5 -0
  2. data/Gemfile +12 -0
  3. data/Gemfile.lock +36 -0
  4. data/LICENSE.txt +20 -0
  5. data/README.rdoc +94 -0
  6. data/Rakefile +39 -0
  7. data/VERSION +1 -0
  8. data/lib/scorm2004/manifest/adlseq_map_info.rb +17 -0
  9. data/lib/scorm2004/manifest/adlseq_objective.rb +14 -0
  10. data/lib/scorm2004/manifest/adlseq_objectives.rb +11 -0
  11. data/lib/scorm2004/manifest/attributes.rb +147 -0
  12. data/lib/scorm2004/manifest/children.rb +83 -0
  13. data/lib/scorm2004/manifest/completion_threshold.rb +13 -0
  14. data/lib/scorm2004/manifest/condition_rule.rb +12 -0
  15. data/lib/scorm2004/manifest/constrained_choice_considerations.rb +12 -0
  16. data/lib/scorm2004/manifest/control_mode.rb +16 -0
  17. data/lib/scorm2004/manifest/custom_error.rb +15 -0
  18. data/lib/scorm2004/manifest/data.rb +11 -0
  19. data/lib/scorm2004/manifest/data_from_lms.rb +21 -0
  20. data/lib/scorm2004/manifest/delivery_controls.rb +13 -0
  21. data/lib/scorm2004/manifest/dependency.rb +21 -0
  22. data/lib/scorm2004/manifest/error.rb +5 -0
  23. data/lib/scorm2004/manifest/file.rb +16 -0
  24. data/lib/scorm2004/manifest/hide_lmsui.rb +21 -0
  25. data/lib/scorm2004/manifest/href.rb +24 -0
  26. data/lib/scorm2004/manifest/item.rb +36 -0
  27. data/lib/scorm2004/manifest/limit_conditions.rb +12 -0
  28. data/lib/scorm2004/manifest/manifest.rb +26 -0
  29. data/lib/scorm2004/manifest/map.rb +13 -0
  30. data/lib/scorm2004/manifest/map_info.rb +15 -0
  31. data/lib/scorm2004/manifest/min_normalized_measure.rb +18 -0
  32. data/lib/scorm2004/manifest/navigation_interface.rb +10 -0
  33. data/lib/scorm2004/manifest/objective.rb +16 -0
  34. data/lib/scorm2004/manifest/objectives.rb +12 -0
  35. data/lib/scorm2004/manifest/organization.rb +20 -0
  36. data/lib/scorm2004/manifest/organizations.rb +24 -0
  37. data/lib/scorm2004/manifest/presentation.rb +10 -0
  38. data/lib/scorm2004/manifest/primary_objective.rb +24 -0
  39. data/lib/scorm2004/manifest/randomization_controls.rb +16 -0
  40. data/lib/scorm2004/manifest/resource.rb +18 -0
  41. data/lib/scorm2004/manifest/resources.rb +12 -0
  42. data/lib/scorm2004/manifest/rollup_action.rb +13 -0
  43. data/lib/scorm2004/manifest/rollup_condition.rb +24 -0
  44. data/lib/scorm2004/manifest/rollup_conditions.rb +14 -0
  45. data/lib/scorm2004/manifest/rollup_considerations.rb +17 -0
  46. data/lib/scorm2004/manifest/rollup_rule.rb +19 -0
  47. data/lib/scorm2004/manifest/rollup_rules.rb +16 -0
  48. data/lib/scorm2004/manifest/rule_action.rb +31 -0
  49. data/lib/scorm2004/manifest/rule_condition.rb +41 -0
  50. data/lib/scorm2004/manifest/rule_conditions.rb +14 -0
  51. data/lib/scorm2004/manifest/schema.rb +18 -0
  52. data/lib/scorm2004/manifest/schemaversion.rb +18 -0
  53. data/lib/scorm2004/manifest/sequencing.rb +24 -0
  54. data/lib/scorm2004/manifest/sequencing_collection.rb +11 -0
  55. data/lib/scorm2004/manifest/sequencing_rules.rb +13 -0
  56. data/lib/scorm2004/manifest/text_node.rb +11 -0
  57. data/lib/scorm2004/manifest/time_limit_action.rb +24 -0
  58. data/lib/scorm2004/manifest/title.rb +16 -0
  59. data/lib/scorm2004/manifest/visitor_pattern.rb +31 -0
  60. data/lib/scorm2004/manifest/xml_base.rb +38 -0
  61. data/lib/scorm2004/manifest.rb +76 -0
  62. data/lib/scorm2004-manifest.rb +1 -0
  63. data/test/functional_test.rb +45 -0
  64. data/test/helper.rb +18 -0
  65. data/test/mbce_test.rb +66 -0
  66. data/test/msce_test.rb +55 -0
  67. data/test/scorm2004/manifest/adlseq_map_info_test.rb +47 -0
  68. data/test/scorm2004/manifest/adlseq_objective_test.rb +44 -0
  69. data/test/scorm2004/manifest/adlseq_objectives_test.rb +29 -0
  70. data/test/scorm2004/manifest/any_uri_token_test.rb +40 -0
  71. data/test/scorm2004/manifest/attributes_test.rb +224 -0
  72. data/test/scorm2004/manifest/children_test.rb +330 -0
  73. data/test/scorm2004/manifest/completion_threshold_test.rb +80 -0
  74. data/test/scorm2004/manifest/condition_rule_test.rb +40 -0
  75. data/test/scorm2004/manifest/constrained_choice_considerations_test.rb +25 -0
  76. data/test/scorm2004/manifest/control_mode_test.rb +41 -0
  77. data/test/scorm2004/manifest/custom_error_test.rb +43 -0
  78. data/test/scorm2004/manifest/data_from_lms_test.rb +47 -0
  79. data/test/scorm2004/manifest/data_test.rb +31 -0
  80. data/test/scorm2004/manifest/delivery_controls_test.rb +27 -0
  81. data/test/scorm2004/manifest/dependency_test.rb +53 -0
  82. data/test/scorm2004/manifest/duration_attribute_test.rb +59 -0
  83. data/test/scorm2004/manifest/file_test.rb +40 -0
  84. data/test/scorm2004/manifest/hide_lmsui_test.rb +40 -0
  85. data/test/scorm2004/manifest/href_test.rb +43 -0
  86. data/test/scorm2004/manifest/item_test.rb +86 -0
  87. data/test/scorm2004/manifest/limit_conditions_test.rb +34 -0
  88. data/test/scorm2004/manifest/manifest_test.rb +152 -0
  89. data/test/scorm2004/manifest/map_info_test.rb +41 -0
  90. data/test/scorm2004/manifest/map_test.rb +32 -0
  91. data/test/scorm2004/manifest/min_normalized_measure_test.rb +28 -0
  92. data/test/scorm2004/manifest/navigation_interface_test.rb +29 -0
  93. data/test/scorm2004/manifest/non_negative_integer_attribute_test.rb +64 -0
  94. data/test/scorm2004/manifest/objective_test.rb +45 -0
  95. data/test/scorm2004/manifest/objectives_test.rb +37 -0
  96. data/test/scorm2004/manifest/organization_test.rb +115 -0
  97. data/test/scorm2004/manifest/organizations_test.rb +68 -0
  98. data/test/scorm2004/manifest/partial_manifest.rb +23 -0
  99. data/test/scorm2004/manifest/partial_manifest_test.rb +44 -0
  100. data/test/scorm2004/manifest/presentation_test.rb +26 -0
  101. data/test/scorm2004/manifest/primary_objective_test.rb +65 -0
  102. data/test/scorm2004/manifest/randomization_controls_test.rb +71 -0
  103. data/test/scorm2004/manifest/resource_test.rb +96 -0
  104. data/test/scorm2004/manifest/resources_test.rb +41 -0
  105. data/test/scorm2004/manifest/rollup_action_test.rb +33 -0
  106. data/test/scorm2004/manifest/rollup_condition_test.rb +42 -0
  107. data/test/scorm2004/manifest/rollup_conditions_test.rb +53 -0
  108. data/test/scorm2004/manifest/rollup_considerations_test.rb +42 -0
  109. data/test/scorm2004/manifest/rollup_rule_test.rb +87 -0
  110. data/test/scorm2004/manifest/rollup_rules_test.rb +60 -0
  111. data/test/scorm2004/manifest/rule_action_test.rb +79 -0
  112. data/test/scorm2004/manifest/rule_condition_test.rb +70 -0
  113. data/test/scorm2004/manifest/rule_conditions_test.rb +37 -0
  114. data/test/scorm2004/manifest/schema_test.rb +29 -0
  115. data/test/scorm2004/manifest/schemaversion_test.rb +29 -0
  116. data/test/scorm2004/manifest/sequencing_collection_test.rb +31 -0
  117. data/test/scorm2004/manifest/sequencing_rules_test.rb +36 -0
  118. data/test/scorm2004/manifest/sequencing_test.rb +42 -0
  119. data/test/scorm2004/manifest/string_attribute_test.rb +68 -0
  120. data/test/scorm2004/manifest/text_node_test.rb +37 -0
  121. data/test/scorm2004/manifest/time_limit_action_test.rb +51 -0
  122. data/test/scorm2004/manifest/title_test.rb +59 -0
  123. data/test/scorm2004/manifest/token_attribute_test.rb +53 -0
  124. data/test/scorm2004/manifest/visitor_pattern_test.rb +85 -0
  125. data/test/scorm2004/manifest/xml_base_test.rb +125 -0
  126. data/test/scorm2004/manifest_test.rb +33 -0
  127. data/test/scorm2004_test.rb +9 -0
  128. data/test/sece_test.rb +53 -0
  129. metadata +260 -0
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/Gemfile ADDED
@@ -0,0 +1,12 @@
1
+ source "http://rubygems.org"
2
+
3
+ gem "nokogiri"
4
+ gem "activesupport"
5
+
6
+ group :development do
7
+ gem "shoulda-context", "~> 1.0"
8
+ gem "mocha", "~> 0.10.4"
9
+ gem "yard", "~> 0.7"
10
+ gem "bundler", '~> 1.1.0'
11
+ gem "jeweler", "~> 1.8.3"
12
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,36 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ activesupport (3.2.2)
5
+ i18n (~> 0.6)
6
+ multi_json (~> 1.0)
7
+ git (1.2.5)
8
+ i18n (0.6.0)
9
+ jeweler (1.8.3)
10
+ bundler (~> 1.0)
11
+ git (>= 1.2.5)
12
+ rake
13
+ rdoc
14
+ json (1.6.5)
15
+ metaclass (0.0.1)
16
+ mocha (0.10.5)
17
+ metaclass (~> 0.0.1)
18
+ multi_json (1.1.0)
19
+ nokogiri (1.5.2)
20
+ rake (0.9.2.2)
21
+ rdoc (3.12)
22
+ json (~> 1.4)
23
+ shoulda-context (1.0.0)
24
+ yard (0.7.5)
25
+
26
+ PLATFORMS
27
+ ruby
28
+
29
+ DEPENDENCIES
30
+ activesupport
31
+ bundler (~> 1.1.0)
32
+ jeweler (~> 1.8.3)
33
+ mocha (~> 0.10.4)
34
+ nokogiri
35
+ shoulda-context (~> 1.0)
36
+ yard (~> 0.7)
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2012 Takahiro Noda
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.rdoc ADDED
@@ -0,0 +1,94 @@
1
+ = scorm2004-manifest
2
+
3
+ * https://github.com/tnoda/scorm2004-manifest
4
+
5
+ == Description
6
+
7
+ +scorm2004-manifest+ is a Ruby gem that provides a manifest file parser for SCORM 2004 4th edition. It parses and validates the manifest file according to SCORM 2004 4th Edition Content Aggregation Model (CAM) Version 1.1. After parsing and validating, it builds an object tree that captures XML's hierarchical structure.
8
+
9
+ == Installation
10
+
11
+ To install scorm2004-manifest, use the following command:
12
+
13
+ $ gem install scorm2004-manifest
14
+
15
+ == Requirements
16
+
17
+ * ruby 1.9.3
18
+ * nokogiri
19
+ * activesupport
20
+
21
+
22
+ == Synopsis
23
+
24
+ require 'scorm2004-manifest'
25
+
26
+ # Parse a manifest file
27
+ manifest = Scorm2004::Manifest(open('imsmanifest.xml'))
28
+
29
+ # Traverse an object tree
30
+ manifest.identifier # => "LMSTestPackage_CM-01"
31
+ manifest.version # => "1.1.1"
32
+ organizations = manifest.organizations
33
+ organization = organizations.organizations[0]
34
+ organization.identifier # => "CM-01"
35
+ organization.title.content # => "LMS Test Content Package CM-01 "
36
+ item_0 = organization.items[0]
37
+ item_0.title.content # => "Activity 1"
38
+ item_0.identifier # => "activity_1"
39
+ item_0.identifierref # => "SEQ01"
40
+ item_0.parameters # => "?tc=CM-01&act=1"
41
+ item_0.sequencing.limit_conditions.attempt_absolute_duration_limit
42
+ # => "P5Y6M4DT12H30M58S"
43
+ item_0.presentation.navigation_interface.hide_lmsuis.map(&:content)
44
+ # => ["continue", "previous", "suspendAll"]
45
+ # ...
46
+
47
+ For every XML element in a manifest file, XML attributes and
48
+ child elements defined in Content Aggregation Model can be
49
+ accessed using accessor methods whose names are underscored.
50
+ Namespace prefixes are omitted from the accessor methods,
51
+ except for either +adlseq_objectives+, +adlseq_objective+,
52
+ or +adlseq_map_info+.
53
+ If an element may have multiple child elements,
54
+ the accessor method for the child elements will be pluralized.
55
+ For example, <organizations> element has one or more
56
+ <organization> elements.
57
+
58
+ # <organizations> can be accessed using the organizations
59
+ # method of the manifest object.
60
+ organizations = manifest.organizations
61
+
62
+ # The <organization> collection of the <organizations>
63
+ # element can be accessed using the organizations method
64
+ # of the organizations object. To get the first
65
+ # <organization> of the <organizations>, use the
66
+ # following expression.
67
+ organization_0 = organizations.organizations[0]
68
+
69
+
70
+ == Documentation
71
+
72
+ To generate scorm2004-manifest's document set, use the following command:
73
+
74
+ $ git clone git://github.com/tnoda/scorm2004-manifest.git
75
+ $ cd scorm2004-manifest
76
+ $ rake yard
77
+
78
+ The document set will be generated under the +doc+ directory.
79
+
80
+
81
+ == Contributing to scorm2004-manifest
82
+
83
+ * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
84
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it.
85
+ * Fork the project.
86
+ * Start a feature/bugfix branch.
87
+ * Commit and push until you are happy with your contribution.
88
+ * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
89
+ * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
90
+
91
+
92
+ == Copyright
93
+
94
+ Copyright (c) 2012 Takahiro Noda. See LICENSE.txt for further details.
data/Rakefile ADDED
@@ -0,0 +1,39 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+
14
+ require 'jeweler'
15
+ Jeweler::Tasks.new do |gem|
16
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
17
+ gem.name = "scorm2004-manifest"
18
+ gem.homepage = "https://github.com/tnoda/scorm2004-manifest"
19
+ gem.license = "MIT"
20
+ gem.summary = %Q{A manifest file parser/validator for SCORM 2004 4th Edition}
21
+ gem.description = <<EOS
22
+ scorm2004-manifest is a Ruby gem that provides a manifest file parser for SCORM 2004 4th edition. It parses and validates the manifest file according to SCORM 2004 4th Edition Content Aggregation Model (CAM) Version 1.1. After parsing and validating, it builds an object tree that captures XML's hierarchical structure.
23
+ EOS
24
+ gem.email = "takahiro.noda+rubygems@gmail.com"
25
+ gem.authors = ["Takahiro Noda"]
26
+ end
27
+ Jeweler::RubygemsDotOrgTasks.new
28
+
29
+ require 'rake/testtask'
30
+ Rake::TestTask.new(:test) do |test|
31
+ test.libs << 'lib' << 'test'
32
+ test.pattern = 'test/**/*_test.rb'
33
+ test.verbose = true
34
+ end
35
+
36
+ task :default => :test
37
+
38
+ require 'yard'
39
+ YARD::Rake::YardocTask.new
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
@@ -0,0 +1,17 @@
1
+ module Scorm2004
2
+ module Manifest
3
+ class AdlseqMapInfo
4
+ include VisitorPattern
5
+ include CustomError
6
+ include Attributes
7
+
8
+ attribute :any_uri, 'targetObjectiveID'
9
+
10
+ SLOTS = %w( RawScore MinScore MaxScore CompletionStatus ProgressMeasure )
11
+ %w( read write ).product(SLOTS).map(&:join).each do |attr|
12
+ default_value = /^read/ =~ attr ? true : false
13
+ attribute :boolean, attr, default: default_value
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,14 @@
1
+ module Scorm2004
2
+ module Manifest
3
+ class AdlseqObjective
4
+ include VisitorPattern
5
+ include CustomError
6
+ include Children
7
+ include Attributes
8
+
9
+ attribute :any_uri, 'objectiveID'
10
+
11
+ has_one_or_more 'adlseq:mapInfo', visitor: :adlseq_map_info
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,11 @@
1
+ module Scorm2004
2
+ module Manifest
3
+ class AdlseqObjectives
4
+ include VisitorPattern
5
+ include CustomError
6
+ include Children
7
+
8
+ has_one_or_more 'adlseq:objective', visitor: :adlseq_objective
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,147 @@
1
+ module Scorm2004
2
+ module Manifest
3
+ module Attributes
4
+ def self.included(base)
5
+ base.extend(ClassMethods)
6
+ end
7
+
8
+ private
9
+
10
+ def replace_and_collapse_whitespaces(string)
11
+ string.gsub(/\s+/, ' ').gsub(/^ | $/, '')
12
+ end
13
+
14
+ def xs_id?(str)
15
+ (/\s|^\d+$/ =~ str).nil?
16
+ end
17
+
18
+ def xs_non_negative_integer?(string)
19
+ /^\+?\d+$/ =~ string
20
+ end
21
+
22
+ def xs_duration?(string)
23
+ /^(\+|-)?P(((\d+Y)?(\d+M)?(\d+D)?(T(\d+H)?(\d+M)?(\d+(\.\d+)?S)?)?)|(\d+W))$/ =~ string
24
+ end
25
+
26
+ module ClassMethods
27
+ def attributes
28
+ @attributes ||= []
29
+ end
30
+
31
+ def attribute(type, name, options = {})
32
+ base = basename(name)
33
+ attributes << base
34
+ define_method("raw_#{base}") do
35
+ el.at("./@#{name}").try(:content) || options[:default].try(:to_s)
36
+ end
37
+ send("#{type}_attribute", name, options)
38
+ attr_reader base
39
+ end
40
+
41
+ def boolean_attribute(name, options)
42
+ base = basename(name)
43
+ define_method("check_#{base}".intern) do
44
+ raw = send("raw_#{base}")
45
+ error("No #{name} attribute.") if raw.nil?
46
+ unless %( true false 1 0 ).include?(raw)
47
+ error("Non xs:boolean value for the #{name}: #{raw}")
48
+ end
49
+ instance_variable_set("@#{base}".intern, %( true 1 ).include?(raw))
50
+ end
51
+ end
52
+
53
+ def string_attribute(name, options)
54
+ base = basename(name)
55
+ define_method("check_#{base}".intern) do
56
+ raw = send("raw_#{base}")
57
+ error("No #{name} attribute.") unless options[:allow_nil] || raw
58
+ if options[:spm] && raw.length > options[:spm]
59
+ error("The length of #{name} exceeds the SPM of #{options[:spm]} characters.")
60
+ end
61
+ instance_variable_set("@#{base}".intern, raw)
62
+ end
63
+ end
64
+
65
+ def id_attribute(name, options)
66
+ base = basename(name)
67
+ define_method("check_#{base}".intern) do
68
+ raw = send("raw_#{base}")
69
+ error("No #{name} attribute.") unless options[:allow_nil] || raw
70
+ error("Non xs:ID value for the #{name} attribute: #{raw}") unless xs_id?(raw)
71
+ instance_variable_set("@#{base}".intern, raw)
72
+ end
73
+ end
74
+ alias :idref_attribute :id_attribute
75
+
76
+ def decimal_attribute(name, options)
77
+ base = basename(name)
78
+ define_method("check_#{base}".intern) do
79
+ raw = send("raw_#{base}".intern)
80
+ return if options[:allow_nil] && raw.nil?
81
+ error("No #{name} attribute.") if raw.nil?
82
+ if options[:range] && !options[:range].include?(Float(raw))
83
+ error("The decimal attribute, #{name}, out of range (#{options[:range]}): #{raw}")
84
+ end
85
+ instance_variable_set("@#{base}".intern, Float(raw))
86
+ end
87
+ end
88
+
89
+ def non_negative_integer_attribute(name, options)
90
+ base = basename(name)
91
+ define_method("check_#{base}".intern) do
92
+ raw = send("raw_#{base}".intern)
93
+ return if options[:allow_nil] && raw.nil?
94
+ error("No #{name} attribute.") if raw.nil?
95
+ unless xs_non_negative_integer?(raw)
96
+ error("Non xs:nonNegativeInteger value for #{name}: #{raw}")
97
+ end
98
+ instance_variable_set("@#{base}".intern, Integer(raw, 10))
99
+ end
100
+ end
101
+
102
+ def duration_attribute(name, options)
103
+ base = basename(name)
104
+ define_method("check_#{base}".intern) do
105
+ raw = send("raw_#{base}".intern)
106
+ return if options[:allow_nil] && raw.nil?
107
+ error("No #{name} attribute.") if raw.nil?
108
+ error("Non xs:duration value for #{name}: #{raw}") unless xs_duration?(raw)
109
+ instance_variable_set("@#{base}".intern, raw)
110
+ end
111
+ end
112
+
113
+ def token_attribute(name, options)
114
+ base = basename(name)
115
+ define_method("check_#{base}".intern) do
116
+ raw = send("raw_#{base}".intern)
117
+ error("No #{name} attribute.") if raw.nil?
118
+ raw = replace_and_collapse_whitespaces(raw)
119
+ error("Invalid #{name}: #{raw}") unless options[:vocabulary].include?(raw)
120
+ instance_variable_set("@#{base}".intern, raw)
121
+ end
122
+ end
123
+
124
+ def any_uri_attribute(name, options)
125
+ base = basename(name)
126
+ define_method("check_#{base}".intern) do
127
+ raw = send("raw_#{base}".intern)
128
+ return if options[:allow_nil] && raw.nil?
129
+ error("No #{name} attribute.") if raw.nil?
130
+ begin
131
+ uri = URI(raw)
132
+ rescue URI::InvalidURIError => e
133
+ error(e)
134
+ end
135
+ instance_variable_set("@#{base}".intern, uri.to_s)
136
+ end
137
+ end
138
+
139
+ private
140
+
141
+ def basename(name)
142
+ name.split(':').last.underscore.intern
143
+ end
144
+ end
145
+ end
146
+ end
147
+ end
@@ -0,0 +1,83 @@
1
+ module Scorm2004
2
+ module Manifest
3
+ module Children
4
+ def self.included(base)
5
+ base.extend(ClassMethods)
6
+ end
7
+
8
+ private
9
+
10
+ def at(xpath)
11
+ xpath = './' + xpath unless /^\.\// =~ xpath
12
+ el.at(xpath, NS)
13
+ end
14
+
15
+ def search(xpath)
16
+ xpath = './' + xpath unless /^\.\// =~ xpath
17
+ el.search(xpath, NS)
18
+ end
19
+
20
+ def create_visitor(name)
21
+ send("#{name}_visitor".intern)
22
+ end
23
+
24
+ module ClassMethods
25
+ def children
26
+ @children ||= []
27
+ end
28
+
29
+ def has_one(xpath, options = {})
30
+ name = options[:name].try(:to_s) || guess_child_name(xpath, options)
31
+ children << name.intern
32
+ attr_reader name.intern
33
+ visitor_name = options[:visitor].try(:to_s) || name
34
+ define_method("visit_#{name}".intern) do
35
+ error("Two <#{xpath}> elements found.") if search(xpath).size > 1
36
+ error("<#{xpath}> not found.") unless options[:allow_nil] || at(xpath)
37
+ if at(xpath)
38
+ instance_variable_set("@#{name}".intern, at(xpath).accept(create_visitor(visitor_name)))
39
+ end
40
+ end
41
+ define_visitor(visitor_name)
42
+ end
43
+ alias :has_one_and_only_one :has_one
44
+
45
+ def has_zero_or_one(xpath, options = {})
46
+ has_one(xpath, options.merge( { :allow_nil => true } ))
47
+ end
48
+
49
+ def has_many(xpath, options = {})
50
+ name = options[:name].try(:to_s) || guess_child_name(xpath, options)
51
+ children << name.pluralize.intern
52
+ attr_reader name.pluralize.intern
53
+ visitor_name = options[:visitor].try(:to_s) || name
54
+ define_method("visit_#{name.pluralize}".intern) do
55
+ unless options[:allow_nil] || search(xpath).size > 0
56
+ error("<#{xpath}> not found.")
57
+ end
58
+ instance_variable_set("@#{name.pluralize}".intern, search(xpath).map { |child|
59
+ child.accept(create_visitor(visitor_name))
60
+ } )
61
+ end
62
+ define_visitor(visitor_name)
63
+ end
64
+ alias :has_one_or_more :has_many
65
+
66
+ def has_zero_or_more(xpath, options = {})
67
+ has_many(xpath, options.merge( { :allow_nil => true} ))
68
+ end
69
+
70
+ def guess_child_name(xpath, options)
71
+ xpath.split(%r{[/:]}).last.underscore
72
+ end
73
+
74
+ def define_visitor(name)
75
+ define_method("#{name}_visitor".intern) do
76
+ options = respond_to?(:base) ? { :base => base } : {}
77
+ "Scorm2004::Manifest::#{name.camelize}".constantize.new(options)
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,13 @@
1
+ module Scorm2004
2
+ module Manifest
3
+ class CompletionThreshold
4
+ include VisitorPattern
5
+ include CustomError
6
+ include Attributes
7
+
8
+ attribute :boolean, 'completedByMeasure', default: false
9
+ attribute :decimal, 'minProgressMeasure', default: 1.0, range: 0.0..1.0
10
+ attribute :decimal, 'progressWeight', default: 1.0, range: 0.0..1.0
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,12 @@
1
+ module Scorm2004
2
+ module Manifest
3
+ class ConditionRule
4
+ include VisitorPattern
5
+ include CustomError
6
+ include Children
7
+
8
+ has_one_and_only_one 'imsss:ruleConditions'
9
+ has_one_and_only_one 'imsss:ruleAction'
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ module Scorm2004
2
+ module Manifest
3
+ class ConstrainedChoiceConsiderations
4
+ include VisitorPattern
5
+ include CustomError
6
+ include Attributes
7
+
8
+ attribute :boolean, 'preventActivation', default: false
9
+ attribute :boolean, 'constrainChoice', default: false
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,16 @@
1
+ module Scorm2004
2
+ module Manifest
3
+ class ControlMode
4
+ include VisitorPattern
5
+ include CustomError
6
+ include Attributes
7
+
8
+ attribute :boolean, 'choice', default: true
9
+ attribute :boolean, 'choiceExit', default: true
10
+ attribute :boolean, 'flow', default: false
11
+ attribute :boolean, 'forwardOnly', default: false
12
+ attribute :boolean, 'useCurrentAttemptObjectiveInfo', default: true
13
+ attribute :boolean, 'useCurrentAttemptProgressInfo', default: true
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,15 @@
1
+ module Scorm2004
2
+ module Manifest
3
+ module CustomError
4
+ def self.included(base)
5
+ base.class_eval do
6
+ const_set('Error', Class.new(Scorm2004::Manifest::Error))
7
+ end
8
+ end
9
+
10
+ def error(message)
11
+ raise("#{self.class}::Error".constantize, [message, el.try(:to_s)].compact.join("\n"))
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,11 @@
1
+ module Scorm2004
2
+ module Manifest
3
+ class Data
4
+ include VisitorPattern
5
+ include CustomError
6
+ include Children
7
+
8
+ has_one_or_more 'adlcp:map'
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,21 @@
1
+ module Scorm2004
2
+ module Manifest
3
+ class DataFromLms
4
+ include VisitorPattern
5
+ include CustomError
6
+ include TextNode
7
+
8
+ def self.spm
9
+ 4000
10
+ end
11
+
12
+ private
13
+
14
+ def do_visit
15
+ if content.length > self.class.spm
16
+ error("<adlcp:dataFromLMS> exceeds the SPM of #{self.class.spm}: #{content}")
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,13 @@
1
+ module Scorm2004
2
+ module Manifest
3
+ class DeliveryControls
4
+ include VisitorPattern
5
+ include CustomError
6
+ include Attributes
7
+
8
+ attribute :boolean, 'tracked', default: true
9
+ attribute :boolean, 'completionSetByContent', default: false
10
+ attribute :boolean, 'objectiveSetByContent', default: false
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,21 @@
1
+ module Scorm2004
2
+ module Manifest
3
+ class Dependency
4
+ include VisitorPattern
5
+ include CustomError
6
+ include Attributes
7
+
8
+ attribute :string, 'identifierref'
9
+
10
+ private
11
+
12
+ def do_visit
13
+ error('Referenced <resource> not found:') unless referenced_resource
14
+ end
15
+
16
+ def referenced_resource
17
+ el.at("/imscp:manifest/imscp:resources/imscp:resource[@identifier='#{identifierref}']", NS)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,5 @@
1
+ module Scorm2004
2
+ module Manifest
3
+ class Error < StandardError; end
4
+ end
5
+ end
@@ -0,0 +1,16 @@
1
+ module Scorm2004
2
+ module Manifest
3
+ class File
4
+ include VisitorPattern
5
+ include CustomError
6
+ include XmlBase
7
+ include Href
8
+
9
+ private
10
+
11
+ def do_visit
12
+ error('href attribute not found:') unless href
13
+ end
14
+ end
15
+ end
16
+ end