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.
@@ -1,25 +1,25 @@
1
1
  [package]
2
- name = "css-inline"
3
- version = "0.17.0"
2
+ name = "css-inline-ruby"
3
+ version = "0.19.0"
4
4
  authors = ["Dmitry Dygalo <dmitry@dygalo.dev>"]
5
- edition = "2021"
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.82"
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.7"
19
+ magnus = "0.8"
20
20
  rayon = "1"
21
21
 
22
22
  [dependencies.css-inline]
23
- version = "0.17"
23
+ version = "0.19.0"
24
24
  default-features = false
25
25
  features = ["http", "file", "stylesheet-cache"]
@@ -27,11 +27,10 @@
27
27
  )]
28
28
  use css_inline as rust_inline;
29
29
  use magnus::{
30
- class, define_module, function, method,
30
+ DataTypeFunctions, RHash, Ruby, TryConvert, TypedData, Value, function, method,
31
31
  prelude::*,
32
- scan_args::{get_kwargs, scan_args, 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 = get_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.0.unwrap_or(true),
81
- keep_style_tags: kwargs.1.unwrap_or(false),
82
- keep_link_tags: kwargs.2.unwrap_or(false),
83
- keep_at_rules: kwargs.3.unwrap_or(false),
84
- base_url: parse_url(kwargs.4)?,
85
- load_remote_stylesheets: kwargs.5.unwrap_or(true),
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
- .6
110
+ .cache
88
111
  .map(|cache| Mutex::new(rust_inline::StylesheetCache::new(cache.size))),
89
- extra_css: kwargs.7.map(Cow::Owned),
90
- preallocate_node_capacity: kwargs.8.unwrap_or(32),
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
- magnus::exception::arg_error(),
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(magnus::exception::arg_error(), error.to_string())
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(magnus::exception::arg_error(), message.to_string())
161
+ magnus::Error::new(ruby.exception_arg_error(), message.to_string())
137
162
  }
138
163
  rust_inline::InlineError::MissingStyleSheet { .. } => {
139
- magnus::Error::new(magnus::exception::arg_error(), error.0.to_string())
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
- magnus::exception::arg_error(),
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", class::object())?;
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", class::object())?;
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.17.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-07-26 00:00:00.000000000 Z
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.82
88
+ - Rust >= 1.83
145
89
  rubygems_version: 3.4.19
146
90
  signing_key:
147
91
  specification_version: 4