activemail 1.2.2 → 2.0.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.
Files changed (70) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +65 -2
  3. data/README.md +105 -47
  4. data/UPGRADING.md +112 -0
  5. data/app/assets/stylesheets/activemail/_components.scss +33 -42
  6. data/app/assets/stylesheets/activemail/_dark.scss +31 -20
  7. data/app/assets/stylesheets/activemail/_grid.scss +2 -0
  8. data/app/assets/stylesheets/activemail/_settings.scss +22 -10
  9. data/app/assets/stylesheets/activemail/_utilities.scss +3 -1
  10. data/app/assets/stylesheets/activemail/activemail.scss +6 -5
  11. data/app/helpers/active_mail/styles_helper.rb +14 -15
  12. data/app/views/layouts/activemail/mailer.html.inky-erb +0 -5
  13. data/lib/activemail/asset_pipeline/base.rb +47 -0
  14. data/lib/activemail/asset_pipeline/null.rb +19 -0
  15. data/lib/activemail/asset_pipeline/propshaft.rb +19 -0
  16. data/lib/activemail/asset_pipeline/sprockets.rb +39 -0
  17. data/lib/activemail/asset_pipeline.rb +35 -0
  18. data/lib/activemail/components/base.rb +35 -39
  19. data/lib/activemail/components/block_grid.rb +11 -4
  20. data/lib/activemail/components/button.rb +5 -28
  21. data/lib/activemail/components/button_renderer.rb +65 -0
  22. data/lib/activemail/components/callout.rb +4 -5
  23. data/lib/activemail/components/center.rb +5 -7
  24. data/lib/activemail/components/columns.rb +26 -7
  25. data/lib/activemail/components/container.rb +11 -4
  26. data/lib/activemail/components/cta.rb +9 -33
  27. data/lib/activemail/components/h_line.rb +3 -5
  28. data/lib/activemail/components/info_box.rb +6 -12
  29. data/lib/activemail/components/menu.rb +3 -4
  30. data/lib/activemail/components/menu_item.rb +10 -3
  31. data/lib/activemail/components/row.rb +3 -4
  32. data/lib/activemail/components/spacer.rb +16 -12
  33. data/lib/activemail/components/table_component.rb +23 -0
  34. data/lib/activemail/components/wrapper.rb +10 -4
  35. data/lib/activemail/configuration.rb +43 -57
  36. data/lib/activemail/errors.rb +15 -0
  37. data/lib/activemail/inliner/base.rb +2 -10
  38. data/lib/activemail/inliner/null.rb +0 -5
  39. data/lib/activemail/inliner/roadie.rb +1 -1
  40. data/lib/activemail/inliner.rb +33 -0
  41. data/lib/activemail/parse_error_reporter.rb +5 -4
  42. data/lib/activemail/pipeline.rb +26 -0
  43. data/lib/activemail/quality/builtin_rules.rb +154 -0
  44. data/lib/activemail/quality/configuration.rb +83 -3
  45. data/lib/activemail/quality/guard.rb +45 -87
  46. data/lib/activemail/quality/minitest.rb +41 -25
  47. data/lib/activemail/quality/output_dir.rb +52 -0
  48. data/lib/activemail/quality/preview_renderer.rb +46 -33
  49. data/lib/activemail/quality/render_all.rb +96 -40
  50. data/lib/activemail/quality/rspec.rb +4 -8
  51. data/lib/activemail/quality/rule.rb +47 -0
  52. data/lib/activemail/rails/engine.rb +13 -13
  53. data/lib/activemail/rails/rendering.rb +51 -0
  54. data/lib/activemail/rails/template_handler.rb +3 -1
  55. data/lib/activemail/tokens/button_style.rb +1 -2
  56. data/lib/activemail/tokens/defaults.rb +77 -0
  57. data/lib/activemail/tokens/scss_serializer.rb +4 -4
  58. data/lib/activemail/tokens.rb +19 -58
  59. data/lib/activemail/version.rb +1 -1
  60. data/lib/activemail.rb +89 -61
  61. data/lib/generators/activemail/templates/component.rb.tt +2 -3
  62. data/lib/generators/activemail/templates/initializer.rb +0 -3
  63. data/lib/generators/activemail/templates/mailer_layout.html.inky-erb +0 -2
  64. data/lib/generators/activemail/templates/mailer_layout.html.inky-haml +0 -2
  65. data/lib/generators/activemail/templates/mailer_layout.html.inky-slim +0 -2
  66. data/lib/tasks/activemail.rake +4 -5
  67. metadata +38 -7
  68. data/lib/activemail/components/inky.rb +0 -18
  69. data/lib/activemail/inliner/interceptor.rb +0 -51
  70. data/lib/activemail/rails/compiled_stylesheet.rb +0 -62
