ghostwriter 0.4.2 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +164 -76
- data/RELEASE_NOTES.md +17 -0
- data/lib/ghostwriter/version.rb +1 -1
- data/lib/ghostwriter/writer.rb +63 -22
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 80d5aced9b18684b3640c28ce1e86c8e9859942f57fefbd26dd1a1f3e7791eaf
|
4
|
+
data.tar.gz: 0f71619c0a7e247cf163f074ca7c8bb54fa8c93daaa5649df8f853fd0ccab1da
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f9760753d4ffc30bee200a33347cd9aeda0b4593304f07ff9ce53c4ca1f971d51b50644feb763ffc51ec5635202e971704592f45d0cbe021693a7e790e39c7e9
|
7
|
+
data.tar.gz: 203df0d639d25f35a73dcdde0f12c037e8f508e086c34cec5e2da7325a8b0e173db10590da50550a50e853f74f0753ce231b36646619fc3c1f166bdd986e7186
|
data/README.md
CHANGED
@@ -2,13 +2,14 @@
|
|
2
2
|
|
3
3
|
Ghostwriter rewrites HTML as plain text while preserving as much legibility and functionality as possible.
|
4
4
|
|
5
|
-
It's sort of like a reverse-markdown.
|
5
|
+
It's sort of like a reverse-markdown or a very, very simple screen reader.
|
6
6
|
|
7
7
|
## But Why, Though?
|
8
8
|
|
9
|
-
* Spam filters tend to like emails with a plain text alternative
|
10
9
|
* Some email clients won't or can’t handle HTML at all
|
11
10
|
* Some people explicitly choose plaintext just by preference or accessibility
|
11
|
+
* Spam filters tend to like emails with a plain text alternative (but if you use this gem to help you spam people, I
|
12
|
+
will yell at you)
|
12
13
|
|
13
14
|
## Installation
|
14
15
|
|
@@ -28,14 +29,16 @@ Or install it manually with:
|
|
28
29
|
|
29
30
|
## Usage
|
30
31
|
|
31
|
-
Create a `Ghostwriter::Writer` with the html you want modified
|
32
|
+
Create a `Ghostwriter::Writer` and call `#textify` with the html you want modified:
|
32
33
|
|
33
34
|
```ruby
|
34
35
|
html = '<html><body><p>This is some markup <a href="tenjin.ca">and a link</a></p><p>Other tags translate, too</p></body></html>'
|
35
36
|
|
36
|
-
Ghostwriter::Writer.new(html)
|
37
|
+
Ghostwriter::Writer.new.textify(html)
|
37
38
|
```
|
39
|
+
|
38
40
|
Produces:
|
41
|
+
|
39
42
|
```
|
40
43
|
This is some markup and a link (tenjin.ca)
|
41
44
|
|
@@ -46,93 +49,153 @@ Other tags translate, too
|
|
46
49
|
|
47
50
|
Links are converted to the link text followed by the link target in brackets:
|
48
51
|
|
49
|
-
```
|
50
|
-
|
51
|
-
|
52
|
+
```html
|
53
|
+
|
54
|
+
<html>
|
55
|
+
<body>
|
56
|
+
Visit our <a href="https://example.com">Website</a>
|
57
|
+
<body>
|
58
|
+
</html>
|
52
59
|
```
|
53
60
|
|
54
|
-
|
61
|
+
Becomes:
|
62
|
+
|
55
63
|
```
|
56
64
|
Visit our Website (https://example.com)
|
57
65
|
```
|
58
66
|
|
59
67
|
#### Relative Links
|
68
|
+
|
60
69
|
Since emails are wholly distinct from your web address, relative links might break.
|
61
70
|
|
62
71
|
To avoid this problem, either use the `<base>` header tag:
|
63
72
|
|
64
|
-
```
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
HTML
|
75
|
-
|
76
|
-
Ghostwriter::Writer.new(html).textify
|
73
|
+
```html
|
74
|
+
|
75
|
+
<html>
|
76
|
+
<head>
|
77
|
+
<base href="https://www.example.com">
|
78
|
+
</head>
|
79
|
+
<body>
|
80
|
+
Use the base tag to <a href="/contact">expand</a> links.
|
81
|
+
</body>
|
82
|
+
</html>
|
77
83
|
```
|
78
|
-
|
84
|
+
|
85
|
+
Becomes:
|
86
|
+
|
79
87
|
```
|
80
|
-
|
88
|
+
Use the base tag to expand (https://www.example.com/contact) links
|
81
89
|
```
|
82
90
|
|
83
|
-
Or you can use the `link_base`
|
91
|
+
Or you can use the `link_base` configuration:
|
92
|
+
|
84
93
|
```ruby
|
85
|
-
|
94
|
+
Ghostwriter::Writer.new(link_base: 'tenjin.ca').textify(html)
|
95
|
+
```
|
86
96
|
|
87
|
-
|
97
|
+
### Images
|
98
|
+
|
99
|
+
Images with alt text are converted:
|
100
|
+
|
101
|
+
```html
|
102
|
+
<img src="logo.jpg" alt="ACME Anvils" />
|
88
103
|
```
|
89
104
|
|
90
|
-
|
105
|
+
Becomes:
|
106
|
+
|
91
107
|
```
|
92
|
-
|
108
|
+
ACME Anvils (logo.jpg)
|
93
109
|
```
|
94
110
|
|
95
|
-
|
96
|
-
Tables are often used email structuring because support for more modern CSS is inconsistent.
|
111
|
+
But images lacking alt text or with a presentation ARIA role are ignored:
|
97
112
|
|
98
|
-
|
113
|
+
```html
|
114
|
+
<!-- these will just become an empty string -->
|
115
|
+
<img src="decoration.jpg">
|
116
|
+
<img src="logo.jpg" role="presentation">
|
117
|
+
```
|
99
118
|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
<base href="https://www.example.com/">
|
105
|
-
</head>
|
106
|
-
<body>
|
107
|
-
<table>
|
108
|
-
<thead>
|
109
|
-
<tr>
|
110
|
-
<th>Ship</th>
|
111
|
-
<th>Captain</th>
|
112
|
-
</tr>
|
113
|
-
</thead>
|
114
|
-
<tbody>
|
115
|
-
<tr>
|
116
|
-
<td>Enterprise</td>
|
117
|
-
<td>Jean-Luc Picard</td>
|
118
|
-
</tr>
|
119
|
-
<tr>
|
120
|
-
<td>TARDIS</td>
|
121
|
-
<td>The Doctor</td>
|
122
|
-
</tr>
|
123
|
-
<tr>
|
124
|
-
<td>Planet Express Ship</td>
|
125
|
-
<td>Turanga Leela</td>
|
126
|
-
</tr>
|
127
|
-
</tbody>
|
128
|
-
</table>
|
129
|
-
</body>
|
130
|
-
</html>
|
131
|
-
HTML
|
132
|
-
|
133
|
-
Ghostwriter::Writer.new(html).textify
|
119
|
+
And images with data URIs won't include the data portion.
|
120
|
+
|
121
|
+
```html
|
122
|
+
<img src="data:image/gif;base64,R0lGODdhIwAjAMZ/AAkMBxETEBUUDBoaExkaGCIcFx4fGCEfFCcfECkjHiUlHiglGikmFjAqFi8pJCsrJT8sCjMzLDUzJzs0GjkzLTszKTM1Mzg4MD48Mzs+O0tAIElCJ1NCGVdBHUtEMkNFQjlHTFJDOkdGPT1ISUxLRENOT1tMI01PTGdLKk1RU0hTVEtTT0NVVFRTTExYWE9YVGhVP1VZXGFYTWhaMFRcWHFYL1FdXV1dRHdZMVRgYFhgXFdiY11hY1tkX31hJltmZ2pnWnloLGFrbG9oYXlqN3NqTnBqWHxqRItvRIh0Nod0ToF2U5J4LX55Xm97e4B5aZqAQpGAdqOCOZKEYZ2FOJyEVoyKbqiOXpySbLCVcLCXaKWbdKCdfZyhi66dksGdc76fbbije7mkdLOmgq6ogrCpibyvirexisWvhs2vgsGyiLq1lce1lMC5ks28nsfBmcHDq9bAl9PDmMnFo9TGh8zIoM7Jm9vLs9nRo93QqtfSquLQpdXUs+fdterlw////ywAAAAAIwAjAAAH/oArOTo6PYaGOz08P0KMOTZCOzw7PzY/Pz2JPYSDhTSFPTSXPY0tIiIfJz05o5Q/O7A5moc6O4Q0oS8uQisXGCItwTItP5OxOrKjhzSfLzYvgz85ERQXJKcSIkZeJDqOl43StrSEKzo2LhkOGBISDw40JyIVFVEyorBCkZmwtCsrtnLQSJCAwoMFCiwoiECPAr0TjPrtECJwXLMVNARlUCBhQAEFC2SsgWPGDBs3d2RcorSD1SVGr3qskOkihoIH70DO0cOHDx48evD0KQONmQ0aORZJE3VLRYoPBRwoUCCCSx07eoL+xLNnj5UfNFry4BHuR6EcK0qkKJFhAYUE/g+cdHlz1efPrnvM2MjhQlYOWTxktXThIoUKhQoKDHBi5Y0dO0CD5smzJ46NvWJfjYW1w4WKEiWkKkgw9UYdPXTo8Mn6042bvX9pTHoFa5GKzykekP5owEidN1u6PKnzMw+QJ3ttUPr7qKUs0C5KHOyoAMMaNWrmjKlSRYscMFm+nBBUybkLSYsIl3DxwAgcKwWMzGnz5kqTK1e09AEDI0uGE8rJEgNfsuxVggoujGABF1xMoYAVc9RRhxxq5JGVHn3EEYcIGfT1igvGKLfDZyWMkMINa5QhQRNz9CQhT1n5URmHJ8Sygw2BSWLDbaCpgEFPNzxBV4QwApVhHBhg/vABZ0pJIhuCoI0wQhFlkLEGGWfQ9wZ2W6KRBhoUJKncKyK2tMOBPI6wwAxltInlG1uKcQUUV3xpwQUXACSJjbCAxgJoJShggBVtnmGGlm/M4UYcX14QQQQ1PpJjUjmsd5sKCg5gBRdkYMlGG2KwoUYWWYARxgXVnODXqmP9CWgJIESwxhJTbEHGGGbMsSWpaRRBQQQXpPKIiJOgg+BnI4AwwhxcHFHrGGN0KYYYaEhAzQX/7flIDMqx4CoIJY7QxhpY0GorXXXwkUcRj1Lg7gfMDavcCSx4BqsIHpyxRhtT1FCDEmNgF4YY1j6KZ4eXXTast9GVcAIHG2TZRhlT/qCAAg5IZIzCA+1QQ0EGKbgAG7c0pPOAAgQcwEQSZ2R5RhlYVIFEFVccAQEAAASgWEIrXEZYDDHQYAEBAQSAcxBUbCExGWVsMfMVCHSA89QCbHBDX4QRRsPURuMcQBBQYLHGHGuwoYUYVdQQxAIOBCCACVLUgDMBS7rwwgtENHDAAEYLMIAAHhABRRVYKFEDDjjU0AA9HiQhxQQOCDC1BXe/UAQVVATRwAIDDGCAAAd0EAQTTEgBBQ4IIFSBFHFPdYEIFJBAQOUE1K5AAyZgnsQME/jNwAG/e7QBFT4sYEABBiQv6ANDDLDCCwPULr0ADYyeOQcMLMAAAxNAIQUHJwckYEDn5CfvgAEKvECA3+R7nrwB2k+ggQkmaLB3++Sz3zkMIawQCAA7" alt="Data picture"/>
|
134
123
|
```
|
135
|
-
|
124
|
+
|
125
|
+
Becomes:
|
126
|
+
|
127
|
+
```
|
128
|
+
Data picture (embedded)
|
129
|
+
```
|
130
|
+
|
131
|
+
|
132
|
+
### Lists
|
133
|
+
|
134
|
+
Lists are converted, too. They are padded with newlines and are given simple markers:
|
135
|
+
|
136
|
+
```html
|
137
|
+
|
138
|
+
<ul>
|
139
|
+
<li>Planes</li>
|
140
|
+
<li>Trains</li>
|
141
|
+
<li>Automobiles</li>
|
142
|
+
</ul>
|
143
|
+
<ol>
|
144
|
+
<li>I get knocked down</li>
|
145
|
+
<li>I get up again</li>
|
146
|
+
<li>Never gonna keep me down</li>
|
147
|
+
</ol>
|
148
|
+
```
|
149
|
+
|
150
|
+
Becomes:
|
151
|
+
|
152
|
+
```
|
153
|
+
|
154
|
+
- Planes
|
155
|
+
- Trains
|
156
|
+
- Automobiles
|
157
|
+
|
158
|
+
1. I get knocked down
|
159
|
+
2. I get up again
|
160
|
+
3. Never gonna keep me down
|
161
|
+
|
162
|
+
```
|
163
|
+
|
164
|
+
### Tables
|
165
|
+
|
166
|
+
Tables are still often used in email structuring because support for more modern HTML and CSS is inconsistent. If your
|
167
|
+
table is purely presentational, mark it with `role="presentation"`. See below for details.
|
168
|
+
|
169
|
+
For real data tables, Ghostwriter tries to maintain table structure for simple tables:
|
170
|
+
|
171
|
+
```html
|
172
|
+
|
173
|
+
<table>
|
174
|
+
<thead>
|
175
|
+
<tr>
|
176
|
+
<th>Ship</th>
|
177
|
+
<th>Captain</th>
|
178
|
+
</tr>
|
179
|
+
</thead>
|
180
|
+
<tbody>
|
181
|
+
<tr>
|
182
|
+
<td>Enterprise</td>
|
183
|
+
<td>Jean-Luc Picard</td>
|
184
|
+
</tr>
|
185
|
+
<tr>
|
186
|
+
<td>TARDIS</td>
|
187
|
+
<td>The Doctor</td>
|
188
|
+
</tr>
|
189
|
+
<tr>
|
190
|
+
<td>Planet Express Ship</td>
|
191
|
+
<td>Turanga Leela</td>
|
192
|
+
</tr>
|
193
|
+
</tbody>
|
194
|
+
</table>
|
195
|
+
```
|
196
|
+
|
197
|
+
Becomes:
|
198
|
+
|
136
199
|
```
|
137
200
|
| Ship | Captain |
|
138
201
|
|---------------------|-----------------|
|
@@ -141,6 +204,30 @@ Produces:
|
|
141
204
|
| Planet Express Ship | Turanga Leela |
|
142
205
|
```
|
143
206
|
|
207
|
+
### Presentation ARIA Role
|
208
|
+
|
209
|
+
Lists and tables with `role="presentation"` will be treated as a simple container and the normal behaviour will be
|
210
|
+
suppressed.
|
211
|
+
|
212
|
+
```html
|
213
|
+
|
214
|
+
<table role="presentation">
|
215
|
+
<tr>
|
216
|
+
<td>The table is a lie</td>
|
217
|
+
</tr>
|
218
|
+
</table>
|
219
|
+
<ul role="presentation">
|
220
|
+
<li>No such list</li>
|
221
|
+
</ul>
|
222
|
+
```
|
223
|
+
|
224
|
+
Becomes:
|
225
|
+
|
226
|
+
```
|
227
|
+
The table is a lie
|
228
|
+
No such list
|
229
|
+
```
|
230
|
+
|
144
231
|
### Mail Gem Example
|
145
232
|
|
146
233
|
To use `#textify` with the [mail](https://github.com/mikel/mail) gem, just provide the text-part by pasisng the html
|
@@ -149,7 +236,8 @@ through Ghostwriter:
|
|
149
236
|
```ruby
|
150
237
|
require 'mail'
|
151
238
|
|
152
|
-
html
|
239
|
+
html = 'My email and a <a href="https://tenjin.ca">link</a>'
|
240
|
+
ghostwriter = Ghostwriter::Writer.new
|
153
241
|
|
154
242
|
Mail.deliver do
|
155
243
|
to 'bob@example.com'
|
@@ -162,7 +250,7 @@ Mail.deliver do
|
|
162
250
|
end
|
163
251
|
|
164
252
|
text_part do
|
165
|
-
body
|
253
|
+
body ghostwriter.textify(html)
|
166
254
|
end
|
167
255
|
end
|
168
256
|
|
@@ -181,19 +269,19 @@ After checking out the repo, run `bundle install` to install dependencies. Then,
|
|
181
269
|
can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
182
270
|
|
183
271
|
#### Local Install
|
184
|
-
To install this gem onto your local machine only, run
|
185
272
|
|
186
|
-
|
273
|
+
To install this gem onto your local machine only, run
|
274
|
+
|
275
|
+
`bundle exec rake install`
|
187
276
|
|
188
277
|
#### Gem Release
|
278
|
+
|
189
279
|
To release a gem to the world at large
|
190
280
|
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
196
|
-
3. Do a wee dance
|
281
|
+
1. Update the version number in `version.rb`,
|
282
|
+
2. Run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push
|
283
|
+
the `.gem` file to [rubygems.org](https://rubygems.org).
|
284
|
+
3. Do a wee dance
|
197
285
|
|
198
286
|
## License
|
199
287
|
|
data/RELEASE_NOTES.md
CHANGED
@@ -1,5 +1,22 @@
|
|
1
1
|
# Release Notes
|
2
2
|
|
3
|
+
## 1.0.0 (2021-03-21)
|
4
|
+
|
5
|
+
### Major
|
6
|
+
|
7
|
+
* Moved `link_base` parameter to constructor
|
8
|
+
* Moved input HTML parameter to `#textify`
|
9
|
+
|
10
|
+
### Minor
|
11
|
+
|
12
|
+
* Treats tables and lists with role="presentation" as simple containers
|
13
|
+
* Now handles ordered and unordered lists
|
14
|
+
* Images are now replaced with their alt text
|
15
|
+
|
16
|
+
### Bugfixes
|
17
|
+
|
18
|
+
* none
|
19
|
+
|
3
20
|
## 0.4.2 (2021-03-17)
|
4
21
|
|
5
22
|
### Major
|
data/lib/ghostwriter/version.rb
CHANGED
data/lib/ghostwriter/writer.rb
CHANGED
@@ -3,23 +3,31 @@
|
|
3
3
|
module Ghostwriter
|
4
4
|
# Main Ghostwriter converter object.
|
5
5
|
class Writer
|
6
|
-
|
7
|
-
|
6
|
+
# Creates a new ghostwriter
|
7
|
+
#
|
8
|
+
# @param [String] link_base the url to prefix relative links with
|
9
|
+
def initialize(link_base: '')
|
10
|
+
@link_base = link_base
|
11
|
+
@list_marker = '-'
|
8
12
|
end
|
9
13
|
|
10
14
|
# Strips HTML down to plain text.
|
11
15
|
#
|
12
|
-
# @param
|
13
|
-
|
14
|
-
|
16
|
+
# @param html [String] the HTML to be convert to text
|
17
|
+
#
|
18
|
+
# @return converted text
|
19
|
+
def textify(html)
|
20
|
+
doc = Nokogiri::HTML(normalize_whitespace(html).gsub('</p>', "</p>\n\n"))
|
21
|
+
|
22
|
+
doc.search('style, script').remove
|
15
23
|
|
16
|
-
doc
|
24
|
+
replace_anchors(doc)
|
25
|
+
replace_images(doc)
|
17
26
|
|
18
|
-
doc
|
19
|
-
doc.search('script').remove
|
27
|
+
simple_replace(doc, '*[role="presentation"]', "\n")
|
20
28
|
|
21
|
-
replace_anchors(doc, link_base)
|
22
29
|
replace_headers(doc)
|
30
|
+
replace_lists(doc)
|
23
31
|
replace_tables(doc)
|
24
32
|
|
25
33
|
simple_replace(doc, 'hr', "\n----------\n")
|
@@ -39,16 +47,9 @@ module Ghostwriter
|
|
39
47
|
html.gsub(/\s/, ' ').squeeze(' ')
|
40
48
|
end
|
41
49
|
|
42
|
-
def replace_anchors(doc
|
43
|
-
base = get_link_base(doc, default: link_base)
|
44
|
-
|
50
|
+
def replace_anchors(doc)
|
45
51
|
doc.search('a').each do |link_node|
|
46
|
-
|
47
|
-
href = URI(link_node['href'])
|
48
|
-
href = base + href.to_s unless href.absolute?
|
49
|
-
rescue URI::InvalidURIError
|
50
|
-
href = link_node['href'].gsub(/^(tel|mailto):/, '').strip
|
51
|
-
end
|
52
|
+
href = get_link_target(link_node, get_link_base(doc))
|
52
53
|
|
53
54
|
link_node.inner_html = if link_matches(href, link_node.inner_html)
|
54
55
|
href.to_s
|
@@ -62,16 +63,56 @@ module Ghostwriter
|
|
62
63
|
first.to_s.gsub(%r{^https?://}, '').chomp('/') == second.gsub(%r{^https?://}, '').chomp('/')
|
63
64
|
end
|
64
65
|
|
65
|
-
def get_link_base(doc
|
66
|
+
def get_link_base(doc)
|
66
67
|
# <base> node is unique by W3C spec
|
67
68
|
base_node = doc.search('base').first
|
68
69
|
|
69
|
-
base_node ? base_node['href'] :
|
70
|
+
base_node ? base_node['href'] : @link_base
|
71
|
+
end
|
72
|
+
|
73
|
+
def get_link_target(link_node, base)
|
74
|
+
href = URI(link_node['href'])
|
75
|
+
if href.absolute?
|
76
|
+
href
|
77
|
+
else
|
78
|
+
base + href.to_s
|
79
|
+
end
|
80
|
+
rescue URI::InvalidURIError
|
81
|
+
link_node['href'].gsub(/^(tel|mailto):/, '').strip
|
70
82
|
end
|
71
83
|
|
72
84
|
def replace_headers(doc)
|
73
85
|
doc.search('header, h1, h2, h3, h4, h5, h6').each do |node|
|
74
|
-
node.inner_html = "
|
86
|
+
node.inner_html = "-- #{ node.inner_html } --\n".squeeze(' ')
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def replace_images(doc)
|
91
|
+
doc.search('img[role=presentation]').remove
|
92
|
+
|
93
|
+
doc.search('img').each do |img_node|
|
94
|
+
src = img_node['src']
|
95
|
+
alt = img_node['alt']
|
96
|
+
|
97
|
+
src = 'embedded' if src.start_with? 'data:'
|
98
|
+
|
99
|
+
img_node.replace("#{ alt } (#{ src })") unless alt.nil? || alt.empty?
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def replace_lists(doc)
|
104
|
+
doc.search('ul, ol').each do |list_node|
|
105
|
+
list_node.search('./li').each_with_index do |list_item, i|
|
106
|
+
marker = if list_node.node_name == 'ol'
|
107
|
+
"#{ i + 1 }."
|
108
|
+
else
|
109
|
+
@list_marker
|
110
|
+
end
|
111
|
+
|
112
|
+
list_item.inner_html = "#{ marker } #{ list_item.inner_html }\n".squeeze(' ')
|
113
|
+
end
|
114
|
+
|
115
|
+
list_node.replace("\n#{ list_node.inner_html }\n")
|
75
116
|
end
|
76
117
|
end
|
77
118
|
|
@@ -120,7 +161,7 @@ module Ghostwriter
|
|
120
161
|
|
121
162
|
def simple_replace(doc, tag, replacement)
|
122
163
|
doc.search(tag).each do |node|
|
123
|
-
node.replace(replacement)
|
164
|
+
node.replace(node.inner_html + replacement)
|
124
165
|
end
|
125
166
|
end
|
126
167
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ghostwriter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Robin Miller
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-03-
|
11
|
+
date: 2021-03-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: nokogiri
|