weekly_snippets 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
[![Gem Version](https://badge.fury.io/rb/weekly_snippets.svg)](https://badge.fury.io/rb/weekly_snippets)
|
4
|
+
[![Build Status](https://travis-ci.org/18F/weekly_snippets.svg?branch=master)](https://travis-ci.org/18F/weekly_snippets)
|
5
|
+
[![Code Climate](https://codeclimate.com/github/18F/weekly_snippets/badges/gpa.svg)](https://codeclimate.com/github/18F/weekly_snippets)
|
6
|
+
[![Test Coverage](https://codeclimate.com/github/18F/weekly_snippets/badges/coverage.svg)](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: []
|