markdown-ruby-china 0.1 → 0.2

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.
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ # coding: utf-8
2
+
3
+ source 'https://rubygems.org'
4
+ gemspec
5
+
@@ -0,0 +1,16 @@
1
+ Markdown render from Ruby China
2
+ ============================
3
+
4
+ ## 如何使用
5
+ ### 添加到Gemfile
6
+ ```ruby
7
+ gem 'markdown-ruby-china'
8
+ ```
9
+
10
+ ### 调用
11
+ ```ruby
12
+ MarkdownTopicConverter.format(content)
13
+ ```
14
+
15
+ ## 新功能
16
+ 1. 代码高亮 自动识别程序语言,文件名,别名等多种格式。
@@ -0,0 +1,244 @@
1
+ # coding: utf-8
2
+
3
+ require 'rails'
4
+ require 'rails_autolink'
5
+ require 'redcarpet'
6
+ require 'singleton'
7
+ require 'md_emoji'
8
+ require 'pygments'
9
+ require "nokogiri"
10
+
11
+ Pygments::Lexer.create :name => "XML", :filenames => ["*.xaml"], :aliases => ["xml"], :mimetypes => ["application/xml+evoque"]
12
+
13
+ module Redcarpet
14
+ module Render
15
+ class HTMLwithSyntaxHighlight < HTML
16
+
17
+ def initialize(extensions={})
18
+ super(extensions.merge(:xhtml => true,
19
+ :no_styles => true,
20
+ :filter_html => true,
21
+ :hard_wrap => true))
22
+ end
23
+
24
+ # 如果换行符没识别,那么code代码块将不会被这里调用
25
+ def block_code(code, lexer)
26
+ lexer = begin
27
+ # 支持程序语言,文件名,别名等多种格式
28
+ lexer = (Pygments::Lexer.find(lexer) || Pygments::Lexer.find_by_extname(".#{lexer}") || Pygments::Lexer.find_by_alias(lexer.downcase))
29
+ lexer.aliases[0]
30
+ rescue
31
+ lexer.to_s.split('.')[-1] || 'text'
32
+ end
33
+
34
+ opts = {:lexer => lexer, :formatter => 'html', :options => {:encoding => 'utf-8', :linenos => 'table'}}
35
+ begin
36
+ Pygments.highlight(code, opts)
37
+ rescue => e
38
+ puts :language => lexer, :code => code
39
+ puts e
40
+ puts e.backtrace
41
+ Pygments.highlight(code, opts.merge(:lexer => 'text'))
42
+ end
43
+ end
44
+
45
+ def autolink(link, link_type)
46
+ # return link
47
+ if link_type.to_s == "email"
48
+ link
49
+ else
50
+ begin
51
+ # 防止 C 的 autolink 出来的内容有编码错误,万一有就直接跳过转换
52
+ # 比如这句:
53
+ # 此版本并非线上的http://yavaeye.com的源码.
54
+ link.match(/.+?/)
55
+ rescue
56
+ return link
57
+ end
58
+ # Fix Chinese neer the URL
59
+ bad_text = link.to_s.match(/[^\w:\/\-\,\$\!\.=\?&#+\|\%]+/im).to_s
60
+ link = link.to_s.gsub(bad_text, '')
61
+ "<a href=\"#{link}\" rel=\"nofollow\" target=\"_blank\">#{link}</a>#{bad_text}"
62
+ end
63
+ end
64
+ end
65
+
66
+ class HTMLwithTopic < HTMLwithSyntaxHighlight
67
+ # Topic 里面,所有的 head 改为 h4 显示
68
+ def header(text, header_level)
69
+ "<h4>#{text}</h4>"
70
+ end
71
+ end
72
+ end
73
+ end
74
+
75
+ class MarkdownConverter
76
+ include Singleton
77
+
78
+ def self.convert(text)
79
+ self.instance.convert(text)
80
+ end
81
+
82
+ def convert(text)
83
+ @converter.render(text)
84
+ end
85
+
86
+ private
87
+ def initialize
88
+ @converter = Redcarpet::Markdown.new(Redcarpet::Render::HTMLwithSyntaxHighlight, {
89
+ :autolink => true,
90
+ :fenced_code_blocks => true,
91
+ :no_intra_emphasis => true
92
+ })
93
+ end
94
+
95
+ end
96
+
97
+ class MarkdownTopicConverter < MarkdownConverter
98
+ def self.format(raw)
99
+ self.instance.format(raw)
100
+ end
101
+
102
+ def format(raw)
103
+ text = raw.clone
104
+ return '' if text.blank?
105
+
106
+ convert_bbcode_img(text)
107
+ users = nomalize_user_mentions(text)
108
+
109
+ # 如果 ``` 在刚刚换行的时候 Redcapter 无法生成正确,需要两个换行
110
+ text.gsub!("\n```","\n\n```")
111
+
112
+ # 调用MarkdownConverter父类来高亮代码
113
+ result = convert(text)
114
+
115
+ doc = Nokogiri::HTML.fragment(result)
116
+ link_mention_floor(doc)
117
+ link_mention_user(doc, users)
118
+ replace_emoji(doc)
119
+
120
+ return doc.to_html.strip
121
+ rescue => e
122
+ puts "MarkdownTopicConverter.format ERROR: #{e}"
123
+ return text
124
+ end
125
+
126
+ private
127
+ # convert bbcode-style image tag [img]url[/img] to markdown syntax ![alt](url)
128
+ def convert_bbcode_img(text)
129
+ text.gsub!(/\[img\](.+?)\[\/img\]/i) {"![#{image_alt $1}](#{$1})"}
130
+ end
131
+
132
+ def image_alt(src)
133
+ File.basename(src, '.*').capitalize
134
+ end
135
+
136
+ # borrow from html-pipeline
137
+ def has_ancestors?(node, tags)
138
+ while node = node.parent
139
+ if tags.include?(node.name.downcase)
140
+ break true
141
+ end
142
+ end
143
+ end
144
+
145
+ # convert '#N楼' to link
146
+ # Refer to emoji_filter in html-pipeline
147
+ def link_mention_floor(doc)
148
+ doc.search('text()').each do |node|
149
+ content = node.to_html
150
+ next if !content.include?('#')
151
+ next if has_ancestors?(node, %w(pre code))
152
+
153
+ html = content.gsub(/#(\d+)([楼樓Ff])/) {
154
+ %(<a href="#reply#{$1}" class="at_floor" data-floor="#{$1}">##{$1}#{$2}</a>)
155
+ }
156
+
157
+ next if html == content
158
+ node.replace(html)
159
+ end
160
+ end
161
+
162
+ NOMALIZE_USER_REGEXP = /(^|[^a-zA-Z0-9_!#\$%&*@@])@([a-zA-Z0-9_]{1,20})/io
163
+ LINK_USER_REGEXP = /(^|[^a-zA-Z0-9_!#\$%&*@@])@(user[0-9]{1,6})/io
164
+
165
+ # rename user name using incremental id
166
+ def nomalize_user_mentions(text)
167
+ users = []
168
+
169
+ text.gsub!(NOMALIZE_USER_REGEXP) do
170
+ prefix = $1
171
+ user = $2
172
+ users.push(user)
173
+ "#{prefix}@user#{users.size}"
174
+ end
175
+
176
+ users
177
+ end
178
+
179
+ # convert '@user' to link
180
+ # match any user even not exist.
181
+ def link_mention_user(doc, users)
182
+ doc.search('text()').each do |node|
183
+ content = node.to_html
184
+ next if !content.include?('@')
185
+ in_code = has_ancestors?(node, %w(pre code))
186
+ html = content.gsub(LINK_USER_REGEXP) {
187
+ prefix = $1
188
+ user_placeholder = $2
189
+ user_id = user_placeholder.sub(/^user/, '').to_i
190
+ user = users[user_id - 1] || user_placeholder
191
+
192
+ if in_code
193
+ "#{prefix}@#{user}"
194
+ else
195
+ %(#{prefix}<a href="/#{user}" class="at_user" title="@#{user}"><i>@</i>#{user}</a>)
196
+ end
197
+ }
198
+
199
+ node.replace(html)
200
+ end
201
+ end
202
+
203
+ def replace_emoji(doc)
204
+ doc.search('text()').each do |node|
205
+ content = node.to_html
206
+ next if !content.include?(':')
207
+ next if has_ancestors?(node, %w(pre code))
208
+
209
+ html = content.gsub(/:(\S+):/) do |emoji|
210
+
211
+ emoji_code = emoji #.gsub("|", "_")
212
+ emoji = emoji_code.gsub(":", "")
213
+
214
+ if MdEmoji::EMOJI.include?(emoji)
215
+ file_name = "#{emoji.gsub('+', 'plus')}.png"
216
+
217
+ %{<img src="#{upload_url}/assets/emojis/#{file_name}" class="emoji" } +
218
+ %{title="#{emoji_code}" alt="" />}
219
+ else
220
+ emoji_code
221
+ end
222
+ end
223
+
224
+ next if html == content
225
+ node.replace(html)
226
+ end
227
+ end
228
+
229
+ # for testing
230
+ def upload_url
231
+ Setting.upload_url
232
+ end
233
+
234
+ def initialize
235
+ @converter = Redcarpet::Markdown.new(Redcarpet::Render::HTMLwithTopic.new, {
236
+ :autolink => true,
237
+ :fenced_code_blocks => true,
238
+ :strikethrough => true,
239
+ :space_after_headers => true,
240
+ :no_intra_emphasis => true
241
+ })
242
+ @emoji = MdEmoji::Render.new
243
+ end
244
+ end
@@ -0,0 +1,19 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'markdown-ruby-china'
3
+ s.version = '0.2'
4
+ s.date = '2013-04-17'
5
+ s.summary = ""
6
+ s.description = ""
7
+ s.authors = ["Ruby-China team", "David Chen"]
8
+ s.email = 'mvjome@gmail.com'
9
+ s.homepage = 'https://github.com/eoecn/markdown-ruby-china'
10
+ s.require_paths = ["lib"]
11
+
12
+ s.add_dependency "rails_autolink"
13
+ s.add_dependency 'redcarpet'
14
+ s.add_dependency 'md_emoji'
15
+ s.add_dependency 'pygments.rb'
16
+ s.add_dependency "nokogiri"
17
+
18
+ s.files = `git ls-files`.split("\n")
19
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: markdown-ruby-china
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.1'
4
+ version: '0.2'
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -97,7 +97,12 @@ email: mvjome@gmail.com
97
97
  executables: []
98
98
  extensions: []
99
99
  extra_rdoc_files: []
100
- files: []
100
+ files:
101
+ - .gitignore
102
+ - Gemfile
103
+ - README.markdown
104
+ - lib/markdown-ruby-china.rb
105
+ - markdown-ruby-china.gemspec
101
106
  homepage: https://github.com/eoecn/markdown-ruby-china
102
107
  licenses: []
103
108
  post_install_message: