qti 0.9.0 → 0.9.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.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/lib/null_logger.rb +2 -4
  3. data/lib/qti/models/base.rb +8 -10
  4. data/lib/qti/models/manifest.rb +4 -8
  5. data/lib/qti/v1/models/assessment.rb +4 -4
  6. data/lib/qti/v1/models/assessment_item.rb +2 -2
  7. data/lib/qti/v1/models/choices/fill_blank_choice.rb +1 -1
  8. data/lib/qti/v1/models/interactions/base_interaction.rb +1 -1
  9. data/lib/qti/v1/models/interactions/choice_interaction.rb +1 -1
  10. data/lib/qti/v1/models/interactions/fill_blank_interaction.rb +6 -7
  11. data/lib/qti/v1/models/interactions/ordering_interaction.rb +1 -1
  12. data/lib/qti/v1/models/scoring_data.rb +1 -1
  13. data/lib/qti/v2/models/assessment_item.rb +1 -1
  14. data/lib/qti/v2/models/assessment_test.rb +3 -3
  15. data/lib/qti/v2/models/base.rb +6 -6
  16. data/lib/qti/v2/models/choices/simple_choice.rb +1 -1
  17. data/lib/qti/v2/models/interactions/base_interaction.rb +1 -1
  18. data/lib/qti/v2/models/interactions/categorization_interaction.rb +1 -1
  19. data/lib/qti/v2/models/interactions/gap_match_interaction.rb +8 -12
  20. data/lib/qti/v2/models/interactions/match_interaction.rb +2 -2
  21. data/lib/qti/v2/models/non_assessment_test.rb +2 -2
  22. data/lib/qti/v2/models/scoring_data.rb +1 -1
  23. data/lib/qti/v2/models/stimulus_item.rb +0 -1
  24. data/lib/qti/version.rb +1 -1
  25. data/spec/gemfiles/nokogiri-1.6.gemfile.lock +126 -0
  26. data/spec/gemfiles/nokogiri-1.8.gemfile.lock +126 -0
  27. data/spec/gemfiles/rails-4.2.gemfile.lock +203 -0
  28. data/spec/gemfiles/rails-5.0.gemfile.lock +209 -0
  29. data/spec/gemfiles/rails-5.1.gemfile.lock +209 -0
  30. data/spec/gemfiles/sanitize-4.2.gemfile.lock +126 -0
  31. data/spec/gemfiles/sanitize-4.5.gemfile.lock +126 -0
  32. data/spec/lib/qti/models/base_spec.rb +10 -10
  33. data/spec/lib/qti/models/manifest_spec.rb +0 -1
  34. data/spec/lib/qti/v1/models/assessment_spec.rb +7 -8
  35. data/spec/lib/qti/v1/models/choices/fill_blank_choice_spec.rb +1 -1
  36. data/spec/lib/qti/v1/models/choices/logical_identifier_choice_spec.rb +1 -1
  37. data/spec/lib/qti/v1/models/interactions/fill_blank_interaction_spec.rb +15 -13
  38. data/spec/lib/qti/v1/models/interactions/ordering_interaction_spec.rb +1 -1
  39. data/spec/lib/qti/v2/models/assessment_item_spec.rb +3 -3
  40. data/spec/lib/qti/v2/models/assessment_test_spec.rb +6 -7
  41. data/spec/lib/qti/v2/models/choices/gap_match_choice_spec.rb +1 -1
  42. data/spec/lib/qti/v2/models/choices/simple_associable_choice_spec.rb +8 -8
  43. data/spec/lib/qti/v2/models/choices/simple_choice_spec.rb +1 -1
  44. data/spec/lib/qti/v2/models/interactions/categorization_interaction_spec.rb +3 -3
  45. data/spec/lib/qti/v2/models/interactions/gap_match_interaction_spec.rb +24 -23
  46. data/spec/lib/qti/v2/models/interactions/ordering_interaction_spec.rb +1 -1
  47. data/spec/lib/qti/v2/models/interactions/short_text_interaction_spec.rb +1 -1
  48. data/spec/lib/qti/v2/models/non_assessment_test_spec.rb +1 -1
  49. data/spec/lib/qti/v2/models/object_element_spec.rb +1 -1
  50. metadata +17 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 96229366751c574392ef6478af9c08bad96cec41
