academic_benchmarks 0.0.4 → 0.0.5

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5d61a80eca5cb7536525e3359da6693d928d24d4
4
- data.tar.gz: 254a3dc74b516c970eb2ec49fb160ef6f285ebbf
3
+ metadata.gz: 7541ca8bbc79a966e924b5de4bd0cfd407d154c3
4
+ data.tar.gz: 00c65e4ec6204e68cff41b59db745b5e70982194
5
5
  SHA512:
6
- metadata.gz: 69667639168d5e6fb7c90f6fe927a0fedfe21675820432182b0f88776b453ee530fd477f6ae0b35aaa8bd85e8780c0a794e86628ba08a98619a4be5146dbcf2d
7
- data.tar.gz: 09e2bacc1aae34f23180c0f0e313e2c49e918f61cbbe4fdc2ce01e65adf8e4b9fd262840fc9a83869fa87360e4d0b861824662cbc62520c0200340ef002c191a
6
+ metadata.gz: 57c6ccc816f6552ae6b5fd5d755ab2bd912660ea73d16c6dc7efaeea89e6c490a1580d0853261735e6f18f5abf3688d8b0b5e05c0b63c5d2d9854cef44213cc9
7
+ data.tar.gz: 7cb00c099914d545e8011c3a93afd270d1b65440f2c977ac4252e8edfa2fbf08c2865d10a1ef84ecb88052254d94e4e7ff6c77ba9834a85d1a29acf7ceef200f
@@ -49,51 +49,86 @@ module AcademicBenchmarks
49
49
  request_search_pages_and_concat_resources(auth_query_params)
50
50
  end
51
51
 
52
- def authorities
53
- raw_search(list: "authority").map do |a|
52
+ def authorities(query_params = {})
53
+ raw_search({list: "authority"}.merge(query_params)).map do |a|
54
54
  AcademicBenchmarks::Standards::Authority.from_hash(a["data"]["authority"])
55
55
  end
56
56
  end
57
57
 
58
- def documents
59
- raw_search(list: "document").map do |a|
58
+ def documents(query_params = {})
59
+ raw_search({list: "document"}.merge(query_params)).map do |a|
60
60
  AcademicBenchmarks::Standards::Document.from_hash(a["data"]["document"])
61
61
  end
62
62
  end
63
63
 
64
- def authority_tree(authority_or_authority_code_guid_or_desc)
65
- authority = if authority_or_authority_code_guid_or_desc.is_a?(Authority)
66
- authority_or_authority_code_guid_or_desc
67
- else
68
- find_authority(authority_or_authority_code_guid_or_desc)
69
- end
64
+ def authority_documents(authority_or_auth_code_guid_or_desc)
65
+ authority = auth_from_code_guid_or_desc(authority_or_auth_code_guid_or_desc)
66
+ documents(authority: authority.code)
67
+ end
68
+
69
+ def authority_tree(authority_or_auth_code_guid_or_desc, include_obsolete_standards: true)
70
+ authority = auth_from_code_guid_or_desc(authority_or_auth_code_guid_or_desc)
70
71
  auth_children = search(authority: authority.code)
71
- StandardsForest.new(auth_children).consolidate_under_root(authority)
72
+ AcademicBenchmarks::Standards::StandardsForest.new(
73
+ auth_children,
74
+ include_obsoletes: include_obsolete_standards
75
+ ).consolidate_under_root(authority)
76
+ end
77
+
78
+ def document_tree(document_or_guid, include_obsolete_standards: true)
79
+ document = doc_from_guid(document_or_guid)
80
+ doc_children = search(document: document.guid)
81
+ AcademicBenchmarks::Standards::StandardsForest.new(
82
+ doc_children,
83
+ include_obsoletes: include_obsolete_standards
84
+ ).consolidate_under_root(document)
72
85
  end
73
86
 
74
87
  private
75
88
 
