team_hub 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5cf9264e56da5d9be22d45f491d56ac435c73ffb
4
- data.tar.gz: 42a5c4d8323cf76de801cd8488af0a3e7dc68c13
3
+ metadata.gz: 06eccea8356a509dea1155db551c5ec3531fffd9
4
+ data.tar.gz: ff689d5c288d78cf8ee1a7dc71fae104b266bc86
5
5
  SHA512:
6
- metadata.gz: 5b39d7741bb71d0b418d0152b3b3db9bcd134244e968928029e0d6dd0d828f9869c87b8b0fd2f1172e56f1420a0fb7488472414b0701a4d649668658276465e9
7
- data.tar.gz: 2915afc5a15fba0e241c0b376f5fa4d7a7b108fd87740557903108394bd64b80b058c6e7e37edcaf3ae420c0259c7f366dbcce838d72f511da2eb597c466a803
6
+ metadata.gz: 61814aa3d81ec152e8aac2de632cedf351c16c2918486c3910435f3d556130e836088263d5445e7b75d19e0e0288b4287fc109e88a0274fd106d77f1bbeb9874
7
+ data.tar.gz: c78e5524d6489ea19f907a61d0e951baedd5849c08ad5ab6e16dde9c5184c0aeae1fbd5682542f0fc2612830f9c24f6c7d6083e551842aea9ecb96656650f877
data/lib/team_hub.rb CHANGED
@@ -15,6 +15,7 @@
15
15
  # @author Mike Bland (michael.bland@gsa.gov)
16
16
 
17
17
  require 'team_hub/canonicalizer'
18
+ require 'team_hub/cross_referencer'
18
19
  require 'team_hub/version'
19
20
  require 'team_hub/page'
20
21
  require 'team_hub/private_assets'