4
- data.tar.gz: ef9619aa3bdf5d8f83c46839f8d04953a79a717b
3
+ metadata.gz: 202d9ba3ef99c4e0df030cf13a8e25f4e19441c2
4
+ data.tar.gz: 077f7118e61d94d1d7796494e481355e0b399833
5
5
  SHA512:
6
- metadata.gz: e9b5a5f1d726675d1cf1b5e161120c73a23ac1c20e633cd738787c9d3f5edbfad5618ac52fcabcb779789c4a2d04b019b386ba99a1819d8316c0c6d5da6dae61
7
- data.tar.gz: 9fa1abca8886f8f5c86bc4e1bcd84a5890dc99ba2facc8e5aad2aa4642af7c95894f1970924b2018b7078400b210c7b8da5e8e43380125894416279f6fbe6074
6
+ metadata.gz: 6119e426a2f6c4b91cfb84ac7da7ca78317490439c0ace3ec067fc65ffa1b8b929979dfa76a4cb648b9d44781e5cb55d38490c89151ab1e66581c9315c8b88ff
7
+ data.tar.gz: 76f7caf87c7c9efd299b770d2adfcfa5737991dbaa3b2ee450616d0ae987bac40bd2a362932769f462006e80a11b40b4cb00c249cf48b1565c70fa50b71d559e
data/lib/null_logger.rb CHANGED
@@ -1,7 +1,5 @@
1
1
  class NullLogger < Logger
2
- def initialize(*args)
3
- end
2
+ def initialize(*args); end
4
3
 
5
- def add(*args, &block)
6
- end
4
+ def add(*args, &block); end
7
5
  end
@@ -113,7 +113,7 @@ module Qti
113
113
  case node[:type]
114
114
  when /^image\//
115
115
  return replace_with_image(node, node[:data])
116
- when "text/html"
116
+ when 'text/html'
117
117
  return replace_with_html(node, path)
118
118
  end
119
119
  end
@@ -127,15 +127,13 @@ module Qti
127
127
  end
128
128
 
129
129
  def replace_with_html(node, path)
130
- begin
131
- content = File.read(path)
132
- html_content = Sanitize.fragment(content, sanitize_config(import_objects: false))
133
- node.name = 'div'
134
- node.add_child(Nokogiri::HTML.fragment(html_content))
135
- rescue StandardError => e
136
- warn "failed to import html object #{path}: #{e.message}"
137
- node.unlink
138
- end
130
+ content = File.read(path)
131
+ html_content = Sanitize.fragment(content, sanitize_config(import_objects: false))
132
+ node.name = 'div'
133
+ node.add_child(Nokogiri::HTML.fragment(html_content))
134
+ rescue StandardError => e
135
+ warn "failed to import html object #{path}: #{e.message}"
136
+ node.unlink
139
137
  end
140
138
  end
141
139
  end
@@ -3,29 +3,25 @@ require 'qti/v1/models/base'
3
3
  module Qti
4
4
  module Models
5
5
  class Manifest < Qti::Models::Base
6
-
7
6
  def assessment_test
8
7
  qti_2_x_href || qti_1_href || qti_2_non_assessment_href || unknown_type
9
8
  end
10
9
 
11
10
  def qti_1_href
12
11
  test_path = xpath_with_single_check("//xmlns:resources/xmlns:resource[@type='imsqti_xmlv1p2']/@href")&.content ||
13
- xpath_with_single_check("//xmlns:resources/xmlns:resource[@type='imsqti_xmlv1p2']/xmlns:file/@href")&.content
12
+ xpath_with_single_check("//xmlns:resources/xmlns:resource[@type='imsqti_xmlv1p2']/xmlns:file/@href")&.content
14
13
  Qti::V1::Models::Assessment.from_path!(remap_href_path(test_path), @package_root) if test_path
