Skip to content

Commit dfcf059

Browse files
authored
Support basic Markdown formatting (#520)
* Add #markdown utility * Chain markdown formatting and test nested tokens * Support markdown's *italic*
1 parent 1e14946 commit dfcf059

File tree

4 files changed

+71
-0
lines changed

4 files changed

+71
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
### 2.3.1 (Next)
22

33
* [#516](https://github.com/slack-ruby/slack-ruby-client/pull/516): Add support for Ruby 3.3 - [@olleolleolle](https://github.com/olleolleolle).
4+
* [#520](https://github.com/slack-ruby/slack-ruby-client/pull/520): Support basic markdown formatting - [@nbgoodall](https://github.com/nbgoodall).
45
* Your contribution here.
56

67
### 2.3.0 (2024/01/31)

README.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ A Ruby client for the Slack [Web](https://api.slack.com/web), [RealTime Messagin
5858
- [Channel ID formatting](#channel-id-formatting)
5959
- [User ID formatting](#user-id-formatting)
6060
- [URL formatting](#url-formatting)
61+
- [Markdown formatting](#markdown-formatting)
6162
- [Parsing Messages](#parsing-messages)
6263
- [Unescaping message content](#unescaping-message-content)
6364
- [Escaping message content](#escaping-message-content)
@@ -657,6 +658,30 @@ Slack::Messages::Formatting.url_link(text, url)
657658
# => "<https://media.giphy.com/media/AcfTF7tyikWyroP0x7/giphy.gif|party time>"
658659
```
659660

661+
##### Markdown formatting
662+
663+
Slack uses a mishmash of regular markdown formatting with its own syntax. Some features like headings aren't supported and will be left as-is, but others like bold, strikethrough, and links are converted.
664+
665+
```ruby
666+
text = """
667+
## A heading
668+
**Bold text**
669+
~~Strikethrough text~~
670+
_Italic text_
671+
[A link](https://example.com)
672+
`code`
673+
"""
674+
Slack::Messages::Formatting.markdown(text)
675+
# => """
676+
# ## A heading
677+
# *Bold text*
678+
# ~Strikethrough text~
679+
# _Italic text_
680+
# <https://example.com|A link>
681+
# `code`
682+
# """
683+
```
684+
660685
#### Parsing Messages
661686

662687
`Slack::Messages::Formatting` also provides ways to escape or unescape messages. This comes handy, for example, you want to treat all input to a real time bot as plain text.

lib/slack/messages/formatting.rb

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,19 @@ def user_link(user_id)
6868
def url_link(text, url)
6969
"<#{url}|#{text}>"
7070
end
71+
72+
#
73+
# Converts text from basic markdown into Slack's mishmash
74+
# @see https://api.slack.com/reference/surfaces/formatting#basic-formatting
75+
#
76+
def markdown(text)
77+
text
78+
.gsub(/(?<!\*)\*([^*]+)\*(?!\*)/, '_\1_') # italic
79+
.gsub(/\*\*\*(.*?)\*\*\*/, '*_\1_*') # bold & italic
80+
.gsub(/\*\*(.*?)\*\*/, '*\1*') # bold
81+
.gsub(/~~(.*?)~~/, '~\1~') # strikethrough
82+
.gsub(/\[(.*?)\]\((.*?)\)/, '<\2|\1>') # links
83+
end
7184
end
7285
end
7386
end

spec/slack/messages/formatting_spec.rb

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,4 +121,36 @@
121121
expect(formatting.url_link(text, url)).to eq "<#{url}|#{text}>"
122122
end
123123
end
124+
125+
context '#markdown' do
126+
it 'formats markdown bold' do
127+
expect(formatting.markdown('**Le bold**')).to eq '*Le bold*'
128+
end
129+
130+
it 'formats markdown italic' do
131+
expect(formatting.markdown("*L'italic*")).to eq "_L'italic_"
132+
end
133+
134+
it 'formats markdown bold and italic' do
135+
expect(formatting.markdown('***Le bold italic***')).to eq '*_Le bold italic_*'
136+
end
137+
138+
it 'formats markdown strikethrough' do
139+
expect(formatting.markdown('~~Le strikethrough~~')).to eq '~Le strikethrough~'
140+
end
141+
142+
it 'formats markdown links' do
143+
expect(formatting.markdown('[Le link](https://theuselessweb.site)')).to eq '<https://theuselessweb.site|Le link>'
144+
end
145+
146+
it 'formats nested markdown' do
147+
expect(formatting.markdown('**[Le **bold and ~~struckout with *italic*~~** link](https://theuselessweb.site)**')).to(
148+
eq '*<https://theuselessweb.site|Le *bold and ~struckout with _italic_~* link>*'
149+
)
150+
end
151+
152+
it "doesn't format other markdown" do
153+
expect(formatting.markdown('## A heading\n_Italics_\n`code`')).to eq '## A heading\n_Italics_\n`code`'
154+
end
155+
end
124156
end

0 commit comments

Comments
 (0)