class Hash
utilities for ruby hashes
Copyright © 2021 Stephan Wenzel <stephan.wenzel@drwpatent.de>
This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
utilities for ruby hashes
Copyright © 2021 Stephan Wenzel <stephan.wenzel@drwpatent.de>
This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
utilities for ruby hashes and ruby arrays
Copyright © 2021 Stephan Wenzel <stephan.wenzel@drwpatent.de>
This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
utilities for ruby hashes and ruby arrays
Copyright © 2021 Stephan Wenzel <stephan.wenzel@drwpatent.de>
This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
utilities for ruby hashes
Copyright © 2021 Stephan Wenzel <stephan.wenzel@drwpatent.de>
This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
Public Instance Methods
apply(&block): applies block to deepest element, which is not a Hash
-> hash
new hash ->
# File lib/hash_base/hash/apply.rb, line 32 def apply( &block ) return to_enum(:each) unless block_given? hash = Hash.new each do |key, value| if value.is_a?(Hash) hash[key] = value.apply( &block ) else hash[key] = yield value end end hash end
apply!(&block): applies block to deepest element, which is not a Hash
-> hash
same hash ->
# File lib/hash_base/hash/apply.rb, line 53 def apply!( &block ) return to_enum(:each) unless block_given? each do |key, value| if value.is_a?(Hash) self[key] = value.apply( &block ) else self[key] = yield value end end self end
deep_diff
: compares two hashes - counter part to Array.deep_diff
source: stackoverflow
# File lib/hash_base/hash/deep_values.rb, line 69 def deep_diff(other, &block) (self.keys + other.keys).uniq.inject({}) do |memo, key| left = self[key] right = other[key] if block_given? next memo if yield left, right else next memo if left == right end if left.respond_to?(:deep_diff) && right.respond_to?(:deep_diff) memo[key] = left.deep_diff(right) else memo[key] = [left, right] end memo end end
deep_values
: gets an array of values of a nested hash as a flat array
-> hash
array ->
# File lib/hash_base/hash/deep_values.rb, line 32 def deep_values arr = Array.new each do |key, value| if value.is_a?(Hash) arr += value.deep_values else arr << value end end #each arr end
expand: reverse of group_by_positions
-> nested_hash
-> array
# File lib/hash_base/hash/grouping.rb, line 52 def expand(path_to_here=[]) arry = [] each do |k, v| if v.is_a?(Hash) arry += v.expand(path_to_here + [k]) elsif v.is_a?(Array) v.each do |el| arry << (path_to_here + [k] + el ) if el.is_a?(Array) arry << (path_to_here + [k] + [el] ) unless el.is_a?(Array) end else arry << (path_to_here + [k] + [v]) end end arry end
group_by_positions
: counter part to Array.group_by_positions
will only be invoked by Array.group_by_positions
# File lib/hash_base/hash/grouping.rb, line 31 def group_by_positions( *positions ) ohash = ActiveSupport::OrderedHash.new each do |key, val| case val when Hash, Array ohash[key] = val.group_by_positions( *positions ) else ohash[key] = val end end #each ohash end
max_depth
: gets max depth of a hash
-> hash
int ->
# File lib/hash_base/hash/deep_values.rb, line 53 def max_depth(depth: 1) max_depth = depth each do |k,v| if v.is_a?(Hash) max_depth = [max_depth, v.max_depth( depth: depth + 1 )].max end end max_depth end
to_table
: creates a rectangular table from a nested hash
-> hash
array -> parameters level: (Integer) only used internally for recursive calls (do not use) indent: (Integer) number of spaces for padding each table element precision (Integer) number of precision digits for floats dosort; (Boolean) should each level of keys be sorted ? content: (String) "style" => creates a table of cell styles, else table of data format: (String) "text" - text output, balanced with indent parameter "html" - html output total: (Proc) "-> x {x.flatten.inject(:+)}" proc to create totals of arrays of deepest values total_caption (String) caption for total line grand_total (Proc) "-> x {x.depp_values.flatten.inject(:+)}" proc to create totals of arrays of deepest values grant_total_caption (string) caption for grand total line
# File lib/hash_base/hash/to_table.rb, line 49 def to_table( level: 0, indent: 15, precision: 2, dosort: true, content: "data", format: nil, divisor: nil, total: nil, total_caption: "", grand_total: nil, grand_total_caption: "" ) arry = [] i = 0 h = dosort ? sort : self h.each do |k, v| first_line = Array.new( i > 0 ? level : 0) {""} + [k] unless content == "style" first_line = Array.new( i > 0 ? level : 0) {|l| "empty level_#{l}"} + ["key level_#{level}"] if content == "style" if v.is_a?(Hash) lines = v.to_table(level: level + 1, content: content, indent: indent, dosort: dosort, divisor: divisor, total: total, total_caption: total_caption, grand_total: grand_total, grand_total_caption: grand_total_caption) first_line += lines[0] # complement current line with last key arry << first_line arry += lines.drop(1) if lines.drop(1).present? elsif v.is_a?(Array) #must be array lines = [] v.each_with_index do |av, i| elem = (av.is_a?(Array) ? av : [av]) lines << (Array.new( i > 0 ? level + 1 : 0) {""} + elem ) unless content == "style" lines << (Array.new( i > 0 ? level + 1 : 0) {|l| "empty level_#{l}"} + Array.new(elem.length){"value level_#{level}"} ) if content == "style" end first_line += lines[0] # complement current line arry << first_line arry += lines.drop(1) if lines.drop(1).present? max_len = arry.map{|r| r.length}.max unless content == "style" arry << (Array.new( max_len + 1) {divisor.to_s * indent} ) if total && divisor arry << (["#{total_caption}"] + Array.new( max_len - 1) {""} + [total.yield(v)] ) if total arry << (Array.new( max_len + 1) {""} ) if total && divisor else arry << (Array.new( max_len + 1) {|l| "divisor level_#{l}"} ) if total && divisor arry << (["total_caption level_0"] + Array.new( max_len - 1) {|l| "empty level_#{l+1}"} + ["total level_#{level}"] ) if total arry << (Array.new( max_len + 1) {|l| "empty level_#{l}"} ) if total && divisor end end i+=1 end #each if level == 0 max_len = arry.map{|r| r.length}.max unless content == "style" arry << (Array.new( max_len + 1 ) {divisor.to_s * indent} ) if grand_total && divisor arry << (["#{grand_total_caption}"] + Array.new( max_len - 1 ) {""} + [grand_total.yield(self)] ) if grand_total else arry << (Array.new( max_len + 1) {"grand_total divisor"} ) if grand_total && divisor arry << (["grand_total_caption level_0"] + Array.new( max_len - 1) {|l| "empty grand_total level_#{l+1}"} + ["grand_total"]) if grand_total end max_len = arry.map{|r| r.length}.max arry.map!{|l| l += Array.new(max_len - l.length) {""} } unless content == "style" arry.map!{|l| l += Array.new(max_len - l.length) {"empty padding"} } if content == "style" if format == "text" arry.to_text(indent: indent, precision: precision) elsif format == "html" arry.to_html( styles: self.to_table(content: "style", total: true, grand_total: true)) else arry end else arry end end
zip_out
: puts elements into one zip file with keys as filenames
-> hash
zip ->
depends on gem 'zip'
# File lib/hash_base/hash/zip_out.rb, line 34 def zip_out(&block) return nil unless defined?(Zip) zip_stream = Zip::OutputStream.write_buffer do |zip| each do |key, obj| zip.put_next_entry(key) if block_given? zip.write(yield obj) else zip.write(obj) end end end # important - rewind the steam zip_stream.rewind # read out zip contents zip_stream.read end