weekly_snippets 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 +7 -0
- data/README.md +244 -0
- data/lib/weekly_snippets.rb +18 -0
- data/lib/weekly_snippets/publisher.rb +110 -0
- data/lib/weekly_snippets/version.rb +172 -0
- metadata +106 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 56b395cc3e7141db6ffdd1c1fab46b846c70fab6
|
4
|
+
data.tar.gz: 6c86ae22375a0bc52522595ffe84cad841251b55
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 0e118fcbf069ab6d4d3a097c7c0f3af0977db2fb674102e6b160c97075ba10c6f79fe1369eca65f0795429c488be46ec8edb4bbd8f8669e82dface6413b03a41
|
7
|
+
data.tar.gz: df30c05e750d18d0857d82bb99b15fd2356edad0d7e5ce29c0edf797ee327524f636f2faa86f6702e4cf216acf0ee8910967e32efbb4f50859734c6a07a86990
|
data/README.md
ADDED
@@ -0,0 +1,244 @@
|
|
1
|
+
## weekly_snippets Gem
|
2
|
+
|
3
|
+
[](https://badge.fury.io/rb/weekly_snippets)
|
4
|
+
[](https://travis-ci.org/18F/weekly_snippets)
|
5
|
+
[](https://codeclimate.com/github/18F/weekly_snippets)
|
6
|
+
[](https://codeclimate.com/github/18F/weekly_snippets)
|
7
|
+
|
8
|
+
Standardizes different weekly snippet formats into a common format,
|
9
|
+
[munges](http://en.wikipedia.org/wiki/Mung_(computer_term)) snippet text
|
10
|
+
according to user-supplied rules, performs redaction of internal information,
|
11
|
+
and publishes snippets in plaintext or Markdown format.
|
12
|
+
|
13
|
+
Downloads and API docs are available on the [weekly_snippets RubyGems
|
14
|
+
page](https://rubygems.org/gems/weekly_snippets). API documentation is written
|
15
|
+
using [YARD markup](http://yardoc.org/).
|
16
|
+
|
17
|
+
Contributed by the 18F team, part of the United States General Services
|
18
|
+
Administration: https://18f.gsa.gov/
|
19
|
+
|
20
|
+
### Motivation
|
21
|
+
|
22
|
+
This gem was extracted from [the 18F Hub Joiner
|
23
|
+
plugin](https://github.com/18F/hub/blob/master/_plugins/joiner.rb). That
|
24
|
+
plugin manipulates [Jekyll-imported data](http://jekyllrb.com/docs/datafiles/)
|
25
|
+
by removing or promoting private data, building indices, and performing joins
|
26
|
+
between different data files so that the results appear as unified collections
|
27
|
+
in Jekyll's `site.data` object. It serves as the first stage in a pipeline
|
28
|
+
that also builds cross-references and canonicalizes data before generating
|
29
|
+
static HTML pages and other artifacts.
|
30
|
+
|
31
|
+
### Installation
|
32
|
+
|
33
|
+
Add this line to your application's Gemfile:
|
34
|
+
|
35
|
+
```ruby
|
36
|
+
gem 'weekly_snippets'
|
37
|
+
```
|
38
|
+
|
39
|
+
And then execute:
|
40
|
+
```
|
41
|
+
$ bundle
|
42
|
+
```
|
43
|
+
|
44
|
+
Or install it yourself as:
|
45
|
+
```
|
46
|
+
$ gem install weekly_snippets
|
47
|
+
```
|
48
|
+
|
49
|
+
### Usage
|
50
|
+
|
51
|
+
The [18F Hub](https://github.com/18F/hub) processes snippet data as [CSV
|
52
|
+
files](https://en.wikipedia.org/wiki/Comma-separated_values) harvested from a
|
53
|
+
web-based spreadsheet, stored using [timestamped
|
54
|
+
filenames](http://en.wikipedia.org/wiki/ISO_8601#Calendar_dates) in the
|
55
|
+
[Jekyll _data folder](http://jekyllrb.com/docs/datafiles/). Since we have
|
56
|
+
experimented with different CSV column formats, we keep the data files
|
57
|
+
corresponding to each version in separate directories:
|
58
|
+
|
59
|
+
```
|
60
|
+
$ ls -1d _data/private/snippets/*
|
61
|
+
_data/private/snippets/v1/
|
62
|
+
_data/private/snippets/v2/
|
63
|
+
_data/private/snippets/v3/
|
64
|
+
```
|
65
|
+
|
66
|
+
The content of the lattermost `v3` directory as of writing:
|
67
|
+
|
68
|
+
```
|
69
|
+
$ ls -1 _data/private/snippets/v3
|
70
|
+
20141208.csv
|
71
|
+
20141215.csv
|
72
|
+
20141222.csv
|
73
|
+
```
|
74
|
+
|
75
|
+
With this data in-place, the Hub performs the following steps:
|
76
|
+
|
77
|
+
#### Standardize versions
|
78
|
+
|
79
|
+
The [18F Hub joiner.rb
|
80
|
+
plugin](https://github.com/18F/hub/blob/master/_plugins/joiner.rb) defines
|
81
|
+
this map from version names to `Version` objects:
|
82
|
+
|
83
|
+
```ruby
|
84
|
+
# Used to standardize snippet data of different versions before joining
|
85
|
+
# and publishing.
|
86
|
+
SNIPPET_VERSIONS = {
|
87
|
+
'v1' => WeeklySnippets::Version.new(
|
88
|
+
version_name:'v1',
|
89
|
+
field_map:{
|
90
|
+
'Username' => 'username',
|
91
|
+
'Timestamp' => 'timestamp',
|
92
|
+
'Name' => 'full_name',
|
93
|
+
'Snippets' => 'last-week',
|
94
|
+
'No This Week' => 'this-week',
|
95
|
+
}
|
96
|
+
),
|
97
|
+
'v2' => WeeklySnippets::Version.new(
|
98
|
+
version_name:'v2',
|
99
|
+
field_map:{
|
100
|
+
'Timestamp' => 'timestamp',
|
101
|
+
'Public vs. Private' => 'public',
|
102
|
+
'Last Week' => 'last-week',
|
103
|
+
'This Week' => 'this-week',
|
104
|
+
'Username' => 'username',
|
105
|
+
},
|
106
|
+
markdown_supported: true
|
107
|
+
),
|
108
|
+
'v3' => WeeklySnippets::Version.new(
|
109
|
+
version_name:'v3',
|
110
|
+
field_map:{
|
111
|
+
'Timestamp' => 'timestamp',
|
112
|
+
'Public' => 'public',
|
113
|
+
'Username' => 'username',
|
114
|
+
'Last week' => 'last-week',
|
115
|
+
'This week' => 'this-week',
|
116
|
+
},
|
117
|
+
public_field: 'public',
|
118
|
+
public_value: 'Public',
|
119
|
+
markdown_supported: true
|
120
|
+
),
|
121
|
+
}
|
122
|
+
```
|
123
|
+
|
124
|
+
This map is then used to standardize batches of weekly snippets, converting
|
125
|
+
each different version to a common format, before joining the data with team
|
126
|
+
member information:
|
127
|
+
|
128
|
+
```ruby
|
129
|
+
# Snippet data is expected to be stored in files matching the pattern:
|
130
|
+
# _data/@source/snippets/[version]/[YYYYMMDD].csv
|
131
|
+
#
|
132
|
+
# resulting in the initial structure:
|
133
|
+
# site.data[@source][snippets][version][YYYYMMDD] = Array<Hash>
|
134
|
+
#
|
135
|
+
# After this function returns, the `standardized` will be of the form:
|
136
|
+
# site.data[snippets][YYYYMMDD] = Array<Hash>
|
137
|
+
standardized = ::WeeklySnippets::Version.standardize_versions(
|
138
|
+
@data[@source]['snippets'], snippet_versions)
|
139
|
+
```
|
140
|
+
|
141
|
+
#### Munge
|
142
|
+
|
143
|
+
To accommodate the preferred formats employed by some team members, the
|
144
|
+
[18F Hub snippets.rb plugin](https://github.com/18F/hub/blob/master/_plugins/snippets.rb)
|
145
|
+
defines a Ruby block to
|
146
|
+
[munge](http://en.wikipedia.org/wiki/Mung_(computer_term)) the snippet data
|
147
|
+
before converting it to a uniform
|
148
|
+
[Markdown](http://daringfireball.net/projects/markdown/syntax) representation:
|
149
|
+
|
150
|
+
```ruby
|
151
|
+
MARKDOWN_SNIPPET_MUNGER = Proc.new do |text|
|
152
|
+
text.gsub!(/^::: (.*) :::$/, "#{HEADLINE} \\1") # For jtag. ;-)
|
153
|
+
text.gsub!(/^\*\*\*/, HEADLINE) # For elaine. ;-)
|
154
|
+
end
|
155
|
+
```
|
156
|
+
|
157
|
+
This block is then passed as an argument to `WeeklySnippets::Publisher.new()`,
|
158
|
+
discussed in the **Publish** section below.
|
159
|
+
|
160
|
+
#### Redact internal info
|
161
|
+
|
162
|
+
Text that should be available when published internally, but redacted from
|
163
|
+
publicly-published snippets, can be surrounded by `{{` and `}}` tokens:
|
164
|
+
|
165
|
+
```ruby
|
166
|
+
> require 'weekly_snippets/publisher'
|
167
|
+
|
168
|
+
# Instantiate a publisher for internally-visible snippets
|
169
|
+
> publisher = WeeklySnippets::Publisher.new(
|
170
|
+
headline: "\n####", public_mode: false)
|
171
|
+
|
172
|
+
> snippets = [
|
173
|
+
'- Did stuff{{ including private details}}',
|
174
|
+
'{{- Did secret stuff}}',
|
175
|
+
'- Did more stuff',
|
176
|
+
'{{- Did more secret stuff',
|
177
|
+
'- Yet more secret stuff}}',
|
178
|
+
]
|
179
|
+
|
180
|
+
# For internally-visible snippets, the text inside the `{{` and `}}`
|
181
|
+
# tokens will be preserved.
|
182
|
+
> puts publisher.redact! snippets.join("\n")
|
183
|
+
|
184
|
+
- Did stuff including private details
|
185
|
+
- Did secret stuff
|
186
|
+
- Did more stuff
|
187
|
+
- Did more secret stuff
|
188
|
+
- Yet more secret stuff
|
189
|
+
|
190
|
+
# Instantiate a publisher for publicly-visible snippets
|
191
|
+
> publisher = WeeklySnippets::Publisher.new(
|
192
|
+
headline: "\n####", public_mode: true)
|
193
|
+
|
194
|
+
# For publicly-visible snippets, the text inside the `{{` and `}}`
|
195
|
+
# tokens will be removed.
|
196
|
+
> puts publisher.redact! snippets.join("\n")
|
197
|
+
|
198
|
+
- Did stuff
|
199
|
+
- Did more stuff
|
200
|
+
```
|
201
|
+
|
202
|
+
`WeeklySnippets::Publisher::publish()` automatically calls
|
203
|
+
`WeeklySnippets::Publisher::redact!`, so it shouldn't be necessary to call it
|
204
|
+
directly.
|
205
|
+
|
206
|
+
#### Publish
|
207
|
+
|
208
|
+
This is how the
|
209
|
+
[18F Hub snippets.rb plugin](https://github.com/18F/hub/blob/master/_plugins/snippets.rb)
|
210
|
+
creates a `WeeklySnippets::Publisher` object and uses its `publish()` method
|
211
|
+
to process snippets and store the result in the [Jekyll site.data
|
212
|
+
object](http://jekyllrb.com/docs/datafiles/):
|
213
|
+
|
214
|
+
```ruby
|
215
|
+
publisher = ::WeeklySnippets::Publisher.new(
|
216
|
+
headline: HEADLINE, public_mode: site.config['public'],
|
217
|
+
markdown_snippet_munger: MARKDOWN_SNIPPET_MUNGER)
|
218
|
+
site.data['snippets'] = publisher.publish site.data['snippets']
|
219
|
+
```
|
220
|
+
|
221
|
+
### Contributing
|
222
|
+
|
223
|
+
1. Fork the repo ( https://github.com/18F/weekly_snippets/fork )
|
224
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
225
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
226
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
227
|
+
5. Create a new Pull Request
|
228
|
+
|
229
|
+
Feel free to ping [@mbland](https://github.com/mbland) with any questions you
|
230
|
+
may have, especially if the current documentation should've addressed your
|
231
|
+
needs, but didn't.
|
232
|
+
|
233
|
+
### Public domain
|
234
|
+
|
235
|
+
This project is in the worldwide [public domain](LICENSE.md). As stated in
|
236
|
+
[CONTRIBUTING](CONTRIBUTING.md):
|
237
|
+
|
238
|
+
> This project is in the public domain within the United States, and copyright
|
239
|
+
> and related rights in the work worldwide are waived through the
|
240
|
+
> [CC0 1.0 Universal public domain dedication](https://creativecommons.org/publicdomain/zero/1.0/).
|
241
|
+
>
|
242
|
+
> All contributions to this project will be released under the CC0 dedication.
|
243
|
+
> By submitting a pull request, you are agreeing to comply with this waiver of
|
244
|
+
> copyright interest.
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# 18F Snippets - Standardize, munge, redact, and publish weekly snippets
|
2
|
+
#
|
3
|
+
# Written in 2014 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
|
+
require "weekly_snippets/version"
|
18
|
+
require "weekly_snippets/publisher"
|
@@ -0,0 +1,110 @@
|
|
1
|
+
# 18F Snippets - Standardize, munge, redact, and publish weekly snippets
|
2
|
+
#
|
3
|
+
# Written in 2014 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 WeeklySnippets
|
18
|
+
class Publisher
|
19
|
+
# @param headline [String] Markdown string used to markup each section
|
20
|
+
# title within a block of snippet text
|
21
|
+
# @param public_mode [true, false, or nil] indicates whether or not the
|
22
|
+
# snippets are to be published publicly; private snippets and redacted
|
23
|
+
# spans of text will not be published when +public_mode+ is true
|
24
|
+
# @param markdown_snippet_munger [Proc] the code block that will be called
|
25
|
+
# with a String of snippet text after redaction and before Markdown
|
26
|
+
# preparation, to modify the snippet text String in-place; will not be
|
27
|
+
# called if the snippet's version doesn't support Markdown syntax
|
28
|
+
def initialize(headline:, public_mode:, markdown_snippet_munger:nil)
|
29
|
+
@headline = headline
|
30
|
+
@public_mode = public_mode
|
31
|
+
@markdown_snippet_munger = markdown_snippet_munger
|
32
|
+
end
|
33
|
+
|
34
|
+
# Processes +snippets+ entries for publication. Any snippets that should
|
35
|
+
# not appear when in +public_mode+ are removed from +snippets+
|
36
|
+
def publish(snippets)
|
37
|
+
result = {}
|
38
|
+
snippets.each do |timestamp, snippet_batch|
|
39
|
+
published = []
|
40
|
+
snippet_batch.each do |snippet|
|
41
|
+
unless @public_mode and !snippet['public']
|
42
|
+
publish_snippet(snippet, published)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
result[timestamp] = published unless published.empty?
|
46
|
+
end
|
47
|
+
result
|
48
|
+
end
|
49
|
+
|
50
|
+
# Parses and publishes a snippet. Filters out snippets rendered empty
|
51
|
+
# after redaction.
|
52
|
+
# @param snippet [Hash<String,String>] snippet hash with two fields:
|
53
|
+
# +last-week+ and +this-week+
|
54
|
+
# @param published [Array<Hash<String,String>>] array of published snippets
|
55
|
+
def publish_snippet(snippet, published)
|
56
|
+
['last-week', 'this-week'].each do |field|
|
57
|
+
text = snippet[field] || ''
|
58
|
+
redact! text
|
59
|
+
if snippet['markdown']
|
60
|
+
@markdown_snippet_munger.yield text if @markdown_snippet_munger
|
61
|
+
text = prepare_markdown text
|
62
|
+
end
|
63
|
+
snippet[field] = text.empty? ? nil : text
|
64
|
+
end
|
65
|
+
|
66
|
+
is_empty = (snippet['last-week'] || '').empty? && (
|
67
|
+
snippet['this-week'] || '').empty?
|
68
|
+
published << snippet unless is_empty
|
69
|
+
end
|
70
|
+
|
71
|
+
# Parses "{{" and "}}" redaction markers. For public snippets, will redact
|
72
|
+
# everything between each set of markers. For internal snippets, will only
|
73
|
+
# remove the markers.
|
74
|
+
def redact!(text)
|
75
|
+
if @public_mode
|
76
|
+
text.gsub!(/\n?\{\{.*?\}\}/m,'')
|
77
|
+
else
|
78
|
+
text.gsub!(/(\{\{|\}\})/,'')
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# Processes snippet text in Markdown format to smooth out any anomalies
|
83
|
+
# before rendering. Also translates arbitrary plaintext to Markdown.
|
84
|
+
#
|
85
|
+
# @param text [String] snippet text
|
86
|
+
# @return [String]
|
87
|
+
def prepare_markdown(text)
|
88
|
+
parsed = []
|
89
|
+
uses_item_markers = (text =~ /^[-*]/)
|
90
|
+
|
91
|
+
text.each_line do |line|
|
92
|
+
line.rstrip!
|
93
|
+
# Convert headline markers.
|
94
|
+
line.sub!(/^(#+)/, @headline)
|
95
|
+
|
96
|
+
# Add item markers for those who used plaintext and didn't add them;
|
97
|
+
# add headline markers for those who defined different sections and
|
98
|
+
# didn't add them.
|
99
|
+
if line =~ /^([A-Za-z0-9])/
|
100
|
+
line = uses_item_markers ? "#{@headline} #{line}" : "- #{line}"
|
101
|
+
end
|
102
|
+
|
103
|
+
# Fixup item markers missing a space.
|
104
|
+
line.sub!(/^[-*]([^ ])/, '- \1')
|
105
|
+
parsed << line unless line.empty?
|
106
|
+
end
|
107
|
+
parsed.join("\n")
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1,172 @@
|
|
1
|
+
# 18F Snippets - Standardize, munge, redact, and publish weekly snippets
|
2
|
+
#
|
3
|
+
# Written in 2014 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 WeeklySnippets
|
18
|
+
VERSION = "0.0.1"
|
19
|
+
|
20
|
+
# Encapsulates the mapping from actual snippet data fields to a standardized
|
21
|
+
# set of data fields for each version of snippets.
|
22
|
+
#
|
23
|
+
# Since 18F experimented with a handful of different snippet formats, with
|
24
|
+
# slightly different field names and semantics, we needed a way to transform
|
25
|
+
# each batch into a common format before generating Hub pages, to streamline
|
26
|
+
# the logic and possibly allow for even more formats in the future without
|
27
|
+
# requiring version-specific hacks.
|
28
|
+
#
|
29
|
+
# The common format fields are:
|
30
|
+
# - username: identifies the snippet author
|
31
|
+
# - last-week: summary of last week's activity
|
32
|
+
# - this-week: summary of this week's anticipated activity
|
33
|
+
# - timestamp: identifies when the snippet was reported; might not
|
34
|
+
# necessarily match the timestamp of the batch in which it appears
|
35
|
+
# - public: true if the snippet may be published publicly
|
36
|
+
# - markdown: true if the snippet version supports Markdown syntax
|
37
|
+
#
|
38
|
+
# When using Jekyll, snippet data should be stored in the _data directory
|
39
|
+
# with versioned subdirectories containing timestamped Comma Separated Value
|
40
|
+
# (CSV) files, e.g.:
|
41
|
+
# - _data/snippets/v1/20141110.csv
|
42
|
+
# - _data/snippets/v2/20141201.csv
|
43
|
+
# - _data/snippets/v3/20141208.csv
|
44
|
+
#
|
45
|
+
# Jekyll imports this data into a Hash structure (site.data['snippets'])
|
46
|
+
# resembling:
|
47
|
+
# - version => { timestamp => [ snippets ] }
|
48
|
+
#
|
49
|
+
# Version.standardize_versions will convert this structure into a Hash
|
50
|
+
# resembling:
|
51
|
+
# - timestamp => [ snippets ]
|
52
|
+
class Version
|
53
|
+
# Set of field name values that the +field_map+ argument of +initialize+
|
54
|
+
# must map to.
|
55
|
+
FIELD_NAMES = ['username', 'last-week', 'this-week', 'timestamp']
|
56
|
+
|
57
|
+
# Raised by +initialize+ when the initialization parameters are flawed.
|
58
|
+
class InitError < ::Exception
|
59
|
+
end
|
60
|
+
|
61
|
+
attr_reader(:version_name, :field_map, :public_field, :public_value,
|
62
|
+
:markdown_supported)
|
63
|
+
|
64
|
+
# @param version_name [String] identifies the version, e.g. "v3"
|
65
|
+
# @param field_map [Hash<String, String>] contains the mapping from the
|
66
|
+
# field name in the original data file to the standardized internal
|
67
|
+
# field name
|
68
|
+
# @param public_field [String] if present, the field that indicates whether
|
69
|
+
# or not a snippet can be published in public mode; if not present, no
|
70
|
+
# snippets matching this version should be published publicly
|
71
|
+
# @param public_value [String] if present, the value for +public_field+
|
72
|
+
# that indicates whether or not a snippet should be published in public
|
73
|
+
# mode
|
74
|
+
# @param markdown_supported [true,false] indicates whether or not the
|
75
|
+
# snippet version supports Markdown syntax
|
76
|
+
# @raise [InitError] if +field_map+ does not contain mappings for every
|
77
|
+
# element of FIELD_NAMES
|
78
|
+
# @raise [InitError] if one of +public_field+ or +public_value+ is set, but
|
79
|
+
# not the other
|
80
|
+
def initialize(version_name:, field_map:, public_field:nil,
|
81
|
+
public_value:nil, markdown_supported: false)
|
82
|
+
|
83
|
+
expected = FIELD_NAMES.sort
|
84
|
+
actual = field_map.values.sort
|
85
|
+
intersection = expected & actual
|
86
|
+
|
87
|
+
unless intersection == expected
|
88
|
+
raise InitError.new("Snippet version \"#{version_name}\" " +
|
89
|
+
"missing mappings for fields: #{expected - intersection}")
|
90
|
+
end
|
91
|
+
|
92
|
+
unless (public_field == nil and public_value == nil) or (
|
93
|
+
public_field != nil and public_value != nil)
|
94
|
+
raise InitError.new("Snippet version \"#{version_name}\" has " +
|
95
|
+
"public_field and public_value mismatched: " +
|
96
|
+
"public_field == #{public_field ? "\"#{public_field}\"" : 'nil'}; " +
|
97
|
+
"public_value == #{public_value ? "\"#{public_value}\"" : 'nil'}")
|
98
|
+
end
|
99
|
+
|
100
|
+
@version_name = version_name
|
101
|
+
@field_map = field_map
|
102
|
+
@public_field = public_field
|
103
|
+
@public_value = public_value
|
104
|
+
@markdown_supported = markdown_supported
|
105
|
+
end
|
106
|
+
|
107
|
+
# Raised by +standardize+ when a snippet contains fields not contained in
|
108
|
+
# +field_map+.
|
109
|
+
class UnknownFieldError < ::Exception
|
110
|
+
end
|
111
|
+
|
112
|
+
# Converts the field names within +snippet+ to standardized names using
|
113
|
+
# +field_map+, and sets snippet[public] and snippet[markdown].
|
114
|
+
#
|
115
|
+
# @param snippet [Hash<String, String>] snippet data to evaluate
|
116
|
+
# @return [Hash<String,String>] +snippet+
|
117
|
+
# @raise [UnknownFieldError] if +snippet+ contains fields not contained in
|
118
|
+
# +field_map+
|
119
|
+
def standardize(snippet)
|
120
|
+
snippet.keys.each do |k|
|
121
|
+
unless @field_map.member? k
|
122
|
+
raise UnknownFieldError.new("Snippet field not recognized by " +
|
123
|
+
"version \"#{@version_name}\": #{k}")
|
124
|
+
end
|
125
|
+
snippet[@field_map[k]] = snippet.delete k
|
126
|
+
end
|
127
|
+
snippet['public'] = (@public_field and
|
128
|
+
snippet[@public_field] == @public_value) ? true : false
|
129
|
+
snippet['markdown'] = @markdown_supported
|
130
|
+
snippet
|
131
|
+
end
|
132
|
+
|
133
|
+
# Raised by +standardize_versions+ if a snippet version is unknown.
|
134
|
+
class UnknownVersionError < ::Exception
|
135
|
+
end
|
136
|
+
|
137
|
+
# Transforms snippets of different versions into a standard format.
|
138
|
+
#
|
139
|
+
# The keys of +snippets_by_version+ should indicate the version of the
|
140
|
+
# corresponding batch of snippets, and also match the keys of
|
141
|
+
# +snippet_versions+. Each batch of snippets for each version should be a
|
142
|
+
# Hash from a timestamp string (typically YYYYMMDD) to an Array of Hashes
|
143
|
+
# representing individual snippet entries.
|
144
|
+
#
|
145
|
+
# The resulting Hash will map from timestamp string to an Array of
|
146
|
+
# standardized snippet Hashes, eliminating the now unnecessary version
|
147
|
+
# information.
|
148
|
+
#
|
149
|
+
# @param snippets_by_version [Hash<String, Hash<String, Array<Hash>>>]
|
150
|
+
# contains: version => { timestamp => [ snippets ] }
|
151
|
+
# @param snippet_versions [Hash<String,Snippets::Version>] mapping from
|
152
|
+
# snippet version name to the corresponding Snippets::Version object
|
153
|
+
# @return [Hash<String, Array<Hash>>] a mapping from a (weekly) timestamp
|
154
|
+
# to a corresponding set of standardized snippets
|
155
|
+
#
|
156
|
+
# @raise [UnknownVersionError] if any snippets correspond to versions not
|
157
|
+
# in +snippet_versions+
|
158
|
+
def self.standardize_versions(snippets_by_version, snippet_versions)
|
159
|
+
result = {}
|
160
|
+
snippets_by_version.each do |version, batch|
|
161
|
+
v = snippet_versions[version]
|
162
|
+
unless v
|
163
|
+
raise UnknownVersionError.new("Unknown snippet version: #{version}")
|
164
|
+
end
|
165
|
+
batch.each do |timestamp, snippets|
|
166
|
+
result[timestamp] = snippets.each {|s| v.standardize s}
|
167
|
+
end
|
168
|
+
end
|
169
|
+
result
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
metadata
ADDED
@@ -0,0 +1,106 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: weekly_snippets
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Mike Bland
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-01-07 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.7'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.7'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: minitest
|
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'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: codeclimate-test-reporter
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
description: Standardizes different weekly snippet formats into a common format, munges
|
70
|
+
snippet text according to user-supplied rules, performs redaction of internal information,
|
71
|
+
and publishes snippets in plaintext or Markdown format.
|
72
|
+
email:
|
73
|
+
- michael.bland@gsa.gov
|
74
|
+
executables: []
|
75
|
+
extensions: []
|
76
|
+
extra_rdoc_files: []
|
77
|
+
files:
|
78
|
+
- README.md
|
79
|
+
- lib/weekly_snippets.rb
|
80
|
+
- lib/weekly_snippets/publisher.rb
|
81
|
+
- lib/weekly_snippets/version.rb
|
82
|
+
homepage: https://github.com/18F/weekly_snippets
|
83
|
+
licenses:
|
84
|
+
- CC0
|
85
|
+
metadata: {}
|
86
|
+
post_install_message:
|
87
|
+
rdoc_options: []
|
88
|
+
require_paths:
|
89
|
+
- lib
|
90
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
91
|
+
requirements:
|
92
|
+
- - ">="
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: '0'
|
95
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
96
|
+
requirements:
|
97
|
+
- - ">="
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
version: '0'
|
100
|
+
requirements: []
|
101
|
+
rubyforge_project:
|
102
|
+
rubygems_version: 2.2.2
|
103
|
+
signing_key:
|
104
|
+
specification_version: 4
|
105
|
+
summary: Standardize, munge, redact, and publish weekly snippets
|
106
|
+
test_files: []
|