76
- def find_authority(authority_code_guid_or_desc)
77
- auths = match_authority(authority_code_guid_or_desc)
78
- if auths.empty?
79
- raise StandardError,
80
- "No authority code, guid, or description matched '#{authority_code_guid_or_desc}'"
81
- elsif auths.count > 1
82
- raise StandardError,
89
+ def doc_from_guid(document_or_guid)
90
+ if document_or_guid.is_a?(AcademicBenchmarks::Standards::Document)
91
+ document_or_guid
92
+ else
93
+ find_type(type: "document", data: document_or_guid)
94
+ end
95
+ end
96
+
97
+ def auth_from_code_guid_or_desc(authority_or_auth_code_guid_or_desc)
98
+ if authority_or_auth_code_guid_or_desc.is_a?(AcademicBenchmarks::Standards::Authority)
99
+ authority_or_auth_code_guid_or_desc
100
+ else
101
+ find_type(type: "authority", data: authority_or_auth_code_guid_or_desc)
102
+ end
103
+ end
104
+
105
+ def find_type(type:, data:)
106
+ matches = send("match_#{type}", data)
107
+ if matches.empty?
108
+ raise StandardError.new(
109
+ "No #{type} code, guid, or description matched '#{data}'"
110
+ )
111
+ elsif matches.count > 1
112
+ raise StandardError.new(
83
113
  "Authority code, guid, or description matched more than one authority. " \
84
- "matched '#{auths.map(&:to_json).join('; ')}'"
114
+ "matched '#{matches.map(&:to_json).join('; ')}'"
115
+ )
85
116
  end
86
- auths.first
117
+ matches.first
87
118
  end
88
119
 
89
- def match_authority(authority_code_guid_or_desc)
120
+ def match_authority(data)
90
121
  authorities.select do |auth|
91
- auth.code == authority_code_guid_or_desc ||
92
- auth.guid == authority_code_guid_or_desc ||
93
- auth.descr == authority_code_guid_or_desc
122
+ auth.code == data ||
123
+ auth.guid == data ||
124
+ auth.descr == data
94
125
  end
95
126
  end
96
127
 
128
+ def match_document(data)
129
+ documents.select { |doc| doc.guid == data }
130
+ end
131
+
97
132
  def raw_search(opts = {})
98
133
  request_search_pages_and_concat_resources(opts.merge(auth_query_params))
99
134
  end
@@ -1,4 +1,3 @@
1
-
2
1
  #
3
2
  # This module will allow you to properly to_s, to_h, and to_json
4
3
  # on classes in which it is included.
@@ -10,22 +9,28 @@
10
9
  #
11
10
 
12
11
  module InstVarsToHash
13
- def to_s(omit_parent: true)
14
- to_h(omit_parent: omit_parent).to_s
12
+ def to_s(omit_parent: true, omit_empty_children: true)
13
+ to_h(
14
+ omit_parent: omit_parent,
15
+ omit_empty_children: omit_empty_children
16
+ ).to_s
15
17
  end
16
18
 
17
- def to_h(omit_parent: true)
19
+ def to_h(omit_parent: true, omit_empty_children: true)
18
20
  retval = {}
19
21
  instance_variables.each do |iv|
20
- unless omit_parent && (iv =~ /^@?parent$/i)
22
+ if !(skip_parent?(omit_parent, iv) || skip_children?(omit_empty_children, iv))
21
23
  retval[iv.to_s.delete('@').to_sym] = elem_to_h(instance_variable_get(iv))
22
24
  end
23
25
  end
24
26
  retval
25
27
  end
26
28
 
27
- def to_json(omit_parent: true)
28
- to_h(omit_parent: omit_parent).to_json
29
+ def to_json(omit_parent: true, omit_empty_children: true)
30
+ to_h(
31
+ omit_parent: omit_parent,
32
+ omit_empty_children: omit_empty_children
33
+ ).to_json
29
34
  end
30
35
 
31
36
  private
@@ -47,4 +52,12 @@ module InstVarsToHash
47
52
  elem
48
53
  end
49
54
  end
55
+
56
+ def skip_parent?(omit_parent, iv)
57
+ omit_parent && (iv =~ /^@?parent$/i)
58
+ end
59
+
60
+ def skip_children?(omit_empty_children, iv)
61
+ omit_empty_children && (iv =~ /^@?children$/i) && instance_variable_get(iv).empty?
62
+ end
50
63
  end
@@ -0,0 +1,10 @@
1
+ module RemoveObsoleteChildren
2
+ def remove_obsolete_children
3
+ @children.delete_if do |child|
4
+ unless child.obsolete?
5
+ child.remove_obsolete_children
6
+ end
7
+ child.obsolete?
8
+ end
9
+ end
10
+ end
@@ -1,9 +1,11 @@
1
1
  require_relative '../lib/inst_vars_to_hash'
2
+ require_relative '../lib/remove_obsolete_children'
2
3
 
3
4
  module AcademicBenchmarks
4
5
  module Standards
5
6
  class Authority
6
7
  include InstVarsToHash
8
+ include RemoveObsoleteChildren
7
9
 
8
10
  attr_accessor :code, :guid, :description, :children
9
11
 
@@ -1,19 +1,22 @@
1
1
  require_relative '../lib/inst_vars_to_hash'
2
+ require_relative '../lib/remove_obsolete_children'
2
3
 
3
4
  module AcademicBenchmarks
4
5
  module Standards
5
6
  class Document
6
7
  include InstVarsToHash
8
+ include RemoveObsoleteChildren
7
9
 
8
- attr_accessor :title, :guid
10
+ attr_accessor :title, :guid, :children
9
11
 
10
12
  def self.from_hash(hash)
11
13
  self.new(title: hash["title"], guid: hash["guid"])
12
14
  end
13
15
 
14
- def initialize(title:, guid:)
16
+ def initialize(title:, guid:, children: [])
15
17
  @title = title
16
18
  @guid = guid
19
+ @children = children
17
20
  end
18
21
  end
19
22
  end
@@ -1,15 +1,18 @@
1
1
  require_relative '../lib/inst_vars_to_hash'
2
+ require_relative '../lib/remove_obsolete_children'
2
3
 
3
4
  module AcademicBenchmarks
4
5
  module Standards
5
6
  class Standard
6
7
  include InstVarsToHash
8
+ include RemoveObsoleteChildren
7
9
 
8
10
  attr_reader :status, :deepest, :children
11
+ attr_writer :grade
9
12
  attr_accessor :guid, :description, :number, :stem, :label, :level,
10
13
  :version, :seq, :adopt_year, :authority, :course,
11
- :document, :grade, :has_relations, :subject,
12
- :subject_doc, :parent, :parent_guid
14
+ :document, :has_relations, :subject, :subject_doc,
15
+ :parent, :parent_guid
13
16
 
14
17
  alias_method :descr, :description
15
18
 
@@ -34,7 +37,7 @@ module AcademicBenchmarks
34
37
  @subject_doc = attr_to_val_or_nil(SubjectDoc, data, "subject_doc")
35
38
  @has_relations = attr_to_val_or_nil(HasRelations, data, "has_relations")
36
39
 
37
- # Parent guid extraction can be a little more complicated. Thanks AB!
40
+ # Parent guid extraction can be a little more complicated
38
41
  if data["parent"] && data["parent"].is_a?(String)
39
42
  @parent_guid = data["parent"]
40
43
  elsif data["parent"] && data["parent"].is_a?(Hash)
@@ -42,6 +45,8 @@ module AcademicBenchmarks
42
45
  end
43
46
  end
44
47
 
48
+ alias_method :from_hash, :initialize
49
+
45
50
  def active?
46
51
  status == "Active"
47
52
  end
@@ -71,13 +76,17 @@ module AcademicBenchmarks
71
76
  end
72
77
 
73
78
  def add_child(child)
79
+ raise StandardError.new("Tried to add self as a child") if self == child
80
+
74
81
  unless child.is_a?(Standard)
75
82
  raise ArgumentError.new("Tried to set child that isn't a Standard")
76
83
  end
84
+ child.parent = self
77
85
  @children.push(child)
78
86
  end
79
87
 
80
88
  def remove_child(child)