@@ -8,8 +8,6 @@ html lang=I18n.locale xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-
8
8
  meta name="supported-color-schemes" content="light dark"
9
9
  | <!--[if mso]><noscript><xml><o:OfficeDocumentSettings><o:PixelsPerInch>96</o:PixelsPerInch></o:OfficeDocumentSettings></xml></noscript><![endif]-->
10
10
  = activemail_inline_styles
11
- / Fallback for when activemail_inline_styles cannot read the compiled asset.
12
- = stylesheet_link_tag "activemail/activemail", media: "all"
13
11
  body style="margin:0;padding:0;word-spacing:normal;"
14
12
  div role="article" aria-roledescription="email" lang=I18n.locale style="width:100%;"
15
13
  container
@@ -20,15 +20,14 @@ namespace :activemail do
20
20
  task render_all: :environment do
21
21
  require 'activemail/quality/render_all'
22
22
 
23
- config = ActiveMail::Quality.config
24
- output_root = defined?(Rails) && Rails.respond_to?(:root) ? Rails.root.join(config.output_dir) : Pathname(config.output_dir)
25
- result = ActiveMail::Quality::RenderAll.new(output_root: output_root, config: config).call
26
- puts "Rendered #{result.rendered} email(s) into #{output_root}"
23
+ root = defined?(Rails) && Rails.respond_to?(:root) && Rails.root ? Rails.root : Pathname.pwd
24
+ result = ActiveMail::Quality::RenderAll.new(root: root, config: ActiveMail::Quality.config).call
25
+ puts "Rendered #{result.rendered} email(s) into #{result.output_root}"
27
26
  # A green run on zero previews would silently verify nothing — make it visible.
28
27
  warn '[activemail] WARNING: no mailer previews were discovered — nothing was checked.' if result.discovered.zero?
29
28
  result.render_failures.each { |key, error| puts " render failed: #{key}: #{error}" }
30
29
  result.guard_failures.each do |key, violations|
31
- puts " guard failed: #{key}", violations.map { |v| " - [#{v.rule}] #{v.message}" }.join("\n")
30
+ puts " guard failed: #{key}", violations.map { |v| " - #{v}" }.join("\n")
32
31
  end
33
32
  abort "\n#{result.broken_required.size} required preview(s) failed: #{result.broken_required.join(', ')}" if result.broken_required.any?
34
33
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activemail
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.2
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Advitam
@@ -16,6 +16,9 @@ dependencies:
16
16
  - - ">="
17
17
  - !ruby/object:Gem::Version
18
18
  version: '1.16'
19
+ - - "<"
20
+ - !ruby/object:Gem::Version
21
+ version: '1.20'
19
22
  type: :runtime
20
23
  prerelease: false
21
24
  version_requirements: !ruby/object:Gem::Requirement
@@ -23,6 +26,9 @@ dependencies:
23
26
  - - ">="
24
27
  - !ruby/object:Gem::Version
25
28
  version: '1.16'
29
+ - - "<"
30
+ - !ruby/object:Gem::Version
31
+ version: '1.20'
26
32
  - !ruby/object:Gem::Dependency
27
33
  name: premailer
28
34
  requirement: !ruby/object:Gem::Requirement
@@ -30,6 +36,9 @@ dependencies:
30
36
  - - ">="
31
37
  - !ruby/object:Gem::Version
32
38
  version: '1.21'
39
+ - - "<"
40
+ - !ruby/object:Gem::Version
41
+ version: '2'
33
42
  type: :runtime
34
43
  prerelease: false
35
44
  version_requirements: !ruby/object:Gem::Requirement
@@ -37,20 +46,29 @@ dependencies:
37
46
  - - ">="
38
47
  - !ruby/object:Gem::Version
39
48
  version: '1.21'
49
+ - - "<"
50
+ - !ruby/object:Gem::Version
51
+ version: '2'
40
52
  - !ruby/object:Gem::Dependency
41
53
  name: sorbet-runtime
42
54
  requirement: !ruby/object:Gem::Requirement
43
55
  requirements:
44
56
  - - ">="
45
57
  - !ruby/object:Gem::Version
46
- version: '0.5'
58
+ version: 0.5.10600
59
+ - - "<"
60
+ - !ruby/object:Gem::Version
61
+ version: '0.7'
47
62
  type: :runtime
48
63
  prerelease: false
49
64
  version_requirements: !ruby/object:Gem::Requirement
50
65
  requirements:
51
66
  - - ">="
52
67
  - !ruby/object:Gem::Version
