Class: DataSet

Inherits:
Object
  • Object
show all
Includes:
Enumerable
Defined in:
lib/tukey/data_set.rb,
lib/tukey/data_set/label.rb

Defined Under Namespace

Classes: Label

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(data: nil, label: nil, parent: nil, id: nil) ⇒ DataSet

Returns a new instance of DataSet.



13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# File 'lib/tukey/data_set.rb', line 13

def initialize(data: nil, label: nil, parent: nil, id: nil)
  self.data = data # We have to use `self` here because we have a custom setter for `data`
  @parent = parent
  @id = id || SecureRandom.uuid

  return unless label

  if label.is_a?(DataSet::Label)
    @label = label
  elsif label.is_a?(String)
    @label = DataSet::Label.new(label)
  elsif label.is_a?(Hash)
    @label = DataSet::Label.new(label.delete(:name), **label)
  else
    fail ArgumentError, 'Given unsupported label type to DataSet initialize'
  end
end

Instance Attribute Details

#dataObject

Returns the value of attribute data.



9
10
11
# File 'lib/tukey/data_set.rb', line 9

def data
  @data
end

#idObject (readonly)

Returns the value of attribute id.



11
12
13
# File 'lib/tukey/data_set.rb', line 11

def id
  @id
end

#labelObject

Returns the value of attribute label.



7
8
9
# File 'lib/tukey/data_set.rb', line 7

def label
  @label
end

#parentObject

Returns the value of attribute parent.



10
11
12
# File 'lib/tukey/data_set.rb', line 10

def parent
  @parent
end

Instance Method Details

#<<(item) ⇒ Object Also known as: add_item



31
32
33
34
35
36
# File 'lib/tukey/data_set.rb', line 31

def <<(item)
  self.data ||= []
  fail(CannotAddToNonEnumerableData, parent: self, item: item) unless data_array?
  item.parent = self
  data.push(item)
end

#<=>(other) ⇒ Object



157
158
159
160
161
162
163
164
# File 'lib/tukey/data_set.rb', line 157

def <=>(other)
  return 0 if data == other.data && label == other.label
  return 1 if data && other.data.nil?
  return -1 if data.nil? && other.data
  return label.id <=> other.label.id if label.id <=> other.label.id
  return data <=> other.data if data.is_a?(Numeric) && other.data.is_a?(Numeric)
  data.size <=> other.data.size
end

#==(other) ⇒ Object

is used for comparison of two instances directly



167
168
169
170
171
# File 'lib/tukey/data_set.rb', line 167

def ==(other)
  other_data = other.data.nil? ? nil : (other.data.is_a?(Enumerable) ? other.data.sort : other.data )
  own_data = data.nil? ? nil : (data.is_a?(Enumerable) ? data.sort : data )
  other.label == label && other_data == own_data
end

#averageObject



211
212
213
214
215
# File 'lib/tukey/data_set.rb', line 211

def average
  values = [reducable_values].flatten.compact
  return nil if values.empty?
  (values.inject(&:+).to_f / values.size).to_f
end

#branch?Boolean

Returns:

  • (Boolean)


74
75
76
# File 'lib/tukey/data_set.rb', line 74

def branch?
  children.any?
end

#child_branchesObject



78
79
80
# File 'lib/tukey/data_set.rb', line 78

def child_branches
  children.select(&:branch?)
end

#childrenObject



44
45
46
47
# File 'lib/tukey/data_set.rb', line 44

def children
  return data if data_array?
  []
end

#combine(other_data_set, operator) ⇒ Object



223
224
225
226
227
228
229
230
231
232
233
# File 'lib/tukey/data_set.rb', line 223

def combine(other_data_set, operator)
  combined_data_set = dup
  if data_array? && other_data_set.data_array?
    combined_data_set.data = combine_data_array(other_data_set.children, operator)
  elsif !data_array? && !other_data_set.data_array?
    combined_data_set.data = combine_data_value(other_data_set.value, operator)
  else
    fail ArgumentError, "Can't combine array DataSet with value DataSet"
  end
  combined_data_set
end

#compact_onelingsObject



58
59
60
# File 'lib/tukey/data_set.rb', line 58

def compact_onelings
  filter(orphan_strategy: :adopt, keep_leafs: true) { |p, d| false if d.oneling? && !d.root? }
end

#data_array?Boolean

Returns:

  • (Boolean)


235
236
237
# File 'lib/tukey/data_set.rb', line 235

def data_array?
  data.is_a? Array
end

#deep_dupObject



183
184
185
186
187
188
189
190
191
192
193
194
# File 'lib/tukey/data_set.rb', line 183

def deep_dup
  new_set = DataSet.new(id: id)
  new_set.label = DataSet::Label.new(dup_value(label.name), id: dup_value(label.id), meta: label.meta.marshal_dump) if label

  if data_array?
    new_set.data = children.map(&:deep_dup)
  else
    new_set.data = data
  end

  new_set
end

#each {|_self| ... } ⇒ Object

Yields:

  • (_self)

Yield Parameters:

  • _self (DataSet)

    the object that the method was called on



262
263
264
265
266
# File 'lib/tukey/data_set.rb', line 262

def each(&block)
  yield self
  children.each { |member| member.each(&block) } if data_array?
  self
end

#empty?Boolean

Returns:

  • (Boolean)


66
67
68
69
70
71
72
# File 'lib/tukey/data_set.rb', line 66

def empty?
  if data_array?
    data.all?(&:empty?)
  else
    data.respond_to?(:empty?) ? !!data.empty? : !data
  end
