• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

hathitrust / holdings-backend / 13379555496

17 Feb 2025 10:31PM UTC coverage: 66.964%. First build
13379555496

Pull #344

github

web-flow
Merge cf5aa3ec1 into 2635c8806
Pull Request #344: DEV-1534 FrequencyTable: implement 'deserialize' method

43 of 44 new or added lines in 2 files covered. (97.73%)

6012 of 8978 relevant lines covered (66.96%)

29.45 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

98.39
/lib/frequency_table.rb
1
# frozen_string_literal: true
2

3
require "json"
1✔
4

5
require "calculate_format"
1✔
6
require "overlap/ht_item_overlap"
1✔
7

8
class FrequencyTable
1✔
9
  protected attr_reader :table
1✔
10

11
  def initialize(data: nil)
1✔
12
    @table = case data
53✔
13
    when String
14
      JSON.parse(data, symbolize_names: true)
10✔
15
    when Hash
16
      deep_copy data
21✔
17
    when NilClass
18
      {}
22✔
19
    else
NEW
20
      raise "unrecognized data format #{data.inspect}"
×
21
    end
22
  end
23

24
  def to_json
1✔
25
    JSON.generate(table)
5✔
26
  end
27

28
  def ==(other)
1✔
29
    self.class == other.class && table == other.table
2✔
30
  end
31

32
  def organizations
1✔
33
    table.keys.sort
12✔
34
  end
35

36
  def fetch(organization: nil, format: nil, bucket: nil)
1✔
37
    return table if organization.nil?
216✔
38

39
    data = table[organization.to_sym] || {}
213✔
40
    if format
213✔
41
      data = data[format.to_sym] || {}
202✔
42
      if bucket
202✔
43
        data = data[bucket.to_s.to_sym] || 0
8✔
44
      end
45
    end
46
    data
213✔
47
  end
48

49
  def each
1✔
50
    table.each do |key, value|
11✔
51
      yield key, value
14✔
52
    end
53
  end
54

55
  def +(other)
1✔
56
    new_obj = self.class.new
3✔
57
    new_obj.append! self
3✔
58
    new_obj.append! other
3✔
59
  end
60

61
  # We try to optimize this beyond a deep addition from the leaves inward by
62
  # checking for missing keys and when possible copying chunks of the operand's
63
  # data structure.
64
  # We use `Marshal` for deep copies and `clone` for shallow copies in order to keep
65
  # prevent subsequent changes to the addend from affecting this object.
66
  def append!(other)
1✔
67
    other.each do |org, data|
11✔
68
      # Example data: org = :umich, data = {:spm=>{1=>1}}
69
      if !table.key? org
14✔
70
        table[org] = deep_copy other.table[org]
11✔
71
        next
11✔
72
      end
73
      table[org] = {} unless table.key?(org)
3✔
74
      data.each do |fmt, frequencies|
3✔
75
        # Example data: fmt = :spm, frequencies = {1 => 1}
76
        #
77
        # Safe to shallow clone `frequencies` since its keys and values are scalars.
78
        if !table[org].key? fmt
3✔
79
          table[org][fmt] = frequencies.clone
1✔
80
          next
1✔
81
        end
82
        frequencies.each do |bucket, count|
2✔
83
          table[org][fmt][bucket] += count
2✔
84
        end
85
      end
86
    end
87
    self
11✔
88
  end
89

90
  def add_ht_item(ht_item)
1✔
91
    item_format = CalculateFormat.new(ht_item.cluster).item_format(ht_item).to_sym
25✔
92
    item_overlap = Overlap::HtItemOverlap.new(ht_item)
25✔
93
    member_count = item_overlap.matching_members.count
25✔
94
    item_overlap.matching_members.each do |org|
25✔
95
      increment(organization: org, format: item_format, bucket: member_count)
40✔
96
    end
97
  end
98

99
  def increment(organization:, format:, bucket:)
1✔
100
    org = organization.to_sym
48✔
101
    fmt = format.to_sym
48✔
102
    bucket = bucket.to_s.to_sym
48✔
103
    table[org] = {} unless table.key?(org)
48✔
104
    table[org][fmt] = {} unless table[org].key?(fmt)
48✔
105
    table[org][fmt][bucket] = 0 unless table[org][fmt].key?(bucket)
48✔
106
    table[org][fmt][bucket] += 1
48✔
107
  end
108

109
  private
1✔
110

111
  def deep_copy(obj)
1✔
112
    Marshal.load(Marshal.dump(obj))
32✔
113
  end
114
end
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc