retter 0.2.2 → 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. data/.travis.yml +1 -1
  2. data/ChangeLog.md +10 -0
  3. data/README.md +1 -3
  4. data/bin/retter +8 -4
  5. data/lib/retter/binder.rb +50 -0
  6. data/lib/retter/command.rb +42 -39
  7. data/lib/retter/config.rb +24 -23
  8. data/lib/retter/entries.rb +14 -18
  9. data/lib/retter/entry.rb +52 -29
  10. data/lib/retter/generator/base.rb +6 -7
  11. data/lib/retter/generator/skel/Gemfile +1 -2
  12. data/lib/retter/generator/skel/Retterfile +2 -2
  13. data/lib/retter/generator/skel/layouts/article.html.haml +3 -2
  14. data/lib/retter/generator/skel/layouts/entry.html.haml +3 -2
  15. data/lib/retter/generator/skel/layouts/index.html.haml +4 -2
  16. data/lib/retter/generator.rb +0 -1
  17. data/lib/retter/{renderers.rb → markdown.rb} +22 -1
  18. data/lib/retter/page/article.rb +54 -0
  19. data/lib/retter/page/base.rb +97 -0
  20. data/lib/retter/page/entries.rb +17 -0
  21. data/lib/retter/page/entry.rb +46 -0
  22. data/lib/retter/page/feed.rb +63 -0
  23. data/lib/retter/page/index.rb +17 -0
  24. data/lib/retter/page/profile.rb +17 -0
  25. data/lib/retter/page/view_helper.rb +9 -1
  26. data/lib/retter/page.rb +22 -74
  27. data/lib/retter/preprint.rb +19 -10
  28. data/lib/retter/version.rb +1 -1
  29. data/lib/retter.rb +41 -29
  30. data/retter.gemspec +44 -53
  31. data/spec/command/callback_spec.rb +16 -6
  32. data/spec/command/clean_spec.rb +20 -0
  33. data/spec/command/commit_spec.rb +11 -12
  34. data/spec/command/edit_spec.rb +28 -38
  35. data/spec/command/list_spec.rb +4 -4
  36. data/spec/command/open_spec.rb +2 -2
  37. data/spec/command/preview_spec.rb +7 -12
  38. data/spec/command/rebind_spec.rb +143 -66
  39. data/spec/spec_helper.rb +10 -3
  40. data/spec/support/example_group_helper.rb +55 -15
  41. data/spec/support/matchers.rb +0 -1
  42. metadata +195 -78
  43. data/lib/retter/generator/updator.rb +0 -7
  44. data/lib/retter/pages/article.rb +0 -41
  45. data/lib/retter/pages/entries.rb +0 -15
  46. data/lib/retter/pages/entry.rb +0 -35
  47. data/lib/retter/pages/feed.rb +0 -51
  48. data/lib/retter/pages/index.rb +0 -15
  49. data/lib/retter/pages/profile.rb +0 -15
  50. data/lib/retter/pages.rb +0 -77
  51. data/spec/command/invoke_after_spec.rb +0 -29
  52. data/spec/fixtures/sample.md +0 -295
@@ -2,7 +2,6 @@
2
2
 
3
3
  module Retter::Generator
4
4
  autoload :Creator, 'retter/generator/creator'
5
- autoload :Updator, 'retter/generator/updator'
6
5
  end
7
6
 
8
7
  require 'retter/generator/base'
@@ -6,7 +6,7 @@ require 'coderay'
6
6
  require 'set'
7
7
 
8
8
  module Retter
