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.
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'