opengraphplus 0.1.2 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 84dcc38250134ee587a8c981aab111e6cc13114455f69f6aff9eb3c90a2333bf
4
- data.tar.gz: 14ff03291f508e0a7d91d1e104b9f8f647e6430885eb3e644b8cc96942aa1f8e
3
+ metadata.gz: 7d947ee47bc0e434395f69cceb99321f78ab4f8ac437f5b537b97ffa9a199d51
4
+ data.tar.gz: 308d3466e160b11f935afd3b9f0c891ba3b268f95f3de12400af9e815020a82f
5
5
  SHA512:
6
- metadata.gz: b3d569b9fc677192c068379c45cb3b7206f3f39c88d024404beb0d91fab470e4c2862b099936ceb2b5c3d8edc857694f85305121a9d438422a39bb8f3a77b106
7
- data.tar.gz: 1627854d4aa87fe61df5c98b803b4788adbe2118732334753b5d117b76bd1abe493ef9848974a48941a716431dcd6c5a2f1a9f1909b45a8a4f95a297307ddcd0
6
+ metadata.gz: ac3f345867d3cc9e5ad6fa1745f5f6ea45cf505fdd057191c0af0d48ca62d8af6e64aa7dfa26b2097f8d97af95fab8dec9888a37b00a573bc94c5ad68660c6c3
7
+ data.tar.gz: 9a20a378f2e36d594667c2abdba8e194bdcae2bc55a2daf33bf1195162b9c9498ca257e426e645ae85a3087cc0f80b83ff9f7065f730cc240564daf7617e58e7
@@ -2,12 +2,14 @@
2
2
 
3
3
  module OpenGraphPlus
4
4
  class Configuration
5
- attr_reader :api_key
6
-
7
5
  def initialize
8
6
  @api_key = nil
9
7
  end
10
8
 
9
+ def api_key
10
+ @api_key or warn "[OpenGraphPlus] API key not configured. Set OpenGraphPlus.configuration.api_key to enable automatic Open Graph image generation."
11
+ end
12
+
11
13
  def api_key=(value)
12
14
  @api_key = value.is_a?(APIKey) ? value : APIKey.parse(value)
13
15
  end
@@ -6,11 +6,20 @@ module OpenGraphPlus
6
6
 
7
7
  def initialize(request)
8
8
  @request = request
9
- @signature_url = Signature::URL.new
10
9
  end
11
10
 
12
11
  def url
13
- @signature_url.build("/opengraph", url: request.original_url)
12
+ return nil unless api_key
13
+
14
+ Signature::URL.new
15
+ .signed_path("/api/websites/v1", api_key)
16
+ .build("image", url: request.original_url)
17
+ end
18
+
19
+ private
20
+
21
+ def api_key
22
+ @api_key ||= OpenGraphPlus.configuration.api_key
14
23
  end
15
24
  end
16
25
  end
@@ -0,0 +1,189 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "forwardable"
4
+
5
+ module OpenGraphPlus
6
+ module Namespace
7
+ class Base
8
+ include Enumerable
9
+
10
+ def each(&block) = tags.each(&block)
11
+
12
+ def tag(property, value)
13
+ Tag.new(property, value) if value
14
+ end
15
+
16
+ def render_in(_view_context = nil)
17
+ map { |tag| tag.render_in }.join("\n").html_safe
18
+ end
19
+
20
+ def update(**kwargs)
21
+ kwargs.each { |key, value| public_send(:"#{key}=", value) }
22
+ self
23
+ end
24
+ end
25
+
26
+ class Image < Base
27
+ attr_accessor :url, :secure_url, :type, :width, :height, :alt
28
+
29
+ def tags
30
+ [
31
+ tag("og:image", url),
32
+ tag("og:image:secure_url", secure_url),
33
+ tag("og:image:type", type),
34
+ tag("og:image:width", width),
35
+ tag("og:image:height", height),
36
+ tag("og:image:alt", alt)
37
+ ].compact
38
+ end
39
+ end
40
+
41
+ class Viewport < Base
42
+ attr_accessor :width
43
+
44
+ def tags
45
+ [
46
+ tag("og:plus:viewport:width", width)
47
+ ].compact
48
+ end
49
+ end
50
+
51
+ class Plus < Base
52
+ attr_accessor :selector, :style
53
+
54
+ def style=(value)
55
+ @style = case value
56
+ when Hash
57
+ hash_to_css(value)
58
+ else
59
+ value
60
+ end
61
+ end
62
+
63
+ def viewport
64
+ @viewport ||= Viewport.new
65
+ end
66
+
67
+ def tags
68
+ [
69
+ tag("og:plus:selector", selector),
70
+ tag("og:plus:style", style),
71
+ *viewport.tags
72
+ ].compact
73
+ end
74
+
75
+ private
76
+
77
+ def hash_to_css(hash)
78
+ hash.map { |k, v| "#{k.to_s.tr("_", "-")}: #{v}" }.join("; ")
79
+ end
80
+ end
81
+
82
+ class OG < Base
83
+ attr_accessor :title, :description, :url, :type, :site_name, :locale, :determiner, :audio, :video
84
+
85
+ def initialize
86
+ @type = "website"
87
+ end
88
+
89
+ def image
90
+ @image ||= Image.new
91
+ end
92
+
93
+ def plus
94
+ @plus ||= Plus.new
95
+ end
96
+
97
+ def image_url=(url)
98
+ image.url = url
99
+ image.secure_url = url
100
+ end
101
+
102
+ def tags
103
+ [
104
+ tag("og:title", title),
105
+ tag("og:description", description),
106
+ tag("og:url", url),
107
+ tag("og:type", type),
108
+ tag("og:site_name", site_name),
109
+ tag("og:locale", locale),
110
+ tag("og:determiner", determiner),
111
+ tag("og:audio", audio),
112
+ tag("og:video", video),
113
+ *image.tags,
114
+ *plus.tags
115
+ ].compact
116
+ end
117
+ end
118
+
119
+ class Twitter < Base
120
+ class Image < Base
121
+ attr_accessor :url, :alt
122
+
123
+ def tags
124
+ [
125
+ tag("twitter:image", url),
126
+ tag("twitter:image:alt", alt)
127
+ ].compact
128
+ end
129
+ end
130
+
131
+ attr_accessor :card, :site, :creator, :title, :description
132
+
133
+ def initialize
134
+ @card = "summary_large_image"
135
+ end
136
+
137
+ def image
138
+ @image ||= Image.new
139
+ end
140
+
141
+ def image_url=(url)
142
+ image.url = url
143
+ end
144
+
145
+ def tags
146
+ [
147
+ tag("twitter:card", card),
148
+ tag("twitter:site", site),
149
+ tag("twitter:creator", creator),
150
+ tag("twitter:title", title),
151
+ tag("twitter:description", description),
152
+ *image.tags
153
+ ].compact
154
+ end
155
+ end
156
+
157
+ class Root < Base
158
+ extend Forwardable
159
+
160
+ def og
161
+ @og ||= OG.new
162
+ end
163
+
164
+ def twitter
165
+ @twitter ||= Twitter.new
166
+ end
167
+
168
+ def tags
169
+ [*og.tags, *twitter.tags]
170
+ end
171
+
172
+ def_delegators :og,
173
+ :title, :title=,
174
+ :description, :description=,
175
+ :url, :url=,
176
+ :type, :type=,
177
+ :site_name, :site_name=,
178
+ :locale, :locale=,
179
+ :determiner, :determiner=,
180
+ :audio, :audio=,
181
+ :video, :video=,
182
+ :image, :image_url=,
183
+ :plus
184
+ end
185
+ end
186
+
187
+ # Backwards compatibility
188
+ Tags = Namespace
189
+ end
@@ -4,9 +4,11 @@ module OpenGraphPlus
4
4
  module Rails
5
5
  module Controller
6
6
  extend ActiveSupport::Concern
7
+ include OpenGraphPlus::Rails::Helper
7
8
 
8
9
  included do
9
10
  helper_method :open_graph, :open_graph_tags, :open_graph_meta_tags
11
+ before_action :set_default_open_graph
10
12
  append_before_action :set_default_open_graph_image
11
13
  end
12
14
 
@@ -22,14 +24,17 @@ module OpenGraphPlus
22
24
 
23
25
  private
24
26
 
27
+ def set_default_open_graph
28
+ open_graph.type = "website"
29
+ open_graph.url = request.original_url
30
+ end
31
+
25
32
  def set_default_open_graph_image
26
33
  return if open_graph.image.url
27
34
 
28
35
  generated_url = open_graph_image_generator.url
29
36
  open_graph.image.url = generated_url if generated_url
30
37
  end
31
-
32
- include Helper
33
38
  end
34
39
  end
35
40
  end
@@ -3,21 +3,19 @@
3
3
  module OpenGraphPlus
4
4
  module Rails
5
5
  module Helper
6
- def open_graph(**kwargs)
7
- @open_graph_root ||= Tags::Root.new
8
- @open_graph_root.update(**kwargs) if kwargs.any?
9
- yield(@open_graph_root) if block_given?
6
+ def open_graph(**)
7
+ @open_graph_root ||= Namespace::Root.new
8
+ @open_graph_root.update(**)
9
+ yield @open_graph_root if block_given?
10
10
  @open_graph_root
11
11
  end
12
12
 
13
13
  def open_graph_tags
14
- root = @open_graph_root || Tags::Root.new
15
- Tags::Renderer.new(root).tags
14
+ open_graph.to_a
16
15
  end
17
16
 
18
17
  def open_graph_meta_tags
19
- result = open_graph_tags.map(&:to_s).join("\n")
20
- result.respond_to?(:html_safe) ? result.html_safe : result
18
+ open_graph.render_in(self)
21
19
  end
22
20
  end
23
21
  end
@@ -6,10 +6,21 @@ require "base64"
6
6
  module OpenGraphPlus
7
7
  module Signature
8
8
  class Generator
9
+ class InvalidAPIKeyError < StandardError; end
10
+
9
11
  attr_reader :api_key
10
12
 
11
13
  def initialize(api_key)
12
- @api_key = api_key
14
+ @api_key = case api_key
15
+ when APIKey
16
+ api_key
17
+ when String
18
+ APIKey.parse(api_key)
19
+ end
20
+
21
+ raise InvalidAPIKeyError, "API key is missing or invalid" unless @api_key
22
+ raise InvalidAPIKeyError, "API key is missing public_key" unless @api_key.public_key
23
+ raise InvalidAPIKeyError, "API key is missing secret_key" unless @api_key.secret_key
13
24
  end
14
25
 
15
26
  def generate(path_and_query)
@@ -6,57 +6,40 @@ module OpenGraphPlus
6
6
  module Signature
7
7
  class URL
8
8
  DEFAULT_BASE_URL = "https://opengraphplus.com"
9
- DEFAULT_PATH_PREFIX = "/v2/:signature"
10
9
 
11
- attr_reader :base_uri, :path_prefix
10
+ attr_reader :base_uri
12
11
 
13
- def initialize(api_key: nil, generator: nil, base_url: nil, path_prefix: DEFAULT_PATH_PREFIX)
14
- @api_key = api_key
15
- @generator = generator
12
+ def initialize(base_url: nil)
16
13
  @base_uri = URI.parse(base_url || ENV.fetch("OPENGRAPHPLUS_URL", DEFAULT_BASE_URL))
17
- @path_prefix = path_prefix
18
14
  end
19
15
 
20
- def build(path, **params)
21
- return nil unless generator
22
-
23
- path_and_query = build_path_and_query(path, params)
24
- signature = generator.generate(path_and_query)
25
-
26
- base_uri.dup.tap do |uri|
27
- uri.path = signed_path(signature, path)
28
- uri.query = URI.encode_www_form(params) unless params.empty?
29
- end.to_s
30
- end
31
-
32
- def generator
33
- @generator ||= begin
34
- api_key = @api_key || OpenGraphPlus.configuration.api_key
35
- if api_key
36
- Generator.new(api_key)
37
- else
38
- warn_missing_api_key
39
- nil
40
- end
41
- end
16
+ def signed_path(prefix, api_key)
17
+ SignedPath.new(prefix:, api_key:, base_uri:)
42
18
  end
19
+ end
43
20
 
44
- private
21
+ class SignedPath
22
+ attr_reader :prefix, :api_key, :base_uri
45
23
 
46
- def build_path_and_query(path, params)
47
- normalized_path = File.join("/", path)
48
- params.empty? ? normalized_path : "#{normalized_path}?#{URI.encode_www_form(params)}"
24
+ def initialize(prefix:, api_key:, base_uri:)
25
+ @prefix = prefix
26
+ @api_key = api_key
27
+ @base_uri = base_uri
49
28
  end
50
29
 
51
- def signed_path(signature, path)
52
- File.join(path_prefix.gsub(":signature", signature), path)
30
+ def generator
31
+ @generator ||= Generator.new(api_key)
53
32
  end
54
33
 
55
- def warn_missing_api_key
56
- return if @warned
34
+ def build(*segments, **params)
35
+ signed_path = File.join("/", *segments.map(&:to_s))
36
+ path_and_query = params.empty? ? signed_path : "#{signed_path}?#{URI.encode_www_form(params)}"
37
+ signature = generator.generate(path_and_query)
57
38
 
58
- warn "[OpenGraphPlus] API key not configured. Set OpenGraphPlus.configuration.api_key to enable automatic Open Graph image generation."
59
- @warned = true
39
+ base_uri.dup.tap do |uri|
40
+ uri.path = File.join(prefix, signature, *segments.map(&:to_s))
41
+ uri.query = URI.encode_www_form(params) unless params.empty?
42
+ end.to_s
60
43
  end
61
44
  end
62
45
  end
@@ -15,15 +15,8 @@ module OpenGraphPlus
15
15
  %(<meta property="#{escape property}" content="#{escape content}">)
16
16
  end
17
17
 
18
- def render_in(view_context = nil)
19
- result = meta
20
- if view_context.respond_to?(:raw)
21
- view_context.raw(result)
22
- elsif result.respond_to?(:html_safe)
23
- result.html_safe
24
- else
25
- result
26
- end
18
+ def render_in(_view_context = nil)
19
+ meta.html_safe
27
20
  end
28
21
 
29
22
  def to_s
@@ -5,6 +5,25 @@ require "forwardable"
5
5
  module OpenGraphPlus
6
6
  module Tags
7
7
  class Base
8
+ include Enumerable
9
+
10
+ def each(&block)
11
+ tags.each do |t|
12
+ case t
13
+ when Base
14
+ t.each(&block)
15
+ when Tag
16
+ yield t if t.content
17
+ end
18
+ end
19
+ end
20
+
21
+ def tags = []
22
+
23
+ def render_in(view_context)
24
+ map { |tag| tag.render_in(view_context) }.join("\n")
25
+ end
26
+
8
27
  def update(**kwargs)
9
28
  kwargs.each { |key, value| public_send(:"#{key}=", value) }
10
29
  self
@@ -13,29 +32,16 @@ module OpenGraphPlus
13
32
 
14
33
  class Image < Base
15
34
  attr_accessor :url, :width, :height, :type, :alt, :secure_url
