CarmineContraption 0.1.0 → 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.
@@ -1,6 +1,4 @@
1
- require_relative 'options'
2
- require_relative 'index'
3
- require_relative 'uploader'
1
+ require_relative '../carmine_contraption'
4
2
 
5
3
  require 'pathname'
6
4
  require 'colorize'
@@ -12,107 +10,109 @@ module CarmineContraption
12
10
  @source = @options.source
13
11
  @destination = @options.destination
14
12
  @override = @options.override
15
- @template = Pathname.new('lib/templates/default.html.erb')
16
13
  @input_extensions = [".md", ".html"]
17
14
  @drafts_path = @source + 'drafts'
18
15
  @posts_path = @source + 'posts'
19
16
  end
20
17
 
21
- def check_for_new_posts
22
- @input_extensions.each do |input_extension|
23
- Pathname.glob(@drafts_path + "*#{input_extension}") do |i|
24
- post = ''
25
- posted_filename = i.basename
26
- move_completed_draft = false
27
- File.foreach(i) do |line|
28
- if line.downcase =~ /publish-now/
29
- move_completed_draft = true
30
- t = Time.now
31
- post += 'Published: ' + t.strftime("%a, %d %b %Y %H:%M:%S %Z") + "\n"
32
- posted_filename = "#{t.strftime('%Y%m%d')}-#{posted_filename}"
33
- else
34
- post += line
35
- end
36
- end
37
- if move_completed_draft
38
- puts "Publishing draft: #{posted_filename}".yellow
39
- (@posts_path+posted_filename).open('w') {|f| f.write(post)}
40
- `rm #{i}`
41
- `lib/update_repo.sh #{@source} #{posted_filename}` if @options.update_repository
42
- up = Uploader.new({access_key_id: @options.s3_access_key_id,
43
- secret_access_key: @options.s3_secret_access_key},
44
- @options.s3_target_bucket)
45
- the_post = Post.from_file((@posts_path+posted_filename).to_s, input_extension)
46
- tmp = []
47
- the_post.media.each do |m|
48
- puts "Uploading #{m.name}...".green
49
- remote_name = "#{the_post.year}/#{the_post.month}/#{m.name}"
50
- up.upload (m.update remote_path: remote_name)
51
- tmp << (m.update remote_path: "http://#{@options.s3_target_bucket}/#{remote_name}")
18
+ def run
19
+ find_new_posts if @options.new_post_check
20
+ if @options.build_targets.has_value?(true)
21
+ @the_index = Index.new @source, @destination
22
+ @the_writer = Writer.new @the_index, @override
23
+ @options.build_targets.each { |k, v| send "build_#{k}" if v }
24
+ end
25
+ end
26
+
27
+ private
28
+ def find_new_posts
29
+ @input_extensions.each do |input_extension|
30
+ Pathname.glob(@drafts_path + "*#{input_extension}") do |i|
31
+ post = IO.read i
32
+ if is_draft_ready? post
33
+ post, posted_filename = timestamp_post post, i.basename
34
+ move_draft post, posted_filename, i
52
35
  end
53
- the_post = the_post.update(media: tmp)
54
- (@posts_path+posted_filename).open('w') { |f| f.write(the_post.formatted_output '') }
55
36
  end
56
37
  end
57
38
  end
58
- end
59
39
 
60
- def build_landing
61
- all_paths = []
62
- @input_extensions.each do |input_extension|
63
- Pathname.glob(@posts_path + "*#{input_extension}") { | path | all_paths << path }
40
+ def is_draft_ready? post
41
+ /^publish-now\s*$/.match post.downcase
64
42
  end
65
- most_recent = all_paths.sort.last
66
- most_recent_extension = most_recent.extname
67
- the_post = Post.from_file most_recent, most_recent_extension
68
- landing_template = Pathname.new('lib/templates/landing_page.html')
69
- output = landing_template.open('r').read
70
- output.gsub!(/\#\{title\}/, the_post.title)
71
- output.gsub!(/\#\{summary\}/, the_post.summary)
72
- link = "#{the_post.year}/#{the_post.month}/#{the_post.guid}.html"
73
- output.gsub!(/\#\{link\}/, link)
74
- (@destination + "index.html").open('w:UTF-8') {|f| f.write(output) }
75
- puts "Rendering #{@destination}index.html".blue
76
- end
77
43
 
78
- def build_monthly
79
- @the_index.build_monthly_archives
80
- @the_index.write_monthly_archives
81
- end
44
+ def timestamp_post post, filename
45
+ t = Time.now
46
+ post.gsub!(/^publish-now\s*$/, "Published: #{t.strftime "%a, %d %b %Y %H:%M:%S %Z"}\n")
47
+ posted_filename = "#{t.strftime('%Y%m%d')}-#{filename}"
48
+ return post, posted_filename
49
+ end
82
50
 
83
- def build_yearly
84
- @the_index.build_yearly_archives
85
- @the_index.write_yearly_archives
86
- end
51
+ def move_draft post, filename, draft_name
52
+ puts "Publishing draft: #{filename}".yellow
53
+ (@posts_path+filename).open('w') {|f| f.write(post)}
54
+ `rm #{draft_name}`
55
+ `lib/update_repo.sh #{@source} #{filename}` if @options.update_repository
56
+ the_post = Post.from_file((@posts_path+filename).to_s, File.extname(draft_name))
57
+ the_post = upload_media the_post
58
+ (@posts_path+filename).open('w') { |f| f.write(the_post.formatted_output Formatter.new(@source+"formats"), :raw) }
59
+ end
87
60
 
88
- def build_tag
89
- @the_index.build_tag_archives
90
- @the_index.write_tag_archives
91
- @the_index.write_tag_cloud
92
- end
61
+ def upload_media post
62
+ up = Uploader.new({access_key_id: @options.s3_access_key_id,
63
+ secret_access_key: @options.s3_secret_access_key},
64
+ @options.s3_target_bucket)
65
+ post.update(media: post.media.map do |m|
66
+ puts "Uploading #{m.name}...".green
67
+ remote_path = post.published.strftime "%Y/%m/"
68
+ up.upload (m.update remote_path: remote_path)
69
+ m.update remote_path: "http://#{@options.s3_target_bucket}/#{remote_path}"
70
+ end
71
+ )
72
+ end
93
73
 
94
- def build_individual
95
- @the_index.write_individual_posts
96
- end
74
+ def build_landing
75
+ all_paths = []
76
+ @input_extensions.each do |input_extension|
77
+ Pathname.glob(@posts_path + "*#{input_extension}") { | path | all_paths << path }
78
+ end
79
+ most_recent = all_paths.sort.last
80
+ most_recent_extension = most_recent.extname
81
+ the_post = Post.from_file most_recent, most_recent_extension
82
+ landing_template = Pathname.new('lib/templates/landing_page.html')
83
+ output = landing_template.open('r').read
84
+ output.gsub!(/\#\{title\}/, the_post.title)
85
+ output.gsub!(/\#\{summary\}/, the_post.summary)
86
+ link = "#{the_post.published.strftime "%Y/%m/"}#{the_post.guid}.html"
87
+ output.gsub!(/\#\{link\}/, link)
88
+ (@destination + "index.html").open('w:UTF-8') {|f| f.write(output) }
89
+ puts "Rendering #{@destination}index.html".blue
90
+ end
97
91
 
98
- def build_index
99
- @the_index.build_yearly_archives
100
- @the_index.build_monthly_archives
101
- @the_index.write_main_page
102
- end
92
+ def build_monthly
93
+ @the_writer.write_monthly_archives
94
+ end
103
95
 
104
- def build_rss
105
- @the_index.build_tag_archives
106
- @the_index.write_rss
107
- end
96
+ def build_yearly
97
+ @the_writer.write_yearly_archives
98
+ end
108
99
 
109
- def run
110
- check_for_new_posts if @options.new_post_check
111
- if @options.build_targets.has_value?(true)
112
- @the_index = Index.new @posts_path, @destination, @template, @override
113
- @the_index.find_all_posts
114
- @options.build_targets.each { |k, v| send "build_#{k}" if v }
100
+ def build_tag
101
+ @the_writer.write_tag_archives
102
+ @the_writer.write_tag_cloud
115
103
  end
116
- end
104
+
105
+ def build_individual
106
+ @the_writer.write_individual_posts
107
+ end
108
+
109
+ def build_index
110
+ @the_writer.write_main_page
111
+ end
112
+
113
+ def build_rss
114
+ @the_writer.write_rss
115
+ end
116
+
117
117
  end
118
118
  end
@@ -1,3 +1,3 @@
1
1
  module CarmineContraption
2
- VERSION = '0.1.0'
2
+ VERSION = '0.1.1'
3
3
  end
@@ -0,0 +1,132 @@
1
+ require_relative '../carmine_contraption'
2
+
3
+ module CarmineContraption
4
+ class Writer
5
+ def initialize the_index, override
6
+ @index = the_index
7
+ @templater = Formatter.new(the_index.base + "templates")
8
+ @formatter = Formatter.new(the_index.base + "formats")
9
+ @override = override
10
+ end
11
+
12
+ def write_rss
13
+ puts "Updating RSS feed".blue
14
+ content = format_post_collection all_posts.reverse, :rss
15
+ feed_path = destination + "rss.xml"
16
+ write_file feed_path, content, false, :rss
17
+ end
18
+
19
+ def write_individual_posts
20
+ all_posts.each do |the_post|
21
+ path = post_path the_post
22
+ write_file path, the_post.formatted_output(@formatter) unless ( path.exist? and !@override )
23
+ end
24
+ end
25
+
26
+ def write_main_page
27
+ content = ""
28
+ content << format_post_collection(all_posts[-8..-1].reverse)
29
+ content << create_archive_links
30
+ write_file destination + "recent.html", content
31
+ end
32
+
33
+ def write_monthly_archives
34
+ monthly_archives.each_key do |k|
35
+ d = build_date_from_key k
36
+ path = destination + d.year.to_s + d.month.to_s
37
+ path.mkpath
38
+ content = format_archive_for_month d, k
39
+ write_file path+"index.html", content, true
40
+ end
41
+ end
42
+
43
+ def write_tag_archives
44
+ path = destination + "tags"
45
+ path.mkpath
46
+ tag_archives.keys.each { |k| write_tag_archive k, path }
47
+ write_tag_feeds
48
+ end
49
+
50
+ def write_yearly_archives
51
+ yearly_archives.keys.each do |k|
52
+ path = destination + k
53
+ path.mkpath
54
+ content = archive_heading "ARCHIVE FOR '<emph>#{k}</emph>'"
55
+ content << format_post_collection(yearly_archives[k])
56
+ write_file path+"index.html", content, true
57
+ end
58
+ end
59
+
60
+ def write_tag_cloud
61
+ path = destination + "tags" + "index.html"
62
+ content = archive_heading "TAG_CLOUD"
63
+ content += "<section class=\"tag_cloud \">\n"
64
+ max = longest_tag
65
+ tag_archives.sort_by{|k,v| k}.each do |k, v|
66
+ content << scale_tag(k, v.length, max)
67
+ end
68
+ content += "</section>\n"
69
+ write_file path, content
70
+ end
71
+
72
+ private
73
+ def method_missing method, *args, &block
74
+ return @index.send method, *args, &block if @index.respond_to? method
75
+ super
76
+ end
77
+
78
+ def post_path the_post
79
+ path = destination + the_post.published.strftime("%Y") + the_post.published.strftime("%m")
80
+ path.mkpath
81
+ path += "#{the_post.guid}.html"
82
+ end
83
+
84
+ def format_post_collection posts, formatting_method=nil
85
+ posts.inject("") { |c, post| c << post.formatted_output(@formatter, formatting_method) }
86
+ end
87
+
88
+ def scale_tag k, tag_length, max
89
+ size = (1+tag_length.to_f/max) * 0.8
90
+ %Q{<span style="font-size: #{size}em;"><a href="tags/#{k.gsub(' ', '_').downcase}.html">#{k.gsub('_', ' ')}</a></span>\n}
91
+ end
92
+
93
+ def write_tag_archive k, path
94
+ content = archive_heading "ARCHIVE FOR '<emph>#{k.upcase.gsub '_', ' ' }</emph>'"
95
+ content << format_post_collection(tag_archives[k].reverse)
96
+ write_file path + "#{k.gsub(' ', '_').downcase}.html", content, true
97
+ end
98
+
99
+ def write_file file, content='', supress_message=false, method=:default
100
+ puts "Rendering #{file}".blue unless supress_message
101
+ file.open('w:UTF-8') { |f| f.write @templater.format(content, method) }
102
+ end
103
+
104
+ def write_tag_feeds
105
+ rss_base_path = destination+"rss"
106
+ rss_base_path.mkpath
107
+ tag_archives.keys.each do |k|
108
+ content = format_post_collection tag_archives[k].reverse, :rss
109
+ write_file (rss_base_path + "#{k}.xml"), content, true, :rss
110
+ end
111
+ end
112
+
113
+ def create_archive_links
114
+ content = %Q{<section class="archive_title">\n<h2>Archives</h2>\n<section class="archives">\n}
115
+ content << monthly_archives.keys.reverse.map do |k|
116
+ d = build_date_from_key k
117
+ %Q{<a href="/#{d.year}/#{d.month}/" class="nohover">#{d.strftime "%b"} #{d.year}</a>\n}
118
+ end .join("\n")
119
+ content << %Q{</section>\n</section>\n}
120
+ end
121
+
122
+
123
+ def format_archive_for_month m, k
124
+ content = archive_heading "ARCHIVE FOR '<emph>#{m.strftime "%^b"} #{m.year}</emph>'"
125
+ content << format_post_collection(monthly_archives[k])
126
+ end
127
+
128
+ def archive_heading text
129
+ "<h1 class=\"archive\">#{text}</h1>\n<hr class=\"subtleSep\" />\n"
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,8 @@
1
+ <%= context.title %>
2
+ <%= "="*context.title.length %>
3
+ Type: <%= context.type %>
4
+ Published: <%= context.published %>
5
+ Tags: <%= context.tags.join ', ' %>
6
+ Summary: <%= context.summary %>
7
+
8
+ <%= context.content %>
@@ -0,0 +1,19 @@
1
+ require_relative '../../test_helper'
2
+
3
+ module CarmineContraption
4
+ class TestError < Test::Unit::TestCase
5
+ context "Error Hierarchy" do
6
+ should "be subclasssed from standard error" do
7
+ assert Error.ancestors.include? StandardError
8
+ end
9
+
10
+ should "be namespaced" do
11
+ assert Error.name.include? "::"
12
+ end
13
+
14
+ should "have CarmineContraption namespace" do
15
+ assert_equal Error.name.to_s.split("::").first, "CarmineContraption"
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,59 @@
1
+ require_relative '../../test_helper'
2
+
3
+ module CarmineContraption
4
+ class TestFormatter < Test::Unit::TestCase
5
+ context "basics" do
6
+ should "exist" do
7
+ assert_not_nil Formatter.new
8
+ end
9
+
10
+ should "find formats" do
11
+ f = Formatter.new "test/data/formats"
12
+ f.formats.each do |t|
13
+ assert [:raw].include?(t), "#{t} not expected"
14
+ end
15
+ assert_equal 1, f.formats.size
16
+ end
17
+ end
18
+
19
+ context "format method" do
20
+ setup do
21
+ @f = Formatter.new "test/data/formats"
22
+ path = 'test/data/posts/20121209-test.md'
23
+ @post = Post.from_file(path)
24
+ @post_content = IO.read(path)
25
+ end
26
+
27
+ should "raise error about missing format" do
28
+ assert_raise MissingFormat do
29
+ @f.format @post, :a
30
+ end
31
+ end
32
+
33
+ should "not raise error when given valid format" do
34
+ assert_nothing_raised MissingFormat do
35
+ @f.format @post, :raw
36
+ end
37
+ end
38
+
39
+ should "return formatted post" do
40
+ expected = "Testing... Testing...\n\n"
41
+ expected << "======================\n"
42
+ expected << "Type: Article\n\n"
43
+ expected << "Published: 2012-12-09T19:37:58-05:00\n"
44
+ expected << "Tags: test\n"
45
+ expected << "Summary: Testing.\n\n\n"
46
+ expected << "Testing whether the markdown support works.\n\n\n\n"
47
+ expected << "Code sample\n\n"
48
+ expected << " #include<iostream>\n\n\n\n"
49
+ expected << " int main(){\n\n"
50
+ expected << " std::cout << \"Hello World.\\n\";\n\n"
51
+ expected << " return 0;\n\n"
52
+ expected << " }\n\n\n\n"
53
+ expected << "Some __bold text__.\n\n"
54
+ assert_equal expected, @f.format(@post, :raw)
55
+ end
56
+ end
57
+
58
+ end
59
+ end
@@ -0,0 +1,4 @@
1
+ require_relative '../../test_helper'
2
+
3
+ class TestIndex < Test::Unit::TestCase
4
+ end
@@ -1,6 +1,4 @@
1
- require 'test/unit'
2
- require 'shoulda'
3
- require_relative '../lib/carmine_contraption/media'
1
+ require_relative '../../test_helper'
4
2
 
5
3
  module CarmineContraption
6
4
  class TestMedia < Test::Unit::TestCase
@@ -1,7 +1,4 @@
1
- require 'test/unit'
2
- require 'shoulda'
3
- require 'pathname'
4
- require_relative '../lib/carmine_contraption/options'
1
+ require_relative '../../test_helper'
5
2
 
6
3
  class TestOptions < Test::Unit::TestCase
7
4