89
+ child.parent = nil
81
90
  @children.delete(child)
82
91
  end
83
92
 
@@ -85,10 +94,26 @@ module AcademicBenchmarks
85
94
  @children.count > 0
86
95
  end
87
96
 
97
+ def leaf?
98
+ !has_children?
99
+ end
100
+
101
+ def grade
102
+ return @grade if @grade
103
+
104
+ # check to see if one of our parents has a grade. Use that if so
105
+ p = parent
106
+ while p
107
+ return p.grade if p.grade
108
+ p = p.parent
109
+ end
110
+ nil
111
+ end
112
+
88
113
  private
89
114
 
90
115
  def attr_to_val_or_nil(klass, hash, attr)
91
- return nil unless hash.has_key?(attr)
116
+ return nil unless hash.key?(attr)
92
117
  klass.from_hash(hash)
93
118
  end
94
119
  end
@@ -1,7 +1,7 @@
1
1
  module AcademicBenchmarks
2
2
  module Standards
3
3
  class StandardsForest
4
- attr_reader :trees, :data_hash
4
+ attr_reader :trees, :data_hash, :orphans
5
5
 
6
6
  # The guid to standard hash can optionally be saved to permit speedily
7
7
  # adding standards to the tree (since the tree is unordered,
@@ -13,21 +13,29 @@ module AcademicBenchmarks
13
13
  def initialize(
14
14
  data_hash,
15
15
  save_guid_to_standard_hash: true,
16
- save_initial_data_hash: false
16
+ save_initial_data_hash: false,
17
+ include_obsoletes: true
17
18
  )
18
19
  @data_hash = data_hash.dup.freeze if save_initial_data_hash
19
20
  @guid_to_standard = {} # a hash of guids to standards
20
21
  @trees = []
22
+ @orphans = []
21
23
  process_items(data_hash)
22
24
 
25
+ @trees.delete_if(&:obsolete?) unless include_obsoletes
26
+
23
27
  # upgrade the hash data to a StandardsTree object
24
28
  @trees.map! do |item|
25
- StandardsTree.new(item, build_item_hash: save_guid_to_standard_hash)
29
+ StandardsTree.new(
30
+ item,
31
+ build_item_hash: save_guid_to_standard_hash,
32
+ include_obsoletes: include_obsoletes
33
+ )
26
34
  end
27
35
 
28
- unless save_guid_to_standard_hash
29
- remove_instance_variable('@guid_to_standard')
30
- end
36
+ # We will still have the guid-to-standards saved at the Tree level,
37
+ # so we can safely remove this variable and let the GC free the memory
38
+ remove_instance_variable('@guid_to_standard')
31
39
  end
32
40
 
33
41
  def consolidate_under_root(root)
@@ -36,7 +44,7 @@ module AcademicBenchmarks
36
44
  tree.root.parent_guid = root.guid
37
45
  root.children.push(tree.root)
38
46
  end
39
- StandardsTree.new(root)
47
+ StandardsTree.new(root).tap{ |st| st.add_orphans(@orphans) }
40
48
  end
41
49
 
42
50
  def add_standard(standard)
@@ -49,7 +57,7 @@ module AcademicBenchmarks
49
57
  else
50
58
  raise ArgumentError.new(
51
59
  "standard must be an 'AcademicBenchmarks::Standards::Standard' " \
52
- "or a 'Hash' but was a #{standard.class.to_s}"
60
+ "or a 'Hash' but was a #{standard.class}"
53
61
  )
54
62
  end
55
63
  end
@@ -62,16 +70,20 @@ module AcademicBenchmarks
62
70
  @trees.empty?
63
71
  end
64
72
 
73
+ def has_orphans?
74
+ @orphans.count > 0
75
+ end
76
+
65
77
  def to_s
66
- trees.map{|tree| tree.to_s}
78
+ trees.map(&:to_s)
67
79
  end
68
80
 
69
81
  def to_h
70
- trees.map{|tree| tree.to_h}
82
+ trees.map(&:to_h)
71
83
  end
72
84
 
73
85
  def to_json
