hateda2md 0.0.1
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.
- data/.DS_Store +0 -0
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +93 -0
- data/Rakefile +2 -0
- data/example/example.rb +9 -0
- data/hateda2md.gemspec +22 -0
- data/lib/hateda2md/converter.rb +176 -0
- data/lib/hateda2md/entry.rb +5 -0
- data/lib/hateda2md/mdbuilder.rb +105 -0
- data/lib/hateda2md/version.rb +3 -0
- data/lib/hateda2md.rb +10 -0
- data/spec/hateda_converter_spec.rb +369 -0
- data/spec/hateda_entry_spec.rb +34 -0
- data/spec/hateda_mdbuilder_spec.rb +111 -0
- data/spec/spec_helper.rb +4 -0
- data/spec/test1.xml +127 -0
- data/spec/test2.xml +25 -0
- metadata +106 -0
data/.DS_Store
ADDED
Binary file
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 kyoendo
|
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.
|
data/README.md
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
# Hateda2md
|
2
|
+
|
3
|
+
This is a converter that build separated markdown files using for Jekyll from a Hatena-Diary XML file, which written with Hatena notations. You can set several pre-defined filters and/or can define your original filters.
|
4
|
+
|
5
|
+
`Hateda2md`は、はてな記法で書かれたXMLファイルから、Jekyll用のMarkdownファイルを生成するコンバータです。定義済みフィルタを使って、または自身でフィルタを定義して変換を行うことができます。
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
gem 'hateda2md'
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install hateda2md
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
require "Hateda2md"
|
24
|
+
|
25
|
+
mdb = HateDa::MdBuilder.new('hatena-diary.xml')
|
26
|
+
|
27
|
+
# set several pre-defined filters
|
28
|
+
# 幾つかの定義済みフィルタをセットする
|
29
|
+
mdb.set :title
|
30
|
+
mdb.set :subtitle
|
31
|
+
mdb.set :link
|
32
|
+
mdb.set :amazon
|
33
|
+
|
34
|
+
# run converter
|
35
|
+
# 変換を実行する
|
36
|
+
mdb.run
|
37
|
+
|
38
|
+
# save converted data to separated markdown files correspond to each entry
|
39
|
+
# 変換後のデータを各エントリーに対応した複数のMarkdownファイルに保存する
|
40
|
+
mdb.save_to_files
|
41
|
+
|
42
|
+
This process create several markdown files under `md` directory.
|
43
|
+
|
44
|
+
本処理により`md`ディレクトリ以下に、複数のmarkdownファイルが生成されます。
|
45
|
+
|
46
|
+
To set all pre-defined filters, you can call `MdBuilder#pre_defined_filters` or `HateDa::Converter.pre_defined_filters` method.
|
47
|
+
|
48
|
+
すべての定義済みフィルタをセットするには、`MdBuilder#pre_defined_filters`または`HateDa::Converter.pre_defined_filters`メソッドを呼びます。
|
49
|
+
|
50
|
+
# read all pre-defined filters
|
51
|
+
# すべての定義済みフィルタを呼ぶ
|
52
|
+
filters = mdb.pre_defined_filters
|
53
|
+
# => [:title, :subtitle, :subsubtitle, :order_list, :unorder_list, :blockquote, :pre, :super_pre, :footnote, :br, :link, :hatebu, :amazon, :youtube, :image, :gist]
|
54
|
+
|
55
|
+
# set all the pre-defined filters
|
56
|
+
# すべての定義済みフィルタをセットする
|
57
|
+
filters.each { |f| mdb.set f }
|
58
|
+
|
59
|
+
You can define filters.
|
60
|
+
|
61
|
+
独自フィルタを定義できます。
|
62
|
+
|
63
|
+
# define a filter to convert wikipedia hatena tag to a correspond liquid tag
|
64
|
+
# はてな記法によるwikipediaタグをliquid tagに変換するフィルタを定義する
|
65
|
+
mdb.filter(/\[wikipedia:(.*?)\]/) do |md, st|
|
66
|
+
st[:wikipedias] << md[1]
|
67
|
+
"{% wikipedia #{md[1]} %}"
|
68
|
+
end
|
69
|
+
|
70
|
+
`MdBuilder#run` can take parameters for selecting entries to be converted.
|
71
|
+
|
72
|
+
`MdBuilder#run`に引数を渡すことで、特定のエントリだけを変換することができます。
|
73
|
+
|
74
|
+
# convert only #20 entry
|
75
|
+
# 20番目のエントリだけを変換
|
76
|
+
mdb.run(20)
|
77
|
+
|
78
|
+
# convert #100 to last entries
|
79
|
+
# 100番から最後のエントリを変換
|
80
|
+
mdb.run(100..-1)
|
81
|
+
|
82
|
+
# convert 20 entries from #10
|
83
|
+
# 10番から20件を変換
|
84
|
+
mdb.run(10,20)
|
85
|
+
|
86
|
+
|
87
|
+
## Contributing
|
88
|
+
|
89
|
+
1. Fork it
|
90
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
91
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
92
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
93
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/example/example.rb
ADDED
data/hateda2md.gemspec
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/hateda2md/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["kyoendo"]
|
6
|
+
gem.email = ["postagie@gmail.com"]
|
7
|
+
gem.description = %q{Convert Hatena-Diary XML file to Markdown files for Jekyll}
|
8
|
+
gem.summary = %q{
|
9
|
+
This is a converter that build separated markdown files using for Jekyll from a Hatena-Diary XML file, which written with Hatena notations. You can set several pre-defined filters or can define your original filters.
|
10
|
+
}.strip
|
11
|
+
gem.homepage = "https://github.com/melborne/hateda2md"
|
12
|
+
|
13
|
+
gem.files = `git ls-files`.split($\)
|
14
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
15
|
+
gem.name = "hateda2md"
|
16
|
+
gem.require_paths = ["lib"]
|
17
|
+
gem.version = Hateda2md::VERSION
|
18
|
+
gem.required_ruby_version = '>=1.9.2'
|
19
|
+
gem.add_development_dependency 'rspec'
|
20
|
+
gem.add_dependency 'nokogiri'
|
21
|
+
gem.add_dependency 'gsub_filter'
|
22
|
+
end
|
@@ -0,0 +1,176 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require "gsub_filter"
|
3
|
+
require "uri"
|
4
|
+
|
5
|
+
module HateDa::Converter
|
6
|
+
class NoFilterError < StandardError; end
|
7
|
+
|
8
|
+
def set(item, *args)
|
9
|
+
unless HateDa::Converter.pre_defined_filters(true).include?(item)
|
10
|
+
raise NoFilterError, "#{item} does not pre-defined."
|
11
|
+
end
|
12
|
+
send item, *args
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_md(hdtext)
|
16
|
+
(@gf ||= GsubFilter.new).run(hdtext)
|
17
|
+
end
|
18
|
+
|
19
|
+
def clear_filter
|
20
|
+
@gf.filters.clear if @gf
|
21
|
+
end
|
22
|
+
|
23
|
+
def stocks
|
24
|
+
@gf.stocks if @gf
|
25
|
+
end
|
26
|
+
|
27
|
+
def filter(pattern, opt={}, &replace)
|
28
|
+
@gf ||= GsubFilter.new
|
29
|
+
@gf.filter(pattern, opt, &replace)
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.pre_defined_filters(aliases=false)
|
33
|
+
als = aliases ? [] : [:header, :subheader, :subsubheader, :ul, :ol]
|
34
|
+
private_instance_methods(false) - [:SYM] - als
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
def SYM(key)
|
39
|
+
{h1:'#',h2:'##',h3:'###',h4:'####',h5:'#####'}[key]
|
40
|
+
end
|
41
|
+
|
42
|
+
def title(h=:h1)
|
43
|
+
filter(/\*p?\d+\*(.*)$/) do |md, st|
|
44
|
+
st[:titles] << md[1]
|
45
|
+
"#{SYM(h)}#{md[1]}"
|
46
|
+
end
|
47
|
+
filter(/^#{SYM(h)}.*$/, global:false) do |md, st|
|
48
|
+
st[:titles].size == 1 ? '' : md.to_s
|
49
|
+
end
|
50
|
+
end
|
51
|
+
alias :header :title
|
52
|
+
|
53
|
+
def subtitle(h=:h2)
|
54
|
+
filter(/^\*\*((?!\*).*)$/) do |md, st|
|
55
|
+
st[:subtitles] << md[1]
|
56
|
+
"#{SYM(h)}#{md[1]}"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
alias :subheader :subtitle
|
60
|
+
|
61
|
+
def subsubtitle(h=:h3)
|
62
|
+
filter(/^\*\*\*((?!\*).*)$/) do |md, st|
|
63
|
+
st[:subsubtitles] << md[1]
|
64
|
+
"#{SYM(h)}#{md[1]}"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
alias :subsubheader :subsubtitle
|
68
|
+
|
69
|
+
def order_list
|
70
|
+
filter(/^(\++)\s*(.*?)$/) do |md, st|
|
71
|
+
st[:order_lists] << md[2]
|
72
|
+
shift = (" " * 4) * (md[1].size-1)
|
73
|
+
"#{shift}1. #{md[2]}"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
alias :ol :order_list
|
77
|
+
|
78
|
+
def unorder_list
|
79
|
+
filter(/^(\-+)\s*(.*?)$/) do |md, st|
|
80
|
+
st[:unorder_lists] << md[2]
|
81
|
+
shift = (" " * 4) * (md[1].size-1)
|
82
|
+
"#{shift}- #{md[2]}"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
alias :ul :unorder_list
|
86
|
+
|
87
|
+
def blockquote
|
88
|
+
filter(/^>>\n(.*?)^<<$/m) do |md|
|
89
|
+
"\n" + md[1].lines.map { |line| "> #{line}" }.join
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def pre
|
94
|
+
filter(/^>\|\n(.*?)^\|<$/m) do |md|
|
95
|
+
"\n" + md[1].lines.map { |line| " #{line}" }.join
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def super_pre
|
100
|
+
filter(/^>\|(\w+)?\|/) do |md|
|
101
|
+
lang = md[1] || "bash"
|
102
|
+
"{% highlight #{lang} %}"
|
103
|
+
end
|
104
|
+
|
105
|
+
filter(/^\|\|</) { "{% endhighlight %}" }
|
106
|
+
end
|
107
|
+
|
108
|
+
def footnote
|
109
|
+
filter(/\(\((.*?)\)\)/) do |md, st|
|
110
|
+
"{% fn_ref #{st[:footnotes].size+1} %}"
|
111
|
+
.tap { st[:footnotes] << "{% fn #{md[1]} %}" }
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def br
|
116
|
+
filter("\n\n") { "\n" }
|
117
|
+
end
|
118
|
+
|
119
|
+
def link
|
120
|
+
url_r = URI.regexp(['http', 'https'])
|
121
|
+
|
122
|
+
filter(/(?:(?<=[ \(])|^)#{url_r}(?!\s%})(?:(?=[ \)])|$)/) do |md|
|
123
|
+
"[#{md}](#{md})"
|
124
|
+
end
|
125
|
+
|
126
|
+
filter(/\[(#{url_r})(?::title=?(.*?))\]/) do |md|
|
127
|
+
t = md.captures.last
|
128
|
+
title = t.empty? ? ((st = stocks[:titles]) ? st.first : 'link') : t
|
129
|
+
"[#{title}](#{md[1]})"
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def hatebu
|
134
|
+
url_r = URI.regexp(['http', 'https'])
|
135
|
+
filter(/\[(#{url_r}):bookmark\]/) do |md|
|
136
|
+
"{% hatebu #{md[1]} %}"
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def amazon
|
141
|
+
filter(/\[?(?:isbn|asin):(\w+)(?::(title|detail|image))?\]?/i) do |md|
|
142
|
+
case md[2]
|
143
|
+
when 'title'
|
144
|
+
"{{ '#{md[1]}' | amazon_link }}"
|
145
|
+
when 'image'
|
146
|
+
"{{ '#{md[1]}' | amazon_medium_image }}"
|
147
|
+
when 'detail'
|
148
|
+
"{{ '#{md[1]}' | amazon_medium_image }}\n{{ '#{md[1]}' | amazon_link }} by {{ '#{md[1]}' | amazon_authors }}"
|
149
|
+
else
|
150
|
+
"{{ '#{md[1]}' | amazon_medium_image }}"
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
def youtube
|
156
|
+
filter(/[\(\[]?\s*https?:\/\/.*?youtube.*?\?v=([a-zA-Z0-9_-]+):movie\s*[\]\)]?/) do |md|
|
157
|
+
"{% youtube #{md[1]} %}"
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
def image
|
162
|
+
filter(/\[?f:id:(.*?):(\d+)(\w):image.*?\]?/) do |md|
|
163
|
+
m1, m2, m3 = md.captures
|
164
|
+
ft = %w(png jpg bmp gif).detect { |e| e[/^#{m3}/] }
|
165
|
+
host = "http://img.f.hatena.ne.jp/images/fotolife"
|
166
|
+
%{\n\n}
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
def gist
|
171
|
+
host = %r{https?://gist.github.com/}
|
172
|
+
filter(/<script src=\"#{host}(\d+)\.js\?file=(.*?)\"><\/script>/) do |md|
|
173
|
+
"{% gist #{md[1]} #{md[2]} %}"
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require "nokogiri"
|
3
|
+
class String
|
4
|
+
def ~
|
5
|
+
mergin = scan(/^ +/).map(&:size).min
|
6
|
+
gsub(/^ {#{mergin}}/, '')
|
7
|
+
end
|
8
|
+
|
9
|
+
def to_nil
|
10
|
+
self.empty? ? nil : self
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class HateDa::MdBuilder
|
15
|
+
attr_reader :entries
|
16
|
+
def initialize(path)
|
17
|
+
@entries = build_entries(path)
|
18
|
+
end
|
19
|
+
|
20
|
+
def build_entries(filepath)
|
21
|
+
xml = Nokogiri::XML(open filepath)
|
22
|
+
xml.search('day').map do |ent|
|
23
|
+
date = ent.attributes['date'].value
|
24
|
+
body = ent.css('body').text.strip
|
25
|
+
mdbody = nil
|
26
|
+
title = ent.attributes['title'].value
|
27
|
+
HateDa::Entry[date, body, mdbody, title]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def set(item, *args)
|
32
|
+
entries.each { |ent| ent.set item, *args }
|
33
|
+
end
|
34
|
+
|
35
|
+
def filter(pattern, opt={}, &replace)
|
36
|
+
entries.each { |ent| ent.filter(pattern, opt, &replace) }
|
37
|
+
end
|
38
|
+
|
39
|
+
def pre_defined_filters(alias_flag=false)
|
40
|
+
HateDa::Converter.pre_defined_filters(alias_flag)
|
41
|
+
end
|
42
|
+
|
43
|
+
def run(*range)
|
44
|
+
range = [0..-1] if range.empty?
|
45
|
+
entries[*range].map do |entry|
|
46
|
+
md = entry.to_md(entry.ent_body)
|
47
|
+
entry.ent_title = get_title(entry) if entry.ent_title.empty?
|
48
|
+
entry.ent_mdbody = md
|
49
|
+
entry
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def save_to_files(dir='md', ext='md')
|
54
|
+
md_entries = entries.select { |ent| ent.ent_mdbody }
|
55
|
+
unless md_entries.empty?
|
56
|
+
Dir.mkdir(dir) unless Dir.exist?(dir)
|
57
|
+
md_entries.each do |ent|
|
58
|
+
path = "#{dir}/#{ent.ent_date}-#{title_for_file(ent.ent_title)}.#{ext}"
|
59
|
+
File.open(path, 'w') do |f|
|
60
|
+
f.puts header(ent.ent_title, ent.ent_date)
|
61
|
+
f.puts ent.ent_mdbody
|
62
|
+
f.puts footnotes(ent.stocks[:footnotes]) unless ent.stocks[:footnotes].empty?
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
rescue => e
|
67
|
+
print "class => #{e.class}\nmessage => #{e.message}\nbacktrace => #{e.backtrace}\n"
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
def get_title(entry)
|
72
|
+
entry.stocks[:titles].first || 'notitle'
|
73
|
+
end
|
74
|
+
|
75
|
+
def title_for_file(title)
|
76
|
+
title.scan(/\w+/).join('-').to_nil || 'notitle'
|
77
|
+
end
|
78
|
+
|
79
|
+
def header(title, date)
|
80
|
+
title = title.gsub(/['"`]/, '')
|
81
|
+
~<<-EOS
|
82
|
+
---
|
83
|
+
layout: post
|
84
|
+
title: "#{title}"
|
85
|
+
date: #{date}
|
86
|
+
comments: true
|
87
|
+
categories:
|
88
|
+
tags:
|
89
|
+
published: true
|
90
|
+
---
|
91
|
+
|
92
|
+
EOS
|
93
|
+
end
|
94
|
+
|
95
|
+
def footnotes(fnotes)
|
96
|
+
notes = fnotes.map { |note| "#{note}" }.join("\n ")
|
97
|
+
~<<-EOS
|
98
|
+
|
99
|
+
{% footnotes %}
|
100
|
+
#{notes}
|
101
|
+
{% endfootnotes %}
|
102
|
+
EOS
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
data/lib/hateda2md.rb
ADDED
@@ -0,0 +1,369 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require_relative "spec_helper"
|
4
|
+
|
5
|
+
include HateDa::Converter
|
6
|
+
|
7
|
+
describe HateDa::Converter do
|
8
|
+
context "pass a text to to_md method" do
|
9
|
+
before(:each) do
|
10
|
+
@hdtext = <<EOS
|
11
|
+
*p1*title1
|
12
|
+
content1
|
13
|
+
content2
|
14
|
+
**subtitle1
|
15
|
+
content3
|
16
|
+
content4
|
17
|
+
**subtitle2
|
18
|
+
contetn5
|
19
|
+
*123*title2
|
20
|
+
|
21
|
+
EOS
|
22
|
+
end
|
23
|
+
|
24
|
+
after(:each) do
|
25
|
+
clear_filter
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should not change the text when filter is empty" do
|
29
|
+
hdtext = "*p1*title1\ncontent"
|
30
|
+
to_md(hdtext).should eql hdtext
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should raise error when set non-defined tags" do
|
34
|
+
->{ set(:hello) }.should raise_error(HateDa::Converter::NoFilterError)
|
35
|
+
end
|
36
|
+
|
37
|
+
context "header" do
|
38
|
+
it "change a header" do
|
39
|
+
hdtext = "*p1*title1\ncontent\n*p2*title2"
|
40
|
+
md = "#title1\ncontent\n#title2"
|
41
|
+
set :header
|
42
|
+
to_md(hdtext).should eql md
|
43
|
+
stocks[:titles].should eql ['title1', 'title2']
|
44
|
+
end
|
45
|
+
|
46
|
+
it "change a header by h3" do
|
47
|
+
hdtext = "*p1*title1\ncontent\n*p2*title2\ncontent"
|
48
|
+
md = "###title1\ncontent\n###title2\ncontent"
|
49
|
+
set :header, :h3
|
50
|
+
to_md(hdtext).should eql md
|
51
|
+
end
|
52
|
+
|
53
|
+
it "change several headers with :title(alias of :header)" do
|
54
|
+
hdtext = "*123*title1\ncontent1\n*p3*title2\ncontent2"
|
55
|
+
md = "#title1\ncontent1\n#title2\ncontent2"
|
56
|
+
set :title
|
57
|
+
to_md(hdtext).should eql md
|
58
|
+
stocks[:titles].should eql ['title1', 'title2']
|
59
|
+
end
|
60
|
+
|
61
|
+
it "change a subheader" do
|
62
|
+
hdtext = "**subtitle1\ncontent**2"
|
63
|
+
md = "##subtitle1\ncontent**2"
|
64
|
+
set :subheader
|
65
|
+
to_md(hdtext).should eql md
|
66
|
+
end
|
67
|
+
|
68
|
+
it "change subheaders with :subtitle(alias of :subheader)" do
|
69
|
+
hdtext = "**subtitle1\ncontent1\n**subtitle2\ncontent**2"
|
70
|
+
md = "##subtitle1\ncontent1\n##subtitle2\ncontent**2"
|
71
|
+
set :subtitle
|
72
|
+
to_md(hdtext).should eql md
|
73
|
+
end
|
74
|
+
|
75
|
+
it "change a subsubheader" do
|
76
|
+
hdtext = "***subsubtitle1\ncontent***2"
|
77
|
+
md = "###subsubtitle1\ncontent***2"
|
78
|
+
set :subsubheader
|
79
|
+
to_md(hdtext).should eql md
|
80
|
+
end
|
81
|
+
|
82
|
+
it "change mixed title cases1" do
|
83
|
+
hdtext = "*p1*title\n***sstitle\ncontent\n**stit***le\nconten**t\n***sstitle"
|
84
|
+
set :subheader
|
85
|
+
md = "*p1*title\n***sstitle\ncontent\n##stit***le\nconten**t\n***sstitle"
|
86
|
+
to_md(hdtext).should eql md
|
87
|
+
end
|
88
|
+
|
89
|
+
it "change mixed title cases2" do
|
90
|
+
hdtext = "*p1*title\n***sstitle\ncontent\n**stit***le\nconten**t\n***sstitle"
|
91
|
+
set :subsubtitle
|
92
|
+
md = "*p1*title\n###sstitle\ncontent\n**stit***le\nconten**t\n###sstitle"
|
93
|
+
to_md(hdtext).should eql md
|
94
|
+
end
|
95
|
+
|
96
|
+
it "change mixed title cases3" do
|
97
|
+
hdtext = "*p1*title\n***sstitle\ncontent\n**stit***le\n*p2*title2\nconten**t\n***sstitle"
|
98
|
+
set :title
|
99
|
+
set :subtitle
|
100
|
+
md = "#title\n***sstitle\ncontent\n##stit***le\n#title2\nconten**t\n***sstitle"
|
101
|
+
to_md(hdtext).should eql md
|
102
|
+
end
|
103
|
+
|
104
|
+
it "change mixed title cases4" do
|
105
|
+
hdtext = "*p1*title\n***sstitle1\ncontent\n**stit***le\nconten**t\n***sstitle2"
|
106
|
+
set :subtitle
|
107
|
+
set :subsubtitle
|
108
|
+
md = "*p1*title\n###sstitle1\ncontent\n##stit***le\nconten**t\n###sstitle2"
|
109
|
+
to_md(hdtext).should eql md
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
context "list" do
|
114
|
+
it "change ordered list" do
|
115
|
+
hdtext = "+item1\n+item2\n+item3"
|
116
|
+
set :order_list
|
117
|
+
md = "1. item1\n1. item2\n1. item3"
|
118
|
+
to_md(hdtext).should eql md
|
119
|
+
end
|
120
|
+
|
121
|
+
it "change nested ordered list" do
|
122
|
+
hdtext = <<EOS
|
123
|
+
+item1
|
124
|
+
++item1-1
|
125
|
+
++item1-2
|
126
|
+
+item2
|
127
|
+
+item3
|
128
|
+
++item3-1
|
129
|
+
+++item3-1-1
|
130
|
+
+++item3-1-2
|
131
|
+
++item3-2
|
132
|
+
EOS
|
133
|
+
|
134
|
+
md = <<EOS
|
135
|
+
1. item1
|
136
|
+
1. item1-1
|
137
|
+
1. item1-2
|
138
|
+
1. item2
|
139
|
+
1. item3
|
140
|
+
1. item3-1
|
141
|
+
1. item3-1-1
|
142
|
+
1. item3-1-2
|
143
|
+
1. item3-2
|
144
|
+
EOS
|
145
|
+
set :order_list
|
146
|
+
to_md(hdtext).should eql md
|
147
|
+
end
|
148
|
+
|
149
|
+
it "change unordered list" do
|
150
|
+
hdtext = "-item1\n-item2\n-item3"
|
151
|
+
set :unorder_list
|
152
|
+
md = "- item1\n- item2\n- item3"
|
153
|
+
to_md(hdtext).should eql md
|
154
|
+
end
|
155
|
+
|
156
|
+
it "change nested unordered list" do
|
157
|
+
hdtext = <<EOS
|
158
|
+
-item1
|
159
|
+
--item1-1
|
160
|
+
--item1-2
|
161
|
+
-item2
|
162
|
+
-item3
|
163
|
+
--item3-1
|
164
|
+
---item3-1-1
|
165
|
+
---item3-1-2
|
166
|
+
--item3-2
|
167
|
+
EOS
|
168
|
+
|
169
|
+
md = <<EOS
|
170
|
+
- item1
|
171
|
+
- item1-1
|
172
|
+
- item1-2
|
173
|
+
- item2
|
174
|
+
- item3
|
175
|
+
- item3-1
|
176
|
+
- item3-1-1
|
177
|
+
- item3-1-2
|
178
|
+
- item3-2
|
179
|
+
EOS
|
180
|
+
set :unorder_list
|
181
|
+
to_md(hdtext).should eql md
|
182
|
+
end
|
183
|
+
|
184
|
+
|
185
|
+
end
|
186
|
+
|
187
|
+
context "pre" do
|
188
|
+
it "change blockquote '>> <<' to '>'" do
|
189
|
+
hdtext = <<EOS
|
190
|
+
>>
|
191
|
+
blockquoted
|
192
|
+
blockquoted
|
193
|
+
blockquoted
|
194
|
+
<<
|
195
|
+
EOS
|
196
|
+
md = <<EOS
|
197
|
+
|
198
|
+
> blockquoted
|
199
|
+
> blockquoted
|
200
|
+
> blockquoted
|
201
|
+
|
202
|
+
EOS
|
203
|
+
set :blockquote
|
204
|
+
to_md(hdtext).should eql md
|
205
|
+
end
|
206
|
+
|
207
|
+
it "change pre '>|' to 4 spaces" do
|
208
|
+
hdtext = <<EOS
|
209
|
+
>|
|
210
|
+
blockquoted
|
211
|
+
blockquoted
|
212
|
+
blockquoted
|
213
|
+
|<
|
214
|
+
EOS
|
215
|
+
md = <<EOS
|
216
|
+
|
217
|
+
blockquoted
|
218
|
+
blockquoted
|
219
|
+
blockquoted
|
220
|
+
|
221
|
+
EOS
|
222
|
+
set :pre
|
223
|
+
to_md(hdtext).should eql md
|
224
|
+
end
|
225
|
+
|
226
|
+
it "change super_pre '>|type|' to highlight tag" do
|
227
|
+
hdtext = <<EOS
|
228
|
+
>|ruby|
|
229
|
+
def hello(name)
|
230
|
+
"hello, \#{name}!"
|
231
|
+
end
|
232
|
+
||<
|
233
|
+
EOS
|
234
|
+
md = <<EOS
|
235
|
+
{% highlight ruby %}
|
236
|
+
def hello(name)
|
237
|
+
"hello, \#{name}!"
|
238
|
+
end
|
239
|
+
{% endhighlight %}
|
240
|
+
EOS
|
241
|
+
set :super_pre
|
242
|
+
to_md(hdtext).should eql md
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
context "footnote" do
|
247
|
+
it "change '(())' to footnote tag" do
|
248
|
+
hdtext = "sentence((aaa)), sentence\nsentence((bbb))"
|
249
|
+
md = "sentence{% fn_ref 1 %}, sentence\nsentence{% fn_ref 2 %}"
|
250
|
+
set :footnote
|
251
|
+
to_md(hdtext).should eql md
|
252
|
+
stocks[:footnotes].should eql ["{% fn aaa %}", "{% fn bbb %}"]
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
context "br" do
|
257
|
+
it "change '\n\n' to <br/>" do
|
258
|
+
hdtext = "content\n\ncontent\ncontent\n\ncontent"
|
259
|
+
md = "content\ncontent\ncontent\ncontent"
|
260
|
+
set :br
|
261
|
+
to_md(hdtext).should eql md
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
context "link" do
|
266
|
+
it "change a url to a link" do
|
267
|
+
hdtext = <<EOS
|
268
|
+
sentence
|
269
|
+
http://www.abc.com
|
270
|
+
sentence http://www.efg.com/123_456 sentence
|
271
|
+
sentence(https://www.xyz.co.jp),sen..
|
272
|
+
EOS
|
273
|
+
md = <<EOS
|
274
|
+
sentence
|
275
|
+
[http://www.abc.com](http://www.abc.com)
|
276
|
+
sentence [http://www.efg.com/123_456](http://www.efg.com/123_456) sentence
|
277
|
+
sentence([https://www.xyz.co.jp](https://www.xyz.co.jp)),sen..
|
278
|
+
EOS
|
279
|
+
set :link
|
280
|
+
to_md(hdtext).should eql md
|
281
|
+
end
|
282
|
+
|
283
|
+
it "change a url with title to a link" do
|
284
|
+
hdtext = <<EOS
|
285
|
+
*p1*Title X
|
286
|
+
sentence
|
287
|
+
[http://www.abc.com/:title]
|
288
|
+
sentence [http://www.efg.com/123_456:title=Title1] sentence
|
289
|
+
*p3*Title Y
|
290
|
+
sentence([https://www.xyz.co.jp/:title=Title no.2]),sen..
|
291
|
+
http://mmm.ff.co.jp/
|
292
|
+
EOS
|
293
|
+
md = <<EOS
|
294
|
+
#Title X
|
295
|
+
sentence
|
296
|
+
[Title X](http://www.abc.com/)
|
297
|
+
sentence [Title1](http://www.efg.com/123_456) sentence
|
298
|
+
#Title Y
|
299
|
+
sentence([Title no.2](https://www.xyz.co.jp/)),sen..
|
300
|
+
[http://mmm.ff.co.jp/](http://mmm.ff.co.jp/)
|
301
|
+
EOS
|
302
|
+
set :title
|
303
|
+
set :link
|
304
|
+
to_md(hdtext).should eql md
|
305
|
+
end
|
306
|
+
end
|
307
|
+
|
308
|
+
context "amazon" do
|
309
|
+
it "change amazon detail link to amazon tag" do
|
310
|
+
hdtext = "[asin:4797356014:detail]"
|
311
|
+
md = "{{ '4797356014' | amazon_medium_image }}\n{{ '4797356014' | amazon_link }} by {{ '4797356014' | amazon_authors }}"
|
312
|
+
set :amazon
|
313
|
+
to_md(hdtext).should eql md
|
314
|
+
end
|
315
|
+
|
316
|
+
it "change amazon image link to amazon tag" do
|
317
|
+
hdtext = "[asin:4797356014:image]"
|
318
|
+
md = "{{ '4797356014' | amazon_medium_image }}"
|
319
|
+
set :amazon
|
320
|
+
to_md(hdtext).should eql md
|
321
|
+
end
|
322
|
+
end
|
323
|
+
|
324
|
+
context "youtube" do
|
325
|
+
it "change youtube link to youtube tag" do
|
326
|
+
hdtext = "[http://www.youtube.com/watch?v=oDSigzI6YKw:movie]"
|
327
|
+
md = "{% youtube oDSigzI6YKw %}"
|
328
|
+
set :youtube
|
329
|
+
to_md(hdtext).should eql md
|
330
|
+
end
|
331
|
+
end
|
332
|
+
|
333
|
+
context "fotolife" do
|
334
|
+
it "change fotolife link to image tag" do
|
335
|
+
hdtext = "[f:id:keyesberry:20110209105103p:image]"
|
336
|
+
md = "\n\n"
|
337
|
+
set :image
|
338
|
+
to_md(hdtext).should eql md
|
339
|
+
end
|
340
|
+
end
|
341
|
+
|
342
|
+
context "gist" do
|
343
|
+
it "change gist link to gist tag" do
|
344
|
+
hdtext = %{<script src="https://gist.github.com/2177656.js?file=gsub_filter.rb"></script>}
|
345
|
+
md = "{% gist 2177656 gsub_filter.rb %}"
|
346
|
+
set :gist
|
347
|
+
to_md(hdtext).should eql md
|
348
|
+
end
|
349
|
+
end
|
350
|
+
|
351
|
+
context "hatebu" do
|
352
|
+
it "change hatena bookmark link to gist tag" do
|
353
|
+
hdtext = %{[http://d.hatena.ne.jp/keyesberry/20090318/p1:bookmark]}
|
354
|
+
md = "{% hatebu http://d.hatena.ne.jp/keyesberry/20090318/p1 %}"
|
355
|
+
set :hatebu
|
356
|
+
to_md(hdtext).should eql md
|
357
|
+
end
|
358
|
+
|
359
|
+
it "change mixed case for hatebu link and regular link" do
|
360
|
+
hdtext = %{[http://d.hatena.ne.jp/keyesberry/20090318/p1:title='hello'][http://d.hatena.ne.jp/keyesberry/20090318/p1:bookmark]}
|
361
|
+
md = "['hello'](http://d.hatena.ne.jp/keyesberry/20090318/p1){% hatebu http://d.hatena.ne.jp/keyesberry/20090318/p1 %}"
|
362
|
+
set :hatebu
|
363
|
+
set :link
|
364
|
+
to_md(hdtext).should eql md
|
365
|
+
end
|
366
|
+
end
|
367
|
+
end
|
368
|
+
end
|
369
|
+
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require_relative 'spec_helper'
|
3
|
+
|
4
|
+
describe HateDa::Entry do
|
5
|
+
context "when created" do
|
6
|
+
context "without argument" do
|
7
|
+
before(:each) do
|
8
|
+
@entry = HateDa::Entry.new
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should have ent_date, ent_title, ent_body, ent_mdbody property" do
|
12
|
+
->{ @entry.ent_date }.should_not raise_error
|
13
|
+
->{ @entry.ent_title }.should_not raise_error
|
14
|
+
->{ @entry.ent_body }.should_not raise_error
|
15
|
+
->{ @entry.ent_mdbody }.should_not raise_error
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
context "with data" do
|
20
|
+
before(:each) do
|
21
|
+
@date, @body, @mdbody, @title = '2012-04-21', "hello\nfriend!", "", "hello"
|
22
|
+
@entry = HateDa::Entry.new(@date, @body, @mdbody, @title)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should return data" do
|
26
|
+
@entry.ent_date.should eql @date
|
27
|
+
@entry.ent_body.should eql @body
|
28
|
+
@entry.ent_mdbody.should eql @mdbody
|
29
|
+
@entry.ent_title.should eql @title
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
@@ -0,0 +1,111 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require_relative "spec_helper"
|
3
|
+
require "fileutils"
|
4
|
+
|
5
|
+
describe HateDa::MdBuilder do
|
6
|
+
before(:each) do
|
7
|
+
@mdb = HateDa::MdBuilder.new('spec/test1.xml')
|
8
|
+
end
|
9
|
+
|
10
|
+
context "when initialized with a sample xml" do
|
11
|
+
it "create entries property" do
|
12
|
+
->{ @mdb.entries }.should_not raise_error
|
13
|
+
end
|
14
|
+
|
15
|
+
it "create entries which are Entry classes" do
|
16
|
+
@mdb.entries.each { |entry| entry.class.should eql HateDa::Entry }
|
17
|
+
end
|
18
|
+
|
19
|
+
it "set date, body, mdbody, titlefor each entry" do
|
20
|
+
body = "*p1*Title\nline1\nline2\nline3\n**SubTitle\nline4"
|
21
|
+
a_entry = @mdb.entries.first
|
22
|
+
a_entry.ent_date.should eql '2012-03-01'
|
23
|
+
a_entry.ent_body.should eql body
|
24
|
+
a_entry.ent_mdbody.should eql nil
|
25
|
+
a_entry.ent_title.should eql 'hello'
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
context "when run for building markdown data for each entry" do
|
30
|
+
it "set original body to mdbody of entry with no filter" do
|
31
|
+
@mdb.run
|
32
|
+
a_entry = @mdb.entries.first
|
33
|
+
a_entry.ent_mdbody.should eql a_entry.ent_body
|
34
|
+
end
|
35
|
+
|
36
|
+
it "set markdowned body to mdbody of entry" do
|
37
|
+
md = "\nline1\nline2\nline3\n##SubTitle\nline4"
|
38
|
+
a_entry = @mdb.entries.first
|
39
|
+
a_entry.set :title
|
40
|
+
a_entry.set :subtitle
|
41
|
+
@mdb.run
|
42
|
+
a_entry.ent_mdbody.should eql md
|
43
|
+
end
|
44
|
+
|
45
|
+
it "set title of entry when it is empty" do
|
46
|
+
body = "*p1*Title1\nline1\nline2\nline3\n\n*p2*Title2\nline4\nline5"
|
47
|
+
a_entry, b_entry = @mdb.entries.take(2)
|
48
|
+
a_entry.set :title
|
49
|
+
b_entry.set :title
|
50
|
+
@mdb.run
|
51
|
+
a_entry.ent_title.should eql 'hello'
|
52
|
+
b_entry.ent_title.should eql 'Title1'
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
context "set filter to all entries at once" do
|
57
|
+
before(:each) do
|
58
|
+
@mdb2 = HateDa::MdBuilder.new('spec/test2.xml')
|
59
|
+
end
|
60
|
+
|
61
|
+
it "set title with set method" do
|
62
|
+
md1 = "\nline1\nline2\nline3\n**SubTitle\nline4"
|
63
|
+
md2 = "#Title1\nline1\nline2\nline3\n\n#Title2\nline4\nline5"
|
64
|
+
@mdb2.set :title
|
65
|
+
@mdb2.run
|
66
|
+
entries = @mdb2.entries.zip([md1, md2])
|
67
|
+
entries.each do |ent, md|
|
68
|
+
ent.ent_mdbody.should eql md
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
it "set title & subtitle with filter method" do
|
73
|
+
md1 = "#Title\nline1\nline2\nline3\n##SubTitle\nline4"
|
74
|
+
md2 = "#Title1\nline1\nline2\nline3\n\n#Title2\nline4\nline5"
|
75
|
+
@mdb2.filter(/\*p?\d+\*(.*)$/) do |md, st|
|
76
|
+
st[:titles] << md[1]
|
77
|
+
"##{md[1]}"
|
78
|
+
end
|
79
|
+
@mdb2.filter(/^\*\*((?!\*).*)$/) do |md, st|
|
80
|
+
st[:subtitles] << md[1]
|
81
|
+
"###{md[1]}"
|
82
|
+
end
|
83
|
+
@mdb2.run
|
84
|
+
entries = @mdb2.entries.zip([md1, md2])
|
85
|
+
entries.each do |ent, md|
|
86
|
+
ent.ent_mdbody.should eql md
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
context "run option" do
|
92
|
+
it "run for top 2 entries" do
|
93
|
+
nilness = [false, false, true, true]
|
94
|
+
@mdb.run(0,2)
|
95
|
+
@mdb.entries.take(4).map { |ent| ent.ent_mdbody.nil? }.should eql nilness
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
context "save md data to files" do
|
100
|
+
it "save md to separate files" do
|
101
|
+
files = Dir['md/*']
|
102
|
+
FileUtils.rm(Dir['md/*']) unless files.empty?
|
103
|
+
num = 5
|
104
|
+
filters = @mdb.pre_defined_filters
|
105
|
+
filters.each { |f| @mdb.set f }
|
106
|
+
@mdb.run(0...num)
|
107
|
+
@mdb.save_to_files
|
108
|
+
Dir['md/*'].size.should eql num
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
data/spec/spec_helper.rb
ADDED
data/spec/test1.xml
ADDED
@@ -0,0 +1,127 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<diary>
|
3
|
+
<day date="2012-03-01" title="hello">
|
4
|
+
<body>
|
5
|
+
*p1*Title
|
6
|
+
line1
|
7
|
+
line2
|
8
|
+
line3
|
9
|
+
**SubTitle
|
10
|
+
line4
|
11
|
+
|
12
|
+
</body>
|
13
|
+
</day>
|
14
|
+
<day date="2012-04-01" title="">
|
15
|
+
<body>
|
16
|
+
*p1*Title1
|
17
|
+
line1
|
18
|
+
line2
|
19
|
+
line3
|
20
|
+
|
21
|
+
*p2*Title2
|
22
|
+
line4
|
23
|
+
line5
|
24
|
+
|
25
|
+
*123*タイトル3
|
26
|
+
ライン1
|
27
|
+
ライン2
|
28
|
+
ライン3
|
29
|
+
</body>
|
30
|
+
</day>
|
31
|
+
<day date="2012-04-04" title="">
|
32
|
+
<body>
|
33
|
+
*1135046820*Title1
|
34
|
+
|
35
|
+
content
|
36
|
+
**SubTitle1
|
37
|
+
line1
|
38
|
+
line2
|
39
|
+
**SubTitle2
|
40
|
+
line3
|
41
|
+
+list1
|
42
|
+
+list2
|
43
|
+
++list2-1
|
44
|
+
++list2-2
|
45
|
+
|
46
|
+
***SubSubTitle
|
47
|
+
line4
|
48
|
+
-list1
|
49
|
+
-list2
|
50
|
+
-list3
|
51
|
+
|
52
|
+
http://arena.nikkeibp.co.jp/rev/20051124/114391/index.shtml
|
53
|
+
|
54
|
+
asin:B000BGEAR2:image:small
|
55
|
+
asin:B000BGEAR2:title
|
56
|
+
|
57
|
+
[http://local.google.co.jp/maps?q=%E6%98%AD%E6%96%87%E7%A4%BE&near=%E5%8D%83%E4%BB%A3%E7%94%B0%E5%8C%BA%E9%BA%B9%E7%94%BA%EF%BC%93&btnG=%E6%A4%9C%E7%B4%A2&sll=36.562600,136.362305&sspn=23.257402,31.684570&t=&hl=ja&cid=35684108,139738742,6343705222926448571&li=lmd&z=0:title]
|
58
|
+
Google local
|
59
|
+
|
60
|
+
|
61
|
+
[http://earth.google.com/:title]
|
62
|
+
|
63
|
+
</body>
|
64
|
+
</day>
|
65
|
+
<day date="2012-05-16" title="">
|
66
|
+
<body>
|
67
|
+
*p1*RubyでText Dollarを解く-CodeEval
|
68
|
+
なんか想像以上に手こずったよ^^;
|
69
|
+
case式内が見苦しい..
|
70
|
+
もっと簡単なやり方あるんだろうな
|
71
|
+
Integer#dollarizeを定義してみた
|
72
|
+
|
73
|
+
|
74
|
+
数字を英語のドル表記に変換
|
75
|
+
<script src="https://gist.github.com/1697463.js?file=print_check.rb"></script>
|
76
|
+
|
77
|
+
</body>
|
78
|
+
</day>
|
79
|
+
<day date="2012-05-18" title="">
|
80
|
+
<body>
|
81
|
+
*p1*RubyでLevenshtein Distanceを解く-CodeEval
|
82
|
+
できません..
|
83
|
+
アルゴリズム的にはできてるんだけど(('causes'の解答が一致した))
|
84
|
+
答えを得るのに1時間とかorz..
|
85
|
+
5秒で答えなきゃいけないのに
|
86
|
+
あとグローバル変数を使ってしまった
|
87
|
+
|
88
|
+
|
89
|
+
どうも高速化は苦手です
|
90
|
+
そこに注力する気がなかなか起きない..
|
91
|
+
|
92
|
+
[http://d.hatena.ne.jp/keyesberry/20120211/p1:title=RubyのEnumerable#mapをもっと便利にしたいよ - hp12c]
|
93
|
+
|
94
|
+
>|ruby|
|
95
|
+
module Enumerable
|
96
|
+
def mapp(op=nil, *args, &blk)
|
97
|
+
op ? map { |e| op.intern.to_proc[e, *args]} : map(&blk)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
langs = ["Ruby", "Python", "Lisp", "Haskell"]
|
102
|
+
langs.mapp(:+, 'ist') # => ["Rubyist", "Pythonist", "Lispist", "Haskellist"]
|
103
|
+
|
104
|
+
[1, 2, 3].mapp(:+, 10) # => [11, 12, 13]
|
105
|
+
|
106
|
+
(1..5).mapp(:**, 2) # => [1, 4, 9, 16, 25]
|
107
|
+
|
108
|
+
[[1,2,3,4], [5,6,7,8], [9,10,11,12]].mapp(:last, 2) # => [[3, 4], [7, 8], [11, 12]]
|
109
|
+
|
110
|
+
["ruby", "python", "lisp", "haskell"].mapp(:[], -2, 2) # => ["by", "on", "sp", "ll"]
|
111
|
+
||<
|
112
|
+
|
113
|
+
レーベンシュタイン距離が1の語同士をfriendとして
|
114
|
+
与えられた辞書におけるhelloの語から始まる
|
115
|
+
friendの輪に含まれるすべての語の数を答える
|
116
|
+
<script src="https://gist.github.com/1697463.js?file=levenshtein_distance.rb"></script>
|
117
|
+
|
118
|
+
>>
|
119
|
+
それはここまで来たらもうmappは
|
120
|
+
要らないんじゃないかってことなんだ
|
121
|
+
<<
|
122
|
+
</body>
|
123
|
+
</day>
|
124
|
+
|
125
|
+
|
126
|
+
|
127
|
+
</diary>
|
data/spec/test2.xml
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<diary>
|
3
|
+
<day date="2012-03-01" title="hello">
|
4
|
+
<body>
|
5
|
+
*p1*Title
|
6
|
+
line1
|
7
|
+
line2
|
8
|
+
line3
|
9
|
+
**SubTitle
|
10
|
+
line4
|
11
|
+
|
12
|
+
</body>
|
13
|
+
</day>
|
14
|
+
<day date="2012-04-01" title="">
|
15
|
+
<body>
|
16
|
+
*p1*Title1
|
17
|
+
line1
|
18
|
+
line2
|
19
|
+
line3
|
20
|
+
|
21
|
+
*p2*Title2
|
22
|
+
line4
|
23
|
+
line5
|
24
|
+
</body>
|
25
|
+
</day>
|
metadata
ADDED
@@ -0,0 +1,106 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: hateda2md
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- kyoendo
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-05-04 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rspec
|
16
|
+
requirement: &2153771040 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *2153771040
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: nokogiri
|
27
|
+
requirement: &2153770580 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *2153770580
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: gsub_filter
|
38
|
+
requirement: &2153770160 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
44
|
+
type: :runtime
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *2153770160
|
47
|
+
description: Convert Hatena-Diary XML file to Markdown files for Jekyll
|
48
|
+
email:
|
49
|
+
- postagie@gmail.com
|
50
|
+
executables: []
|
51
|
+
extensions: []
|
52
|
+
extra_rdoc_files: []
|
53
|
+
files:
|
54
|
+
- .DS_Store
|
55
|
+
- .gitignore
|
56
|
+
- Gemfile
|
57
|
+
- LICENSE
|
58
|
+
- README.md
|
59
|
+
- Rakefile
|
60
|
+
- example/example.rb
|
61
|
+
- hateda2md.gemspec
|
62
|
+
- lib/hateda2md.rb
|
63
|
+
- lib/hateda2md/converter.rb
|
64
|
+
- lib/hateda2md/entry.rb
|
65
|
+
- lib/hateda2md/mdbuilder.rb
|
66
|
+
- lib/hateda2md/version.rb
|
67
|
+
- spec/hateda_converter_spec.rb
|
68
|
+
- spec/hateda_entry_spec.rb
|
69
|
+
- spec/hateda_mdbuilder_spec.rb
|
70
|
+
- spec/spec_helper.rb
|
71
|
+
- spec/test1.xml
|
72
|
+
- spec/test2.xml
|
73
|
+
homepage: https://github.com/melborne/hateda2md
|
74
|
+
licenses: []
|
75
|
+
post_install_message:
|
76
|
+
rdoc_options: []
|
77
|
+
require_paths:
|
78
|
+
- lib
|
79
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
80
|
+
none: false
|
81
|
+
requirements:
|
82
|
+
- - ! '>='
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
version: 1.9.2
|
85
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
86
|
+
none: false
|
87
|
+
requirements:
|
88
|
+
- - ! '>='
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: '0'
|
91
|
+
requirements: []
|
92
|
+
rubyforge_project:
|
93
|
+
rubygems_version: 1.8.11
|
94
|
+
signing_key:
|
95
|
+
specification_version: 3
|
96
|
+
summary: This is a converter that build separated markdown files using for Jekyll
|
97
|
+
from a Hatena-Diary XML file, which written with Hatena notations. You can set several
|
98
|
+
pre-defined filters or can define your original filters.
|
99
|
+
test_files:
|
100
|
+
- spec/hateda_converter_spec.rb
|
101
|
+
- spec/hateda_entry_spec.rb
|
102
|
+
- spec/hateda_mdbuilder_spec.rb
|
103
|
+
- spec/spec_helper.rb
|
104
|
+
- spec/test1.xml
|
105
|
+
- spec/test2.xml
|
106
|
+
has_rdoc:
|