academic_benchmarks 0.0.7 → 1.0.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.
@@ -0,0 +1,21 @@
1
+ require 'academic_benchmarks/lib/attr_to_vals'
2
+ require 'academic_benchmarks/lib/inst_vars_to_hash'
3
+
4
+ module AcademicBenchmarks
5
+ module Standards
6
+ class Disciplines
7
+ include AttrToVals
8
+ include InstVarsToHash
9
+
10
+ attr_accessor :subjects
11
+
12
+ def self.from_hash(hash)
13
+ self.new(subjects: hash["subjects"])
14
+ end
15
+
16
+ def initialize(subjects:)
17
+ @subjects = attr_to_vals(Subject, subjects)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -1,23 +1,30 @@
1
- require_relative '../lib/inst_vars_to_hash'
2
- require_relative '../lib/remove_obsolete_children'
1
+ require 'academic_benchmarks/lib/inst_vars_to_hash'
3
2
 
4
3
  module AcademicBenchmarks
5
4
  module Standards
6
5
  class Document
7
6
  include InstVarsToHash
8
- include RemoveObsoleteChildren
9
7
 
10
- attr_accessor :title, :guid, :children
8
+ attr_accessor :guid, :descr, :publication, :adopt_year, :children
11
9
 
12
10
  def self.from_hash(hash)
13
- self.new(title: hash["title"], guid: hash["guid"])
11
+ self.new(guid: hash["guid"], descr: hash["descr"], publication: hash["publication"], adopt_year: hash["adopt_year"])
14
12
  end
15
13
 
16
- def initialize(title:, guid:, children: [])
17
- @title = title
14
+ def initialize(guid:, descr:, publication:, adopt_year:, children: [])
18
15
  @guid = guid
16
+ @descr = descr
17
+ @publication = attr_to_val_or_nil(Publication, publication)
18
+ @adopt_year = adopt_year
19
19
  @children = children
20
20
  end
21
+
22
+ private
23
+
24
+ def attr_to_val_or_nil(klass, hash)
25
+ return nil if hash.nil?
26
+ klass.from_hash(hash)
27
+ end
21
28
  end
22
29
  end
23
30
  end
@@ -0,0 +1,21 @@
1
+ require 'academic_benchmarks/lib/attr_to_vals'
2
+ require 'academic_benchmarks/lib/inst_vars_to_hash'
3
+
4
+ module AcademicBenchmarks
5
+ module Standards
6
+ class EducationLevels
7
+ include AttrToVals
8
+ include InstVarsToHash
9
+
10
+ attr_accessor :grades
11
+
12
+ def self.from_hash(hash)
13
+ self.new(grades: hash["grades"])
14
+ end
15
+
16
+ def initialize(grades:)
17
+ @grades = attr_to_vals(Grade, grades)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -1,19 +1,18 @@
1
- require_relative '../lib/inst_vars_to_hash'
1
+ require 'academic_benchmarks/lib/inst_vars_to_hash'
2
2
 
3
3
  module AcademicBenchmarks
4
4
  module Standards
5
5
  class Grade
6
6
  include InstVarsToHash
7
7
 
8
- attr_accessor :high, :low
8
+ attr_accessor :code
9
9
 
10
10
  def self.from_hash(hash)
11
- self.new(high: hash["high"], low: hash["low"])
11
+ self.new(code: hash["code"])
12
12
  end
13
13
 
14
- def initialize(high:, low:)
15
- @high = high
16
- @low = low
14
+ def initialize(code:)
15
+ @code = code
17
16
  end
18
17
  end
19
18
  end
