tdiary-style-markdown 0.1.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.
- checksums.yaml +7 -0
- data/.gitignore +36 -0
- data/Gemfile +6 -0
- data/LICENSE +675 -0
- data/README.md +41 -0
- data/Rakefile +1 -0
- data/lib/tdiary/style/markdown/version.rb +7 -0
- data/lib/tdiary/style/markdown.rb +208 -0
- data/lib/tdiary-style-markdown.rb +1 -0
- data/tdiaty-style-markdown.gemspec +29 -0
- data/test/run-test.rb +29 -0
- data/test/tdiary/style/markdown-test.rb +536 -0
- data/test/test-helper.rb +10 -0
- metadata +157 -0
data/README.md
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
# TDiary::Style::Markdown
|
2
|
+
|
3
|
+
"Markdown" style for tDiary 2.x format.
|
4
|
+
|
5
|
+
This is based on tdiary-style-gfm gem.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
gem 'tdiary-style-markdown'
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install tdiary-style-markdown
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
if you want to use this style, add @style into tdiary.conf below:
|
24
|
+
|
25
|
+
@style = 'Markdown'
|
26
|
+
|
27
|
+
## Contributing
|
28
|
+
|
29
|
+
1. Fork it
|
30
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
31
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
32
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
33
|
+
5. Create new Pull Request
|
34
|
+
|
35
|
+
## Copyright
|
36
|
+
|
37
|
+
* Copyright (C) 2003, TADA Tadashi <sho@spc.gr.jp>
|
38
|
+
* Copyright (C) 2004, MoonWolf <moonwolf@moonwolf.com>
|
39
|
+
* Copyright (C) 2012, kdmsnr <kdmsnr@gmail.com>
|
40
|
+
* Copyright (C) 2013, hsbt <shibata.hiroshi@gmail.com>
|
41
|
+
* Copyright (C) 2015, Kenji Okimoto <okimoto@clear-code.com>
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,208 @@
|
|
1
|
+
require 'redcarpet'
|
2
|
+
require 'pygments'
|
3
|
+
require 'twitter-text'
|
4
|
+
|
5
|
+
module TDiary
|
6
|
+
module Style
|
7
|
+
class MarkdownSection
|
8
|
+
def initialize(fragment, author = nil)
|
9
|
+
@author = author
|
10
|
+
@subtitle, @body = fragment.split(/\n/, 2)
|
11
|
+
@subtitle.sub!(/^\#\s*/,'')
|
12
|
+
@body ||= ''
|
13
|
+
|
14
|
+
@categories = get_categories
|
15
|
+
@stripped_subtitle = strip_subtitle
|
16
|
+
|
17
|
+
@subtitle_to_html = @subtitle ? to_html('# ' + @subtitle).gsub(/\A<h\d>|<\/h\d>\z/io, '') : nil
|
18
|
+
@stripped_subtitle_to_html = @stripped_subtitle ? to_html('# ' + @stripped_subtitle).gsub(/\A<h\d>|<\/h\d>\z/io, '') : nil
|
19
|
+
@body_to_html = to_html(@body)
|
20
|
+
end
|
21
|
+
|
22
|
+
def subtitle=(subtitle)
|
23
|
+
@subtitle = (subtitle || '').sub(/^# /,"\##{categories_to_string} ")
|
24
|
+
@strip_subtitle = strip_subtitle
|
25
|
+
end
|
26
|
+
|
27
|
+
def categories=(categories)
|
28
|
+
@subtitle = "#{categories_to_string} " + (strip_subtitle || '')
|
29
|
+
@strip_subtitle = strip_subtitle
|
30
|
+
end
|
31
|
+
|
32
|
+
def to_src
|
33
|
+
r = ''
|
34
|
+
r << "\# #{@subtitle}\n" if @subtitle
|
35
|
+
r << @body
|
36
|
+
end
|
37
|
+
|
38
|
+
def do_html4(date, idx, opt)
|
39
|
+
subtitle = to_html('# ' + @subtitle)
|
40
|
+
subtitle.sub!( %r!<h3>(.+?)</h3>!m ) do
|
41
|
+
"<h3><%= subtitle_proc( Time.at( #{date.to_i} ), #{$1.dump.gsub( /%/, '\\\\045' )} ) %></h3>"
|
42
|
+
end
|
43
|
+
if opt['multi_user'] and @author then
|
44
|
+
subtitle.sub!(/<\/h3>/,%Q|[#{@author}]</h3>|)
|
45
|
+
end
|
46
|
+
r = subtitle
|
47
|
+
r << @body_to_html
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def to_html(string)
|
53
|
+
r = string.dup
|
54
|
+
|
55
|
+
# 1. Stash plugin calls
|
56
|
+
plugin_stashes = []
|
57
|
+
r.gsub!(/\{\{(.*?)\}\}/) do |matched|
|
58
|
+
# Convert `{{ }}' to erb tags
|
59
|
+
plugin_stashes.push([matched, "<%=#{$1}%>"])
|
60
|
+
"@@tdiary-style-markdown-plugin#{plugin_stashes.length - 1}@@"
|
61
|
+
end
|
62
|
+
|
63
|
+
# 2. Apply markdown conversion
|
64
|
+
renderer = Redcarpet::Markdown.new(HTMLwithPygments,
|
65
|
+
fenced_code_blocks: true,
|
66
|
+
tables: true,
|
67
|
+
autolink: true,
|
68
|
+
footnotes: true)
|
69
|
+
r = renderer.render(r)
|
70
|
+
|
71
|
+
# 3. Stash <pre> and <code> tags
|
72
|
+
pre_tag_stashes = []
|
73
|
+
r.gsub!(/<pre(.*?)<\/pre>/m) do |matched|
|
74
|
+
pre_tag_stashes.push(matched)
|
75
|
+
"@@tdiary-style-markdown-pre_tag#{pre_tag_stashes.length - 1}@@"
|
76
|
+
end
|
77
|
+
|
78
|
+
code_tag_stashes = []
|
79
|
+
r.gsub!(/<code(.*?)<\/code>/m) do |matched|
|
80
|
+
code_tag_stashes.push(matched)
|
81
|
+
"@@tdiary-style-markdown-code_tag#{code_tag_stashes.length - 1}@@"
|
82
|
+
end
|
83
|
+
|
84
|
+
# 4. Convert miscellaneous
|
85
|
+
if pre_tag_stashes.none? && code_tag_stashes.none?
|
86
|
+
r = Twitter::Autolink.auto_link_usernames_or_lists(r)
|
87
|
+
end
|
88
|
+
|
89
|
+
r = r.emojify
|
90
|
+
|
91
|
+
# diary anchor
|
92
|
+
r.gsub!(/<h(\d)/) { "<h#{$1.to_i + 2}" }
|
93
|
+
r.gsub!(/<\/h(\d)/) { "</h#{$1.to_i + 2}" }
|
94
|
+
|
95
|
+
# my syntax
|
96
|
+
r.gsub!(/<a href="(\d{4}|\d{6}|\d{8}|\d{8}-\d+)[^\d]*?#?([pct]\d+)?">(.*?)<\/a>/) {
|
97
|
+
unless $3.empty?
|
98
|
+
%Q|<%=my "#{$1}#{$2}", "#{$3}" %>|
|
99
|
+
else
|
100
|
+
%Q|<%=my "#{$1}#{$2}", "#{$1}#{$2}" %>|
|
101
|
+
end
|
102
|
+
}
|
103
|
+
|
104
|
+
# 5. Unstash <pre>, <code> and plugin call
|
105
|
+
pre_tag_stashes.each.with_index do |str, i|
|
106
|
+
plugin_stashes.each.with_index do |(p_str, p_erb), j|
|
107
|
+
if str["@@tdiary-style-markdown-plugin#{j}@@"]
|
108
|
+
str["@@tdiary-style-markdown-plugin#{j}@@"] = CGI.escapeHTML(p_str)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
r["@@tdiary-style-markdown-pre_tag#{i}@@"] = str
|
112
|
+
end
|
113
|
+
code_tag_stashes.each.with_index do |str, i|
|
114
|
+
plugin_stashes.each.with_index do |(p_str, p_erb), j|
|
115
|
+
if str["@@tdiary-style-markdown-plugin#{j}@@"]
|
116
|
+
str["@@tdiary-style-markdown-plugin#{j}@@"] = CGI.escapeHTML(p_str)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
r["@@tdiary-style-markdown-code_tag#{i}@@"] = str
|
120
|
+
end
|
121
|
+
plugin_stashes.each.with_index do |(str, erb), i|
|
122
|
+
if r["@@tdiary-style-markdown-plugin#{i}@@"]
|
123
|
+
r["@@tdiary-style-markdown-plugin#{i}@@"] = erb
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
r
|
128
|
+
end
|
129
|
+
|
130
|
+
def get_categories
|
131
|
+
return [] unless @subtitle
|
132
|
+
cat = /(\\?\[([^\[]+?)\\?\])+/.match(@subtitle).to_a[0]
|
133
|
+
return [] unless cat
|
134
|
+
cat.scan(/\\?\[(.*?)\\?\]/).collect do |c|
|
135
|
+
c[0].split(/,/)
|
136
|
+
end.flatten
|
137
|
+
end
|
138
|
+
|
139
|
+
def strip_subtitle
|
140
|
+
return nil unless @subtitle
|
141
|
+
r = @subtitle.sub(/^((\\?\[[^\[]+?\]\\?)+\s+)?/, '')
|
142
|
+
if r.empty?
|
143
|
+
nil
|
144
|
+
else
|
145
|
+
r
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
class MarkdownDiary
|
151
|
+
def initialize(date, title, body, modified = Time.now)
|
152
|
+
init_diary
|
153
|
+
replace( date, title, body )
|
154
|
+
@last_modified = modified
|
155
|
+
end
|
156
|
+
|
157
|
+
def style
|
158
|
+
'Markdown'
|
159
|
+
end
|
160
|
+
|
161
|
+
def append(body, author = nil)
|
162
|
+
in_code_block = false
|
163
|
+
section = nil
|
164
|
+
body.each_line do |l|
|
165
|
+
case l
|
166
|
+
when /^\#[^\#]/
|
167
|
+
if in_code_block
|
168
|
+
section << l
|
169
|
+
else
|
170
|
+
@sections << MarkdownSection.new(section, author) if section
|
171
|
+
section = l
|
172
|
+
end
|
173
|
+
when /^```/
|
174
|
+
in_code_block = !in_code_block
|
175
|
+
section << l
|
176
|
+
else
|
177
|
+
section = '' unless section
|
178
|
+
section << l
|
179
|
+
end
|
180
|
+
end
|
181
|
+
if section
|
182
|
+
section << "\n" unless section =~ /\n\n\z/
|
183
|
+
@sections << MarkdownSection.new(section, author)
|
184
|
+
end
|
185
|
+
@last_modified = Time.now
|
186
|
+
self
|
187
|
+
end
|
188
|
+
|
189
|
+
def add_section(subtitle, body)
|
190
|
+
@sections = MarkdownSection.new("\# #{subtitle}\n\n#{body}")
|
191
|
+
@sections.size
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
class HTMLwithPygments < Redcarpet::Render::HTML
|
196
|
+
def block_code(code, language)
|
197
|
+
Pygments.highlight(code, lexer: language)
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
# Local Variables:
|
204
|
+
# mode: ruby
|
205
|
+
# indent-tabs-mode: t
|
206
|
+
# tab-width: 3
|
207
|
+
# ruby-indent-level: 3
|
208
|
+
# End:
|
@@ -0,0 +1 @@
|
|
1
|
+
require "tdiary/style/markdown"
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'tdiary/style/markdown/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "tdiary-style-markdown"
|
8
|
+
spec.version = TDiary::Style::Markdown::VERSION
|
9
|
+
spec.authors = ["Kenji Okimoto"]
|
10
|
+
spec.email = ["okimoto@clear-code.com"]
|
11
|
+
spec.description = %q{Markdown Style for tDiary}
|
12
|
+
spec.summary = %q{Markdown Style for tDiary}
|
13
|
+
spec.homepage = "https://github.com/clear-code/tdiary-style-markdown"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_dependency 'redcarpet'
|
22
|
+
spec.add_dependency 'pygments.rb'
|
23
|
+
spec.add_dependency 'twitter-text'
|
24
|
+
spec.add_dependency 'gemoji'
|
25
|
+
|
26
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
27
|
+
spec.add_development_dependency "rake"
|
28
|
+
spec.add_development_dependency "test-unit"
|
29
|
+
end
|
data/test/run-test.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# -*- coding: utf-8 -*-
|
3
|
+
#
|
4
|
+
# Copyright (C) 2013 Kouhei Sutou <kou@clear-code.com>
|
5
|
+
#
|
6
|
+
# This program is free software: you can redistribute it and/or modify
|
7
|
+
# it under the terms of the GNU General Public License as published by
|
8
|
+
# the Free Software Foundation, either version 3 of the License, or
|
9
|
+
# (at your option) any later version.
|
10
|
+
#
|
11
|
+
# This program is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
# GNU General Public License for more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU General Public License
|
17
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
18
|
+
|
19
|
+
$VERBOSE = true
|
20
|
+
|
21
|
+
top_dir = File.expand_path(File.join(File.dirname(__FILE__), ".."))
|
22
|
+
lib_dir = File.join(top_dir, "lib")
|
23
|
+
test_dir = File.dirname(__FILE__)
|
24
|
+
|
25
|
+
require "test-unit"
|
26
|
+
|
27
|
+
$LOAD_PATH.unshift(lib_dir)
|
28
|
+
|
29
|
+
exit Test::Unit::AutoRunner.run(true, test_dir)
|