diary 0.1.1

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.
@@ -0,0 +1,22 @@
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.swp
15
+
16
+ ## PROJECT::GENERAL
17
+ coverage
18
+ rdoc
19
+ pkg
20
+
21
+ ## PROJECT::SPECIFIC
22
+ .document
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Robin Clart
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,3 @@
1
+ = Diary
2
+
3
+ Dead Simple, Static Blog Generator.
@@ -0,0 +1,20 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "diary"
8
+ gem.summary = "Dead Simple, Static Blog Generator"
9
+
10
+ gem.email = "robin@clart.me"
11
+ gem.homepage = "http://github.com/robinclart/diary"
12
+ gem.authors = ["Robin Clart"]
13
+
14
+ gem.add_dependency('liquid', '>= 2.0.0')
15
+ gem.add_dependency('bluecloth', '>= 2.0.7')
16
+ end
17
+ Jeweler::GemcutterTasks.new
18
+ rescue LoadError
19
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
20
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.1
@@ -0,0 +1,43 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
4
+
5
+ require 'diary'
6
+ require 'diary/cli'
7
+
8
+ options = Diary::CLI.parse(ARGV)
9
+ # Diary.config(options)
10
+
11
+ case ARGV.size
12
+ when 1
13
+ case ARGV[0]
14
+ when "compile"
15
+ Diary::Site.compile(options.force)
16
+ when "init"
17
+ Diary::Site.new(options)
18
+ else
19
+ puts "Invalid option. Run `diary --help`."
20
+ end
21
+ when 2
22
+ case ARGV[0]
23
+ when "draft"
24
+ Diary::Draft.new(ARGV[1])
25
+ when "page"
26
+ Diary::Page.new(ARGV[1])
27
+ when "post"
28
+ Diary::Post.new(ARGV[1])
29
+ when "publish"
30
+ Diary::Draft.publish(ARGV[1])
31
+ else
32
+ puts "Invalid option. Run `diary --help`."
33
+ end
34
+ when 3
35
+ case ARGV[0]
36
+ when "publish"
37
+ Diary::Draft.publish(ARGV[1], ARGV[2])
38
+ else
39
+ puts "Invalid option. Run `diary --help`."
40
+ end
41
+ else
42
+ puts "Invalid option(s). Run `diary --help`."
43
+ end
@@ -0,0 +1,65 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{diary}
8
+ s.version = "0.1.1"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Robin Clart"]
12
+ s.date = %q{2010-06-28}
13
+ s.default_executable = %q{diary}
14
+ s.email = %q{robin@clart.me}
15
+ s.executables = ["diary"]
16
+ s.extra_rdoc_files = [
17
+ "LICENSE",
18
+ "README.rdoc"
19
+ ]
20
+ s.files = [
21
+ ".gitignore",
22
+ "LICENSE",
23
+ "README.rdoc",
24
+ "Rakefile",
25
+ "VERSION",
26
+ "bin/diary",
27
+ "diary.gemspec",
28
+ "lib/diary.rb",
29
+ "lib/diary/cli.rb",
30
+ "lib/diary/draft.rb",
31
+ "lib/diary/item.rb",
32
+ "lib/diary/page.rb",
33
+ "lib/diary/post.rb",
34
+ "lib/diary/site.rb",
35
+ "lib/diary/template.rb",
36
+ "test/helper.rb",
37
+ "test/test_diary.rb"
38
+ ]
39
+ s.homepage = %q{http://github.com/robinclart/diary}
40
+ s.rdoc_options = ["--charset=UTF-8"]
41
+ s.require_paths = ["lib"]
42
+ s.rubygems_version = %q{1.3.6}
43
+ s.summary = %q{Dead Simple, Static Blog Generator}
44
+ s.test_files = [
45
+ "test/helper.rb",
46
+ "test/test_diary.rb"
47
+ ]
48
+
49
+ if s.respond_to? :specification_version then
50
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
51
+ s.specification_version = 3
52
+
53
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
54
+ s.add_runtime_dependency(%q<liquid>, [">= 2.0.0"])
55
+ s.add_runtime_dependency(%q<bluecloth>, [">= 2.0.7"])
56
+ else
57
+ s.add_dependency(%q<liquid>, [">= 2.0.0"])
58
+ s.add_dependency(%q<bluecloth>, [">= 2.0.7"])
59
+ end
60
+ else
61
+ s.add_dependency(%q<liquid>, [">= 2.0.0"])
62
+ s.add_dependency(%q<bluecloth>, [">= 2.0.7"])
63
+ end
64
+ end
65
+
@@ -0,0 +1,46 @@
1
+ $:.unshift File.dirname(__FILE__)
2
+
3
+ # rubygems
4
+ require 'rubygems'
5
+
6
+ # stdlib
7
+ require 'fileutils'
8
+ require 'date'
9
+ require 'yaml'
10
+ require 'ostruct'
11
+
12
+ # third party
13
+ require 'liquid'
14
+ require 'bluecloth'
15
+
16
+ module Diary
17
+ module Message
18
+ # Red
19
+ Error = " \e[1;31merror\e[0m"
20
+
21
+ # Green
22
+ Published = " \e[1;32mpublished\e[0m"
23
+ Created = " \e[1;32mcreated\e[0m"
24
+ Updated = " \e[1;32mupdated\e[0m"
25
+
26
+ # Yellow
27
+ Identical = " \e[1;33midentical\e[0m"
28
+ Exist = " \e[1;33mexist\e[0m"
29
+
30
+ # Cyan
31
+ Invoke = " \e[1;36minvoke\e[0m"
32
+ end
33
+
34
+ def self.version
35
+ File.read(File.expand_path("../../VERSION", __FILE__))
36
+ end
37
+ end
38
+
39
+
40
+ # internals
41
+ require 'diary/site'
42
+ require 'diary/template'
43
+ require 'diary/item'
44
+ require 'diary/draft'
45
+ require 'diary/page'
46
+ require 'diary/post'
@@ -0,0 +1,47 @@
1
+ require 'optparse'
2
+
3
+ module Diary
4
+ class CLI
5
+ def self.parse(args)
6
+ # The options specified on the command line will be collected in *options*.
7
+ # We set default values here.
8
+ options = OpenStruct.new
9
+ options.verbose = false
10
+ options.force = false
11
+
12
+ opts = OptionParser.new do |opts|
13
+ opts.banner = "Usage: diary ACTION [-vf]"
14
+
15
+ opts.separator "\nSpecific options:"
16
+
17
+ # Verbose
18
+ opts.on("-v", "--[no-]verbose", "Run verbosely") do |v|
19
+ options.verbose = v
20
+ end
21
+
22
+ # Force
23
+ opts.on("-f", "--[no-]force", "Force all items to compile") do |f|
24
+ options.force = f
25
+ end
26
+
27
+ opts.separator "\nCommon options:"
28
+
29
+ # No argument, shows at tail. This will print an options summary.
30
+ # Try it and see!
31
+ opts.on_tail("-h", "--help", "Show this message") do
32
+ puts opts
33
+ exit
34
+ end
35
+
36
+ # Another typical switch to print the version.
37
+ opts.on_tail("--version", "Show version") do
38
+ puts "diary #{Diary.version}"
39
+ exit
40
+ end
41
+ end
42
+
43
+ opts.parse!(args)
44
+ options
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,27 @@
1
+ module Diary
2
+ class Draft < Item
3
+ include Message
4
+
5
+ def initialize(title, not_used = nil)
6
+ super(title, "")
7
+ end
8
+
9
+ def self.publish(title, date = Date.today)
10
+ from = [base_directory, "#{title}.md"].join('/')
11
+ to = [Post.base_directory, date.to_s.split('-').join('/')].join('/')
12
+
13
+ FileUtils.mkdir_p to
14
+ FileUtils.mv from, to
15
+
16
+ puts "#{Published} #{to}/#{title}.md"
17
+ rescue Errno::ENOENT
18
+ puts "#{Error} No draft found"
19
+ end
20
+
21
+ private
22
+
23
+ def self.base_directory
24
+ 'drafts'
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,166 @@
1
+ # coding: utf-8
2
+
3
+ module Diary
4
+ class Item
5
+ include Message
6
+
7
+ ACCENTS = {
8
+ ['á','à','â','ä','ã'] => 'a',
9
+ ['Ã','Ä','Â','À','�?'] => 'A',
10
+ ['é','è','ê','ë'] => 'e',
11
+ ['Ë','É','È','Ê'] => 'E',
12
+ ['í','ì','î','ï'] => 'i',
13
+ ['�?','Î','Ì','�?'] => 'I',
14
+ ['ó','ò','ô','ö','õ'] => 'o',
15
+ ['Õ','Ö','Ô','Ò','Ó'] => 'O',
16
+ ['ú','ù','û','ü'] => 'u',
17
+ ['Ú','Û','Ù','Ü'] => 'U',
18
+ ['ç'] => 'c', ['Ç'] => 'C',
19
+ ['ñ'] => 'n', ['Ñ'] => 'N'
20
+ }
21
+
22
+ attr_reader :file_name
23
+ attr_reader :dir_path
24
+
25
+ def initialize(title, directory)
26
+ @file_name = title
27
+ @dir_path = directory.eql?("") ? nil : directory
28
+ @file_path = file_path
29
+
30
+ unless file_exists?
31
+ self.class.create(file_name, file_path, dir_path)
32
+ else
33
+ puts "#{Exist} #{file_path}"
34
+ end
35
+ end
36
+
37
+ def output(force = false)
38
+ if changed? or force
39
+ FileUtils.mkdir_p ["output", dir_path].compact.join('/')
40
+ output_file = File.new(output_file_path, 'w+')
41
+ output_file.puts render
42
+ output_file.close
43
+
44
+ puts "#{Invoke} #{template.path}"
45
+ puts "#{Updated} #{output_file_path}"
46
+ else
47
+ puts "#{Identical} #{output_file_path}"
48
+ end
49
+ end
50
+
51
+ def template
52
+ @template ||= Template.lookup(self, options.template)
53
+ end
54
+
55
+ def file
56
+ File.new(file_path)
57
+ end
58
+
59
+ def content
60
+ file.read.split(/---\n/).slice(-1)
61
+ end
62
+
63
+ def options
64
+ if ydoc.is_a?(Hash)
65
+ @options ||= OpenStruct.new(ydoc)
66
+ else
67
+ OpenStruct.new
68
+ end
69
+ end
70
+
71
+ def ydoc
72
+ YAML.parse_file(file_path).transform if YAML.parse_file(file_path)
73
+ end
74
+
75
+ def slug
76
+ nice_slug
77
+ end
78
+
79
+ def file_path
80
+ @file_path ||= [self.class.base_directory, @dir_path, "#{file_name}.md"].compact.join('/')
81
+ end
82
+
83
+ def output_file_path
84
+ @output_file_path ||= ["output", @dir_path, "#{slug}.html"].compact.join('/')
85
+ end
86
+
87
+ def class_name
88
+ self.class.name.split('::').slice(-1)
89
+ end
90
+
91
+ def changed?
92
+ file.mtime > File.new(output_file_path).ctime
93
+ rescue Errno::ENOENT
94
+ true
95
+ end
96
+
97
+ def self.first
98
+ all.first
99
+ end
100
+
101
+ def self.last
102
+ all.last
103
+ end
104
+
105
+ def self.all
106
+ Dir[File.join(base_directory, "**", "*.md")].map do |path|
107
+ self.new resolve_file_name(path), resolve_directory(path)
108
+ end
109
+ end
110
+
111
+ def self.compile(force = false)
112
+ all.each { |p| p.output(force) }
113
+ end
114
+
115
+ private
116
+
117
+ def file_exists?
118
+ File.exists?(file_path)
119
+ end
120
+
121
+ def render
122
+ liquidize.render('yield' => markdownize)
123
+ end
124
+
125
+ def liquidize
126
+ Liquid::Template.parse(template.file.read)
127
+ end
128
+
129
+ def markdownize
130
+ BlueCloth.new(content).to_html
131
+ end
132
+
133
+ def nice_slug
134
+ str = ""
135
+ ACCENTS.each do |ac,rep|
136
+ ac.each do |s|
137
+ str = file_name.gsub(s, rep)
138
+ end
139
+ end
140
+ str.gsub(/[^a-zA-Z0-9 ]/, "")
141
+ .gsub(/[ ]+/, " ")
142
+ .gsub(/ /, "-")
143
+ .downcase
144
+ end
145
+
146
+ def self.resolve_directory(path)
147
+ ary = path.split('/')
148
+ ary.pop
149
+ ary.shift
150
+ ary.join('/')
151
+ end
152
+
153
+ def self.resolve_file_name(path)
154
+ path.gsub(/.md/, '').split('/').slice(-1)
155
+ end
156
+
157
+ def self.create(title, path, directory)
158
+ FileUtils.mkdir_p("#{base_directory}/#{directory}")
159
+ file = File.new(path, "w+")
160
+ file.puts("# #{title}")
161
+ file.close
162
+
163
+ puts "#{Created} #{path}"
164
+ end
165
+ end
166
+ end
@@ -0,0 +1,13 @@
1
+ module Diary
2
+ class Page < Item
3
+ def initialize(title, path = "")
4
+ super(title, path)
5
+ end
6
+
7
+ private
8
+
9
+ def self.base_directory
10
+ 'pages'
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,17 @@
1
+ module Diary
2
+ class Post < Item
3
+ def initialize(title, date_or_path = Date.today)
4
+ super(title, date_or_path.to_s.split('-').join('/'))
5
+ end
6
+
7
+ def date
8
+ @date ||= Date.parse(@dir_path)
9
+ end
10
+
11
+ private
12
+
13
+ def self.base_directory
14
+ 'posts'
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,55 @@
1
+ module Diary
2
+ class Site
3
+ include Message
4
+
5
+ def initialize(options = {})
6
+ # Create directories
7
+ create_dir 'templates'
8
+ create_dir 'drafts'
9
+ create_dir 'posts'
10
+ create_dir 'pages'
11
+ create_dir 'assets'
12
+
13
+ # Create files
14
+ create_file 'templates/index.html', '{{ yield }}'
15
+ end
16
+
17
+ def self.compile(force = false)
18
+ unless (Post.all.size == 0) and (Page.all.size == 0)
19
+ Post.compile(force)
20
+ Page.compile(force)
21
+ return self
22
+ else
23
+ puts "#{Error} Nothing to compile"
24
+ end
25
+ end
26
+
27
+ def self.sync
28
+ # TODO use rsync to sync over ftp
29
+ end
30
+
31
+ private
32
+
33
+ def create_dir(path)
34
+ unless File.exists?(path)
35
+ FileUtils.mkdir_p(path)
36
+
37
+ puts "#{Created} #{path}"
38
+ else
39
+ puts "#{Exist} #{path}"
40
+ end
41
+ end
42
+
43
+ def create_file(path, content)
44
+ unless File.exists?(path)
45
+ f = File.new(path, "w+")
46
+ f.puts(content)
47
+ f.close
48
+
49
+ puts "#{Created} #{path}"
50
+ else
51
+ puts "#{Exist} #{path}"
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,35 @@
1
+ module Diary
2
+ class Template
3
+ attr_reader :path
4
+
5
+ def initialize(path)
6
+ @path = path
7
+ end
8
+
9
+ def file
10
+ File.new(@path)
11
+ end
12
+
13
+ def self.all
14
+ Dir[File.join("templates", "*.html")].map { |t| Template.new(t) }
15
+ end
16
+
17
+ def self.lookup(page_or_post, template_name = nil)
18
+ Template.new resolve_path(page_or_post, template_name)
19
+ end
20
+
21
+ private
22
+
23
+ def self.resolve_path(page_or_post, template_name)
24
+ if template_name and File.exists?("templates/#{template_name}.html")
25
+ "templates/#{template_name}.html"
26
+ elsif File.exists?("templates/#{page_or_post.slug}.html")
27
+ "templates/#{page_or_post.slug}.html"
28
+ elsif File.exists?("templates/#{page_or_post.class_name.downcase}.html")
29
+ "templates/#{page_or_post.class_name.downcase}.html"
30
+ else
31
+ 'templates/index.html'
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,10 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'shoulda'
4
+
5
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
6
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
7
+ require 'diary'
8
+
9
+ class Test::Unit::TestCase
10
+ end
@@ -0,0 +1,7 @@
1
+ require 'helper'
2
+
3
+ class TestDiary < Test::Unit::TestCase
4
+ should "probably rename this file and start testing for real" do
5
+ flunk "hey buddy, you should probably rename this file and start testing for real"
6
+ end
7
+ end
metadata ADDED
@@ -0,0 +1,107 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: diary
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ - 1
9
+ version: 0.1.1
10
+ platform: ruby
11
+ authors:
12
+ - Robin Clart
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-06-28 00:00:00 +02:00
18
+ default_executable: diary
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: liquid
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 2
29
+ - 0
30
+ - 0
31
+ version: 2.0.0
32
+ type: :runtime
33
+ version_requirements: *id001
34
+ - !ruby/object:Gem::Dependency
35
+ name: bluecloth
36
+ prerelease: false
37
+ requirement: &id002 !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ segments:
42
+ - 2
43
+ - 0
44
+ - 7
45
+ version: 2.0.7
46
+ type: :runtime
47
+ version_requirements: *id002
48
+ description:
49
+ email: robin@clart.me
50
+ executables:
51
+ - diary
52
+ extensions: []
53
+
54
+ extra_rdoc_files:
55
+ - LICENSE
56
+ - README.rdoc
57
+ files:
58
+ - .gitignore
59
+ - LICENSE
60
+ - README.rdoc
61
+ - Rakefile
62
+ - VERSION
63
+ - bin/diary
64
+ - diary.gemspec
65
+ - lib/diary.rb
66
+ - lib/diary/cli.rb
67
+ - lib/diary/draft.rb
68
+ - lib/diary/item.rb
69
+ - lib/diary/page.rb
70
+ - lib/diary/post.rb
71
+ - lib/diary/site.rb
72
+ - lib/diary/template.rb
73
+ - test/helper.rb
74
+ - test/test_diary.rb
75
+ has_rdoc: true
76
+ homepage: http://github.com/robinclart/diary
77
+ licenses: []
78
+
79
+ post_install_message:
80
+ rdoc_options:
81
+ - --charset=UTF-8
82
+ require_paths:
83
+ - lib
84
+ required_ruby_version: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ segments:
89
+ - 0
90
+ version: "0"
91
+ required_rubygems_version: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ segments:
96
+ - 0
97
+ version: "0"
98
+ requirements: []
99
+
100
+ rubyforge_project:
101
+ rubygems_version: 1.3.6
102
+ signing_key:
103
+ specification_version: 3
104
+ summary: Dead Simple, Static Blog Generator
105
+ test_files:
106
+ - test/helper.rb
107
+ - test/test_diary.rb