team_hub 0.0.2 → 0.0.3

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 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: