baron 1.0.3 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. data/VERSION +1 -1
  2. data/baron.gemspec +32 -23
  3. data/lib/baron.rb +15 -13
  4. data/spec/baron_article_spec.rb +1 -1
  5. data/spec/baron_blog_engine_spec.rb +22 -20
  6. data/spec/baron_spec.rb +10 -22
  7. data/spec/sample_data/.gitignore +5 -0
  8. data/spec/sample_data/Gemfile +1 -1
  9. data/spec/sample_data/README.md +243 -0
  10. data/spec/sample_data/Rakefile +1 -1
  11. data/spec/sample_data/articles/favorites/1916-01-01-the-road-not-taken.txt +26 -0
  12. data/spec/sample_data/articles/north of boston/1914-01-01-the-pasture.txt +10 -0
  13. data/spec/sample_data/articles/north of boston/1914-01-02-mending-wall.txt +48 -0
  14. data/spec/sample_data/articles/north of boston/1914-01-03-the-death-of-the-hired-man.txt +211 -0
  15. data/spec/sample_data/articles/north of boston/1914-01-04-the-mountain.txt +121 -0
  16. data/spec/sample_data/articles/north of boston/1914-01-05-A-Hundred-callers.txt +196 -0
  17. data/spec/sample_data/articles/poems/1909-01-02-If.txt b/data/spec/sample_data/articles/other → authors/1909-01-02-If.txt +0 -0
  18. data/spec/sample_data/config.ru +63 -29
  19. data/spec/sample_data/images/robert-frost-small.png +0 -0
  20. data/spec/sample_data/images/robert-frost.png +0 -0
  21. data/spec/sample_data/pages/about.rhtml +9 -14
  22. data/spec/sample_data/resources/redirects.txt +1 -29
  23. data/spec/sample_data/resources/robots.txt +4 -1
  24. data/spec/sample_data/themes/typography/css/app.css +58 -0
  25. data/spec/sample_data/themes/{test → typography}/css/bootstrap-responsive.css +0 -0
  26. data/spec/sample_data/themes/{test → typography}/css/bootstrap-responsive.min.css +0 -0
  27. data/spec/sample_data/themes/{test → typography}/css/bootstrap.css +0 -0
  28. data/spec/sample_data/themes/{test → typography}/css/bootstrap.min.css +0 -0
  29. data/spec/sample_data/themes/typography/img/github.png +0 -0
  30. data/spec/sample_data/themes/{test → typography}/img/glyphicons-halflings-white.png +0 -0
  31. data/spec/sample_data/themes/{test → typography}/img/glyphicons-halflings.png +0 -0
  32. data/spec/sample_data/{images → themes/typography/img}/instagram.png +0 -0
  33. data/spec/sample_data/themes/typography/js/bootstrap.js +2159 -0
  34. data/spec/sample_data/themes/typography/js/bootstrap.min.js +6 -0
  35. data/spec/sample_data/themes/typography/js/image_alt.js +12 -0
  36. data/spec/sample_data/themes/typography/js/read_later.js +14 -0
  37. data/spec/sample_data/themes/typography/templates/archives.rhtml +18 -0
  38. data/spec/sample_data/themes/typography/templates/article.rhtml +14 -0
  39. data/spec/sample_data/themes/typography/templates/category.rhtml +17 -0
  40. data/spec/sample_data/themes/typography/templates/error.rhtml +3 -0
  41. data/spec/sample_data/themes/typography/templates/home.rhtml +28 -0
  42. data/spec/sample_data/themes/typography/templates/layout.rhtml +141 -0
  43. data/spec/spec_helper.rb +1 -1
  44. metadata +32 -23
  45. data/spec/sample_data/articles/2012-11-09-sample-post.txt +0 -11
  46. data/spec/sample_data/articles/poems/1916-01-01-the-road-not-taken.txt +0 -26
  47. data/spec/sample_data/images/import-csv-file-1.png +0 -0
  48. data/spec/sample_data/images/import-csv-file-2.png +0 -0
  49. data/spec/sample_data/images/import-csv-file-3.png +0 -0
  50. data/spec/sample_data/themes/test/css/app.css +0 -27
  51. data/spec/sample_data/themes/test/img/instagram.png +0 -0
  52. data/spec/sample_data/themes/test/templates/archives.rhtml +0 -14
  53. data/spec/sample_data/themes/test/templates/article.rhtml +0 -14
  54. data/spec/sample_data/themes/test/templates/category.rhtml +0 -15
  55. data/spec/sample_data/themes/test/templates/error.rhtml +0 -11
  56. data/spec/sample_data/themes/test/templates/home.rhtml +0 -26
  57. data/spec/sample_data/themes/test/templates/layout.rhtml +0 -90
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.0.3
1
+ 1.0.4
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "baron"
8
- s.version = "1.0.3"
8
+ s.version = "1.0.4"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Nathan Buggia"]
12
- s.date = "2013-03-13"
12
+ s.date = "2013-03-18"
13
13
  s.description = "What's in the box: (1) Publish to Heroku using Git (2) Author articles in markdown (3) Article categories (4) Multiple permalink formats supported (5) Redirects (6) Advanced SEO optimizations and Google Analytics/ Webmaster Tools support. Uses Rack, RSpec, Bootstrap, JQuery, Disqus, Thin"