15
14
  end
16
15
 
17
16
  def qti_2_x_href
18
17
  test_path = xpath_with_single_check("//xmlns:resources/xmlns:resource[@type='imsqti_test_xmlv2p1']/@href")&.content ||
19
- xpath_with_single_check("//xmlns:resources/xmlns:resource[@type='imsqti_test_xmlv2p2']/@href")&.content
18
+ xpath_with_single_check("//xmlns:resources/xmlns:resource[@type='imsqti_test_xmlv2p2']/@href")&.content
20
19
  Qti::V2::Models::AssessmentTest.from_path!(remap_href_path(test_path), @package_root) if test_path
21
20
  end
22
21
 
23
22
  def qti_2_non_assessment_href
24
- qti2_ns = ["http://www.imsglobal.org/xsd/imsqti_metadata_v2p1", "http://www.imsglobal.org/xsd/imsqti_v2p1"]
25
- if qti2_ns.include?(xpath_with_single_check("//xmlns:manifest")&.namespaces["xmlns:imsqti"])
26
- # use imsmanifest.xml as the assessment XML if there is no assessment xml
27
- Qti::V2::Models::NonAssessmentTest.from_path!(@path, @package_root)
28
- end
23
+ item_path = @doc.at_xpath("//xmlns:resources/xmlns:resource[@type='imsqti_item_xmlv2p1']/@href")&.content
24
+ Qti::V2::Models::NonAssessmentTest.from_path!(@path, @package_root) if item_path
29
25
  end
30
26
 
31
27
  def unknown_type
@@ -16,12 +16,12 @@ module Qti
16
16
  Qti::V1::Models::AssessmentItem.new(assessment_item, @package_root)
17
17
  end
18
18
 
19
- def stimulus_ref(ref)
20
- return nil
19
+ def stimulus_ref(_ref)
20
+ nil
21
21
  end
22
22
 
23
- def create_stimulus(stimulus)
24
- raise "Stimulus type not supported for QTI version"
23
+ def create_stimulus(_stimulus)
24
+ raise 'Stimulus type not supported for QTI version'
25
25
  end
26
26
  end
27
27
  end
@@ -36,7 +36,7 @@ module Qti
36
36
 
37
37
  def has_points_possible_qti_metadata?
38
38
  if @doc.at_xpath('.//xmlns:qtimetadata').present?
39
- points_possible_label = qti_metadata_children.children.find {|node| node.text == "points_possible"}
39
+ points_possible_label = qti_metadata_children.children.find { |node| node.text == 'points_possible' }
40
40
  points_possible_label.present?
41
41
  else
42
42
  false
@@ -46,7 +46,7 @@ module Qti
46
46
  def points_possible
47
47
  @points_possible ||= begin
48
48
  if has_points_possible_qti_metadata?
49
- points_possible_label = qti_metadata_children.children.find {|node| node.text == "points_possible"}
49
+ points_possible_label = qti_metadata_children.children.find { |node| node.text == 'points_possible' }
50
50
  points_possible_node = points_possible_label.next.text
51
51
  else
52
52
  decvar_maxvalue
@@ -12,7 +12,7 @@ module Qti
12
12
 
13
13
  def identifier
14
14
  @identifier ||= @node.attributes['respident']&.value ||
15
- @node.attributes['ident']&.value
15
+ @node.attributes['ident']&.value
16
16
  end
17
17
 
18
18
  def item_body
@@ -5,7 +5,7 @@ module Qti
5
5
  class BaseInteraction < Qti::V1::Models::Base
6
6
  attr_reader :node
7
7
 
8
- def self.matches(node, parent)
8
+ def self.matches(_node, _parent)
9
9
  false
10
10
  end
11
11
 
@@ -6,7 +6,7 @@ module Qti
6
6
  # This will know if a class matches
7
7
  def self.matches(node, parent)
8
8
  matches = node.xpath('.//xmlns:response_lid')
9
- return false if matches.count > 1 || matches.empty?
9
+ return false if matches.count > 1 || matches.empty?
10
10
  rcardinality = matches.first.attributes['rcardinality']&.value || 'Single'
11
11
  return false if rcardinality == 'Ordered'
12
12
  new(node, parent)
@@ -45,22 +45,21 @@ module Qti
45
45
  end
46
46
 
47
47
  def scoring_data_structs
48
- answer_nodes.map { |value_node| ScoringData.new(
48
+ answer_nodes.map do |value_node|
49
+ ScoringData.new(
49
50
  value_node.content,
50
51
  rcardinality,
51
- {
52
- id: value_node.attributes['respident']&.value,
53
- case: value_node.attributes['case']&.value || 'no'
54
- }
52
+ id: value_node.attributes['respident']&.value,
53
+ case: value_node.attributes['case']&.value || 'no'
55
54
  )
56
- }
55
+ end
57
56
  end
58
57
 
59
58
  private
60
59
 
61
60
  def rcardinality
62
61
  @rcardinality ||= @node.at_xpath('.//xmlns:response_str/@rcardinality')&.value ||
63
- @node.at_xpath('.//xmlns:response_num/@rcardinality')&.value
62
+ @node.at_xpath('.//xmlns:response_num/@rcardinality')&.value
64
63
  end
65
64
 
66
65
  def answer_nodes
@@ -6,7 +6,7 @@ module Qti
6
6
  # This will know if a class matches
7
7
  def self.matches(node, parent)
8
8
  matches = node.xpath('.//xmlns:response_lid')
9
- return false if matches.count > 1 || matches.empty?
9
+ return false if matches.count > 1 || matches.empty?
10
10
  rcardinality = matches.first.attributes['rcardinality']&.value || 'Single'
11
11
  return false if rcardinality != 'Ordered'
12
12
  new(node, parent)
@@ -2,7 +2,7 @@ module Qti
2
2
  module V1
3
3
  module Models
4
4
  ScoringData = Struct.new(:values, :rcardinality, :id, :case) do
5
- def initialize(values, rcardinality, options={})
5
+ def initialize(values, rcardinality, options = {})
6
6
  super(values, rcardinality, options[:id], options[:case])
7
7
  end
8
8
  end
@@ -35,7 +35,7 @@ module Qti
35
35
  def points_possible
36
36
  @points_possible ||= begin
37
37
  xpath_with_single_check("//xmlns:outcomeDeclaration[@identifier='SCORE']/@normalMaximum")&.content ||
38
- xpath_with_single_check("//xmlns:outcomeDeclaration[@identifier='MAXSCORE']//xmlns:value")&.content
38
+ xpath_with_single_check("//xmlns:outcomeDeclaration[@identifier='MAXSCORE']//xmlns:value")&.content
39
39
  end
40
40
  end
41
41
 
@@ -5,7 +5,7 @@ module Qti
5
5
  module Models
6
6
  class AssessmentTest < Qti::V2::Models::Base
7
7
  def title
8
- @title ||= xpath_with_single_check('//xmlns:assessmentTest/@title')&.content || File.basename(@path, ".xml")
8
+ @title ||= xpath_with_single_check('//xmlns:assessmentTest/@title')&.content || File.basename(@path, '.xml')
9
9
  end
10
10
 
11
11
  def assessment_items
@@ -29,8 +29,8 @@ module Qti
29
29
  Qti::V2::Models::AssessmentItem.from_path!(assessment_item_ref, @package_root)
30
30
  end
31
31
 
32
- def stimulus_ref(ref)
33
- return nil
32
+ def stimulus_ref(_ref)
33
+ nil
34
34
  end
35
35
 
36
36
  def create_stimulus(stimulus_ref)
@@ -4,7 +4,7 @@ module Qti
4
4
  module V2
5
5
  module Models
6
6
  class Base < Qti::Models::Base
7
- BODY_ELEMENTS_CSS = %w(
7
+ BODY_ELEMENTS_CSS = %w[
8
8
  atomicBlock
9
9
  atomicInline
10
10
  caption
@@ -33,9 +33,9 @@ module Qti
33
33
  tr
34
34
  ul
35
35
  infoControl
36
- ).join(',').freeze
36
+ ].join(',').freeze
37
37
 
38
- INTERACTION_ELEMENTS_CSS = %w(
38
+ INTERACTION_ELEMENTS_CSS = %w[
39
39
  blockInteraction
40
40
  customInteraction
41
41
  inlineInteraction
@@ -55,11 +55,11 @@ module Qti
55
55
  orderInteraction
56
56
  sliderInteraction
57
57
  uploadInteraction
58
- ).join(',').freeze
58
+ ].join(',').freeze
59
59
 
60
- CHOICE_ELEMENTS_CSS = %w(
60
+ CHOICE_ELEMENTS_CSS = %w[
61
61
  simpleChoice
62
- ).join(',').freeze
62
+ ].join(',').freeze
63
63
 
64
64
  def qti_version
65
65
  2
@@ -5,7 +5,7 @@ module Qti
5
5
  module Models
6
6
  module Choices
7
7
  class SimpleChoice < Qti::V2::Models::Base
8
- PROHIBITED_NODE_NAMES = %w(feedbackInline).join(',').freeze
8
+ PROHIBITED_NODE_NAMES = %w[feedbackInline].join(',').freeze
9
9
 
10
10
  def initialize(node, parent)
11
11
  @node = node
@@ -5,7 +5,7 @@ module Qti
5
5
  class BaseInteraction < Qti::V2::Models::Base
6
6
  attr_reader :node
7
7
 
8
- def self.matches(node)
8
+ def self.matches(_node)
9
9
  false
10
10
  end
11
11
 
@@ -16,7 +16,7 @@ module Qti
16
16
  def self.use_match_interaction_implementation?(node)
17
17
  MatchItemTagProcessors::MatchInteractionTagProcessor.match_interaction_tag?(node) &&
18
18
  MatchItemTagProcessors::MatchInteractionTagProcessor.number_of_questions_per_answer(node)
19
- .any? { |n| n != 1 }
19
+ .any? { |n| n != 1 }
20
20
  end
21
21
 
22
22
  def scoring_data_structs
@@ -20,9 +20,7 @@ module Qti
20
20
  gap_node.children.filter('gapText').each(&:remove)
21
21
 
22
22
  gap_node.children.each do |child|
23
- if child.inner_text.strip.empty?
24
- child.remove
25
- end
23
+ child.remove if child.inner_text.strip.empty?
26
24
  end
27
25
 
28
26
  gap_node
@@ -68,7 +66,7 @@ module Qti
68
66
  else
69
67
  {
70
68
  type: 'text',
71
- value: stem_item.text.empty? ? " " : stem_item.text
69
+ value: stem_item.text.empty? ? ' ' : stem_item.text
72
70
  }
73
71
  end
74
72
  end
@@ -90,20 +88,18 @@ module Qti
90
88
  question_response_pairs = node.xpath('.//xmlns:correctResponse//xmlns:value').map do |value|
91
89
  value.content.split
92
90
  end
93
- question_response_pairs.map!{ |qrp| qrp.reverse }
91
+ question_response_pairs.map!(&:reverse)
94
92
  question_response_id_mapping = Hash[question_response_pairs]
95
- answer_nodes.map { |value_node|
93
+ answer_nodes.map do |value_node|
96
94
  node_id = value_node.attributes['identifier']&.value
97
- answer_choice = choices.find{ |choice| choice.attributes['identifier']&.value == question_response_id_mapping[node_id] }
95
+ answer_choice = choices.find { |choice| choice.attributes['identifier']&.value == question_response_id_mapping[node_id] }
98
96
  ScoringData.new(
99
97
  answer_choice.content,
100
98
  'directedPair',
101
- {
102
- id: node_id,
103
- case: false
104
- }
99
+ id: node_id,
100
+ case: false
105
101
  )
106
- }
102
+ end
107
103
  end
108
104
 
109
105
  def choices
@@ -36,13 +36,13 @@ module Qti
36
36
  def self.use_associate_interaction_implementation?(node)
37
37
  MatchItemTagProcessors::AssociateInteractionTagProcessor.associate_interaction_tag?(node) &&
38
38
  MatchItemTagProcessors::AssociateInteractionTagProcessor.number_of_questions_per_answer(node)
39
- .all? { |n| n == 1 }
39
+ .all? { |n| n == 1 }
40
40
  end
41
41
 
42
42
  def self.use_match_interaction_implementation?(node)
43
43
  MatchItemTagProcessors::MatchInteractionTagProcessor.match_interaction_tag?(node) &&
44
44
  MatchItemTagProcessors::MatchInteractionTagProcessor.number_of_questions_per_answer(node)
45
- .all? { |n| n == 1 }
45
+ .all? { |n| n == 1 }
46
46
  end
47
47
  end
48
48
  end
@@ -16,11 +16,11 @@ module Qti
16
16
  def stimulus_ref(assessment_item_ref)
17
17
  ref = assessment_item_ref.sub(@package_root, '')
18
18
  dependencies = @doc.xpath("//xmlns:resource[@href='#{ref}']/xmlns:dependency/@identifierref")
19
- return unless dependencies && dependencies.count == 1
19
+ return unless dependencies&.count == 1
20
20
  href = xpath_with_single_check("//xmlns:resource[@identifier='#{dependencies.first}']/@href")
21
21
  remap_href_path(href)
22
22
  end
23
23
  end
24
24
  end
25
25
  end
26
- end
26
+ end
@@ -2,7 +2,7 @@ module Qti
2
2
  module V2
3
3
  module Models
4
4
  ScoringData = Struct.new(:values, :type, :id, :case, :question_id, :questions_ids) do
5
- def initialize(values, type, options={})
5
+ def initialize(values, type, options = {})
6
6
  super(values, type, options[:id], options[:case], options[:question_id], options[:questions_ids])
7
7
  end
8
8
  end
@@ -2,7 +2,6 @@ module Qti
2
2
  module V2
3
3
  module Models
4
4
  class StimulusItem < Qti::V2::Models::Base
5
-
6
5
  def body
7
6
  @body ||= begin
8
7
  item_body_node = xpath_with_single_check('//html/body')
data/lib/qti/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Qti
2
- VERSION = '0.9.0'.freeze
2
+ VERSION = '0.9.1'.freeze
3
3
  end
@@ -0,0 +1,126 @@
1
+ PATH
2
+ remote: ../..
3
+ specs:
4
+ qti (0.9.1)
5
+ activesupport (>= 4.2.9, < 5.2)
6
+ dry-struct (~> 0.2.1)
7
+ nokogiri (>= 1.6.8, < 1.9)
8
+ rubyzip (~> 1.2)
9
+ sanitize (>= 4.2.0, < 5.0)
10
+
11
+ GEM
12
+ remote: https://rubygems.org/
13
+ specs:
14
+ activesupport (5.1.4)
15
+ concurrent-ruby (~> 1.0, >= 1.0.2)
16
+ i18n (~> 0.7)
17
+ minitest (~> 5.1)
18
+ tzinfo (~> 1.1)
19
+ ast (2.3.0)
20
+ byebug (9.1.0)
21
+ coderay (1.1.2)
22
+ concurrent-ruby (1.0.5)
23
+ crass (1.0.2)
24
+ diff-lcs (1.3)
25
+ docile (1.1.5)
26
+ dry-configurable (0.7.0)
27
+ concurrent-ruby (~> 1.0)
28
+ dry-container (0.6.0)
29
+ concurrent-ruby (~> 1.0)
30
+ dry-configurable (~> 0.1, >= 0.1.3)
31
+ dry-core (0.3.3)
32
+ concurrent-ruby (~> 1.0)
33
+ dry-equalizer (0.2.0)
34
+ dry-logic (0.4.2)
35
+ dry-container (~> 0.2, >= 0.2.6)
36
+ dry-core (~> 0.2)
37
+ dry-equalizer (~> 0.2)
38
+ dry-struct (0.2.1)
39
+ dry-configurable (~> 0.1)
40
+ dry-equalizer (~> 0.2)
41
+ dry-types (~> 0.9, >= 0.9.0)
42
+ ice_nine (~> 0.11)
43
+ dry-types (0.12.0)
44
+ concurrent-ruby (~> 1.0)
45
+ dry-configurable (~> 0.1)
46
+ dry-container (~> 0.3)
47
+ dry-core (~> 0.2, >= 0.2.1)
48
+ dry-equalizer (~> 0.2)
49
+ dry-logic (~> 0.4, >= 0.4.2)
50
+ inflecto (~> 0.0.0, >= 0.0.2)
51
+ i18n (0.8.6)
52
+ ice_nine (0.11.2)
53
+ inflecto (0.0.2)
54
+ json (2.1.0)
55
+ method_source (0.9.0)
56
+ mini_portile2 (2.1.0)
57
+ minitest (5.10.3)
58
+ nokogiri (1.6.8.1)
59
+ mini_portile2 (~> 2.1.0)
60
+ nokogumbo (1.4.13)
61
+ nokogiri
62
+ parallel (1.12.0)
63
+ parser (2.4.0.0)
64
+ ast (~> 2.2)
65
+ powerpack (0.1.1)
66
+ pry (0.11.1)
67
+ coderay (~> 1.1.0)
68
+ method_source (~> 0.9.0)
69
+ rainbow (2.2.2)
70
+ rake
71
+ rake (0.9.6)
72
+ rspec (3.6.0)
73
+ rspec-core (~> 3.6.0)
74
+ rspec-expectations (~> 3.6.0)
75
+ rspec-mocks (~> 3.6.0)
76
+ rspec-core (3.6.0)
77
+ rspec-support (~> 3.6.0)
78
+ rspec-expectations (3.6.0)
79
+ diff-lcs (>= 1.2.0, < 2.0)
80
+ rspec-support (~> 3.6.0)
81
+ rspec-mocks (3.6.0)
82
+ diff-lcs (>= 1.2.0, < 2.0)
83
+ rspec-support (~> 3.6.0)
84
+ rspec-support (3.6.0)
85
+ rubocop (0.50.0)
86
+ parallel (~> 1.10)
87
+ parser (>= 2.3.3.1, < 3.0)
88
+ powerpack (~> 0.1)
89
+ rainbow (>= 2.2.2, < 3.0)
90
+ ruby-progressbar (~> 1.7)
91
+ unicode-display_width (~> 1.0, >= 1.0.1)
92
+ ruby-progressbar (1.8.3)
93
+ rubyzip (1.2.1)
94
+ sanitize (4.5.0)
95
+ crass (~> 1.0.2)
96
+ nokogiri (>= 1.4.4)
97
+ nokogumbo (~> 1.4.1)
98
+ simplecov (0.15.1)
99
+ docile (~> 1.1.0)
100
+ json (>= 1.8, < 3)
101
+ simplecov-html (~> 0.10.0)
102
+ simplecov-html (0.10.2)
103
+ thread_safe (0.3.6)
104
+ tzinfo (1.2.3)
105
+ thread_safe (~> 0.1)
106
+ unicode-display_width (1.3.0)
107
+ wwtd (1.3.0)
108
+
109
+ PLATFORMS
110
+ ruby
111
+
112
+ DEPENDENCIES
113
+ bundler (~> 1.15)
114
+ byebug (~> 9.0)
115
+ nokogiri (~> 1.6.8)
116
+ pry (~> 0)
117
+ qti!
118
+ rake (~> 0)
119
+ rspec (~> 3.6)
120
+ rspec-mocks (~> 3.6)
121
+ rubocop (~> 0.50.0)
122
+ simplecov (~> 0)
123
+ wwtd (~> 1.3)
124
+
125
+ BUNDLED WITH
126
+ 1.15.4