@@ -0,0 +1,23 @@
1
+ require 'academic_benchmarks/lib/inst_vars_to_hash'
2
+
3
+ module AcademicBenchmarks
4
+ module Standards
5
+ class Number
6
+ include InstVarsToHash
7
+
8
+ attr_accessor :enhanced, :raw
9
+
10
+ def self.from_hash(hash)
11
+ self.new(
12
+ enhanced: hash["enhanced"],
13
+ raw: hash["raw"]
14
+ )
15
+ end
16
+
17
+ def initialize(enhanced:, raw:)
18
+ @enhanced = enhanced
19
+ @raw = raw
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,59 @@
1
+ require 'academic_benchmarks/lib/attr_to_vals'
2
+ require 'academic_benchmarks/lib/inst_vars_to_hash'
3
+
4
+ module AcademicBenchmarks
5
+ module Standards
6
+ class Publication
7
+ include AttrToVals
8
+ include InstVarsToHash
9
+
10
+ attr_accessor :acronym, :descr, :guid, :authorities, :children
11
+
12
+ alias_method :code, :acronym
13
+ alias_method :description, :descr
14
+
15
+ def self.from_hash(hash)
16
+ self.new(
17
+ acronym: hash["acronym"],
18
+ descr: hash["descr"],
19
+ guid: hash["guid"],
20
+ authorities: hash["authorities"]
21
+ )
22
+ end
23
+
24
+ def initialize(acronym:, descr:, guid:, authorities:, children: [])
25
+ @acronym = acronym
26
+ @descr = descr
27
+ @guid = guid
28
+ @authorities = attr_to_vals(Authority, authorities)
29
+ @children = children
30
+ end
31
+
32
+ # Children are standards, so rebranch them so we have
33
+ # the following structure:
34
+ #
35
+ # Publication -> Document -> Section -> Standard
36
+ def rebranch_children
37
+ @seen = Set.new()
38
+ @guid_to_obj = {}
39
+ new_children = []
40
+ @children.each do |child|
41
+ doc = reparent(child.document, new_children)
42
+ sec = reparent(child.section, doc.children)
43
+ sec.children.push(child)
44
+ end
45
+ @children.replace(new_children)
46
+ remove_instance_variable('@seen')
47
+ remove_instance_variable('@guid_to_obj')
48
+ end
49
+
50
+ private
51
+
52
+ def reparent(object, children)
53
+ cached_object = (@guid_to_obj[object.guid] ||= object)
54
+ children.push(cached_object) if @seen.add? cached_object.guid
55
+ cached_object
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,23 @@
1
+ require 'academic_benchmarks/lib/inst_vars_to_hash'
2
+
3
+ module AcademicBenchmarks
4
+ module Standards
5
+ class Section
6
+ include InstVarsToHash
7
+
8
+ attr_accessor :guid, :descr, :children
9
+
10
+ alias_method :description, :descr
11
+
12
+ def self.from_hash(hash)
13
+ self.new(descr: hash["descr"], guid: hash["guid"])
14
+ end
15
+
16
+ def initialize(guid:, descr:, children: [])
17
+ @guid = guid
18
+ @descr = descr
19
+ @children = children
20
+ end
21
+ end
22
+ end
23
+ end
@@ -1,80 +1,47 @@
1
- require_relative '../lib/inst_vars_to_hash'
2
- require_relative '../lib/remove_obsolete_children'
1
+ require 'academic_benchmarks/lib/inst_vars_to_hash'
3
2
 
4
3
  module AcademicBenchmarks
5
4
  module Standards
6
5
  class Standard
7
6
  include InstVarsToHash
8
- include RemoveObsoleteChildren
9
7
 
10
- attr_reader :status, :deepest, :children
11
- attr_writer :grade
12
- attr_accessor :guid, :description, :number, :stem, :label, :level,
13
- :version, :seq, :adopt_year, :authority, :course,
14
- :document, :has_relations, :subject, :subject_doc,
8
+ attr_reader :status, :children
9
+ attr_writer :education_levels
10
+ attr_accessor :guid,
11
+ :statement,
12
+ :number, :stem, :label, :level,
13
+ :seq,
14
+ :section,
15
+ :document, :disciplines,
15
16
  :parent, :parent_guid
16
17
 
17
- alias_method :descr, :description
18
-
18
+ # Before standards are rebranched in Authority#rebranch_children
19
+ # or Document#rebranch_children, they have the following structure.
20
+ #
21
+ # Standard
22
+ # |-> Document
23
+ # | |-> Publication
24
+ # | |-> Authority
25
+ # |-> Section
26
+ #
19
27
  def initialize(data)
