css_inline 0.22.0-x86_64-linux → 0.23.0-x86_64-linux
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/README.md +118 -87
- data/lib/css_inline/3.2/css_inline.so +0 -0
- data/lib/css_inline/3.3/css_inline.so +0 -0
- data/lib/css_inline/3.4/css_inline.so +0 -0
- data/lib/css_inline/4.0/css_inline.so +0 -0
- data/src/lib.rs +325 -0
- metadata +5 -6
- data/Cargo.lock +0 -1947
- data/Cargo.toml +0 -3
data/src/lib.rs
ADDED
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
//! Ruby bindings for css-inline
|
|
2
|
+
#![warn(
|
|
3
|
+
clippy::pedantic,
|
|
4
|
+
clippy::doc_markdown,
|
|
5
|
+
clippy::redundant_closure,
|
|
6
|
+
clippy::explicit_iter_loop,
|
|
7
|
+
clippy::match_same_arms,
|
|
8
|
+
clippy::needless_borrow,
|
|
9
|
+
clippy::print_stdout,
|
|
10
|
+
clippy::arithmetic_side_effects,
|
|
11
|
+
clippy::cast_possible_truncation,
|
|
12
|
+
clippy::unwrap_used,
|
|
13
|
+
clippy::map_unwrap_or,
|
|
14
|
+
clippy::trivially_copy_pass_by_ref,
|
|
15
|
+
clippy::needless_pass_by_value,
|
|
16
|
+
missing_debug_implementations,
|
|
17
|
+
trivial_casts,
|
|
18
|
+
trivial_numeric_casts,
|
|
19
|
+
unreachable_pub,
|
|
20
|
+
unused_extern_crates,
|
|
21
|
+
unused_import_braces,
|
|
22
|
+
unused_qualifications,
|
|
23
|
+
variant_size_differences,
|
|
24
|
+
rust_2018_idioms,
|
|
25
|
+
rust_2018_compatibility,
|
|
26
|
+
rust_2021_compatibility
|
|
27
|
+
)]
|
|
28
|
+
use css_inline as rust_inline;
|
|
29
|
+
use magnus::{
|
|
30
|
+
DataTypeFunctions, RHash, Ruby, TryConvert, TypedData, Value, function, method,
|
|
31
|
+
prelude::*,
|
|
32
|
+
scan_args::{Args, get_kwargs, scan_args},
|
|
33
|
+
typed_data::Obj,
|
|
34
|
+
};
|
|
35
|
+
use rayon::prelude::*;
|
|
36
|
+
use std::{
|
|
37
|
+
borrow::Cow,
|
|
38
|
+
num::NonZeroUsize,
|
|
39
|
+
sync::{Arc, Mutex},
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
type RubyResult<T> = Result<T, magnus::Error>;
|
|
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
|
+
/// Apply `width` HTML attributes from CSS `width` properties on supported elements.
|
|
73
|
+
apply_width_attributes: Option<bool>,
|
|
74
|
+
/// Apply `height` HTML attributes from CSS `height` properties on supported elements.
|
|
75
|
+
apply_height_attributes: Option<bool>,
|
|
76
|
+
/// Substitute `var()` references with the values of the custom properties they refer to
|
|
77
|
+
/// and drop the `--*` declarations from the inlined styles.
|
|
78
|
+
resolve_css_variables: Option<bool>,
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
impl TryConvert for Options {
|
|
82
|
+
fn try_convert(v: Value) -> Result<Self, magnus::Error> {
|
|
83
|
+
let h = RHash::try_convert(v)?;
|
|
84
|
+
let ruby = Ruby::get_with(v);
|
|
85
|
+
Ok(Self {
|
|
86
|
+
inline_style_tags: h.aref::<_, Option<bool>>(ruby.to_symbol("inline_style_tags"))?,
|
|
87
|
+
keep_style_tags: h.aref::<_, Option<bool>>(ruby.to_symbol("keep_style_tags"))?,
|
|
88
|
+
keep_link_tags: h.aref::<_, Option<bool>>(ruby.to_symbol("keep_link_tags"))?,
|
|
89
|
+
keep_at_rules: h.aref::<_, Option<bool>>(ruby.to_symbol("keep_at_rules"))?,
|
|
90
|
+
minify_css: h.aref::<_, Option<bool>>(ruby.to_symbol("minify_css"))?,
|
|
91
|
+
base_url: h.aref::<_, Option<String>>(ruby.to_symbol("base_url"))?,
|
|
92
|
+
load_remote_stylesheets: h
|
|
93
|
+
.aref::<_, Option<bool>>(ruby.to_symbol("load_remote_stylesheets"))?,
|
|
94
|
+
cache: h.aref::<_, Option<Obj<StylesheetCache>>>(ruby.to_symbol("cache"))?,
|
|
95
|
+
extra_css: h.aref::<_, Option<String>>(ruby.to_symbol("extra_css"))?,
|
|
96
|
+
preallocate_node_capacity: h
|
|
97
|
+
.aref::<_, Option<usize>>(ruby.to_symbol("preallocate_node_capacity"))?,
|
|
98
|
+
remove_inlined_selectors: h
|
|
99
|
+
.aref::<_, Option<bool>>(ruby.to_symbol("remove_inlined_selectors"))?,
|
|
100
|
+
apply_width_attributes: h
|
|
101
|
+
.aref::<_, Option<bool>>(ruby.to_symbol("apply_width_attributes"))?,
|
|
102
|
+
apply_height_attributes: h
|
|
103
|
+
.aref::<_, Option<bool>>(ruby.to_symbol("apply_height_attributes"))?,
|
|
104
|
+
resolve_css_variables: h
|
|
105
|
+
.aref::<_, Option<bool>>(ruby.to_symbol("resolve_css_variables"))?,
|
|
106
|
+
})
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
fn parse_options<Req>(
|
|
111
|
+
args: &Args<Req, (), (), (), RHash, ()>,
|
|
112
|
+
) -> RubyResult<rust_inline::InlineOptions<'static>> {
|
|
113
|
+
let kwargs: Options = Options::try_convert(args.keywords.as_value())?;
|
|
114
|
+
Ok(rust_inline::InlineOptions {
|
|
115
|
+
inline_style_tags: kwargs.inline_style_tags.unwrap_or(true),
|
|
116
|
+
keep_style_tags: kwargs.keep_style_tags.unwrap_or(false),
|
|
117
|
+
keep_link_tags: kwargs.keep_link_tags.unwrap_or(false),
|
|
118
|
+
keep_at_rules: kwargs.keep_at_rules.unwrap_or(false),
|
|
119
|
+
minify_css: kwargs.minify_css.unwrap_or(false),
|
|
120
|
+
base_url: parse_url(kwargs.base_url)?,
|
|
121
|
+
load_remote_stylesheets: kwargs.load_remote_stylesheets.unwrap_or(true),
|
|
122
|
+
cache: kwargs
|
|
123
|
+
.cache
|
|
124
|
+
.map(|cache| Mutex::new(rust_inline::StylesheetCache::new(cache.size))),
|
|
125
|
+
extra_css: kwargs.extra_css.map(Cow::Owned),
|
|
126
|
+
preallocate_node_capacity: kwargs.preallocate_node_capacity.unwrap_or(32),
|
|
127
|
+
resolver: Arc::new(rust_inline::DefaultStylesheetResolver),
|
|
128
|
+
remove_inlined_selectors: kwargs.remove_inlined_selectors.unwrap_or(false),
|
|
129
|
+
apply_width_attributes: kwargs.apply_width_attributes.unwrap_or(false),
|
|
130
|
+
apply_height_attributes: kwargs.apply_height_attributes.unwrap_or(false),
|
|
131
|
+
resolve_css_variables: kwargs.resolve_css_variables.unwrap_or(false),
|
|
132
|
+
})
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
#[derive(DataTypeFunctions, TypedData)]
|
|
136
|
+
#[magnus(class = "CSSInline::StylesheetCache")]
|
|
137
|
+
struct StylesheetCache {
|
|
138
|
+
size: NonZeroUsize,
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
impl StylesheetCache {
|
|
142
|
+
fn new(args: &[Value]) -> RubyResult<StylesheetCache> {
|
|
143
|
+
fn error() -> magnus::Error {
|
|
144
|
+
let ruby = Ruby::get().expect("Always called from a Ruby thread");
|
|
145
|
+
magnus::Error::new(
|
|
146
|
+
ruby.exception_arg_error(),
|
|
147
|
+
"Cache size must be an integer greater than zero",
|
|
148
|
+
)
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
let args: Args<(), (), (), (), RHash, ()> = scan_args::<(), _, _, _, RHash, _>(args)?;
|
|
152
|
+
let kwargs = get_kwargs::<_, (), (Option<usize>,), ()>(args.keywords, &[], &["size"])
|
|
153
|
+
.map_err(|_| error())?;
|
|
154
|
+
let size = NonZeroUsize::new(kwargs.optional.0.unwrap_or(8)).ok_or_else(error)?;
|
|
155
|
+
Ok(StylesheetCache { size })
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
#[magnus::wrap(class = "CSSInline::CSSInliner")]
|
|
160
|
+
struct CSSInliner {
|
|
161
|
+
inner: rust_inline::CSSInliner<'static>,
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
struct InlineErrorWrapper(rust_inline::InlineError);
|
|
165
|
+
|
|
166
|
+
impl From<InlineErrorWrapper> for magnus::Error {
|
|
167
|
+
fn from(error: InlineErrorWrapper) -> Self {
|
|
168
|
+
let ruby = Ruby::get().expect("Always called from a Ruby thread");
|
|
169
|
+
match error.0 {
|
|
170
|
+
rust_inline::InlineError::IO(error) => {
|
|
171
|
+
magnus::Error::new(ruby.exception_arg_error(), error.to_string())
|
|
172
|
+
}
|
|
173
|
+
rust_inline::InlineError::Network { error, location } => {
|
|
174
|
+
magnus::Error::new(ruby.exception_arg_error(), format!("{error}: {location}"))
|
|
175
|
+
}
|
|
176
|
+
rust_inline::InlineError::ParseError(message) => {
|
|
177
|
+
magnus::Error::new(ruby.exception_arg_error(), message.to_string())
|
|
178
|
+
}
|
|
179
|
+
rust_inline::InlineError::MissingStyleSheet { .. } => {
|
|
180
|
+
magnus::Error::new(ruby.exception_arg_error(), error.0.to_string())
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
struct UrlError {
|
|
187
|
+
error: rust_inline::ParseError,
|
|
188
|
+
url: String,
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
impl From<UrlError> for magnus::Error {
|
|
192
|
+
fn from(error: UrlError) -> magnus::Error {
|
|
193
|
+
let ruby = Ruby::get().expect("Always called from a Ruby thread");
|
|
194
|
+
magnus::Error::new(
|
|
195
|
+
ruby.exception_arg_error(),
|
|
196
|
+
format!("{}: {}", error.error, error.url),
|
|
197
|
+
)
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
fn parse_url(url: Option<String>) -> RubyResult<Option<rust_inline::Url>> {
|
|
202
|
+
Ok(if let Some(url) = url {
|
|
203
|
+
Some(rust_inline::Url::parse(url.as_str()).map_err(|error| UrlError { error, url })?)
|
|
204
|
+
} else {
|
|
205
|
+
None
|
|
206
|
+
})
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
impl CSSInliner {
|
|
210
|
+
fn new(args: &[Value]) -> RubyResult<CSSInliner> {
|
|
211
|
+
let args = scan_args::<(), _, _, _, _, _>(args)?;
|
|
212
|
+
let options = parse_options(&args)?;
|
|
213
|
+
Ok(CSSInliner {
|
|
214
|
+
inner: rust_inline::CSSInliner::new(options),
|
|
215
|
+
})
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
#[allow(clippy::needless_pass_by_value)]
|
|
219
|
+
fn inline(&self, html: String) -> RubyResult<String> {
|
|
220
|
+
Ok(self.inner.inline(&html).map_err(InlineErrorWrapper)?)
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
#[allow(clippy::needless_pass_by_value)]
|
|
224
|
+
fn inline_fragment(&self, html: String, css: String) -> RubyResult<String> {
|
|
225
|
+
Ok(self
|
|
226
|
+
.inner
|
|
227
|
+
.inline_fragment(&html, &css)
|
|
228
|
+
.map_err(InlineErrorWrapper)?)
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
#[allow(clippy::needless_pass_by_value)]
|
|
232
|
+
fn inline_many(&self, html: Vec<String>) -> RubyResult<Vec<String>> {
|
|
233
|
+
inline_many_impl(&html, &self.inner)
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
#[allow(clippy::needless_pass_by_value)]
|
|
237
|
+
fn inline_many_fragments(
|
|
238
|
+
&self,
|
|
239
|
+
html: Vec<String>,
|
|
240
|
+
css: Vec<String>,
|
|
241
|
+
) -> RubyResult<Vec<String>> {
|
|
242
|
+
inline_many_fragments_impl(&html, &css, &self.inner)
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
fn inline(args: &[Value]) -> RubyResult<String> {
|
|
247
|
+
let args = scan_args::<(String,), _, _, _, _, _>(args)?;
|
|
248
|
+
let options = parse_options(&args)?;
|
|
249
|
+
let html = args.required.0;
|
|
250
|
+
Ok(rust_inline::CSSInliner::new(options)
|
|
251
|
+
.inline(&html)
|
|
252
|
+
.map_err(InlineErrorWrapper)?)
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
fn inline_fragment(args: &[Value]) -> RubyResult<String> {
|
|
256
|
+
let args = scan_args::<(String, String), _, _, _, _, _>(args)?;
|
|
257
|
+
let options = parse_options(&args)?;
|
|
258
|
+
let html = args.required.0;
|
|
259
|
+
let css = args.required.1;
|
|
260
|
+
Ok(rust_inline::CSSInliner::new(options)
|
|
261
|
+
.inline_fragment(&html, &css)
|
|
262
|
+
.map_err(InlineErrorWrapper)?)
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
fn inline_many(args: &[Value]) -> RubyResult<Vec<String>> {
|
|
266
|
+
let args = scan_args::<(Vec<String>,), _, _, _, _, _>(args)?;
|
|
267
|
+
let options = parse_options(&args)?;
|
|
268
|
+
let inliner = rust_inline::CSSInliner::new(options);
|
|
269
|
+
inline_many_impl(&args.required.0, &inliner)
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
fn inline_many_impl(
|
|
273
|
+
htmls: &[String],
|
|
274
|
+
inliner: &rust_inline::CSSInliner<'static>,
|
|
275
|
+
) -> RubyResult<Vec<String>> {
|
|
276
|
+
let output: Result<Vec<_>, _> = htmls.par_iter().map(|html| inliner.inline(html)).collect();
|
|
277
|
+
Ok(output.map_err(InlineErrorWrapper)?)
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
fn inline_many_fragments(args: &[Value]) -> RubyResult<Vec<String>> {
|
|
281
|
+
let args = scan_args::<(Vec<String>, Vec<String>), _, _, _, _, _>(args)?;
|
|
282
|
+
let options = parse_options(&args)?;
|
|
283
|
+
let inliner = rust_inline::CSSInliner::new(options);
|
|
284
|
+
inline_many_fragments_impl(&args.required.0, &args.required.1, &inliner)
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
fn inline_many_fragments_impl(
|
|
288
|
+
htmls: &[String],
|
|
289
|
+
css: &[String],
|
|
290
|
+
inliner: &rust_inline::CSSInliner<'static>,
|
|
291
|
+
) -> RubyResult<Vec<String>> {
|
|
292
|
+
let output: Result<Vec<_>, _> = htmls
|
|
293
|
+
.par_iter()
|
|
294
|
+
.zip(css)
|
|
295
|
+
.map(|(html, css)| inliner.inline_fragment(html, css))
|
|
296
|
+
.collect();
|
|
297
|
+
Ok(output.map_err(InlineErrorWrapper)?)
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
#[magnus::init(name = "css_inline")]
|
|
301
|
+
fn init(ruby: &Ruby) -> RubyResult<()> {
|
|
302
|
+
let module = ruby.define_module("CSSInline")?;
|
|
303
|
+
|
|
304
|
+
module.define_module_function("inline", function!(inline, -1))?;
|
|
305
|
+
module.define_module_function("inline_fragment", function!(inline_fragment, -1))?;
|
|
306
|
+
module.define_module_function("inline_many", function!(inline_many, -1))?;
|
|
307
|
+
module.define_module_function(
|
|
308
|
+
"inline_many_fragments",
|
|
309
|
+
function!(inline_many_fragments, -1),
|
|
310
|
+
)?;
|
|
311
|
+
|
|
312
|
+
let class = module.define_class("CSSInliner", ruby.class_object())?;
|
|
313
|
+
class.define_singleton_method("new", function!(CSSInliner::new, -1))?;
|
|
314
|
+
class.define_method("inline", method!(CSSInliner::inline, 1))?;
|
|
315
|
+
class.define_method("inline_fragment", method!(CSSInliner::inline_fragment, 2))?;
|
|
316
|
+
class.define_method("inline_many", method!(CSSInliner::inline_many, 1))?;
|
|
317
|
+
class.define_method(
|
|
318
|
+
"inline_many_fragments",
|
|
319
|
+
method!(CSSInliner::inline_many_fragments, 2),
|
|
320
|
+
)?;
|
|
321
|
+
|
|
322
|
+
let class = module.define_class("StylesheetCache", ruby.class_object())?;
|
|
323
|
+
class.define_singleton_method("new", function!(StylesheetCache::new, -1))?;
|
|
324
|
+
Ok(())
|
|
325
|
+
}
|
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.23.0
|
|
5
5
|
platform: x86_64-linux
|
|
6
6
|
authors:
|
|
7
7
|
- Dmitry Dygalo
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-10-
|
|
11
|
+
date: 2026-10-16 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rake-compiler
|
|
@@ -33,21 +33,20 @@ executables: []
|
|
|
33
33
|
extensions: []
|
|
34
34
|
extra_rdoc_files: []
|
|
35
35
|
files:
|
|
36
|
-
- Cargo.lock
|
|
37
|
-
- Cargo.toml
|
|
38
36
|
- README.md
|
|
39
37
|
- lib/css_inline.rb
|
|
40
38
|
- lib/css_inline/3.2/css_inline.so
|
|
41
39
|
- lib/css_inline/3.3/css_inline.so
|
|
42
40
|
- lib/css_inline/3.4/css_inline.so
|
|
43
41
|
- lib/css_inline/4.0/css_inline.so
|
|
42
|
+
- src/lib.rs
|
|
44
43
|
homepage: https://github.com/Stranger6667/css-inline
|
|
45
44
|
licenses:
|
|
46
45
|
- MIT
|
|
47
46
|
metadata:
|
|
48
47
|
bug_tracker_uri: https://github.com/Stranger6667/css-inline/issues
|
|
49
|
-
changelog_uri: https://github.com/Stranger6667/css-inline/tree/master/
|
|
50
|
-
source_code_uri: https://github.com/Stranger6667/css-inline/tree/master/
|
|
48
|
+
changelog_uri: https://github.com/Stranger6667/css-inline/tree/master/crates/css-inline-ruby/CHANGELOG.md
|
|
49
|
+
source_code_uri: https://github.com/Stranger6667/css-inline/tree/master/crates/css-inline-ruby
|
|
51
50
|
funding_uri: https://github.com/sponsors/Stranger6667/
|
|
52
51
|
post_install_message:
|
|
53
52
|
rdoc_options:
|