Skip to content

Commit 404d869

Browse files
committed
Adding premailer.
1 parent 4f7e2d7 commit 404d869

File tree

11 files changed

+93
-27
lines changed

11 files changed

+93
-27
lines changed

Gemfile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,5 @@ gem "jekyll-feed", "~> 0.17.0"
1717
# Avoid polling for changes on Windows
1818
gem 'wdm', '>= 0.1.0' if Gem.win_platform?
1919
gem "jekyll-toc", "~> 0.19.0"
20+
21+
gem "premailer"

Gemfile.lock

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ GEM
2222
colorator (1.1.0)
2323
concurrent-ruby (1.3.5)
2424
connection_pool (2.5.0)
25+
css_parser (1.21.1)
26+
addressable
2527
csv (3.3.2)
2628
drb (2.2.1)
2729
em-websocket (0.5.3)
@@ -33,6 +35,7 @@ GEM
3335
google-protobuf (4.29.3-x64-mingw-ucrt)
3436
bigdecimal
3537
rake (>= 13)
38+
htmlentities (4.3.4)
3639
http_parser.rb (0.8.0)
3740
i18n (1.14.7)
3841
concurrent-ruby (~> 1.0)
@@ -84,6 +87,10 @@ GEM
8487
racc (~> 1.4)
8588
pathutil (0.16.2)
8689
forwardable-extended (~> 2.6)
90+
premailer (1.27.0)
91+
addressable
92+
css_parser (>= 1.19.0)
93+
htmlentities (>= 4.0.0)
8794
public_suffix (6.0.1)
8895
racc (1.8.1)
8996
rake (13.2.1)
@@ -115,6 +122,7 @@ DEPENDENCIES
115122
jekyll-last-modified-at (~> 1.3)
116123
jekyll-redirect-from (~> 0.16.0)
117124
jekyll-toc (~> 0.19.0)
125+
premailer
118126
wdm (>= 0.1.0)
119127

120128
BUNDLED WITH