14
14
  s.email = "nbuggia@gmail.com"
15
15
  s.extra_rdoc_files = [
@@ -25,34 +25,43 @@ Gem::Specification.new do |s|
25
25
  "spec/baron_article_spec.rb",
26
26
  "spec/baron_blog_engine_spec.rb",
27
27
  "spec/baron_spec.rb",
28
+ "spec/sample_data/.gitignore",
28
29
  "spec/sample_data/Gemfile",
30
+ "spec/sample_data/README.md",
29
31
  "spec/sample_data/Rakefile",
30
- "spec/sample_data/articles/2012-11-09-sample-post.txt",
31
- "spec/sample_data/articles/poems/1909-01-02-If.txt",
32
- "spec/sample_data/articles/poems/1916-01-01-the-road-not-taken.txt",
32
+ "spec/sample_data/articles/favorites/1916-01-01-the-road-not-taken.txt",
33
+ "spec/sample_data/articles/north of boston/1914-01-01-the-pasture.txt",
34
+ "spec/sample_data/articles/north of boston/1914-01-02-mending-wall.txt",
35
+ "spec/sample_data/articles/north of boston/1914-01-03-the-death-of-the-hired-man.txt",
36
+ "spec/sample_data/articles/north of boston/1914-01-04-the-mountain.txt",
37
+ "spec/sample_data/articles/north of boston/1914-01-05-A-Hundred-callers.txt",
38
+ "spec/sample_data/articles/other authors/1909-01-02-If.txt",
33
39
  "spec/sample_data/config.ru",
34
- "spec/sample_data/images/import-csv-file-1.png",
35
- "spec/sample_data/images/import-csv-file-2.png",
36
- "spec/sample_data/images/import-csv-file-3.png",
37
- "spec/sample_data/images/instagram.png",
40
+ "spec/sample_data/images/robert-frost-small.png",
41
+ "spec/sample_data/images/robert-frost.png",
38
42
  "spec/sample_data/pages/about.rhtml",
39
43
  "spec/sample_data/resources/feed.rss",
40
44
  "spec/sample_data/resources/redirects.txt",
41
45
  "spec/sample_data/resources/robots.txt",
42
- "spec/sample_data/themes/test/css/app.css",
43
- "spec/sample_data/themes/test/css/bootstrap-responsive.css",
44
- "spec/sample_data/themes/test/css/bootstrap-responsive.min.css",
45
- "spec/sample_data/themes/test/css/bootstrap.css",
46
- "spec/sample_data/themes/test/css/bootstrap.min.css",
47
- "spec/sample_data/themes/test/img/glyphicons-halflings-white.png",
48
- "spec/sample_data/themes/test/img/glyphicons-halflings.png",
49
- "spec/sample_data/themes/test/img/instagram.png",
50
- "spec/sample_data/themes/test/templates/archives.rhtml",
51
- "spec/sample_data/themes/test/templates/article.rhtml",
52
- "spec/sample_data/themes/test/templates/category.rhtml",
53
- "spec/sample_data/themes/test/templates/error.rhtml",
54
- "spec/sample_data/themes/test/templates/home.rhtml",
55
- "spec/sample_data/themes/test/templates/layout.rhtml",
46
+ "spec/sample_data/themes/typography/css/app.css",
47
+ "spec/sample_data/themes/typography/css/bootstrap-responsive.css",
48
+ "spec/sample_data/themes/typography/css/bootstrap-responsive.min.css",
49
+ "spec/sample_data/themes/typography/css/bootstrap.css",
50
+ "spec/sample_data/themes/typography/css/bootstrap.min.css",
51
+ "spec/sample_data/themes/typography/img/github.png",
52
+ "spec/sample_data/themes/typography/img/glyphicons-halflings-white.png",
53
+ "spec/sample_data/themes/typography/img/glyphicons-halflings.png",
54
+ "spec/sample_data/themes/typography/img/instagram.png",
55
+ "spec/sample_data/themes/typography/js/bootstrap.js",
56
+ "spec/sample_data/themes/typography/js/bootstrap.min.js",
57
+ "spec/sample_data/themes/typography/js/image_alt.js",
58
+ "spec/sample_data/themes/typography/js/read_later.js",
59
+ "spec/sample_data/themes/typography/templates/archives.rhtml",
60
+ "spec/sample_data/themes/typography/templates/article.rhtml",
61
+ "spec/sample_data/themes/typography/templates/category.rhtml",
62
+ "spec/sample_data/themes/typography/templates/error.rhtml",
63
+ "spec/sample_data/themes/typography/templates/home.rhtml",
64
+ "spec/sample_data/themes/typography/templates/layout.rhtml",
56
65
  "spec/spec_helper.rb"
57
66
  ]