53
- version: '0.5'
68
+ version: 0.5.10600
69
+ - - "<"
70
+ - !ruby/object:Gem::Version
71
+ version: '0.7'
54
72
  description: |
55
73
  ActiveMail is a plug & play gem for sending beautiful emails, written entirely in Ruby.
56
74
  It turns simple, semantic tags into responsive, bulletproof email markup and ships with
@@ -63,6 +81,7 @@ files:
63
81
  - CHANGELOG.md
64
82
  - LICENSE.txt
65
83
  - README.md
84
+ - UPGRADING.md
66
85
  - app/assets/stylesheets/activemail/_activemail_tokens.scss.erb
67
86
  - app/assets/stylesheets/activemail/_components.scss
68
87
  - app/assets/stylesheets/activemail/_dark.scss
@@ -75,9 +94,15 @@ files:
75
94
  - app/views/layouts/activemail/_head.html.inky-erb
76
95
  - app/views/layouts/activemail/mailer.html.inky-erb
77
96
  - lib/activemail.rb
97
+ - lib/activemail/asset_pipeline.rb
98
+ - lib/activemail/asset_pipeline/base.rb
99
+ - lib/activemail/asset_pipeline/null.rb
100
+ - lib/activemail/asset_pipeline/propshaft.rb
101
+ - lib/activemail/asset_pipeline/sprockets.rb
78
102
  - lib/activemail/components/base.rb
79
103
  - lib/activemail/components/block_grid.rb
80
104
  - lib/activemail/components/button.rb
105
+ - lib/activemail/components/button_renderer.rb
81
106
  - lib/activemail/components/callout.rb
82
107
  - lib/activemail/components/center.rb
83
108
  - lib/activemail/components/columns.rb
@@ -85,32 +110,38 @@ files:
85
110
  - lib/activemail/components/cta.rb
86
111
  - lib/activemail/components/h_line.rb
87
112
  - lib/activemail/components/info_box.rb
88
- - lib/activemail/components/inky.rb
89
113
  - lib/activemail/components/menu.rb
90
114
  - lib/activemail/components/menu_item.rb
91
115
  - lib/activemail/components/row.rb
92
116
  - lib/activemail/components/spacer.rb
117
+ - lib/activemail/components/table_component.rb
93
118
  - lib/activemail/components/wrapper.rb
94
119
  - lib/activemail/configuration.rb
120
+ - lib/activemail/errors.rb
121
+ - lib/activemail/inliner.rb
95
122
  - lib/activemail/inliner/base.rb
96
- - lib/activemail/inliner/interceptor.rb
97
123
  - lib/activemail/inliner/null.rb
98
124
  - lib/activemail/inliner/premailer.rb
99
125
  - lib/activemail/inliner/roadie.rb
100
126
  - lib/activemail/libxml.rb
101
127
  - lib/activemail/parse_error_reporter.rb
128
+ - lib/activemail/pipeline.rb
102
129
  - lib/activemail/quality.rb
130
+ - lib/activemail/quality/builtin_rules.rb
103
131
  - lib/activemail/quality/configuration.rb
104
132
  - lib/activemail/quality/guard.rb
105
133
  - lib/activemail/quality/minitest.rb
134
+ - lib/activemail/quality/output_dir.rb
106
135
  - lib/activemail/quality/preview_renderer.rb
107
136
  - lib/activemail/quality/render_all.rb
108
137
  - lib/activemail/quality/rspec.rb
109
- - lib/activemail/rails/compiled_stylesheet.rb
138
+ - lib/activemail/quality/rule.rb
110
139
  - lib/activemail/rails/engine.rb
140
+ - lib/activemail/rails/rendering.rb
111
141
  - lib/activemail/rails/template_handler.rb
112
142
  - lib/activemail/tokens.rb
113
143
  - lib/activemail/tokens/button_style.rb
144
+ - lib/activemail/tokens/defaults.rb
114
145
  - lib/activemail/tokens/scss_serializer.rb
115
146
  - lib/activemail/version.rb
116
147
  - lib/generators/activemail/component_generator.rb
@@ -145,7 +176,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
145
176
  - !ruby/object:Gem::Version
146
177
  version: '0'
147
178
  requirements: []
148
- rubygems_version: 3.6.9
179
+ rubygems_version: 4.0.20
149
180
  specification_version: 4
150
181
  summary: Plug & play gem to send modern emails, entirely in Ruby, with dark mode and
151
182
  more out of the box.
