fileboost 0.2.0.pre → 0.2.0.pre2

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: e41eb33a273bb73c63284223566b994fca3583c8e72c82c0dde3ffc6c19b9adc
4
- data.tar.gz: 21a0c4088aea9ac6eeb3bb82310d850b99fa718155c0b253798aa5343da46caa
3
+ metadata.gz: b09c6f264244d950aef3d870c4e102e3766449f24b724834de3d58c08e9eecd8
4
+ data.tar.gz: beaf90aa5f6a0b579fd54298b108fe9fa427356d3fce5f6bffe570d828cbc0ac
5
5
  SHA512:
6
- metadata.gz: 11b1349683d425b709d351ca165394f86f6ce7db6e71af7359d8c10a8532d2f31843464fa82b4a7da4a98ba792601b97cfa86fa02d08a36e8fe5528defe8622f
7
- data.tar.gz: df922239b99ecbd4e87e6272908bc85f1ecf6e303faa704e5f5843a991ad783df29f2b6eeccd961a140342b1c7ab6e560ed93eca3222d9a4ae89c3fd690553e6
6
+ metadata.gz: 143c252e1134fef6790e18ac6d9ea6b85995fb90bd7755475cbdc8411ab85aefa9ae1d80c7362ebc8fadc53500109449ffef66818ebdb641dd302129e5a9bd1e
7
+ data.tar.gz: d90e35602b8be26133a51ca1ff25d65db41080ebdadff3988e81888b90c9b69e2843c2d84c58f67c8e5bcc8075d705782f575ac9b9f44d15e7725bc9e1ec549a
data/README.md CHANGED
@@ -4,13 +4,39 @@
4
4
 
5
5
  Fileboost is a Rails gem that provides seamless integration with the Fileboost.dev image optimization service. It offers drop-in replacement helpers for Rails' native image helpers with automatic optimization, HMAC authentication, and comprehensive transformation support for ActiveStorage objects.
6
6
 
7
+ ## Table of Contents
8
+
9
+ - [Features](#features)
10
+ - [Installation](#installation)
11
+ - [Configuration](#configuration)
12
+ - [Usage](#usage)
13
+ - [Drop-in Replacement (Recommended)](#drop-in-replacement-recommended)
14
+ - [Manual Helper Method](#manual-helper-method)
15
+ - [URL Generation](#url-generation)
16
+ - [Transformation Options](#transformation-options)
17
+ - [Parameter Aliases](#parameter-aliases)
18
+ - [ActiveStorage Support](#activestorage-support)
19
+ - [ActiveStorage Variants (NEW in v0.2.0)](#activestorage-variants-new-in-v020)
20
+ - [Variant Transformation Mapping](#variant-transformation-mapping)
21
+ - [Combining Variants with Custom Options](#combining-variants-with-custom-options)
22
+ - [Responsive Images](#responsive-images)
23
+ - [Error Handling](#error-handling)
24
+ - [Security](#security)
25
+ - [Development](#development)
26
+ - [Testing](#testing)
27
+ - [Contributing](#contributing)
28
+ - [License](#license)
29
+ - [Support](#support)
30
+
7
31
  ## Features
8
32
 
9
- - 🚀 **Drop-in replacement** for Rails `image_tag` and `url_for` helpers
33
+ - 🚀 **Drop-in replacement** for Rails `image_tag` with zero code changes (NEW in v0.2.0)
34
+ - 🎨 **Full ActiveStorage Variant support** with automatic transformation mapping (NEW in v0.2.0)
10
35
  - 🔒 **Secure HMAC authentication** with Fileboost.dev service
11
36
  - 📱 **ActiveStorage only** - works exclusively with ActiveStorage attachments
12
37
  - 🎛️ **Comprehensive transformations** - resize, quality, format conversion, and more
13
38
  - 🔧 **Simple configuration** - just project ID and token required
39
+ - 🔄 **Automatic fallback** - non-ActiveStorage images work exactly as before
14
40
 
15
41
  ## Installation
16
42
 
@@ -43,11 +69,59 @@ export FILEBOOST_PROJECT_ID="your-project-id"
43
69
  export FILEBOOST_TOKEN="your-secret-token"
44
70
  ```
45
71
 
72
+ Or configure directly in your initializer:
73
+
74
+ ```ruby
75
+ # config/initializers/fileboost.rb
76
+ Fileboost.configure do |config|
77
+ config.project_id = ENV["FILEBOOST_PROJECT_ID"]
78
+ config.token = ENV["FILEBOOST_TOKEN"]
79
+
80
+ # Optional: Enable drop-in replacement for Rails image_tag (default: false)
81
+ config.patch_image_tag = true
82
+ end
83
+ ```
84
+
46
85
  ## Usage
47
86
 
48
- ### Basic Image Tag
87
+ ### Drop-in Replacement (Recommended)
88
+
89
+ Enable `patch_image_tag` in your configuration to automatically optimize ActiveStorage images with your existing `image_tag` calls:
90
+
91
+ ```ruby
92
+ # config/initializers/fileboost.rb
93
+ Fileboost.configure do |config|
94
+ config.project_id = ENV["FILEBOOST_PROJECT_ID"]
95
+ config.token = ENV["FILEBOOST_TOKEN"]
96
+ config.patch_image_tag = true # Enable automatic optimization
97
+ end
98
+ ```
49
99
 
50
- Replace `image_tag` with `fileboost_image_tag` for ActiveStorage objects:
100
+ With this enabled, your existing Rails code automatically gets Fileboost optimization:
101
+
102
+ ```erb
103
+ <!-- This now automatically uses Fileboost for ActiveStorage objects -->
104
+ <%= image_tag user.avatar, resize: { w: 300, h: 300 }, alt: "Avatar" %>
105
+ <%= image_tag post.featured_image, resize: { width: 800, quality: 85 }, class: "hero" %>
106
+
107
+ <!-- ActiveStorage variants work seamlessly -->
108
+ <%= image_tag user.avatar.variant(resize_to_limit: [100, 100]), alt: "Thumbnail" %>
109
+ <%= image_tag post.image.variant(:thumb), alt: "Post thumbnail" %>
110
+
111
+ <!-- Non-ActiveStorage images work exactly as before -->
112
+ <%= image_tag "/assets/logo.png", alt: "Logo" %>
113
+ <%= image_tag "https://example.com/image.jpg", alt: "External" %>
114
+ ```
115
+
116
+ **Benefits:**
117
+ - Zero code changes required for existing ActiveStorage images
118
+ - Full ActiveStorage variant support with automatic transformation mapping
119
+ - Automatic fallback to Rails behavior for non-ActiveStorage assets
120
+ - Gradual migration path - enable/disable with single configuration option
121
+
122
+ ### Manual Helper Method
123
+
124
+ Alternatively, use `fileboost_image_tag` explicitly for ActiveStorage objects:
51
125
 
52
126
  ```erb
53
127
  <!-- Before (Rails) -->
@@ -104,7 +178,7 @@ fileboost_image_tag(image, resize: { w: 400, h: 300, q: 85 })
104
178
  fileboost_image_tag(image, resize: { width: 400, height: 300, quality: 85 })
105
179
  ```
106
180
 
107
- **Note:** Avoid using the `format` parameter. Fileboost automatically selects the optimal image format (WebP, AVIF, JPEG, etc.) based on browser headers and capabilities for the best performance and compatibility.
181
+ **🎯 Smart Optimization:** Fileboost's CDN automatically detects and delivers the optimal image format (WebP, AVIF, JPEG, etc.) based on browser capabilities, device type, and connection speed for maximum performance.
108
182
 
109
183
  ### ActiveStorage Support
110
184
 
@@ -123,6 +197,63 @@ Works seamlessly with all ActiveStorage attachment types:
123
197
  <%= fileboost_image_tag post.featured_image.blob, resize: { w: 800 } %>
124
198
  ```
125
199
 
200
+ ### ActiveStorage Variants (NEW in v0.2.0)
201
+
202
+ Fileboost now provides full support for ActiveStorage variants with automatic transformation mapping:
203
+
204
+ ```erb
205
+ <!-- Basic variants with automatic transformation mapping -->
206
+ <%= image_tag user.avatar.variant(resize_to_limit: [200, 200]) %>
207
+ <!-- ↓ Automatically becomes: w=200&h=200&fit=scale-down -->
208
+
209
+ <%= image_tag post.image.variant(resize_to_fit: [400, 300]) %>
210
+ <!-- ↓ Automatically becomes: w=400&h=300&fit=contain -->
211
+
212
+ <%= image_tag hero.banner.variant(resize_to_fill: [800, 400]) %>
213
+ <!-- ↓ Automatically becomes: w=800&h=400&fit=cover -->
214
+
215
+ <!-- Complex variants with multiple transformations -->
216
+ <%= image_tag post.image.variant(
217
+ resize_to_limit: [600, 400],
218
+ quality: 85
219
+ ) %>
220
+ <!-- ↓ Automatically becomes: w=600&h=400&fit=scale-down&q=85 -->
221
+
222
+ <!-- Named variants work seamlessly -->
223
+ <%= image_tag user.avatar.variant(:thumb) %>
224
+ <!-- ↓ Uses predefined variant transformations -->
225
+ ```
226
+
227
+ #### Variant Transformation Mapping
228
+
229
+ Fileboost automatically maps ActiveStorage variant transformations to optimized URL parameters:
230
+
231
+ | ActiveStorage Variant | Fileboost Parameters | Description |
232
+ |----------------------|---------------------|-------------|
233
+ | `resize_to_limit: [w, h]` | `w=W&h=H&fit=scale-down` | Resize within bounds, preserving aspect ratio |
234
+ | `resize_to_fit: [w, h]` | `w=W&h=H&fit=contain` | Resize to fit exactly, with letterboxing if needed |
235
+ | `resize_to_fill: [w, h]` | `w=W&h=H&fit=cover` | Resize and crop to fill exactly |
236
+ | `resize_and_pad: [w, h]` | `w=W&h=H&fit=pad` | Resize with padding |
237
+ | `quality: 85` | `q=85` | JPEG/WebP quality (1-100) |
238
+ | `rotate: "-90"` | `r=-90` | Rotation in degrees |
239
+
240
+
241
+ #### Combining Variants with Custom Options
242
+
243
+ You can combine variant transformations with additional Fileboost options:
244
+
245
+ ```erb
246
+ <!-- Variant transformations + additional options -->
247
+ <%= image_tag user.avatar.variant(resize_to_limit: [200, 200]),
248
+ resize: { blur: 5, brightness: 110 } %>
249
+ <!-- ↓ Combines variant params with additional blur and brightness -->
250
+
251
+ <!-- Override variant parameters -->
252
+ <%= image_tag post.image.variant(resize_to_limit: [400, 300]),
253
+ resize: { w: 500 } %>
254
+ <!-- ↓ Uses h=300&fit=scale-down from variant, but overrides width to 500 -->
255
+ ```
256
+
126
257
  ### Responsive Images
127
258
 
128
259
  Generate multiple sizes for responsive designs:
@@ -171,7 +302,7 @@ After checking out the repo, run:
171
302
 
172
303
  ```bash
173
304
  $ bundle install
174
- $ rake test
305
+ $ bundle exec rspec
175
306
  ```
176
307
 
177
308
  To test against the dummy Rails application:
@@ -186,7 +317,7 @@ $ rails server
186
317
  Run the test suite:
187
318
 
188
319
  ```bash
189
- $ rake test
320
+ $ bundle exec rspec
190
321
  ```
191
322
 
192
323
  Run RuboCop:
@@ -43,7 +43,7 @@ module Fileboost
43
43
  full_path = "/#{project_id}#{asset_path}"
44
44
 
45
45
  # Extract and normalize transformation parameters
46
- transformation_params = extract_transformation_params(options)
46
+ transformation_params = extract_transformation_params(asset, options)
47
47
 
48
48
  # Generate HMAC signature for secure authentication
49
49
  signature = Fileboost::SignatureGenerator.generate(
@@ -89,10 +89,16 @@ module Fileboost
89
89
  end
90
90
  end
91
91
 
92
- def self.extract_transformation_params(options)
92
+ def self.extract_transformation_params(asset, options)
93
93
  params = {}
94
94
 
95
- # Only handle nested resize parameter
95
+ # First, extract variant transformations if this is a variant
96
+ if asset.is_a?(ActiveStorage::VariantWithRecord)
97
+ variant_params = Fileboost::VariantTransformer.transform_variant_params(asset)
98
+ params.merge!(variant_params)
99
+ end
100
+
101
+ # Then handle explicit resize parameter (this can override variant params)
96
102
  if options[:resize].is_a?(Hash)
97
103
  resize_options = options[:resize]
98
104
  resize_options.each do |key, value|
@@ -117,9 +123,13 @@ module Fileboost
117
123
 
118
124
  def self.normalize_param_value(key, value)
119
125
  case key
120
- when "w", "h", "q", "b", "br", "c", "r"
126
+ when "w", "h", "b", "br", "c", "r"
121
127
  # Numeric parameters
122
128
  value.to_i.to_s if value.to_i > 0
129
+ when "q"
130
+ # Quality parameter - validate range 1-100
131
+ q = value.to_i
132
+ (q > 0 && q <= 100) ? q.to_s : nil
123
133
  when "f"
124
134
  # Format parameter - validate against common formats
125
135
  valid_formats = %w[webp jpeg jpg png gif avif]
@@ -0,0 +1,130 @@
1
+ module Fileboost
2
+ # Maps ActiveStorage variant transformations to Fileboost URL parameters
3
+ class VariantTransformer
4
+ # Maps ActiveStorage transformation operations to Fileboost parameters
5
+ TRANSFORMATION_MAPPING = {
6
+ # Resize operations
7
+ resize_to_limit: { fit: "scale-down" },
8
+ resize_to_fit: { fit: "contain" },
9
+ resize_to_fill: { fit: "cover" },
10
+ resize_and_pad: { fit: "pad" },
11
+
12
+ # Quality settings
13
+ quality: { param: "q" },
14
+
15
+ # Format settings
16
+ format: { param: "f" },
17
+
18
+ # Rotation
19
+ rotate: { param: "r" },
20
+
21
+ # Crop operations - need special handling
22
+ crop: { special: :crop_handler }
23
+ }.freeze
24
+
25
+ # Convert ActiveStorage variant transformations to Fileboost parameters
26
+ def self.transform_variant_params(variant)
27
+ return {} unless variant.respond_to?(:variation)
28
+
29
+ transformations = variant.variation.transformations
30
+ params = {}
31
+
32
+ transformations.each do |operation, value|
33
+ case operation
34
+ when :resize_to_limit, :resize_to_fit, :resize_to_fill, :resize_and_pad
35
+ resize_params = handle_resize_operation(operation, value)
36
+ params.merge!(resize_params)
37
+
38
+ when :quality
39
+ params["q"] = normalize_quality(value)
40
+
41
+ when :format
42
+ params["f"] = normalize_format(value)
43
+
44
+ when :rotate
45
+ params["r"] = normalize_rotation(value)
46
+
47
+ when :crop
48
+ crop_params = handle_crop_operation(value)
49
+ params.merge!(crop_params) if crop_params
50
+
51
+ # Add more transformations as needed
52
+ end
53
+ end
54
+
55
+ params
56
+ end
57
+
58
+ private
59
+
60
+ # Handle resize operations (resize_to_limit, resize_to_fit, etc.)
61
+ def self.handle_resize_operation(operation, dimensions)
62
+ return {} unless dimensions.is_a?(Array) && dimensions.length >= 2
63
+
64
+ width, height = dimensions[0], dimensions[1]
65
+ params = {}
66
+
67
+ # Set dimensions
68
+ params["w"] = width.to_s if width && width > 0
69
+ params["h"] = height.to_s if height && height > 0
70
+
71
+ # Set fit parameter based on resize operation
72
+ fit_mapping = TRANSFORMATION_MAPPING[operation]
73
+ params["fit"] = fit_mapping[:fit] if fit_mapping && fit_mapping[:fit]
74
+
75
+ params
76
+ end
77
+
78
+ # Handle crop operations
79
+ def self.handle_crop_operation(crop_params)
80
+ # Crop can be in different formats depending on the processor
81
+ # For now, we'll handle simple array format: [x, y, width, height]
82
+ if crop_params.is_a?(Array) && crop_params.length == 4
83
+ x, y, w, h = crop_params
84
+ return { "crop" => "#{x},#{y},#{w},#{h}" }
85
+ end
86
+
87
+ # Could extend this for other crop formats
88
+ nil
89
+ end
90
+
91
+ # Normalize quality value (0-100)
92
+ def self.normalize_quality(quality)
93
+ q = quality.to_i
94
+ return nil if q <= 0 || q > 100
95
+ q.to_s
96
+ end
97
+
98
+ # Normalize format value
99
+ def self.normalize_format(format)
100
+ # Convert to string and lowercase
101
+ format_str = format.to_s.downcase
102
+
103
+ # Map common format variations
104
+ case format_str
105
+ when "jpg", "jpeg"
106
+ "jpg"
107
+ when "png"
108
+ "png"
109
+ when "webp"
110
+ "webp"
111
+ when "avif"
112
+ "avif"
113
+ when "gif"
114
+ "gif"
115
+ else
116
+ # If it's already a recognized format, use it
117
+ valid_formats = %w[webp jpeg jpg png gif avif]
118
+ valid_formats.include?(format_str) ? format_str : nil
119
+ end
120
+ end
121
+
122
+ # Normalize rotation value
123
+ def self.normalize_rotation(rotation)
124
+ # Rotation should be a number (degrees)
125
+ r = rotation.to_s.gsub(/[^\d\-]/, "") # Remove non-numeric chars except minus
126
+ return nil if r.empty?
127
+ r
128
+ end
129
+ end
130
+ end
@@ -1,3 +1,3 @@
1
1
  module Fileboost
2
- VERSION = "0.2.0.pre"
2
+ VERSION = "0.2.0.pre2"
3
3
  end
data/lib/fileboost.rb CHANGED
@@ -2,6 +2,7 @@ require "fileboost/version"
2
2
  require "fileboost/config"
3
3
  require "fileboost/error_handler"
4
4
  require "fileboost/signature_generator"
5
+ require "fileboost/variant_transformer"
5
6
  require "fileboost/url_builder"
6
7
  require "fileboost/helpers"
7
8
  require "fileboost/image_tag_patch"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fileboost
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0.pre
4
+ version: 0.2.0.pre2
5
5
  platform: ruby
6
6
  authors:
7
7
  - bilal
@@ -141,6 +141,7 @@ files:
141
141
  - lib/fileboost/image_tag_patch.rb
142
142
  - lib/fileboost/signature_generator.rb
143
143
  - lib/fileboost/url_builder.rb
144
+ - lib/fileboost/variant_transformer.rb
144
145
  - lib/fileboost/version.rb
145
146
  - lib/generators/fileboost/install_generator.rb
146
147
  - lib/generators/fileboost/templates/INSTALL.md