Class: DataSet
- Inherits:
-
Object
- Object
- DataSet
- Includes:
- Enumerable
- Defined in:
- lib/tukey/data_set.rb,
lib/tukey/data_set/label.rb
Defined Under Namespace
Classes: Label
Instance Attribute Summary collapse
-
#data ⇒ Object
Returns the value of attribute data.
-
#id ⇒ Object
readonly
Returns the value of attribute id.
-
#label ⇒ Object
Returns the value of attribute label.
-
#parent ⇒ Object
Returns the value of attribute parent.
Instance Method Summary collapse
- #<<(item) ⇒ Object (also: #add_item)
- #<=>(other) ⇒ Object
-
#==(other) ⇒ Object
is used for comparison of two instances directly.
- #ancestors ⇒ Object
- #average ⇒ Object
- #branch? ⇒ Boolean
- #child_branches ⇒ Object
- #children ⇒ Object
- #combine(other_data_set, operator) ⇒ Object
- #data_array? ⇒ Boolean
- #deep_dup ⇒ Object
- #each {|_self| ... } ⇒ Object
- #empty? ⇒ Boolean
-
#eql?(other) ⇒ Boolean
eql? and hash are both used for comparisons when you call ‘.uniq` on an array of data sets.
-
#filter(leaf_label_id = nil, keep_leafs: false, orphan_strategy: :destroy, &block) ⇒ Object
Filter method that returns a new (dup) data_set with certain nodes filtered out Filtering is done through either passing: 1.
- #find(subtree_id = nil, &block) ⇒ Object
- #find_by(query) ⇒ Object
- #hash ⇒ Object
-
#initialize(data: nil, label: nil, parent: nil, id: nil) ⇒ DataSet
constructor
A new instance of DataSet.
- #label_path ⇒ Object
- #leaf? ⇒ Boolean
- #leaf_labels ⇒ Object
- #oneling? ⇒ Boolean
- #pretty_inspect(level = 0, final_s: '') ⇒ Object
- #reducable_values(set = nil) ⇒ Object
- #reduce {|reducable_values| ... } ⇒ Object
- #root? ⇒ Boolean
- #siblings ⇒ Object
- #sum ⇒ Object
- #to_comparable_h ⇒ Object
- #twig? ⇒ Boolean
- #value ⇒ Object
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
#data ⇒ Object
Returns the value of attribute data.
9 10 11 |
# File 'lib/tukey/data_set.rb', line 9 def data @data end |
#id ⇒ Object (readonly)
Returns the value of attribute id.
11 12 13 |
# File 'lib/tukey/data_set.rb', line 11 def id @id end |
#label ⇒ Object
Returns the value of attribute label.
7 8 9 |
# File 'lib/tukey/data_set.rb', line 7 def label @label end |
#parent ⇒ Object
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
197 198 199 200 201 202 203 204 |
# File 'lib/tukey/data_set.rb', line 197 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
207 208 209 210 211 |
# File 'lib/tukey/data_set.rb', line 207 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 |
#ancestors ⇒ Object
54 55 56 57 58 59 60 61 62 63 64 65 |
# File 'lib/tukey/data_set.rb', line 54 def ancestors return [] if parent.nil? ancs = [] par = parent require 'pry' until par.nil? puts par.label.name ancs.push par par = par.parent end ancs.reverse end |
#average ⇒ Object
251 252 253 254 255 |
# File 'lib/tukey/data_set.rb', line 251 def average values = [reducable_values].flatten.compact return nil if values.empty? (values.inject(&:+).to_f / values.size).to_f end |
#branch? ⇒ Boolean
87 88 89 |
# File 'lib/tukey/data_set.rb', line 87 def branch? children.any? end |
#child_branches ⇒ Object
91 92 93 |
# File 'lib/tukey/data_set.rb', line 91 def child_branches children.select(&:branch?) end |
#children ⇒ Object
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
263 264 265 266 267 268 269 270 271 272 273 |
# File 'lib/tukey/data_set.rb', line 263 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 |
#data_array? ⇒ Boolean
275 276 277 |
# File 'lib/tukey/data_set.rb', line 275 def data_array? data.is_a? Array end |
#deep_dup ⇒ Object
223 224 225 226 227 228 229 230 231 232 233 234 |
# File 'lib/tukey/data_set.rb', line 223 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..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
302 303 304 305 306 |
# File 'lib/tukey/data_set.rb', line 302 def each(&block) yield self children.each { |member| member.each(&block) } if data_array? self end |
#empty? ⇒ Boolean
79 80 81 82 83 84 85 |
# File 'lib/tukey/data_set.rb', line 79 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.
215 216 217 |
# File 'lib/tukey/data_set.rb', line 215 def eql?(other) self == other end |
#filter(leaf_label_id = nil, keep_leafs: false, orphan_strategy: :destroy, &block) ⇒ Object
Filter method that returns a new (dup) data_set with certain nodes filtered out Filtering is done through either passing:
1. a 'leaf_label_id'. All matching nodes will be present in the new set
in their original position in the tree.
2. by passing a block that returns either `true`, `nil` or `false` for a given node:
true: A node is kept, _including its children_
nil: The matcher is indifferent about the node and will continue recursing the tree
a. When at some point `true` is returned for a descendant node the whole branch will be
kept up to and including the node for which the block returned `true`.
b. If `true` is not returned the whole branch will not be included in the filter result,
unless the option `keep_leafs` was set to true, in which case only nodes that were cut
off with `false` will be excluded in the result.
false: When the block returns false for a given node that node is taken out of the results
this inludes its children, unless the option `orphan_strategy` was set to `:adopt` in
which case the children will be filtered using the same block and appended to first ancestor
node that was not excluded by the filter.
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 |
# File 'lib/tukey/data_set.rb', line 128 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 set_dup = set.deep_dup # We want to have this node and its children if condition_met == true parent_set.add_item(set_dup) # Complex looking clause, but useful for performance and DRY-ness elsif set.data_array? && (condition_met.nil? || (condition_met == false && orphan_strategy == :adopt)) deep_filter_result = set_dup.filter(leaf_label_id, keep_leafs: keep_leafs, orphan_strategy: orphan_strategy, &block) # Here is where either the taking along or adopting of nodes happens if deep_filter_result.data # Filtering underlying children and adding the potential filter result to parent. parent_set.add_item(deep_filter_result) if condition_met.nil? # We are losing the node, but since 'orphan_strategy' == :adopt we will adopt the orphans that match the filter deep_filter_result.children.each { |c| parent_set.add_item(c) } if condition_met == false end # We are indifferent to the match (nil), but since the node is a leaf we will keep it elsif condition_met.nil? && set.leaf? parent_set.add_item(set_dup) if keep_leafs end parent_set end end |
#find(subtree_id = nil, &block) ⇒ Object
164 165 166 167 168 169 170 171 172 173 |
# File 'lib/tukey/data_set.rb', line 164 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
175 176 177 |
# File 'lib/tukey/data_set.rb', line 175 def find_by(query) return find { |s| s.to_comparable_h.deep_merge(query) == s.to_comparable_h } end |
#hash ⇒ Object
219 220 221 |
# File 'lib/tukey/data_set.rb', line 219 def hash "#{data.hash}#{label.hash}".to_i end |
#label_path ⇒ Object
67 68 69 |
# File 'lib/tukey/data_set.rb', line 67 def label_path [ancestors, self].flatten.map(&:label) end |
#leaf? ⇒ Boolean
99 100 101 |
# File 'lib/tukey/data_set.rb', line 99 def leaf? children.none? end |
#leaf_labels ⇒ Object
103 104 105 106 107 108 |
# File 'lib/tukey/data_set.rb', line 103 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
71 72 73 |
# File 'lib/tukey/data_set.rb', line 71 def oneling? siblings.none? end |
#pretty_inspect(level = 0, final_s: '') ⇒ Object
279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 |
# File 'lib/tukey/data_set.rb', line 279 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
257 258 259 260 261 |
# File 'lib/tukey/data_set.rb', line 257 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
241 242 243 |
# File 'lib/tukey/data_set.rb', line 241 def reduce yield reducable_values end |
#root? ⇒ Boolean
75 76 77 |
# File 'lib/tukey/data_set.rb', line 75 def root? parent.nil? end |
#siblings ⇒ Object
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 |
#sum ⇒ Object
245 246 247 248 249 |
# File 'lib/tukey/data_set.rb', line 245 def sum values = [reducable_values].flatten.compact return nil if values.empty? values.inject(&:+) end |
#to_comparable_h ⇒ Object
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 |
# File 'lib/tukey/data_set.rb', line 179 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..to_h, } end ch end |
#twig? ⇒ Boolean
95 96 97 |
# File 'lib/tukey/data_set.rb', line 95 def twig? !leaf? && children.all?(&:leaf?) end |
#value ⇒ Object
236 237 238 239 |
# File 'lib/tukey/data_set.rb', line 236 def value fail NotImplementedError, 'DataSet is not a leaf and thus has no value' unless leaf? data end |