58
67
  s.homepage = "https://github.com/nbuggia/baron-blog-engine-gem"
@@ -99,8 +99,8 @@ module Baron
99
99
  route = (path || '/').split('/').reject { |i| i.empty? }
100
100
  route << @config[:root] if route.empty?
101
101
  mime_type = (mime_type =~ /txt|rss|json/) ? mime_type.to_sym : :html
102
- categories = get_all_categories()
103
- params = {:page_name => route.first}
102
+ categories = get_all_categories
103
+ params = {:page_name => route.first, :rss_feed => get_feed_path}
104
104
  params[:page_title] = (route.first == @config[:root] ? '' : "#{route.first.capitalize} #{@config[:title_delimiter]} ") + "#{@config[:title]}"
105
105
 
106
106
  begin
@@ -112,19 +112,20 @@ module Baron
112
112
 
113
113
  # Robots... /robots.txt
114
114
  elsif route.first == 'robots'
115
- File.read(get_system_resource('robots.txt')) rescue raise(Errno::ENOENT, 'Page not found')
115
+ PageController.new(get_all_articles, categories, @config[:article_max], params, @config) .
116
+ render_rss(get_system_resource('robots.txt'))
116
117
 
117
118
  # Home page... /
118
119
  elsif route.first == @config[:root]
119
- all_articles = get_all_articles()
120
+ all_articles = get_all_articles
120
121
  params[:page_forward] = '/page/2/' if @config[:article_max] < all_articles.count
121
122
  PageController.new(all_articles, categories, @config[:article_max], params, @config) .
122
123
  render_html(get_theme_template(route.first), get_theme_template('layout'))
123
124
 
124
125
  # Pagination... /page/2, /page/2/
125
126
  elsif route.first == 'page' && route.count == 2
126
- page_num = route.last.to_i() rescue page_num = -1
127
- all_articles = get_all_articles()
127
+ page_num = route.last.to_i rescue page_num = -1
128
+ all_articles = get_all_articles
128
129
  max_pages = (all_articles.count.to_f / @config[:article_max].to_f).ceil
129
130
  raise(Errno::ENOENT, 'Page not found') if page_num < 1 or page_num > max_pages
130
131
 
@@ -142,18 +143,18 @@ module Baron
142
143
  # System routes... /robots.txt, /archives
143
144
  elsif route.first == 'archives' or route.first == 'robots'
144
145
  max_articles = ('archives' == route.first) ? :all : @config[:article_max]
145
- PageController.new(get_all_articles(), categories, max_articles, params, @config) .
146
+ PageController.new(get_all_articles, categories, max_articles, params, @config) .
146
147
  render_html(get_theme_template(route.first), get_theme_template('layout'))
