retter 0.2.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,17 +1,25 @@
1
1
  # coding: utf-8
2
2
 
3
- require 'active_support/core_ext/object'
3
+ require 'active_support/cache'
4
4
  require 'digest/sha1'
5
5
  require 'redcarpet'
6
+ require 'chronic'
6
7
 
7
8
  module Retter
8
9
  class EntryLoadError < RetterError; end
9
10
 
10
11
  class Entries < Array
11
- include Retter::Stationery
12
+ include Stationery
13
+ extend Configurable
14
+
15
+ configurable :renderer, :retters_dir, :wip_file
12
16
 
13
17
  def initialize
14
- load_entries config.retters_dir
18
+ load_entries retters_dir
19
+ end
20
+
21
+ def retter_file(date)
22
+ retters_dir.join(date ? date.strftime('%Y%m%d.md') : 'today.md')
15
23
  end
16
24
 
17
25
  def detect_by_string(str)
@@ -36,10 +44,10 @@ module Retter
36
44
 
37
45
  def detect_by_filename(filename)
38
46
  case filename
39
- when config.wip_file.basename.to_s
47
+ when wip_file.basename.to_path
40
48
  wip_entry
41
49
  else
42
- detect {|e| e.pathname.basename.to_s == filename }
50
+ detect {|e| e.pathname.basename.to_path == filename }
43
51
  end
44
52
  end
45
53
 
@@ -52,43 +60,37 @@ module Retter
52
60
  end
53
61
 
54
62
  def parse_date_string(date_str)
55
- case date_str
56
- when /^yesterday$/i then 1.day.ago
57
- when /^today$/i then 0.day.ago
58
- when /^tomorrow$/i then 1.day.since
59
- when /^[0-9]+[\.\s](?:days?|weeks?|months?|years?)[\.\s](?:ago|since)$/i
60
- eval(date_str.gsub(/\s+/, '.')).to_date
61
- else
62
- Date.parse(date_str)
63
- end
63
+ normalized = date_str.gsub(/\./, ' ')
64
+
65
+ (Chronic.parse(normalized) || Date.parse(normalized)).to_date
64
66
  end
65
67
 
66
68
  def wip_entry(date = nil)
67
- wip_file = config.retter_file(date)
68
- wip_date = date || Date.today
69
- wip_body = wip_file.exist? ? wip_file.read : ''
69
+ file = retter_file(date)
70
+ date = date || Date.today
71
+ body = file.exist? ? file.read : ''
70
72
 
71
- Retter::Entry.new date: wip_date, body: rendered_body(wip_body), pathname: wip_file
73
+ Entry.new date: date, body: rendered_body(body), pathname: file
72
74
  end
73
75
 
74
76
  def commit_wip_entry!
75
- if config.wip_file.exist?
76
- copy = config.wip_file.read
77
- config.retter_file(Date.today).open('a') {|f| f.puts copy }
78
- config.wip_file.unlink
77
+ if wip_file.exist?
78
+ copy = wip_file.read
79
+ retter_file(Date.today).open('a') {|f| f.puts copy }
80
+ wip_file.unlink
79
81
  end
80
82
 
81
- Retter.reset_entries!
83
+ Retter.reset!
82
84
  end
83
85
 
84
86
  def load_entries(path)
85
87
  date_files = find_markup_files(path).map {|file|
86
- date_str = file.basename('.*').to_s
88
+ date_str = file.basename('.*').to_path
87
89
  [Date.parse(date_str), file]
88
90
  }.sort_by(&:first)
89
91
 
90
92
  date_files.reverse_each {|date, file|
91
- self << Retter::Entry.new(date: date, body: rendered_body(file.read))
93
+ self << Entry.new(date: date, body: rendered_body(file.read))
92
94
  }
93
95
  end
94
96
 
@@ -102,7 +104,7 @@ module Retter
102
104
 
103
105
  config.cache.fetch(key) do
104
106
  Redcarpet::Markdown.new(
105
- config.renderer,
107
+ renderer,
106
108
  autolink: true,
107
109
  space_after_headers: true,
108
110
  fenced_code_blocks: true,
data/lib/retter/entry.rb CHANGED
@@ -2,103 +2,105 @@
2
2
 
3
3
  require 'nokogiri'
4
4
 
5
- class Retter::Entry
6
- class Article
7
- attr_accessor :entry, :id, :title, :body
5
+ module Retter
6
+ class Entry
7
+ class Article
8
+ attr_accessor :entry, :id, :title, :body
8
9
 
9
- def initialize(attrs = {})
10
- @id, @entry, @title, @body = attrs.values_at(:id, :entry, :title, :body)
11
- end
10
+ def initialize(attrs = {})
11
+ @id, @entry, @title, @body = attrs.values_at(:id, :entry, :title, :body)
12
+ end
12
13
 
13
- def to_s
14
- body
15
- end
14
+ def to_s
15
+ body
16
+ end
16
17
 
17
- def next
18
- articles[index.next] || (entry.next && entry.next.articles.first)
19
- end
18
+ def next
19
+ articles[index.next] || (entry.next && entry.next.articles.first)
20
+ end
20
21
 
21
- def prev
22
- index.pred < 0 ? (entry.prev && entry.prev.articles.last) : articles[index.pred]
23
- end
22
+ def prev
23
+ index.pred < 0 ? (entry.prev && entry.prev.articles.last) : articles[index.pred]
24
+ end
24
25
 
25
- def index
26
- articles.index(self)
27
- end
26
+ def index
27
+ articles.index(self)
28
+ end
28
29
 
29
- def articles
30
- @articles ||= entry.articles
30
+ def articles
31
+ @articles ||= entry.articles
32
+ end
31
33
  end
32
- end
33
34
 
34
- include Retter::Stationery
35
+ include Stationery
35
36
 
36
- attr_accessor :date, :lede, :body, :articles
37
- attr_reader :pathname
37
+ attr_accessor :date, :lede, :body, :articles
38
+ attr_reader :pathname
38
39
 
39
- def initialize(attrs={})
40
- @date, @body = attrs.values_at(:date, :body)
40
+ def initialize(attrs={})
41
+ @date, @body = attrs.values_at(:date, :body)
41
42
 
42
- pathname_by_date = Retter.config.retters_dir.join(date.strftime('%Y%m%d.md'))
43
- @pathname = attrs[:pathname] || pathname_by_date
43
+ pathname_by_date = Entries.retters_dir.join(date.strftime('%Y%m%d.md'))
44
+ @pathname = attrs[:pathname] || pathname_by_date
44
45
 
45
- attach_titles
46
- extract_articles
47
- load_lede
48
- end
49
-
50
- def path
51
- pathname.to_s
52
- end
46
+ attach_titles
47
+ extract_articles
48
+ load_lede
49
+ end
53
50
 
54
- def to_s
55
- body
56
- end
51
+ def path
52
+ pathname.to_path
53
+ end
57
54
 
58
- def next
59
- entries[index.next]
60
- end
55
+ def to_s
56
+ body
57
+ end
61
58
 
62
- def prev
63
- entries[index.pred] unless index.pred < 0
64
- end
59
+ def next
60
+ entries[index.next]
61
+ end
65
62
 
66
- def index
67
- entries.index(self) || 0
68
- end
63
+ def prev
64
+ entries[index.pred] unless index.pred < 0
65
+ end
69
66
 
70
- private
67
+ def index
68
+ entries.index(self) || 0
69
+ end
71
70
 
72
- def body_elements
73
- Nokogiri::HTML(body)
74
- end
71
+ private
75
72
 
76
- def attach_titles
77
- html = body_elements
78
- html.search('//h1').each_with_index do |h1, seq|
79
- h1.set_attribute 'id', "a#{seq}"
73
+ def body_elements
74
+ Nokogiri::HTML(body)
80
75
  end
81
76
 
82
- @body = html.search('//body/*').to_s
83
- end
77
+ def attach_titles
78
+ html = body_elements
79
+ html.search('//h1').each_with_index do |h1, seq|
80
+ h1.set_attribute 'id', "a#{seq}"
81
+ end
84
82
 
85
- def extract_articles
86
- @articles = body_elements.search('body > *').each_with_object([]) {|c, r|
87
- if c.name == 'h1'
88
- r << Article.new(entry: self, id: c.attr('id'), title: c.text, body: '')
89
- else
90
- next if r.empty?
83
+ @body = html.search('//body/*').to_s
84
+ end
91
85
 
92
- article = r.last
93
- article.body += c.to_s
94
- end
95
- } || []
96
- end
86
+ def extract_articles
87
+ @articles = body_elements.search('body > *').each_with_object([]) {|c, r|
88
+ if c.name == 'h1'
89
+ r << Article.new(entry: self, id: c.attr('id'), title: c.text, body: '')
90
+ else
91
+ next if r.empty?
92
+
93
+ article = r.last
94
+ article.body += c.to_s
95
+ end
96
+ } || []
97
+ end
97
98
 
98
- def load_lede
99
- @lede = body_elements.search('body > *').each_with_object('') {|c, r|
100
- break r if c.name == 'h1'
101
- r << c.to_s
102
- }
99
+ def load_lede
100
+ @lede = body_elements.search('body > *').each_with_object('') {|c, r|
101
+ break r if c.name == 'h1'
102
+ r << c.to_s
103
+ }
104
+ end
103
105
  end
104
106
  end
@@ -7,23 +7,32 @@ description '<%= name %>'
7
7
  author '<%= ENV["USER"] %>'
8
8
  renderer Retter::Renderers::PygmentsRenderer
9
9
 
10
- ## Callbacks for retter sub-command: edit, rebind, commit
11
- ##
12
- ## Syntax:
13
- ## after [command], [invoke command or proc]
10
+ # Callbacks for retter sub-command: edit, rebind, commit
14
11
  #
15
- ## Using symbol example:
16
- # after :rebind, :commit
12
+ # Syntax:
13
+ # after [command], [invoke command or proc]
17
14
  #
18
- ## Using proc example:
19
- # after :commit do
20
- # if yes?("Deploy now? [yes/no]")
21
- # system "cd #{config.retter_home}"
22
- # system 'git push origin master'
23
- # end
24
- # end
15
+ # Using symbol example:
16
+ # after :rebind, :commit
25
17
  #
26
- # after :edit do
27
- # ident = ARGV.pop || 'today'
28
- # preview ident if yes?("Preview now? [yes/no]")
29
- # end
18
+ # Using proc example:
19
+ # after :commit do
20
+ # if yes?("Deploy now? [yes/no]")
21
+ # system "cd #{config.retter_home}"
22
+ # system 'git push origin master'
23
+ # end
24
+ # end
25
+ #
26
+ # after :edit do
27
+ # Retter.reset!
28
+ # ident = ARGV.pop || 'today'
29
+ #
30
+ # preview ident if yes?("Preview now? [yes/no]")
31
+ # end
32
+ #
33
+ # Skip binding:
34
+ # examples:
35
+ # allow_binding :none
36
+ # allow_binding [:profile, :entries, :feed]
37
+ #
38
+ # Anyway index page will be bound.
@@ -1,14 +1,14 @@
1
1
  # coding: utf-8
2
2
 
3
- module Retter::Page
4
- module ViewHelper
5
- include Retter::Stationery
3
+ module Retter
4
+ module Page::ViewHelper
5
+ include Stationery
6
6
 
7
7
  def entry_path(*args)
8
8
  case args.first
9
9
  when Date, Time
10
10
  entry_path_by_date(*args)
11
- when Retter::Entry
11
+ when Entry
12
12
  entry_path_by_entry(args.first)
13
13
  else
14
14
  raise TypeError, "wrong argument type #{args.first.class} (expected Date, Time or Retter::Entry)"
@@ -19,7 +19,7 @@ module Retter::Page
19
19
  case args.first
20
20
  when Date, Time
21
21
  article_path_by_date_and_id(*args)
22
- when Retter::Entry::Article
22
+ when Entry::Article
23
23
  article_path_by_article(args.first)
24
24
  else
25
25
  raise TypeError, "wrong argument type #{args.first.class} (expected Date, Time or Retter::Entry::Article)"
data/lib/retter/page.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  # coding: utf-8
2
2
 
3
+ require 'tilt'
3
4
  require 'haml'
4
5
  require 'nokogiri'
5
6
 
@@ -7,7 +8,7 @@ module Retter
7
8
  module Page
8
9
  require 'retter/page/view_helper'
9
10
 
10
- include Retter::Stationery
11
+ include Stationery
11
12
 
12
13
  attr_reader :path_prefix, :title
13
14
 
@@ -17,10 +18,10 @@ module Retter
17
18
  end
18
19
 
19
20
  def print
20
- part = Haml::Engine.new(
21
- part_layout_pathname.read,
21
+ part = Tilt.new(
22
+ part_layout_pathname.to_path,
22
23
  ugly: true,
23
- filename: part_layout_pathname.to_s
24
+ filename: part_layout_pathname.to_path
24
25
  ).render(view_scope)
25
26
 
26
27
  print_with_layout part
@@ -31,7 +32,7 @@ module Retter
31
32
  end
32
33
 
33
34
  def path
34
- pathname.to_s
35
+ pathname.to_path
35
36
  end
36
37
 
37
38
  def part_layout_pathname
@@ -48,7 +49,8 @@ module Retter
48
49
  end
49
50
 
50
51
  def layout_renderer
51
- @layout_renderer ||= Haml::Engine.new(config.layout_file.read, ugly: true, filename: config.layout_file.to_s)
52
+ layout_file = Pages.layout_file.to_path
53
+ @layout_renderer ||= Tilt.new(layout_file, ugly: true, filename: layout_file)
52
54
  end
53
55
 
54
56
  def fix_path(html, prefix='./')
@@ -1,39 +1,41 @@
1
1
  # coding: utf-8
2
2
 
3
- class Retter::Pages::Article
4
- include Retter::Page
5
-
6
- attr_reader :article
7
-
8
- def initialize(article)
9
- super()
10
- @path_prefix = '../../'
11
- @article = article
12
- @title = "#{article.title} - #{config.title}"
13
- end
14
-
15
- def pathname
16
- config.entry_dir(article.entry.date).join("#{article.id}.html")
17
- end
18
-
19
- def part_layout_pathname
20
- config.article_layout_file
21
- end
22
-
23
- def print
24
- options = {entry: article.entry, article: article}
25
- part = Haml::Engine.new(
26
- part_layout_pathname.read,
27
- ugly: true,
28
- filename: part_layout_pathname.to_s
29
- ).render(view_scope, options)
30
-
31
- mkdir
32
- print_with_layout part
33
- end
34
-
35
- def mkdir
36
- entry_dir = config.entry_dir(article.entry.date)
37
- entry_dir.mkdir unless entry_dir.directory?
3
+ module Retter
4
+ class Pages::Article
5
+ include Page
6
+
7
+ attr_reader :article
8
+
9
+ def initialize(article)
10
+ super()
11
+ @path_prefix = '../../'
12
+ @article = article
13
+ @title = "#{article.title} - #{config.title}"
14
+ end
15
+
16
+ def pathname
17
+ Pages.entry_dir(article.entry.date).join("#{article.id}.html")
18
+ end
19
+
20
+ def part_layout_pathname
21
+ Pages.find_layout_path('article')
22
+ end
23
+
24
+ def print
25
+ options = {entry: article.entry, article: article}
26
+ part = Tilt.new(
27
+ part_layout_pathname.to_path,
28
+ ugly: true,
29
+ filename: part_layout_pathname.to_path
30
+ ).render(view_scope, options)
31
+
32
+ mkdir
33
+ print_with_layout part
34
+ end
35
+
36
+ def mkdir
37
+ entry_dir = Pages.entry_dir(article.entry.date)
38
+ entry_dir.mkdir unless entry_dir.directory?
39
+ end
38
40
  end
39
41
  end
@@ -0,0 +1,15 @@
1
+ # coding: utf-8
2
+
3
+ module Retter
4
+ class Pages::Entries
5
+ include Page
6
+
7
+ def pathname
8
+ config.retter_home.join('entries.html')
9
+ end
10
+
11
+ def part_layout_pathname
12
+ Pages.find_layout_path('entries')
13
+ end
14
+ end
15
+ end
@@ -1,32 +1,35 @@
1
1
  # coding: utf-8
2
2
 
3
- class Retter::Pages::Entry
4
- include Retter::Page
3
+ module Retter
4
+ class Pages::Entry
5
+ include Page
5
6
 
6
- attr_reader :entry
7
+ attr_reader :entry
7
8
 
8
- def initialize(entry)
9
- super()
10
- @path_prefix = '../'
11
- @entry = entry
12
- @title = "#{entry.date} - #{config.title}"
13
- end
9
+ def initialize(entry)
10
+ super()
14
11
 
15
- def pathname
16
- config.entry_file(entry.date)
17
- end
12
+ @path_prefix = '../'
13
+ @entry = entry
14
+ @title = "#{entry.date} - #{config.title}"
15
+ end
18
16
 
19
- def part_layout_pathname
20
- config.entry_layout_file
21
- end
17
+ def pathname
18
+ Pages.entry_file(entry.date)
19
+ end
20
+
21
+ def part_layout_pathname
22
+ Pages.find_layout_path('entry')
23
+ end
22
24
 
23
- def print
24
- part = Haml::Engine.new(
25
- part_layout_pathname.read,
26
- ugly: true,
27
- filename: part_layout_pathname.to_s
28
- ).render(view_scope, entry: entry)
25
+ def print
26
+ part = Tilt.new(
27
+ part_layout_pathname.to_path,
28
+ ugly: true,
29
+ filename: part_layout_pathname.to_path
30
+ ).render(view_scope, entry: entry)
29
31
 
30
- print_with_layout part
32
+ print_with_layout part
33
+ end
31
34
  end
32
35
  end
@@ -3,45 +3,47 @@
3
3
  require 'builder'
4
4
  require 'uri'
5
5
 
6
- class Retter::Pages::Feed
7
- include Retter::Page
6
+ module Retter
7
+ class Pages::Feed
8
+ include Page
8
9
 
9
- def pathname
10
- config.feed_file
11
- end
10
+ def pathname
11
+ config.retter_home.join('entries.rss')
12
+ end
12
13
 
13
- def print
14
- pathname.open('w') {|f| f.puts rss }
15
- end
14
+ def print
15
+ pathname.open('w') {|f| f.puts rss }
16
+ end
16
17
 
17
- private
18
+ private
18
19
 
19
- def entry_url(date, id = nil)
20
- (URI.parse(config.url) + date.strftime('/entries/%Y%m%d.html')).to_s
21
- end
20
+ def entry_url(date, id = nil)
21
+ (URI.parse(config.url) + date.strftime('/entries/%Y%m%d.html')).to_s
22
+ end
22
23
 
23
- def rss
24
- xml = Builder::XmlMarkup.new
25
- xml.instruct!
26
- xml.rdf:RDF, :xmlns => 'http://purl.org/rss/1.0/',
27
- :'xmlns:rdf' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
28
- :'xmlns:dc' => 'http://purl.org/dc/elements/1.1/',
29
- :'xml:lang' => 'ja' do
30
- xml.channel :'rdf:about' => config.url do
31
- xml.title config.title
32
- xml.link config.url
33
- xml.dc:date, entries.empty? ? nil : entries.first.date
34
- xml.description config.description
35
- xml.items { xml.rdf(:Seq) { entries.each {|e| xml.rdf:li, :'rdf:resource' => entry_url(e.date) } } }
36
- end
24
+ def rss
25
+ xml = Builder::XmlMarkup.new
26
+ xml.instruct!
27
+ xml.rdf:RDF, :xmlns => 'http://purl.org/rss/1.0/',
28
+ :'xmlns:rdf' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
29
+ :'xmlns:dc' => 'http://purl.org/dc/elements/1.1/',
30
+ :'xml:lang' => 'ja' do
31
+ xml.channel :'rdf:about' => config.url do
32
+ xml.title config.title
33
+ xml.link config.url
34
+ xml.dc:date, entries.empty? ? nil : entries.first.date
35
+ xml.description config.description
36
+ xml.items { xml.rdf(:Seq) { entries.each {|e| xml.rdf:li, :'rdf:resource' => entry_url(e.date) } } }
37
+ end
37
38
 
38
- entries[0...20].each do |entry| # XXX hardcoding
39
- xml.item about: entry_url(entry.date) do
40
- xml.title entry.date.strftime('%Y/%m/%d')
41
- xml.description { xml.cdata! entry.body }
42
- xml.dc:date, entry.date
43
- xml.link entry_url(entry.date)
44
- xml.author config.author
39
+ entries[0...20].each do |entry| # XXX hardcoding
40
+ xml.item about: entry_url(entry.date) do
41
+ xml.title entry.date.strftime('%Y/%m/%d')
42
+ xml.description { xml.cdata! entry.body }
43
+ xml.dc:date, entry.date
44
+ xml.link entry_url(entry.date)
45
+ xml.author config.author
46
+ end
45
47
  end
46
48
  end
47
49
  end
@@ -1,13 +1,15 @@
1
1
  # coding: utf-8
2
2
 
3
- class Retter::Pages::Index
4
- include Retter::Page
3
+ module Retter
4
+ class Pages::Index
5
+ include Page
5
6
 
6
- def pathname
7
- config.index_file
8
- end
7
+ def pathname
8
+ config.retter_home.join('index.html')
9
+ end
9
10
 
10
- def part_layout_pathname
11
- config.index_layout_file
11
+ def part_layout_pathname
12
+ Pages.find_layout_path('index')
13
+ end
12
14
  end
13
15
  end