20
- data = data["data"] if data["data"]
21
- @guid = data["guid"]
22
- @grade = attr_to_val_or_nil(Grade, data, "grade")
23
- @label = data["label"]
24
- @level = data["level"]
25
- @course = attr_to_val_or_nil(Course, data, "course")
26
- @number = data["number"]
27
- @status = data["status"]
28
- @parent = nil
29
- @subject = attr_to_val_or_nil(Subject, data, "subject")
30
- @deepest = data["deepest"]
31
- @version = data["version"]
28
+ attributes = data["attributes"]
29
+ @guid = attributes["guid"]
30
+ @education_levels = attr_to_val_or_nil(EducationLevels, attributes, "education_levels")
31
+ @label = attributes["label"]
32
+ @level = attributes["level"]
33
+ @section = attr_to_val_or_nil(Section, attributes, "section")
34
+ @number = attr_to_val_or_nil(Number, attributes, "number")
35
+ @status = attributes["status"]
36
+ @disciplines = attr_to_val_or_nil(Disciplines, attributes, "disciplines")
32
37
  @children = []
33
- @document = attr_to_val_or_nil(Document, data, "document")
34
- @authority = attr_to_val_or_nil(Authority, data, "authority")
35
- @adopt_year = data["adopt_year"]
36
- @description = data["descr"]
37
- @subject_doc = attr_to_val_or_nil(SubjectDoc, data, "subject_doc")
38
- @has_relations = attr_to_val_or_nil(HasRelations, data, "has_relations")
39
-
40
- # Parent guid extraction can be a little more complicated
41
- if data["parent"] && data["parent"].is_a?(String)
42
- @parent_guid = data["parent"]
43
- elsif data["parent"] && data["parent"].is_a?(Hash)
44
- @parent_guid = data["parent"]["guid"]
45
- end
38
+ @document = attr_to_val_or_nil(Document, attributes, "document")
39
+ @statement = attr_to_val_or_nil(Statement, attributes, "statement")
40
+ @parent_guid = data.dig("relationships", "parent", "data", "id")
46
41
  end
47
42
 
48
43
  alias_method :from_hash, :initialize
49
44
 
50
- def active?
51
- status == "Active"
52
- end
53
-
54
- def obsolete?
55
- status == "Obsolete"
56
- end
57
-
58
- def deepest?
59
- deepest == 'Y'
60
- end
61
-
62
- def status=(status)
63
- unless %w[Active Obsolete].include?(status)
64
- raise ArgumentError.new(
65
- "Standard status must be either 'Active' or 'Obsolete'"
66
- )
67
- end
68
- @status = status
69
- end
70
-
71
- def deepest=(deepest)
72
- unless %w[Y N].include?(deepest)
73
- raise ArgumentError.new("Standard deepest must be either 'Y' or 'N'")
74
- end
75
- @deepest = deepest
76
- end
77
-
78
45
  def add_child(child)
79
46
  raise StandardError.new("Tried to add self as a child") if self == child
80
47
 
@@ -94,17 +61,13 @@ module AcademicBenchmarks
94
61
  @children.count > 0
95
62
  end
96
63
 
97
- def leaf?
98
- !has_children?
99
- end
100
-
101
- def grade
102
- return @grade if @grade
64
+ def education_levels
65
+ return @education_levels if @education_levels
103
66
 
104
- # check to see if one of our parents has a grade. Use that if so
67
+ # check to see if one of our parents has education levels. Use that if so
105
68
  p = parent
106
69
  while p
107
- return p.grade if p.grade
70
+ return p.education_levels if p.education_levels
108
71
  p = p.parent
109
72
  end
110
73
  nil
@@ -114,7 +77,7 @@ module AcademicBenchmarks
114
77
 
115
78
  def attr_to_val_or_nil(klass, hash, attr)
116
79
  return nil unless hash.key?(attr)
117
- klass.from_hash(hash)
80
+ klass.from_hash(hash[attr])
118
81
  end
119
82
  end
120
83
  end
@@ -1,36 +1,17 @@
1
1
  module AcademicBenchmarks
2
2
  module Standards
3
3
  class StandardsForest
4
- attr_reader :trees, :data_hash, :orphans
5
-
6
- # The guid to standard hash can optionally be saved to permit speedily
7
- # adding standards to the tree (since the tree is unordered,
8
- # this would otherwise be an expensive operation).
9
- #
10
- # The initial data hash can also be optionally saved to
11
- # permit testing and internal consistency checks
12
-
13
- def initialize(
14
- data_hash,
15
- save_guid_to_standard_hash: true,
16
- save_initial_data_hash: false,
17
- include_obsoletes: true
18
- )
19
- @data_hash = data_hash.dup.freeze if save_initial_data_hash
4
+ attr_reader :trees, :orphans
5
+
6
+ def initialize(data_hash)
20
7
  @guid_to_standard = {} # a hash of guids to standards
