Completed
Push — master ( c714c7...739021 )
by
unknown
05:26 queued 03:15
created

SchedulesHelper.session_columns_for_slot()   A

Complexity

Conditions 2

Size

Total Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
dl 0
loc 7
rs 9.4285
c 0
b 0
f 0
1
module SchedulesHelper
2
3
  def pill_label(slot)
4
    slot.starts_at.in_time_zone.to_s(:usahhmm)
5
  end
6
7
  def session_columns_for_slot(slot, &block)
8
    if params[:stable_room_order].to_i == 1
9
      stable_room_order_session_columns_for_slot(slot, &block)
10
    else
11
      balanced_session_columns_for_slot(slot, &block)
12
    end
13
  end
14
15
private
16
17
  def stable_room_order_session_columns_for_slot(slot, &block)
18
    sessions = slot.sessions.sort_by { |s| session_sort_order(s) }
19
    split = (sessions.size+1) / 2
20
    yield sessions[0...split]
21
    yield sessions[split..-1]
22
  end
23
24
  # Attempt to divide these sessions into two roughly equal groups of roughly equal height.
25
  # (Without this, the fully expanded details grow very lopsided.)
26
  #
27
  def balanced_session_columns_for_slot(slot, &block)
28
29
    unassigned = slot.sessions.sort_by { |s| -estimated_height(s) }
30
31
    columns = [[], []]
32
    heights = [0, 0]
33
    i = 0
34
    first = true
35
    until unassigned.empty?
36
      if unassigned.size == 1 && columns[0].size == columns[1].size  # odd number of sessions, so last one can go in either column
37
        i = if heights[0] < heights[1]
38
          0
39
        else
40
          1
41
        end
42
      end
43
44
      if first
45
        # Start by placing longest description
46
        session = unassigned.shift
47
        first = false
48
      else
49
        # Greedy algo: choose next session to try to keep heights as close as possible
50
        desired_height = heights[1-i] - heights[i]
51
        session = nil
52
        best_diff = 1 / 0.0
53
        unassigned.each do |candidate|  # O(n^2), so watch this one if we start assigning lots of sessions per slot!
54
          diff = (estimated_height(candidate) - desired_height).abs
55
          if diff < best_diff
56
            best_diff = diff
57
            session = candidate
58
          end
59
        end
60
        unassigned.delete(session)
61
      end
62
      break unless session
63
64
      columns[i] << session
65
      heights[i] += estimated_height(session)
66
      i = 1-i
67
    end
68
69
    # Now yield each column with session sorted by room size.
70
71
    columns.map! { |col| col.sort_by { |s| session_sort_order(s) } }
72
    unless columns[0].empty? || columns[1].empty?
73
      if columns[0].first.attendance_count < columns[1].first.attendance_count
74
        columns = [columns[1], columns[0]]
75
      end
76
    end
77
78
    columns.each(&block)
79
  end
80
81
  def session_sort_order(session)
82
    [-session.attendance_count, session.room&.name || ""]
0 ignored issues
show
Bug introduced by
The Ruby parser could not interpret the code. It reported: unexpected token error (Using Ruby 2.0 pa...meter, under `AllCops`).
Loading history...
Bug introduced by
The Ruby parser could not interpret the code. It reported: unexpected token tRBRACK (Using Ruby 2.0 ...meter, under `AllCops`).
Loading history...
83
  end
84
85
  def estimated_height(session)
86
    if session.instance_variable_get(:@estimated_height).blank?
87
      h = 0
88
      h += (session.title.length / 42 + 1) * 25
89
      h += (session.presenters.size / 5 + 1) * 20
90
      h += session.description.length / 4 + 17
91
      session.presenters.each { |presenter| h += (presenter.bio || '').length / 5 + 30}
92
      session.instance_variable_set(:@estimated_height, h)
93
    end
94
    session.instance_variable_get(:@estimated_height)
95
  end
96
97
end
98
0 ignored issues
show
Bug introduced by
The Ruby parser could not interpret the code. It reported: unexpected token $end (Using Ruby 2.0 par...meter, under `AllCops`).
Loading history...