css_inline 0.17.0 → 0.19.0
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 +4 -4
- data/Cargo.lock +311 -427
- data/README.md +22 -7
- data/ext/css_inline/Cargo.lock +311 -427
- data/ext/css_inline/Cargo.toml +6 -6
- data/ext/css_inline/src/lib.rs +82 -56
- metadata +3 -59
data/ext/css_inline/Cargo.toml
CHANGED
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
[package]
|
|
2
|
-
name = "css-inline"
|
|
3
|
-
version = "0.
|
|
2
|
+
name = "css-inline-ruby"
|
|
3
|
+
version = "0.19.0"
|
|
4
4
|
authors = ["Dmitry Dygalo <dmitry@dygalo.dev>"]
|
|
5
|
-
edition = "
|
|
5
|
+
edition = "2024"
|
|
6
6
|
readme = "README.rdoc"
|
|
7
7
|
description = "High-performance library for inlining CSS into HTML 'style' attributes"
|
|
8
8
|
repository = "https://github.com/Stranger6667/css-inline"
|
|
9
9
|
keywords = ["css", "html", "email", "stylesheet", "inlining"]
|
|
10
10
|
categories = ["web-programming"]
|
|
11
11
|
license = "MIT"
|
|
12
|
-
rust-version = "1.
|
|
12
|
+
rust-version = "1.85"
|
|
13
13
|
|
|
14
14
|
[lib]
|
|
15
15
|
name = "css_inline"
|
|
16
16
|
crate-type = ["cdylib"]
|
|
17
17
|
|
|
18
18
|
[dependencies]
|
|
19
|
-
magnus = "0.
|
|
19
|
+
magnus = "0.8"
|
|
20
20
|
rayon = "1"
|
|
21
21
|
|
|
22
22
|
[dependencies.css-inline]
|
|
23
|
-
version = "0.
|
|
23
|
+
version = "0.19.0"
|
|
24
24
|
default-features = false
|
|
25
25
|
features = ["http", "file", "stylesheet-cache"]
|
data/ext/css_inline/src/lib.rs
CHANGED
|
@@ -27,11 +27,10 @@
|
|
|
27
27
|
)]
|
|
28
28
|
use css_inline as rust_inline;
|
|
29
29
|
use magnus::{
|
|
30
|
-
|
|
30
|
+
DataTypeFunctions, RHash, Ruby, TryConvert, TypedData, Value, function, method,
|
|
31
31
|
prelude::*,
|
|
32
|
-
scan_args::{get_kwargs, scan_args
|
|
32
|
+
scan_args::{Args, get_kwargs, scan_args},
|
|
33
33
|
typed_data::Obj,
|
|
34
|
-
DataTypeFunctions, RHash, TypedData, Value,
|
|
35
34
|
};
|
|
36
35
|
use rayon::prelude::*;
|
|
37
36
|
use std::{
|
|
@@ -42,53 +41,78 @@ use std::{
|
|
|
42
41
|
|
|
43
42
|
type RubyResult<T> = Result<T, magnus::Error>;
|
|
44
43
|
|
|
44
|
+
#[allow(clippy::struct_excessive_bools)]
|
|
45
|
+
struct Options {
|
|
46
|
+
/// Whether to inline CSS from "style" tags.
|
|
47
|
+
///
|
|
48
|
+
/// Sometimes HTML may include a lot of boilerplate styles, that are not applicable in every
|
|
49
|
+
/// scenario, and it is useful to ignore them and use `extra_css` instead.
|
|
50
|
+
inline_style_tags: Option<bool>,
|
|
51
|
+
/// Keep "style" tags after inlining.
|
|
52
|
+
keep_style_tags: Option<bool>,
|
|
53
|
+
/// Keep "link" tags after inlining.
|
|
54
|
+
keep_link_tags: Option<bool>,
|
|
55
|
+
/// Keep "at-rules" after inlining.
|
|
56
|
+
keep_at_rules: Option<bool>,
|
|
57
|
+
/// Remove trailing semicolons and spaces between properties and values.
|
|
58
|
+
minify_css: Option<bool>,
|
|
59
|
+
/// Used for loading external stylesheets via relative URLs.
|
|
60
|
+
base_url: Option<String>,
|
|
61
|
+
/// Whether remote stylesheets should be loaded or not.
|
|
62
|
+
load_remote_stylesheets: Option<bool>,
|
|
63
|
+
/// An LRU Cache for external stylesheets.
|
|
64
|
+
cache: Option<Obj<StylesheetCache>>,
|
|
65
|
+
/// Additional CSS to inline.
|
|
66
|
+
extra_css: Option<String>,
|
|
67
|
+
/// Pre-allocate capacity for HTML nodes during parsing.
|
|
68
|
+
/// It can improve performance when you have an estimate of the number of nodes in your HTML document.
|
|
69
|
+
preallocate_node_capacity: Option<usize>,
|
|
70
|
+
/// Remove selectors that were successfully inlined from inline `<style>` blocks.
|
|
71
|
+
remove_inlined_selectors: Option<bool>,
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
impl TryConvert for Options {
|
|
75
|
+
fn try_convert(v: Value) -> Result<Self, magnus::Error> {
|
|
76
|
+
let h = RHash::try_convert(v)?;
|
|
77
|
+
let ruby = Ruby::get_with(v);
|
|
78
|
+
Ok(Self {
|
|
79
|
+
inline_style_tags: h.aref::<_, Option<bool>>(ruby.to_symbol("inline_style_tags"))?,
|
|
80
|
+
keep_style_tags: h.aref::<_, Option<bool>>(ruby.to_symbol("keep_style_tags"))?,
|
|
81
|
+
keep_link_tags: h.aref::<_, Option<bool>>(ruby.to_symbol("keep_link_tags"))?,
|
|
82
|
+
keep_at_rules: h.aref::<_, Option<bool>>(ruby.to_symbol("keep_at_rules"))?,
|
|
83
|
+
minify_css: h.aref::<_, Option<bool>>(ruby.to_symbol("minify_css"))?,
|
|
84
|
+
base_url: h.aref::<_, Option<String>>(ruby.to_symbol("base_url"))?,
|
|
85
|
+
load_remote_stylesheets: h
|
|
86
|
+
.aref::<_, Option<bool>>(ruby.to_symbol("load_remote_stylesheets"))?,
|
|
87
|
+
cache: h.aref::<_, Option<Obj<StylesheetCache>>>(ruby.to_symbol("cache"))?,
|
|
88
|
+
extra_css: h.aref::<_, Option<String>>(ruby.to_symbol("extra_css"))?,
|
|
89
|
+
preallocate_node_capacity: h
|
|
90
|
+
.aref::<_, Option<usize>>(ruby.to_symbol("preallocate_node_capacity"))?,
|
|
91
|
+
remove_inlined_selectors: h
|
|
92
|
+
.aref::<_, Option<bool>>(ruby.to_symbol("remove_inlined_selectors"))?,
|
|
93
|
+
})
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
45
97
|
fn parse_options<Req>(
|
|
46
98
|
args: &Args<Req, (), (), (), RHash, ()>,
|
|
47
99
|
) -> RubyResult<rust_inline::InlineOptions<'static>> {
|
|
48
|
-
let kwargs =
|
|
49
|
-
_,
|
|
50
|
-
(),
|
|
51
|
-
(
|
|
52
|
-
Option<bool>,
|
|
53
|
-
Option<bool>,
|
|
54
|
-
Option<bool>,
|
|
55
|
-
Option<bool>,
|
|
56
|
-
Option<String>,
|
|
57
|
-
Option<bool>,
|
|
58
|
-
Option<Obj<StylesheetCache>>,
|
|
59
|
-
Option<String>,
|
|
60
|
-
Option<usize>,
|
|
61
|
-
),
|
|
62
|
-
(),
|
|
63
|
-
>(
|
|
64
|
-
args.keywords,
|
|
65
|
-
&[],
|
|
66
|
-
&[
|
|
67
|
-
"inline_style_tags",
|
|
68
|
-
"keep_style_tags",
|
|
69
|
-
"keep_link_tags",
|
|
70
|
-
"keep_at_rules",
|
|
71
|
-
"base_url",
|
|
72
|
-
"load_remote_stylesheets",
|
|
73
|
-
"cache",
|
|
74
|
-
"extra_css",
|
|
75
|
-
"preallocate_node_capacity",
|
|
76
|
-
],
|
|
77
|
-
)?;
|
|
78
|
-
let kwargs = kwargs.optional;
|
|
100
|
+
let kwargs: Options = Options::try_convert(args.keywords.as_value())?;
|
|
79
101
|
Ok(rust_inline::InlineOptions {
|
|
80
|
-
inline_style_tags: kwargs.
|
|
81
|
-
keep_style_tags: kwargs.
|
|
82
|
-
keep_link_tags: kwargs.
|
|
83
|
-
keep_at_rules: kwargs.
|
|
84
|
-
|
|
85
|
-
|
|
102
|
+
inline_style_tags: kwargs.inline_style_tags.unwrap_or(true),
|
|
103
|
+
keep_style_tags: kwargs.keep_style_tags.unwrap_or(false),
|
|
104
|
+
keep_link_tags: kwargs.keep_link_tags.unwrap_or(false),
|
|
105
|
+
keep_at_rules: kwargs.keep_at_rules.unwrap_or(false),
|
|
106
|
+
minify_css: kwargs.minify_css.unwrap_or(false),
|
|
107
|
+
base_url: parse_url(kwargs.base_url)?,
|
|
108
|
+
load_remote_stylesheets: kwargs.load_remote_stylesheets.unwrap_or(true),
|
|
86
109
|
cache: kwargs
|
|
87
|
-
.
|
|
110
|
+
.cache
|
|
88
111
|
.map(|cache| Mutex::new(rust_inline::StylesheetCache::new(cache.size))),
|
|
89
|
-
extra_css: kwargs.
|
|
90
|
-
preallocate_node_capacity: kwargs.
|
|
112
|
+
extra_css: kwargs.extra_css.map(Cow::Owned),
|
|
113
|
+
preallocate_node_capacity: kwargs.preallocate_node_capacity.unwrap_or(32),
|
|
91
114
|
resolver: Arc::new(rust_inline::DefaultStylesheetResolver),
|
|
115
|
+
remove_inlined_selectors: kwargs.remove_inlined_selectors.unwrap_or(false),
|
|
92
116
|
})
|
|
93
117
|
}
|
|
94
118
|
|
|
@@ -101,8 +125,9 @@ struct StylesheetCache {
|
|
|
101
125
|
impl StylesheetCache {
|
|
102
126
|
fn new(args: &[Value]) -> RubyResult<StylesheetCache> {
|
|
103
127
|
fn error() -> magnus::Error {
|
|
128
|
+
let ruby = Ruby::get().expect("Always called from a Ruby thread");
|
|
104
129
|
magnus::Error::new(
|
|
105
|
-
|
|
130
|
+
ruby.exception_arg_error(),
|
|
106
131
|
"Cache size must be an integer greater than zero",
|
|
107
132
|
)
|
|
108
133
|
}
|
|
@@ -124,19 +149,19 @@ struct InlineErrorWrapper(rust_inline::InlineError);
|
|
|
124
149
|
|
|
125
150
|
impl From<InlineErrorWrapper> for magnus::Error {
|
|
126
151
|
fn from(error: InlineErrorWrapper) -> Self {
|
|
152
|
+
let ruby = Ruby::get().expect("Always called from a Ruby thread");
|
|
127
153
|
match error.0 {
|
|
128
154
|
rust_inline::InlineError::IO(error) => {
|
|
129
|
-
magnus::Error::new(
|
|
155
|
+
magnus::Error::new(ruby.exception_arg_error(), error.to_string())
|
|
156
|
+
}
|
|
157
|
+
rust_inline::InlineError::Network { error, location } => {
|
|
158
|
+
magnus::Error::new(ruby.exception_arg_error(), format!("{error}: {location}"))
|
|
130
159
|
}
|
|
131
|
-
rust_inline::InlineError::Network { error, location } => magnus::Error::new(
|
|
132
|
-
magnus::exception::arg_error(),
|
|
133
|
-
format!("{error}: {location}"),
|
|
134
|
-
),
|
|
135
160
|
rust_inline::InlineError::ParseError(message) => {
|
|
136
|
-
magnus::Error::new(
|
|
161
|
+
magnus::Error::new(ruby.exception_arg_error(), message.to_string())
|
|
137
162
|
}
|
|
138
163
|
rust_inline::InlineError::MissingStyleSheet { .. } => {
|
|
139
|
-
magnus::Error::new(
|
|
164
|
+
magnus::Error::new(ruby.exception_arg_error(), error.0.to_string())
|
|
140
165
|
}
|
|
141
166
|
}
|
|
142
167
|
}
|
|
@@ -149,8 +174,9 @@ struct UrlError {
|
|
|
149
174
|
|
|
150
175
|
impl From<UrlError> for magnus::Error {
|
|
151
176
|
fn from(error: UrlError) -> magnus::Error {
|
|
177
|
+
let ruby = Ruby::get().expect("Always called from a Ruby thread");
|
|
152
178
|
magnus::Error::new(
|
|
153
|
-
|
|
179
|
+
ruby.exception_arg_error(),
|
|
154
180
|
format!("{}: {}", error.error, error.url),
|
|
155
181
|
)
|
|
156
182
|
}
|
|
@@ -256,8 +282,8 @@ fn inline_many_fragments_impl(
|
|
|
256
282
|
}
|
|
257
283
|
|
|
258
284
|
#[magnus::init(name = "css_inline")]
|
|
259
|
-
fn init() -> RubyResult<()> {
|
|
260
|
-
let module = define_module("CSSInline")?;
|
|
285
|
+
fn init(ruby: &Ruby) -> RubyResult<()> {
|
|
286
|
+
let module = ruby.define_module("CSSInline")?;
|
|
261
287
|
|
|
262
288
|
module.define_module_function("inline", function!(inline, -1))?;
|
|
263
289
|
module.define_module_function("inline_fragment", function!(inline_fragment, -1))?;
|
|
@@ -267,7 +293,7 @@ fn init() -> RubyResult<()> {
|
|
|
267
293
|
function!(inline_many_fragments, -1),
|
|
268
294
|
)?;
|
|
269
295
|
|
|
270
|
-
let class = module.define_class("CSSInliner",
|
|
296
|
+
let class = module.define_class("CSSInliner", ruby.class_object())?;
|
|
271
297
|
class.define_singleton_method("new", function!(CSSInliner::new, -1))?;
|
|
272
298
|
class.define_method("inline", method!(CSSInliner::inline, 1))?;
|
|
273
299
|
class.define_method("inline_fragment", method!(CSSInliner::inline_fragment, 2))?;
|
|
@@ -277,7 +303,7 @@ fn init() -> RubyResult<()> {
|
|
|
277
303
|
method!(CSSInliner::inline_many_fragments, 2),
|
|
278
304
|
)?;
|
|
279
305
|
|
|
280
|
-
let class = module.define_class("StylesheetCache",
|
|
306
|
+
let class = module.define_class("StylesheetCache", ruby.class_object())?;
|
|
281
307
|
class.define_singleton_method("new", function!(StylesheetCache::new, -1))?;
|
|
282
308
|
Ok(())
|
|
283
309
|
}
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: css_inline
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.19.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Dmitry Dygalo
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2025-
|
|
11
|
+
date: 2025-12-29 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rb_sys
|
|
@@ -38,62 +38,6 @@ dependencies:
|
|
|
38
38
|
- - "~>"
|
|
39
39
|
- !ruby/object:Gem::Version
|
|
40
40
|
version: 1.3.0
|
|
41
|
-
- !ruby/object:Gem::Dependency
|
|
42
|
-
name: benchmark-ips
|
|
43
|
-
requirement: !ruby/object:Gem::Requirement
|
|
44
|
-
requirements:
|
|
45
|
-
- - "~>"
|
|
46
|
-
- !ruby/object:Gem::Version
|
|
47
|
-
version: '2.10'
|
|
48
|
-
type: :development
|
|
49
|
-
prerelease: false
|
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
-
requirements:
|
|
52
|
-
- - "~>"
|
|
53
|
-
- !ruby/object:Gem::Version
|
|
54
|
-
version: '2.10'
|
|
55
|
-
- !ruby/object:Gem::Dependency
|
|
56
|
-
name: premailer
|
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
|
58
|
-
requirements:
|
|
59
|
-
- - "~>"
|
|
60
|
-
- !ruby/object:Gem::Version
|
|
61
|
-
version: '1.21'
|
|
62
|
-
type: :development
|
|
63
|
-
prerelease: false
|
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
-
requirements:
|
|
66
|
-
- - "~>"
|
|
67
|
-
- !ruby/object:Gem::Version
|
|
68
|
-
version: '1.21'
|
|
69
|
-
- !ruby/object:Gem::Dependency
|
|
70
|
-
name: roadie
|
|
71
|
-
requirement: !ruby/object:Gem::Requirement
|
|
72
|
-
requirements:
|
|
73
|
-
- - "~>"
|
|
74
|
-
- !ruby/object:Gem::Version
|
|
75
|
-
version: 5.2.1
|
|
76
|
-
type: :development
|
|
77
|
-
prerelease: false
|
|
78
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
79
|
-
requirements:
|
|
80
|
-
- - "~>"
|
|
81
|
-
- !ruby/object:Gem::Version
|
|
82
|
-
version: 5.2.1
|
|
83
|
-
- !ruby/object:Gem::Dependency
|
|
84
|
-
name: nokogiri
|
|
85
|
-
requirement: !ruby/object:Gem::Requirement
|
|
86
|
-
requirements:
|
|
87
|
-
- - "~>"
|
|
88
|
-
- !ruby/object:Gem::Version
|
|
89
|
-
version: '1.15'
|
|
90
|
-
type: :development
|
|
91
|
-
prerelease: false
|
|
92
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
93
|
-
requirements:
|
|
94
|
-
- - "~>"
|
|
95
|
-
- !ruby/object:Gem::Version
|
|
96
|
-
version: '1.15'
|
|
97
41
|
description: |2
|
|
98
42
|
`css_inline` inlines CSS into HTML documents, using components from Mozilla's Servo project.
|
|
99
43
|
This process is essential for sending HTML emails as you need to use "style" attributes instead of "style" tags.
|
|
@@ -141,7 +85,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
141
85
|
- !ruby/object:Gem::Version
|
|
142
86
|
version: 3.3.26
|
|
143
87
|
requirements:
|
|
144
|
-
- Rust >= 1.
|
|
88
|
+
- Rust >= 1.83
|
|
145
89
|
rubygems_version: 3.4.19
|
|
146
90
|
signing_key:
|
|
147
91
|
specification_version: 4
|