@@ -0,0 +1,210 @@
1
+ # team_hub - Components for creating a team Hub using Jekyll
2
+ #
3
+ # Written in 2015 by Mike Bland (michael.bland@gsa.gov)
4
+ # on behalf of the 18F team, part of the US General Services Administration:
5
+ # https://18f.gsa.gov/
6
+ #
7
+ # To the extent possible under law, the author(s) have dedicated all copyright
8
+ # and related and neighboring rights to this software to the public domain
9
+ # worldwide. This software is distributed without any warranty.
10
+ #
11
+ # You should have received a copy of the CC0 Public Domain Dedication along
12
+ # with this software. If not, see
13
+ # <https://creativecommons.org/publicdomain/zero/1.0/>.
14
+ #
15
+ # @author Mike Bland (michael.bland@gsa.gov)
16
+
17
+ module TeamHub
18
+
19
+ # Operations for creating cross-references between data objects
20
+ class CrossReferencer
21
+ # Creates an index of +collection+ items based on +key+.
22
+ #
23
+ # @param collection [Array<Hash>] collection from which to build an index
24
+ # @param key [String] property used to build the index
25
+ # @return [Hash]
26
+ def self.create_index(collection, key)
27
+ index = collection.group_by {|i| i[key]}
28
+ index.delete nil
29
+ index
30
+ end
31
+
32
+ # Creates cross-references between Hash objects in +sources+ and Hash
33
+ # objects in +targets+.
34
+ #
35
+ # Each object in +sources+ should have a +source_key+ member that is an
36
+ # Array<String> of target identifiers (keys into +targets+) that will be
37
+ # replaced with an Array<Hash> of object references from +targets+.
38
+ #
39
+ # Objects in +targets+ should not yet contain a +target_key+ member. This
40
+ # member will be created as an Array<Hash> of object references from
41
+ # +sources+.
42
+ #
43
+ # If an object cross-referenced by an object in +sources+ does not exist
44
+ # in +targets+, that cross-reference will be skipped without error. If an
45
+ # object from +sources+ does not contain a +source_key+ property, it will
46
+ # also be skipped.
47
+ #
48
+ # @param sources [Array<Hash>] objects containing the information
49
+ # needed to establish cross-references with objects in +targets+
50
+ # @param source_key [String] identifies the cross-referenced property from
51
+ # +sources+
52
+ # @param targets [Hash<Hash>] index of objects to cross-reference with
53
+ # objects from +sources+
54
+ # @param target_key [String] identifies the cross-referenced property from
55
+ # +targets+
56
+ def self.create_xrefs(sources, source_key, targets, target_key)
57
+ (sources || []).each do |source|
58
+ (source[source_key] || []).map! do |target_id|
59
+ target = targets[target_id]
60
+ (target[target_key] ||= Array.new) << source if target
61
+ target
62
+ end.compact!
63
+ end
64
+ end
65
+
66
+ # Creates a copy of +collection+ where each item's +property+ member has
67
+ # had its objects replaced with an Array of +property_key+ values.
68
+ #
69
+ # The primary use case is to "flatten" a list of Hash objects that have
70
+ # cross-reference links back to Hash objects in +collection+. While
71
+ # cross-referencing objects makes it easy to traverse the object graph
72
+ # in-memory, it is useful to flatten these cross-references when
73
+ # serializing data, generating API data, checking cross-references in
74
+ # automated tests (in concert with property_map, to avoid producing
75
+ # voluminous output for assertion failures due to extraneous data and the
76
+ # infinite recursion between cross-referenced objects), logging, and error
77
+ # reporting.
78
+ #
79
+ # @param collection [Array<Hash>] objects for which to flatten the
80
+ # +property+ collection
81
+ # @param property [String] property of objects in +collection+
82
+ # corresponding to a list of (possibly cross-referenced) Hash objects
83
+ # @param property_key [String] primary key of cross-referenced objects;
84
+ # the corresponding value should be a String
85
+ # @return [Array] a copy of collection with +property+ items flattened
86
+ def self.flatten_property(collection, property, property_key)
87
+ collection.map do |i|
88
+ item = i.clone
89
+ item[property] = i[property].map {|p| p[property_key]} if i[property]
90
+ item
91
+ end
92
+ end
93
+
94
+ # The in-place version of flatten_property which directly replaces the
95
+ # +property+ member of each item of +collection+ with an Array of
96
+ # +property_key+ values.
97
+ #
98
+ # In addition to the use cases described in the the flatten_property
99
+ # comment, the in-place version may be useful to help free memory by
100
+ # eliminating circular object references.
101
+ #
102
+ # @see flatten_property
103
+ def self.flatten_property!(collection, property, property_key)
104
+ collection.each do |i|
105
+ i[property].map! {|p| p[property_key]} if i[property]
106
+ end
107
+ end
108
+
109
+ # Creates a map from +primary_key+ values to flattened +property+ values
110
+ # for each item in +collection+.
111
+ #
112
+ # For checking cross-referenced property values in automated tests,
113
+ # first process +collection+ using flatten_property to avoid voluminous
114
+ # output due to the infinite recursion between cross-referenced objects.
115
+ #
116
+ # @param collection [Array<Hash>] objects for which to flatten the
117
+ # +property+ collection
118
+ # @param primary_key [String] primary key for objects in +collection+; the
119
+ # corresponding value should be a String
120
+ # @param property [String] property of objects in +collection+
121
+ # corresponding to a list of (possibly cross-referenced) Hash objects
122
+ # @param property_key [String] primary key of cross-referenced objects; the
123
+ # corresponding value should be a String
124
+ # @return [Hash<String, Array<String>>] +primary_key+ values =>
125
+ # flattened +property+ values
126
+ # @see flatten_property
127
+ def self.property_map(collection, primary_key, property, property_key)
128
+ collection.map do |i|
129
+ [i[primary_key], i[property].map {|p| p[property_key]}] if i[property]
130
+ end.compact.to_h
131
+ end
132
+ end
133
+
134
+ # Implements CrossReferencer operations.
135
+ class CrossReferencerImpl
136
+ attr_reader :site_data
137
+
138
+ def initialize(site_data)
139
+ @site_data = site_data
140
+ @team = @site_data['team'].map {|i| [i['name'], i]}.to_h
141
+ end
142
+
143
+ # Cross-references geographic locations with team members.
144
+ #
145
+ # The resulting site.data['locations'] collection will be an Array of
146
+ # [location code, Array<Hash> of team members].
147
+ def xref_locations_and_team_members
148
+ locations = CrossReferencer.create_index(@site_data['team'], 'location')
149
+ @site_data['locations'] = locations.to_a.sort! unless locations.empty?
150
+ end
151
+
152
+ # Cross-references projects with team members. Replaces string-based
153
+ # site_data['projects']['team'] values with team member hashes.
154
+ def xref_projects_and_team_members
155
+ projects = @site_data['projects']
156
+ projects.each {|p| p['team'] = p['team'].split(/, ?/) if p['team']}
157
+ CrossReferencer.create_xrefs projects, 'team', @team, 'projects'
158
+ end
159
+
160
+ # Cross-references groups with team members.
161
+ #
162
+ # @param groups_name [String] site.data key identifying the group
163
+ # collection, e.g. 'working_groups'
164
+ # @param member_type_list_names [Array<String>] names of the properties
165
+ # identifying lists of members, e.g. ['leads', 'members']
166
+ def xref_groups_and_team_members(groups_name, member_type_list_names)
167
+ member_type_list_names.each do |member_type|
168
+ CrossReferencer.create_xrefs(
169
+ @site_data[groups_name], member_type, @team, groups_name)
170
+ end
171
+ @team.values.each {|i| (i[groups_name] || []).uniq! {|g| g['name']}}
172
+ end
173
+
174
+ # Cross-references snippets with team members. Also sets
175
+ # site.data['snippets_latest'] and @site_data['snippets_team_members'].
176
+ def xref_snippets_and_team_members
177
+ (@site_data['snippets'] || []).each do |timestamp, snippets|
178
+ snippets.each do |snippet|
179
+ (@team[snippet['name']]['snippets'] ||= Array.new) << snippet
180
+ end
181
+
182
+ # Since the snippets are naturally ordered in chronological order,
183
+ # the last will be the latest.
184
+ @site_data['snippets_latest'] = timestamp
185
+ end
186
+
187
+ @site_data['snippets_team_members'] = @team.values.select do |i|
188
+ i['snippets']
189
+ end unless (@site_data['snippets'] || []).empty?
190
+ end
191
+
192
+ # Cross-references skillsets with team members.
193
+ #
194
+ # @param skills [Array<String>] list of skill categories; may be
195
+ # capitalized, though the members of site.data['team'] pertaining to
196
+ # each category should be lowercased
197
+ def xref_skills_and_team_members(categories)
198
+ skills = categories.map {|category| [category, Hash.new]}.to_h
199
+
200
+ @team.values.each do |i|
201
+ skills.each do |category, xref|
202
+ (i[category.downcase] || []).each {|s| (xref[s] ||= Array.new) << i}
203
+ end
204
+ end
205
+
206
+ skills.delete_if {|category, skill_xref| skill_xref.empty?}
207
+ @site_data['skills'] = skills unless skills.empty?
208
+ end
209
+ end
210
+ end
@@ -23,5 +23,5 @@
23
23
  # https://github.com/18F/hub"
24
24
 
25
25
  module TeamHub
26
- VERSION = "0.0.2"
26
+ VERSION = "0.0.3"
27
27
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: team_hub
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike Bland
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-01-30 00:00:00.000000000 Z
11
+ date: 2015-02-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: hash-joiner
@@ -136,6 +136,7 @@ files:
136
136
  - README.md
137
137
  - lib/team_hub.rb
138
138
  - lib/team_hub/canonicalizer.rb
139
+ - lib/team_hub/cross_referencer.rb
139
140
  - lib/team_hub/page.rb
140
141
  - lib/team_hub/private_assets.rb
141
142
  - lib/team_hub/version.rb
@@ -164,4 +165,3 @@ signing_key:
164
165
  specification_version: 4
165
166
  summary: Components for creating a team Hub using Jekyll
166
167
  test_files: []
167
- has_rdoc: