og_pilot_ruby 0.2.1 → 0.3.1

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: 34c76008dde8c56d665a3eece4869fa7f28ec0ad656ef2cae798da373956d055
4
- data.tar.gz: 1a2e055c83968ed81d0ca747457403c865c045d37acd5694f9ac5fc221497d57
3
+ metadata.gz: 9624035f48941775c8b1e55637f9d20e6c65a10ffdcfe983ab47ef2ae53dae5d
4
+ data.tar.gz: 4889190ff785ff95df863f3e320fa17c04f08e1ae2f9772ffa405922440ec58f
5
5
  SHA512:
6
- metadata.gz: efb3af2ede82a7519c855dfd6e9bbbfc17940a22ce91a12f3bac1e3e63e65fba92e61b9554ba8e5f2a39cc47a2557ef215595b4776d71dbef1c232333cc5d16b
7
- data.tar.gz: e3f0bc81c47bfce15490c8348c0db2a32c601b6761200dd25487baf0294799890ebb5b7d864ebf44ea800f5d3a2f9393b433a19f8c8a0df117c2ed3d8a934dc2
6
+ metadata.gz: 8e43e439eea7e9a8684c77cbc591a94dabc41b40b4096b8ea06eba2a8a73cb680868f362360ede49242285e94902b0258439bf40c47ae5ca91206098c74eb6b6
7
+ data.tar.gz: 5b966815886946cf1af21c2028a1e9a0721a8c820df34557e8bdd047fc457fe7650b8b4848a5438ecf56dbb8cb0653519bdcf6b8a2999800ab29e9f4f2071a99
data/README.md CHANGED
@@ -28,6 +28,7 @@ Override as needed:
28
28
  OgPilotRuby.configure do |config|
29
29
  config.api_key = ENV.fetch("OG_PILOT_API_KEY")
30
30
  config.domain = ENV.fetch("OG_PILOT_DOMAIN")
31
+ # config.strip_extensions = true
31
32
  end
32
33
  ```
33
34
 
@@ -60,6 +61,30 @@ image_url = OgPilotRuby.create_image(
60
61
  If you omit `iat`, OG Pilot will cache the image indefinitely. Provide an `iat` to
61
62
  refresh the cache daily.
62
63
 
64
+ ### Template helpers
65
+
66
+ `create_image` defaults to the `page` template when `template` is omitted.
67
+
68
+ Use these helpers to force a specific template:
69
+
70
+ - `OgPilotRuby.create_blog_post_image(...)`
71
+ - `OgPilotRuby.create_podcast_image(...)`
72
+ - `OgPilotRuby.create_product_image(...)`
73
+ - `OgPilotRuby.create_event_image(...)`
74
+ - `OgPilotRuby.create_book_image(...)`
75
+ - `OgPilotRuby.create_company_image(...)`
76
+ - `OgPilotRuby.create_portfolio_image(...)`
77
+
78
+ Example:
79
+
80
+ ```ruby
81
+ image_url = OgPilotRuby.create_blog_post_image(
82
+ title: "How to Build Amazing OG Images",
83
+ author_name: "Jane Smith",
84
+ publish_date: "2024-01-15"
85
+ )
86
+ ```
87
+
63
88
  ## Parameters
64
89
 
65
90
  All parameters are embedded in the signed JWT payload; the only query param is `token`.
@@ -79,6 +104,17 @@ The gem handles `iss` (domain) and `sub` (API key prefix) automatically.
79
104
  | `iat` | No | — | Issued-at timestamp for daily cache busting |
80
105
  | `path` | No | auto-set | Request path for image rendering context. When provided, it overrides auto-resolution (see [Path handling](#path-handling)) |
81
106
 
107
+ ### Configuration options
108
+
109
+ | Option | Default | Description |
110
+ |--------------------|-------------------------|--------------------------------------------------------------------------|
111
+ | `api_key` | `ENV["OG_PILOT_API_KEY"]` | Your OG Pilot API key |
112
+ | `domain` | `ENV["OG_PILOT_DOMAIN"]` | Your domain registered with OG Pilot |
113
+ | `base_url` | `https://ogpilot.com` | OG Pilot API base URL |
114
+ | `open_timeout` | `5` | Connection timeout in seconds |
115
+ | `read_timeout` | `10` | Read timeout in seconds |
116
+ | `strip_extensions` | `true` | When `true`, file extensions are stripped from resolved paths (see [Strip extensions](#strip-extensions)) |
117
+
82
118
  ### Ruby options
83
119
 
84
120
  | Option | Default | Description |
@@ -137,12 +173,37 @@ Fetch JSON metadata instead:
137
173
  ```ruby
138
174
  payload = {
139
175
  template: "page",
140
- title: "Hello OG Pilot"
176
+ title: "Hello OG Pilot"q
141
177
  }
142
178
 
143
179
  data = OgPilotRuby.create_image(**payload, json: true)
144
180
  ```
145
181
 
182
+ ### Strip extensions
183
+
184
+ When `strip_extensions` is enabled, the client removes file extensions from the
185
+ last segment of every resolved path. This ensures that `/docs`, `/docs.md`,
186
+ `/docs.php`, and `/docs.html` all resolve to `"/docs"`, so analytics are
187
+ consolidated under a single path regardless of the URL extension.
188
+
189
+ Multiple extensions are also stripped (`/archive.tar.gz` becomes `/archive`).
190
+ Dotfiles like `/.hidden` are left unchanged. Query strings are preserved.
191
+
192
+ ```ruby
193
+ OgPilotRuby.configure do |config|›
194
+ config.strip_extensions = true
195
+ end
196
+
197
+ # All of these resolve to path "/docs":
198
+ OgPilotRuby.create_image(title: "Docs", path: "/docs")
199
+ OgPilotRuby.create_image(title: "Docs", path: "/docs.md")
200
+ OgPilotRuby.create_image(title: "Docs", path: "/docs.php")
201
+
202
+ # Nested paths work too: /blog/my-post.html → /blog/my-post
203
+ # Query strings are preserved: /docs.md?ref=main → /docs?ref=main
204
+ # Dotfiles are unchanged: /.hidden stays /.hidden
205
+ ```
206
+
146
207
  ## Development
147
208
 
148
209
  Run tests with:
@@ -8,4 +8,5 @@ OgPilotRuby.configure do |config|
8
8
  # Optional overrides:
9
9
  # config.open_timeout = 5
10
10
  # config.read_timeout = 10
11
+ # config.strip_extensions = true
11
12
  end
@@ -166,9 +166,32 @@ module OgPilotRuby
166
166
 
167
167
  cleaned = extract_request_uri(cleaned)
168
168
  cleaned = "/#{cleaned}" unless cleaned.start_with?("/")
169
+ cleaned = strip_extension(cleaned) if config.strip_extensions
169
170
  cleaned
170
171
  end
171
172
 
173
+ def strip_extension(path)
174
+ path_part, query = path.split("?", 2)
175
+
176
+ dir = File.dirname(path_part)
177
+ base = File.basename(path_part)
178
+
179
+ # Don't strip dotfiles like "/.hidden" or "/.env" — only strip when
180
+ # there's a non-dot character before the first meaningful dot.
181
+ unless base.match?(/\A\./) # starts with dot = hidden file, skip
182
+ base = base.sub(/\..+\z/, "")
183
+ end
184
+
185
+ stripped = if dir == "/" || dir == "."
186
+ "/#{base}"
187
+ else
188
+ "#{dir}/#{base}"
189
+ end
190
+ stripped = "/" if stripped.empty?
191
+
192
+ query ? "#{stripped}?#{query}" : stripped
193
+ end
194
+
172
195
  def extract_request_uri(value)
173
196
  return value unless value.start_with?("http://", "https://")
174
197
 
@@ -5,7 +5,7 @@ module OgPilotRuby
5
5
  DEFAULT_BASE_URL = "https://ogpilot.com"
6
6
  private_constant :DEFAULT_BASE_URL
7
7
 
8
- attr_accessor :api_key, :domain, :base_url, :open_timeout, :read_timeout
8
+ attr_accessor :api_key, :domain, :base_url, :open_timeout, :read_timeout, :strip_extensions
9
9
 
10
10
  def initialize
11
11
  @api_key = ENV.fetch("OG_PILOT_API_KEY", nil)
@@ -13,6 +13,7 @@ module OgPilotRuby
13
13
  @base_url = DEFAULT_BASE_URL
14
14
  @open_timeout = 5
15
15
  @read_timeout = 10
16
+ @strip_extensions = true
16
17
  end
17
18
  end
18
19
  end
@@ -1,9 +1,59 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module OgPilotRuby
4
+ # View-helper mix-in for Rails controllers and views.
5
+ #
6
+ # Include this module to access all +OgPilotRuby+ image-generation methods
7
+ # as instance methods. Every call is forwarded to the corresponding
8
+ # module-level method, so configuration and client behaviour remain
9
+ # identical.
10
+ #
11
+ # @example In a Rails controller or view
12
+ # class PagesController < ApplicationController
13
+ # helper OgPilotRuby::RailsHelper
14
+ # end
15
+ #
16
+ # # In a view:
17
+ # <%= tag.meta property: "og:image", content: create_image(title: "Hello") %>
4
18
  module RailsHelper
5
- def create_image(params = {}, json: false, iat: nil, headers: {}, default: false, **keyword_params)
6
- OgPilotRuby.create_image(params, json:, iat:, headers:, default:, **keyword_params)
19
+ # @see OgPilotRuby.create_image
20
+ def create_image(**options)
21
+ OgPilotRuby.create_image(**options)
22
+ end
23
+
24
+ # @see OgPilotRuby.create_blog_post_image
25
+ def create_blog_post_image(**options)
26
+ OgPilotRuby.create_blog_post_image(**options)
27
+ end
28
+
29
+ # @see OgPilotRuby.create_podcast_image
30
+ def create_podcast_image(**options)
31
+ OgPilotRuby.create_podcast_image(**options)
32
+ end
33
+
34
+ # @see OgPilotRuby.create_product_image
35
+ def create_product_image(**options)
36
+ OgPilotRuby.create_product_image(**options)
37
+ end
38
+
39
+ # @see OgPilotRuby.create_event_image
40
+ def create_event_image(**options)
41
+ OgPilotRuby.create_event_image(**options)
42
+ end
43
+
44
+ # @see OgPilotRuby.create_book_image
45
+ def create_book_image(**options)
46
+ OgPilotRuby.create_book_image(**options)
47
+ end
48
+
49
+ # @see OgPilotRuby.create_company_image
50
+ def create_company_image(**options)
51
+ OgPilotRuby.create_company_image(**options)
52
+ end
53
+
54
+ # @see OgPilotRuby.create_portfolio_image
55
+ def create_portfolio_image(**options)
56
+ OgPilotRuby.create_portfolio_image(**options)
7
57
  end
8
58
  end
9
59
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module OgPilotRuby
4
- VERSION = "0.2.1"
4
+ VERSION = "0.3.1"
5
5
  end
data/lib/og_pilot_ruby.rb CHANGED
@@ -9,26 +9,265 @@ loader.setup
9
9
 
10
10
  module OgPilotRuby
11
11
  class << self
12
+ # Returns the current {Configuration} instance, initializing one with
13
+ # defaults when accessed for the first time.
14
+ #
15
+ # @return [OgPilotRuby::Configuration]
12
16
  def config
13
17
  @config ||= Configuration.new
14
18
  end
15
19
 
20
+ # Yields the current {Configuration} for block-style setup.
21
+ #
22
+ # @yieldparam config [OgPilotRuby::Configuration]
23
+ # @return [void]
24
+ #
25
+ # @example
26
+ # OgPilotRuby.configure do |config|
27
+ # config.api_key = ENV.fetch("OG_PILOT_API_KEY")
28
+ # config.domain = ENV.fetch("OG_PILOT_DOMAIN")
29
+ # end
16
30
  def configure
17
31
  yield config
18
32
  end
19
33
 
34
+ # Resets the configuration to a fresh {Configuration} instance.
35
+ # Primarily useful in tests.
36
+ #
37
+ # @return [OgPilotRuby::Configuration]
20
38
  def reset_config!
21
39
  @config = Configuration.new
22
40
  end
23
41
 
42
+ # Returns a new {Client} instance wired to the current configuration.
43
+ #
44
+ # @return [OgPilotRuby::Client]
24
45
  def client
25
46
  Client.new(config)
26
47
  end
27
48
 
28
- def create_image(params = {}, json: false, iat: nil, headers: {}, default: false, **keyword_params)
29
- params ||= {}
30
- client.create_image(params.merge(keyword_params), json:, iat:, headers:, default:)
49
+ # Generates an Open Graph image URL via OG Pilot.
50
+ #
51
+ # All image parameters and request options are passed as keyword arguments.
52
+ # Defaults to the +page+ template when +template+ is omitted.
53
+ #
54
+ # == Core parameters
55
+ # template - String template name (default: +"page"+).
56
+ # title - String primary title text (*required*).
57
+ # description - String subtitle or supporting text.
58
+ # logo_url - String logo image URL.
59
+ # image_url - String hero image URL.
60
+ # bg_color - String background color (hex format).
61
+ # text_color - String text color (hex format).
62
+ # path - String request path for analytics context.
63
+ #
64
+ # == Request options
65
+ # iat - Integer issued-at timestamp for daily cache busting.
66
+ # json - Boolean when +true+, returns parsed JSON metadata
67
+ # instead of an image URL (default: +false+).
68
+ # headers - Hash of additional HTTP headers to include.
69
+ # default - Boolean forces +path+ to +"/"+ when +true+
70
+ # (default: +false+).
71
+ #
72
+ # @param options [Hash] keyword arguments containing image parameters
73
+ # and request options.
74
+ # @return [String] the resolved image URL when +json+ is +false+.
75
+ # @return [Hash] the parsed JSON response when +json+ is +true+.
76
+ #
77
+ # @example Generate an image URL
78
+ # OgPilotRuby.create_image(
79
+ # template: "blog_post",
80
+ # title: "How to Build Amazing OG Images",
81
+ # iat: Time.now.to_i
82
+ # )
83
+ #
84
+ # @example Fetch JSON metadata
85
+ # OgPilotRuby.create_image(title: "Hello OG Pilot", json: true)
86
+ def create_image(**options)
87
+ request_opts = extract_request_options!(options)
88
+ client.create_image(options, **request_opts)
31
89
  end
90
+
91
+ # Generates an Open Graph image using the +blog_post+ template.
92
+ #
93
+ # == Template parameters
94
+ # title - String primary title text (*required*).
95
+ # author_name - String author display name.
96
+ # author_avatar_url - String author avatar image URL.
97
+ # publish_date - String publication date (ISO 8601).
98
+ #
99
+ # Accepts all core parameters and request options documented on
100
+ # {.create_image}.
101
+ #
102
+ # @param options [Hash] keyword arguments.
103
+ # @return [String] the resolved image URL when +json+ is +false+.
104
+ # @return [Hash] the parsed JSON response when +json+ is +true+.
105
+ #
106
+ # @example
107
+ # OgPilotRuby.create_blog_post_image(
108
+ # title: "How to Build Amazing OG Images",
109
+ # author_name: "Jane Smith",
110
+ # publish_date: "2024-01-15"
111
+ # )
112
+ def create_blog_post_image(**options)
113
+ create_image(**options.merge(template: "blog_post"))
114
+ end
115
+
116
+ # Generates an Open Graph image using the +podcast+ template.
117
+ #
118
+ # == Template parameters
119
+ # title - String primary title text (*required*).
120
+ # episode_date - String episode date (ISO 8601).
121
+ #
122
+ # Accepts all core parameters and request options documented on
123
+ # {.create_image}.
124
+ #
125
+ # @param options [Hash] keyword arguments.
126
+ # @return [String] the resolved image URL when +json+ is +false+.
127
+ # @return [Hash] the parsed JSON response when +json+ is +true+.
128
+ #
129
+ # @example
130
+ # OgPilotRuby.create_podcast_image(
131
+ # title: "The Future of Ruby",
132
+ # episode_date: "2024-03-01"
133
+ # )
134
+ def create_podcast_image(**options)
135
+ create_image(**options.merge(template: "podcast"))
136
+ end
137
+
138
+ # Generates an Open Graph image using the +product+ template.
139
+ #
140
+ # == Template parameters
141
+ # title - String primary title text (*required*).
142
+ # unique_selling_point - String product USP.
143
+ #
144
+ # Accepts all core parameters and request options documented on
145
+ # {.create_image}.
146
+ #
147
+ # @param options [Hash] keyword arguments.
148
+ # @return [String] the resolved image URL when +json+ is +false+.
149
+ # @return [Hash] the parsed JSON response when +json+ is +true+.
150
+ #
151
+ # @example
152
+ # OgPilotRuby.create_product_image(
153
+ # title: "Wireless Headphones",
154
+ # unique_selling_point: "50-hour battery life"
155
+ # )
156
+ def create_product_image(**options)
157
+ create_image(**options.merge(template: "product"))
158
+ end
159
+
160
+ # Generates an Open Graph image using the +event+ template.
161
+ #
162
+ # == Template parameters
163
+ # title - String primary title text (*required*).
164
+ # event_date - String event date.
165
+ # event_location - String event location.
166
+ #
167
+ # Accepts all core parameters and request options documented on
168
+ # {.create_image}.
169
+ #
170
+ # @param options [Hash] keyword arguments.
171
+ # @return [String] the resolved image URL when +json+ is +false+.
172
+ # @return [Hash] the parsed JSON response when +json+ is +true+.
173
+ #
174
+ # @example
175
+ # OgPilotRuby.create_event_image(
176
+ # title: "RubyConf 2024",
177
+ # event_date: "2024-11-13",
178
+ # event_location: "Chicago, IL"
179
+ # )
180
+ def create_event_image(**options)
181
+ create_image(**options.merge(template: "event"))
182
+ end
183
+
184
+ # Generates an Open Graph image using the +book+ template.
185
+ #
186
+ # == Template parameters
187
+ # title - String primary title text (*required*).
188
+ # description - String subtitle or supporting text.
189
+ # book_author - String book author name.
190
+ # book_series_number - String or Integer series number.
191
+ # book_description - String book description.
192
+ # book_genre - String book genre.
193
+ #
194
+ # Accepts all core parameters and request options documented on
195
+ # {.create_image}.
196
+ #
197
+ # @param options [Hash] keyword arguments.
198
+ # @return [String] the resolved image URL when +json+ is +false+.
199
+ # @return [Hash] the parsed JSON response when +json+ is +true+.
200
+ #
201
+ # @example
202
+ # OgPilotRuby.create_book_image(
203
+ # title: "The Ruby Way",
204
+ # book_author: "Hal Fulton",
205
+ # book_genre: "Programming"
206
+ # )
207
+ def create_book_image(**options)
208
+ create_image(**options.merge(template: "book"))
209
+ end
210
+
211
+ # Generates an Open Graph image using the +company+ template.
212
+ #
213
+ # == Template parameters
214
+ # title - String primary title text (*required*).
215
+ # description - String company description.
216
+ # company_logo_url - String company logo image URL.
217
+ #
218
+ # Note: +image_url+ is ignored for this template.
219
+ #
220
+ # Accepts all core parameters and request options documented on
221
+ # {.create_image}.
222
+ #
223
+ # @param options [Hash] keyword arguments.
224
+ # @return [String] the resolved image URL when +json+ is +false+.
225
+ # @return [Hash] the parsed JSON response when +json+ is +true+.
226
+ #
227
+ # @example
228
+ # OgPilotRuby.create_company_image(
229
+ # title: "Acme Corp",
230
+ # description: "Building the future",
231
+ # company_logo_url: "https://example.com/logo.png"
232
+ # )
233
+ def create_company_image(**options)
234
+ create_image(**options.merge(template: "company"))
235
+ end
236
+
237
+ # Generates an Open Graph image using the +portfolio+ template.
238
+ #
239
+ # == Template parameters
240
+ # title - String primary title text (*required*).
241
+ #
242
+ # Accepts all core parameters and request options documented on
243
+ # {.create_image}.
244
+ #
245
+ # @param options [Hash] keyword arguments.
246
+ # @return [String] the resolved image URL when +json+ is +false+.
247
+ # @return [Hash] the parsed JSON response when +json+ is +true+.
248
+ #
249
+ # @example
250
+ # OgPilotRuby.create_portfolio_image(title: "My Portfolio")
251
+ def create_portfolio_image(**options)
252
+ create_image(**options.merge(template: "portfolio"))
253
+ end
254
+
255
+ private
256
+
257
+ # Extracts Ruby-specific request options from +options+, mutating the
258
+ # hash in place so that only image parameters remain.
259
+ #
260
+ # @param options [Hash] the full keyword arguments hash (modified in place).
261
+ # @return [Hash] a keyword hash (+json+, +iat+, +headers+, +default+)
262
+ # compatible with {Client#create_image}.
263
+ def extract_request_options!(options)
264
+ {
265
+ json: options.delete(:json) || false,
266
+ iat: options.delete(:iat),
267
+ headers: options.delete(:headers) || {},
268
+ default: options.delete(:default) || false
269
+ }
270
+ end
32
271
  end
33
272
  end
34
273
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: og_pilot_ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sunergos IT LLC