retter 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,14 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ .rvmrc
6
+ lib/generator/skel/.gitignore
7
+ lib/generator/skel/.preview.html
8
+ lib/generator/skel/retters/*.md
9
+ lib/generator/skel/tmp/*
10
+ lib/generator/skel/entries.*
11
+ lib/generator/skel/entries/*.html
12
+ lib/generator/skel/vendor
13
+ tmp
14
+ .DS_Store
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source :rubygems
2
+
3
+ gem 'redcarpet', '>= 2.0.0b3'
4
+ gemspec
data/Rakefile ADDED
File without changes
data/bin/retter ADDED
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+ # coding: utf-8
3
+
4
+ $LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
5
+
6
+ require 'retter'
7
+
8
+ if ARGV[0] == 'new'
9
+ require 'generator/newretter'
10
+ Newretter.start ARGV[1..-1]
11
+ else
12
+ Retter::Command.start
13
+ end
@@ -0,0 +1,62 @@
1
+ # coding: utf-8
2
+
3
+ require 'thor/group'
4
+ require 'grit'
5
+ require 'bundler'
6
+ require 'bundler/cli'
7
+
8
+ class Newretter < Thor::Group
9
+ FILES = %w(
10
+ .gitignore
11
+ Gemfile
12
+ Retterfile
13
+ config.ru
14
+ layouts/entries.html.haml
15
+ layouts/entry.html.haml
16
+ layouts/profile.html.haml
17
+ layouts/index.html.haml
18
+ layouts/retter.html.haml
19
+ images/.gitkeep
20
+ index.html
21
+ entries/.gitkeep
22
+ javascripts/.gitkeep
23
+ stylesheets/application.css
24
+ retters/.gitkeep
25
+ )
26
+
27
+ include Thor::Actions
28
+
29
+ argument :name
30
+
31
+ def self.source_root
32
+ File.dirname(__FILE__)
33
+ end
34
+
35
+ def create_files
36
+ FILES.each do |file|
37
+ template("skel/#{file}", "#{name}/#{file}")
38
+ end
39
+ end
40
+
41
+ def bundle_install
42
+ pwd = Dir.pwd
43
+ FileUtils.cd name
44
+
45
+ Bundler::CLI.new.install
46
+
47
+ FileUtils.cd pwd
48
+ end
49
+
50
+ def git_init
51
+ Grit::Repo.init "#{Dir.pwd}/#{name}"
52
+ end
53
+
54
+ def notice_how_to_use
55
+ say <<-EOM, :green
56
+ -- Thanks for flying Retter :-> --
57
+ You have to set $RETTER_HOME variable to use #{name}.
58
+ example:
59
+ export RETTER_HOME=#{Dir.pwd}/#{name}
60
+ EOM
61
+ end
62
+ end
@@ -0,0 +1,2 @@
1
+ .preview.html
2
+ tmp/*
@@ -0,0 +1,5 @@
1
+ source :rubygems
2
+
3
+ gem 'rack'
4
+ gem 'thin' # for heroku
5
+
@@ -0,0 +1,6 @@
1
+ # coding: utf-8
2
+
3
+ url 'http://retter.example.com/'
4
+ title '<%= name %>'
5
+ description '<%= name %>'
6
+ author '<%= ENV["USER"] %>'
@@ -0,0 +1,28 @@
1
+ require 'rack'
2
+
3
+ use Rack::Static, root: '.', urls: %w(
4
+ /index.html
5
+ /profile.html
6
+ /entries.html
7
+ /entries.rss
8
+ /favicon.png
9
+ /entries
10
+ /stylesheets
11
+ /javascripts
12
+ /images
13
+ )
14
+
15
+ map '/' do
16
+ run ->(env) {
17
+ if env['PATH_INFO'] == '/'
18
+ [
19
+ 200,
20
+ {'Content-Type' => 'text/html', 'Cache-Control' => 'public, max-age=86400'},
21
+ File.open('index.html', File::RDONLY)
22
+ ]
23
+ else
24
+ [404, {'Content-Type' => 'text/plain'}, ['Not Found']]
25
+ end
26
+ }
27
+ end
28
+
File without changes
File without changes
@@ -0,0 +1 @@
1
+ :-)
File without changes
@@ -0,0 +1,9 @@
1
+ %article
2
+ %ul#entries
3
+ - entries.each do |entry|
4
+ %li
5
+ %a.entry{href: entry_path(entry.date)}= entry.date.strftime('%Y/%m/%d')
6
+ %ul.titles
7
+ - entry.titles.each do |id, title|
8
+ %li
9
+ %a.title{href: entry_path(entry.date, id)}= title
@@ -0,0 +1,4 @@
1
+ %article
2
+ .entry
3
+ %h1.date= entry.date.strftime('%Y/%m/%d')
4
+ = entry
@@ -0,0 +1,7 @@
1
+ #entries
2
+ - entries[0..5].each do |entry|
3
+ %article
4
+ .entry
5
+ %h1.date
6
+ %a{href: entry_path(entry.date)}= entry.date.strftime('%Y/%m/%d')
7
+ = entry
@@ -0,0 +1,6 @@
1
+ %article
2
+ %dl
3
+ %dt Author
4
+ %dd= config.author
5
+ %dt= config.title
6
+ %dd= config.description
@@ -0,0 +1,25 @@
1
+ !!!
2
+ %html
3
+ %head
4
+ %title= config.title
5
+ %meta{:'http-equiv' => 'Content-Type', content: 'text/html', charset: 'utf-8'}
6
+ %link{rel: 'icon', type: 'image/png', href: '/favicon.png'}
7
+ %link{href: '/stylesheets/application.css', media: 'screen', rel: 'stylesheet', type: 'text/css'}
8
+ %link{rel: 'alternate', type: 'application/rss+xml', title: 'RSS', href: '/entries.rss'}
9
+ %body
10
+ #header
11
+ %h1
12
+ %a{href: '/'}= config.title
13
+ %ul#menu
14
+ %li
15
+ %a{href: '/'} Home
16
+ %li
17
+ %a{href: '/profile.html'} Profile
18
+ %li
19
+ %a{href: '/entries.html'} Archives
20
+ %li
21
+ %a{href: '/entries.rss'} RSS
22
+ #page
23
+ #content= content
24
+ #footer
25
+ #{config.title} (C) #{config.author}
File without changes
@@ -0,0 +1,114 @@
1
+ html {
2
+ height: 100%;
3
+ }
4
+
5
+ body {
6
+ margin: 0 auto 0 auto;
7
+ padding: 0;
8
+ font-family: sans-serif;
9
+ /*lbackground: rgb(55,65,60);*/
10
+ background: #EEE;
11
+ height: 100%;
12
+ }
13
+
14
+ ul {
15
+ list-style: none;
16
+ }
17
+
18
+ a {
19
+ text-decoration: none;
20
+ color: rgb(25,30,10);
21
+ }
22
+
23
+ #header {
24
+ width: 100%;
25
+ padding: 0;
26
+ margin: 0;
27
+ }
28
+
29
+ #header h1 {
30
+ width: 100%;
31
+ margin: 0;
32
+ padding: 0.2em 0 0.2em 1em;
33
+ background: rgb(25,30,10);
34
+ color: rgb(77,144,253);
35
+ }
36
+
37
+ #header h1 a {
38
+ color: rgb(77,144,253);
39
+ }
40
+
41
+ #header ul#menu {
42
+ margin: 0.5em 0 3em 0;
43
+ padding: 0 0 0 2em;
44
+ background: #FFF;
45
+ }
46
+
47
+ #header ul#menu li {
48
+ float: left;
49
+ margin-right: 1em;
50
+ }
51
+
52
+ #page {
53
+ clear: both;
54
+ margin: 0 auto 0 auto;
55
+ width: 800px;
56
+ position: relative;
57
+ min-height: 100%;
58
+ }
59
+
60
+ article {
61
+ background: rgb(228,239,192);
62
+ color: rgb(0,30,67);
63
+ border-radius: 20px;
64
+ border: 3px rgb(25,30,10) solid;
65
+ -moz-border-radius: 20px;
66
+ -webkit-border-radius: 20px;
67
+ padding: 1em 1.5em 1em 1.5em;
68
+ margin: 1em 0 1em 0;
69
+ width 100%;
70
+ }
71
+
72
+ article h1 {
73
+ margin-top: 2em;
74
+ }
75
+
76
+ article h1.date {
77
+ font-size: 1em;
78
+ text-align: right;
79
+ margin-top: 0.5em;
80
+ margin-bottom: -2em;
81
+ }
82
+
83
+ article ul#entries > li {
84
+ margin-top: 1em;
85
+ }
86
+
87
+ article ul#entries {
88
+ line-height: 1.5em;
89
+ }
90
+
91
+ #entries {
92
+ width 100%;
93
+ }
94
+
95
+ pre {
96
+ background: #EEE;
97
+ color: rgb(0,30,67);
98
+ padding: 1em;
99
+ border-radius: 10px;
100
+ border: 1px #000 solid;
101
+ -moz-border-radius: 10px;
102
+ -webkit-border-radius: 10px;
103
+ }
104
+
105
+ #footer {
106
+ text-align: center;
107
+ margin: 1em 0 0 0;
108
+ padding: 0.5em 0.5em 0.5em 1em;
109
+ width: 100%;
110
+ background: rgb(0,40,40);
111
+ color: rgb(77,144,253);
112
+ position: relative; bottom: 0;
113
+ }
114
+
@@ -0,0 +1,74 @@
1
+ # coding: utf-8
2
+
3
+ class Retter::Command < Thor
4
+ desc 'edit', 'Edit current entry with $EDITOR'
5
+ method_options date: :string
6
+ def edit
7
+ system config.editor, detected_retter_file.to_s
8
+ end
9
+
10
+ default_task :edit
11
+
12
+ desc 'preview', 'Preview current entry'
13
+ method_options date: :string
14
+ def preview
15
+ preview = Retter::Stationery.previewer(detected_date, config)
16
+
17
+ preview.print
18
+ Launchy.open preview.file_path.to_s
19
+ end
20
+
21
+ desc 'open', 'Open site statically'
22
+ def open
23
+ Launchy.open config.index_file.to_s
24
+ end
25
+
26
+ desc 'rebind', 'Re generate site pages'
27
+ def rebind
28
+ binder = Retter::Stationery.binder(config)
29
+
30
+ binder.commit_wip_file
31
+ binder.rebind!
32
+ end
33
+
34
+ desc 'bind', 'Generate site pages'
35
+ alias_method :bind, :rebind
36
+
37
+ desc 'new', 'Create new site'
38
+ def new
39
+ end
40
+
41
+ private
42
+
43
+ def detected_retter_file
44
+ if options[:date]
45
+ config.retter_file(Date.parse(options[:date]), '.md')
46
+ else
47
+ todays_file = config.retter_file(Date.today, '.md')
48
+ todays_file.exist? ? todays_file : config.wip_file
49
+ end
50
+ end
51
+
52
+ def detected_date
53
+ options[:date] ? Date.parse(options[:date]) : Date.today
54
+ end
55
+
56
+ def config
57
+ @retter_config ||= Retter::Config.new(ENV)
58
+ rescue Retter::EnvError
59
+ say 'Set $RETTER_HOME and $EDITOR, first.', :red
60
+ say <<-EOM, :green
61
+ usage:
62
+ export EDITOR=`which vim` # or other editor
63
+ cd /path/to/dir
64
+ retter new my_sweet_diary
65
+ export RETTER_HOME=/path/to/dir/my_sweet_diary
66
+ cd my_sweet_diary
67
+ retter # Write the article with markdown, and save.
68
+ retter preview # Draft article will be opened in your default browser.
69
+ retter bind # Your actual website will be generated.
70
+ bundle exec rackup # Open your browser, and visit http://localhost:9292/ .
71
+ EOM
72
+ exit 1
73
+ end
74
+ end
@@ -0,0 +1,89 @@
1
+ # coding: utf-8
2
+
3
+ class Retter::Config
4
+ [:editor, :retter_home, :title, :description, :url, :author].each do |att|
5
+ class_eval <<-EOM
6
+ def #{att}(val = nil)
7
+ val ? @options[:#{att}] = val : @options[:#{att}]
8
+ end
9
+ EOM
10
+ end
11
+
12
+ def initialize(env)
13
+ @env, @options = env, {}
14
+
15
+ detect_retter_home
16
+ raise Retter::EnvError unless env.values_at('EDITOR', 'RETTER_HOME').all?
17
+
18
+ editor env['EDITOR']
19
+ retter_home Pathname.new(env['RETTER_HOME'])
20
+ url 'http://example.com'
21
+
22
+ retterfile = retter_home.join('Retterfile')
23
+ instance_eval retterfile.read if retterfile.exist?
24
+ end
25
+
26
+ def detect_retter_home
27
+ @env['RETTER_HOME'] = Dir.pwd if File.exist? 'Retterfile'
28
+ end
29
+
30
+ def retters_dir
31
+ retter_home.join 'retters/'
32
+ end
33
+
34
+ def wip_file
35
+ retters_dir.join 'today.md'
36
+ end
37
+
38
+ def retter_file(date, suf)
39
+ retters_dir.join(date ? date.strftime("%Y%m%d#{suf}") : "today#{suf}")
40
+ end
41
+
42
+ def layouts_dir
43
+ retter_home.join 'layouts/'
44
+ end
45
+
46
+ def layout_file
47
+ layouts_dir.join 'retter.html.haml'
48
+ end
49
+
50
+ def profile_layout_file
51
+ layouts_dir.join 'profile.html.haml'
52
+ end
53
+
54
+ def entry_layout_file
55
+ layouts_dir.join 'entry.html.haml'
56
+ end
57
+
58
+ def entries_layout_file
59
+ layouts_dir.join 'entries.html.haml'
60
+ end
61
+
62
+ def index_layout_file
63
+ layouts_dir.join 'index.html.haml'
64
+ end
65
+
66
+ def entries_dir
67
+ retter_home.join 'entries/'
68
+ end
69
+
70
+ def entry_file(date)
71
+ entries_dir.join date.strftime('%Y%m%d.html')
72
+ end
73
+
74
+ def profile_file
75
+ retter_home.join 'profile.html'
76
+ end
77
+
78
+ def index_file
79
+ retter_home.join 'index.html'
80
+ end
81
+
82
+ def entries_file
83
+ retter_home.join 'entries.html'
84
+ end
85
+
86
+ def feed_file
87
+ retter_home.join 'entries.rss'
88
+ end
89
+ end
@@ -0,0 +1,37 @@
1
+ # coding: utf-8
2
+
3
+ class Retter::Entry
4
+ attr_accessor :date, :body, :titles
5
+
6
+ def initialize(attrs={})
7
+ @date, @body = attrs.values_at(:date, :body)
8
+
9
+ attach_titles
10
+ load_titles
11
+ end
12
+
13
+ def to_s
14
+ body
15
+ end
16
+
17
+ private
18
+
19
+ def body_elements
20
+ Nokogiri::HTML(body)
21
+ end
22
+
23
+ def attach_titles
24
+ html = body_elements
25
+ html.search('//h1').each_with_index do |h1, seq|
26
+ h1.set_attribute 'id', "a#{seq}"
27
+ end
28
+
29
+ @body = html.search('//body/*').to_s
30
+ end
31
+
32
+ def load_titles
33
+ @titles = body_elements.search('//h1').each_with_object({}) {|h1, titles|
34
+ titles[h1.attr('id')] = h1.text
35
+ }
36
+ end
37
+ end
@@ -0,0 +1,130 @@
1
+ # coding: utf-8
2
+
3
+ module Retter::Stationery
4
+ class Binder
5
+ attr_reader :config, :entries
6
+
7
+ def initialize(config)
8
+ @config = config
9
+ end
10
+
11
+ def view_scope
12
+ @view_scope ||= View::Scope.new(config, entries: entries)
13
+ end
14
+
15
+ def renderer
16
+ Haml::Engine.new(config.layout_file.read, ugly: true)
17
+ end
18
+
19
+ def entries_renderer
20
+ Haml::Engine.new(config.entries_layout_file.read, ugly: true)
21
+ end
22
+
23
+ def entry_renderer
24
+ Haml::Engine.new(config.entry_layout_file.read, ugly: true)
25
+ end
26
+
27
+ def index_renderer
28
+ Haml::Engine.new(config.index_layout_file.read, ugly: true)
29
+ end
30
+
31
+ def profile_renderer
32
+ Haml::Engine.new(config.profile_layout_file.read, ugly: true)
33
+ end
34
+
35
+ def rebind!
36
+ commit_wip_file
37
+
38
+ @entries = Retter::Stationery.scan(config.retters_dir)
39
+
40
+ bind_entries
41
+ print_index
42
+ print_profile
43
+ print_rss
44
+ end
45
+
46
+ def commit_wip_file
47
+ if config.wip_file.exist?
48
+ html = config.wip_file.read
49
+ config.retter_file(Date.today, '.md').open('a') {|f| f.puts html }
50
+ config.wip_file.unlink
51
+ end
52
+ end
53
+
54
+ def bind_entries
55
+ @entries.each {|entry| print_entry entry }
56
+ print_toc
57
+ end
58
+
59
+ def print_entry(entry)
60
+ part = entry_renderer.render(view_scope, entry: entry)
61
+ html = renderer.render(view_scope, content: part)
62
+
63
+ config.entry_file(entry.date).open('w') do |f|
64
+ f.puts View::Helper.fix_path(html, '../')
65
+ end
66
+ end
67
+
68
+ def print_index
69
+ part = index_renderer.render(view_scope)
70
+ html = renderer.render(view_scope, content: part)
71
+
72
+ config.index_file.open('w') do |f|
73
+ f.puts View::Helper.fix_path(html, './')
74
+ end
75
+ end
76
+
77
+ def print_profile
78
+ part = profile_renderer.render(view_scope)
79
+ html = renderer.render(view_scope, content: part)
80
+
81
+ config.profile_file.open('w') do |f|
82
+ f.puts View::Helper.fix_path(html, './')
83
+ end
84
+ end
85
+
86
+ def print_toc
87
+ part = entries_renderer.render(view_scope)
88
+ html = renderer.render(view_scope, content: part)
89
+
90
+ config.entries_file.open('w') do |f|
91
+ f.puts View::Helper.fix_path(html, './')
92
+ end
93
+ end
94
+
95
+ def print_rss
96
+ config.feed_file.open('w') {|f| f.puts rss }
97
+ end
98
+
99
+ def rss
100
+ xml = Builder::XmlMarkup.new
101
+ xml.instruct!
102
+ xml.rdf:RDF, :xmlns => 'http://purl.org/rss/1.0/',
103
+ :'xmlns:rdf' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
104
+ :'xmlns:dc' => 'http://purl.org/dc/elements/1.1/',
105
+ :'xml:lang' => 'ja' do
106
+ xml.channel :'rdf:about' => config.url do
107
+ xml.title config.title
108
+ xml.link config.url
109
+ xml.dc:date, entries.first.date
110
+ xml.description config.description
111
+ xml.items { xml.rdf(:Seq) { entries.each {|e| xml.rdf:li, :'rdf:resource' => entry_url(e.date) } } }
112
+ end
113
+
114
+ entries.each do |entry|
115
+ xml.item about: entry_url(entry.date) do
116
+ xml.title entry.date.strftime('%Y/%m/%d')
117
+ xml.description { xml.cdata! entry.body }
118
+ xml.dc:date, entry.date
119
+ xml.link entry_url(entry.date)
120
+ xml.author config.author
121
+ end
122
+ end
123
+ end
124
+ end
125
+
126
+ def entry_url(date, id = nil)
127
+ (URI.parse(config.url) + date.strftime('/entries/%Y%m%d.html')).to_s
128
+ end
129
+ end
130
+ end
@@ -0,0 +1,59 @@
1
+ # coding: utf-8
2
+
3
+ module Retter::Stationery
4
+ class Previewer
5
+ attr_reader :config
6
+
7
+ def initialize(date, config)
8
+ @config, @date = config, date
9
+ @body, @entry = *nil
10
+
11
+ load_retter_file
12
+ load_wip_entry_if_needed
13
+ end
14
+
15
+ def file_path
16
+ config.retter_home.join '.preview.html'
17
+ end
18
+
19
+ def renderer
20
+ Haml::Engine.new(config.layout_file.read, ugly: true)
21
+ end
22
+
23
+ def entry_renderer
24
+ Haml::Engine.new(config.entry_layout_file.read, ugly: true)
25
+ end
26
+
27
+ def print
28
+ build_entry
29
+ print_html
30
+ end
31
+
32
+ private
33
+
34
+ def print_html
35
+ scope = View::Scope.new(config)
36
+ part = entry_renderer.render(scope, entry: @entry)
37
+ html = renderer.render(scope, content: part, entries: [@entry])
38
+
39
+ file_path.open('w') do |file|
40
+ file.puts View::Helper.fix_path(html, './')
41
+ end
42
+ end
43
+
44
+ def build_entry
45
+ @entry = Retter::Entry.new(date: @date, body: Retter::Stationery.parser.render(@body))
46
+ end
47
+
48
+ def load_retter_file
49
+ retter_file = config.retter_file(@date, '.md')
50
+ @body = retter_file.exist? ? retter_file.read : ''
51
+ end
52
+
53
+ def load_wip_entry_if_needed
54
+ if @date == Date.today && config.wip_file.exist?
55
+ @body = [@body, config.wip_file.read].join("\n")
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,9 @@
1
+ # coding: utf-8
2
+
3
+ module Retter::Stationery
4
+ class Renderer < ::Redcarpet::Render::HTML
5
+ def block_code(code, lang)
6
+ ::CodeRay.scan(code, lang ? lang.intern : :plain).div#.div(line_numbers: :table)
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,52 @@
1
+ # coding: utf-8
2
+
3
+ module Retter::Stationery::View
4
+ module Helper
5
+ extend self
6
+
7
+ def fix_path(html, prefix='./')
8
+ elements = Nokogiri::HTML(html)
9
+
10
+ elements.search("[src!=''][src!='']").each do |el|
11
+ src = el.attr('src').scan(/[^\.\/]{3}.*/).first
12
+ next if src =~ /^(?:http|https):\/\//
13
+
14
+ el.set_attribute 'src', [prefix, src].join
15
+ end
16
+
17
+ elements.search("[href][href!='#']").each do |el|
18
+ href = el.attr('href')
19
+ next if href =~ /^(?:http|https):\/\//
20
+
21
+ if href == '/'
22
+ el.set_attribute 'href', [prefix, 'index.html'].join
23
+ else
24
+ el.set_attribute 'href', [prefix, href.scan(/[^\.\/]{3}.*/).first].join
25
+ end
26
+ end
27
+
28
+ elements.to_s
29
+ end
30
+
31
+ def entry_path(date, id = nil)
32
+ date.strftime('/entries/%Y%m%d.html') + (id ? "##{id}" : '')
33
+ end
34
+ end
35
+
36
+ class Scope
37
+ attr_reader :config
38
+ attr_accessor :assigns
39
+
40
+ include Helper
41
+
42
+ [:entries].each do |meth|
43
+ define_method meth do
44
+ @assigns[meth]
45
+ end
46
+ end
47
+
48
+ def initialize(config, assigns = {})
49
+ @config, @assigns = config, assigns
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,47 @@
1
+ # coding: utf-8
2
+
3
+ module Retter::Stationery
4
+ class << self
5
+ def scan(path)
6
+ entries = find_markup_files(path).map {|file|
7
+ date = file.basename('.*').to_s
8
+ mkup = File.open(file, &:read)
9
+ Retter::Entry.new date: Date.parse(date), body: parser.render(mkup)
10
+ }
11
+
12
+ entries.sort_by(&:date).reverse
13
+ end
14
+
15
+ def find_markup_files(path)
16
+ path = Pathname.new(path).realpath
17
+ Dir.open(path, &:to_a).grep(/^\d{4}(?:0[1-9]|1[012])(?:0[1-9]|[12][0-9]|3[01])\.(md)$/).map {|f| path.join f }
18
+ end
19
+
20
+ def parser
21
+ @parser ||= ::Redcarpet::Markdown.new(
22
+ Renderer,
23
+ autolink: true,
24
+ space_after_headers: true,
25
+ fenced_code_blocks: true,
26
+ strikethrough: true,
27
+ superscript: true,
28
+ fenced_code_blocks: true,
29
+ tables: true
30
+ )
31
+ end
32
+
33
+ def previewer(date, config)
34
+ Previewer.new date, config
35
+ end
36
+
37
+ def binder(config)
38
+ Binder.new config
39
+ end
40
+ end
41
+ end
42
+
43
+ require 'retter/stationery/renderer'
44
+ require 'retter/stationery/view'
45
+ require 'retter/stationery/previewer'
46
+ require 'retter/stationery/binder'
47
+
@@ -0,0 +1,3 @@
1
+ module Retter
2
+ VERSION = '0.0.0'
3
+ end
data/lib/retter.rb ADDED
@@ -0,0 +1,25 @@
1
+ # coding: utf-8
2
+
3
+ here = File.dirname(__FILE__)
4
+ $LOAD_PATH.unshift here unless $LOAD_PATH.include?(here)
5
+
6
+ module Retter
7
+ class EnvError < RuntimeError; end
8
+ end
9
+
10
+ require 'date'
11
+ require 'time'
12
+ require 'builder'
13
+ require 'pathname'
14
+ require 'thor'
15
+ require 'redcarpet'
16
+ require 'coderay'
17
+ require 'nokogiri'
18
+ require 'launchy'
19
+ require 'haml'
20
+ require 'uri'
21
+ require 'retter/version'
22
+ require 'retter/entry'
23
+ require 'retter/stationery'
24
+ require 'retter/config'
25
+ require 'retter/command'
data/retter.gemspec ADDED
@@ -0,0 +1,34 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "retter/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "retter"
7
+ s.version = Retter::VERSION
8
+ s.authors = ["hibariya"]
9
+ s.email = ["celluloid.key@gmail.com"]
10
+ s.homepage = "http://retter.heroku.com"
11
+ s.summary = %q{Lightweight diary workflow}
12
+ s.description = %q{Lightweight diary workflow}
13
+
14
+ #s.rubyforge_project = "retter"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ s.add_runtime_dependency 'thor'
22
+ s.add_runtime_dependency 'builder'
23
+ s.add_runtime_dependency 'redcarpet', ['>= 2.0.0b3']
24
+ s.add_runtime_dependency 'coderay'
25
+ s.add_runtime_dependency 'nokogiri'
26
+ s.add_runtime_dependency 'launchy'
27
+ s.add_runtime_dependency 'haml'
28
+ s.add_runtime_dependency 'bundler'
29
+ s.add_runtime_dependency 'grit'
30
+
31
+ s.add_development_dependency 'ir_b'
32
+ s.add_development_dependency 'tapp'
33
+ s.add_development_dependency 'rspec'
34
+ end
@@ -0,0 +1,52 @@
1
+ # coding: utf-8
2
+
3
+ require File.dirname(__FILE__) + '/../spec_helper'
4
+
5
+ describe 'Retter::Command#edit', clean: :all do
6
+ let(:command) { Retter::Command.new }
7
+ let(:wip_file) { retter_config.wip_file }
8
+
9
+ before do
10
+ command.stub!(:config) { retter_config }
11
+ end
12
+
13
+ context 'no options' do
14
+ before do
15
+ command.edit
16
+ end
17
+
18
+ it { wip_file.should be_exist }
19
+ end
20
+
21
+ context 'no options after rebind' do
22
+ let(:date) { '20110101' }
23
+
24
+ before do
25
+ Date.stub!(:today).and_return(Date.parse(date))
26
+
27
+ command.edit
28
+ command.bind
29
+ command.edit
30
+ end
31
+
32
+ it { wip_file.should_not be_exist }
33
+ it { retter_config.retters_dir.join("#{date}.md").should be_exist }
34
+ end
35
+
36
+ context 'with date' do
37
+ let(:date) { '20110101' }
38
+
39
+ before do
40
+ command.stub!(:options) { {date: date} }
41
+ command.edit
42
+ end
43
+
44
+ it { wip_file.should_not be_exist }
45
+
46
+ describe 'target date file' do
47
+ subject { retter_config.retters_dir.join("#{date}.md") }
48
+
49
+ it { should be_exist }
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,43 @@
1
+ # coding: utf-8
2
+
3
+ require File.dirname(__FILE__) + '/../spec_helper'
4
+
5
+ describe 'Retter::Command#preview', clean: :all do
6
+ let(:command) { Retter::Command.new }
7
+ let(:preview) { retter_config.retter_home.join('.preview.html').read }
8
+ let(:wip_file) { retter_config.wip_file }
9
+ let(:date_file) { retter_config.retter_file(Date.parse(date), '.md') }
10
+
11
+ before do
12
+ command.stub!(:config) { retter_config }
13
+ end
14
+
15
+ context 'no options' do
16
+ let(:article) { 'w00t!' }
17
+
18
+ before do
19
+ wip_file.open('w') {|f| f.puts article }
20
+ Launchy.stub!(:open).with(anything)
21
+
22
+ command.preview
23
+ end
24
+
25
+ it { preview.should =~ /<body.*#{article}.*\/body>/mi }
26
+ end
27
+
28
+ context 'with date' do
29
+ let(:article) { 'おはようございます' }
30
+ let(:date) { '20110101' }
31
+
32
+ before do
33
+ wip_file.open('w') {|f| f.puts 'おやすみなさい' }
34
+ date_file.open('w') {|f| f.puts article }
35
+ Launchy.stub!(:open).with(anything)
36
+
37
+ command.preview
38
+ end
39
+
40
+ it { preview =~ /#{article}/mi }
41
+ it { preview !~ /おやすみなさい/mi }
42
+ end
43
+ end
@@ -0,0 +1,53 @@
1
+ # coding: utf-8
2
+
3
+ require File.dirname(__FILE__) + '/../spec_helper'
4
+
5
+ describe 'Retter::Command#rebind', clean: :all do
6
+ let(:command) { Retter::Command.new }
7
+ let(:wip_file) { retter_config.wip_file }
8
+ let(:date_file) { retter_config.retter_file(Date.parse(date), '.md') }
9
+ let(:date_html) { retter_config.retter_home.join('entries', "#{date}.html") }
10
+
11
+ before do
12
+ command.stub!(:config) { retter_config }
13
+ end
14
+
15
+ context 'first post' do
16
+ let(:date) { '20110101' }
17
+ let(:article) { <<-EOM }
18
+ # 朝11時
19
+
20
+ おはようございます
21
+
22
+ # 夜1時
23
+
24
+ おやすみなさい
25
+ EOM
26
+
27
+ before do
28
+ wip_file.open('w') {|f| f.puts article }
29
+ Date.stub!(:today).and_return(Date.parse(date))
30
+
31
+ command.rebind
32
+ end
33
+
34
+ describe 'today.md' do
35
+ it { wip_file.should_not be_exist }
36
+ end
37
+
38
+ describe 'index.html' do
39
+ subject { Nokogiri::HTML(retter_config.retter_home.join('index.html').read) }
40
+
41
+ it { subject.search('body').text.should =~ /おはようございます/ }
42
+ it { subject.search('.entry h1.date').first.text.should be_include('2011/01/01') }
43
+ it { subject.search('.entry h1').map(&:text).map(&:strip).should == %w(2011/01/01 朝11時 夜1時) }
44
+ end
45
+
46
+ describe 'entries.html' do
47
+ subject { Nokogiri::HTML(retter_config.retter_home.join('entries.html').read) }
48
+
49
+ it { subject.search('a.entry').first.text.should be_include('2011/01/01') }
50
+ it { subject.search('a.title').map(&:text).map(&:strip).should == %w(朝11時 夜1時) }
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,37 @@
1
+ # coding: utf-8
2
+
3
+ RETTER_ROOT = Pathname.new(File.dirname(__FILE__) + '/../').realpath
4
+
5
+ require RETTER_ROOT.join('lib', 'retter')
6
+ require 'tapp'
7
+
8
+ module Retter::ConfigSupport
9
+ def retter_config
10
+ return @config if @config
11
+
12
+ env = {
13
+ 'EDITOR' => 'touch',
14
+ 'RETTER_HOME' => RETTER_ROOT.join('tmp', 'test').to_s
15
+ }
16
+
17
+ @config = Retter::Config.new(env)
18
+ end
19
+ end
20
+
21
+ RSpec.configure do |config|
22
+ config.filter_run focus: true
23
+ config.run_all_when_everything_filtered = true
24
+
25
+ retter_home = RETTER_ROOT.join('tmp', 'test')
26
+ skel = RETTER_ROOT.join('lib', 'generator', 'skel')
27
+
28
+ config.after(:each, clean: :all) do
29
+ FileUtils.cp_r skel, retter_home.dirname.join('test')
30
+ end
31
+
32
+ config.after(:each, clean: :all) do
33
+ FileUtils.rm_rf retter_home
34
+ end
35
+
36
+ config.include Retter::ConfigSupport
37
+ end
metadata ADDED
@@ -0,0 +1,217 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: retter
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - hibariya
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-09-08 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: thor
16
+ requirement: &70260599810340 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *70260599810340
25
+ - !ruby/object:Gem::Dependency
26
+ name: builder
27
+ requirement: &70260599899920 !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: *70260599899920
36
+ - !ruby/object:Gem::Dependency
37
+ name: redcarpet
38
+ requirement: &70260599902380 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: 2.0.0b3
44
+ type: :runtime
45
+ prerelease: false
46
+ version_requirements: *70260599902380
47
+ - !ruby/object:Gem::Dependency
48
+ name: coderay
49
+ requirement: &70260599904040 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :runtime
56
+ prerelease: false
57
+ version_requirements: *70260599904040
58
+ - !ruby/object:Gem::Dependency
59
+ name: nokogiri
60
+ requirement: &70260599913220 !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ! '>='
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ type: :runtime
67
+ prerelease: false
68
+ version_requirements: *70260599913220
69
+ - !ruby/object:Gem::Dependency
70
+ name: launchy
71
+ requirement: &70260599914340 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ! '>='
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ type: :runtime
78
+ prerelease: false
79
+ version_requirements: *70260599914340
80
+ - !ruby/object:Gem::Dependency
81
+ name: haml
82
+ requirement: &70260599913880 !ruby/object:Gem::Requirement
83
+ none: false
84
+ requirements:
85
+ - - ! '>='
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ type: :runtime
89
+ prerelease: false
90
+ version_requirements: *70260599913880
91
+ - !ruby/object:Gem::Dependency
92
+ name: bundler
93
+ requirement: &70260599913440 !ruby/object:Gem::Requirement
94
+ none: false
95
+ requirements:
96
+ - - ! '>='
97
+ - !ruby/object:Gem::Version
98
+ version: '0'
99
+ type: :runtime
100
+ prerelease: false
101
+ version_requirements: *70260599913440
102
+ - !ruby/object:Gem::Dependency
103
+ name: grit
104
+ requirement: &70260599912660 !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ type: :runtime
111
+ prerelease: false
112
+ version_requirements: *70260599912660
113
+ - !ruby/object:Gem::Dependency
114
+ name: ir_b
115
+ requirement: &70260599910020 !ruby/object:Gem::Requirement
116
+ none: false
117
+ requirements:
118
+ - - ! '>='
119
+ - !ruby/object:Gem::Version
120
+ version: '0'
121
+ type: :development
122
+ prerelease: false
123
+ version_requirements: *70260599910020
124
+ - !ruby/object:Gem::Dependency
125
+ name: tapp
126
+ requirement: &70260599907780 !ruby/object:Gem::Requirement
127
+ none: false
128
+ requirements:
129
+ - - ! '>='
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: *70260599907780
135
+ - !ruby/object:Gem::Dependency
136
+ name: rspec
137
+ requirement: &70260599907300 !ruby/object:Gem::Requirement
138
+ none: false
139
+ requirements:
140
+ - - ! '>='
141
+ - !ruby/object:Gem::Version
142
+ version: '0'
143
+ type: :development
144
+ prerelease: false
145
+ version_requirements: *70260599907300
146
+ description: Lightweight diary workflow
147
+ email:
148
+ - celluloid.key@gmail.com
149
+ executables:
150
+ - retter
151
+ extensions: []
152
+ extra_rdoc_files: []
153
+ files:
154
+ - .gitignore
155
+ - Gemfile
156
+ - Rakefile
157
+ - bin/retter
158
+ - lib/generator/newretter.rb
159
+ - lib/generator/skel/.gitignore
160
+ - lib/generator/skel/Gemfile
161
+ - lib/generator/skel/Retterfile
162
+ - lib/generator/skel/config.ru
163
+ - lib/generator/skel/entries/.gitkeep
164
+ - lib/generator/skel/images/.gitkeep
165
+ - lib/generator/skel/index.html
166
+ - lib/generator/skel/javascripts/.gitkeep
167
+ - lib/generator/skel/layouts/entries.html.haml
168
+ - lib/generator/skel/layouts/entry.html.haml
169
+ - lib/generator/skel/layouts/index.html.haml
170
+ - lib/generator/skel/layouts/profile.html.haml
171
+ - lib/generator/skel/layouts/retter.html.haml
172
+ - lib/generator/skel/retters/.gitkeep
173
+ - lib/generator/skel/stylesheets/application.css
174
+ - lib/retter.rb
175
+ - lib/retter/command.rb
176
+ - lib/retter/config.rb
177
+ - lib/retter/entry.rb
178
+ - lib/retter/stationery.rb
179
+ - lib/retter/stationery/binder.rb
180
+ - lib/retter/stationery/previewer.rb
181
+ - lib/retter/stationery/renderer.rb
182
+ - lib/retter/stationery/view.rb
183
+ - lib/retter/version.rb
184
+ - retter.gemspec
185
+ - spec/command/edit_spec.rb
186
+ - spec/command/preview_spec.rb
187
+ - spec/command/rebind_spec.rb
188
+ - spec/spec_helper.rb
189
+ homepage: http://retter.heroku.com
190
+ licenses: []
191
+ post_install_message:
192
+ rdoc_options: []
193
+ require_paths:
194
+ - lib
195
+ required_ruby_version: !ruby/object:Gem::Requirement
196
+ none: false
197
+ requirements:
198
+ - - ! '>='
199
+ - !ruby/object:Gem::Version
200
+ version: '0'
201
+ required_rubygems_version: !ruby/object:Gem::Requirement
202
+ none: false
203
+ requirements:
204
+ - - ! '>='
205
+ - !ruby/object:Gem::Version
206
+ version: '0'
207
+ requirements: []
208
+ rubyforge_project:
209
+ rubygems_version: 1.8.6
210
+ signing_key:
211
+ specification_version: 3
212
+ summary: Lightweight diary workflow
213
+ test_files:
214
+ - spec/command/edit_spec.rb
215
+ - spec/command/preview_spec.rb
216
+ - spec/command/rebind_spec.rb
217
+ - spec/spec_helper.rb