147
148
 
148
149
  # Custom pages... /about, /contact-us
149
150
  elsif is_route_custom_page? route.first
150
- PageController.new(get_all_articles(), categories, @config[:article_max], params, @config) .
151
+ PageController.new(get_all_articles, categories, @config[:article_max], params, @config) .
151
152
  render_html(get_page_template(route.first), get_theme_template('layout'))
152
153
 
153
154
  # Category home pages... /projects/, /photography/, /poems/, etc
154
155
  elsif is_route_category_home? route.last
155
- filtered_articles = get_all_articles().select { |h| h[:category] == route.last }
156
- params[:page_name] = route.last.gsub('-', ' ').titleize()
156
+ filtered_articles = get_all_articles.select { |h| h[:category] == route.last }
157
+ params[:page_name] = route.last.gsub('-', ' ').titleize
157
158
  PageController.new(filtered_articles, categories, :all, params, @config) .
158
159
  render_html(get_theme_template('category'), get_theme_template('layout'))
159
160
 
@@ -186,7 +187,7 @@ module Baron
186
187
  end
187
188
 
188
189
  def get_all_articles
189
- get_all_category_folder_paths().map do |folder_name|
190
+ get_all_category_folder_paths.map do |folder_name|
190
191
  Dir["#{folder_name}/*"].map do |e|
191
192
  if e.end_with? @config[:ext]
192
193
  parts = e.split('/')
@@ -219,7 +220,7 @@ module Baron
219
220
  end
220
221
 
221
222
  def find_single_article article_slug
222
- get_all_articles().each { |fileparts| return fileparts if fileparts[:filename] == article_slug }
223
+ get_all_articles.each { |fileparts| return fileparts if fileparts[:filename] == article_slug }
223
224
  raise Errno::ENOENT, 'Article not found'
224
225
  end
225
226
 
@@ -228,7 +229,7 @@ module Baron
228
229
  end
229
230
 
230
231
  def is_route_category_home? path_node
231
- get_all_categories().each { |h| return true if h[:node_name] == path_node }
232
+ get_all_categories.each { |h| return true if h[:node_name] == path_node }
232
233
  return false
233
234
  end
234
235
 
@@ -237,6 +238,7 @@ module Baron
237
238
  def get_page_template(name) "#{@config[:sample_data_path]}pages/#{name}.rhtml" end
238
239
  def get_theme_template(name) "#{@config[:sample_data_path]}themes/#{@config[:theme]}/templates/#{name}.rhtml" end
239
240
  def get_system_resource(name) "#{@config[:sample_data_path]}resources/#{name}" end
241
+ def get_feed_path() "#{@config[:url]}/feed.rss" end
240
242
  end
241
243
 
242
244
  class Article < Hash
@@ -8,7 +8,7 @@ require 'spec_helper'
8
8
  describe "Baron::ArticleModel" do
9
9
  before :all do
10
10
  @config = load_config()