9
- module Renderers
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,17 @@
1
+ # coding: utf-8
2
+
3
+ module Retter
4
+ module Page
5
+ class Entries
6
+ include Base
7
+
8
+ def path
9
+ config.retter_home.join('entries.html')
10
+ end
11
+
12
+ def template_path
13
+ Page.find_template_path('entries')
14
+ end
15
+ end
16
+ end
17
+ 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
@@ -0,0 +1,17 @@
1
+ # coding: utf-8
2
+
3
+ module Retter
4
+ module Page
5
+ class Index
6
+ include Base
7
+
8
+ def path
9
+ config.retter_home.join('index.html')
10
+ end
11
+
12
+ def template_path
13
+ Page.find_template_path('index')
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ # coding: utf-8
2
+
3
+ module Retter
4
+ module Page
5
+ class Profile
6
+ include Base
7
+
8
+ def path
9
+ config.retter_home.join('profile.html')
10
+ end
11
+
12
+ def template_path
13
+ Page.find_template_path('profile')
14
+ end
15
+ end
16
+ end
17
+ end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Retter
4
4
  module Page::ViewHelper
5
- include Stationery
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
- require 'retter/page/view_helper'
9
+ autoload :Base, 'retter/page/base'
10
+ autoload :ViewHelper, 'retter/page/view_helper'
10
11
 
11
- include Stationery
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
- attr_reader :path_prefix, :title
19
+ extend Configurable
14
20
 
15
- def initialize
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
- def fix_path(html, prefix='./')
57
- elements = Nokogiri::HTML(html)
23
+ class << self
24
+ def find_template_path(name)
25
+ detected = Dir.glob(layouts_dir.join("#{name}.*.*")).first
58
26
 
59
- fix_href_path(fix_src_path(elements, prefix), prefix).to_s
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
- elements
71
- end
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
- elements
86
- end
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
- define_method :view_scope do
92
- view_scope
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
@@ -2,24 +2,33 @@
2
2
 
3
3
  module Retter
4
4
  class Preprint
5
- include Page
5
+ class ViewContext < Page::Base::ViewContext
6
+ attr_reader :entry
6
7
 
7
- def pathname
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 part_layout_pathname
12
- Pages.find_layout_path('entry')
19
+ def template_path
20
+ Page.find_template_path('entry')
13
21
  end
14
22
 
15
- def print(entry)
16
- part = Tilt.new(
17
- part_layout_pathname.to_path,
23
+ def bind(entry)
24
+ context = ViewContext.new(entry)
25
+ part = Tilt.new(
26
+ template_path.to_path,
18
27
  ugly: true,
19
- filename: part_layout_pathname.to_path
20
- ).render(view_scope, entry: entry)
28
+ filename: template_path.to_path
29
+ ).render(context)
21
30
 
22
- print_with_layout part
31
+ print part
23
32
  end
24
33
  end
25
34
  end
@@ -1,3 +1,3 @@
1
1
  module Retter
2
- VERSION = '0.2.2'
2
+ VERSION = '0.2.3'
3
3
  end
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 Stationery
10
- [:config, :entries].each do |meth|
11
- define_method meth do
12
- Retter.send meth
13
- end
14
- end
15
- end
27
+ module Site
28
+ extend self
29
+ extend Configurable
16
30
 
17
- class << self
18
- attr_reader :config
31
+ configurable :home, :title, :description, :url, :author
19
32
 
20
33
  def load(env)
21
- @config = Config.new(env)
34
+ @@config = Config.new(env)
22
35
  end
23
36
 
24
37
  def reset!
25
- @entries = nil
38
+ @@entries = nil
26
39
  end
27
40
 
28
41
  def entries
29
- @entries ||= Entries.new
42
+ @@entries ||= Entries.new
30
43
  end
31
- end
32
44
 
33
- autoload :Generator, 'retter/generator'
45
+ def config
46
+ @@config
47
+ end
48
+ end
34
49
 
35
- autoload :VERSION, 'retter/version'
36
- autoload :Configurable, 'retter/configurable'
37
- autoload :Config, 'retter/config'
38
- autoload :Renderers, 'retter/renderers'
39
- autoload :Entry, 'retter/entry'
40
- autoload :Entries, 'retter/entries'
41
- autoload :Page, 'retter/page'
42
- autoload :Pages, 'retter/pages'
43
- autoload :Preprint, 'retter/preprint'
44
- autoload :Repository, 'retter/repository'
45
- autoload :Command, 'retter/command'
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'