74
- trees.map{|tree| tree.to_json}
86
+ trees.map(&:to_h).to_json
75
87
  end
76
88
 
77
89
  private
@@ -96,22 +108,21 @@ module AcademicBenchmarks
96
108
  def link_parent_and_children
97
109
  @guid_to_standard.values.each do |child|
98
110
  if child.parent_guid
99
- present_in_hash_or_raise(child.parent_guid)
100
- parent = @guid_to_standard[child.parent_guid]
101
- parent.add_child(child)
102
- child.parent = parent
111
+ parent_in_hash?(child.parent_guid) ? set_parent_and_child(child) : @orphans.push(child)
103
112
  else
104
113
  @trees.push(child)
105
114
  end
106
115
  end
107
116
  end
108
117
 
109
- def present_in_hash_or_raise(guid)
110
- unless @guid_to_standard.has_key?(guid)
111
- raise StandardError.new(
112
- "item missing from guid_to_standard hash"
113
- )
114
- end
118
+ def set_parent_and_child(child)
119
+ parent = @guid_to_standard[child.parent_guid]
120
+ parent.add_child(child)
121
+ child.parent = parent
122
+ end
123
+
124
+ def parent_in_hash?(guid)
125
+ @guid_to_standard.key?(guid)
115
126
  end
116
127
  end
117
128
  end
@@ -3,15 +3,18 @@ require 'active_support/core_ext/module'
3
3
  module AcademicBenchmarks
4
4
  module Standards
5
5
  class StandardsTree
6
- attr_reader :root
6
+ attr_reader :root, :orphans
7
7
  delegate :children, :to_s, :to_h, :to_json, to: :root
8
8
 
9
9
  # The item hash can optionally be built to permit the speedy
10
10
  # addition of standards to the tree. since the tree is unordered,
11
11
  # adding to it can be expensive without this
12
12
 
13
- def initialize(root, build_item_hash: true)
13
+ def initialize(root, build_item_hash: true, include_obsoletes: true)
14
+ @orphans = []
14
15
  @root = root
16
+ prune_obsolete_branches unless include_obsoletes
17
+
15
18
  if build_item_hash
16
19
  @item_hash = {}
17
20
  go_ahead_and_build_item_hash
@@ -34,11 +37,23 @@ module AcademicBenchmarks
34
37
  else
35
38
  raise ArgumentError.new(
36
39
  "standard must be an 'AcademicBenchmarks::Standards::Standard' " \
37
- "or a 'Hash' but was a #{standard.class.to_s}"
40
+ "or a 'Hash' but was a #{standard.class}"
38
41
  )
39
42
  end
40
43
  end
41
44
 
45
+ def add_orphan(orphan)
46
+ add_orphans([orphan])
47
+ end
48
+
49
+ def add_orphans(orphans)
50
+ @orphans.concat(orphans)
51
+ end
52
+
53
+ def has_orphans?
54
+ @orphans.present?
55
+ end
56
+
42
57
  private
43
58
 
44
59
  def go_ahead_and_build_item_hash
@@ -65,6 +80,10 @@ module AcademicBenchmarks
65
80
  check_children_for_parent(parent_guid, child) if child.has_children?
66
81
  end
67
82
  end
83
+
84
+ def prune_obsolete_branches
85
+ root.remove_obsolete_children
86
+ end
68
87
  end
69
88
  end
70
89
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: academic_benchmarks
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Benjamin Porter
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-01-15 00:00:00.000000000 Z
11
+ date: 2016-02-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: httparty
@@ -155,6 +155,7 @@ files:
155
155
  - lib/academic_benchmarks/api/handle.rb
156
156
  - lib/academic_benchmarks/api/standards.rb
157
157
  - lib/academic_benchmarks/lib/inst_vars_to_hash.rb
158
+ - lib/academic_benchmarks/lib/remove_obsolete_children.rb
158
159
  - lib/academic_benchmarks/standards/authority.rb
159
160
  - lib/academic_benchmarks/standards/course.rb
160
161
  - lib/academic_benchmarks/standards/document.rb