Deep::Hash::Struct
Struct copes with the operation that is Deep.
Because the data maintenance of many hierarchies became possible, I can treat it like Hash.
Installation
Add this line to your application's Gemfile:
gem 'deep-hash-struct'
And then execute:
$ bundle
Or install it yourself as:
$ gem install deep-hash-struct
Supported Ruby Versions
Wrapper Class Usage
The basic usage is the same as Hash Class.
Basic
wrapper = Deep::Hash::Struct::Wrapper.new
wrapper.a = 1
wrapper.b.a = 2
wrapper[:c][:a] = 3
wrapper[:c].b = 4
wrapper.to_h
Block
wrapper.a do
1 + 1
end
wrapper.a
wrapper.b do
{ c: 3 }
end
wrapper.b.c
#dig
wrapper.a.b = { c: 1, d: [1, 2, [3, 4, 5]] }
wrapper.dig(:a, :b, :c)
wrapper.dig(:a, :b, :d, 2, 0)
wrapper.dig(:a, :c).blank?
#merge
Deep::Hash::Struct::Wrapper Class
wrapper.a = 1
wrapper.b = 2
wrapper.c.a = 3
wrapper.c.b = 4
wrapper.c.c = 5
other = wrapper.class.new
other.a = 6
other.b = 7
other.c.a = 8
wrapper.merge(other).to_h
Hash Class
wrapper.a = 1
wrapper.b = 2
wrapper.c.a = 3
wrapper.c.b = 4
wrapper.c.c = 5
other = {}
other[:a] = 6
other[:b] = 7
other[:c] = {}
other[:c][:a] = 8
wrapper.merge(other).to_h
#merge! #update
bang merge method
#deep_merge
Deep::Hash::Struct::Wrapper Class
wrapper.a = 1
wrapper.b = 2
wrapper.c.a = 3
wrapper.c.b = 4
wrapper.c.c = 5
other = wrapper.class.new
other.a = 6
other.b = 7
other.c.a = 8
wrapper.deep_merge(other).to_h
Hash Class
wrapper.a = 1
wrapper.b = 2
wrapper.c.a = 3
wrapper.c.b = 4
wrapper.c.c = 5
other = {}
other[:a] = 6
other[:b] = 7
other[:c] = {}
other[:c][:a] = 8
wrapper.deep_merge(other).to_h
#deep_merge!
bang deep_merge method
#reverse_merge
Deep::Hash::Struct::Wrapper Class
wrapper.a = 1
wrapper.b = 2
wrapper.c.a = 3
wrapper.c.b = 4
wrapper.c.c = 5
other = wrapper.class.new
other.a = 6
other.b = 7
other.c.a = 8
other.d.a = 9
wrapper.reverse_merge(other).to_h
Hash Class
wrapper.a = 1
wrapper.b = 2
wrapper.c.a = 3
wrapper.c.b = 4
wrapper.c.c = 5
other = {}
other[:a] = 6
other[:b] = 7
other[:c] = {}
other[:c][:a] = 8
other[:d] = {}
other[:d][:a] = 9
wrapper.reverse_merge(other).to_h
#reverse_merge!
bang reverse_merge method
#reverse_deep_merge
Deep::Hash::Struct::Wrapper Class
wrapper.a = 1
wrapper.b = 2
wrapper.c.a = 3
wrapper.c.b = 4
wrapper.c.c = 5
other = wrapper.class.new
other.a = 6
other.b = 7
other.c.a = 8
other.c.d = 9
wrapper.reverse_deep_merge(other).to_h
Hash Class
wrapper.a = 1
wrapper.b = 2
wrapper.c.a = 3
wrapper.c.b = 4
wrapper.c.c = 5
other = {}
other[:a] = 6
other[:b] = 7
other[:c] = {}
other[:c][:a] = 8
other[:c][:d] = 9
wrapper.reverse_deep_merge(other).to_h
#reverse_deep_merge!
bang reverse_deep_merge method
#fetch
wrapper.a = 1
wrapper.fetch(:a, :not_found)
wrapper.fetch(:a) { |k| "#{k} not found" }
wrapper.fetch(:b)
wrapper.fetch(:b, :not_found)
wrapper.fetch(:b) { |k| "#{k} not found" }
#default
wrapper.a.default = 0
wrapper.b.default = []
wrapper.a.a
wrapper.b.a
#map_key
wrapper.a = 1
wrapper.b = 2
wrapper.c = 3
wrapper.map_key { |k| [k] }
#map_value
wrapper.a = 1
wrapper.b = 2
wrapper.c = 3
wrapper.map_value { |k| [k] }
#fetch_values
wrapper.a = 1
wrapper.b = 2
wrapper.fetch_values(:a, :b)
wrapper.fetch_values(:a, :c)
wrapper.fetch_values(:a, :c) { |k| k.upcase }
#values_at
wrapper.a = 1
wrapper.b = 2
wrapper.c = 3
wrapper.values_at(:a, :b, :d)
#invert
wrapper.a = 1
wrapper.b = 2
wrapper.c = 3
wrapper.invert
#delete
wrapper.a = 1
wrapper.b = 2
wrapper.c = 3
wrapper.delete(:a)
wrapper.keys
#delete_if
wrapper.a = 1
wrapper.b = 2
wrapper.c = 3
wrapper.delete_if{ |k, v| k == :a || v == 2 }.to_h
wrapper.keys
#reject
wrapper.a = 1
wrapper.b = 2
wrapper.c = 3
wrapper.reject { |k, v| v > 2 }.to_h
#reject!
bang reject method
#clear
wrapper.a = 1
wrapper.b = 2
wrapper.c = 3
wrapper.clear
wrapper.to_h
#flatten
wrapper.a = 1
wrapper.b = 2
wrapper.c.a = 3
wrapper.c.b = 4
wrapper.c.c = 5
wrapper.flatten
#has_key? #include?
wrapper.a = 1
wrapper.has_key?(:a)
wrapper.has_key?(:b)
#has_keys?
wrapper.a = 1
wrapper.b = 2
wrapper.c.a = 3
wrapper.has_keys?(:a)
wrapper.has_keys?(:c, :a)
wrapper.has_keys?(:d)
wrapper.has_keys?(:c, :b)
wrapper.has_keys?(:d, :a)
#exclude?
wrapper.a = 1
wrapper.exclude?(:a)
wrapper.exclude?(:d)
#sort
wrapper.c = 1
wrapper.b = 2
wrapper.a = 3
wrapper.sort
#shift
wrapper.a = 1
wrapper.b = 2
wrapper.c = 3
wrapper.shift
wrapper.to_h
#compact
wrapper.a = 1
wrapper.b = nil
wrapper.c.a = 2
wrapper.c.b = ""
wrapper.d.a = nil
wrapper.keys
wrapper.c.keys
wrapper.compact.keys
wrapper.compact.c.keys
wrapper.keys
wrapper.c.keys
#compact!
bang compact method
#deep_compact
wrapper.a = 1
wrapper.b = nil
wrapper.c.a = 2
wrapper.c.b = ""
wrapper.d.a = nil
wrapper.keys
wrapper.c.keys
wrapper.deep_compact.keys
wrapper.deep_compact.c.keys
wrapper.keys
wrapper.c.keys
#deep_compact!
bang deep_compact method
#slice
wrapper.a = 1
wrapper.b = 2
wrapper.c = 3
wrapper.slice(:a, :b).to_h
wrapper.slice(:b, :c).to_h
wrapper.slice(:c, :d).to_h
wrapper.to_h
#slice!
bang slice method
#to_hash #to_h
wrapper.a = 1
wrapper.b = 2
wrapper.c.a = 3
wrapper.to_hash
#to_json
wrapper.a = 1
wrapper.b = 2
wrapper.c.a = 3
wrapper.to_json
#max_stages
wrapper.a = 1
wrapper.b.a = 2
wrapper.b.b = 3
wrapper.c.a.b = 4
wrapper.c.a.c = 5
wrapper.c.a.d = 6
wrapper.max_stages
wrapper.b.max_stages
wrapper.c.max_stages
#min_stages
wrapper.a = 1
wrapper.b.a = 2
wrapper.b.b = 3
wrapper.c.a.b = 4
wrapper.c.a.c = 5
wrapper.c.a.d = 6
wrapper.min_stages
wrapper.b.min_stages
wrapper.c.min_stages
Dashboard Class Usage
It is used like a two-dimensional array representing a table.
Add matrix table
dashboard = Deep::Hash::Struct::Dashboard.new
dashboard.add_table(matrix: true, side_header: "sh") do |t|
t.add_header do |h|
h.a = "h1"
h[:b] = "h2"
h.add :c, "h3"
end
t.add_side do |s|
s.a = "s1"
s[:b] = "s2"
s.add :c, "s3"
end
t.add_body do |row|
row.a.a = 11
row.a[:b] = 12
row[:a][:c] = 13
row[:b].a = 14
row.b.add :b, 15
row.b.c = 16
row.c.a = 17
row.c.b = 18
row.c.c = 19
end
end
dashboard.tables
table = "<table>\n"
dashboard.tables[0].each do |rows|
table << " <tr>\n"
rows.each do |row|
if row.side_or_header?
table << " <th>#{row.name}</th>\n"
else
table << " <td>#{row.value}</td>\n"
end
end
table << " </tr>\n"
end
table << "</table>\n"
puts table
Add segment table
dashboard = Deep::Hash::Struct::Dashboard.new
dashboard.add_table do |t|
t.add_header do |h|
h.a = "h1"
h[:b] = "h2"
h.add :c, "h3"
end
t.add_body do |row|
row.a = 11
row.b = 12
row.c = 13
end
t.add_body do |row|
row.c = 16
row.b = 15
row.a = 14
end
t.add_body do |row|
row.c = 19
row.a = 17
row.b = 18
end
end
dashboard.tables
table = "<table>\n"
dashboard.tables[0].each do |rows|
table << " <tr>\n"
rows.each do |row|
if row.header?
table << " <th>#{row.name}</th>\n"
else
table << " <td>#{row.value}</td>\n"
end
end
table << " </tr>\n"
end
table << "</table>\n"
puts table
Unset value to matrix table
dashboard = Deep::Hash::Struct::Dashboard.new
dashboard.add_table(matrix: true) do |t|
t.add_header do |h|
h.a = "h1"
h[:b] = "h2"
h.add :c, "h3"
end
t.add_side do |s|
s.a = "s1"
s[:b] = "s2"
s.add :c, "s3"
end
t.add_body do |row|
row.a.b = 2
row.a.c = 3
row.b.a = 4
row.b.c = 6
row.c.a = 7
row.c.b = 8
end
end
dashboard.tables
table = "<table>\n"
dashboard.tables[0].each do |rows|
table << " <tr>\n"
rows.each do |row|
if row.side_or_header?
table << " <th>#{row.name}</th>\n"
else
table << " <td>#{row.value}</td>\n"
end
end
table << " </tr>\n"
end
table << "</table>\n"
puts table
Unset value to segment table
dashboard = Deep::Hash::Struct::Dashboard.new
dashboard.add_table do |t|
t.add_header do |h|
h.a = "h1"
h.b = "h2"
h.c = "h3"
end
t.add_body do |row|
row.b = 2
row.c = 3
end
t.add_body do |row|
row.a = 4
row.c = 6
end
t.add_body do |row|
row.a = 7
row.b = 8
end
end
dashboard.tables
table = "<table>\n"
dashboard.tables[0].each do |rows|
table << " <tr>\n"
rows.each do |row|
if row.header?
table << " <th>#{row.name}</th>\n"
else
table << " <td>#{row.value}</td>\n"
end
end
table << " </tr>\n"
end
table << "</table>\n"
puts table
Default to matrix table
dashboard = Deep::Hash::Struct::Dashboard.new
dashboard.add_table(matrix: true, default: 0) do |t|
t.add_header do |h|
h.a = "h1"
h.b = "h2"
h.c = "h3"
end
t.add_side do |s|
s.a = "s1"
s.b = "s2"
s.c = "s3"
end
t.add_body do |row|
row.a.b = 2
row.a.c = 3
row.b.a = 4
row.b.c = 6
row.c.a = 7
row.c.b = 8
end
end
dashboard.tables
table = "<table>\n"
dashboard.tables[0].each do |rows|
table << " <tr>\n"
rows.each do |row|
if row.side_or_header?
table << " <th>#{row.name}</th>\n"
else
table << " <td>#{row.value}</td>\n"
end
end
table << " </tr>\n"
end
table << "</table>\n"
puts table
Default to segment table
dashboard = Deep::Hash::Struct::Dashboard.new
dashboard.add_table(default: 0) do |t|
t.add_header do |h|
h.a = "h1"
h.b = "h2"
h.c = "h3"
end
t.add_body do |row|
row.b = 2
row.c = 3
end
t.add_body do |row|
row.a = 4
row.c = 6
end
t.add_body do |row|
row.a = 7
row.b = 8
end
end
dashboard.tables
table = "<table>\n"
dashboard.tables[0].each do |rows|
table << " <tr>\n"
rows.each do |row|
if row.header?
table << " <th>#{row.name}</th>\n"
else
table << " <td>#{row.value}</td>\n"
end
end
table << " </tr>\n"
end
table << "</table>\n"
puts table
Create like html matrix table
dashboard = Deep::Hash::Struct::Dashboard.new
dashboard.add_table(matrix: true) do |t|
t.tr do |tr|
tr.th "header1"
tr.th "header2"
tr.th "header3"
end
t.tr side: true do |tr|
tr.th "side1"
tr.td 1
tr.td 2
tr.td 3
end
t.tr side: true do |tr|
tr.th "side2"
tr.td 4
tr.td 5
tr.td 6
end
t.tr side: true do |tr|
tr.th "side3"
tr.td 7
tr.td 8
tr.td 9
end
end
result = "<table>\n"
dashboard.each do |t|
t.each do |tr|
result << " <tr>\n"
tr.each do |cell|
if cell.side_or_header?
result << " <th>#{cell.name}</th>"
else
result << " <td>#{cell.value}</td>"
end
result << "\n"
end
result << " </tr>\n"
end
end
result << "</table>\n"
puts table
# => <table>
# => <tr>
# => <th></th>
# => <th>header1</th>
# => <th>header2</th>
# => <th>header3</th>
# => </tr>
# => <tr>
# => <th>side1</th>
# => <td>1</td>
# => <td>2</td>
# => <td>3</td>
# => </tr>
# => <tr>
# => <th>side2</th>
# => <td>4</td>
# => <td>5</td>
# => <td>6</td>
# => </tr>
# => <tr>
# => <th>side3</th>
# => <td>7</td>
# => <td>8</td>
# => <td>9</td>
# => </tr>
# => </table>
Create like html segment table
dashboard = Deep::Hash::Struct::Dashboard.new
dashboard.add_table do |t|
t.tr do |tr|
tr.th "header1"
tr.th "header2"
tr.th "header3"
end
t.tr do |tr|
tr.td 1
tr.td 2
tr.td 3
end
t.tr do |tr|
tr.td 4
tr.td 5
tr.td 6
end
t.tr do |tr|
tr.td 7
tr.td 8
tr.td 9
end
end
result = "<table>\n"
dashboard.each do |t|
t.each do |tr|
result << " <tr>\n"
tr.each do |cell|
if cell.side_or_header?
result << " <th>#{cell.name}</th>"
else
result << " <td>#{cell.value}</td>"
end
result << "\n"
end
result << " </tr>\n"
end
end
result << "</table>\n"
puts table
# => <table>
# => <tr>
# => <th>header1</th>
# => <th>header2</th>
# => <th>header3</th>
# => </tr>
# => <tr>
# => <td>1</td>
# => <td>2</td>
# => <td>3</td>
# => </tr>
# => <tr>
# => <td>4</td>
# => <td>5</td>
# => <td>6</td>
# => </tr>
# => <tr>
# => <td>7</td>
# => <td>8</td>
# => <td>9</td>
# => </tr>
# => </table>
Contributing
Bug reports and pull requests are welcome on GitHub at https://github.com/etiopiamokamame/deep-hash-struct. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the Contributor Covenant code of conduct.
License
The gem is available as open source under the terms of the MIT License.