hash_map_hash 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. checksums.yaml +7 -0
  2. data/lib/hash_map_hash.rb +153 -0
  3. metadata +58 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: d9049c119e58ba8638d5d32c15516f58aa58eb0c
4
+ data.tar.gz: 083f9276f0e2c4d00746f1df32d4fe4f1a7a7072
5
+ SHA512:
6
+ metadata.gz: 7d2cf8ed1e41177cc5804554743cd09cd210180c29d321211e23ab5a860a4f41c1625490c4e24fa0cde614bfd0dd3b7f2721db5e8dd1a067aead69af66d79a86
7
+ data.tar.gz: bdb697f3b6495610d3daf7fb3be981cb3fd3dc913d5c219c6f0b847c4d22b7a1c468ca80d33b4aba00978a79eb1fe90352f5686493504b409b780059c085a2a0
@@ -0,0 +1,153 @@
1
+ require 'deep_dup'
2
+
3
+ class HashMapHash
4
+ attr_reader :mapping
5
+
6
+ def initialize(mapping)
7
+ @mapping = mapping.extend(DeepDup)
8
+ end
9
+
10
+ # Data sample (source_data)
11
+ #
12
+ # { 'Contractors' =>
13
+ # { 'Contractor' =>
14
+ # [
15
+ # {
16
+ # 'Value' => 'FirstAid, Moscow',
17
+ # 'Role' => 'Payer'
18
+ # },
19
+ # {
20
+ # 'Value' => '84266',
21
+ # 'OfficialName' => 'FirstAid, Moscow (442, Glow st)',
22
+ # 'Role' => 'Receiver'
23
+ # }
24
+ # ]
25
+ # },
26
+ # 'Items' => {
27
+ # 'NumberOfPositions' => 10
28
+ # },
29
+ # 'Total' => 123.45
30
+ # }
31
+ #
32
+ # To get data, we should pass a mapping:
33
+ #
34
+ # mapping = {
35
+ # payer: ['Contractors', 'Contractor', %w(Role Payer), 'Value'],
36
+ # receiver: ['Contractors', 'Contractor', %w(Role Receiver), 'Value'],
37
+ # amount: ['Items', 'NumberOfPositions'],
38
+ # summ: 'Total'
39
+ # }
40
+ #
41
+ # output:
42
+ # {
43
+ # payer: 'FirstAid, Moscow',
44
+ # receiver: '84266',
45
+ # amount: 10,
46
+ # summ: 123.45
47
+ # }
48
+ def map(source_data)
49
+ mapping.deep_dup.each_with_object({}) do |(attribute_key, attribute_mapping), result|
50
+ result[attribute_key] = filtered_deep_fetch source_data, Array(attribute_mapping)
51
+ end
52
+ end
53
+
54
+ def add_nested_properties(nested_properties)
55
+ @mapping.merge! nested_mapping(nested_properties) if nested_properties.any?
56
+ self
57
+ end
58
+
59
+ private
60
+
61
+ # data: hash with source data, for example:
62
+ # {'Contractors' =>
63
+ # {'Contractor' =>
64
+ # [
65
+ # {
66
+ # 'Value' => 'FirstAid, Moscow',
67
+ # 'Role' => 'Payer'
68
+ # },
69
+ # {
70
+ # 'Value' => '84266',
71
+ # 'OfficialName' => 'FirstAid, Moscow (442, Glow st)',
72
+ # 'Role' => 'Receiver'
73
+ # }
74
+ # ]
75
+ # }
76
+ # }
77
+ #
78
+ # data_mapping: mapping for single attribute
79
+ # ['Contractors', 'Contractor', %w(Role Payer), 'Value']
80
+ #
81
+ # This is a recursive method, it takes one key from mapping and uses it
82
+ # to walk through data.
83
+ # Next iteration will receive data and mapping starting from next key.
84
+ #
85
+ # Arrays here are filters.
86
+ # If there is an array in mapping, say, ['Role', 'Payer'], then data on this
87
+ # level also must be some array.
88
+ # It will be filtered using #filter_array_of_hashes
89
+ #
90
+ def filtered_deep_fetch(data, data_mapping)
91
+ current_filter = data_mapping.shift
92
+ return data.fetch(current_filter) if data_mapping.size == 0
93
+ if current_filter.is_a?(Array)
94
+ filtered_deep_fetch filter_array_of_hashes(data, current_filter), data_mapping
95
+ else
96
+ filtered_deep_fetch data.fetch(current_filter), data_mapping
97
+ end
98
+ end
99
+
100
+ # array is an array of hashes, for example:
101
+ # [
102
+ # {
103
+ # 'Value' => 'FirstAid, Moscow',
104
+ # 'Role' => 'Payer'
105
+ # },
106
+ # {
107
+ # 'Value' => '84266',
108
+ # 'OfficialName' => 'FirstAid, Moscow (442, Glow st)',
109
+ # 'Role' => 'Receiver'
110
+ # }
111
+ # ]
112
+ #
113
+ # keyvalue_filter: key and value for filter, for example ['Role', 'Payer']
114
+ #
115
+ # The output is one particular array element:
116
+ #
117
+ # {
118
+ # 'Value' => 'FirstAid, Moscow',
119
+ # 'Role' => 'Payer'
120
+ # },
121
+ def filter_array_of_hashes(data_array, keyvalue_filter)
122
+ filter_key, filter_value = keyvalue_filter
123
+ data_array.detect do |element|
124
+ element[filter_key] == filter_value
125
+ end
126
+ end
127
+
128
+ # This metod translates nested_properties to mapping format.
129
+ # It helps avoValue repeating multiple keys on one level
130
+ #
131
+ # Sample:
132
+ # nested_properties = {
133
+ # prefix: %w(Contractors Contractor),
134
+ # filter_key: 'Role',
135
+ # value_key: 'Value',
136
+ # keys: {
137
+ # payer: 'Payer',
138
+ # receiver: 'Receiver'
139
+ # }
140
+ # }
141
+ #
142
+ # Output:
143
+ # {
144
+ # payer: ['Contractors', 'Contractor', %w(Role Payer), 'Value'],
145
+ # receiver: ['Contractors', 'Contractor', %w(Role Receiver), 'Value']
146
+ # }
147
+ def nested_mapping(nested_properties)
148
+ nested_properties[:keys].each_with_object({}) do |(key, raw_key), result|
149
+ result[key] = nested_properties[:prefix] +
150
+ [[nested_properties[:filter_key], raw_key], nested_properties[:value_key]]
151
+ end
152
+ end
153
+ end
metadata ADDED
@@ -0,0 +1,58 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: hash_map_hash
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Denis Peplin
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-11-28 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rspec
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ description: Flatten deeply nested hash and convert keys
28
+ email: denis.peplin@gmail.com
29
+ executables: []
30
+ extensions: []
31
+ extra_rdoc_files: []
32
+ files:
33
+ - lib/hash_map_hash.rb
34
+ homepage: http://github.com/denispeplin/hash_map_hash
35
+ licenses:
36
+ - MIT
37
+ metadata: {}
38
+ post_install_message:
39
+ rdoc_options: []
40
+ require_paths:
41
+ - lib
42
+ required_ruby_version: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '2.0'
47
+ required_rubygems_version: !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ version: '0'
52
+ requirements: []
53
+ rubyforge_project:
54
+ rubygems_version: 2.4.8
55
+ signing_key:
56
+ specification_version: 4
57
+ summary: Convert hash to hash using hash map
58
+ test_files: []