hash-joiner 0.0.0 → 0.0.1
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.
- checksums.yaml +4 -4
- data/README.md +153 -0
- data/lib/hash-joiner.rb +68 -68
- metadata +48 -5
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 49618706629e42c71fde8cb81f186d1c16a65468
|
|
4
|
+
data.tar.gz: cee8620a4dc55411b95385d9f01dae8fd1ab40c8
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a57bca28a0d760274250824714f0e8033ec1ad3a59e925fb878910c435ea20c61aae0ac23d20054f591d9a1d133c381c42812001082432e9a0eb650c5e394686
|
|
7
|
+
data.tar.gz: 0aeba3a5e17a911d7449b10da5efd80f510f56be597b0631d54dc39b196ff0e17cd441e8318055b4cc7fc49551d35af4c31aaf776a601c8afe7358dd38a51cb7
|
data/README.md
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
## hash-joiner Gem
|
|
2
|
+
|
|
3
|
+
[](http://badge.fury.io/rb/hash-joiner)
|
|
4
|
+
[](https://travis-ci.org/18F/hash-joiner)
|
|
5
|
+
[](https://codeclimate.com/github/18F/hash-joiner)
|
|
6
|
+
[](https://codeclimate.com/github/18F/hash-joiner)
|
|
7
|
+
|
|
8
|
+
Performs pruning or one-level promotion of `Hash` attributes (typically labeled `private:`), and deep merges and joins of `Hash` objects. Works on `Array` objects containing `Hash` objects as well.
|
|
9
|
+
|
|
10
|
+
Downloads and API docs are available on the [hash-joiner RubyGems page](https://rubygems.org/gems/hash-joiner). API documentation is written using [YARD markup](http://yardoc.org/).
|
|
11
|
+
|
|
12
|
+
Contributed by the 18F team, part of the United States General Services Administration: https://18f.gsa.gov/
|
|
13
|
+
|
|
14
|
+
### Motivation
|
|
15
|
+
|
|
16
|
+
This gem was extracted from [the 18F Hub Joiner plugin](https://github.com/18F/hub/blob/master/_plugins/joiner.rb). That plugin manipulates [Jekyll-imported data](http://jekyllrb.com/docs/datafiles/) by removing or promoting private data, building indices, and performing joins between different data files so that the results appear as unified collections in Jekyll's `site.data` object. It serves as the first stage in a pipeline that also builds cross-references and canonicalizes data before generating static HTML pages and other artifacts.
|
|
17
|
+
|
|
18
|
+
### Installation
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
$ gem install hash-joiner
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### Usage
|
|
25
|
+
|
|
26
|
+
The typical use case is to have a YAML file containing both public and private data, with all private data nested within `private:` properties:
|
|
27
|
+
|
|
28
|
+
```ruby
|
|
29
|
+
> require 'hash-joiner'
|
|
30
|
+
> my_data_collection = {
|
|
31
|
+
'name' => 'mbland', 'full_name' => 'Mike Bland',
|
|
32
|
+
'private' => {
|
|
33
|
+
'email' => 'michael.bland@gsa.gov', 'location' => 'DCA',
|
|
34
|
+
},
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
The following examples, except for **Join an Array of Hash values**, all begin with `my_data_collection` in the above state. Further examples can be found in the [test/](test/) directory.
|
|
39
|
+
|
|
40
|
+
#### Strip private data
|
|
41
|
+
|
|
42
|
+
```ruby
|
|
43
|
+
# Everything within the `private:` property will be deleted.
|
|
44
|
+
> HashJoiner.remove_data my_data_collection, "private"
|
|
45
|
+
=> {"name"=>"mbland", "full_name"=>"Mike Bland"}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
#### Promote private data
|
|
49
|
+
|
|
50
|
+
This will render `private:` data at the same level as other, nonprivate data:
|
|
51
|
+
|
|
52
|
+
```ruby
|
|
53
|
+
# Everything within the `private:` property will be
|
|
54
|
+
# promoted up one level.
|
|
55
|
+
> HashJoiner.promote_data my_data_collection, "private"
|
|
56
|
+
=> {"name"=>"mbland", "full_name"=>"Mike Bland",
|
|
57
|
+
"email"=>"michael.bland@gsa.gov", "location"=>"DCA"}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
#### Perform a deep merge with other Hash values
|
|
61
|
+
|
|
62
|
+
```ruby
|
|
63
|
+
> extra_info = {
|
|
64
|
+
'languages' => ['C++', 'Python'], 'full_name' => 'Michael S. Bland',
|
|
65
|
+
'private' => {
|
|
66
|
+
'location' => 'Alexandria, VA', 'previous_companies' => ['Google'],
|
|
67
|
+
},
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
# The original Hash will have information added for
|
|
71
|
+
# `full_name`, `languages', and `private => location`.
|
|
72
|
+
> HashJoiner.deep_merge my_data_collection, extra_info
|
|
73
|
+
=> {"name"=>"mbland", "full_name"=>"Michael S. Bland",
|
|
74
|
+
"private"=>{
|
|
75
|
+
"email"=>"michael.bland@gsa.gov", "location"=>"Alexandria, VA",
|
|
76
|
+
"previous_companies"=>["Google"]},
|
|
77
|
+
"languages"=>["C++", "Python"]}
|
|
78
|
+
|
|
79
|
+
> extra_info = {
|
|
80
|
+
'languages' => ['Ruby'],
|
|
81
|
+
'private' => {
|
|
82
|
+
'previous_companies' => ['Northrop Grumman'],
|
|
83
|
+
},
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
# The Hash will now have added information for
|
|
87
|
+
# `languages` and `private => previous_companies`.
|
|
88
|
+
> HashJoiner.deep_merge my_data_collection, extra_info
|
|
89
|
+
=> {"name"=>"mbland", "full_name"=>"Michael S. Bland",
|
|
90
|
+
"private"=>{
|
|
91
|
+
"email"=>"michael.bland@gsa.gov", "location"=>"Alexandria, VA",
|
|
92
|
+
"previous_companies"=>["Google", "Northrop Grumman"]},
|
|
93
|
+
"languages"=>["C++", "Python", "Ruby"]}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
#### Join an Array of Hash values
|
|
97
|
+
|
|
98
|
+
This corresponds to the process of joining different collections of Jekyll-imported data within the 18F Hub, such as joining `site.data['private']['team']` into `site.data['team']`.
|
|
99
|
+
|
|
100
|
+
```ruby
|
|
101
|
+
# This defines a fake object emulating a Jekyll::Site.
|
|
102
|
+
> class DummySite
|
|
103
|
+
attr_accessor :data
|
|
104
|
+
def initialize
|
|
105
|
+
@data = {'private' => {}}
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
> site = DummySite.new
|
|
110
|
+
|
|
111
|
+
# This data would correspond to _data/team.yml
|
|
112
|
+
# in a Jekyll project.
|
|
113
|
+
> site.data['team'] = [
|
|
114
|
+
{'name' => 'mbland', 'languages' => ['C++']},
|
|
115
|
+
{'name' => 'foobar', 'full_name' => 'Foo Bar'},
|
|
116
|
+
]
|
|
117
|
+
|
|
118
|
+
# This data would correspond to _data/private/team.yml
|
|
119
|
+
# in a Jekyll project.
|
|
120
|
+
> site.data['private']['team'] = [
|
|
121
|
+
{'name' => 'mbland', 'languages' => ['Python', 'Ruby']},
|
|
122
|
+
{'name' => 'foobar', 'email' => 'foo.bar@gsa.gov'},
|
|
123
|
+
{'name' => 'bazquux', 'email' => 'baz.quux@gsa.gov'},
|
|
124
|
+
]
|
|
125
|
+
|
|
126
|
+
# After joining, each element of `site.data['team']` contains
|
|
127
|
+
# the union of the original element and the corresponding
|
|
128
|
+
# element in `site.data['private']['team']`.
|
|
129
|
+
#
|
|
130
|
+
# `site.data['private']` can now be safely discarded.
|
|
131
|
+
> HashJoiner.join_data 'team', 'name', site.data, site.data['private']
|
|
132
|
+
=> {"private"=>{
|
|
133
|
+
"team"=>[
|
|
134
|
+
{"name"=>"mbland", "languages"=>["Python", "Ruby"]},
|
|
135
|
+
{"name"=>"foobar", "email"=>"foo.bar@gsa.gov"},
|
|
136
|
+
{"name"=>"bazquux", "email"=>"baz.quux@gsa.gov"}]},
|
|
137
|
+
"team"=>[
|
|
138
|
+
{"name"=>"mbland", "languages"=>["C++", "Python", "Ruby"]},
|
|
139
|
+
{"name"=>"foobar", "full_name"=>"Foo Bar", "email"=>"foo.bar@gsa.gov"},
|
|
140
|
+
{"name"=>"bazquux", "email"=>"baz.quux@gsa.gov"}]}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### Contributing
|
|
144
|
+
|
|
145
|
+
Just fork [18F/hash-joiner](https://github.com/18F/hash-joiner) and start sending pull requests! Feel free to ping [@mbland](https://github.com/mbland) with any questions you may have, especially if the current documentation should've addressed your needs, but didn't.
|
|
146
|
+
|
|
147
|
+
### Public domain
|
|
148
|
+
|
|
149
|
+
This project is in the worldwide [public domain](LICENSE.md). As stated in [CONTRIBUTING](CONTRIBUTING.md):
|
|
150
|
+
|
|
151
|
+
> This project is in the public domain within the United States, and copyright and related rights in the work worldwide are waived through the [CC0 1.0 Universal public domain dedication](https://creativecommons.org/publicdomain/zero/1.0/).
|
|
152
|
+
>
|
|
153
|
+
> All contributions to this project will be released under the CC0 dedication. By submitting a pull request, you are agreeing to comply with this waiver of copyright interest.
|
data/lib/hash-joiner.rb
CHANGED
|
@@ -1,32 +1,13 @@
|
|
|
1
|
-
#
|
|
2
|
-
# labeled "private") and deep joins of Hash objects. Works on Array objects
|
|
3
|
-
# containing Hash objects as well.
|
|
4
|
-
#
|
|
5
|
-
# The typical use case is to have a YAML file containing both public and
|
|
6
|
-
# private data, with all private data nested within "private" properties:
|
|
7
|
-
#
|
|
8
|
-
# my_data_collection = {
|
|
9
|
-
# 'name' => 'mbland', 'full_name' => 'Mike Bland',
|
|
10
|
-
# 'private' => {
|
|
11
|
-
# 'email' => 'michael.bland@gsa.gov', 'location' => 'DCA',
|
|
12
|
-
# },
|
|
13
|
-
# }
|
|
14
|
-
#
|
|
15
|
-
# Contributed by the 18F team, part of the United States
|
|
16
|
-
# General Services Administration: https://18f.gsa.gov/
|
|
17
|
-
#
|
|
18
|
-
# Author: Mike Bland (michael.bland@gsa.gov)
|
|
1
|
+
# @author: Mike Bland (michael.bland@gsa.gov)
|
|
19
2
|
module HashJoiner
|
|
20
3
|
# Recursively strips information from +collection+ matching +key+.
|
|
21
4
|
#
|
|
22
|
-
#
|
|
23
|
-
#
|
|
24
|
-
#
|
|
25
|
-
#
|
|
26
|
-
#
|
|
27
|
-
#
|
|
28
|
-
# +collection+:: Hash or Array from which to strip information
|
|
29
|
-
# +key+:: key determining data to be stripped from +collection+
|
|
5
|
+
# @param collection [Hash,Array<Hash>] collection from which to strip
|
|
6
|
+
# information
|
|
7
|
+
# @param key [String] property to be stripped from +collection+
|
|
8
|
+
# @return [Hash,Array<Hash>] +collection+ if +collection+ is a +Hash+ or
|
|
9
|
+
# +Array<Hash>+
|
|
10
|
+
# @return [nil] if +collection+ is not a +Hash+ or +Array<Hash>+
|
|
30
11
|
def self.remove_data(collection, key)
|
|
31
12
|
if collection.instance_of? ::Hash
|
|
32
13
|
collection.delete key
|
|
@@ -41,15 +22,12 @@ module HashJoiner
|
|
|
41
22
|
# same level as +key+ itself. After promotion, each +key+ reference will
|
|
42
23
|
# be deleted.
|
|
43
24
|
#
|
|
44
|
-
#
|
|
45
|
-
#
|
|
46
|
-
#
|
|
47
|
-
#
|
|
48
|
-
#
|
|
49
|
-
#
|
|
50
|
-
#
|
|
51
|
-
# +collection+:: Hash or Array from which to promote information
|
|
52
|
-
# +key+:: key determining data to be promoted within +collection+
|
|
25
|
+
# @param collection [Hash,Array<Hash>] collection in which to promote
|
|
26
|
+
# information
|
|
27
|
+
# @param key [String] property to be promoted within +collection+
|
|
28
|
+
# @return [Hash,Array<Hash>] +collection+ if +collection+ is a +Hash+ or
|
|
29
|
+
# +Array<Hash>+
|
|
30
|
+
# @return [nil] if +collection+ is not a +Hash+ or +Array<Hash>+
|
|
53
31
|
def self.promote_data(collection, key)
|
|
54
32
|
if collection.instance_of? ::Hash
|
|
55
33
|
if collection.member? key
|
|
@@ -76,20 +54,21 @@ module HashJoiner
|
|
|
76
54
|
end
|
|
77
55
|
end
|
|
78
56
|
|
|
79
|
-
# Raised by deep_merge
|
|
57
|
+
# Raised by +deep_merge+ if +lhs+ and +rhs+ are of different types.
|
|
58
|
+
# @see deep_merge
|
|
80
59
|
class MergeError < ::Exception
|
|
81
60
|
end
|
|
82
61
|
|
|
83
|
-
# Performs a deep merge of Hash and Array structures. If the collections
|
|
84
|
-
# are
|
|
85
|
-
# any existing members in +lhs+. If the collections are
|
|
86
|
-
# from +rhs+ will be appended to lhs
|
|
87
|
-
#
|
|
88
|
-
# Raises MergeError if lhs and rhs are of different classes, or if they
|
|
89
|
-
# are of classes other than Hash or Array.
|
|
62
|
+
# Performs a deep merge of +Hash+ and +Array+ structures. If the collections
|
|
63
|
+
# are +Hash+es, +Hash+ or +Array+ members of +rhs+ will be deep-merged with
|
|
64
|
+
# any existing members in +lhs+. If the collections are +Array+s, the values
|
|
65
|
+
# from +rhs+ will be appended to +lhs+.
|
|
90
66
|
#
|
|
91
|
-
#
|
|
92
|
-
#
|
|
67
|
+
# @param lhs [Hash,Array] merged data sink (left-hand side)
|
|
68
|
+
# @param rhs [Hash,Array] merged data source (right-hand side)
|
|
69
|
+
# @return [Hash,Array] +lhs+
|
|
70
|
+
# @raise [MergeError] if +lhs+ and +rhs+ are of different classes, or if
|
|
71
|
+
# they are of classes other than Hash or Array.
|
|
93
72
|
def self.deep_merge(lhs, rhs)
|
|
94
73
|
mergeable_classes = [::Hash, ::Array]
|
|
95
74
|
|
|
@@ -112,25 +91,33 @@ module HashJoiner
|
|
|
112
91
|
elsif rhs.instance_of? ::Array
|
|
113
92
|
lhs.concat rhs
|
|
114
93
|
end
|
|
94
|
+
lhs
|
|
115
95
|
end
|
|
116
96
|
|
|
117
|
-
# Raised by join_data
|
|
97
|
+
# Raised by +join_data+ if an error is encountered.
|
|
98
|
+
# @see join_data
|
|
118
99
|
class JoinError < ::Exception
|
|
119
100
|
end
|
|
120
101
|
|
|
121
|
-
# Joins objects in +lhs[category]
|
|
122
|
-
#
|
|
123
|
-
# the primary key
|
|
102
|
+
# Joins objects in +lhs+[category] with data from +rhs+[category]. If the
|
|
103
|
+
# +category+ objects are of type +Array<Hash>+, +key_field+ will be used as
|
|
104
|
+
# the primary key to join the objects in the two collections; otherwise
|
|
105
|
+
# +key_field+ is ignored.
|
|
124
106
|
#
|
|
125
|
-
#
|
|
126
|
-
#
|
|
127
|
-
#
|
|
128
|
-
#
|
|
129
|
-
#
|
|
130
|
-
#
|
|
107
|
+
# @param category [String] determines member of +lhs+ to join with +rhs+
|
|
108
|
+
# @param key_field [String] primary key for objects in each +Array<Hash>+
|
|
109
|
+
# collection specified by +category+
|
|
110
|
+
# @param lhs [Hash,Array<Hash>] joined data sink of type Hash (left-hand
|
|
111
|
+
# side)
|
|
112
|
+
# @param rhs [Hash,Array<Hash>] joined data source of type Hash (right-hand
|
|
113
|
+
# side)
|
|
114
|
+
# @return [Hash,Array<Hash>] +lhs+
|
|
115
|
+
# @raise [JoinError] if an error is encountered
|
|
116
|
+
# @see deep_merge
|
|
117
|
+
# @see join_array_data
|
|
131
118
|
def self.join_data(category, key_field, lhs, rhs)
|
|
132
119
|
rhs_data = rhs[category]
|
|
133
|
-
return unless rhs_data
|
|
120
|
+
return lhs unless rhs_data
|
|
134
121
|
|
|
135
122
|
lhs_data = lhs[category]
|
|
136
123
|
if !(lhs_data and [::Hash, ::Array].include? lhs_data.class)
|
|
@@ -140,10 +127,17 @@ module HashJoiner
|
|
|
140
127
|
else
|
|
141
128
|
self.join_array_data key_field, lhs_data, rhs_data
|
|
142
129
|
end
|
|
130
|
+
lhs
|
|
143
131
|
end
|
|
144
132
|
|
|
145
|
-
#
|
|
146
|
-
#
|
|
133
|
+
# Asserts that +h+ is a hash containing +key+. Used to ensure that a +Hash+
|
|
134
|
+
# can be joined with another +Hash+ object.
|
|
135
|
+
#
|
|
136
|
+
# @raise [JoinError] if +h+ is not a +Hash+, or if +key_field+ is absent
|
|
137
|
+
# from any element of +lhs+ or +rhs+.
|
|
138
|
+
# @return [NilClass] +nil+
|
|
139
|
+
# @see join_data
|
|
140
|
+
# @see join_array_data
|
|
147
141
|
def self.assert_is_hash_with_key(h, key, error_prefix)
|
|
148
142
|
if !h.instance_of? ::Hash
|
|
149
143
|
raise JoinError.new("#{error_prefix} is not a Hash: #{h}")
|
|
@@ -152,17 +146,20 @@ module HashJoiner
|
|
|
152
146
|
end
|
|
153
147
|
end
|
|
154
148
|
|
|
155
|
-
# Joins data in
|
|
156
|
-
#
|
|
157
|
-
#
|
|
158
|
-
#
|
|
159
|
-
#
|
|
160
|
-
# Raises JoinError if either lhs or rhs is not an Array of Hash, or if
|
|
161
|
-
# +key_field+ is absent from any element of +lhs+ or +rhs+.
|
|
149
|
+
# Joins data in +lhs+ with data from +rhs+ based on +key_field+. Both +lhs+
|
|
150
|
+
# and +rhs+ should be of type +Array<Hash>+. Performs a +deep_merge+ on
|
|
151
|
+
# matching objects; assigns values from +rhs+ to +lhs+ if no corresponding
|
|
152
|
+
# value yet exists in +lhs+.
|
|
162
153
|
#
|
|
163
|
-
#
|
|
164
|
-
#
|
|
165
|
-
#
|
|
154
|
+
# @param key_field [String] primary key for joined objects
|
|
155
|
+
# @param lhs [Array<Hash>] joined data sink (left-hand side)
|
|
156
|
+
# @param rhs [Array<Hash>] joined data source (right-hand side)
|
|
157
|
+
# @return [Array<Hash>] +lhs+
|
|
158
|
+
# @raise [JoinError] if either +lhs+ or +rhs+ is not an +Array<Hash>+, or if
|
|
159
|
+
# +key_field+ is absent from any element of +lhs+ or +rhs+
|
|
160
|
+
# @see deep_merge
|
|
161
|
+
# @see join_data
|
|
162
|
+
# @see assert_is_hash_with_key
|
|
166
163
|
def self.join_array_data(key_field, lhs, rhs)
|
|
167
164
|
unless lhs.instance_of? ::Array and rhs.instance_of? ::Array
|
|
168
165
|
raise JoinError.new("Both lhs (#{lhs.class}) and " +
|
|
@@ -175,6 +172,8 @@ module HashJoiner
|
|
|
175
172
|
lhs_index[i[key_field]] = i
|
|
176
173
|
end
|
|
177
174
|
|
|
175
|
+
# TODO(mbland): Make exception-safe by splitting into two loops: one for
|
|
176
|
+
# the assert; one to modify lhs after all the assertions have succeeded.
|
|
178
177
|
rhs.each do |i|
|
|
179
178
|
self.assert_is_hash_with_key(i, key_field, "RHS element")
|
|
180
179
|
key = i[key_field]
|
|
@@ -184,5 +183,6 @@ module HashJoiner
|
|
|
184
183
|
lhs << i
|
|
185
184
|
end
|
|
186
185
|
end
|
|
186
|
+
lhs
|
|
187
187
|
end
|
|
188
188
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: hash-joiner
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0.
|
|
4
|
+
version: 0.0.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Mike Bland
|
|
@@ -9,15 +9,58 @@ autorequire:
|
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
11
|
date: 2014-12-19 00:00:00.000000000 Z
|
|
12
|
-
dependencies:
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: rake
|
|
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
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: minitest
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - ">="
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '0'
|
|
34
|
+
type: :development
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - ">="
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '0'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: codeclimate-test-reporter
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - ">="
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '0'
|
|
48
|
+
type: :development
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - ">="
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '0'
|
|
13
55
|
description: Performs pruning or one-level promotion of Hash attributes (typically
|
|
14
|
-
labeled "private") and deep joins of Hash objects. Works on Array objects
|
|
15
|
-
Hash objects as well.
|
|
56
|
+
labeled "private:"), and deep merges and joins of Hash objects. Works on Array objects
|
|
57
|
+
containing Hash objects as well.
|
|
16
58
|
email: michael.bland@gsa.gov
|
|
17
59
|
executables: []
|
|
18
60
|
extensions: []
|
|
19
61
|
extra_rdoc_files: []
|
|
20
62
|
files:
|
|
63
|
+
- README.md
|
|
21
64
|
- lib/hash-joiner.rb
|
|
22
65
|
homepage: https://github.com/18F/hash-joiner
|
|
23
66
|
licenses:
|
|
@@ -42,5 +85,5 @@ rubyforge_project:
|
|
|
42
85
|
rubygems_version: 2.2.2
|
|
43
86
|
signing_key:
|
|
44
87
|
specification_version: 4
|
|
45
|
-
summary: Module for pruning, promoting,
|
|
88
|
+
summary: Module for pruning, promoting, deep-merging, and joining Hash data
|
|
46
89
|
test_files: []
|