hateda2md 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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![image](#{host}/#{m1[0]}/#{m1}/#{m2[0,8]}/#{m2}.#{ft})\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![image](http://img.f.hatena.ne.jp/images/fotolife/k/keyesberry/20110209/20110209105103.png)\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:
|