21
8
  @trees = []
22
9
  @orphans = []
23
10
  process_items(data_hash)
24
11
 
25
- @trees.delete_if(&:obsolete?) unless include_obsoletes
26
-
27
12
  # upgrade the hash data to a StandardsTree object
28
13
  @trees.map! do |item|
29
- StandardsTree.new(
30
- item,
31
- build_item_hash: save_guid_to_standard_hash,
32
- include_obsoletes: include_obsoletes
33
- )
14
+ StandardsTree.new(item)
34
15
  end
35
16
 
36
17
  # We will still have the guid-to-standards saved at the Tree level,
@@ -47,21 +28,6 @@ module AcademicBenchmarks
47
28
  StandardsTree.new(root).tap{ |st| st.add_orphans(@orphans) }
48
29
  end
49
30
 
50
- def add_standard(standard)
51
- if standard.is_a?(Standard)
52
- raise StandardError.new(
53
- "adding standards is not currently implemented"
54
- )
55
- elsif standard.is_a?(Hash)
56
- add_standard(Standard.new(standard))
57
- else
58
- raise ArgumentError.new(
59
- "standard must be an 'AcademicBenchmarks::Standards::Standard' " \
60
- "or a 'Hash' but was a #{standard.class}"
61
- )
62
- end
63
- end
64
-
65
31
  def single_tree?
66
32
  @trees.count == 1
67
33
  end
@@ -6,40 +6,10 @@ module AcademicBenchmarks
6
6
  attr_reader :root, :orphans
7
7
  delegate :children, :to_s, :to_h, :to_json, to: :root
8
8
 
9
- # The item hash can optionally be built to permit the speedy
10
- # addition of standards to the tree. since the tree is unordered,
11
- # adding to it can be expensive without this
12
-
13
- def initialize(root, build_item_hash: true, include_obsoletes: true)
9
+ def initialize(root)
14
10
  @orphans = []
15
11
  @root = root
16
- prune_obsolete_branches unless include_obsoletes
17
-
18
- if build_item_hash
19
- @item_hash = {}
20
- go_ahead_and_build_item_hash
21
- end
22
- end
23
-
24
- def add_standard(standard)
25
- if standard.is_a?(Standard)
26
- parent = @item_hash ? @item_hash[standard.parent_guid] : find_parent(standard)
27
- unless parent
28
- raise StandardError.new(
29
- "Parent of standard not found in tree. Parent guid is " \
30
- "'#{standard.parent_guid}' and child guid is '#{standard.guid}'"
31
- )
32
- end
33
- parent.add_child(standard)
34
- standard.parent = parent
35
- elsif standard.is_a?(Hash)
36
- add_standard(Standard.new(standard))
37
- else
38
- raise ArgumentError.new(
39
- "standard must be an 'AcademicBenchmarks::Standards::Standard' " \
40
- "or a 'Hash' but was a #{standard.class}"
41
- )
42
- end
12
+ root.rebranch_children if root.is_a?(Authority) || root.is_a?(Publication)
43
13
  end
44
14
 
45
15
  def add_orphan(orphan)
@@ -53,37 +23,6 @@ module AcademicBenchmarks
53
23
  def has_orphans?
54
24
  @orphans.present?
55
25
  end
56
-
57
- private
58
-
59
- def go_ahead_and_build_item_hash
60
- @item_hash[@root.guid] = @root
61
- add_children_to_item_hash(@root)
62
- end
63
-
64
- def add_children_to_item_hash(parent)
65
- parent.children.each do |child|
66
- @item_hash[child.guid] = child
67
- add_children_to_item_hash(child) if child.has_children?
68
- end
69
- end
70
-
71
- def find_parent(standard)
72
- return @root if @root.guid == standard.parent_guid
73
- check_children_for_parent(standard.parent_guid, @root)
74
- end
75
-
76
- # does a depth-first search
77
- def check_children_for_parent(parent_guid, standard)
78
- standard.children.each do |child|
79
- return child if child.guid == parent_guid
80
- check_children_for_parent(parent_guid, child) if child.has_children?
81
- end
82
- end
83
-
84
- def prune_obsolete_branches
85
- root.remove_obsolete_children
86
- end
87
26
  end
88
27
  end
89
28
  end