jekyll-twitter-plugin 1.3.1 → 1.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +6 -0
- data/.rspec +2 -0
- data/.rubocop.yml +16 -0
- data/.travis.yml +17 -0
- data/Gemfile +2 -1
- data/README.md +43 -9
- data/Rakefile +2 -1
- data/jekyll-twitter-plugin.gemspec +16 -13
- data/lib/jekyll-twitter-plugin.rb +87 -53
- data/spec/integration_tests.rb +82 -0
- data/spec/oembed_spec.rb +103 -0
- data/spec/spec_helper.rb +30 -0
- data/spec/support/jekyll_template.rb +11 -0
- data/spec/support/shared_contexts.rb +21 -0
- data/spec/twitter_tag_spec.rb +243 -0
- metadata +39 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: eb81bd5f03311d7ea54536c4ae9b66a4958a0581
|
4
|
+
data.tar.gz: 8718758139ec729d224592a725e406e3fd18e795
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 32e14f43bd34316445f6ac38eeb685b4fc5fa554a765022df00febfd45c8d153f4864144e95163e6f03e0fd6c4c46abf99a4bbd999715df4bf04c1c90fc683c0
|
7
|
+
data.tar.gz: a7a19a137770446e06eda37ee35ce540f880962d6e1f380b71ee8405d2602fdb2b49b7f803aed58e657eea5cda83acca6fa09bd64fd21f428dd1fe527243a708
|
data/.gitignore
CHANGED
@@ -8,6 +8,7 @@
|
|
8
8
|
/test/tmp/
|
9
9
|
/test/version_tmp/
|
10
10
|
/tmp/
|
11
|
+
.byebug_history
|
11
12
|
|
12
13
|
## Specific to RubyMotion:
|
13
14
|
.dat*
|
@@ -32,3 +33,8 @@ Gemfile.lock
|
|
32
33
|
|
33
34
|
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
|
34
35
|
.rvmrc
|
36
|
+
|
37
|
+
# App specific
|
38
|
+
.env
|
39
|
+
output_test.html
|
40
|
+
.tweet-cache
|
data/.rspec
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
LineLength:
|
2
|
+
Enabled: false
|
3
|
+
|
4
|
+
StringLiterals:
|
5
|
+
EnforcedStyle: double_quotes
|
6
|
+
Enabled: true
|
7
|
+
|
8
|
+
Documentation:
|
9
|
+
Enabled: false
|
10
|
+
|
11
|
+
Style/FileName:
|
12
|
+
Exclude:
|
13
|
+
- 'lib/jekyll-twitter-plugin.rb'
|
14
|
+
|
15
|
+
Lint/AssignmentInCondition:
|
16
|
+
Enabled: false
|
data/.travis.yml
ADDED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
A Liquid tag plugin for Jekyll that renders Tweets from Twitter API.
|
4
4
|
|
5
|
+
[![Build Status](https://travis-ci.org/rob-murray/jekyll-twitter-plugin.svg?branch=master)](https://travis-ci.org/rob-murray/jekyll-twitter-plugin)
|
5
6
|
[![Gem Version](https://badge.fury.io/rb/jekyll-twitter-plugin.svg)](http://badge.fury.io/rb/jekyll-twitter-plugin)
|
6
7
|
|
7
8
|
|
@@ -9,16 +10,17 @@ A Liquid tag plugin for Jekyll that renders Tweets from Twitter API.
|
|
9
10
|
|
10
11
|
A Liquid tag plugin for [Jekyll](http://jekyllrb.com/) that enables Twitter content to be used in any content served by Jekyll, content is fetched from the [Twitter API](https://dev.twitter.com/home).
|
11
12
|
|
12
|
-
It is based on the original Jekyll Tweet Tag
|
13
|
+
It is based on the original [Jekyll Tweet Tag](https://github.com/scottwb/jekyll-tweet-tag) from [scottwb](https://github.com/scottwb/) which has not been updated since Twitter changed their API to require certain preconditions. This version uses the excellent [Twitter gem](https://github.com/sferik/twitter) to make requests and handle authentication.
|
13
14
|
|
14
|
-
This plugin replaces the broken plugin mentioned above and uses a different tag name and API - this is by design so that the two plugins can be used
|
15
|
+
This plugin replaces the broken [Jekyll Tweet Tag](https://github.com/scottwb/jekyll-tweet-tag) plugin mentioned above and uses a different tag name and API - this is by design so that the two plugins can be separated and you can be certain which plugin is being used. You can also install this plugin via Rubygems and require it in your Jekyll `_config.yml` file. You can use *ENV* variables or `_config.yml` file for your Twitter API secret keys.
|
15
16
|
|
16
17
|
|
17
18
|
### Features
|
18
19
|
|
19
20
|
The plugin supports the following features:
|
20
21
|
|
21
|
-
* Installed via Rubygems
|
22
|
+
* Installed via Rubygems.
|
23
|
+
* Twitter API secrets read from *ENV* vars or `_config.yml` file.
|
22
24
|
* [Oembed](#oembed) - Embed a Tweet in familiar Twitter styling.
|
23
25
|
* [Caching](#caching) - Twitter API responses can be cached to avoid hitting request limits.
|
24
26
|
|
@@ -27,10 +29,12 @@ The plugin supports the following features:
|
|
27
29
|
|
28
30
|
* Twitter oauth credentials - Most Twitter api functions now require authentication. Set up your [application](https://dev.twitter.com/apps/new) and get the credentials.
|
29
31
|
|
32
|
+
|
30
33
|
### Usage
|
31
34
|
|
32
35
|
As mentioned by [Jekyll's documentation](http://jekyllrb.com/docs/plugins/#installing-a-plugin) you have two options; manually import the source file or require the plugin as a `gem`.
|
33
36
|
|
37
|
+
|
34
38
|
#### Require gem
|
35
39
|
|
36
40
|
Install the gem, add it to your Gemfile;
|
@@ -45,8 +49,11 @@ Add the `jekyll-twitter-plugin` to your site `_config.yml` file for Jekyll to im
|
|
45
49
|
gems: ['jekyll-twitter-plugin']
|
46
50
|
```
|
47
51
|
|
52
|
+
|
48
53
|
#### Manual import
|
49
54
|
|
55
|
+
> Note: this is deprecated and support will be removed in a later version.
|
56
|
+
|
50
57
|
Just download the source file into your `_plugins` directory, e.g.
|
51
58
|
|
52
59
|
```bash
|
@@ -55,6 +62,7 @@ $ mkdir -p _plugins && cd _plugins
|
|
55
62
|
$ wget https://raw.githubusercontent.com/rob-murray/jekyll-twitter-plugin/master/lib/jekyll-twitter-plugin.rb
|
56
63
|
```
|
57
64
|
|
65
|
+
|
58
66
|
#### Credentials
|
59
67
|
|
60
68
|
Your Twitter application authentication credentials are private - do not distribute these!
|
@@ -80,8 +88,11 @@ environment variables.
|
|
80
88
|
|
81
89
|
```bash
|
82
90
|
$ export TWITTER_CONSUMER_KEY=foo etc.
|
91
|
+
# Or given a file .env with the keys and secrets
|
92
|
+
$ export $(cat .env | xargs)
|
83
93
|
```
|
84
94
|
|
95
|
+
|
85
96
|
#### Plugin tag usage
|
86
97
|
|
87
98
|
To use the plugin, in your source content use the tag `twitter` and then pass additional parameters to the plugin.
|
@@ -90,27 +101,41 @@ To use the plugin, in your source content use the tag `twitter` and then pass ad
|
|
90
101
|
{% plugin_type api_type *params %}
|
91
102
|
```
|
92
103
|
|
93
|
-
|
94
|
-
|
95
|
-
|
104
|
+
| Argument | Required? | Description |
|
105
|
+
|---|---|---|
|
106
|
+
| `plugin_type` | Yes | Either `twitter` or `twitternocache` (same as `twitter` but does not cache api responses) |
|
107
|
+
| `api_type` | No - defaults to **oembed** | The Twitter API to use, check below for supported APIs. |
|
108
|
+
| `*params` | Yes* | Parameters for the API separated by spaces. Refer below and to respective Twitter API documentation for available parameters. |
|
109
|
+
|
110
|
+
* Required arguments depend on the API used.
|
111
|
+
|
96
112
|
|
97
113
|
### Supported Twitter APIs
|
98
114
|
|
99
115
|
The following Twitter APIs are supported.
|
100
116
|
|
101
|
-
|
117
|
+
|
118
|
+
#### Oembed - Default
|
102
119
|
|
103
120
|
The [oembed](https://dev.twitter.com/rest/reference/get/statuses/oembed) API returns html snippet to embed in your app, this will be rendered in the familiar Twitter style.
|
104
121
|
|
122
|
+
This API requires the `status_url` parameter, all others are optional.
|
123
|
+
|
105
124
|
```liquid
|
125
|
+
# With api_type specified
|
106
126
|
{% twitter oembed status_url *options %}
|
127
|
+
# 'oembed' autoselected by default
|
128
|
+
{% twitter status_url *options %}
|
107
129
|
|
108
|
-
#
|
130
|
+
# Basic example
|
109
131
|
{% twitter oembed https://twitter.com/rubygems/status/518821243320287232 %}
|
132
|
+
# Oembed default example
|
133
|
+
{% twitter https://twitter.com/rubygems/status/518821243320287232 %}
|
110
134
|
# With options
|
111
135
|
{% twitter oembed https://twitter.com/rubygems/status/518821243320287232 align='right' width='350' %}
|
112
136
|
```
|
113
137
|
|
138
|
+
|
114
139
|
### Output
|
115
140
|
|
116
141
|
As with the original plugin, all content will be rendered inside a div with the classes 'embed' and 'twitter'
|
@@ -129,6 +154,7 @@ If the Twitter client receives one of `Twitter::Error::NotFound, Twitter::Error:
|
|
129
154
|
|
130
155
|
> There was a '{error name}' error fetching Tweet '{Tweet status url}'
|
131
156
|
|
157
|
+
|
132
158
|
### Caching
|
133
159
|
|
134
160
|
Twitter API responses can be cached to speed up Jekyll site builds and avoid going over API limits. The reponses will be cached in a directory within your Jekyll project called `.tweet-cache`, ensure that this is not commit to source control.
|
@@ -145,12 +171,20 @@ It is possible to disable caching by using the specific `twitternocache` tag.
|
|
145
171
|
|
146
172
|
```
|
147
173
|
|
174
|
+
|
148
175
|
### Contributions
|
149
176
|
|
150
|
-
I've tried hard to keep all classes and code in the one `lib/jekyll-twitter-plugin.rb` file so that people can just grab this file and include in their Jekyll `_plugins` directory if they do not want to use the Gem. This
|
177
|
+
I've tried hard to keep all classes and code in the one `lib/jekyll-twitter-plugin.rb` file so that people can just grab this file and include in their Jekyll `_plugins` directory if they do not want to use the Gem. This will be dropped in a later version.
|
151
178
|
|
152
179
|
Please use the GitHub pull-request mechanism to submit contributions.
|
153
180
|
|
181
|
+
There is a quick integration test in `spec/integration_tests.rb` that needs API keys and will use the public api and output a file `output_test.html`. Run this with the following command:
|
182
|
+
|
183
|
+
```ruby
|
184
|
+
$ ruby spec/integration_tests.rb
|
185
|
+
```
|
186
|
+
|
187
|
+
|
154
188
|
### License
|
155
189
|
|
156
190
|
This project is available for use under the MIT software license.
|
data/Rakefile
CHANGED
@@ -1 +1,2 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require "bundler/gem_tasks"
|
@@ -1,23 +1,26 @@
|
|
1
1
|
# coding: utf-8
|
2
|
-
|
2
|
+
# frozen_string_literal: true
|
3
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
5
|
|
5
6
|
Gem::Specification.new do |spec|
|
6
|
-
spec.name =
|
7
|
-
spec.version =
|
8
|
-
spec.authors = [
|
9
|
-
spec.email = [
|
10
|
-
spec.summary =
|
11
|
-
spec.homepage =
|
12
|
-
spec.license =
|
7
|
+
spec.name = "jekyll-twitter-plugin"
|
8
|
+
spec.version = "1.4.0"
|
9
|
+
spec.authors = ["Rob Murray"]
|
10
|
+
spec.email = ["robmurray17@gmail.com"]
|
11
|
+
spec.summary = "A Liquid tag plugin for Jekyll that renders Tweets from Twitter API"
|
12
|
+
spec.homepage = "https://github.com/rob-murray/jekyll-twitter-plugin"
|
13
|
+
spec.license = "MIT"
|
14
|
+
spec.required_ruby_version = ">= 1.9.3"
|
13
15
|
|
14
16
|
spec.files = `git ls-files -z`.split("\x0")
|
15
17
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
16
|
-
spec.require_paths = [
|
18
|
+
spec.require_paths = ["lib"]
|
17
19
|
|
18
|
-
spec.add_development_dependency
|
19
|
-
spec.add_development_dependency
|
20
|
-
spec.add_development_dependency
|
20
|
+
spec.add_development_dependency "bundler", "~> 1.6"
|
21
|
+
spec.add_development_dependency "rake"
|
22
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
23
|
+
spec.add_development_dependency "byebug" if RUBY_VERSION >= "2.0"
|
21
24
|
|
22
|
-
spec.add_dependency
|
25
|
+
spec.add_dependency "twitter", "~> 5.16"
|
23
26
|
end
|
@@ -1,14 +1,26 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require "fileutils"
|
3
|
+
require "twitter"
|
2
4
|
|
3
5
|
##
|
4
6
|
# A Liquid tag plugin for Jekyll that renders Tweets from Twitter API.
|
5
7
|
# https://github.com/rob-murray/jekyll-twitter-plugin
|
6
8
|
#
|
7
|
-
|
8
9
|
module TwitterJekyll
|
10
|
+
MissingApiKeyError = Class.new(StandardError)
|
11
|
+
TwitterSecrets = Struct.new(:consumer_key, :consumer_secret, :access_token, :access_token_secret) do
|
12
|
+
def self.build(source, keys)
|
13
|
+
new(*source.values_at(*keys))
|
14
|
+
end
|
15
|
+
end
|
16
|
+
CONTEXT_API_KEYS = %w(consumer_key consumer_secret access_token access_token_secret).freeze
|
17
|
+
ENV_API_KEYS = %w(TWITTER_CONSUMER_KEY TWITTER_CONSUMER_SECRET TWITTER_ACCESS_TOKEN TWITTER_ACCESS_TOKEN_SECRET).freeze
|
18
|
+
TWITTER_STATUS_URL = %r{\Ahttps?://twitter\.com/(:#!\/)?\w+/status(es)?/\d+}i
|
19
|
+
REFER_TO_README = "Please see 'https://github.com/rob-murray/jekyll-twitter-plugin' for usage."
|
20
|
+
|
9
21
|
class FileCache
|
10
22
|
def initialize(path)
|
11
|
-
@cache_folder
|
23
|
+
@cache_folder = File.expand_path path
|
12
24
|
FileUtils.mkdir_p @cache_folder
|
13
25
|
end
|
14
26
|
|
@@ -21,7 +33,7 @@ module TwitterJekyll
|
|
21
33
|
file_to_write = cache_file(cache_filename(key))
|
22
34
|
data_to_write = JSON.generate data.to_h
|
23
35
|
|
24
|
-
File.open(file_to_write,
|
36
|
+
File.open(file_to_write, "w") do |f|
|
25
37
|
f.write(data_to_write)
|
26
38
|
end
|
27
39
|
end
|
@@ -38,6 +50,8 @@ module TwitterJekyll
|
|
38
50
|
end
|
39
51
|
|
40
52
|
class NullCache
|
53
|
+
def initialize(*_args); end
|
54
|
+
|
41
55
|
def read(_key); end
|
42
56
|
|
43
57
|
def write(_key, _data); end
|
@@ -52,7 +66,7 @@ module TwitterJekyll
|
|
52
66
|
end
|
53
67
|
|
54
68
|
class TwitterApi
|
55
|
-
ERRORS_TO_IGNORE = [Twitter::Error::NotFound, Twitter::Error::Forbidden]
|
69
|
+
ERRORS_TO_IGNORE = [Twitter::Error::NotFound, Twitter::Error::Forbidden].freeze
|
56
70
|
|
57
71
|
attr_reader :error
|
58
72
|
|
@@ -62,12 +76,12 @@ module TwitterJekyll
|
|
62
76
|
parse_args(params)
|
63
77
|
end
|
64
78
|
|
79
|
+
def fetch; end
|
80
|
+
|
65
81
|
private
|
66
82
|
|
67
83
|
def id_from_status_url(url)
|
68
|
-
if url.to_s =~
|
69
|
-
Regexp.last_match[1]
|
70
|
-
end
|
84
|
+
Regexp.last_match[1] if url.to_s =~ %r{([^\/]+$)}
|
71
85
|
end
|
72
86
|
|
73
87
|
def find_tweet(id)
|
@@ -81,17 +95,13 @@ module TwitterJekyll
|
|
81
95
|
|
82
96
|
def parse_args(args)
|
83
97
|
@params ||= begin
|
84
|
-
|
85
|
-
|
86
|
-
k, v = arg.split('=').map(&:strip)
|
98
|
+
args.each_with_object({}) do |arg, params|
|
99
|
+
k, v = arg.split("=").map(&:strip)
|
87
100
|
if k && v
|
88
|
-
if v =~ /^'(.*)'$/
|
89
|
-
v = Regexp.last_match[1]
|
90
|
-
end
|
101
|
+
v = Regexp.last_match[1] if v =~ /^'(.*)'$/
|
91
102
|
params[k] = v
|
92
103
|
end
|
93
104
|
end
|
94
|
-
params
|
95
105
|
end
|
96
106
|
end
|
97
107
|
|
@@ -118,17 +128,13 @@ module TwitterJekyll
|
|
118
128
|
private
|
119
129
|
|
120
130
|
def key
|
121
|
-
|
131
|
+
format("%s-%s", @status_url, @params.to_s)
|
122
132
|
end
|
123
133
|
end
|
124
134
|
|
125
|
-
class UnknownTypeClient
|
126
|
-
include TwitterJekyll::Cacheable
|
127
|
-
|
128
|
-
def fetch; end
|
129
|
-
end
|
130
|
-
|
131
135
|
class ErrorResponse
|
136
|
+
attr_reader :error
|
137
|
+
|
132
138
|
def initialize(error)
|
133
139
|
@error = error
|
134
140
|
end
|
@@ -143,18 +149,22 @@ module TwitterJekyll
|
|
143
149
|
end
|
144
150
|
|
145
151
|
class TwitterTag < Liquid::Tag
|
146
|
-
ERROR_BODY_TEXT
|
152
|
+
ERROR_BODY_TEXT = "<p>Tweet could not be processed</p>"
|
153
|
+
DEFAULT_API_TYPE = "oembed"
|
154
|
+
|
155
|
+
attr_writer :cache # for testing
|
147
156
|
|
148
157
|
def initialize(_name, params, _tokens)
|
149
158
|
super
|
150
|
-
@
|
151
|
-
|
152
|
-
|
153
|
-
|
159
|
+
@api_type, @params = parse_params(params)
|
160
|
+
end
|
161
|
+
|
162
|
+
def self.cache_klass
|
163
|
+
FileCache
|
154
164
|
end
|
155
165
|
|
156
166
|
def render(context)
|
157
|
-
secrets =
|
167
|
+
secrets = find_secrets!(context)
|
158
168
|
create_twitter_rest_client(secrets)
|
159
169
|
api_client = create_api_client(@api_type, @params)
|
160
170
|
response = cached_response(api_client) || live_response(api_client)
|
@@ -163,38 +173,48 @@ module TwitterJekyll
|
|
163
173
|
|
164
174
|
private
|
165
175
|
|
166
|
-
def
|
167
|
-
|
176
|
+
def cache
|
177
|
+
@cache ||= self.class.cache_klass.new("./.tweet-cache")
|
178
|
+
end
|
168
179
|
|
169
|
-
|
170
|
-
|
171
|
-
end
|
180
|
+
def html_output_for(response)
|
181
|
+
body = (response.html if response) || ERROR_BODY_TEXT
|
172
182
|
|
173
183
|
"<div class='embed twitter'>#{body}</div>"
|
174
184
|
end
|
175
185
|
|
176
186
|
def live_response(api_client)
|
177
187
|
if response = api_client.fetch
|
178
|
-
|
188
|
+
cache.write(api_client.cache_key, response)
|
179
189
|
response
|
180
190
|
end
|
181
191
|
end
|
182
192
|
|
183
193
|
def cached_response(api_client)
|
184
|
-
response =
|
194
|
+
response = cache.read(api_client.cache_key)
|
185
195
|
OpenStruct.new(response) unless response.nil?
|
186
196
|
end
|
187
197
|
|
188
|
-
def
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
198
|
+
def parse_params(params)
|
199
|
+
args = params.split(/\s+/).map(&:strip)
|
200
|
+
|
201
|
+
case args[0]
|
202
|
+
when DEFAULT_API_TYPE
|
203
|
+
api_type, *api_args = args
|
204
|
+
[api_type, api_args]
|
205
|
+
when TWITTER_STATUS_URL
|
206
|
+
[DEFAULT_API_TYPE, args]
|
193
207
|
else
|
194
|
-
|
208
|
+
invalid_args!(args)
|
195
209
|
end
|
196
210
|
end
|
197
211
|
|
212
|
+
def create_api_client(api_type, params)
|
213
|
+
klass_name = api_type.capitalize
|
214
|
+
api_client_klass = TwitterJekyll.const_get(klass_name)
|
215
|
+
api_client_klass.new(@twitter_client, params)
|
216
|
+
end
|
217
|
+
|
198
218
|
def create_twitter_rest_client(secrets)
|
199
219
|
@twitter_client = Twitter::REST::Client.new do |config|
|
200
220
|
config.consumer_key = secrets.consumer_key
|
@@ -204,29 +224,43 @@ module TwitterJekyll
|
|
204
224
|
end
|
205
225
|
end
|
206
226
|
|
207
|
-
|
227
|
+
def find_secrets!(context)
|
228
|
+
extract_twitter_secrets_from_context(context) || extract_twitter_secrets_from_env || missing_keys!
|
229
|
+
end
|
208
230
|
|
209
231
|
def extract_twitter_secrets_from_context(context)
|
210
|
-
|
211
|
-
|
232
|
+
twitter_secrets = context.registers[:site].config.fetch("twitter", {})
|
233
|
+
return unless store_has_keys?(twitter_secrets, CONTEXT_API_KEYS)
|
212
234
|
|
213
|
-
|
214
|
-
twitter_secrets = context.registers[:site].config['twitter'] || {}
|
215
|
-
['consumer_key', 'consumer_secret', 'access_token', 'access_token_secret'].all? {|s| twitter_secrets.key?(s)}
|
235
|
+
TwitterSecrets.build(twitter_secrets, CONTEXT_API_KEYS)
|
216
236
|
end
|
217
237
|
|
218
238
|
def extract_twitter_secrets_from_env
|
219
|
-
|
239
|
+
return unless store_has_keys?(ENV, ENV_API_KEYS)
|
240
|
+
|
241
|
+
TwitterSecrets.build(ENV, ENV_API_KEYS)
|
242
|
+
end
|
243
|
+
|
244
|
+
def store_has_keys?(store, keys)
|
245
|
+
keys.all? { |required_key| store.key?(required_key) }
|
246
|
+
end
|
247
|
+
|
248
|
+
def missing_keys!
|
249
|
+
raise MissingApiKeyError, "Twitter API keys not found. You can specify these in Jekyll config or ENV. #{REFER_TO_README}"
|
250
|
+
end
|
251
|
+
|
252
|
+
def invalid_args!(arguments)
|
253
|
+
formatted_args = Array(arguments).join(" ")
|
254
|
+
raise ArgumentError, "Invalid arguments '#{formatted_args}' passed to 'jekyll-twitter-plugin'. #{REFER_TO_README}"
|
220
255
|
end
|
221
256
|
end
|
222
257
|
|
223
258
|
class TwitterTagNoCache < TwitterTag
|
224
|
-
def
|
225
|
-
|
226
|
-
@cache = NullCache.new
|
259
|
+
def self.cache_klass
|
260
|
+
NullCache
|
227
261
|
end
|
228
262
|
end
|
229
263
|
end
|
230
264
|
|
231
|
-
Liquid::Template.register_tag(
|
232
|
-
Liquid::Template.register_tag(
|
265
|
+
Liquid::Template.register_tag("twitter", TwitterJekyll::TwitterTag)
|
266
|
+
Liquid::Template.register_tag("twitternocache", TwitterJekyll::TwitterTagNoCache)
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# Basic integration example - run code to produce html output
|
3
|
+
#
|
4
|
+
# * Requires .env populated with valid Twitter API creds.
|
5
|
+
#
|
6
|
+
$LOAD_PATH.unshift File.expand_path("../../lib", __FILE__)
|
7
|
+
require_relative "./support/jekyll_template"
|
8
|
+
require "jekyll-twitter-plugin"
|
9
|
+
require "erb"
|
10
|
+
|
11
|
+
OUTPUT_FILENAME = "output_test.html"
|
12
|
+
OPTIONS = [
|
13
|
+
"oembed https://twitter.com/rubygems/status/518821243320287232",
|
14
|
+
"oembed https://twitter.com/rubygems/status/518821243320287232 align='right' width='350'",
|
15
|
+
"https://twitter.com/rubygems/status/518821243320287232",
|
16
|
+
"oembed https://twitter.com/rubygems/status/missing"
|
17
|
+
].freeze
|
18
|
+
|
19
|
+
COLOUR_MAP = {
|
20
|
+
red: 31,
|
21
|
+
green: 32,
|
22
|
+
yellow: 33,
|
23
|
+
blue: 34
|
24
|
+
}.freeze
|
25
|
+
|
26
|
+
def say_with_colour(text, colour_name)
|
27
|
+
colour_code = COLOUR_MAP.fetch(colour_name)
|
28
|
+
puts "\e[#{colour_code}m#{text}\e[0m"
|
29
|
+
end
|
30
|
+
|
31
|
+
class TwitterRenderer
|
32
|
+
Context = Struct.new(:registers)
|
33
|
+
Site = Struct.new(:config)
|
34
|
+
|
35
|
+
def initialize(options)
|
36
|
+
@options = options
|
37
|
+
@jekyll_context = Context.new(site: Site.new({}))
|
38
|
+
end
|
39
|
+
|
40
|
+
def render
|
41
|
+
ERB.new(template)
|
42
|
+
.result(binding)
|
43
|
+
.gsub!("src=\"//", "src=\"https://")
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
attr_reader :options, :jekyll_context
|
49
|
+
|
50
|
+
def render_twitter_tag(params)
|
51
|
+
say_with_colour "Fetching with params: #{params}", :yellow
|
52
|
+
TwitterJekyll::TwitterTag.new(nil, params, nil).render(jekyll_context)
|
53
|
+
end
|
54
|
+
|
55
|
+
def template
|
56
|
+
<<~HTML
|
57
|
+
<html>
|
58
|
+
<body>
|
59
|
+
<h1>jekyll-twitter-plugin output tests</h1>
|
60
|
+
<% options.each do |option| %>
|
61
|
+
<h3><%= option %></h3>
|
62
|
+
<%= render_twitter_tag(option) %>
|
63
|
+
<hr>
|
64
|
+
<% end %>
|
65
|
+
</body>
|
66
|
+
</html>
|
67
|
+
HTML
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def main
|
72
|
+
rederer = TwitterRenderer.new(OPTIONS)
|
73
|
+
File.open(OUTPUT_FILENAME, "w") do |f|
|
74
|
+
f.write rederer.render
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
if __FILE__ == $PROGRAM_NAME
|
79
|
+
say_with_colour "Running integration tests...", :red
|
80
|
+
main
|
81
|
+
say_with_colour "Created file: #{OUTPUT_FILENAME}", :green
|
82
|
+
end
|
data/spec/oembed_spec.rb
ADDED
@@ -0,0 +1,103 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
RSpec.describe TwitterJekyll::Oembed do
|
3
|
+
let(:api_client) { double("Twitter::REST::Client") }
|
4
|
+
let(:status_response) { double }
|
5
|
+
subject { described_class.new(api_client, params) }
|
6
|
+
|
7
|
+
describe "parsing status id" do
|
8
|
+
let(:params) { ["https://twitter.com/twitter_user/status/12345"] }
|
9
|
+
|
10
|
+
it "parses the status id from the tweet url correctly" do
|
11
|
+
status_response = double
|
12
|
+
allow(Twitter::REST::Client).to receive(:new).and_return(api_client)
|
13
|
+
|
14
|
+
expect(api_client).to receive(:status).with(12_345).and_return(status_response)
|
15
|
+
expect(api_client).to receive(:oembed).with(status_response, {}).and_return("")
|
16
|
+
subject.fetch
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe "parsing options" do
|
21
|
+
context "with extra options" do
|
22
|
+
let(:params) { ["https://twitter.com/twitter_user/status/12345", "align='right'", "width='350'"] }
|
23
|
+
|
24
|
+
it "passes to api" do
|
25
|
+
allow(Twitter::REST::Client).to receive(:new).and_return(api_client)
|
26
|
+
allow(api_client).to receive(:status).with(12_345).and_return(status_response)
|
27
|
+
|
28
|
+
expect(api_client).to receive(:oembed).with(status_response, "align" => "right", "width" => "350").and_return("")
|
29
|
+
subject.fetch
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
context "with an invalid option" do
|
34
|
+
let(:params) { ["https://twitter.com/twitter_user/status/12345", "align=", "width='350'"] }
|
35
|
+
|
36
|
+
it "ignores param" do
|
37
|
+
allow(Twitter::REST::Client).to receive(:new).and_return(api_client)
|
38
|
+
allow(api_client).to receive(:status).with(12_345).and_return(status_response)
|
39
|
+
|
40
|
+
expect(api_client).to receive(:oembed).with(status_response, "width" => "350").and_return("")
|
41
|
+
subject.fetch
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe "#fetch" do
|
47
|
+
let(:params) { ["https://twitter.com/twitter_user/status/12345"] }
|
48
|
+
|
49
|
+
it "returns response from api" do
|
50
|
+
allow(Twitter::REST::Client).to receive(:new).and_return(api_client)
|
51
|
+
allow(api_client).to receive(:status).with(12_345).and_return(status_response)
|
52
|
+
|
53
|
+
expect(api_client).to receive(:oembed).with(status_response, {}).and_return("api response")
|
54
|
+
expect(subject.fetch).to eq "api response"
|
55
|
+
end
|
56
|
+
|
57
|
+
context "when status is not found" do
|
58
|
+
it "returns error" do
|
59
|
+
allow(Twitter::REST::Client).to receive(:new).and_return(api_client)
|
60
|
+
allow(api_client).to receive(:status).with(12_345).and_raise(Twitter::Error::NotFound)
|
61
|
+
|
62
|
+
expect(api_client).not_to receive(:oembed)
|
63
|
+
result = subject.fetch
|
64
|
+
expect(result).to be_a(TwitterJekyll::ErrorResponse)
|
65
|
+
expect(result.error).to eq "There was a 'Twitter::Error::NotFound' error fetching Tweet 'https://twitter.com/twitter_user/status/12345'"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
describe "#cache_key" do
|
71
|
+
context "with no params" do
|
72
|
+
let(:params) { ["https://twitter.com/twitter_user/status/12345"] }
|
73
|
+
|
74
|
+
it "matches on status url" do
|
75
|
+
oembed_1 = TwitterJekyll::Oembed.new(api_client, params.dup)
|
76
|
+
oembed_2 = TwitterJekyll::Oembed.new(api_client, params.dup)
|
77
|
+
|
78
|
+
expect(
|
79
|
+
oembed_1.cache_key == oembed_2.cache_key
|
80
|
+
).to be true
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
context "with params" do
|
85
|
+
let(:params_1) { ["https://twitter.com/twitter_user/status/12345", "align='right'"] }
|
86
|
+
let(:params_2) { ["https://twitter.com/twitter_user/status/12345", "align='left'"] }
|
87
|
+
|
88
|
+
it "matches on keys and values" do
|
89
|
+
oembed_1 = TwitterJekyll::Oembed.new(api_client, params_1.dup)
|
90
|
+
oembed_2 = TwitterJekyll::Oembed.new(api_client, params_2.dup)
|
91
|
+
oembed_3 = TwitterJekyll::Oembed.new(api_client, params_1.dup)
|
92
|
+
|
93
|
+
expect(
|
94
|
+
oembed_1.cache_key == oembed_2.cache_key
|
95
|
+
).to be false
|
96
|
+
|
97
|
+
expect(
|
98
|
+
oembed_1.cache_key == oembed_3.cache_key
|
99
|
+
).to be true
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
$LOAD_PATH.unshift File.expand_path("../../lib", __FILE__)
|
3
|
+
require "support/jekyll_template"
|
4
|
+
require "support/shared_contexts"
|
5
|
+
require "jekyll-twitter-plugin"
|
6
|
+
require "byebug" if RUBY_VERSION >= "2.0"
|
7
|
+
|
8
|
+
#
|
9
|
+
# The `.rspec` file also contains a few flags that are not defaults but that
|
10
|
+
# users commonly want.
|
11
|
+
#
|
12
|
+
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
13
|
+
RSpec.configure do |config|
|
14
|
+
config.expect_with :rspec do |expectations|
|
15
|
+
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
|
16
|
+
end
|
17
|
+
|
18
|
+
config.mock_with :rspec do |mocks|
|
19
|
+
mocks.verify_partial_doubles = true
|
20
|
+
end
|
21
|
+
|
22
|
+
config.shared_context_metadata_behavior = :apply_to_host_groups
|
23
|
+
config.filter_run_when_matching :focus
|
24
|
+
config.disable_monkey_patching!
|
25
|
+
config.warnings = true
|
26
|
+
config.default_formatter = "doc" if config.files_to_run.one?
|
27
|
+
|
28
|
+
config.order = :random
|
29
|
+
Kernel.srand config.seed
|
30
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
RSpec.shared_context "without cached response" do
|
3
|
+
let(:cache) { null_cache }
|
4
|
+
|
5
|
+
before do
|
6
|
+
subject.cache = cache
|
7
|
+
end
|
8
|
+
|
9
|
+
def null_cache
|
10
|
+
double("TwitterJekyll::NullCache", read: nil, write: nil)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
RSpec.shared_context "with any oembed request and response" do
|
15
|
+
let(:options) { "oembed https://twitter.com/twitter_user/status/12345" }
|
16
|
+
let(:response) { OpenStruct.new(html: "<p>tweet html</p>") }
|
17
|
+
|
18
|
+
before do
|
19
|
+
allow(api_client).to receive(:oembed).and_return(response)
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,243 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
RSpec.describe TwitterJekyll::TwitterTag do
|
3
|
+
let(:context) { double.as_null_object }
|
4
|
+
let(:options) { "" }
|
5
|
+
subject { described_class.new(nil, options, nil) }
|
6
|
+
|
7
|
+
describe "output from oembed request" do
|
8
|
+
let(:api_response_hash) do
|
9
|
+
{
|
10
|
+
"url" => "https://twitter.com/twitter_user/status/12345",
|
11
|
+
"author_name" => "twitter user",
|
12
|
+
"author_url" => "https://twitter.com/twitter_user",
|
13
|
+
"html" => "<p>tweet html</p>",
|
14
|
+
"width" => 550,
|
15
|
+
"height" => nil,
|
16
|
+
"type" => "rich",
|
17
|
+
"cache_age" => "3153600000",
|
18
|
+
"provider_name" => "Twitter",
|
19
|
+
"provider_url" => "https://twitter.com",
|
20
|
+
"version" => "1.0"
|
21
|
+
}
|
22
|
+
end
|
23
|
+
let(:options) { "oembed https://twitter.com/twitter_user/status/12345" }
|
24
|
+
|
25
|
+
context "with cached response" do
|
26
|
+
let(:cache) { double("TwitterJekyll::FileCache") }
|
27
|
+
before do
|
28
|
+
subject.cache = cache
|
29
|
+
end
|
30
|
+
|
31
|
+
it "renders response from cache" do
|
32
|
+
allow(Twitter::REST::Client).to receive(:new).and_return(double.as_null_object)
|
33
|
+
expect(cache).to receive(:read).with(an_instance_of(String)).and_return(api_response_hash)
|
34
|
+
|
35
|
+
output = subject.render(context)
|
36
|
+
expect_output_to_match_tag_content(output, api_response_hash.fetch("html"))
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
context "without cached response" do
|
41
|
+
let(:cache) { double("TwitterJekyll::FileCache") }
|
42
|
+
let(:response) { build_response_object(api_response_hash) }
|
43
|
+
before do
|
44
|
+
subject.cache = cache
|
45
|
+
allow(cache).to receive(:read).with(an_instance_of(String)).and_return(nil)
|
46
|
+
end
|
47
|
+
|
48
|
+
context "with successful api request" do
|
49
|
+
it "renders response from api and writes to cache" do
|
50
|
+
api_client = double("Twitter::REST::Client", status: double)
|
51
|
+
allow(Twitter::REST::Client).to receive(:new).and_return(api_client)
|
52
|
+
|
53
|
+
expect(api_client).to receive(:oembed).and_return(response)
|
54
|
+
expect(cache).to receive(:write).with(an_instance_of(String), response)
|
55
|
+
|
56
|
+
output = subject.render(context)
|
57
|
+
expect_output_to_match_tag_content(output, api_response_hash.fetch("html"))
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
context "with a status not found api request" do
|
62
|
+
it "renders response from api and does not write to cache" do
|
63
|
+
api_client = double("Twitter::REST::Client", status: double)
|
64
|
+
allow(Twitter::REST::Client).to receive(:new).and_return(api_client)
|
65
|
+
|
66
|
+
expect(api_client).to receive(:status).and_raise(Twitter::Error::NotFound)
|
67
|
+
expect(cache).not_to receive(:write).with(an_instance_of(String), response)
|
68
|
+
|
69
|
+
output = subject.render(context)
|
70
|
+
expect_output_to_have_error(output, Twitter::Error::NotFound)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
context "with a status request not permitted api request" do
|
75
|
+
it "renders response from api and does not write to cache" do
|
76
|
+
api_client = double("Twitter::REST::Client", status: double)
|
77
|
+
allow(Twitter::REST::Client).to receive(:new).and_return(api_client)
|
78
|
+
|
79
|
+
expect(api_client).to receive(:status).and_raise(Twitter::Error::Forbidden)
|
80
|
+
expect(cache).not_to receive(:write).with(an_instance_of(String), response)
|
81
|
+
|
82
|
+
output = subject.render(context)
|
83
|
+
expect_output_to_have_error(output, Twitter::Error::Forbidden)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
describe "With an invalid request type" do
|
90
|
+
context "without any arguments" do
|
91
|
+
let(:options) { "" }
|
92
|
+
|
93
|
+
it "raises an exception" do
|
94
|
+
expect_to_raise_invalid_args_error(options) do
|
95
|
+
tag = described_class.new(nil, options, nil)
|
96
|
+
tag.render(context)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
context "with an api request type not supported" do
|
102
|
+
let(:options) { "unsupported https://twitter.com/twitter_user/status/12345" }
|
103
|
+
|
104
|
+
it "raises an exception" do
|
105
|
+
expect_to_raise_invalid_args_error(options) do
|
106
|
+
tag = described_class.new(nil, options, nil)
|
107
|
+
tag.render(context)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
context "without an api request type and no valid status url" do
|
113
|
+
let(:options) { "https://anything.com/twitter_user/status/12345" }
|
114
|
+
|
115
|
+
it "raises an exception" do
|
116
|
+
expect_to_raise_invalid_args_error(options) do
|
117
|
+
tag = described_class.new(nil, options, nil)
|
118
|
+
tag.render(context)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
describe "parsing api request type" do
|
125
|
+
include_context "without cached response"
|
126
|
+
let(:response) { OpenStruct.new(html: "anything") }
|
127
|
+
let(:status) { double }
|
128
|
+
|
129
|
+
context "with oembed requested" do
|
130
|
+
let(:options) { "oembed https://twitter.com/twitter_user/status/12345" }
|
131
|
+
|
132
|
+
it "uses the oembed api" do
|
133
|
+
api_client = double("Twitter::REST::Client", status: status)
|
134
|
+
allow(Twitter::REST::Client).to receive(:new).and_return(api_client)
|
135
|
+
|
136
|
+
expect(api_client).to receive(:oembed).with(status, {}).and_return(response)
|
137
|
+
subject.render(context)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
context "without an api request type" do
|
142
|
+
let(:options) { "https://twitter.com/twitter_user/status/12345" }
|
143
|
+
|
144
|
+
it "uses the default oembed api type" do
|
145
|
+
api_client = double("Twitter::REST::Client", status: status)
|
146
|
+
allow(Twitter::REST::Client).to receive(:new).and_return(api_client)
|
147
|
+
|
148
|
+
expect(api_client).to receive(:oembed).with(status, {}).and_return(response)
|
149
|
+
subject.render(context)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
describe "parsing api secrets" do
|
155
|
+
include_context "without cached response"
|
156
|
+
include_context "with any oembed request and response"
|
157
|
+
let(:api_client) { double("Twitter::REST::Client", status: double) }
|
158
|
+
let(:config_builder) { double }
|
159
|
+
|
160
|
+
before do
|
161
|
+
allow(Twitter::REST::Client).to receive(:new).and_yield(config_builder).and_return(api_client)
|
162
|
+
end
|
163
|
+
|
164
|
+
context "with api secrets provided by ENV" do
|
165
|
+
let(:context) { double("context", registers: { site: double(config: {}) }) }
|
166
|
+
before do
|
167
|
+
stub_const("ENV", "TWITTER_CONSUMER_KEY" => "consumer_key",
|
168
|
+
"TWITTER_CONSUMER_SECRET" => "consumer_secret",
|
169
|
+
"TWITTER_ACCESS_TOKEN" => "access_token",
|
170
|
+
"TWITTER_ACCESS_TOKEN_SECRET" => "access_token_secret")
|
171
|
+
end
|
172
|
+
|
173
|
+
it "creates api client correctly" do
|
174
|
+
expect(config_builder).to receive(:consumer_key=).with("consumer_key")
|
175
|
+
expect(config_builder).to receive(:consumer_secret=).with("consumer_secret")
|
176
|
+
expect(config_builder).to receive(:access_token=).with("access_token")
|
177
|
+
expect(config_builder).to receive(:access_token_secret=).with("access_token_secret")
|
178
|
+
|
179
|
+
subject.render(context)
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
context "with api secrets provided by Jekyll config" do
|
184
|
+
let(:context) do
|
185
|
+
api_secrets = %w(consumer_key consumer_secret access_token access_token_secret)
|
186
|
+
.each_with_object({}) { |secret, h| h[secret] = secret }
|
187
|
+
double("context", registers:
|
188
|
+
{ site: double(config: { "twitter" => api_secrets }) })
|
189
|
+
end
|
190
|
+
before do
|
191
|
+
stub_const("ENV", {})
|
192
|
+
end
|
193
|
+
|
194
|
+
it "creates api client correctly" do
|
195
|
+
expect(config_builder).to receive(:consumer_key=).with("consumer_key")
|
196
|
+
expect(config_builder).to receive(:consumer_secret=).with("consumer_secret")
|
197
|
+
expect(config_builder).to receive(:access_token=).with("access_token")
|
198
|
+
expect(config_builder).to receive(:access_token_secret=).with("access_token_secret")
|
199
|
+
|
200
|
+
subject.render(context)
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
context "with no api secrets provided" do
|
205
|
+
let(:context) { double("context", registers: { site: double(config: {}) }) }
|
206
|
+
before do
|
207
|
+
stub_const("ENV", {})
|
208
|
+
end
|
209
|
+
|
210
|
+
it "raises an exception" do
|
211
|
+
expect do
|
212
|
+
subject.render(context)
|
213
|
+
end.to raise_error(TwitterJekyll::MissingApiKeyError)
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
private
|
219
|
+
|
220
|
+
def expect_output_to_match_tag_content(actual, content)
|
221
|
+
expect(actual).to eq(
|
222
|
+
"<div class='embed twitter'>#{content}</div>"
|
223
|
+
)
|
224
|
+
end
|
225
|
+
|
226
|
+
def expect_output_to_have_error(actual, error, tweet_url = "https://twitter.com/twitter_user/status/12345")
|
227
|
+
expect_output_to_match_tag_content(actual, "<p>There was a '#{error}' error fetching Tweet '#{tweet_url}'</p>")
|
228
|
+
end
|
229
|
+
|
230
|
+
def expect_to_raise_invalid_args_error(options)
|
231
|
+
raise unless block_given?
|
232
|
+
|
233
|
+
message = "Invalid arguments '#{options}' passed to 'jekyll-twitter-plugin'. Please see 'https://github.com/rob-murray/jekyll-twitter-plugin' for usage."
|
234
|
+
expect do
|
235
|
+
yield
|
236
|
+
end.to raise_error(ArgumentError, message)
|
237
|
+
end
|
238
|
+
|
239
|
+
# The twitter gem responds with a struct like object so we do too.
|
240
|
+
def build_response_object(response)
|
241
|
+
OpenStruct.new(response)
|
242
|
+
end
|
243
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jekyll-twitter-plugin
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rob Murray
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-09-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '1.
|
19
|
+
version: '1.6'
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '1.
|
26
|
+
version: '1.6'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rake
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -39,7 +39,21 @@ dependencies:
|
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: byebug
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
44
58
|
requirements:
|
45
59
|
- - ">="
|
@@ -58,14 +72,14 @@ dependencies:
|
|
58
72
|
requirements:
|
59
73
|
- - "~>"
|
60
74
|
- !ruby/object:Gem::Version
|
61
|
-
version: '5.
|
75
|
+
version: '5.16'
|
62
76
|
type: :runtime
|
63
77
|
prerelease: false
|
64
78
|
version_requirements: !ruby/object:Gem::Requirement
|
65
79
|
requirements:
|
66
80
|
- - "~>"
|
67
81
|
- !ruby/object:Gem::Version
|
68
|
-
version: '5.
|
82
|
+
version: '5.16'
|
69
83
|
description:
|
70
84
|
email:
|
71
85
|
- robmurray17@gmail.com
|
@@ -74,12 +88,21 @@ extensions: []
|
|
74
88
|
extra_rdoc_files: []
|
75
89
|
files:
|
76
90
|
- ".gitignore"
|
91
|
+
- ".rspec"
|
92
|
+
- ".rubocop.yml"
|
93
|
+
- ".travis.yml"
|
77
94
|
- Gemfile
|
78
95
|
- LICENSE
|
79
96
|
- README.md
|
80
97
|
- Rakefile
|
81
98
|
- jekyll-twitter-plugin.gemspec
|
82
99
|
- lib/jekyll-twitter-plugin.rb
|
100
|
+
- spec/integration_tests.rb
|
101
|
+
- spec/oembed_spec.rb
|
102
|
+
- spec/spec_helper.rb
|
103
|
+
- spec/support/jekyll_template.rb
|
104
|
+
- spec/support/shared_contexts.rb
|
105
|
+
- spec/twitter_tag_spec.rb
|
83
106
|
homepage: https://github.com/rob-murray/jekyll-twitter-plugin
|
84
107
|
licenses:
|
85
108
|
- MIT
|
@@ -92,7 +115,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
92
115
|
requirements:
|
93
116
|
- - ">="
|
94
117
|
- !ruby/object:Gem::Version
|
95
|
-
version:
|
118
|
+
version: 1.9.3
|
96
119
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
97
120
|
requirements:
|
98
121
|
- - ">="
|
@@ -100,8 +123,14 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
100
123
|
version: '0'
|
101
124
|
requirements: []
|
102
125
|
rubyforge_project:
|
103
|
-
rubygems_version: 2.
|
126
|
+
rubygems_version: 2.5.1
|
104
127
|
signing_key:
|
105
128
|
specification_version: 4
|
106
129
|
summary: A Liquid tag plugin for Jekyll that renders Tweets from Twitter API
|
107
|
-
test_files:
|
130
|
+
test_files:
|
131
|
+
- spec/integration_tests.rb
|
132
|
+
- spec/oembed_spec.rb
|
133
|
+
- spec/spec_helper.rb
|
134
|
+
- spec/support/jekyll_template.rb
|
135
|
+
- spec/support/shared_contexts.rb
|
136
|
+
- spec/twitter_tag_spec.rb
|