article_json 0.3.7 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +31 -0
- data/README.md +118 -67
- data/bin/article_json_export_amp.rb +15 -0
- data/bin/article_json_export_apple_news.rb +15 -0
- data/bin/article_json_export_facebook.rb +16 -0
- data/bin/article_json_export_html.rb +1 -0
- data/bin/article_json_export_plain_text.rb +15 -0
- data/bin/article_json_parse_google_doc.rb +1 -0
- data/bin/check_google_doc_export.rb +41 -0
- data/bin/update_oembed_request-stubs.sh +11 -0
- data/bin/update_reference_document.sh +16 -0
- data/lib/article_json/article.rb +22 -2
- data/lib/article_json/configuration.rb +2 -1
- data/lib/article_json/elements/base.rb +0 -1
- data/lib/article_json/elements/image.rb +7 -3
- data/lib/article_json/export/amp/elements/embed.rb +1 -1
- data/lib/article_json/export/apple_news/elements/base.rb +53 -0
- data/lib/article_json/export/apple_news/elements/embed.rb +130 -0
- data/lib/article_json/export/apple_news/elements/heading.rb +32 -0
- data/lib/article_json/export/apple_news/elements/image.rb +58 -0
- data/lib/article_json/export/apple_news/elements/list.rb +67 -0
- data/lib/article_json/export/apple_news/elements/paragraph.rb +36 -0
- data/lib/article_json/export/apple_news/elements/quote.rb +60 -0
- data/lib/article_json/export/apple_news/elements/text.rb +42 -0
- data/lib/article_json/export/apple_news/elements/text_box.rb +51 -0
- data/lib/article_json/export/apple_news/exporter.rb +37 -0
- data/lib/article_json/export/common/html/elements/image.rb +1 -1
- data/lib/article_json/import/google_doc/html/image_parser.rb +24 -3
- data/lib/article_json/import/google_doc/html/node_analyzer.rb +11 -1
- data/lib/article_json/import/google_doc/html/parser.rb +6 -1
- data/lib/article_json/utils/o_embed_resolver/facebook_video.rb +17 -1
- data/lib/article_json/utils/o_embed_resolver/youtube_video.rb +1 -1
- data/lib/article_json/version.rb +1 -1
- data/lib/article_json.rb +11 -0
- metadata +37 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 561ba1f1fff25cba3e32eea10bdff57757ab6776a688bc78f85ec4eafeb62b32
|
4
|
+
data.tar.gz: e72e2425f7008d24be098be9024a27f493c2f13c99577ec71d7dda953564bcef
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 14e75d7a01ad409337b79b98075063807de0d18dd911980c7ef816668ddf4adc6f02211fb36ed54a530962bf0839628b217cfd6c849ff6153575c9e9274500b2
|
7
|
+
data.tar.gz: a2a1eac1de2d0d8b0379c1d1bbc85a7af99e33c44ebdc544d88de7983597be878e59c9bc90a2a1a4958b4dcb1ea26d4bc5817fb6944e04e02224d1af8fd52353
|
data/CHANGELOG.md
CHANGED
@@ -1,4 +1,35 @@
|
|
1
1
|
# Changelog
|
2
|
+
## 0.4.0 - 2024/01/17
|
3
|
+
In this fourth release we **added support for Apple News**:
|
4
|
+
**New**:
|
5
|
+
Support for Apple News Format, specifically the following elements:
|
6
|
+
- text
|
7
|
+
- text boxes
|
8
|
+
- lists
|
9
|
+
- pull quotes
|
10
|
+
- image
|
11
|
+
- embed objects (posts from X etc.)
|
12
|
+
- image captions for images and embed objects
|
13
|
+
- video
|
14
|
+
Support for Ruby 3.2
|
15
|
+
|
16
|
+
**Removes**:
|
17
|
+
Support for Ruby 2.3
|
18
|
+
|
19
|
+
**Refactoring**:
|
20
|
+
- Rubocop autocorrections
|
21
|
+
|
22
|
+
**Fix:**
|
23
|
+
- Fix failing rspec tests
|
24
|
+
|
25
|
+
|
26
|
+
## 0.3.8 - 2020/7/31
|
27
|
+
- **Improvements:**
|
28
|
+
- Add a script to update oembed stubs fixtures.
|
29
|
+
- Support for `alt` attribute in images.
|
30
|
+
|
31
|
+
- **Fix:** Fix a bug when using the `[image-link-to: ]` tag.
|
32
|
+
|
2
33
|
## 0.3.7 - 2019/8/21
|
3
34
|
- **Fix:** Only use https for soundcloud oembed api
|
4
35
|
|
data/README.md
CHANGED
@@ -1,10 +1,25 @@
|
|
1
1
|
# article_json
|
2
|
-
|
2
|
+
The `article_json` gem is a Ruby library designed to simplify the conversion and manipulation of structured articles in various formats, allowing easy importing, manipulation and export of content across different platforms and environments.
|
3
|
+
|
4
|
+
It takes an article from a Google Doc and creates a JSON version of it.
|
5
|
+
|
6
|
+
From there it can export the article:
|
7
|
+
- as HTML
|
8
|
+
- as AMP
|
9
|
+
- as Apple News Format (ANF)
|
10
|
+
- as Facebook Instant Article HTML
|
11
|
+
- as plain text
|
12
|
+
- as JSON
|
13
|
+
|
14
|
+
It also provides functionalities to parse content from Google Document HTML exports and initialize articles from JSON strings or already parsed JSON.
|
15
|
+
|
16
|
+
---
|
3
17
|
|
4
18
|
## Status
|
5
19
|
[![Gem Version](https://badge.fury.io/rb/article_json.svg)](https://badge.fury.io/rb/article_json)
|
6
|
-
[![
|
7
|
-
[![
|
20
|
+
[![Check Google Doc](https://github.com/Devex/article_json/workflows/Check%20Google%20Doc/badge.svg)](https://github.com/Devex/article_json/actions/workflows/check-google-doc.yml)
|
21
|
+
[![RSpec](https://github.com/Devex/article_json/workflows/rspec/badge.svg)](https://github.com/Devex/article_json/actions/workflows/rspec.yml)
|
22
|
+
[![Code Climate](https://codeclimate.com/github/Devex/article_json/badges/gpa.svg)](https://codeclimate.com/github/Devex/article_json?event=push)
|
8
23
|
[![Coverage Status](https://coveralls.io/repos/github/Devex/article_json/badge.svg?branch=master)](https://coveralls.io/github/Devex/article_json?branch=master)
|
9
24
|
|
10
25
|
## Usage
|
@@ -32,6 +47,9 @@ puts article.to_amp
|
|
32
47
|
# get javascript libraries needed for the AMP article
|
33
48
|
puts article.amp_exporter.amp_libraries
|
34
49
|
|
50
|
+
# export article as Apple News Format (ANF)
|
51
|
+
puts article.to_apple_news
|
52
|
+
|
35
53
|
# export article as Facebook Instant Article HTML
|
36
54
|
puts article.to_facebook_instant_article
|
37
55
|
|
@@ -43,20 +61,47 @@ puts article.to_json
|
|
43
61
|
```
|
44
62
|
|
45
63
|
### CLI
|
46
|
-
To load, parse and
|
47
|
-
run the following:
|
64
|
+
To load, parse and export the latest (amp/ apple news/ facebook/ html) version of the reference document, run the following:
|
48
65
|
|
49
|
-
```
|
66
|
+
```bash
|
50
67
|
$ export DOC_ID=1E4lncZE2jDkbE34eDyYQmXKA9O26BHUiwguz4S9qyE8
|
51
68
|
$ ./bin/article_json_export_google_doc.rb $DOC_ID \
|
52
69
|
| ./bin/article_json_parse_google_doc.rb \
|
53
70
|
| ./bin/article_json_export_html.rb
|
71
|
+
## OR
|
72
|
+
# | ./bin/article_json_export_amp.rb
|
73
|
+
# | ./bin/article_json_export_apple_news.rb
|
74
|
+
# | ./bin/article_json_export_facebook.rb
|
75
|
+
# | ./bin/article_json_export_plain_text.rb
|
76
|
+
```
|
77
|
+
|
78
|
+
Alternatively, you can concatenate your command line commands, like so:
|
79
|
+
```bash
|
80
|
+
$ ./bin/article_json_export_google_doc.rb $DOC_ID > test_ref_doc.html
|
81
|
+
$ cat test_ref_doc.html | bin/article_json_parse_google_doc.rb > \
|
82
|
+
test_ref_doc_parsed_apple.json
|
83
|
+
$ cat test_ref_doc_parsed_apple.json | bin/article_json_export_apple_news.rb > \
|
84
|
+
test_ref_doc_exported_apple.json
|
85
|
+
```
|
86
|
+
|
87
|
+
You can also update _all_ the different exported versions of the reference document _(amp, apple_news, facebook, google_doc, html and plain_text)_ by running the following command:
|
88
|
+
|
89
|
+
```
|
90
|
+
$ ./bin/update_reference_document.sh
|
91
|
+
```
|
92
|
+
|
93
|
+
When running the tests, we use some fixtures to mock the responses for oembed requests, but these may change over time.
|
94
|
+
|
95
|
+
To update them, run:
|
96
|
+
|
97
|
+
```
|
98
|
+
$ ./bin/update_oembed_request-stubs.sh
|
54
99
|
```
|
55
100
|
|
56
101
|
### Configuration
|
57
|
-
|
58
|
-
|
59
|
-
available setting:
|
102
|
+
Some configuration options allow a more tailored usage of the `article_json` gem.
|
103
|
+
|
104
|
+
The following code snippet gives an example for every available setting:
|
60
105
|
|
61
106
|
```ruby
|
62
107
|
ArticleJSON.configure do |config|
|
@@ -69,48 +114,63 @@ ArticleJSON.configure do |config|
|
|
69
114
|
:html,
|
70
115
|
advertisement: ArticleJSON::Export::HTML::Elements::Advertisement
|
71
116
|
)
|
72
|
-
|
117
|
+
|
73
118
|
# You can also overwrite existing exporters:
|
74
119
|
config.register_element_exporters(
|
75
120
|
:html,
|
76
121
|
image: ArticleJSON::Export::HTML::Elements::ScaledImage
|
77
122
|
)
|
78
|
-
|
123
|
+
|
79
124
|
# And you can define multiple custom exporters:
|
80
125
|
config.register_element_exporters(
|
81
126
|
:html,
|
82
127
|
advertisement: ArticleJSON::Export::HTML::Elements::Advertisement,
|
83
128
|
image: ArticleJSON::Export::HTML::Elements::ScaledImage
|
84
129
|
)
|
85
|
-
|
86
|
-
# It works the same way for custom AMP, FacebookInstantArticle, or
|
87
|
-
#
|
130
|
+
|
131
|
+
# It works the same way for custom AMP, FacebookInstantArticle, or PlainText
|
132
|
+
# exporters:
|
88
133
|
config.register_element_exporters(
|
89
134
|
:amp, # Or change this for `:facebook_instant_article` or `:plain_text`
|
90
135
|
image: ArticleJSON::Export::AMP::Elements::ScaledImage
|
91
|
-
)
|
136
|
+
)
|
137
|
+
end
|
138
|
+
```
|
139
|
+
|
140
|
+
### Facebook Oembed
|
141
|
+
Facebook deprecated its public endpoints for embeddable Facebook content in 2020 (See https://developers.facebook.com/docs/plugins/oembed-legacy for more info).
|
142
|
+
|
143
|
+
You now need to use a Facebook token to access the new oembed endpoints. You can configure the gem to use this token so:
|
144
|
+
|
145
|
+
``` ruby
|
146
|
+
ArticleJSON.configure do |config|
|
147
|
+
# 'token' being the combination of the app-id and the access token joined
|
148
|
+
# with the pipe symbol (`|`)
|
149
|
+
config.facebook_token = 'token'
|
92
150
|
end
|
93
|
-
```
|
151
|
+
```
|
152
|
+
|
153
|
+
Find more info about the access token [here](https://developers.facebook.com/docs/plugins/oembed#access-tokens).
|
94
154
|
|
95
155
|
## Format
|
96
|
-
A full example of the format can be found in the test fixtures
|
97
|
-
[Parsed Reference Document](https://github.com/Devex/article_json/blob/master/spec/fixtures/reference_document_parsed.json)
|
156
|
+
A [full example of the format](https://github.com/Devex/article_json/blob/master/spec/fixtures/reference_document_parsed.json) can be found in the test fixtures.
|
98
157
|
|
99
158
|
## Import
|
100
159
|
### Google Document Parser
|
101
|
-
This [
|
102
|
-
lists contains all supported formatting along with some descriptions.
|
160
|
+
This [reference document](https://docs.google.com/document/d/1E4lncZE2jDkbE34eDyYQmXKA9O26BHUiwguz4S9qyE8/editusp=sharing) contains all the supported formatting along with some descriptions.
|
103
161
|
|
104
162
|
## Add custom elements
|
105
|
-
Sometimes you might want to place additional elements into the article, like e.g. advertisements.
|
106
|
-
|
107
|
-
Each element that is added this way will directly get placed in between paragraphs of the article.
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
You can pass any type of element into this method.
|
113
|
-
|
163
|
+
Sometimes you might want to place additional elements into the article, like e.g. advertisements. `article_json` supports this via `article.place_additional_elements`, which accepts an array of elements that you can define in your code.
|
164
|
+
|
165
|
+
Each element that is added this way will directly get placed in between paragraphs of the article. The method ensures that an additional element is never added before or after any node other than paragraphs (e.g. an image). The elements are added in the order you pass them into the method.
|
166
|
+
|
167
|
+
If the article does not have enough space to place all the provided elements, they will be placed after the last
|
168
|
+
element in the article.
|
169
|
+
|
170
|
+
You can pass any type of element into this method.
|
171
|
+
|
172
|
+
If the objects you pass in are instances of elements defined within this gem (e.g. `ArticleJSON::Elements::Image`), you won't have to do anything else to render them.
|
173
|
+
|
114
174
|
If you pass in an instance of a custom class (e.g. `MyAdvertisement`), make sure to register an exporter for this type (check the _Configuration_ section for more details).
|
115
175
|
|
116
176
|
Example using only existing elements:
|
@@ -119,45 +179,45 @@ Example using only existing elements:
|
|
119
179
|
article = ArticleJSON::Article.from_hash(parsed_json)
|
120
180
|
|
121
181
|
# Within your code, create additional elements you would like to add
|
122
|
-
image_advertisement =
|
123
|
-
ArticleJSON::Elements::Image.new(source_url: 'https://robohash.org/great-ad',
|
182
|
+
image_advertisement =
|
183
|
+
ArticleJSON::Elements::Image.new(source_url: 'https://robohash.org/great-ad',
|
124
184
|
caption: ArticleJSON::Elements::Text.new(
|
125
185
|
content: 'Buy more robots!',
|
126
186
|
href: '/robot-sale'
|
127
187
|
))
|
128
|
-
text_box_similar_articles =
|
188
|
+
text_box_similar_articles =
|
129
189
|
ArticleJSON::Elements::TextBox.new(content: [
|
130
|
-
ArticleJSON::Elements::Heading.new(level: 3, content: 'Read more...'),
|
190
|
+
ArticleJSON::Elements::Heading.new(level: 3, content: 'Read more...'),
|
131
191
|
ArticleJSON::Elements::List.new(content: [
|
132
192
|
ArticleJSON::Elements::Paragraph(content: [
|
133
|
-
ArticleJSON::Elements::Text.new(content: 'Very similar article',
|
193
|
+
ArticleJSON::Elements::Text.new(content: 'Very similar article',
|
134
194
|
href: '/news/123'),
|
135
195
|
]),
|
136
196
|
ArticleJSON::Elements::Paragraph(content: [
|
137
|
-
ArticleJSON::Elements::Text.new(content: 'Great article!',
|
197
|
+
ArticleJSON::Elements::Text.new(content: 'Great article!',
|
138
198
|
href: '/news/42'),
|
139
199
|
]),
|
140
|
-
]),
|
200
|
+
]),
|
141
201
|
])
|
142
202
|
|
143
203
|
# Add these elements to the article
|
144
|
-
article.place_additional_elements([image_advertisement,
|
204
|
+
article.place_additional_elements([image_advertisement,
|
145
205
|
text_box_similar_articles])
|
146
|
-
|
147
|
-
# Export the article to the different formats as you would normally do
|
206
|
+
|
207
|
+
# Export the article to the different formats as you would normally do
|
148
208
|
article.to_html # this will now include the custom elements
|
149
|
-
```
|
209
|
+
```
|
150
210
|
|
151
211
|
Example with custom advertisement elements:
|
152
212
|
```ruby
|
153
213
|
# Define your custom element class
|
154
214
|
class MyAdvertisement
|
155
215
|
attr_reader :url
|
156
|
-
|
216
|
+
|
157
217
|
def initialize(url:)
|
158
218
|
@url = url
|
159
219
|
end
|
160
|
-
|
220
|
+
|
161
221
|
def type
|
162
222
|
:my_advertisement
|
163
223
|
end
|
@@ -165,9 +225,9 @@ end
|
|
165
225
|
|
166
226
|
# Define an exporter for your class, we only use HTML in this example but this
|
167
227
|
# would work similarly for AMP or other formats
|
168
|
-
class MyAdvertisementExporter <
|
169
|
-
ArticleJSON::Export::HTML::Elements::Base
|
170
|
-
|
228
|
+
class MyAdvertisementExporter <
|
229
|
+
ArticleJSON::Export::HTML::Elements::Base
|
230
|
+
|
171
231
|
# Needs to implement the `#export` method
|
172
232
|
def export
|
173
233
|
create_element(:iframe, src: @element.url)
|
@@ -194,35 +254,26 @@ article.to_html
|
|
194
254
|
|
195
255
|
## Export
|
196
256
|
### HTML
|
197
|
-
The HTML exporter generates
|
198
|
-
the HTML export for the parsed reference document can be found
|
199
|
-
[here](https://github.com/Devex/article_json/blob/master/spec/fixtures/reference_document_exported.html).
|
257
|
+
The HTML exporter generates an HTML string for a list of elements. An example of the HTML export for the parsed reference document can be found [here](https://github.com/Devex/article_json/blob/master/spec/fixtures/reference_document_exported.html).
|
200
258
|
|
201
259
|
### AMP
|
202
|
-
The AMP exporter generates an AMP HTML representation of the elements.
|
260
|
+
The AMP exporter generates an AMP HTML representation of the elements.
|
203
261
|
|
204
262
|
AMP uses [custom HTML tags](https://www.ampproject.org/docs/reference/components), some of which require additional Javascript libraries.
|
205
|
-
If you have an `article` (see code example in _Usage_ section), you can get a list of the custom tags required by this article by calling `article.amp_exporter.custom_element_tags` and by calling `article.amp_exporter.amp_libraries` you get a list of `<script>` tags that can directly be included on your page to render the AMP article.
|
206
263
|
|
207
|
-
|
208
|
-
|
209
|
-
[here](https://github.com/Devex/article_json/blob/master/spec/fixtures/reference_document_exported.amp.html).
|
264
|
+
If you have an `article` (see code example in _Usage_ section), you can get a list of the custom tags required by this article by calling `article.amp_exporter.custom_element_tags` and calling `article.amp_exporter.amp_libraries` gives a list of `<script>` tags that can directly be included on your page to render the AMP article.
|
265
|
+
|
266
|
+
An example of the AMP HTML export for the parsed reference document can be found [here](https://github.com/Devex/article_json/blob/master/spec/fixtures/reference_document_exported.amp.html).
|
210
267
|
|
211
268
|
### Facebook Instant Articles
|
212
|
-
The `FacebookInstantArticle` exporter generates a custom HTML string for a list
|
213
|
-
of elements. An example of the Facebook Instant Article export for the parsed
|
214
|
-
reference document can be found
|
215
|
-
[here](https://github.com/Devex/article_json/blob/master/spec/fixtures/reference_document_exported.html).
|
269
|
+
The `FacebookInstantArticle` exporter generates a custom HTML string for a list of elements. An example of the Facebook Instant Article export for the parsed reference document can be found [here](https://github.com/Devex/article_json/blob/master/spec/fixtures/reference_document_exported.html).
|
216
270
|
|
217
|
-
To learn more about the Facebook Instant Article HTML format see have a look at
|
218
|
-
the [Facebook Developer Documentation](https://developers.facebook.com/docs/instant-articles/guides/format-overview).
|
271
|
+
To learn more about the Facebook Instant Article HTML format see have a look at the [Facebook Developer Documentation](https://developers.facebook.com/docs/instant-articles/guides/format-overview).
|
219
272
|
|
220
273
|
### Plain Text
|
221
|
-
As the name suggests, this exporter generates a plain text version of the article.
|
222
|
-
Rich text elements like images, embeds or even text boxes are not being rendered.
|
274
|
+
As the name suggests, this exporter generates a plain text version of the article. Rich text elements like images, embeds or even text boxes are not being rendered.
|
223
275
|
|
224
|
-
The reference document rendered as plain text can be found
|
225
|
-
[here](https://github.com/Devex/article_json/blob/master/spec/fixtures/reference_document_exported.txt).
|
276
|
+
The reference document rendered as plain text can be found [here](https://github.com/Devex/article_json/blob/master/spec/fixtures/reference_document_exported.txt).
|
226
277
|
|
227
278
|
Usage:
|
228
279
|
```ruby
|
@@ -230,22 +281,22 @@ Usage:
|
|
230
281
|
article = ArticleJSON::Article.from_hash(parsed_json)
|
231
282
|
|
232
283
|
# Then simply call `#to_plain_text` on it
|
233
|
-
article.to_plain_text
|
284
|
+
article.to_plain_text
|
234
285
|
```
|
235
286
|
|
236
287
|
## Contributing
|
237
288
|
- Fork this repository
|
238
|
-
- Implement your feature or fix including
|
289
|
+
- Implement your feature or fix including tests
|
239
290
|
- Update the [change log](CHANGELOG.md)
|
240
291
|
- Commit your changes with a meaningful commit message
|
241
292
|
- Create a pull request
|
242
293
|
|
243
294
|
Thank you!
|
244
295
|
|
245
|
-
See the
|
296
|
+
See the
|
246
297
|
[list of contributors](https://github.com/Devex/article_json/contributors).
|
247
298
|
|
248
|
-
|
299
|
+
## Tests
|
249
300
|
For the whole test suite, run `bundle exec rspec`.
|
250
301
|
|
251
302
|
For individual tests, run `bundle exec rspec spec/article_json/version_spec.rb`.
|
@@ -0,0 +1,15 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
4
|
+
#
|
5
|
+
# Simple script to read a JSON document and export it to AMP.
|
6
|
+
#
|
7
|
+
# Usage:
|
8
|
+
#
|
9
|
+
# ./bin/article_json_export_amp.rb < my_document.json
|
10
|
+
#
|
11
|
+
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
12
|
+
|
13
|
+
require 'bundler/setup'
|
14
|
+
require_relative '../lib/article_json'
|
15
|
+
puts ArticleJSON::Article.from_json(ARGF.read).to_amp
|
@@ -0,0 +1,15 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
4
|
+
#
|
5
|
+
# Simple script to read a JSON document and export it to Apple News.
|
6
|
+
#
|
7
|
+
# Usage:
|
8
|
+
#
|
9
|
+
# ./bin/article_json_export_apple_news.rb < my_document.json
|
10
|
+
#
|
11
|
+
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
12
|
+
|
13
|
+
require 'bundler/setup'
|
14
|
+
require_relative '../lib/article_json'
|
15
|
+
puts ArticleJSON::Article.from_json(ARGF.read).to_apple_news
|
@@ -0,0 +1,16 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
4
|
+
#
|
5
|
+
# Simple script to read a JSON document and export it to Facebook Instant
|
6
|
+
# Article.
|
7
|
+
#
|
8
|
+
# Usage:
|
9
|
+
#
|
10
|
+
# ./bin/article_json_export_facebook.rb < my_document.json
|
11
|
+
#
|
12
|
+
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
13
|
+
|
14
|
+
require 'bundler/setup'
|
15
|
+
require_relative '../lib/article_json'
|
16
|
+
puts ArticleJSON::Article.from_json(ARGF.read).to_facebook_instant_article
|
@@ -0,0 +1,15 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
4
|
+
#
|
5
|
+
# Simple script to read a JSON document and export it to plain text.
|
6
|
+
#
|
7
|
+
# Usage:
|
8
|
+
#
|
9
|
+
# ./bin/article_json_export_plain_text.rb < my_document.json
|
10
|
+
#
|
11
|
+
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
12
|
+
|
13
|
+
require 'bundler/setup'
|
14
|
+
require_relative '../lib/article_json'
|
15
|
+
puts ArticleJSON::Article.from_json(ARGF.read).to_plain_text
|
@@ -0,0 +1,41 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
4
|
+
#
|
5
|
+
# Script to check that google doc export works as expected.
|
6
|
+
#
|
7
|
+
# Usage:
|
8
|
+
#
|
9
|
+
# ./bin/check_google_doc_export.rb
|
10
|
+
#
|
11
|
+
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
|
12
|
+
|
13
|
+
require 'bundler/setup'
|
14
|
+
require 'net/http'
|
15
|
+
require 'uri'
|
16
|
+
require_relative '../lib/article_json'
|
17
|
+
|
18
|
+
doc_id = '1E4lncZE2jDkbE34eDyYQmXKA9O26BHUiwguz4S9qyE8'
|
19
|
+
url =
|
20
|
+
"https://docs.google.com/feeds/download/documents/export/Export?id=#{doc_id}&exportFormat=html"
|
21
|
+
parsed_exported_doc = JSON.parse(
|
22
|
+
ArticleJSON::Article
|
23
|
+
.from_google_doc_html(Net::HTTP.get(URI.parse(url)))
|
24
|
+
.to_json
|
25
|
+
)
|
26
|
+
parsed_expected_doc = JSON.parse(File.read('spec/fixtures/reference_document_parsed.json'))
|
27
|
+
|
28
|
+
# `source_url` (for hosted images) is dynamic, so we need to remove it from the comparison`
|
29
|
+
def nullify_source_url(hash)
|
30
|
+
hash['content'].each { |element| element['source_url'] = nil if element['source_url'] }
|
31
|
+
hash
|
32
|
+
end
|
33
|
+
|
34
|
+
parsed_exported_doc = nullify_source_url(parsed_exported_doc)
|
35
|
+
parsed_expected_doc = nullify_source_url(parsed_expected_doc)
|
36
|
+
|
37
|
+
if parsed_exported_doc != parsed_expected_doc
|
38
|
+
raise StandardError, "Google doc export doesn't work as expected"
|
39
|
+
end
|
40
|
+
|
41
|
+
puts 'Google doc export worked as expected'
|
@@ -0,0 +1,11 @@
|
|
1
|
+
#!/usr/bin/env sh
|
2
|
+
|
3
|
+
curl -X GET "https://vimeo.com/api/oembed.json?url=https://vimeo.com/42315417" | jq > spec/fixtures/vimeo_video_oembed.json
|
4
|
+
|
5
|
+
curl -X GET "https://www.youtube.com/oembed?format=json&url=https://www.youtube.com/watch?v=_ZG8HBuDjgc" | jq > spec/fixtures/youtube_video_oembed.json
|
6
|
+
|
7
|
+
curl -X GET "https://www.slideshare.net/api/oembed/2?format=json&url=https://www.slideshare.net/Devex/the-best-global-development-quotes-of-2012" | jq > spec/fixtures/slideshare_oembed.json
|
8
|
+
|
9
|
+
curl -X GET "https://api.twitter.com/1/statuses/oembed.json?align=center&url=https://twitter.com/d3v3x/status/554608639030599681" | jq > spec/fixtures/tweet_oembed.json
|
10
|
+
|
11
|
+
curl -X GET 'https://soundcloud.com/oembed?format=json&url=https://soundcloud.com/rich-the-kid/plug-walk-1' | jq > spec/fixtures/soundcloud_oembed.json
|
@@ -7,6 +7,10 @@ DOC_ID="1E4lncZE2jDkbE34eDyYQmXKA9O26BHUiwguz4S9qyE8"
|
|
7
7
|
SOURCE_HTML_FILE="spec/fixtures/reference_document.html"
|
8
8
|
JSON_FILE="spec/fixtures/reference_document_parsed.json"
|
9
9
|
HTML_EXPORT_FILE="spec/fixtures/reference_document_exported.html"
|
10
|
+
AMP_EXPORT_FILE="spec/fixtures/reference_document_exported.amp.html"
|
11
|
+
FACEBOOK_EXPORT_FILE="spec/fixtures/reference_document_exported.facebook.html"
|
12
|
+
APPLE_NEWS_EXPORT_FILE="spec/fixtures/reference_document_exported.apple_news.json"
|
13
|
+
PLAIN_TEXT_EXPORT_FILE="spec/fixtures/reference_document_exported.txt"
|
10
14
|
|
11
15
|
# export the google doc to HTML
|
12
16
|
./bin/article_json_export_google_doc.rb ${DOC_ID} > ${SOURCE_HTML_FILE}
|
@@ -16,3 +20,15 @@ HTML_EXPORT_FILE="spec/fixtures/reference_document_exported.html"
|
|
16
20
|
|
17
21
|
# convert the JSON export to HTML
|
18
22
|
./bin/article_json_export_html.rb < ${JSON_FILE} > ${HTML_EXPORT_FILE}
|
23
|
+
|
24
|
+
# convert the JSON export to AMP
|
25
|
+
./bin/article_json_export_amp.rb < ${JSON_FILE} > ${AMP_EXPORT_FILE}
|
26
|
+
|
27
|
+
# convert the JSON export to Facebook Instant Article
|
28
|
+
./bin/article_json_export_facebook.rb < ${JSON_FILE} > ${FACEBOOK_EXPORT_FILE}
|
29
|
+
|
30
|
+
# convert the JSON export to Apple News
|
31
|
+
./bin/article_json_export_apple_news.rb < ${JSON_FILE} > ${APPLE_NEWS_EXPORT_FILE}
|
32
|
+
|
33
|
+
# convert the JSON export to plain text
|
34
|
+
./bin/article_json_export_plain_text.rb < ${JSON_FILE} > ${PLAIN_TEXT_EXPORT_FILE}
|
data/lib/article_json/article.rb
CHANGED
@@ -14,7 +14,7 @@ module ArticleJSON
|
|
14
14
|
def elements
|
15
15
|
@elements ||= begin
|
16
16
|
if @additional_elements.any?
|
17
|
-
|
17
|
+
@additional_element_placer_class
|
18
18
|
.new(@article_elements, @additional_elements)
|
19
19
|
.merge_elements
|
20
20
|
else
|
@@ -62,6 +62,18 @@ module ArticleJSON
|
|
62
62
|
amp_exporter.html
|
63
63
|
end
|
64
64
|
|
65
|
+
# Exporter instance for AppleNews
|
66
|
+
# @return [ArticleJSON::Export::AppleNews::Exporter]
|
67
|
+
def apple_news_exporter
|
68
|
+
ArticleJSON::Export::AppleNews::Exporter.new(elements)
|
69
|
+
end
|
70
|
+
|
71
|
+
# AppleNews export of the article
|
72
|
+
# @return [String]
|
73
|
+
def to_apple_news
|
74
|
+
apple_news_exporter.to_json
|
75
|
+
end
|
76
|
+
|
65
77
|
# Exporter instance for FacebookInstantArticle
|
66
78
|
# @return [ArticleJSON::Export::FacebookInstantArticle::Exporter]
|
67
79
|
def facebook_instant_article_exporter
|
@@ -91,10 +103,18 @@ module ArticleJSON
|
|
91
103
|
# article. If the method is called multiple times, the order of additional
|
92
104
|
# elements is maintained.
|
93
105
|
# @param [Object] additional_elements
|
94
|
-
|
106
|
+
# @param [Class<#merge_elements>] with - The passes class's `#initialize` method needs
|
107
|
+
# to accept two lists of elements. See
|
108
|
+
# `ArticleJSON::Utils::AdditionalElementPlacer`
|
109
|
+
# for reference.
|
110
|
+
def place_additional_elements(
|
111
|
+
additional_elements,
|
112
|
+
with: ArticleJSON::Utils::AdditionalElementPlacer
|
113
|
+
)
|
95
114
|
# Reset the `#elements` method memoization
|
96
115
|
@elements = nil
|
97
116
|
@additional_elements.concat(additional_elements)
|
117
|
+
@additional_element_placer_class = with
|
98
118
|
end
|
99
119
|
|
100
120
|
class << self
|
@@ -14,10 +14,11 @@ module ArticleJSON
|
|
14
14
|
end
|
15
15
|
|
16
16
|
class Configuration
|
17
|
-
attr_accessor :oembed_user_agent
|
17
|
+
attr_accessor :oembed_user_agent, :facebook_token
|
18
18
|
|
19
19
|
def initialize
|
20
20
|
@oembed_user_agent = nil
|
21
|
+
@facebook_token = nil
|
21
22
|
@custom_element_exporters = {}
|
22
23
|
end
|
23
24
|
|
@@ -1,18 +1,20 @@
|
|
1
1
|
module ArticleJSON
|
2
2
|
module Elements
|
3
3
|
class Image < Base
|
4
|
-
attr_reader :source_url, :caption, :float, :href
|
4
|
+
attr_reader :source_url, :caption, :float, :href, :alt
|
5
5
|
|
6
6
|
# @param [String] source_url
|
7
7
|
# @param [Array[ArticleJSON::Elements::Text]] caption
|
8
8
|
# @param [Symbol] float
|
9
9
|
# @param [String] href
|
10
|
-
|
10
|
+
# @param [String] alt
|
11
|
+
def initialize(source_url:, caption:, float: nil, href: nil, alt: nil)
|
11
12
|
@type = :image
|
12
13
|
@source_url = source_url
|
13
14
|
@caption = caption
|
14
15
|
@float = float
|
15
16
|
@href = href
|
17
|
+
@alt = alt
|
16
18
|
end
|
17
19
|
|
18
20
|
# Hash representation of this image element
|
@@ -24,6 +26,7 @@ module ArticleJSON
|
|
24
26
|
float: float,
|
25
27
|
caption: caption.map(&:to_h),
|
26
28
|
href: href,
|
29
|
+
alt: alt,
|
27
30
|
}
|
28
31
|
end
|
29
32
|
|
@@ -35,7 +38,8 @@ module ArticleJSON
|
|
35
38
|
source_url: hash[:source_url],
|
36
39
|
caption: parse_hash_list(hash[:caption]),
|
37
40
|
float: hash[:float]&.to_sym,
|
38
|
-
href: hash[:href]
|
41
|
+
href: hash[:href],
|
42
|
+
alt: hash[:alt]
|
39
43
|
)
|
40
44
|
end
|
41
45
|
end
|
@@ -69,7 +69,7 @@ module ArticleJSON
|
|
69
69
|
|
70
70
|
# @return [Nokogiri::XML::Element]
|
71
71
|
def facebook_node
|
72
|
-
url = "#{@element.oembed_data[:author_url]}videos/#{@element.embed_id}"
|
72
|
+
url = "#{@element.oembed_data[:author_url]}/videos/#{@element.embed_id}"
|
73
73
|
create_element('amp-facebook',
|
74
74
|
'data-embedded-as' => 'video',
|
75
75
|
'data-href' => url,
|