social_linker 0.4.0.2 → 0.5.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 +17 -5
- data/app/helpers/view_helpers.rb +37 -5
- data/lib/social_linker.rb +1 -0
- data/lib/social_linker/engine.rb +1 -0
- data/lib/social_linker/subject.rb +97 -47
- data/lib/social_linker/version.rb +2 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c0dbc4dbe4ad685bd7760c48fe3dac052a188032
|
4
|
+
data.tar.gz: f16384779b4de79aa9967b7725eb4cc7513a4f99
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dee63ce241837647b68683a93f3bd285163b8d0d5511b03c6a794aa6689f7a81b1eef3e10c28c9468a179107fa956a578d88e48b3afb354376bf1a4f57c8dc5a
|
7
|
+
data.tar.gz: 4e0d002887b6b7aba2959883a31ae2bedba65483c3f099657a59fd486907bf2190143c6ed1d5995270506d7c873ab717950cbc4d5b5444461b7430733761a123
|
data/README.md
CHANGED
@@ -56,7 +56,7 @@ Which will deliver you the following url:
|
|
56
56
|
The supported options are:
|
57
57
|
|
58
58
|
* url
|
59
|
-
* media (media url, e.g. an image (
|
59
|
+
* media (media url, e.g. an image (shared only for Pinterest, but also used in OpenGraph headers & Twitter Cards))
|
60
60
|
* summary
|
61
61
|
* description
|
62
62
|
* title
|
@@ -76,8 +76,8 @@ For example:
|
|
76
76
|
@subject = SocialLinker::Subject.new(
|
77
77
|
title: "title",
|
78
78
|
url: "https://murb.nl/blog",
|
79
|
-
|
80
|
-
|
79
|
+
media: "https://murb.nl/image.jpg",
|
80
|
+
media_dimensions: [640, 480],
|
81
81
|
summary: "short summary",
|
82
82
|
tags: ["key1", "key2", "key3"],
|
83
83
|
)
|
@@ -97,12 +97,24 @@ ApplicationController. Later on you can merge details into this subject:
|
|
97
97
|
@subject.merge!({
|
98
98
|
title: "title",
|
99
99
|
url: "https://murb.nl/blog",
|
100
|
-
|
101
|
-
|
100
|
+
media: "https://murb.nl/image.jpg",
|
101
|
+
media_dimensions: [640, 480],
|
102
102
|
summary: "short summary",
|
103
103
|
tags: ["key1", "key2", "key3"]
|
104
104
|
})
|
105
105
|
|
106
|
+
*Hint*, the media_dimensions are 'compatible' with the output of the Dimensions-gem:
|
107
|
+
|
108
|
+
@subject.merge!({
|
109
|
+
title: @article.title,
|
110
|
+
url: article_url(@article),
|
111
|
+
media: @article.image.url(:inline),
|
112
|
+
media_dimensions: Dimensions.dimensions(@article.image.path(:inline)),
|
113
|
+
summary: @article.description,
|
114
|
+
tags: @article.tag_list.to_a
|
115
|
+
})
|
116
|
+
|
117
|
+
|
106
118
|
### Creating share links
|
107
119
|
|
108
120
|
|
data/app/helpers/view_helpers.rb
CHANGED
@@ -1,11 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module ViewHelpers
|
2
3
|
# renders a metatag
|
3
4
|
# param [String, Symbol] name (or property) (defaults to name, values starting with 'og:' (opengraph) will be using the property attribute)
|
4
5
|
# param [String, Symbol] content (the value for the name or the property)
|
5
6
|
# @returns [String, nil] nil is returned when the content is empty
|
6
7
|
def meta_tag(name, content)
|
7
|
-
|
8
|
-
name = erb_sanitized(name)
|
8
|
+
key_value_pairs = {}
|
9
9
|
name_or_property_attribute = if (name.start_with?("og:") or name.start_with?("fb:"))
|
10
10
|
"property"
|
11
11
|
elsif ['Content-Language'].include? name
|
@@ -13,7 +13,27 @@ module ViewHelpers
|
|
13
13
|
else
|
14
14
|
"name"
|
15
15
|
end
|
16
|
-
|
16
|
+
key_value_pairs[name_or_property_attribute] = name
|
17
|
+
key_value_pairs[:content] = content
|
18
|
+
tag_if(:meta, key_value_pairs, :content)
|
19
|
+
end
|
20
|
+
|
21
|
+
# renders a tag conditionally (if value is said)
|
22
|
+
# param [String, Symbol] tagname of the tag
|
23
|
+
# param [Hash] key value pairs (the attributes and their corresponding values
|
24
|
+
# param [String, Symbol] if_key is the key to be checked for containing a value, otherwise nil is returned, defaults to :content
|
25
|
+
# @returns [String, nil] nil is returned when the if_key is empty
|
26
|
+
def tag_if(tagname, key_value_pairs, if_key=:content)
|
27
|
+
tag = tagname.to_sym
|
28
|
+
critical_value = key_value_pairs[if_key]
|
29
|
+
if critical_value and critical_value.to_s.strip != ""
|
30
|
+
attribs = key_value_pairs.collect do |k,v|
|
31
|
+
key = erb_sanitized(k)
|
32
|
+
value = erb_sanitized(v)
|
33
|
+
rv = "#{key}=\"#{value}\""
|
34
|
+
end.join(" ")
|
35
|
+
"<#{tag} #{attribs} />"
|
36
|
+
end
|
17
37
|
end
|
18
38
|
|
19
39
|
def erb_sanitized(value)
|
@@ -40,8 +60,15 @@ module ViewHelpers
|
|
40
60
|
|
41
61
|
header_html = []
|
42
62
|
|
63
|
+
# <link href="https://plus.google.com/+YourPage" rel="publisher">
|
64
|
+
# <meta itemprop="name" content="Content Title">
|
65
|
+
# <meta itemprop="description" content="Content description less than 200 characters">
|
66
|
+
# <meta itemprop="image" content="http://example.com/image.jpg">
|
67
|
+
# =
|
68
|
+
|
43
69
|
header_html << meta_tag("twitter:site", options[:twitter_username])
|
44
70
|
header_html << meta_tag("twitter:creator", options[:twitter_username])
|
71
|
+
header_html << tag_if(:link, {href: "https://plus.google.com/+#{options[:google_plus_name]}", rel: "publisher"}, :href) if options[:google_plus_name]
|
45
72
|
header_html << meta_tag("twitter:domain", domain)
|
46
73
|
header_html << meta_tag("Content-Language", language)
|
47
74
|
header_html << meta_tag("dc.language", language)
|
@@ -61,12 +88,15 @@ module ViewHelpers
|
|
61
88
|
|
62
89
|
header_html << meta_tag("twitter:description", subject.summary(true))
|
63
90
|
header_html << meta_tag("og:description", subject.summary(false))
|
64
|
-
|
91
|
+
header_html << tag_if(:meta, {itemprop: :description, content: subject.summary(false)})
|
65
92
|
|
66
93
|
if subject.media
|
67
94
|
header_html << meta_tag("twitter:image:src", subject.media)
|
68
95
|
header_html << meta_tag("og:image", subject.media)
|
69
|
-
header_html << meta_tag("og:image:
|
96
|
+
header_html << meta_tag("og:image:width", subject.media_width)
|
97
|
+
header_html << meta_tag("og:image:height", subject.media_height)
|
98
|
+
header_html << meta_tag("og:image:type", subject.image_type)
|
99
|
+
header_html << tag_if(:meta, {itemprop: :image, content: subject.media})
|
70
100
|
end
|
71
101
|
end
|
72
102
|
|
@@ -77,6 +107,8 @@ module ViewHelpers
|
|
77
107
|
header_html << meta_tag("twitter:title", title)
|
78
108
|
header_html << meta_tag("og:title", title)
|
79
109
|
header_html << meta_tag("og:site_name", site_name)
|
110
|
+
header_html << tag_if(:meta, {itemprop: :name, content: site_title}, :content)
|
111
|
+
|
80
112
|
|
81
113
|
header_html.compact!
|
82
114
|
header_html = header_html.join("\n") if header_html
|
data/lib/social_linker.rb
CHANGED
data/lib/social_linker/engine.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module SocialLinker
|
2
3
|
class Subject
|
3
4
|
|
@@ -77,12 +78,60 @@ module SocialLinker
|
|
77
78
|
@options[:image_url]
|
78
79
|
end
|
79
80
|
|
80
|
-
def
|
81
|
+
def media_dimensions
|
82
|
+
return @media_dimensions if @media_dimensions
|
83
|
+
if media
|
84
|
+
@media_dimensions = @options[:media_dimensions]
|
85
|
+
if @media_dimensions.is_a? Array
|
86
|
+
@media_dimensions = {
|
87
|
+
width: @media_dimensions[0],
|
88
|
+
height: @media_dimensions[1]
|
89
|
+
}
|
90
|
+
end
|
91
|
+
@media_dimensions ||= {
|
92
|
+
width: @options[:media_width],
|
93
|
+
height: @options[:media_height]
|
94
|
+
}
|
95
|
+
else
|
96
|
+
@media_dimensions = {}
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def media_width
|
101
|
+
media_dimensions[:width].to_i if media_dimensions[:width]
|
102
|
+
end
|
103
|
+
|
104
|
+
def media_height
|
105
|
+
media_dimensions[:height].to_i if media_dimensions[:height]
|
106
|
+
end
|
107
|
+
|
108
|
+
def utm_parameters?
|
81
109
|
[nil, true].include?(@options[:utm_parameters]) ? true : false
|
82
110
|
end
|
83
111
|
|
112
|
+
def utm_parameters
|
113
|
+
if utm_parameters?
|
114
|
+
{
|
115
|
+
utm_source: "<%=share_source%>",
|
116
|
+
utm_medium: "share_link",
|
117
|
+
utm_campaign: "social"
|
118
|
+
}
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
84
122
|
def canonical_url
|
85
|
-
@options[:canonical_url]
|
123
|
+
prefix_domain((@options[:canonical_url] || @options[:url]), @options[:domain])
|
124
|
+
end
|
125
|
+
|
126
|
+
def share_url
|
127
|
+
url_to_share = prefix_domain((@options[:share_url] || @options[:url]), @options[:domain])
|
128
|
+
if utm_parameters?
|
129
|
+
utm_url_params = utm_parameters.collect{|k,v| "#{k}=#{v}" unless url_to_share.match(k.to_s)}.compact.join("&")
|
130
|
+
combine_with = url_to_share.match(/\?/) ? "&" : "?"
|
131
|
+
return "#{url_to_share}#{combine_with}#{utm_url_params}"
|
132
|
+
else
|
133
|
+
return url_to_share
|
134
|
+
end
|
86
135
|
end
|
87
136
|
|
88
137
|
# default title accessor
|
@@ -94,7 +143,8 @@ module SocialLinker
|
|
94
143
|
# default summary accessor
|
95
144
|
# @return String with summary
|
96
145
|
def summary(strip=false)
|
97
|
-
|
146
|
+
summ = @options[:summary] || @options[:description]
|
147
|
+
strip ? strip_string(summ, 300) : summ
|
98
148
|
end
|
99
149
|
|
100
150
|
# default media accessor
|
@@ -103,6 +153,23 @@ module SocialLinker
|
|
103
153
|
@options[:media]
|
104
154
|
end
|
105
155
|
|
156
|
+
def filename_derived_image_type
|
157
|
+
if media
|
158
|
+
extension = media.to_s.split(".").last.downcase
|
159
|
+
if extension == "jpg" or extension == "jpeg"
|
160
|
+
"image/jpeg"
|
161
|
+
elsif extension == "png"
|
162
|
+
"image/png"
|
163
|
+
elsif extension == "gif"
|
164
|
+
"image/gif"
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
def image_type
|
170
|
+
@options[:image_type] || filename_derived_image_type
|
171
|
+
end
|
172
|
+
|
106
173
|
# default tags accessor
|
107
174
|
# @return Array<String> with tags
|
108
175
|
def tags
|
@@ -142,6 +209,7 @@ module SocialLinker
|
|
142
209
|
# * url
|
143
210
|
# * title
|
144
211
|
# * image_url & image_type(image/jpeg, image/png)
|
212
|
+
# * width and height for the images
|
145
213
|
# * description
|
146
214
|
# * facebook_app_id
|
147
215
|
# * twitter_username
|
@@ -180,38 +248,18 @@ module SocialLinker
|
|
180
248
|
# @return SocialLinker::Subject (self)
|
181
249
|
def merge!(options)
|
182
250
|
options = options.options if options.is_a? SocialLinker::Subject
|
251
|
+
options[:render_site_title_postfix] = true if options[:render_site_title_postfix].nil?
|
252
|
+
options[:u] ||= options[:url]
|
253
|
+
options[:media] ||= options[:image_url]
|
254
|
+
options[:title] ||= "#{ strip_string(options[:summary], 120) }"
|
255
|
+
options[:subject] ||= options[:title]
|
256
|
+
options[:via] ||= options[:twitter_username]
|
257
|
+
options[:url] ||= options[:media]
|
258
|
+
options[:text] = "#{options[:title]} #{options[:url]}" unless options[:text] #facebook & whatsapp native
|
259
|
+
options[:domain] = options[:url].split(/\//)[0..2].join("/") if options[:url] and !options[:domain]
|
260
|
+
options.select!{|k,v| !v.nil?}
|
183
261
|
@options.merge!(options)
|
184
|
-
|
185
|
-
@options[:u] = @options[:url] unless @options[:u]
|
186
|
-
@options[:media] = @options[:image_url] unless @options[:media]
|
187
|
-
@options[:description] = @options[:summary] unless @options[:description]
|
188
|
-
@options[:summary] = @options[:description] unless @options[:summary]
|
189
|
-
@options[:title] = "#{ strip_string(@options[:summary], 120) }" unless @options[:title]
|
190
|
-
@options[:description] = @options[:title] unless @options[:description]
|
191
|
-
@options[:subject] = @options[:title] unless @options[:subject]
|
192
|
-
@options[:via] = @options[:twitter_username] unless @options[:via]
|
193
|
-
@options[:url] = @options[:media] unless @options[:url]
|
194
|
-
raise ArgumentError, "#{url} is not a valid url" if @options[:url] and !@options[:url].include?('//')
|
195
|
-
|
196
|
-
@options[:text] = "#{@options[:title]} #{@options[:url]}" unless @options[:text] #facebook & whatsapp native
|
197
|
-
@options[:canonical_url] = @options[:url]
|
198
|
-
@options[:share_url] = @options[:url]
|
199
|
-
@options[:domain] = @options[:url].split(/\//)[0..2].join("/") if @options[:url] and !@options[:domain]
|
200
|
-
|
201
|
-
if @options[:share_url] and utm_parameters
|
202
|
-
unless @options[:share_url].match /utm_source/
|
203
|
-
combine_with = @options[:share_url].match(/\?/) ? "&" : "?"
|
204
|
-
@options[:share_url] = "#{@options[:share_url]}#{combine_with}utm_source=<%=share_source%>"
|
205
|
-
end
|
206
|
-
unless @options[:share_url].match /utm_medium/
|
207
|
-
combine_with = "&"
|
208
|
-
@options[:share_url] = "#{@options[:share_url]}#{combine_with}utm_medium=share_link"
|
209
|
-
end
|
210
|
-
unless @options[:share_url].match /utm_campaign/
|
211
|
-
combine_with = "&"
|
212
|
-
@options[:share_url] = "#{@options[:share_url]}#{combine_with}utm_campaign=social"
|
213
|
-
end
|
214
|
-
end
|
262
|
+
|
215
263
|
if @options[:tags]
|
216
264
|
@options[:tags].compact!
|
217
265
|
@options[:hashtags] = @options[:tags][0..1].collect{|a| camelize_tag_when_needed(a) }.join(",") if @options[:tags] and !@options[:hashtags]
|
@@ -219,8 +267,6 @@ module SocialLinker
|
|
219
267
|
|
220
268
|
# make sure urls are absolute
|
221
269
|
@options[:url] = prefix_domain(@options[:url],@options[:domain])
|
222
|
-
@options[:share_url] = prefix_domain(@options[:share_url],@options[:domain])
|
223
|
-
@options[:canonical_url] = prefix_domain(@options[:canonical_url],@options[:domain])
|
224
270
|
@options[:image_url] = prefix_domain(@options[:image_url],@options[:domain])
|
225
271
|
@options[:media] = prefix_domain(@options[:media],@options[:domain])
|
226
272
|
|
@@ -236,16 +282,20 @@ module SocialLinker
|
|
236
282
|
def body
|
237
283
|
return options[:body] if options[:body]
|
238
284
|
rv = ""
|
239
|
-
rv += "#{
|
240
|
-
rv += "\n#{
|
241
|
-
rv += "\n#{
|
242
|
-
rv += "\n#{@options[:media]}\n" if options[:media] !=
|
285
|
+
rv += "#{summary}\n" if summary
|
286
|
+
rv += "\n#{share_url}\n" if share_url
|
287
|
+
rv += "\n#{description}\n" if summary != description and description
|
288
|
+
rv += "\n#{@options[:media]}\n" if options[:media] != share_url and options[:media]
|
243
289
|
rv += "\n\n#{hashtag_string(@options[:tags])}" if options[:tags]
|
244
290
|
rv.strip!
|
245
291
|
rv = nil if rv == ""
|
246
292
|
return rv
|
247
293
|
end
|
248
294
|
|
295
|
+
def description
|
296
|
+
@options[:description] || @options[:summary]
|
297
|
+
end
|
298
|
+
|
249
299
|
# Turns the first two tags in to tweetable hash tags
|
250
300
|
# Conform recommendation never to have more than 2 tags in a twitter message
|
251
301
|
# @return String with two tags as #tags.
|
@@ -278,13 +328,14 @@ module SocialLinker
|
|
278
328
|
# @param [String] domain of the file
|
279
329
|
# @return String with full url
|
280
330
|
def prefix_domain path, domain
|
281
|
-
return_string = path
|
282
331
|
if path and !path.include?("//")
|
283
|
-
|
284
|
-
|
285
|
-
|
332
|
+
return [
|
333
|
+
domain.gsub(/\/$/,''),
|
334
|
+
path.gsub(/^\//,'')
|
335
|
+
].join("/")
|
336
|
+
else
|
337
|
+
return path
|
286
338
|
end
|
287
|
-
return_string
|
288
339
|
end
|
289
340
|
|
290
341
|
# Returns the given options, extended with the (derived) defaults
|
@@ -331,5 +382,4 @@ module SocialLinker
|
|
331
382
|
end
|
332
383
|
end
|
333
384
|
end
|
334
|
-
end
|
335
|
-
|
385
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: social_linker
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- murb
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-10-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|