16
- end
17
35
 
18
- class Twitter < Base
19
- attr_accessor :card, :site, :creator, :title, :description, :image, :image_alt
20
-
21
- def initialize
22
- @card = "summary_large_image"
23
- end
24
- end
25
-
26
- class OpenGraph < Base
27
- attr_accessor :title, :description, :url, :type, :site_name, :locale, :determiner, :audio, :video
28
- attr_reader :image, :plus
29
-
30
- def initialize
31
- @type = "website"
32
- @image = Image.new
33
- @plus = Plus.new
34
- end
35
-
36
- def image_url=(url)
37
- @image.url = url
38
- @image.secure_url = url
36
+ def tags
37
+ [
38
+ Tag.new("og:image", url),
39
+ Tag.new("og:image:secure_url", secure_url),
40
+ Tag.new("og:image:type", type),
41
+ Tag.new("og:image:width", width),
42
+ Tag.new("og:image:height", height),
43
+ Tag.new("og:image:alt", alt),
44
+ ]
39
45
  end
40
46
  end
41
47
 
@@ -52,6 +58,13 @@ module OpenGraphPlus
52
58
  end
53
59
  end
54
60
 
61
+ def tags
62
+ [
63
+ Tag.new("og:plus:selector", selector),
64
+ Tag.new("og:plus:style", style),
65
+ ]
66
+ end
67
+
55
68
  private
56
69
 
57
70
  def hash_to_css(hash)
@@ -59,12 +72,65 @@ module OpenGraphPlus
59
72
  end
60
73
  end
61
74
 
75
+ class OpenGraph < Base
76
+ attr_accessor :title, :description, :url, :type, :site_name, :locale, :determiner, :audio, :video
77
+
78
+ def image = @image ||= Image.new
79
+ def plus = @plus ||= Plus.new
80
+
81
+ def initialize
82
+ @type = "website"
83
+ end
84
+
85
+ def image_url=(url)
86
+ image.url = url
87
+ image.secure_url = url
88
+ end
89
+
90
+ def tags
91
+ [
92
+ Tag.new("og:title", title),
93
+ Tag.new("og:description", description),
94
+ Tag.new("og:url", url),
95
+ Tag.new("og:type", type),
96
+ Tag.new("og:site_name", site_name),
97
+ Tag.new("og:locale", locale),
98
+ Tag.new("og:determiner", determiner),
99
+ Tag.new("og:audio", audio),
100
+ Tag.new("og:video", video),
101
+ image,
102
+ plus,
103
+ ]
104
+ end
105
+ end
106
+
107
+ class Twitter < Base
108
+ attr_accessor :card, :site, :creator, :title, :description, :image, :image_alt
109
+
110
+ def initialize
111
+ @card = "summary_large_image"
112
+ end
113
+
114
+ def tags
115
+ [
116
+ Tag.new("twitter:card", card),
117
+ Tag.new("twitter:site", site),
118
+ Tag.new("twitter:creator", creator),
119
+ Tag.new("twitter:title", title),
120
+ Tag.new("twitter:description", description),
121
+ Tag.new("twitter:image", image),
122
+ Tag.new("twitter:image:alt", image_alt),
123
+ ]
124
+ end
125
+ end
126
+
62
127
  class Root < Base
63
128
  extend Forwardable
64
129
 
65
- attr_reader :og, :twitter
130
+ def og = @og ||= OpenGraph.new
131
+ def twitter = @twitter ||= Twitter.new
66
132
 
67
- def_delegators :@og,
133
+ def_delegators :og,
68
134
  :title, :title=,
69
135
  :description, :description=,
70
136
  :url, :url=,
@@ -77,9 +143,8 @@ module OpenGraphPlus
77
143
  :image, :image_url=,
78
144
  :plus
79
145
 
80
- def initialize
81
- @og = OpenGraph.new
82
- @twitter = Twitter.new
146
+ def tags
147
+ [og, twitter]
83
148
  end
