CarmineContraption 0.0.5 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -1,3 +1,7 @@
1
1
  *.html
2
2
  *.yaml
3
+ .bundle
4
+ Gemfile.lock
5
+ pkg
6
+ lib/photo_upload.rb
3
7
 
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,7 @@
1
+ Copyright (c) 2012 Casey Robinson (kc@rampantmonkey.com)
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
+
5
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
+
7
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,16 @@
1
+ require 'pathname'
2
+ require 'colorize'
3
+
4
+ task default: [:test]
5
+
6
+ task :test do
7
+ Pathname.glob("test/test_*.rb") do |path|
8
+ puts "\nExecuting #{path.basename.to_s.magenta}"
9
+ ruby path
10
+ end
11
+ end
12
+
13
+ task :build_gem do
14
+ system "gem build carmine_contraption.gemspec"
15
+ system "mv *.gem pkg/"
16
+ end
data/Readme.md ADDED
@@ -0,0 +1,90 @@
1
+ Carmine Contraption is an engine for managing static web content specifically targeted at blogging.
2
+
3
+ ## Defintion
4
+ __Contraption__ - *Informal, often facetious or derogatory a device or contrivance, esp one considered strange, unnecessarily intricate, or improvised*
5
+
6
+ ## Warning
7
+ Carmine Contraption, as the name implies, is unfriendly and unsuitable for users uncomfortable with [Ruby](http://www.ruby-lang.org/en/) and [Git](http://git-scm.com).
8
+
9
+ Despite being used to manage [rampantmonkey.com](http://rampantmonkey.com) for a long time many features are missing and bugs run rampant through the code.
10
+
11
+ ## Then why publish it?
12
+ I created Carmine Contraption as a learning experience to explore many of the unique features Ruby provides. This project provides examples of metaprogramming, design patterns, testing, and many more. The small code size allows exploration of these features while maintaining a detailed view of the entire system.
13
+
14
+ ## Getting Started
15
+ Currently, Carmine Contraption requires ssh access to a web server and a Git repository for the site's content. First let's take a look at the folder structures that Carmine Contraption works with.
16
+
17
+ ### Content Folder Structure
18
+ This is the tree that you write in. More specifically, the drafts folder. `content` is known as `source` within the bowels of Carmine Contraption.
19
+
20
+ content
21
+ |
22
+ |-- drafts
23
+ | |
24
+ | |-- first_draft.html
25
+ | |
26
+ | |-- another_draft.md
27
+ |
28
+ |-- posts
29
+ |
30
+ |-- 20120721-on-metaprogramming.html
31
+ |
32
+ |-- 20120801-example-post.md
33
+
34
+ ### Server Folder Structure
35
+ This layout is the living, breathing incarnation of your content. `www` is known as `destination` to Carmine Contraption. I have only listed the directories that Carmine Contraption will generate and modify. Other useful directories you may consider including are `css` and `js`.
36
+
37
+ www
38
+ |
39
+ |-- 2012
40
+ | |-- index.html
41
+ | |
42
+ | |-- 07
43
+ | | |-- index.html
44
+ | | |
45
+ | | |-- on-metaprogramming.html
46
+ | |
47
+ | |-- 08
48
+ | |-- example-post.html
49
+ |
50
+ |-- index.html
51
+ |
52
+ |-- rss.xml
53
+ |
54
+ |-- tags
55
+ |-- Apple
56
+ |-- Vim
57
+
58
+ ### Basic Program Flow
59
+ When Carmine Contraption is started up it looks in the drafts folder for any post that is ready to publish (see the Post Format section for details). A post that is ready to publish will then be timestamped and moved to the posts folder. These changes are then committed to the git content repo and pushed to the remote server. After the `new post check` is completed Carmine Contraption moves into update mode.
60
+
61
+ In update mode, all of the posts are read and sorted. Carmine Contraption then goes through and fills out templates with the relevant content. Current templates include: landing page, recent posts, individual posts, date ranges (yearly and monthly) posts, posts with the same tag, and rss feeds for the whole site as well as each tag. Refining the template system is a high priority for improving Carmine Contraption.
62
+
63
+ Once all of the templates are filled out Carmine Contraption shuts down.
64
+
65
+ ### Post Format
66
+ Posts follow a specific, yet flexible, file format. Posts are plain text files with a header section.
67
+
68
+ This is a Title
69
+ Type: Article
70
+ Tags: test, Ruby
71
+ Summary: Testing...
72
+
73
+ <p>Content goes here. Both HTML and Markdown are supported</p>
74
+
75
+ The header tags can be placed in any order. Once Carmine Contraption encounters a blank (only whitespace) line the rest of the file is considered the post's content.
76
+
77
+ To mark a post as ready to publish add `publish-now` as a line anywhere in the file. This line will be replaced with the Publication timestamp.
78
+
79
+ ## Contributing
80
+ ### Build Status
81
+ All statuses provided by [Gitlab CI](https://github.com/gitlabhq/gitlab-ci).
82
+
83
+ - Master &rarr; ![master](http://ci.rampantmonkey.com/projects/1/status?ref=master)
84
+ - Dev &rarr; ![dev](http://ci.rampantmonkey.com/projects/1/status?ref=dev)
85
+ - Testing &rarr; ![testing](http://ci.rampantmonkey.com/projects/1/status?ref=testing)
86
+
87
+ ## License
88
+ Carmine Contraption is licensed under [The MIT License](http://opensource.org/licenses/MIT).
89
+
90
+ In other words: Do whatever you feel like.
@@ -0,0 +1,26 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "carmine_contraption/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "CarmineContraption"
7
+ s.version = CarmineContraption::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Casey Robinson"]
10
+ s.email = ["kc@rampantmonkey.com"]
11
+ s.homepage = ""
12
+ s.summary = "Static Website Generator"
13
+ s.description = "Longer and more detailed version of summary..."
14
+
15
+ s.rubyforge_project = "carmine_contraption"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+
22
+ s.add_development_dependency 'shoulda', '~> 3.3.2'
23
+ s.add_development_dependency 'rake', '~> 0.9.2.2'
24
+
25
+ s.add_runtime_dependency 'colorize', '~> 0.5.8'
26
+ end
@@ -1,6 +1,8 @@
1
1
  require_relative 'month_transform.rb'
2
2
  require_relative 'post'
3
+ require 'pathname'
3
4
  require 'time'
5
+ require 'erb'
4
6
 
5
7
  module CarmineContraption
6
8
  class Index
@@ -10,7 +12,7 @@ module CarmineContraption
10
12
  def initialize source, destination, template
11
13
  @source = source
12
14
  @destination = destination
13
- raise "Template not found." unless File.file?(template)
15
+ raise "Template not found." unless template.file?
14
16
  @template = template
15
17
  end
16
18
 
@@ -37,33 +39,25 @@ module CarmineContraption
37
39
 
38
40
  def find_all_posts
39
41
  @all_paths = []
40
- Dir.glob("#{@source}posts/*.html") { |path| @all_paths << path}
41
- Dir.glob("#{@source}posts/*.md") { |path| @all_paths << path}
42
+ Pathname.glob(@source+"*.html") { |path| @all_paths << path}
43
+ Pathname.glob(@source+"*.md") { |path| @all_paths << path}
42
44
  @all_posts = []
43
45
  @all_paths.sort.each do |path|
44
- extension = File.extname(path)
45
- @all_posts << Post.from_file(path, extension)
46
+ @all_posts << Post.from_file(path, path.extname)
46
47
  end
47
48
  end
48
49
 
49
- def mkdir directory
50
- `mkdir #{directory}` unless File.directory? directory
51
- end
52
-
53
- def write_file filename, content=''
54
- output = File.open(@template, 'r').read
55
- output.gsub!(/\#\{content\}/, content)
56
- File.open("#{filename}", 'w:UTF-8') {|f| f.write(output) }
50
+ def write_file file, content=''
51
+ renderer = ERB.new(@template.read)
52
+ file.open('w:UTF-8') { |f| f.write renderer.result(binding) }
57
53
  end
58
54
 
59
55
  def write_individual_posts
60
56
  @all_posts.each do |the_post|
61
- path = "#{@destination}#{the_post.year}"
62
- mkdir path
63
- path += "/#{the_post.month}"
64
- mkdir path
65
- path += "/#{the_post.guid}.html"
66
- write_file path, the_post.formatted_output unless File.exists? path
57
+ path = @destination + the_post.year + the_post.month
58
+ path.mkpath
59
+ path += "#{the_post.guid}.html"
60
+ write_file path, the_post.formatted_output unless path.exist?
67
61
  end
68
62
  end
69
63
 
@@ -77,16 +71,16 @@ module CarmineContraption
77
71
  content << %Q{<a href="/#{k[0..3]}/#{k[4..5]}/" class="nohover">#{month_alpha_long k[4..5]} #{k[0..3]}</a>\n}
78
72
  end
79
73
  content << %Q{</section>\n</section>\n}
80
- write_file "#{@destination}recent.html", content
74
+ write_file @destination + "recent.html", content
81
75
  end
82
76
 
83
77
  def write_monthly_archives
84
78
  @monthly_archives.keys.each do |k|
85
- mkdir "#{@destination}#{k[0..3]}"
86
- mkdir "#{@destination}#{k[0..3]}/#{k[4..5]}"
79
+ path = @destination + k[0..3] + k[4..5]
80
+ path.mkpath
87
81
  content = "<h1 class=\"archive\">ARCHIVE FOR '<emph>#{(month_alpha_long k[4..5]).upcase} #{k[0..3]}</emph>'</h1>\n<hr class=\"subtleSep\" />"
88
82
  @monthly_archives[k].each { |the_post| content << the_post.formatted_output }
89
- write_file "#{@destination}#{k[0..3]}/#{k[4..5]}/index.html", content
83
+ write_file path+"index.html", content
90
84
  end
91
85
  end
92
86
 
@@ -94,31 +88,35 @@ module CarmineContraption
94
88
  content = %Q(<?xml version="1.0" encoding="utf-8" ?>\n<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom">\n<channel>\n<title>Rampant Monkey</title>\n<link>http://rampantmonkey.com</link>\n<description>Rampant Monkey - Kitchen Sink</description>\n<language>en-us</language>\n<atom:link href="http://rampantmonkey.com/rss.xml" rel="self" type="application/rss+xml" /><lastBuildDate>#{Time.now.strftime("%a, %d %b %Y %H:%M:%S %Z")}</lastBuildDate>\n)
95
89
  @all_posts.reverse.each { |the_post| content += the_post.formatted_output 'rss' }
96
90
  content += %Q(</channel>\n</rss>)
97
- File.open("#{@destination}rss.xml", 'w:UTF-8') {|f| f.write(content) }
98
- mkdir "#{@destination}/rss"
91
+ feed_path = @destination + "rss.xml"
92
+ feed_path.open('w:UTF-8') { |f| f.write(content) }
93
+ rss_base_path = @destination+"rss"
94
+ rss_base_path.mkpath
99
95
  @tag_archives.keys.each do |k|
100
96
  content = %Q(<?xml version="1.0" encoding="utf-8" ?>\n<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom">\n<channel>\n<title>Rampant Monkey</title>\n<link>http://rampantmonkey.com</link>\n<description>Rampant Monkey - #{k}</description>\n<language>en-us</language>\n<atom:link href="http://rampantmonkey.com/rss/#{k}.xml" rel="self" type="application/rss+xml" /><lastBuildDate>#{Time.now.strftime("%a, %d %b %Y %H:%M:%S %Z")}</lastBuildDate>\n)
101
97
  @tag_archives[k].reverse.each { |the_post| content += the_post.formatted_output 'rss' }
102
98
  content += %Q(</channel>\n</rss>)
103
- File.open("#{@destination}rss/#{k}.xml", 'w:UTF-8') {|f| f.write(content) }
99
+ (rss_base_path + "#{k}.xml").open('w:UTF-8') { |f| f.write(content) }
104
100
  end
105
101
  end
106
102
 
107
103
  def write_tag_archives
108
- mkdir "#{@destination}/tags"
104
+ path = @destination + "tags"
105
+ path.mkpath
109
106
  @tag_archives.keys.each do |k|
110
107
  content = "<h1 class=\"archive\">ARCHIVE FOR '<emph>#{k.upcase.gsub('_', ' ')}</emph>' CATEGORY</h1>\n<hr class=\"subtleSep\" />"
111
108
  @tag_archives[k].reverse.each { |the_post| content << the_post.formatted_output }
112
- write_file "#{@destination}tags/#{k.gsub(' ', '_').downcase}.html", content
109
+ write_file path + "#{k.gsub(' ', '_').downcase}.html", content
113
110
  end
114
111
  end
115
112
 
116
113
  def write_yearly_archives
117
114
  @yearly_archives.keys.each do |k|
118
- mkdir "#{@destination}#{k}"
115
+ path = @destination + k
116
+ path.mkpath
119
117
  content = "<h1 class=\"archive\">ARCHIVE FOR '<emph>#{k}</emph>'</h1>\n<hr class=\"subtleSep\" />"
120
118
  @yearly_archives[k].each { |the_post| content << the_post.formatted_output }
121
- write_file "#{@destination}#{k}/index.html", content
119
+ write_file path+"index.html", content
122
120
  end
123
121
  end
124
122
  end
@@ -1,13 +1,14 @@
1
1
  require 'optparse'
2
2
  require 'yaml'
3
+ require 'pathname'
3
4
 
4
5
  module CarmineContraption
5
6
  class Options
6
7
 
7
- DEFAULT_SOURCE = "/srv/www/rampantmonkey.com/content/"
8
- DEFAULT_DESTINATION = "/srv/www/rampantmonkey.com/public_html/"
8
+ DEFAULT_SOURCE = Pathname.new("/srv/www/rampantmonkey.com/content/")
9
+ DEFAULT_DESTINATION = Pathname.new("/srv/www/rampantmonkey.com/public_html/")
9
10
 
10
- DEFAULT_CONFIG_FILE = "#{Dir.home}/.carmine_contraption.yaml"
11
+ DEFAULT_CONFIG_FILE = Pathname.new("~/.carmine_contraption.yaml").expand_path
11
12
 
12
13
  attr_reader :build_targets
13
14
 
@@ -17,16 +18,11 @@ module CarmineContraption
17
18
  new_post_check: true,
18
19
  update_repository: true
19
20
  }
20
- @config.merge!(YAML.load_file(DEFAULT_CONFIG_FILE)) if File.exists? DEFAULT_CONFIG_FILE
21
+ @config.merge!(YAML.load_file(DEFAULT_CONFIG_FILE)) if DEFAULT_CONFIG_FILE.file?
22
+ @config.each_pair { |k, v| @config[k] = Pathname.new(v) if v.class == String }
21
23
  @build_targets = Hash.new(false)
22
24
  @build_targets[:individual] = true
23
25
  parse(argv)
24
- @config[:source] += "/" unless ends_with_slash? @config[:source]
25
- @config[:destination] += "/" unless ends_with_slash? @config[:destination]
26
- end
27
-
28
- def ends_with_slash? s
29
- s[-1] == "/"
30
26
  end
31
27
 
32
28
  def method_missing(m, *args, &block)
@@ -50,11 +46,10 @@ module CarmineContraption
50
46
  @build_targets[:individual] = true
51
47
  end
52
48
  opts.on("-d", "--destination path", String, "Path to destination") do |path|
53
- path += "/" unless path[-1] == "/"
54
- @config[:destination] = path
49
+ @config[:destination] = Pathname.new(path).expand_path
55
50
  end
56
51
  opts.on("--generate-config-file", "Create YAML file containing configuration options") do
57
- File.open("#{Dir.home}/.engine.yaml", 'w+') {|f| f.write(@config.to_yaml) }
52
+ DEFAULT_CONFIG_FILE.open('w+') {|f| f.write(@config.to_yaml) }
58
53
  exit
59
54
  end
60
55
  opts.on("-h", "--help", "Show this message") do
@@ -74,8 +69,7 @@ module CarmineContraption
74
69
  @build_targets[:rss] = true
75
70
  end
76
71
  opts.on("-s", "--source path", String, "Path to source files") do |path|
77
- path += "/" unless path[-1] == "/"
78
- @config[:source] = path
72
+ @config[:source] = Pathname.new(path).expand_path
79
73
  end
80
74
  opts.on("--skip-new-post-check", "Do not check for new posts") do
81
75
  @config[:new_post_check] = false
@@ -13,55 +13,72 @@ module CarmineContraption
13
13
  def self.from_file path, extension=".html"
14
14
  guid = File.basename(path, extension)
15
15
  guid = guid[9..-1]
16
- new_post = CarmineContraption::Post.new '', '', '', '', '', '', '', '', []
17
- header_complete = false
18
- content = ''
19
- counter = 0
20
- File.open(path, "r:UTF-8").each do |line|
21
- counter += 1
22
- if header_complete
23
- content += line
24
- next
25
- end
16
+ a = IO.readlines(path)
17
+ new_post = extract_header a
18
+ new_post.content = translate_markdown new_post.content if extension == ".md"
19
+ new_post.guid = guid
20
+ new_post
21
+ end
22
+
23
+ def self.extract_header raw_content
24
+ raw_content = raw_content.split('\n') if raw_content.class == String
25
+ new_post = CarmineContraption::Post.new nil, '', '', '', '', '', '', '', []
26
+ raw_content.each_with_index do |line, i|
26
27
  if line =~ /^\s/
27
- header_complete = true
28
- next
28
+ new_post.content = raw_content[(i+1)..-1].join("\n")
29
+ break
29
30
  end
30
31
  l = line.split ': '
31
32
  if l.length == 1
32
- new_post.title = l[0] unless line =~ /^=+/
33
+ new_post.title ||= ignore_separator l[0]
33
34
  else
34
35
  case l[0].downcase
35
36
  when /type/
36
37
  new_post.type = l[1]
37
38
  when /published/
38
- if l[1] =~ /^\D/
39
- published = l[1].split(' ')
40
- tmp = []
41
- tmp[0] = "#{published[3]}-#{month_arabic published[2]}-#{published[1]}"
42
- tmp[1] = published[4]
43
- tmp[2] = '-0400'
44
- tmp[2] = '-0500' if published[-1] == 'EST'
45
- new_post.published = tmp.join(' ')
46
- else
47
- new_post.published = l[1]
48
- end
39
+ new_post.published = convert_date l[1]
49
40
  when /tags/
50
- tags = l[1].chomp.downcase.split(', ')
51
- new_post.tags = tags
41
+ new_post.tags = parse_tags l[1]
52
42
  when /extra/
53
- new_post.extra = l[1..-1].join
43
+ new_post.extra = rejoin_string l
54
44
  when /summary/
55
- new_post.summary = l[1..-1].join
45
+ new_post.summary = rejoin_string l
56
46
  end
57
47
  end
58
48
  end
59
- content = `echo "#{content}" | bin/markdown.pl` if extension == ".md"
60
- new_post.content = content
61
- new_post.guid = guid
62
49
  new_post
63
50
  end
64
51
 
52
+ def self.ignore_separator line
53
+ line unless line =~ /^=+/
54
+ end
55
+
56
+ def self.convert_date date
57
+ if date =~ /^\D/
58
+ published = date.split(' ')
59
+ tmp = []
60
+ tmp[0] = "#{published[3]}-#{month_arabic published[2]}-#{published[1]}"
61
+ tmp[1] = published[4]
62
+ tmp[2] = '-0400'
63
+ tmp[2] = '-0500' if published[-1] == 'EST'
64
+ tmp.join(' ')
65
+ else
66
+ date
67
+ end
68
+ end
69
+
70
+ def self.parse_tags unparsed
71
+ unparsed.chomp.downcase.split(', ')
72
+ end
73
+
74
+ def self.rejoin_string array
75
+ array[1..-1].join ': '
76
+ end
77
+
78
+ def self.translate_markdown content
79
+ `echo "#{content}" | bin/markdown.pl`
80
+ end
81
+
65
82
  def initialize(title, content, extra, guid, summary, published, status, type, tags)
66
83
  @title = title
67
84
  @content = content
@@ -1,5 +1,6 @@
1
1
  require_relative 'options'
2
2
  require_relative 'index'
3
+ require 'pathname'
3
4
 
4
5
  module CarmineContraption
5
6
  class Runner
@@ -7,18 +8,17 @@ module CarmineContraption
7
8
  @options = Options.new(argv)
8
9
  @source = @options.source
9
10
  @destination = @options.destination
10
- @template = 'lib/templates/default.html'
11
+ @template = Pathname.new('lib/templates/default.html.erb')
11
12
  @input_extensions = [".md", ".html"]
13
+ @drafts_path = @source + 'drafts'
14
+ @posts_path = @source + 'posts'
12
15
  end
13
16
 
14
17
  def check_for_new_posts
15
- drafts_path = @source + '/drafts/'
16
- posts_path = @source + '/posts/'
17
-
18
18
  @input_extensions.each do |input_extension|
19
- Dir.glob(drafts_path + '*' + input_extension) do |i|
19
+ Pathname.glob(@drafts_path + "*#{input_extension}") do |i|
20
20
  post = ''
21
- posted_filename = File.basename(i, input_extension)
21
+ posted_filename = i.basename
22
22
  move_completed_draft = false
23
23
  File.foreach(i) do |line|
24
24
  if line.downcase =~ /publish-now/
@@ -31,7 +31,7 @@ module CarmineContraption
31
31
  end
32
32
  end
33
33
  if move_completed_draft
34
- File.open(posts_path+posted_filename, 'w') {|f| f.write(post)}
34
+ (@posts_path+posted_filename).open('w') {|f| f.write(post)}
35
35
  `rm #{i}`
36
36
  `lib/update_repo.sh #{@source} #{posted_filename}` if @options.update_repository
37
37
  end
@@ -42,17 +42,18 @@ module CarmineContraption
42
42
  def build_landing
43
43
  all_paths = []
44
44
  @input_extensions.each do |input_extension|
45
- Dir.glob("#{@source}posts/*#{input_extension}") { | path | all_paths << path }
45
+ Pathname.glob(@posts_path + "*#{input_extension}") { | path | all_paths << path }
46
46
  end
47
47
  most_recent = all_paths.sort.last
48
- most_recent_extension = most_recent.split(".")[-1]
48
+ most_recent_extension = most_recent.extname
49
49
  the_post = Post.from_file(most_recent, ".#{most_recent_extension}")
50
- output = File.open('lib/templates/landing_page.html', 'r').read
50
+ landing_template = Pathname.new('lib/templates/landing_page.html')
51
+ output = landing_template.open('r').read
51
52
  output.gsub!(/\#\{title\}/, the_post.title)
52
53
  output.gsub!(/\#\{summary\}/, the_post.summary)
53
54
  link = "#{the_post.year}/#{the_post.month}/#{the_post.guid}.html"
54
55
  output.gsub!(/\#\{link\}/, link)
55
- File.open("#{@destination}index.html", 'w:UTF-8') {|f| f.write(output) }
56
+ (@destination + "index.html").open('w:UTF-8') {|f| f.write(output) }
56
57
  end
57
58
 
58
59
  def build_monthly
@@ -88,7 +89,7 @@ module CarmineContraption
88
89
  def run
89
90
  check_for_new_posts if @options.new_post_check
90
91
  if @options.build_targets.has_value?(true)
91
- @the_index = Index.new @source, @destination, @template
92
+ @the_index = Index.new @posts_path, @destination, @template
92
93
  @the_index.find_all_posts
93
94
  @options.build_targets.each { |k, v| send "build_#{k}" if v }
94
95
  end
@@ -0,0 +1,3 @@
1
+ module CarmineContraption
2
+ VERSION = '0.0.6'
3
+ end
@@ -38,7 +38,7 @@
38
38
  </div>
39
39
  </section>
40
40
  <section class="scaffold">
41
- #{content}
41
+ <%= content %>
42
42
  </section>
43
43
 
44
44
  <section class="grid2 group" id="right">
@@ -0,0 +1,6 @@
1
+ require 'test/unit'
2
+ require 'shoulda'
3
+ require_relative '../lib/carmine_contraption/index'
4
+
5
+ class TestIndex < Test::Unit::TestCase
6
+ end
data/test/test_options.rb CHANGED
@@ -1,11 +1,17 @@
1
1
  require 'test/unit'
2
2
  require 'shoulda'
3
- require_relative '../lib/engine/options'
3
+ require 'pathname'
4
+ require_relative '../lib/carmine_contraption/options'
4
5
 
5
6
  class TestOptions < Test::Unit::TestCase
7
+
8
+ def path_expander string
9
+ Pathname.new(string).expand_path
10
+ end
11
+
6
12
  context "specifying nothing" do
7
13
  setup do
8
- @block = lambda { Engine::Options.new([]) }
14
+ @block = lambda { CarmineContraption::Options.new([]) }
9
15
  end
10
16
 
11
17
  should "throw SystemExit exception" do
@@ -15,148 +21,130 @@ class TestOptions < Test::Unit::TestCase
15
21
 
16
22
  context "specifying a source" do
17
23
  should "return it unchanged" do
18
- opts = Engine::Options.new(["-s", "TheSource/"])
19
- assert_equal "TheSource/", opts.source
20
- end
21
-
22
- should "add a trailing slash" do
23
- opts = Engine::Options.new(["-s", "TheSource"])
24
- assert_equal "TheSource/", opts.source
24
+ opts = CarmineContraption::Options.new(["-s", "TheSource"])
25
+ assert_equal path_expander("TheSource"), opts.source
25
26
  end
26
27
  end
27
28
 
28
29
  context "specifying a destination" do
29
30
  should "return it unchanged" do
30
- opts = Engine::Options.new(["-d", "TheDestination/"])
31
- assert_equal "TheDestination/", opts.destination
32
- end
33
-
34
- should "add a trailing slash" do
35
- opts = Engine::Options.new(["-d", "TheDestination"])
36
- assert_equal "TheDestination/", opts.destination
31
+ opts = CarmineContraption::Options.new(["-d", "TheDestination"])
32
+ assert_equal path_expander("TheDestination"), opts.destination
37
33
  end
38
34
  end
39
35
 
40
36
  context "specifying a source and destination" do
41
- should "return both with trailing slashes" do
42
- opts = Engine::Options.new(["-s", "TheSource", "-d", "TheDestination"])
43
- assert_equal "TheSource/", opts.source
44
- assert_equal "TheDestination/", opts.destination
45
- end
46
-
47
- should "return both unchanged" do
48
- opts = Engine::Options.new(["-s", "TheSource/", "-d", "TheDestination/"])
49
- assert_equal "TheSource/", opts.source
50
- assert_equal "TheDestination/", opts.destination
37
+ should "return both" do
38
+ opts = CarmineContraption::Options.new(["-s", "TheSource", "-d", "TheDestination"])
39
+ assert_equal path_expander("TheSource"), opts.source
40
+ assert_equal path_expander("TheDestination"), opts.destination
51
41
  end
52
42
  end
53
43
 
54
44
  context "skip new post check" do
55
45
  should "return default value" do
56
- opts = Engine::Options.new(["-s", "TheSource"])
46
+ opts = CarmineContraption::Options.new(["-s", "TheSource"])
57
47
  assert_equal true, opts.new_post_check
58
48
  end
59
49
 
60
50
  should "disable new post checking" do
61
- opts = Engine::Options.new(["--skip-new-post-check"])
51
+ opts = CarmineContraption::Options.new(["--skip-new-post-check"])
62
52
  assert_equal false, opts.new_post_check
63
53
  end
64
54
  end
65
55
 
66
56
  context "build index" do
67
57
  should "return the default value" do
68
- opts = Engine::Options.new(["-s", "TheSource"])
69
- assert_equal false, opts.build_index
58
+ opts = CarmineContraption::Options.new(["-s", "TheSource"])
59
+ assert_equal false, opts.build_targets[:index]
70
60
  end
71
61
 
72
62
  should "enable build index (short)" do
73
- opts = Engine::Options.new(["-i"])
74
- assert_equal = true, opts.build_index
63
+ opts = CarmineContraption::Options.new(["-i"])
64
+ assert_equal = true, opts.build_targets[:index]
75
65
  end
76
66
 
77
67
  should "enable build index (long)" do
78
- opts = Engine::Options.new(["--build_index"])
79
- assert_equal = true, opts.build_index
68
+ opts = CarmineContraption::Options.new(["--build_index"])
69
+ assert_equal = true, opts.build_targets[:index]
80
70
  end
81
71
  end
82
72
 
83
73
  context "build monthly" do
84
74
  should "return the default value" do
85
- opts = Engine::Options.new(["-s", "TheSource"])
86
- assert_equal false, opts.build_monthly
75
+ opts = CarmineContraption::Options.new(["-s", "TheSource"])
76
+ assert_equal false, opts.build_targets[:monthly]
87
77
  end
88
78
 
89
- should "enable build index (short)" do
90
- opts = Engine::Options.new(["-m"])
91
- assert_equal = true, opts.build_monthly
79
+ should "enable build monthly (short)" do
80
+ opts = CarmineContraption::Options.new(["-m"])
81
+ assert_equal = true, opts.build_targets[:monthly]
92
82
  end
93
83
 
94
- should "enable build index (long)" do
95
- opts = Engine::Options.new(["--build_monthly"])
96
- assert_equal = true, opts.build_monthly
84
+ should "enable build monthly (long)" do
85
+ opts = CarmineContraption::Options.new(["--build_monthly"])
86
+ assert_equal = true, opts.build_targets[:monthly]
97
87
  end
98
88
  end
99
89
 
100
90
  context "build tags" do
101
91
  should "return the default value" do
102
- opts = Engine::Options.new(["-s", "TheSource"])
103
- assert_equal false, opts.build_tags
92
+ opts = CarmineContraption::Options.new(["-s", "TheSource"])
93
+ assert_equal false, opts.build_targets[:tags]
104
94
  end
105
95
 
106
- should "enable build index (short)" do
107
- opts = Engine::Options.new(["-t"])
108
- assert_equal = true, opts.build_tags
96
+ should "enable build tags (short)" do
97
+ opts = CarmineContraption::Options.new(["-t"])
98
+ assert_equal = true, opts.build_targets[:tags]
109
99
  end
110
100
 
111
- should "enable build index (long)" do
112
- opts = Engine::Options.new(["--build_tags"])
113
- assert_equal = true, opts.build_tags
101
+ should "enable build tags (long)" do
102
+ opts = CarmineContraption::Options.new(["--build_tags"])
103
+ assert_equal = true, opts.build_targets[:tags]
114
104
  end
115
105
  end
116
106
 
117
107
  context "build yearly" do
118
108
  should "return the default value" do
119
- opts = Engine::Options.new(["-s", "TheSource"])
120
- assert_equal false, opts.build_yearly
109
+ opts = CarmineContraption::Options.new(["-s", "TheSource"])
110
+ assert_equal false, opts.build_targets[:yearly]
121
111
  end
122
112
 
123
113
  should "enable build yearly (short)" do
124
- opts = Engine::Options.new(["-y"])
125
- assert_equal = true, opts.build_yearly
114
+ opts = CarmineContraption::Options.new(["-y"])
115
+ assert_equal = true, opts.build_targets[:yearly]
126
116
  end
127
117
 
128
118
  should "enable build yearly (long)" do
129
- opts = Engine::Options.new(["--build_yearly"])
130
- assert_equal = true, opts.build_yearly
119
+ opts = CarmineContraption::Options.new(["--build_yearly"])
120
+ assert_equal = true, opts.build_targets[:yearly]
131
121
  end
132
122
  end
133
123
 
134
124
  context "build everything" do
135
125
  should "return the default value" do
136
- opts = Engine::Options.new(["-s", "TheSource"])
137
- assert_equal false, opts.build_index
138
- assert_equal false, opts.build_monthly
139
- assert_equal false, opts.build_rss
140
- assert_equal false, opts.build_tags
141
- assert_equal false, opts.build_yearly
126
+ opts = CarmineContraption::Options.new(["-s", "TheSource"])
127
+ opts.build_targets.each do |k, v|
128
+ if k == :individual
129
+ assert_equal true, v, "Individual build target incorrect"
130
+ else
131
+ assert_equal false, v, "Build #{k} incorrect"
132
+ end
133
+ end
142
134
  end
143
135
 
144
136
  should "enable build everything (short)" do
145
- opts = Engine::Options.new(["-a"])
146
- assert_equal true, opts.build_index
147
- assert_equal true, opts.build_monthly
148
- assert_equal true, opts.build_rss
149
- assert_equal true, opts.build_tags
150
- assert_equal true, opts.build_yearly
137
+ opts = CarmineContraption::Options.new(["-a"])
138
+ opts.build_targets.each do |k, v|
139
+ assert_equal true, v, "Build #{k} not set"
140
+ end
151
141
  end
152
142
 
153
143
  should "enable build everything (long)" do
154
- opts = Engine::Options.new(["--build_all"])
155
- assert_equal true, opts.build_index
156
- assert_equal true, opts.build_monthly
157
- assert_equal true, opts.build_rss
158
- assert_equal true, opts.build_tags
159
- assert_equal true, opts.build_yearly
144
+ opts = CarmineContraption::Options.new(["--build_all"])
145
+ opts.build_targets.each do |k, v|
146
+ assert_equal true, v, "Build #{k} not set"
147
+ end
160
148
  end
161
149
  end
162
150
  end
data/test/test_post.rb ADDED
@@ -0,0 +1,107 @@
1
+ require 'test/unit'
2
+ require 'shoulda'
3
+ require_relative '../lib/carmine_contraption/post'
4
+
5
+ class TestPost < Test::Unit::TestCase
6
+ context "Parsing Tags" do
7
+ should "Return zero tags" do
8
+ assert_equal CarmineContraption::Post.parse_tags(""), []
9
+ end
10
+
11
+ should "Return one tag" do
12
+ assert_equal CarmineContraption::Post.parse_tags("boogers"), ["boogers"]
13
+ end
14
+
15
+ should "Return three tags" do
16
+ assert_equal CarmineContraption::Post.parse_tags("a, b, c"), ["a", "b", "c"]
17
+ end
18
+
19
+ should "Return lots of tags" do
20
+ tags = Array.new(999, "z")
21
+ assert_equal CarmineContraption::Post.parse_tags(tags.join(", ")), tags
22
+ end
23
+ end
24
+
25
+ context "Markdown" do
26
+ should "return same text" do
27
+ text = "<p></p>\n"
28
+ assert_equal text, CarmineContraption::Post.translate_markdown(text)
29
+ end
30
+
31
+ should "convert to code block" do
32
+ text = " int main(){"
33
+ assert_equal "<pre><code>int main(){\n</code></pre>\n", CarmineContraption::Post.translate_markdown(text)
34
+ end
35
+
36
+ should "convert to link" do
37
+ assert_equal %Q{<p><a href="http://rampantmonkey.com">Website</a></p>\n}, CarmineContraption::Post.translate_markdown(%q{[Website](http://rampantmonkey.com)})
38
+ end
39
+ end
40
+
41
+ context "Date Importing" do
42
+ should "return date" do
43
+ d = "2010-02-21 18:42:49 -0400"
44
+ assert_equal d, CarmineContraption::Post.convert_date(d)
45
+ end
46
+
47
+ should "return formatted date" do
48
+ assert_equal "2012-11-20 08:56:32 -0500",
49
+ CarmineContraption::Post.convert_date("Tue, 20 Nov 2012 08:56:32 EST")
50
+ end
51
+ end
52
+
53
+ context "Date Processing" do
54
+ setup do
55
+ @the_post = CarmineContraption::Post.new('', '', '', '', '', "2010-02-21 18:00:00 -0400", '', '', '')
56
+ end
57
+
58
+ should "return year" do
59
+ assert_respond_to @the_post, :year
60
+ assert_equal "2010", @the_post.year
61
+ end
62
+
63
+ should "return month" do
64
+ assert_respond_to @the_post, :month
65
+ assert_equal "02", @the_post.month
66
+ end
67
+
68
+ should "return day" do
69
+ assert_respond_to @the_post, :day
70
+ assert_equal "21", @the_post.day
71
+ end
72
+ end
73
+
74
+ context "Separator" do
75
+ should "ignore separator" do
76
+ assert_equal nil, CarmineContraption::Post.ignore_separator("=")
77
+ end
78
+
79
+ should "ignore longer separator" do
80
+ assert_equal nil, CarmineContraption::Post.ignore_separator("="*10)
81
+ end
82
+
83
+ should "not ignore valid title" do
84
+ title = "This is the Title"
85
+ assert_equal title, CarmineContraption::Post.ignore_separator(title)
86
+ end
87
+
88
+ should "not ignore empty string" do
89
+ title = ""
90
+ assert_equal title, CarmineContraption::Post.ignore_separator(title)
91
+ end
92
+ end
93
+
94
+ context "Rejoining Strings" do
95
+ should "return nothing" do
96
+ assert CarmineContraption::Post.rejoin_string(["word"]).empty?
97
+ end
98
+
99
+ should "return original word" do
100
+ assert_equal "word", CarmineContraption::Post.rejoin_string(["a", "word"])
101
+ end
102
+
103
+ should "return all but the first word" do
104
+ assert_equal "word: play", CarmineContraption::Post.rejoin_string(["a", "word", "play"])
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,6 @@
1
+ require 'test/unit'
2
+ require 'shoulda'
3
+ require_relative '../lib/carmine_contraption/runner'
4
+
5
+ class TestRunner < Test::Unit::TestCase
6
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: CarmineContraption
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.5
4
+ version: 0.0.6
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,8 +9,56 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-11-14 00:00:00.000000000 Z
13
- dependencies: []
12
+ date: 2012-12-04 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: shoulda
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 3.3.2
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: 3.3.2
30
+ - !ruby/object:Gem::Dependency
31
+ name: rake
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: 0.9.2.2
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: 0.9.2.2
46
+ - !ruby/object:Gem::Dependency
47
+ name: colorize
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: 0.5.8
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: 0.5.8
14
62
  description: Longer and more detailed version of summary...
15
63
  email:
16
64
  - kc@rampantmonkey.com
@@ -21,20 +69,29 @@ extensions: []
21
69
  extra_rdoc_files: []
22
70
  files:
23
71
  - .gitignore
72
+ - Gemfile
73
+ - LICENSE.txt
74
+ - Rakefile
75
+ - Readme.md
24
76
  - bin/carmine_contraption
25
77
  - bin/markdown.pl
78
+ - carmine_contraption.gemspec
26
79
  - lib/carmine_contraption/formatters.rb
27
80
  - lib/carmine_contraption/index.rb
28
81
  - lib/carmine_contraption/month_transform.rb
29
82
  - lib/carmine_contraption/options.rb
30
83
  - lib/carmine_contraption/post.rb
31
84
  - lib/carmine_contraption/runner.rb
85
+ - lib/carmine_contraption/version.rb
32
86
  - lib/photos.rb
33
- - lib/templates/default.html
87
+ - lib/templates/default.html.erb
34
88
  - lib/templates/landing_page.html
35
89
  - lib/templates/photo.html
36
90
  - lib/update_repo.sh
91
+ - test/test_index.rb
37
92
  - test/test_options.rb
93
+ - test/test_post.rb
94
+ - test/test_runner.rb
38
95
  homepage: ''
39
96
  licenses: []
40
97
  post_install_message:
@@ -47,12 +104,18 @@ required_ruby_version: !ruby/object:Gem::Requirement
47
104
  - - ! '>='
48
105
  - !ruby/object:Gem::Version
49
106
  version: '0'
107
+ segments:
108
+ - 0
109
+ hash: -3708087154013416350
50
110
  required_rubygems_version: !ruby/object:Gem::Requirement
51
111
  none: false
52
112
  requirements:
53
113
  - - ! '>='
54
114
  - !ruby/object:Gem::Version
55
115
  version: '0'
116
+ segments:
117
+ - 0
118
+ hash: -3708087154013416350
56
119
  requirements: []
57
120
  rubyforge_project: carmine_contraption
58
121
  rubygems_version: 1.8.23
@@ -60,4 +123,7 @@ signing_key:
60
123
  specification_version: 3
61
124
  summary: Static Website Generator
62
125
  test_files:
126
+ - test/test_index.rb
63
127
  - test/test_options.rb
128
+ - test/test_post.rb
129
+ - test/test_runner.rb