├── lib
├── slack_markdown
│ ├── version.rb
│ ├── filters
│ │ ├── ignorable_ancestor_tags.rb
│ │ ├── line_break_filter.rb
│ │ ├── bold_filter.rb
│ │ ├── italic_filter.rb
│ │ ├── strike_filter.rb
│ │ ├── code_filter.rb
│ │ ├── multiple_code_filter.rb
│ │ ├── multiple_quote_filter.rb
│ │ ├── emoji_filter.rb
│ │ ├── quote_filter.rb
│ │ └── convert_filter.rb
│ └── processor.rb
└── slack_markdown.rb
├── Gemfile
├── spec
├── spec_helper.rb
└── slack_markdown
│ ├── filters
│ ├── code_filter_spec.rb
│ ├── multiple_quote_filter_spec.rb
│ ├── bold_filter_spec.rb
│ ├── italic_filter_spec.rb
│ ├── strike_filter_spec.rb
│ ├── multiple_code_filter_spec.rb
│ ├── quote_filter_spec.rb
│ └── emoji_filter_spec.rb
│ └── processor_spec.rb
├── Rakefile
├── .rubocop.yml
├── .github
└── workflows
│ └── spec.yml
├── LICENSE.txt
├── README.md
├── slack_markdown.gemspec
├── .rubocop_todo.yml
└── .gitignore
/lib/slack_markdown/version.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module SlackMarkdown
4 | VERSION = '0.4.1'
5 | end
6 |
--------------------------------------------------------------------------------
/lib/slack_markdown.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require 'slack_markdown/version'
4 | require 'slack_markdown/processor'
5 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | source 'https://rubygems.org'
4 |
5 | # Specify your gem's dependencies in slack_markdown.gemspec
6 | gemspec
7 |
--------------------------------------------------------------------------------
/spec/spec_helper.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require 'rspec'
4 | require 'slack_markdown'
5 |
6 | Dir.glob('./support/**/*.rb').sort.each { |f| require f }
7 |
--------------------------------------------------------------------------------
/Rakefile:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require 'bundler/gem_tasks'
4 | require 'rspec/core/rake_task'
5 |
6 | RSpec::Core::RakeTask.new('spec')
7 | task default: :spec
8 |
--------------------------------------------------------------------------------
/.rubocop.yml:
--------------------------------------------------------------------------------
1 | inherit_from: .rubocop_todo.yml
2 |
3 | AllCops:
4 | NewCops: enable
5 |
6 | Style/Documentation:
7 | Enabled: false
8 |
9 | Layout/LineLength:
10 | Max: 140
11 | Exclude:
12 | - spec/**/*
13 |
14 | Metrics/BlockLength:
15 | Exclude:
16 | - spec/**/*
17 |
--------------------------------------------------------------------------------
/.github/workflows/spec.yml:
--------------------------------------------------------------------------------
1 | name: spec
2 | on: [push, pull_request]
3 | jobs:
4 | spec:
5 | strategy:
6 | fail-fast: false
7 | matrix:
8 | ruby: [2.6, 2.7, 3.0, head]
9 | runs-on: ubuntu-latest
10 | steps:
11 | - uses: actions/checkout@v2
12 | - uses: ruby/setup-ruby@v1
13 | with:
14 | ruby-version: ${{ matrix.ruby }}
15 | bundler-cache: true
16 | - run: bundle exec rubocop
17 | - run: bundle exec rake spec
18 |
--------------------------------------------------------------------------------
/lib/slack_markdown/filters/ignorable_ancestor_tags.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | module SlackMarkdown
4 | module Filters
5 | module IgnorableAncestorTags
6 | DEFAULT_IGNORED_ANCESTOR_TAGS = %w[pre code tt].freeze
7 | def ignored_ancestor_tags
8 | if context[:ignored_ancestor_tags]
9 | DEFAULT_IGNORED_ANCESTOR_TAGS | context[:ignored_ancestor_tags]
10 | else
11 | DEFAULT_IGNORED_ANCESTOR_TAGS
12 | end
13 | end
14 | end
15 | end
16 | end
17 |
--------------------------------------------------------------------------------
/spec/slack_markdown/filters/code_filter_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require 'spec_helper'
4 |
5 | describe SlackMarkdown::Filters::CodeFilter do
6 | subject do
7 | filter = SlackMarkdown::Filters::CodeFilter.new(text)
8 | filter.call.to_s
9 | end
10 |
11 | context '`hoge`' do
12 | let(:text) { '`hoge`' }
13 | it { should eq 'hoge' }
14 | end
15 |
16 | context '`hoge` fuga `piyo`' do
17 | let(:text) { '`hoge` fuga `piyo`' }
18 | it { should eq 'hoge fuga piyo' }
19 | end
20 | end
21 |
--------------------------------------------------------------------------------
/spec/slack_markdown/filters/multiple_quote_filter_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require 'spec_helper'
4 |
5 | describe SlackMarkdown::Filters::MultipleQuoteFilter do
6 | subject do
7 | filter = SlackMarkdown::Filters::MultipleQuoteFilter.new(text)
8 | filter.call.to_s
9 | end
10 |
11 | context '>>> hoge' do
12 | let(:text) { '>>> hoge' }
13 | it { should eq '
hoge' } 14 | end 15 | 16 | context 'multiline' do 17 | let(:text) { ">>>\nhoge\nfuga" } 18 | it { should eq "
hoge\nfuga" } 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /spec/slack_markdown/filters/bold_filter_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper' 4 | 5 | describe SlackMarkdown::Filters::BoldFilter do 6 | subject do 7 | filter = SlackMarkdown::Filters::BoldFilter.new(text) 8 | filter.call.to_s 9 | end 10 | 11 | context '*hoge*' do 12 | let(:text) { '*hoge*' } 13 | it { should eq 'hoge' } 14 | end 15 | 16 | context 'hoge*fuga*poyo' do 17 | let(:text) { 'hoge*fuga*poyo' } 18 | it { should eq 'hoge*fuga*poyo' } 19 | end 20 | 21 | context 'hoge *fuga* poyo' do 22 | let(:text) { 'hoge *fuga* poyo' } 23 | it { should eq 'hoge fuga poyo' } 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /spec/slack_markdown/filters/italic_filter_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper' 4 | 5 | describe SlackMarkdown::Filters::ItalicFilter do 6 | subject do 7 | filter = SlackMarkdown::Filters::ItalicFilter.new(text) 8 | filter.call.to_s 9 | end 10 | 11 | context '_hoge_' do 12 | let(:text) { '_hoge_' } 13 | it { should eq 'hoge' } 14 | end 15 | 16 | context 'hoge_fuga_poyo' do 17 | let(:text) { 'hoge_fuga_poyo' } 18 | it { should eq 'hoge_fuga_poyo' } 19 | end 20 | 21 | context 'hoge _fuga_ poyo' do 22 | let(:text) { 'hoge _fuga_ poyo' } 23 | it { should eq 'hoge fuga poyo' } 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /spec/slack_markdown/filters/strike_filter_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper' 4 | 5 | describe SlackMarkdown::Filters::StrikeFilter do 6 | subject do 7 | filter = SlackMarkdown::Filters::StrikeFilter.new(text) 8 | filter.call.to_s 9 | end 10 | 11 | context '~hoge~' do 12 | let(:text) { '~hoge~' } 13 | it { should eq '
def hoge\n 1 + 1\nend\n" }
14 | end
15 |
16 | context 'multiple multiple code' do
17 | let(:text) { "```\ndef hoge\n 1 + 1\nend\n``` fuga ```\ndef piyo\n 1 * 1\nend\n```" }
18 | it {
19 | should eq "def hoge\n 1 + 1\nend\n fuga def piyo\n 1 * 1\nend\n"
20 | }
21 | end
22 | end
23 |
--------------------------------------------------------------------------------
/spec/slack_markdown/filters/quote_filter_spec.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require 'spec_helper'
4 |
5 | describe SlackMarkdown::Filters::QuoteFilter do
6 | subject do
7 | filter = SlackMarkdown::Filters::QuoteFilter.new(text)
8 | filter.call.to_s
9 | end
10 |
11 | context '> hoge' do
12 | let(:text) { '> hoge' }
13 | it { should eq "hoge\n" } 14 | end 15 | 16 | context 'multiline' do 17 | let(:text) { "> hoge\n> fuga" } 18 | it { should eq "
hoge\nfuga\n" } 19 | end 20 | 21 | context 'include text element' do 22 | let(:text) { "> hoge\n> fuga\ntext\n> hai" } 23 | it { should eq "
hoge\nfuga\ntext\n
hai\n" } 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /lib/slack_markdown/filters/bold_filter.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'html/pipeline' 4 | require 'slack_markdown/filters/ignorable_ancestor_tags' 5 | 6 | module SlackMarkdown 7 | module Filters 8 | class BoldFilter < ::HTML::Pipeline::Filter 9 | include IgnorableAncestorTags 10 | 11 | def call 12 | doc.search('.//text()').each do |node| 13 | content = node.to_html 14 | next if has_ancestor?(node, ignored_ancestor_tags) 15 | next unless content.include?('*') 16 | 17 | html = bold_filter(content) 18 | next if html == content 19 | 20 | node.replace(html) 21 | end 22 | doc 23 | end 24 | 25 | def bold_filter(text) 26 | text.gsub(BOLD_PATTERN) do 27 | "#{Regexp.last_match(1)}" 28 | end 29 | end 30 | 31 | BOLD_PATTERN = /(?<=^|\W)\*(.+)\*(?=\W|$)/.freeze 32 | end 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /lib/slack_markdown/filters/italic_filter.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'html/pipeline' 4 | require 'slack_markdown/filters/ignorable_ancestor_tags' 5 | 6 | module SlackMarkdown 7 | module Filters 8 | class ItalicFilter < ::HTML::Pipeline::Filter 9 | include IgnorableAncestorTags 10 | 11 | def call 12 | doc.search('.//text()').each do |node| 13 | content = node.to_html 14 | next if has_ancestor?(node, ignored_ancestor_tags) 15 | next unless content.include?('_') 16 | 17 | html = italic_filter(content) 18 | next if html == content 19 | 20 | node.replace(html) 21 | end 22 | doc 23 | end 24 | 25 | def italic_filter(text) 26 | text.gsub(ITALIC_PATTERN) do 27 | "#{Regexp.last_match(1)}" 28 | end 29 | end 30 | 31 | ITALIC_PATTERN = /(?<=^|\W)_(.+)_(?=\W|$)/.freeze 32 | end 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /lib/slack_markdown/filters/strike_filter.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'html/pipeline' 4 | require 'slack_markdown/filters/ignorable_ancestor_tags' 5 | 6 | module SlackMarkdown 7 | module Filters 8 | class StrikeFilter < ::HTML::Pipeline::Filter 9 | include IgnorableAncestorTags 10 | 11 | def call 12 | doc.search('.//text()').each do |node| 13 | content = node.to_html 14 | next if has_ancestor?(node, ignored_ancestor_tags) 15 | next unless content.include?('~') 16 | 17 | html = strike_filter(content) 18 | next if html == content 19 | 20 | node.replace(html) 21 | end 22 | doc 23 | end 24 | 25 | def strike_filter(text) 26 | text.gsub(STRIKE_PATTERN) do 27 | "
#{Regexp.last_match(1)}"
30 | end
31 | end
32 |
33 | CODE_PATTERN = /(?<=^|\W)`(.+?)`(?=\W|$)/.freeze
34 | end
35 | end
36 | end
37 |
--------------------------------------------------------------------------------
/lib/slack_markdown/filters/multiple_code_filter.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require 'html/pipeline'
4 | require 'slack_markdown/filters/ignorable_ancestor_tags'
5 |
6 | module SlackMarkdown
7 | module Filters
8 | class MultipleCodeFilter < ::HTML::Pipeline::Filter
9 | include IgnorableAncestorTags
10 |
11 | def call
12 | doc.search('.//text()').each do |node|
13 | content = node.to_html
14 | next if has_ancestor?(node, ignored_ancestor_tags)
15 | next unless content.include?('`')
16 |
17 | html = multiple_code_filter(content)
18 | next if html == content
19 |
20 | node.replace(html)
21 | end
22 | doc
23 | end
24 |
25 | private
26 |
27 | def multiple_code_filter(text)
28 | text.gsub(CODE_PATTERN) do
29 | "#{Regexp.last_match(1)}"
30 | end
31 | end
32 |
33 | CODE_PATTERN = /(?<=^|\W)```\n?((?:.|\n)+?)```(?=\W|$)/.freeze
34 | end
35 | end
36 | end
37 |
--------------------------------------------------------------------------------
/lib/slack_markdown/filters/multiple_quote_filter.rb:
--------------------------------------------------------------------------------
1 | # frozen_string_literal: true
2 |
3 | require 'html/pipeline'
4 | require 'slack_markdown/filters/ignorable_ancestor_tags'
5 |
6 | module SlackMarkdown
7 | module Filters
8 | class MultipleQuoteFilter < ::HTML::Pipeline::Filter
9 | include IgnorableAncestorTags
10 |
11 | def call
12 | doc.search('.//text()').each do |node|
13 | content = node.to_html
14 | next if has_ancestor?(node, ignored_ancestor_tags)
15 | next unless content.include?('>>>')
16 |
17 | html = multiple_quote_filter(content)
18 | next if html == content
19 |
20 | node.replace(html)
21 | end
22 | doc
23 | end
24 |
25 | private
26 |
27 | def multiple_quote_filter(text)
28 | lines = text.split(/^>>>(?:\s|\n)*/, 2)
29 | if lines.size < 2
30 | text
31 | else
32 | "#{lines.join('')}" 33 | end 34 | end 35 | end 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /lib/slack_markdown/filters/emoji_filter.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'html/pipeline' 4 | 5 | module SlackMarkdown 6 | module Filters 7 | class EmojiFilter < ::HTML::Pipeline::EmojiFilter 8 | def emoji_url(name) 9 | emoji_names.include?(name) ? super : original_emoji_path(name) 10 | end 11 | 12 | def emoji_pattern 13 | @emoji_pattern ||= /:(#{(emoji_names + original_emoji_names).map { |name| Regexp.escape(name) }.join('|')}):/ 14 | end 15 | 16 | def emoji_names 17 | self.class.superclass.emoji_names 18 | end 19 | 20 | def original_emoji_set 21 | context[:original_emoji_set] || {} 22 | end 23 | 24 | def original_emoji_names 25 | original_emoji_set.keys 26 | end 27 | 28 | def original_emoji_path(name) 29 | path = original_emoji_set[name] 30 | 31 | if (matches = path.match(/\Aalias:(.+)\z/)) 32 | emoji_url(matches[1]) 33 | else 34 | path 35 | end 36 | end 37 | end 38 | end 39 | end 40 | -------------------------------------------------------------------------------- /lib/slack_markdown/filters/quote_filter.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'html/pipeline' 4 | require 'slack_markdown/filters/ignorable_ancestor_tags' 5 | 6 | module SlackMarkdown 7 | module Filters 8 | class QuoteFilter < ::HTML::Pipeline::Filter 9 | include IgnorableAncestorTags 10 | 11 | def call 12 | html = replace_quote_line(doc.to_s) 13 | collect_blockquote(html) 14 | end 15 | 16 | private 17 | 18 | def replace_quote_line(str) 19 | str.gsub(/^>\s*(.+)(?:\n|$)/) do 20 | "
#{Regexp.last_match(1)}\n" 21 | end 22 | end 23 | 24 | def collect_blockquote(html) 25 | doc = Nokogiri::HTML.fragment(html) 26 | doc.search('blockquote + blockquote').each do |node| 27 | next unless node.previous.name == 'blockquote' 28 | 29 | html = "
#{node.previous.inner_html}#{node.inner_html}" 30 | node.previous.remove 31 | node.replace(html) 32 | end 33 | doc 34 | end 35 | end 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 Ru/MuckRu 2 | 3 | MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SlackMarkdown 2 | 3 | SlackMarkdown (https://api.slack.com/docs/formatting) to HTML converter. 4 | 5 | ## Installation 6 | 7 | Add this line to your application's Gemfile: 8 | 9 | ```ruby 10 | gem 'slack_markdown' 11 | ``` 12 | 13 | And then execute: 14 | 15 | $ bundle 16 | 17 | Or install it yourself as: 18 | 19 | $ gem install slack_markdown 20 | 21 | ## Usage 22 | 23 | ```ruby 24 | require 'slack_markdown' 25 | 26 | processor = SlackMarkdown::Processor.new( 27 | on_slack_channel_id: -> (uid) { 28 | # TODO: use Slack API 29 | return { url: '/general', text: 'general' } 30 | }, 31 | on_slack_user_id: -> (uid) { 32 | # TODO: use Slack API 33 | return { url: '/ru_shalm', text: 'ru_shalm' } 34 | }, 35 | asset_root: '/', 36 | original_emoji_set: { ... }, 37 | ) 38 | 39 | processor.call("<@U12345> hello *world*")[:output].to_s 40 | # => "@ru_shalm hello world" 41 | ``` 42 | 43 | ## Contributing 44 | 45 | 1. Fork it ( https://github.com/rutan/slack_markdown/fork ) 46 | 2. Create your feature branch (`git checkout -b my-new-feature`) 47 | 3. Commit your changes (`git commit -am 'Add some feature'`) 48 | 4. Push to the branch (`git push origin my-new-feature`) 49 | 5. Create a new Pull Request 50 | -------------------------------------------------------------------------------- /slack_markdown.gemspec: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | lib = File.expand_path('lib', __dir__) 4 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 5 | require 'slack_markdown/version' 6 | 7 | Gem::Specification.new do |spec| 8 | spec.name = 'slack_markdown' 9 | spec.version = SlackMarkdown::VERSION 10 | spec.authors = ['Ru/MuckRu'] 11 | spec.email = ['ru_shalm@hazimu.com'] 12 | 13 | spec.summary = 'Convert Slack message markdown to HTML.' 14 | spec.description = 'Convert Slack message markdown to HTML.' 15 | spec.homepage = 'https://github.com/rutan/slack_markdown' 16 | spec.license = 'MIT' 17 | 18 | spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) } 19 | spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) } 20 | spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) 21 | spec.require_paths = ['lib'] 22 | 23 | spec.add_dependency 'escape_utils' 24 | spec.add_dependency 'gemoji' 25 | spec.add_dependency 'html-pipeline', '~> 2.0' 26 | 27 | spec.add_development_dependency 'bundler' 28 | spec.add_development_dependency 'pry' 29 | spec.add_development_dependency 'rake' 30 | spec.add_development_dependency 'rspec', '~> 3.2' 31 | spec.add_development_dependency 'rubocop', '~> 1.22.3' 32 | end 33 | -------------------------------------------------------------------------------- /.rubocop_todo.yml: -------------------------------------------------------------------------------- 1 | # This configuration was generated by 2 | # `rubocop --auto-gen-config` 3 | # on 2021-11-01 14:17:02 UTC using RuboCop version 1.22.3. 4 | # The point is for the user to remove these configuration records 5 | # one by one as the offenses are removed from the code base. 6 | # Note that changes in the inspected code, or installation of new 7 | # versions of RuboCop, may require this file to be generated again. 8 | 9 | # Offense count: 1 10 | # Configuration parameters: Include. 11 | # Include: **/*.gemspec 12 | Gemspec/RequiredRubyVersion: 13 | Exclude: 14 | - 'slack_markdown.gemspec' 15 | 16 | # Offense count: 1 17 | # Configuration parameters: IgnoredMethods, CountRepeatedAttributes. 18 | Metrics/AbcSize: 19 | Max: 43 20 | 21 | # Offense count: 1 22 | # Configuration parameters: IgnoredMethods. 23 | Metrics/CyclomaticComplexity: 24 | Max: 16 25 | 26 | # Offense count: 2 27 | # Configuration parameters: CountComments, CountAsOne, ExcludedMethods, IgnoredMethods. 28 | Metrics/MethodLength: 29 | Max: 42 30 | 31 | # Offense count: 1 32 | # Configuration parameters: IgnoredMethods. 33 | Metrics/PerceivedComplexity: 34 | Max: 19 35 | 36 | # Offense count: 1 37 | # Configuration parameters: ForbiddenDelimiters. 38 | # ForbiddenDelimiters: (?-mix:(^|\s)(EO[A-Z]{1}|END)(\s|$)) 39 | Naming/HeredocDelimiterNaming: 40 | Exclude: 41 | - 'spec/slack_markdown/processor_spec.rb' 42 | -------------------------------------------------------------------------------- /lib/slack_markdown/processor.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'html/pipeline' 4 | require 'slack_markdown/filters/convert_filter' 5 | require 'slack_markdown/filters/multiple_quote_filter' 6 | require 'slack_markdown/filters/quote_filter' 7 | require 'slack_markdown/filters/multiple_code_filter' 8 | require 'slack_markdown/filters/code_filter' 9 | require 'slack_markdown/filters/emoji_filter' 10 | require 'slack_markdown/filters/bold_filter' 11 | require 'slack_markdown/filters/italic_filter' 12 | require 'slack_markdown/filters/strike_filter' 13 | require 'slack_markdown/filters/line_break_filter' 14 | 15 | module SlackMarkdown 16 | class Processor 17 | def initialize(context = {}) 18 | @context = context 19 | end 20 | attr_reader :context 21 | 22 | def filters 23 | @filters ||= [ 24 | SlackMarkdown::Filters::ConvertFilter, # must first run 25 | SlackMarkdown::Filters::MultipleQuoteFilter, 26 | SlackMarkdown::Filters::QuoteFilter, 27 | SlackMarkdown::Filters::MultipleCodeFilter, 28 | SlackMarkdown::Filters::CodeFilter, 29 | SlackMarkdown::Filters::EmojiFilter, 30 | SlackMarkdown::Filters::BoldFilter, 31 | SlackMarkdown::Filters::ItalicFilter, 32 | SlackMarkdown::Filters::StrikeFilter, 33 | SlackMarkdown::Filters::LineBreakFilter 34 | ] 35 | end 36 | 37 | def call(src_text, context = {}, result = nil) 38 | HTML::Pipeline.new(filters, self.context).call(src_text, context, result) 39 | end 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /spec/slack_markdown/filters/emoji_filter_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'spec_helper' 4 | 5 | describe SlackMarkdown::Filters::EmojiFilter do 6 | subject do 7 | context = { 8 | asset_root: '/assets', 9 | original_emoji_set: { 10 | 'ru_shalm' => 'http://toripota.com/img/ru_shalm.png', 11 | 'shalm' => 'alias:ru_shalm', 12 | 'happy' => 'alias:smile' 13 | } 14 | } 15 | filter = SlackMarkdown::Filters::EmojiFilter.new(text, context) 16 | filter.call.to_s 17 | end 18 | 19 | context 'Hello :smile:' do 20 | let(:text) { 'Hello :smile:' } 21 | it { 22 | should eq 'Hello
text formatter 34 |@ru_shalm override_me #ru_shalm override_meis http://toripota.com/img/ru_shalm.png
35 |