@@ -1,18 +0,0 @@
1
- # typed: strict
2
- # frozen_string_literal: true
3
-
4
- require_relative 'base'
5
-
6
- module ActiveMail
7
- module Components
8
- # Renders a bare <tr>, useful inside hand-written tables.
9
- class Inky < Base
10
- extend T::Sig
11
-
12
- sig { override.params(_node: Nokogiri::XML::Node, inner: String).returns(String) }
13
- def transform(_node, inner)
14
- %(<tr>#{inner}</tr>)
15
- end
16
- end
17
- end
18
- end
@@ -1,51 +0,0 @@
1
- # typed: strict
2
- # frozen_string_literal: true
3
-
4
- require 'sorbet-runtime'
5
-
6
- module ActiveMail
7
- module Inliner
8
- class Interceptor
9
- class << self
10
- extend T::Sig
11
-
12
- sig { params(message: T.untyped).void }
13
- def delivering_email(message)
14
- config = ActiveMail.configuration
15
- # Runtime check: an engine initializer runs before the host's, so a
16
- # boot-time flag read would always see the default.
17
- return unless config.register_inline_interceptor
18
-
19
- inliner = config.resolved_inliner
20
- return if inliner.noop?
21
-
22
- html_parts(message).each do |part|
23
- part.body = inliner.inline(part.body.to_s)
24
- rescue StandardError => e
25
- # Surface which inliner failed; do not swallow (a silently non-inlined
26
- # mail is worse). Ruby sets e as #cause, preserving the original backtrace.
27
- raise ActiveMail::Inliner::Error, "[#{inliner.class}] CSS inlining failed: #{e.message}"
28
- end
29
- end
30
-
31
- private
32
-
33
- # The html part(s) to inline: a single text/html message, or every text/html
34
- # part of a multipart message. Attachments are never inlined.
35
- sig { params(message: T.untyped).returns(T::Array[T.untyped]) }
36
- def html_parts(message)
37
- return message.all_parts.select { |part| html_body_part?(part) } if message.multipart?
38
-
39
- html_body_part?(message) ? [message] : []
40
- end
41
-
42
- sig { params(part: T.untyped).returns(T::Boolean) }
43
- def html_body_part?(part)
44
- return false unless part.respond_to?(:mime_type) && part.mime_type == 'text/html'
45
-
46
- !(part.respond_to?(:attachment?) && part.attachment?)
47
- end
48
- end
49
- end
50
- end
51
- end
@@ -1,62 +0,0 @@
1
- # typed: strict
2
- # frozen_string_literal: true
3
-
4
- require 'sorbet-runtime'
5
-
6
- module ActiveMail
7
- # Reads a compiled CSS asset's bytes (Sprockets or Propshaft, by duck-type) — the
8
- # bytes, not a digest URL, are what the Premailer adapter needs to inline.
9
- module CompiledStylesheet
10
- class << self
11
- extend T::Sig
12
-
13
- # '' (not nil) on a miss: callers embed the result verbatim, and a missing
14
- # asset must degrade to an empty <style>, never interpolate "nil" into HTML.
15
- sig { params(logical_path: String).returns(String) }
16
- def read(logical_path)
17
- sprockets_source(logical_path) || propshaft_source(logical_path) || ''
18
- end
19
-
20
- private
21
-
22
- # Sprockets: config.assets.compile (dev) resolves logical paths in-memory;
23
- # precompiled (prod) resolves through the manifest. #find_asset covers both.
24
- sig { params(logical_path: String).returns(T.nilable(String)) }
25
- def sprockets_source(logical_path)
26
- assets = rails_assets_environment
27
- return unless assets.respond_to?(:find_asset)
28
-
29
- asset = assets.find_asset(logical_path)
30
- asset&.source&.to_s
31
- end
32
-
33
- # Propshaft: the load_path resolves a logical path to a compiled file on disk.
34
- sig { params(logical_path: String).returns(T.nilable(String)) }
35
- def propshaft_source(logical_path)
36
- assets = rails_assets
37
- load_path = assets.respond_to?(:load_path) ? assets.load_path : nil
38
- return unless load_path.respond_to?(:find)
39
-
40
- asset = load_path.find(logical_path)
41
- asset&.path && File.exist?(asset.path) ? File.read(asset.path) : nil
42
- end
43
-
44
- # config.assets.environment is the Sprockets::Environment; absent under Propshaft.
45
- sig { returns(T.untyped) }
46
- def rails_assets_environment
47
- assets = rails_assets
48
- assets.respond_to?(:environment) ? assets.environment : nil
49
- end
50
-
51
- sig { returns(T.untyped) }
52
- def rails_assets
53
- return unless Object.const_defined?(:Rails)
54
-
55
- rails = Object.const_get(:Rails)
56
- app = rails.respond_to?(:application) ? rails.application : nil
57
- config = app&.config
58
- config.respond_to?(:assets) ? config.assets : nil
59
- end
60
- end
61
- end
62
- end