84
149
  end
85
150
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module OpenGraphPlus
4
- VERSION = "0.1.2"
4
+ VERSION = "0.1.5"
5
5
  end
data/lib/opengraphplus.rb CHANGED
@@ -5,8 +5,7 @@ require_relative "opengraphplus/api_key"
5
5
  require_relative "opengraphplus/configuration"
6
6
  require_relative "opengraphplus/signature"
7
7
  require_relative "opengraphplus/tag"
8
- require_relative "opengraphplus/tags"
9
- require_relative "opengraphplus/tags/renderer"
8
+ require_relative "opengraphplus/namespace"
10
9
  require_relative "opengraphplus/image_generator"
11
10
 
12
11
  module OpenGraphPlus
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: opengraphplus
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brad Gessler
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2025-12-18 00:00:00.000000000 Z
10
+ date: 2026-01-07 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: activesupport
@@ -42,6 +42,7 @@ files:
42
42
  - lib/opengraphplus/api_key.rb
43
43
  - lib/opengraphplus/configuration.rb
44
44
  - lib/opengraphplus/image_generator.rb
45
+ - lib/opengraphplus/namespace.rb
45
46
  - lib/opengraphplus/rails.rb
46
47
  - lib/opengraphplus/rails/controller.rb
47
48
  - lib/opengraphplus/rails/helper.rb
@@ -55,7 +56,6 @@ files:
55
56
  - lib/opengraphplus/signature/verifier.rb
56
57
  - lib/opengraphplus/tag.rb
57
58
  - lib/opengraphplus/tags.rb
58
- - lib/opengraphplus/tags/renderer.rb
59
59
  - lib/opengraphplus/version.rb
60
60
  - sig/open_graph_plus.rbs
61
61
  homepage: https://opengraphplus.com/ruby
@@ -1,78 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module OpenGraphPlus
4
- module Tags
5
- class Renderer
6
- attr_reader :root
7
-
8
- def initialize(root)
9
- @root = root
10
- end
11
-
12
- def tags
13
- [*og_tags, *twitter_tags].compact
14
- end
15
-
16
- private
17
-
18
- def og
19
- root.og
20
- end
21
-
22
- def twitter
23
- root.twitter
24
- end
25
-
26
- def tag(property, content)
27
- return nil if content.nil?
28
-
29
- Tag.new(property, content)
30
- end
31
-
32
- def og_tags
33
- [
34
- tag("og:title", og.title),
35
- tag("og:description", og.description),
36
- tag("og:url", og.url),
37
- tag("og:type", og.type),
38
- tag("og:site_name", og.site_name),
39
- tag("og:locale", og.locale),
40
- tag("og:determiner", og.determiner),
41
- tag("og:audio", og.audio),
42
- tag("og:video", og.video),
43
- *og_image_tags
44
- ]
45
- end
46
-
47
- def og_image_tags
48
- return [] unless og.image
49
-
50
- image = og.image
51
- [
52
- tag("og:image", image.url),
53
- tag("og:image:secure_url", image.secure_url),
54
- tag("og:image:type", image.type),
55
- tag("og:image:width", image.width),
56
- tag("og:image:height", image.height),
57
- tag("og:image:alt", image.alt)
58
- ]
59
- end
60
-
61
- def twitter_tags
62
- [
63
- tag("twitter:card", twitter.card),
64
- tag("twitter:site", twitter.site),
65
- tag("twitter:creator", twitter.creator),
66
- tag("twitter:title", twitter.title || og.title),
67
- tag("twitter:description", twitter.description || og.description),
68
- tag("twitter:image", twitter_image_url),
69
- tag("twitter:image:alt", twitter.image_alt || og.image&.alt)
70
- ]
71
- end
72
-
73
- def twitter_image_url
74
- twitter.image || og.image&.url
75
- end
76
- end
77
- end
78
- end