_layouts/instantly.html

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@
55
pre {
66
white-space: pre-wrap;
77
}
8+
code {
9+
font-family: 'Courier New', Courier, monospace;
10+
line-height: 1em;
11+
}
812
blockquote.note {
913
background-color: #addde6;
1014
border-radius: 5px;

_plugins/inline_css.rb

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
require 'premailer'
2+
require 'nokogiri'
3+
4+
Jekyll::Hooks.register [:pages, :documents], :post_render do |doc|
5+
if doc.output_ext == '.html'
6+
premailer = Premailer.new(doc.output, with_html_string: true)
7+
html = premailer.to_inline_css
8+
body_content = html[/<body\b[^>]*>(.*?)<\/body>/mi, 1] || html
9+
10+
fragment = Nokogiri::HTML::DocumentFragment.parse(body_content)
11+
fragment.css('code').each do |code_node|
12+
code_node.xpath('.//text()').each do |text_node|
13+
content = text_node.content
14+
# Replace only space characters with &middot; entity, preserve other whitespace
15+
new_nodes = content.chars.map do |char|
16+
if char == ' '
17+
Nokogiri::XML::EntityReference.new(code_node.document, 'middot')
18+
else
19+
Nokogiri::XML::Text.new(char, code_node.document)
20+
end
21+
end
22+
next if new_nodes.length == 1 && new_nodes.first.text?
23+
new_nodes.reverse_each { |n| text_node.add_next_sibling(n) }
24+
text_node.remove
25+
end
26+
end
27+
28+
output_html = fragment.to_html
29+
# Insert <br> after every </div> or </p>
30+
output_html.gsub!(%r{</(div|p)>}i, '</\1><br>')
31+
32+
# Wrap contiguous &middot; entities with a span for color
33+
output_html.gsub!(/((?:&middot;)+)/) do |dots|
34+
%Q{<span style="color:#1a1a1a">#{dots}</span>}
35+
end
36+
37+
doc.output = output_html
38+
end
39+
end

metalama-awareness-campaign/01_more_effective_way.md

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
subject: 'Discover Metalama: A New Code Generation Framework for C#'
2+
subject: "Discover Metalama: A New Code Generation Framework for C#"
33
layout: instantly
44
---
55

@@ -9,7 +9,7 @@ Hi {{firstName}},
99

1010
I'm **{{sendingAccountFirstName}}**, reaching out on behalf of our founder to gather feedback from experienced .NET engineers like you about [Metalama](https://metalama.net?mtm_campaign=awareness&mtm_source=instantly&mtm_kwd=email1), an open source meta-programming framework for code generation, architecture validation, and aspect-oriented programming in C#.
1111

12-
As someone who works with .NET, you know how repetitive patterns and boilerplate can slow down development, clutter codebases, and, hinder its maintenanbility -- although maintenance typically counts for 70% of the total cost of enterprise projects. Metalama is designed to help you eliminate that friction by letting you write special custom attributes, called **aspects**, that act as code templates. Heres a quick look at a simple logging aspect:
12+
As someone who works with .NET, you know how repetitive patterns and boilerplate can slow down development, clutter codebases, and hinder their maintainability -- although maintenance typically counts for 70% of the total cost of enterprise projects. Metalama is designed to help you eliminate that friction by allowing you to write special custom attributes, called **aspects**, that act as code templates. Here's a quick look at a simple logging aspect:
1313

1414
```csharp
1515
using Metalama.Framework.Aspects;
@@ -59,11 +59,11 @@ With Metalama, you can preview and debug generated code, making it easy to see e
5959

6060
**Why choose Metalama?**
6161

62-
**Reduce code and bugs by 15%.** Let the machine handle repetitive tasks so engineers can focus on meaningful work.
62+
* **Reduce code and bugs by 15%.** Let the machine handle repetitive tasks so engineers can focus on meaningful work.
6363

64-
**Maintain clean and readable code.** Simplify your codebase for better maintainability and collaboration.
64+
* **Maintain clean and readable code.** Simplify your codebase for better maintainability and collaboration.
6565

66-
**Enforce architectural consistency.** Define validation rules in C# and receive instant feedback directly in your IDE.
66+
* **Enforce architectural consistency.** Define validation rules in C# and receive instant feedback directly in your IDE.
6767

6868
If you have ever wished for a more effective way to handle logging, validation, or other cross-cutting concerns, Metalama is designed for you. There are [dozens of use cases](https://metalama.net/applications?mtm_campaign=awareness&mtm_source=instantly&mtm_kwd=email1) in any non-trivial application. Explore our [documentation](https://doc.metalama.net/conceptual/getting-started?mtm_campaign=awareness&mtm_source=instantly&mtm_kwd=email1) and [commented examples](https://doc.metalama.net/examples?mtm_campaign=awareness&mtm_source=instantly&mtm_kwd=email1) to learn more.
6969

@@ -72,9 +72,12 @@ We would love to hear your thoughts, questions, or feedback. Join the conversati
7272
Thank you for your time.
7373

7474
Best regards,
75+
7576
**{{sendingAccountFirstName}}**
77+
7678
Community Manager
7779

7880
*P.S. We will send you four more emails about Metalama and then stop. You can unsubscribe at any time.*
7981

80-
{% endraw %}
82+
{% endraw %}
83+

metalama-awareness-campaign/02_caching.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
subject: 'Here is How to Save Time on Caching'
2+
subject: "Here is How to Save Time on Caching"
33
layout: instantly
44
---
55
{% raw %}
@@ -77,7 +77,9 @@ We would love to hear your thoughts, questions, or feedback. Join the conversati
7777
Thank you for your time.
7878

7979
All the best,
80+
8081
**{{sendingAccountFirstName}}**
82+
8183
Community Manager
8284

8385
*P.S. We will send you three more emails about Metalama and then stop. You can unsubscribe at any time.*

metalama-awareness-campaign/03_ui.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
---
2-
subject: 'Building UIs with .NET Without Boilerplate'
2+
subject: "Building UIs with .NET Without Boilerplate"
33
layout: instantly
44
---
55

66
{% raw %}
77

88
Hi {{firstName}},
99

10-
This is **{{sendingAccountFirstName}}** from Metalama. In my previous emails, I showed how Metalama can help you reduce boilerplate code for DevOps concerns like logging and caching. Today, Id like to show you how Metalama can simplify common front-end challenges: think observability (`INotifyPropertyChanged`), undo/redo, change tracking, and WPF dependency properties and commands.
10+
This is **{{sendingAccountFirstName}}** from Metalama. In my previous emails, I showed how Metalama can help you reduce boilerplate code for DevOps concerns like logging and caching. Today, I'd like to show you how Metalama can simplify common front-end challenges: think observability (`INotifyPropertyChanged`), undo/redo, change tracking, and WPF dependency properties and commands.
1111

1212
## INotifyPropertyChanged
1313

@@ -136,7 +136,9 @@ We’d love to hear your thoughts, questions, or feedback. Join the conversation
136136
Thank you for your time.
137137

138138
All the best,
139+
139140
**{{sendingAccountFirstName}}**
141+
140142
Community Manager
141143

142144
*P.S. We will send you two more emails about Metalama and then stop. You can unsubscribe at any time.*

metalama-awareness-campaign/04_patterns.md

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
---
2-
subject: 'Classic Design Patterns Without Boilerplate: Builder, Proxy, and More with Metalama'
2+
subject: "Classic Design Patterns Without Boilerplate: Builder, Proxy, and More with Metalama"
33
layout: instantly
44
---
55

66
{% raw %}
77

88
Hi {{firstName}},
99

10-
This is **{{sendingAccountFirstName}}** from Metalama, the open-source meta-programming framework for .NET. In my previous emails, I showed how Metalama can help you eliminate boilerplate in DevOps and UI scenarios. Today, Id like to show you how Metalama can simplify classic design patterns. Youve already seen the Memento pattern. Lets look at a few more: Builder, Decorator, and Proxy.
10+
This is **{{sendingAccountFirstName}}** from Metalama, the open-source meta-programming framework for .NET. In my previous emails, I showed how Metalama can help you eliminate boilerplate in DevOps and UI scenarios. Today, I'd like to show you how Metalama can simplify classic design patterns. You've already seen the Memento pattern. Let's look at a few more: Builder, Decorator, and Proxy.
1111

1212
## Builder Pattern
1313

14-
The [Builder pattern](https://metalama.net/applications/builder?mtm_campaign=awareness&mtm_source=instantly&mtm_kwd=email4) is a creational design pattern that lets you construct complex objects step by step. Its especially useful for creating immutable objects with many optional parameters or properties. The Abstract Builder variant adds even more flexibility.
14+
The [Builder pattern](https://metalama.net/applications/builder?mtm_campaign=awareness&mtm_source=instantly&mtm_kwd=email4) is a creational design pattern that lets you construct complex objects step by step. It's especially useful for creating immutable objects with many optional parameters or properties. The Abstract Builder variant adds even more flexibility.
1515

1616
The main drawback of the Builder pattern is the sheer amount of repetitive code it requires. With Metalama, you can eliminate almost all of this boilerplate.
1717

@@ -66,7 +66,7 @@ public partial class Song
6666
}
6767
```
6868

69-
Thats a lot of code you dont have to write or maintain!
69+
That's a lot of code you don't have to write or maintain!
7070

7171
For more details, check out these resources:
7272

@@ -77,7 +77,7 @@ For more details, check out these resources:
7777

7878
The [Proxy pattern](https://metalama.net/applications/proxy?mtm_campaign=awareness&mtm_source=instantly&mtm_kwd=email4) is a structural design pattern that lets you provide a substitute or placeholder for another object, typically to add new behavior. In C#, proxies are usually based on interfaces.
7979

80-
You can implement the proxys added behavior in each member, or abstract it into an _Interceptor_.
80+
You can implement the proxy's added behavior in each member, or abstract it into an _Interceptor_.
8181

8282
Implementing the Proxy pattern by hand means duplicating all interface members—a lot of boilerplate. With Metalama, you can generate the entire proxy automatically. Use `ProjectFabric` as a compile-time entry point to tell Metalama what to generate or validate:
8383

@@ -106,9 +106,9 @@ You can find the full example on [GitHub](https://github.com/metalama/Metalama.S
106106

107107
## Deep Cloning
108108

109-
Another common pattern is [deep cloning](https://doc.metalama.net/examples/clone/clone-1?mtm_campaign=awareness&mtm_source=instantly&mtm_kwd=email4). Unlike shallow cloning (which just calls `MemberwiseClone`), deep cloning requires recursively cloning child objects—a task thats tedious and error-prone to do by hand.
109+
Another common pattern is [deep cloning](https://doc.metalama.net/examples/clone/clone-1?mtm_campaign=awareness&mtm_source=instantly&mtm_kwd=email4). Unlike shallow cloning (which just calls `MemberwiseClone`), deep cloning requires recursively cloning child objects—a task that's tedious and error-prone to do by hand.
110110

111-
.NET doesnt have a built-in concept of child objects, so a common solution is to mark child properties and fields with a `[Child]` attribute. Heres how it looks:
111+
.NET doesn't have a built-in concept of "child" objects, so a common solution is to mark child properties and fields with a `[Child]` attribute. Here's how it looks:
112112

113113
```csharp
114114
[Cloneable]
@@ -150,7 +150,7 @@ See the [documentation](https://doc.metalama.net/examples/clone?mtm_campaign=awa
150150

151151
## Why Not Just Use Roslyn Source Generators?
152152

153-
You might wonder: couldnt all this be done with plain Roslyn source generators? For simple cases, yes. But Metalama is much more powerful and easier to use.
153+
You might wonder: couldn't all this be done with plain Roslyn source generators? For simple cases, yes. But Metalama is much more powerful and easier to use.
154154

155155
Metalama is a high-level framework built on top of Roslyn generators. In fact, Metalama uses Roslyn generators for its design-time experience. But with Metalama, you get:
156156

@@ -163,7 +163,7 @@ To learn more about code generation alternatives, read [this article](https://me
163163

164164
## Other Patterns
165165

166-
We cant cover every use case in a single email, but here are more ways Metalama can help:
166+
We can't cover every use case in a single email, but here are more ways Metalama can help:
167167

168168
- **Design Patterns:** [Singleton](https://metalama.net/applications/classic-singleton?mtm_campaign=awareness&mtm_source=instantly&mtm_kwd=email4), [Memento](https://metalama.net/applications/memento?mtm_campaign=awareness&mtm_source=instantly&mtm_kwd=email4), [Factory](https://metalama.net/applications/factory?mtm_campaign=awareness&mtm_source=instantly&mtm_kwd=email4), [Builder](https://metalama.net/applications/builder?mtm_campaign=awareness&mtm_source=instantly&mtm_kwd=email4), [Decorator](https://metalama.net/applications/decorator?mtm_campaign=awareness&mtm_source=instantly&mtm_kwd=email4), [Proxy](https://metalama.net/applications/proxy?mtm_campaign=awareness&mtm_source=instantly&mtm_kwd=email4), ...
169169
- **UI Patterns:** [INotifyPropertyChanged](https://metalama.net/applications/inotifypropertychanged?mtm_campaign=awareness&mtm_source=instantly&mtm_kwd=email4), [Change Tracking](https://metalama.net/applications/command?mtm_campaign=awareness&mtm_source=instantly&mtm_kwd=email4), [Memoization](https://metalama.net/applications/memoization?mtm_campaign=awareness&mtm_source=instantly&mtm_kwd=email4), [Undo/Redo](https://metalama.net/applications/undo-redo?mtm_campaign=awareness&mtm_source=instantly&mtm_kwd=email4), [Command](https://metalama.net/applications/command?mtm_campaign=awareness&mtm_source=instantly&mtm_kwd=email4), [Dependency Properties](https://metalama.net/applications/dependency-property?mtm_campaign=awareness&mtm_source=instantly&mtm_kwd=email4), [Enum View-Mode](https://doc.metalama.net/examples/enum-viewmodel?mtm_campaign=awareness&mtm_source=instantly&mtm_kwd=email4) ...
@@ -177,12 +177,14 @@ For even more use cases and open-source aspect implementations, visit the [Metal
177177

178178
Classic design patterns remain essential in modern .NET applications, but many still require a lot of boilerplate code. Metalama helps you generate this code automatically, so you can focus on what matters most: building great software.
179179

180-
Wed love to hear your thoughts, questions, or feedback. Join the conversation on our [GitHub discussion space](https://github.com/orgs/metalama/discussions/categories/q-a), or simply reply to this email and Ill connect you directly with our engineering team.
180+
We'd love to hear your thoughts, questions, or feedback. Join the conversation on our [GitHub discussion space](https://github.com/orgs/metalama/discussions/categories/q-a), or simply reply to this email and I'll connect you directly with our engineering team.
181181

182182
Thank you for your time.
183183

184184
All the best,
185+
185186
**{{sendingAccountFirstName}}**
187+
186188
Community Manager
187189

188190
*P.S. We will send you two one email about Metalama and then stop. You can unsubscribe at any time.*

metalama-awareness-campaign/05_validating_architecture.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
---
2-
subject: 'Get your development team to adhere to architecture'
2+
subject: "Validating Architecture With Metalama: Compile-Time Safety for Your Codebase"
33
layout: instantly
44
---
55

66
{% raw %}
77

88
Hi {{firstName}},
99

10-
This is **{{sendingAccountFirstName}}** from Metalama. This is my final email in this series. In previous messages, I introduced Metalama's first pillar: code generation, using aspect-oriented programming. Today, I’m excited to introduce Metalama’s second pillar: architecture verification.
10+
This is **{{sendingAccountFirstName}}** from Metalama. In my previous emails, I showed how Metalama can help you reduce boilerplate code for DevOps, UI, and design patterns. Today, let's talk about how Metalama can help you enforce architecture rules and naming conventions at compile time.
1111

1212
Unlike code generation and aspect-oriented programming, which are open source, architecture verification is a proprietary feature available with a [Metalama Professional](https://metalama.net/premium?mtm_campaign=awareness&mtm_source=instantly&mtm_kwd=email5) license.
1313

@@ -117,7 +117,9 @@ You can learn more about architecture validation in our [online documentation](h
117117
Thank you for following along! We hope you enjoyed this series. Remember, the vast majority of Metalama’s features (85% of the codebase) are free and open source. Follow our [Getting Started](https://doc.metalama.net/conceptual/getting-started?mtm_campaign=awareness&mtm_source=instantly&mtm_kwd=email5) guide to start your journey against boilerplate code and architecture headaches—or join the conversation on our [GitHub discussion space](https://github.com/orgs/metalama/discussions/categories/q-a). You can also reply to this email and I’ll connect you directly with our engineering team.
118118

119119
All the best,
120+
120121
**{{sendingAccountFirstName}}**
122+
121123
Community Manager
122124

123125
*P.S. This was the last email in our series.*

metalama-email-course/010-required-contract.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
---
2-
subject: Verifying Required Fields and Parameters With Metalama
2+
subject: "Verifying Required Fields and Parameters With Metalama"
33
---
44

5+
# Verifying Required Fields and Parameters With Metalama
6+
57
Welcome to the Metalama e-mail course! In this first email, we will explore one of the most straightforward features of Metalama: code contracts.
68

79
Developers frequently need to verify that certain fields, properties, parameters, or return values are not null. Even though the code necessary to perform these checks is not complex, it can lead to clutter in the codebase.

0 commit comments

Comments
 (0)