retter 0.2.2 → 0.2.3
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/.travis.yml +1 -1
- data/ChangeLog.md +10 -0
- data/README.md +1 -3
- data/bin/retter +8 -4
- data/lib/retter/binder.rb +50 -0
- data/lib/retter/command.rb +42 -39
- data/lib/retter/config.rb +24 -23
- data/lib/retter/entries.rb +14 -18
- data/lib/retter/entry.rb +52 -29
- data/lib/retter/generator/base.rb +6 -7
- data/lib/retter/generator/skel/Gemfile +1 -2
- data/lib/retter/generator/skel/Retterfile +2 -2
- data/lib/retter/generator/skel/layouts/article.html.haml +3 -2
- data/lib/retter/generator/skel/layouts/entry.html.haml +3 -2
- data/lib/retter/generator/skel/layouts/index.html.haml +4 -2
- data/lib/retter/generator.rb +0 -1
- data/lib/retter/{renderers.rb → markdown.rb} +22 -1
- data/lib/retter/page/article.rb +54 -0
- data/lib/retter/page/base.rb +97 -0
- data/lib/retter/page/entries.rb +17 -0
- data/lib/retter/page/entry.rb +46 -0
- data/lib/retter/page/feed.rb +63 -0
- data/lib/retter/page/index.rb +17 -0
- data/lib/retter/page/profile.rb +17 -0
- data/lib/retter/page/view_helper.rb +9 -1
- data/lib/retter/page.rb +22 -74
- data/lib/retter/preprint.rb +19 -10
- data/lib/retter/version.rb +1 -1
- data/lib/retter.rb +41 -29
- data/retter.gemspec +44 -53
- data/spec/command/callback_spec.rb +16 -6
- data/spec/command/clean_spec.rb +20 -0
- data/spec/command/commit_spec.rb +11 -12
- data/spec/command/edit_spec.rb +28 -38
- data/spec/command/list_spec.rb +4 -4
- data/spec/command/open_spec.rb +2 -2
- data/spec/command/preview_spec.rb +7 -12
- data/spec/command/rebind_spec.rb +143 -66
- data/spec/spec_helper.rb +10 -3
- data/spec/support/example_group_helper.rb +55 -15
- data/spec/support/matchers.rb +0 -1
- metadata +195 -78
- data/lib/retter/generator/updator.rb +0 -7
- data/lib/retter/pages/article.rb +0 -41
- data/lib/retter/pages/entries.rb +0 -15
- data/lib/retter/pages/entry.rb +0 -35
- data/lib/retter/pages/feed.rb +0 -51
- data/lib/retter/pages/index.rb +0 -15
- data/lib/retter/pages/profile.rb +0 -15
- data/lib/retter/pages.rb +0 -77
- data/spec/command/invoke_after_spec.rb +0 -29
- data/spec/fixtures/sample.md +0 -295
data/lib/retter/generator.rb
CHANGED
@@ -6,7 +6,7 @@ require 'coderay'
|
|
6
6
|
require 'set'
|
7
7
|
|
8
8
|
module Retter
|
9
|
-
module
|
9
|
+
module Markdown
|
10
10
|
class CodeRayRenderer < Redcarpet::Render::HTML
|
11
11
|
def block_code(code, lang)
|
12
12
|
CodeRay.scan(code, lang ? lang.intern : :plain).div
|
@@ -22,5 +22,26 @@ module Retter
|
|
22
22
|
Pygments.highlight(code, lexer: lang, formatter: 'html', options: {encoding: 'utf-8'})
|
23
23
|
end
|
24
24
|
end
|
25
|
+
|
26
|
+
extend Configurable
|
27
|
+
|
28
|
+
configurable :renderer
|
29
|
+
|
30
|
+
class << self
|
31
|
+
def instance
|
32
|
+
@instances ||= {}
|
33
|
+
|
34
|
+
@instances[renderer.name] ||= Redcarpet::Markdown.new(
|
35
|
+
renderer,
|
36
|
+
autolink: true,
|
37
|
+
space_after_headers: true,
|
38
|
+
fenced_code_blocks: true,
|
39
|
+
strikethrough: true,
|
40
|
+
superscript: true,
|
41
|
+
fenced_code_blocks: true,
|
42
|
+
tables: true
|
43
|
+
)
|
44
|
+
end
|
45
|
+
end
|
25
46
|
end
|
26
47
|
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
module Retter
|
4
|
+
module Page
|
5
|
+
class Article
|
6
|
+
class ViewContext < Base::ViewContext
|
7
|
+
attr_reader :entry, :article
|
8
|
+
|
9
|
+
def initialize(entry, article)
|
10
|
+
@entry, @article = entry, article
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
include Base
|
15
|
+
|
16
|
+
attr_reader :article
|
17
|
+
|
18
|
+
def initialize(article)
|
19
|
+
super()
|
20
|
+
@path_prefix = '../../'
|
21
|
+
@article = article
|
22
|
+
@title = "#{article.title} - #{config.title}"
|
23
|
+
end
|
24
|
+
|
25
|
+
def path
|
26
|
+
Page.entry_dir(article.entry.date).join("#{article.id}.html")
|
27
|
+
end
|
28
|
+
|
29
|
+
def template_path
|
30
|
+
Page.find_template_path('article')
|
31
|
+
end
|
32
|
+
|
33
|
+
def bind
|
34
|
+
context = ViewContext.new(article.entry, article)
|
35
|
+
part = Tilt.new(
|
36
|
+
template_path.to_path,
|
37
|
+
ugly: true,
|
38
|
+
filename: template_path.to_path
|
39
|
+
).render(context)
|
40
|
+
|
41
|
+
print part
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def print(part)
|
47
|
+
entry_dir = Page.entry_dir(article.entry.date)
|
48
|
+
entry_dir.mkdir unless entry_dir.directory?
|
49
|
+
|
50
|
+
super
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
module Retter
|
4
|
+
module Page
|
5
|
+
module Base
|
6
|
+
class ViewContext
|
7
|
+
include ViewHelper
|
8
|
+
end
|
9
|
+
|
10
|
+
include Site
|
11
|
+
|
12
|
+
attr_reader :path_prefix, :title
|
13
|
+
|
14
|
+
def initialize
|
15
|
+
@path_prefix = './'
|
16
|
+
@title = config.title
|
17
|
+
end
|
18
|
+
|
19
|
+
def bind
|
20
|
+
context = ViewContext.new
|
21
|
+
part = Tilt.new(
|
22
|
+
template_path.to_path,
|
23
|
+
ugly: true,
|
24
|
+
filename: template_path.to_path
|
25
|
+
).render(context)
|
26
|
+
|
27
|
+
print part
|
28
|
+
end
|
29
|
+
|
30
|
+
def path
|
31
|
+
raise NotImplementedError
|
32
|
+
end
|
33
|
+
|
34
|
+
def template_path
|
35
|
+
raise NotImplementedError
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def print(content)
|
41
|
+
context = ViewContext.new
|
42
|
+
draft = layout_renderer.render(context, content: content, title: title)
|
43
|
+
path_fixed = fix_path(draft, path_prefix)
|
44
|
+
|
45
|
+
path.open('w') {|f| f.puts path_fixed }
|
46
|
+
end
|
47
|
+
|
48
|
+
def layout_renderer
|
49
|
+
path = Page.layout_path.to_path
|
50
|
+
|
51
|
+
@layout_renderer ||= Tilt.new(path, ugly: true, filename: path)
|
52
|
+
end
|
53
|
+
|
54
|
+
def fix_path(html, prefix='./')
|
55
|
+
elements = Nokogiri::HTML(html)
|
56
|
+
|
57
|
+
fix_href_path(fix_src_path(elements, prefix), prefix).to_s
|
58
|
+
end
|
59
|
+
|
60
|
+
def fix_src_path(elements, prefix = './')
|
61
|
+
elements.search("[src!=''][src!='']").each do |el|
|
62
|
+
src = el.attr('src')
|
63
|
+
next if src =~ /^(?:http:|https:|\/\/)/
|
64
|
+
|
65
|
+
el.set_attribute 'src', normarize_path(prefix, src)
|
66
|
+
end
|
67
|
+
|
68
|
+
elements
|
69
|
+
end
|
70
|
+
|
71
|
+
def fix_href_path(elements, prefix = './')
|
72
|
+
elements.search("[href][href!='#']").each do |el|
|
73
|
+
href = el.attr('href')
|
74
|
+
next if href =~ /^(?:http:|https:|\/\/)/
|
75
|
+
|
76
|
+
if href == '/'
|
77
|
+
el.set_attribute 'href', [prefix, 'index.html'].join
|
78
|
+
else
|
79
|
+
el.set_attribute 'href', normarize_path(prefix, href)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
elements
|
84
|
+
end
|
85
|
+
|
86
|
+
def normarize_path(prefix, path)
|
87
|
+
absolute = /^\//
|
88
|
+
|
89
|
+
if path =~ absolute
|
90
|
+
[prefix, path.gsub(absolute, '')].join
|
91
|
+
else
|
92
|
+
path
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
module Retter
|
4
|
+
module Page
|
5
|
+
class Entry
|
6
|
+
class ViewContext < Base::ViewContext
|
7
|
+
attr_reader :entry
|
8
|
+
|
9
|
+
def initialize(entry)
|
10
|
+
@entry = entry
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
include Base
|
15
|
+
|
16
|
+
attr_reader :entry
|
17
|
+
|
18
|
+
def initialize(entry)
|
19
|
+
super()
|
20
|
+
|
21
|
+
@path_prefix = '../'
|
22
|
+
@entry = entry
|
23
|
+
@title = "#{entry.date} - #{config.title}"
|
24
|
+
end
|
25
|
+
|
26
|
+
def path
|
27
|
+
Page.entry_file(entry.date)
|
28
|
+
end
|
29
|
+
|
30
|
+
def template_path
|
31
|
+
Page.find_template_path('entry')
|
32
|
+
end
|
33
|
+
|
34
|
+
def bind
|
35
|
+
context = ViewContext.new(entry)
|
36
|
+
part = Tilt.new(
|
37
|
+
template_path.to_path,
|
38
|
+
ugly: true,
|
39
|
+
filename: template_path.to_path
|
40
|
+
).render(context)
|
41
|
+
|
42
|
+
print part
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require 'builder'
|
4
|
+
require 'uri'
|
5
|
+
|
6
|
+
module Retter
|
7
|
+
module Page
|
8
|
+
class Feed
|
9
|
+
include Base
|
10
|
+
|
11
|
+
def path
|
12
|
+
config.retter_home.join('entries.rss')
|
13
|
+
end
|
14
|
+
|
15
|
+
def bind
|
16
|
+
print rss
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def print(content)
|
22
|
+
path.open('w') {|f| f.write content }
|
23
|
+
end
|
24
|
+
|
25
|
+
def articles(limit = 20)
|
26
|
+
entries.map {|e| e.articles.reverse }.flatten[0..limit]
|
27
|
+
end
|
28
|
+
|
29
|
+
def helper
|
30
|
+
@helper ||= Object.new.extend(Page::ViewHelper)
|
31
|
+
end
|
32
|
+
|
33
|
+
def rss
|
34
|
+
xml = Builder::XmlMarkup.new
|
35
|
+
xml.instruct!
|
36
|
+
xml.rdf:RDF, :xmlns => 'http://purl.org/rss/1.0/',
|
37
|
+
:'xmlns:rdf' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
|
38
|
+
:'xmlns:dc' => 'http://purl.org/dc/elements/1.1/',
|
39
|
+
:'xmlns:content' => 'xmlns:content="http://purl.org/rss/1.0/modules/content/',
|
40
|
+
:'xml:lang' => 'ja' do
|
41
|
+
xml.channel :'rdf:about' => config.url do
|
42
|
+
xml.title config.title
|
43
|
+
xml.link config.url
|
44
|
+
xml.dc:date, (entries.empty? ? Time.now : entries.first.date).iso8601
|
45
|
+
xml.description config.description
|
46
|
+
xml.items { xml.rdf(:Seq) { articles.each {|a| xml.rdf:li, :'rdf:resource' => helper.article_url(a) } } }
|
47
|
+
end
|
48
|
+
|
49
|
+
articles.each do |article|
|
50
|
+
xml.item about: helper.article_url(article) do
|
51
|
+
xml.title article.title
|
52
|
+
xml.description article.snippet
|
53
|
+
xml.content(:encoded) { xml.cdata! article.body }
|
54
|
+
xml.dc:date, article.entry.date.iso8601
|
55
|
+
xml.link helper.article_url(article)
|
56
|
+
xml.author config.author
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
module Retter
|
4
4
|
module Page::ViewHelper
|
5
|
-
include
|
5
|
+
include Site
|
6
6
|
|
7
7
|
def entry_path(*args)
|
8
8
|
case args.first
|
@@ -15,6 +15,14 @@ module Retter
|
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
18
|
+
def entry_url(*args)
|
19
|
+
URI.parse(config.url) + entry_path(*args)
|
20
|
+
end
|
21
|
+
|
22
|
+
def article_url(*args)
|
23
|
+
URI.parse(config.url) + article_path(*args)
|
24
|
+
end
|
25
|
+
|
18
26
|
def article_path(*args)
|
19
27
|
case args.first
|
20
28
|
when Date, Time
|
data/lib/retter/page.rb
CHANGED
@@ -6,90 +6,38 @@ require 'nokogiri'
|
|
6
6
|
|
7
7
|
module Retter
|
8
8
|
module Page
|
9
|
-
|
9
|
+
autoload :Base, 'retter/page/base'
|
10
|
+
autoload :ViewHelper, 'retter/page/view_helper'
|
10
11
|
|
11
|
-
|
12
|
+
autoload :Index, 'retter/page/index'
|
13
|
+
autoload :Profile, 'retter/page/profile'
|
14
|
+
autoload :Entries, 'retter/page/entries'
|
15
|
+
autoload :Feed, 'retter/page/feed'
|
16
|
+
autoload :Entry, 'retter/page/entry'
|
17
|
+
autoload :Article, 'retter/page/article'
|
12
18
|
|
13
|
-
|
19
|
+
extend Configurable
|
14
20
|
|
15
|
-
|
16
|
-
@path_prefix = './'
|
17
|
-
@title = config.title
|
18
|
-
end
|
19
|
-
|
20
|
-
def print
|
21
|
-
part = Tilt.new(
|
22
|
-
part_layout_pathname.to_path,
|
23
|
-
ugly: true,
|
24
|
-
filename: part_layout_pathname.to_path
|
25
|
-
).render(view_scope)
|
26
|
-
|
27
|
-
print_with_layout part
|
28
|
-
end
|
29
|
-
|
30
|
-
def pathname
|
31
|
-
raise NotImplementedError
|
32
|
-
end
|
33
|
-
|
34
|
-
def path
|
35
|
-
pathname.to_path
|
36
|
-
end
|
37
|
-
|
38
|
-
def part_layout_pathname
|
39
|
-
raise NotImplementedError
|
40
|
-
end
|
41
|
-
|
42
|
-
private
|
43
|
-
|
44
|
-
def print_with_layout(content)
|
45
|
-
draft = layout_renderer.render(view_scope, content: content, title: title)
|
46
|
-
path_fixed = fix_path(draft, path_prefix)
|
47
|
-
|
48
|
-
pathname.open('w') {|f| f.puts path_fixed }
|
49
|
-
end
|
50
|
-
|
51
|
-
def layout_renderer
|
52
|
-
layout_file = Pages.layout_file.to_path
|
53
|
-
@layout_renderer ||= Tilt.new(layout_file, ugly: true, filename: layout_file)
|
54
|
-
end
|
21
|
+
configurable :layouts_dir, :entries_dir
|
55
22
|
|
56
|
-
|
57
|
-
|
23
|
+
class << self
|
24
|
+
def find_template_path(name)
|
25
|
+
detected = Dir.glob(layouts_dir.join("#{name}.*.*")).first
|
58
26
|
|
59
|
-
|
60
|
-
end
|
61
|
-
|
62
|
-
def fix_src_path(elements, prefix = './')
|
63
|
-
elements.search("[src!=''][src!='']").each do |el|
|
64
|
-
src = el.attr('src').scan(/[^\.\/]{3}.*/).first
|
65
|
-
next if src =~ /^(?:http|https):\/\//
|
66
|
-
|
67
|
-
el.set_attribute 'src', [prefix, src].join
|
27
|
+
Pathname.new(detected)
|
68
28
|
end
|
69
29
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
def fix_href_path(elements, prefix = './')
|
74
|
-
elements.search("[href][href!='#']").each do |el|
|
75
|
-
href = el.attr('href')
|
76
|
-
next if href =~ /^(?:http|https):\/\//
|
77
|
-
|
78
|
-
if href == '/'
|
79
|
-
el.set_attribute 'href', [prefix, 'index.html'].join
|
80
|
-
else
|
81
|
-
el.set_attribute 'href', [prefix, href.scan(/[^\.\/]{3}.*/).first].join
|
82
|
-
end
|
30
|
+
def layout_path
|
31
|
+
@layout_path ||= find_template_path('retter')
|
83
32
|
end
|
84
33
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
view_scope = Object.new
|
89
|
-
view_scope.extend ViewHelper
|
34
|
+
def entry_file(date)
|
35
|
+
entries_dir.join date.strftime('%Y%m%d.html')
|
36
|
+
end
|
90
37
|
|
91
|
-
|
92
|
-
|
38
|
+
def entry_dir(date)
|
39
|
+
entries_dir.join date.strftime('%Y%m%d')
|
40
|
+
end
|
93
41
|
end
|
94
42
|
end
|
95
43
|
end
|
data/lib/retter/preprint.rb
CHANGED
@@ -2,24 +2,33 @@
|
|
2
2
|
|
3
3
|
module Retter
|
4
4
|
class Preprint
|
5
|
-
|
5
|
+
class ViewContext < Page::Base::ViewContext
|
6
|
+
attr_reader :entry
|
6
7
|
|
7
|
-
|
8
|
+
def initialize(entry)
|
9
|
+
@entry = entry
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
include Page::Base
|
14
|
+
|
15
|
+
def path
|
8
16
|
config.retter_home.join '.preview.html'
|
9
17
|
end
|
10
18
|
|
11
|
-
def
|
12
|
-
|
19
|
+
def template_path
|
20
|
+
Page.find_template_path('entry')
|
13
21
|
end
|
14
22
|
|
15
|
-
def
|
16
|
-
|
17
|
-
|
23
|
+
def bind(entry)
|
24
|
+
context = ViewContext.new(entry)
|
25
|
+
part = Tilt.new(
|
26
|
+
template_path.to_path,
|
18
27
|
ugly: true,
|
19
|
-
filename:
|
20
|
-
).render(
|
28
|
+
filename: template_path.to_path
|
29
|
+
).render(context)
|
21
30
|
|
22
|
-
|
31
|
+
print part
|
23
32
|
end
|
24
33
|
end
|
25
34
|
end
|
data/lib/retter/version.rb
CHANGED
data/lib/retter.rb
CHANGED
@@ -3,48 +3,60 @@
|
|
3
3
|
here = File.dirname(__FILE__)
|
4
4
|
$LOAD_PATH.unshift here unless $LOAD_PATH.include?(here)
|
5
5
|
|
6
|
+
require 'date'
|
7
|
+
require 'time'
|
8
|
+
require 'pathname'
|
9
|
+
require 'active_support/time_with_zone' # XXX: workaround for uninitialized constant ActiveSupport::TimeWithZone (NameError)
|
10
|
+
|
6
11
|
module Retter
|
12
|
+
autoload :Generator, 'retter/generator'
|
13
|
+
autoload :VERSION, 'retter/version'
|
14
|
+
autoload :Configurable, 'retter/configurable'
|
15
|
+
autoload :Config, 'retter/config'
|
16
|
+
autoload :Markdown, 'retter/markdown'
|
17
|
+
autoload :Entry, 'retter/entry'
|
18
|
+
autoload :Entries, 'retter/entries'
|
19
|
+
autoload :Page, 'retter/page'
|
20
|
+
autoload :Binder, 'retter/binder'
|
21
|
+
autoload :Preprint, 'retter/preprint'
|
22
|
+
autoload :Repository, 'retter/repository'
|
23
|
+
autoload :Command, 'retter/command'
|
24
|
+
|
7
25
|
class RetterError < RuntimeError; end
|
8
26
|
|
9
|
-
module
|
10
|
-
|
11
|
-
|
12
|
-
Retter.send meth
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
27
|
+
module Site
|
28
|
+
extend self
|
29
|
+
extend Configurable
|
16
30
|
|
17
|
-
|
18
|
-
attr_reader :config
|
31
|
+
configurable :home, :title, :description, :url, :author
|
19
32
|
|
20
33
|
def load(env)
|
21
|
-
|
34
|
+
@@config = Config.new(env)
|
22
35
|
end
|
23
36
|
|
24
37
|
def reset!
|
25
|
-
|
38
|
+
@@entries = nil
|
26
39
|
end
|
27
40
|
|
28
41
|
def entries
|
29
|
-
|
42
|
+
@@entries ||= Entries.new
|
30
43
|
end
|
31
|
-
end
|
32
44
|
|
33
|
-
|
45
|
+
def config
|
46
|
+
@@config
|
47
|
+
end
|
48
|
+
end
|
34
49
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
50
|
+
class << self
|
51
|
+
def const_missing(name)
|
52
|
+
case name.intern
|
53
|
+
when :Renderers
|
54
|
+
warn %(Retter::Renderers is OBSOLETE, Use Retter::Markdown.)
|
55
|
+
|
56
|
+
Markdown
|
57
|
+
else
|
58
|
+
super
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
46
62
|
end
|
47
|
-
|
48
|
-
require 'date'
|
49
|
-
require 'time'
|
50
|
-
require 'pathname'
|