11
- @article_parts = {:filename_and_path => "#{SAMPLE_DATA_PATH}articles/poems/1916-01-01-the-road-not-taken.txt",
11
+ @article_parts = {:filename_and_path => "#{SAMPLE_DATA_PATH}articles/favorites/1916-01-01-the-road-not-taken.txt",
12
12
  :date => '1916-01-01',
13
13
  :filename => 'the-road-not-taken',
14
14
  :category => 'poems'}
@@ -17,11 +17,11 @@ describe "Baron::BlogEngine" do
17
17
  @blog_engine.get_pages_path.should == SAMPLE_DATA_PATH + 'pages/'
18
18
  @blog_engine.get_articles_path.should == SAMPLE_DATA_PATH + 'articles'
19
19
  @blog_engine.get_page_template('about').should == SAMPLE_DATA_PATH + 'pages/about.rhtml'
20
- @blog_engine.get_theme_template('article').should == SAMPLE_DATA_PATH + 'themes/test/templates/article.rhtml'
21
- @blog_engine.get_theme_template('category').should == SAMPLE_DATA_PATH + 'themes/test/templates/category.rhtml'
22
- @blog_engine.get_theme_template('error').should == SAMPLE_DATA_PATH + 'themes/test/templates/error.rhtml'
23
- @blog_engine.get_theme_template('home').should == SAMPLE_DATA_PATH + 'themes/test/templates/home.rhtml'
24
- @blog_engine.get_theme_template('layout').should == SAMPLE_DATA_PATH + 'themes/test/templates/layout.rhtml'
20
+ @blog_engine.get_theme_template('article').should == SAMPLE_DATA_PATH + 'themes/typography/templates/article.rhtml'
21
+ @blog_engine.get_theme_template('category').should == SAMPLE_DATA_PATH + 'themes/typography/templates/category.rhtml'
22
+ @blog_engine.get_theme_template('error').should == SAMPLE_DATA_PATH + 'themes/typography/templates/error.rhtml'
23
+ @blog_engine.get_theme_template('home').should == SAMPLE_DATA_PATH + 'themes/typography/templates/home.rhtml'
24
+ @blog_engine.get_theme_template('layout').should == SAMPLE_DATA_PATH + 'themes/typography/templates/layout.rhtml'
25
25
  @blog_engine.get_system_resource('redirects.txt').should == SAMPLE_DATA_PATH + 'resources/redirects.txt'
26
26
  @blog_engine.get_system_resource('robots.txt').should == SAMPLE_DATA_PATH + 'resources/robots.txt'
27
27
  @blog_engine.get_system_resource('feeds.rss').should == SAMPLE_DATA_PATH + 'resources/feeds.rss'
@@ -29,26 +29,28 @@ describe "Baron::BlogEngine" do
29
29
 
30
30
  it "finds all categories" do
31
31
  categories = @blog_engine.get_all_categories
32
- categories.count.should == 2
33
- categories.first[:name].should == 'Code Projects'
34
- categories.first[:path].should == '/code-projects/'
35
- categories.first[:count].should == 0
36
- categories.last[:name].should == 'Poems'
37
- categories.last[:path].should == '/poems/'
38
- categories.last[:count].should == 2
32
+ categories.count.should == 4
33
+ categories.first[:name].should == 'Favorites'
34
+ categories.first[:path].should == '/favorites/'
35
+ categories.first[:count].should == 1
36
+ categories.last[:name].should == 'Other Authors'
37
+ categories.last[:path].should == '/other-authors/'
38
+ categories.last[:count].should == 1
39
39
  end
40
-
40
+
41
+ # todo, refactor to break out testing that we're appropriately breaking the fileparts down
42
+
41
43
  it "finds all articles" do
42
44
  articles_fileparts = @blog_engine.get_all_articles()
43
- articles_fileparts.count.should == 3
44
- articles_fileparts.first[:filename_and_path].should == SAMPLE_DATA_PATH + 'articles/2012-11-09-sample-post.txt'
45
- articles_fileparts.first[:date].should == '2012-11-09'
46
- articles_fileparts.first[:filename].should == 'sample-post'
47
- articles_fileparts.first[:category].should == ''
48
- articles_fileparts.last[:filename_and_path].should == SAMPLE_DATA_PATH + 'articles/poems/1909-01-02-If.txt'
45
+ articles_fileparts.count.should == 7
46
+ articles_fileparts.first[:filename_and_path].should == SAMPLE_DATA_PATH + 'articles/favorites/1916-01-01-the-road-not-taken.txt'
47
+ articles_fileparts.first[:date].should == '1916-01-01'
48
+ articles_fileparts.first[:filename].should == 'the-road-not-taken'
49
+ articles_fileparts.first[:category].should == 'favorites'
50
+ articles_fileparts.last[:filename_and_path].should == SAMPLE_DATA_PATH + 'articles/other authors/1909-01-02-If.txt'
49
51
  articles_fileparts.last[:date].should == '1909-01-02'
50
52
  articles_fileparts.last[:filename].should == 'if'
51
- articles_fileparts.last[:category].should == 'poems'
53
+ articles_fileparts.last[:category].should == 'other authors'
52
54
  end
53
55
 
54
56
  it "returns all article parts" do
@@ -65,7 +65,7 @@ describe "Baron" do
65
65
 
66
66
  describe "GET category home page" do
67
67
  before :all do
68
- @response = @baron.get('/poems/')
68
+ @response = @baron.get('/north-of-boston/')
69
69
  end
70
70
 
71
71
  it_behaves_like "Server Response"
@@ -113,7 +113,6 @@ describe "Baron" do
113
113
  response.body.should include('404')
114
114
  # should not render in the layout.rhtml if <html is in the first 100 chars
115
115
  response.body.should_not include("<meta name=\"description\" content="">")
116
- response.body.should include ('Error')
117
116
  end
118
117
 
119
118
  end
@@ -128,11 +127,11 @@ describe "Baron" do
128
127
  it "returns expected content" do
129
128
  @response.body.should include(@config[:title])
130
129
  @response.body.should include("#{@config[:url]}/feed.rss")
131
- @response.body.scan(/<entry>/).count.should == 3
132
- @response.body.scan(/<\/entry>/).count.should == 3
130
+ @response.body.scan(/<entry>/).count.should == 5
131
+ @response.body.scan(/<\/entry>/).count.should == 5
133
132
  @response.body.should include('<feed')
134
133
  @response.body.should include('</feed>')
135
- end
134
+ end
136
135
  end
137
136
 
138
137
  describe "GET /robots.txt" do
@@ -140,19 +139,14 @@ describe "Baron" do
140
139
  @response = @baron.get('/robots.txt')
141
140
  end
142
141
 
143
- it_behaves_like "Server Response"
142
+ it_behaves_like "Server Response"
143
+
144
+ it "renders expected parameters" do
145
+ @response.body.should include("#{@config[:url]}/feed.rss")
146
+ end
144
147
  end
145
148
 
146
149
  describe "Redirect URLs" do
147
- it "should redirect with 301" do
148
- @response = @baron.get('/foobar-test-1')
149
- @response.status.should == 301
150
- @response['Location'].should == '/'
151
- @response = @baron.get('/foobar-test-2')
152
- @response.status.should == 301
153
- @response['Location'].should == '/archives'
154
- end
155
-
156
150
  it "should canonicalize pagination at page 1" do
157
151
  @response = @baron.get('/page/1/')
158
152
  @response.status.should == 301
@@ -160,13 +154,7 @@ describe "Baron" do
160
154
  @response = @baron.get('/page/1')
161
155
  @response.status.should == 301
162
156
  @response['Location'].should == '/'
163
- end
164
-
165
- it "should redirect with 302" do
166
- @response = @baron.get('/foobar-test-3')
167
- @response.status.should == 302
168
- @response['Location'].should == '/posts/poems/the-road-not-taken/'
169
- end
157
+ end
170
158
  end
171
159
 
172
160
  describe "Helper Functions" do
@@ -0,0 +1,5 @@
1
+ *.sw?
2
+ .DS_Store
3
+ coverage
4
+ rdoc
5
+ pkg
@@ -3,4 +3,4 @@ source 'https://rubygems.org'
3
3
  ruby '1.9.3'
4
4
  gem 'baron'
5
5
  gem 'rack'
6
- gem 'rdiscount'
6
+ gem 'rdiscount'
@@ -0,0 +1,243 @@
1
+ #The Baron Blog
2
+
3
+ A full-featured, yet minimalist, blog engine for developers
4
+
5
+ I know what you're thinking, the world doesn't need another Ruby blog
6
+ engine. And, okay, you're right, however Baron is a little bit different from
7
+ all the others in that it is a lot more full-featured, and still only a scant
8
+ 400 lines of easy-to-ready code.
9
+
10
+ **Features**
11
+ * Publish to heroku (or similar PaaS) using Git
12
+ * Author articles or custom pages in markdown, text or HTML
13
+ * Article categories supported by simply putting articles in a folder
14
+ * Many permalink formats are supported, including a custom prefix and several
15
+ date formats
16
+ * 301 or 302 redirects are support for easy porting from your current blog
17
+ * SEO optimized with built-in support for Robots.txt, Google Analytics, Google
18
+ web master tools
19
+ * Easy to customize the look & feel via a common site layout template
20
+ * Frameworks used: Rack, RSpec, Bootstrap, JQuery, Disqus, Thin
21
+
22
+ ##Quick Start
23
+
24
+ Dependencies: <a href="http://git-scm.com/">git</a>,
25
+ <a href="https://devcenter.heroku.com/articles/quickstart">heroku</a>,
26
+ <a href="http://www.ruby-lang.org/en/downloads/">ruby</a>
27
+
28
+ $ git clone https://github.com/nbuggia/baron-blog.git
29
+ $ mv baron-blog my-blog
30
+ $ heroku create my-blog
31
+ $ TODO: heroku add local...????
32
+ $ git init
33
+ $ git add .
34
+ $ git commit -m 'First commit of my new blog!'
35
+ $ git push heroku master
36
+ $ heroku open
37
+
38
+ Yay! Now you probably are going to want to customize this thing, read on for
39
+ all the bells and whistles.
40
+
41
+ ##Quick How To's
42
+
43
+ ###Customize Your Blog
44
+
45
+ $ less config.ru
46
+
47
+ There are many bells and whistles available for your blog, most of them can be
48
+ set from inside <code>config.ru</code>. The file is well documented for all the
49
+ options.
50
+
51
+ The other big customization route is to hack the theme to either make your own,
52
+ or to just modify it the way you'd like. Check out the
53
+ **Creating Your Own Themes*** section for more information.
54
+
55
+ ###Adding a Custom Domain Name (with Heroku)
56
+
57
+ Go to the config section of your blog app and then enter in one or more new
58
+ domain names. Next step is to redirect your DNS server to to heroku
59
+
60
+ **GoDaddy**
61
+
62
+
63
+ **FOOBAR**
64
+
65
+
66
+ If you have a different hoster, just ask google how to set it up.
67
+
68
+ Finally, you'll want to redirect the nude domain name to www, like this:
69
+
70
+ my-domain.com &rarr; www.my-domain.com
71
+
72
+ ###Create New Post
73
+
74
+ $ rake new
75
+ Title: My Blog Title
76
+
77
+ This command creates a new blog post with the current date in your
78
+ <code>drafts/</code> folder.
79
+
80
+ To create a new post, you simply create a new text file in your favorite
81
+ editor. Simply save the file somewhere in your <code>articles/</code> folder in
82
+ the format of <code>YYYY-MM-DD-article-title.txt</code>. Where YYYY means the
83
+ year in 4 digits, MM means the month in two digits and DD means the day of the
84
+ month in 2 digits.
85
+
86
+ **Attributes**
87
+
88
+ The first few lines of the file are where you can place attribute value
89
+ pairs in YAML format (e.g. <code>my_attribute: 'attribute'</code>). Add two new
90
+ lines to start the article, and then you can write it using markdown, HTML,
91
+ plain text, or a combination of all 3.
92
+
93
+ * You can add additional attributes you want and then access them in the rhtml
94
+ template with <code>@article[:my_attribute]</code>.
95
+ * If you need to use ':' or other special characters in your value, wrap it in
96
+ quotes (e.g. <code>title: "My article: Lots & Lots of Smiles"</code>)
97
+
98
+ Notes
99
+
100
+ * Baron forces all folder names and file names to lower case for canonicalization
101
+ * You can't have periods in the file name
102
+
103
+ ###Create A New Custom Page
104
+
105
+ use the directory structure
106
+
107
+ ###Setup redirects
108
+
109
+
110
+ ###SEO
111
+
112
+ ###Explore the Project
113
+
114
+ Project structure:
115
+
116
+ ├── Gemfile
117
+ ├── Rakefile
118
+ ├── articles/ place your published articles here
119
+ │   ├── 2012-11-09-sample-1.txt the date and URL slug are the filename
120
+ │   └── category/ creating folders puts these articles in a category
121
+ │   ├── another category/ spaces in folder names will be replaces with '-'s
122
+ ├── config.ru configure features of the blog here
123
+ ├── downloads/ files in here are publicly accessible
124
+ ├── drafts/ place for your unfinished articles
125
+ ├── images/ images in here are publicly accessible
126
+ ├── pages/ you can create custom pages in here
127
+ │   └── about.rhtml
128
+ ├── resources/
129
+ │   ├── feed.rss your rss feed's rendering template
130
+ │   ├── redirects.txt list of redirects the blog will process
131
+ │   └── robots.txt your robots.txt file
132
+ └── themes/
133
+ └── my-theme/ each theme has the same folder structure
134
+ ├── css/
135
+ ├── img/
136
+ ├── js/
137
+ └── templates/ rhtml rendering templates for each page type
138
+
139
+ ###Create a New Article
140
+
141
+
142
+ ###Create a New Page
143
+
144
+
145
+ ###Add a Custom Domain Name in Heroku (free!)
146
+
147
+ TODO
148
+
149
+ ###Deploy to Heroku (free!)
150
+
151
+ TODO
152
+
153
+ ###Domain Name Configuration
154
+
155
+ Then setup use the Forwarding feature in GoDaddy to send buggia.org --> www.buggia.org
156
+
157
+ http://stackoverflow.com/questions/11492563/heroku-godaddy-send-naked-domain-to-www
158
+
159
+
160
+ ###Run Blog Locally
161
+
162
+ Uses Thin to run the blog
163
+
164
+ > cd my-blog
165
+ > sudo gem install thin
166
+ > thin start
167
+
168
+ If you make a change to config.ru, you will need to restart thin.
169
+
170
+ ###Creating Your Own Themes
171
+
172
+
173
+ ##Next Steps
174
+
175
+ I wrote this as an excuse to learn a handful of new technologies and approaches,
176
+ like Ruby and TDD. There are an ambitious set of features I'd like to add that
177
+ each align to something else I would like to learn:
178
+
179
+ * Themes - I'm designing 3-4 fancy, shmancy themes to try out this new 'flat'
180
+ and minimalist thing everyone's excited about. Also a good excuse to dig into
181
+ HTML5, CSS3, JQuery, Instagram's API and a few other things.
182
+
183
+ * Pre-rendering - the platform nerd in me doesn't understand why the whole
184
+ blog isn't pre-rendered at deploy time so heroku just serves static HTML and
185
+ assets (a la <a href="https://github.com/mojombo/jekyll">Jekyll</a>)
186
+
187
+ * JavaScript Comments - the blog engine currently uses Disqus for comments,
188
+ which is free and cool, but I hate letting other people own my data. I want
189
+ to build something similar to Disqus on top of
190
+ <a href="https://www.parse.com/">Parse</a> /
191
+ <a href="https://github.com/documentcloud/backbone">Backbone</a> and make it
192
+ really easy to use
193
+
194
+ * Simple Plugin Model - I've always wanted to write a plug-in model. I tried
195
+ to write one in C++ in college and was only able to do static linking (lame). I
196
+ think an interpreted language will make it much easier, right?
197
+
198
+ ##Namesake
199
+
200
+ Pictures of the adorable baron von underbite
201
+
202
+ ##Thanks
203
+
204
+ While writing this blog engine, I barrowed a lot of code and design approaches
205
+ from the Toto project by Cloudhead and the Scanty project by Adam Wiggins. The
206
+ primary purpose of this project was a learning one for me, and both of these
207
+ folks provided a lot of good code an examples. I'm not sure how much code or
208
+ design awesomeness one needs to use before they are obligated to include their
209
+ license, so I'm included a link to each of them just in case (and thank you
210
+ both for your awesomeness!)
211
+
212
+ Toto
213
+ - URL: https://github.com/cloudhead/toto
214
+ - Author: http://cloudhead.io/ (Alexis Sellier)
215
+ - License: https://github.com/cloudhead/toto/blob/master/LICENSE
216
+
217
+ Scanty
218
+ - URL: https://github.com/adamwiggins/scanty
219
+ - Author: http://about.adamwiggins.com/ (Adam Wiggins)
220
+
221
+ ##License
222
+
223
+ This software is licensed under the MIT Software License
224
+
225
+ Copyright (c) 2013 Nathan Buggia
226
+
227
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
228
+ this software and associated documentation files (the "Software"), to deal in
229
+ the Software without restriction, including without limitation the rights to
230
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
231
+ of the Software, and to permit persons to whom the Software is furnished to do
232
+ so, subject to the following conditions:
233
+
234
+ The above copyright notice and this permission notice shall be included in all
235
+ copies or substantial portions of the Software.
236
+
237
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
238
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
239
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
240
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
241
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
242
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
243
+ SOFTWARE.