end

#eql?(other) ⇒ Boolean

eql? and hash are both used for comparisons when you call ‘.uniq` on an array of data sets.

Returns:

  • (Boolean)


175
176
177
# File 'lib/tukey/data_set.rb', line 175

def eql?(other)
  self == other
end

#filter(leaf_label_id = nil, keep_leafs: false, orphan_strategy: :destroy, &block) ⇒ Object



97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/tukey/data_set.rb', line 97

def filter(leaf_label_id = nil, keep_leafs: false, orphan_strategy: :destroy, &block)
  fail ArgumentError, 'No block and no leaf_label_id passed' if !block_given? && leaf_label_id.nil?
  self.data.each_with_object(DataSet.new(id: id, label: label.deep_dup)) do |set, parent_set|
    if block_given?
      condition_met = yield(parent_set, set)
    else
      condition_met = set.leaf? ? (set.label.id == leaf_label_id) : nil
    end

    if condition_met == true
      parent_set.add_item(set.deep_dup)
    elsif condition_met.nil? && set.data_array?
      deep_filter_result = set.deep_dup.filter(leaf_label_id, keep_leafs: keep_leafs, orphan_strategy: orphan_strategy, &block)
      parent_set.add_item(deep_filter_result) if deep_filter_result.data
    elsif condition_met == false && set.data_array?
      if orphan_strategy == :adopt
        deep_filter_result = set.deep_dup.filter(leaf_label_id, keep_leafs: keep_leafs, orphan_strategy: orphan_strategy, &block)
        deep_filter_result.children.each { |c| parent_set.add_item(c) } if deep_filter_result.data
      end
    elsif condition_met.nil? && set.leaf?
      parent_set.add_item(set) if keep_leafs
    end

    parent_set
  end
end

#find(subtree_id = nil, &block) ⇒ Object



124
125
126
127
128
129
130
131
132
133
# File 'lib/tukey/data_set.rb', line 124

def find(subtree_id = nil, &block)
  return super if block_given?
  return self if id == subtree_id
  return nil unless data_array?
  data.each do |child|
    match = child.find(subtree_id)
    return match if match
  end
  nil
end

#find_by(query) ⇒ Object



135
136
137
# File 'lib/tukey/data_set.rb', line 135

def find_by(query)
  return find { |s| s.to_comparable_h.deep_merge(query) == s.to_comparable_h }
end

#hashObject



179
180
181
# File 'lib/tukey/data_set.rb', line 179

def hash
  "#{data.hash}#{label.hash}".to_i
end

#leaf?Boolean

Returns:

  • (Boolean)


86
87
88
# File 'lib/tukey/data_set.rb', line 86

def leaf?
  children.none?
end

#leaf_labelsObject



90
91
92
93
94
95
# File 'lib/tukey/data_set.rb', line 90

def leaf_labels
  return [] if leaf?
  return [] if children.none?
  return children.map(&:label) if twig?
  children.map(&:leaf_labels).flatten.uniq
end

#oneling?Boolean

Returns:

  • (Boolean)


54
55
56
# File 'lib/tukey/data_set.rb', line 54

def oneling?
  siblings.none?
end

#pretty_inspect(level = 0, final_s: '') ⇒ Object



239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
# File 'lib/tukey/data_set.rb', line 239

def pretty_inspect(level = 0, final_s: '')
  prefix = ''

  if root?
    prefix << '* '
  else
    prefix << (' ' * (level) * 3) + '|- '
  end

  if label
    node_s = "#{prefix}#{label.name}"
  else
    node_s = "#{prefix} (no label)"
  end
  node_s += ": #{value}" if leaf?
  final_s += "#{node_s} \n"

  return final_s if children.none?

  children.each { |c| final_s << c.pretty_inspect(level + 1) }
  final_s
end

#reducable_values(set = nil) ⇒ Object



217
218
219
220
221
# File 'lib/tukey/data_set.rb', line 217

def reducable_values(set = nil)
  set ||= self
  return set.children.map { |c| reducable_values(c) } if set.data_array?
  set.data
end

#reduce {|reducable_values| ... } ⇒ Object

Yields:



201
202
203
# File 'lib/tukey/data_set.rb', line 201

def reduce
  yield reducable_values
end

#root?Boolean

Returns:

  • (Boolean)


62
63
64
# File 'lib/tukey/data_set.rb', line 62

def root?
  parent.nil?
end

#siblingsObject



49
50
51
52
# File 'lib/tukey/data_set.rb', line 49

def siblings
  return [] if parent.nil?
  parent.children.reject { |c| c == self }
end

#sumObject



205
206
207
208
209
# File 'lib/tukey/data_set.rb', line 205

def sum
  values = [reducable_values].flatten.compact
  return nil if values.empty?
  values.inject(&:+)
end

#to_comparable_hObject



139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
# File 'lib/tukey/data_set.rb', line 139

def to_comparable_h
  ch = {
    id: self.id,
  }

  ch[:data] = data unless data_array?

  if label
    ch[:label] = {
      id: label.id,
      name: label.name,
      meta: label.meta.to_h,
    }
  end

  ch
end

#twig?Boolean

Returns:

  • (Boolean)


82
83
84
# File 'lib/tukey/data_set.rb', line 82

def twig?
  !leaf? && children.all?(&:leaf?)
end

#valueObject



196
197
198
199
# File 'lib/tukey/data_set.rb', line 196

def value
  fail NotImplementedError, 'DataSet is not a leaf and thus has no value' unless leaf?
  data
end