gidget 0.2.1 → 0.3.0

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.
@@ -7,29 +7,17 @@ Gidget is a minimalist blog engine designed to run on Heroku with a Git-based wo
7
7
  == Basic Structure
8
8
 
9
9
  * Sinatra based server
10
- * A singleton array containing post information (the body of a post is lazily-loaded)
10
+ * A File Mapper to help map requests to pages, posts, and tags
11
+ * A class to handle page information
11
12
  * A class to handle post information
12
13
 
13
- == Routing
14
+ == Templates
14
15
 
15
- * / - an index template with access to the full array of posts
16
- * /2010/11/19 - an archive template with access to all posts from the specified year/month/day as well as what year, month, and day it is for (month and day are optional)
17
- * /2010/11/19/first-post - a post template with access to the full array of posts and the current post index
18
- * /page/1 - a paging template with access to posts for the specified day as well as the current page number and total number of pages
19
- * /some-special-page - a custom template with access to the full array of posts
16
+ <This section is being rewritten>
20
17
 
21
- == Post Creation
18
+ == Page/Post Creation
22
19
 
23
- Posts are simply .txt files located under a folder named posts located off the root of the web app. Text files contain two sections of data. The first is metadata including at least a title and date as such:
24
-
25
- title: My great post title
26
- date: 2010-11-19
27
-
28
- _Hello World!_ This is my first blog post!
29
-
30
- The second section is the body of the post and uses markdown as it's markup language. The two sections should be separated by an empty line.
31
-
32
- File name and structure (other than the .txt extension) don't matter. Gidget will determine request paths based on the date and title metadata and sort them accordingly.
20
+ <This section is being rewritten>
33
21
 
34
22
  == Settings
35
23
 
@@ -38,7 +26,6 @@ Gidget uses Sinatra's built-in setting support. Settings can be set in your con
38
26
  gidget = Gidget::Server.new do
39
27
  set :title, "My Awesome Blog"
40
28
  set :author, "Your Name Goes Here"
41
- set :summary_size, 100
42
29
  set :page_size, 10
43
30
  end
44
31
 
@@ -79,10 +66,11 @@ In order to deploy an app to Heroku you must have an account with them. Once yo
79
66
  git push heroku master
80
67
  heroku open
81
68
 
82
- Congrats! You now have your own blog running on the internets!
69
+ Congrats! You now have your own blog running on the world wide web!
83
70
 
84
71
  == TO BE DONE
85
72
 
73
+ * Cleanup stub contents
86
74
  * Come up with a decent base theme
87
75
 
88
76
  == Contributing to gidget
@@ -0,0 +1,3 @@
1
+ title: About
2
+
3
+ This is an about page with whatever information you want to be here.
@@ -7,4 +7,5 @@
7
7
  %h1 My Blog
8
8
  %article
9
9
  %h1= posts[0].title
10
- = posts[0].body
10
+ = posts[0].body
11
+ = DateTime.now.to_s
@@ -6,4 +6,5 @@
6
6
  %header
7
7
  %h1 My Blog
8
8
  %article
9
- %h1= "I found #{posts.size} posts!"
9
+ %h1= page.title
10
+ = page.body
@@ -0,0 +1,9 @@
1
+ !!! 5
2
+ %html
3
+ %head
4
+ %title= settings.title
5
+ %body
6
+ %header
7
+ %h1 My Blog
8
+ %article
9
+ %h1= "I found #{posts.size} posts!"
data/bin/gidget CHANGED
@@ -24,6 +24,7 @@ class App
24
24
 
25
25
  print " Copying stub ... "
26
26
  FileUtils.cp_r(source + "/.", destination)
27
+ FileUtils.remove_file(File.join(destination, "config.dev.ru"))
27
28
  puts "done."
28
29
 
29
30
  puts "Done."
@@ -4,11 +4,6 @@ class String
4
4
  end
5
5
 
6
6
 
7
- def humanize
8
- self.capitalize.gsub(/[-_]+/, ' ')
9
- end
10
-
11
-
12
7
  def starts_with?(prefix)
13
8
  prefix = prefix.to_s
14
9
  self[0, prefix.length] == prefix
@@ -0,0 +1,68 @@
1
+ require 'singleton'
2
+ require 'gidget/page'
3
+ require 'gidget/post'
4
+
5
+
6
+ module Gidget
7
+ class FileMapper
8
+ include Singleton
9
+
10
+ attr_reader :pages
11
+ attr_reader :posts
12
+ attr_reader :tags
13
+
14
+
15
+ def initialize
16
+ @pages = Hash.new
17
+ @posts = Array.new
18
+ @tags = Hash.new
19
+ end
20
+
21
+
22
+ def load
23
+ page_paths = Dir.glob("pages/**/*.txt")
24
+
25
+ # load the page index
26
+ page_paths.each { |file_path|
27
+ page = Page.new(file_path)
28
+ @pages[page.request_path] = page
29
+ }
30
+
31
+ puts "Page Index created, size = " + @pages.keys.size.to_s
32
+
33
+
34
+ post_paths = Dir.glob("posts/**/*.txt")
35
+
36
+ # load the post index
37
+ post_paths.each { |file_path|
38
+ post = Post.new(file_path)
39
+ @posts << post
40
+ }
41
+
42
+ # sort the post index by date descending (newest will be first)
43
+ @posts.replace @posts.sort_by { |p| Time.parse(p.date.to_s).to_i }.reverse!
44
+
45
+ puts "Post Index created, size = " + @posts.size.to_s
46
+
47
+
48
+ # load the tag index
49
+ @posts.each { |post|
50
+ if (post.meta_data.has_key? :tags)
51
+ tags = post.meta_data[:tags].split(',')
52
+
53
+ tags.each { |tag|
54
+ tag.strip!
55
+
56
+ if (!@tags.has_key? tag)
57
+ @tags[tag] = []
58
+ end
59
+
60
+ @tags[tag] << post
61
+ }
62
+ end
63
+ }
64
+
65
+ puts "Tag Index created, size = " + @tags.keys.size.to_s
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,55 @@
1
+ require 'rdiscount'
2
+ require 'yaml'
3
+ require 'gidget/ext'
4
+
5
+
6
+ module Gidget
7
+ class Page
8
+ attr_reader :file_path
9
+ attr_reader :meta_data
10
+
11
+
12
+ def initialize(file_path)
13
+ @file_path = file_path
14
+
15
+ begin
16
+ file = File.open(@file_path, "r")
17
+
18
+ # read the first paragraph and load it into a Hash with symbols as keys
19
+ @meta_data = YAML.load(file.gets("")).inject({}) { |h, (k,v)| h.merge(k.to_sym => v) }
20
+ ensure
21
+ file.close()
22
+ end
23
+ end
24
+
25
+
26
+ def request_path
27
+ @meta_data[:permalink] || "/" + self.title.slugize
28
+ end
29
+
30
+
31
+ def title
32
+ @meta_data[:title]
33
+ end
34
+
35
+
36
+ def body
37
+ begin
38
+ file = File.open(@file_path, "r")
39
+
40
+ # ignore the first paragraph
41
+ file.gets("")
42
+
43
+ # read the rest of the file and process it's markdown
44
+ RDiscount.new(file.gets(nil)).to_html
45
+ ensure
46
+ file.close()
47
+ end
48
+ end
49
+
50
+
51
+ def method_missing(m, *args, &block)
52
+ @meta_data[m] || super
53
+ end
54
+ end
55
+ end
@@ -1,52 +1,20 @@
1
- require 'yaml'
2
- require 'rdiscount'
3
- require 'gidget/ext'
1
+ require 'gidget/page'
4
2
 
5
3
 
6
4
  module Gidget
7
- class Post
8
- attr_reader :file_path
9
- attr_reader :request_path
10
- attr_reader :meta_data
11
-
12
-
13
- def initialize(file_path)
14
- @file_path = file_path
15
-
16
- begin
17
- file = File.open(@file_path, "r")
18
-
19
- # read the first paragraph and load it into a Hash with symbols as keys
20
- @meta_data = YAML.load(file.gets("")).inject({}) { |h, (k,v)| h.merge(k.to_sym => v) }
21
- ensure
22
- file.close()
23
- end
24
-
25
- @request_path = @meta_data[:date].strftime("/%Y/%m/%d/") + @meta_data[:title].slugize
5
+ class Post < Page
6
+ def request_path
7
+ @meta_data[:permalink] || self.date.strftime("/%Y/%m/") + self.title.slugize
26
8
  end
27
9
 
28
10
 
29
- def body
30
- begin
31
- file = File.open(@file_path, "r")
32
-
33
- # ignore the first paragraph
34
- file.gets("")
35
-
36
- # read the rest of the file and process it's markdown
37
- RDiscount.new(file.gets(nil)).to_html
38
- ensure
39
- file.close()
40
- end
11
+ def date
12
+ @meta_data[:date]
41
13
  end
42
14
 
43
15
 
44
- def method_missing(m, *args, &block)
45
- if (@meta_data.has_key?(m))
46
- return @meta_data[m]
47
- else
48
- super
49
- end
16
+ def tags
17
+ @meta_data[:tags] || ""
50
18
  end
51
19
  end
52
20
  end
@@ -1,6 +1,7 @@
1
1
  require 'sinatra/base'
2
+ require 'benchmark'
2
3
  require 'haml'
3
- require 'gidget/post_index'
4
+ require 'gidget/file_mapper'
4
5
 
5
6
 
6
7
  module Gidget
@@ -14,82 +15,97 @@ module Gidget
14
15
  super(app, &b=nil)
15
16
  Server.class_exec(&block) if block_given?
16
17
 
17
- PostIndex.instance.load
18
+ # load the file mapper
19
+ puts Benchmark.measure { FileMapper.instance.load }
18
20
  end
19
21
 
20
22
 
23
+ # route for root
21
24
  get '/' do
22
- render_view(:index, { :posts => PostIndex.instance })
25
+ haml :index, :locals => { :posts => FileMapper.instance.posts }
23
26
  end
24
27
 
25
28
 
26
- get %r{^\/\d{4}\/\d{2}\/\d{2}\/[\w,-]+$} do
29
+ # route for a specific page
30
+ get %r{^\/[\w,\-,\/]+$} do
31
+ page = FileMapper.instance.pages[request.path]
32
+
33
+ if (page != nil)
34
+ haml :page, :locals => { :page => page }
35
+ else
36
+ pass
37
+ end
38
+ end
39
+
40
+
41
+ # route for a specific post
42
+ get %r{^\/[\w,\-,\/]+$} do
27
43
  index = nil
28
-
29
- PostIndex.instance.each_with_index { |p, i|
44
+
45
+ FileMapper.instance.posts.each_with_index { |p, i|
30
46
  if (p.request_path == request.path)
31
47
  index = i
32
48
  break
33
49
  end
34
50
  }
35
-
51
+
36
52
  if (index != nil)
37
- render_view(:post, { :posts => PostIndex.instance, :index => index })
53
+ haml :post, :locals => { :posts => FileMapper.instance.posts, :index => index }
54
+ else
55
+ pass
38
56
  end
39
57
  end
40
-
41
-
42
- get %r{^\/(\d{4})(\/(\d{2})(\/(\d{2}))?)?$} do
43
- year = params[:captures][0]
44
- month = params[:captures][2]
45
- day = params[:captures][4]
46
-
47
- posts = PostIndex.instance.select { |p|
48
- p.request_path.starts_with? request.path
49
- }
50
-
51
- render_view(:archive, { :posts => posts, :year => year, :month => month, :day => day })
52
- end
53
58
 
54
59
 
55
- get %r{^\/page\/(\d+$)} do
60
+ # route for an archive listing in the format /archive/yyyy/mm (year and month are optional)
61
+ get %r{^\/archive(\/(\d{4})(\/(\d{2}))?)?$} do
62
+ if (params[:captures] == nil)
63
+ posts = FileMapper.instance.posts
64
+ else
65
+ year = params[:captures][1]
66
+ month = params[:captures][3]
67
+
68
+ prefix = "#{year}#{month}"
69
+
70
+ posts = FileMapper.instance.posts.select { |p|
71
+ p.date.strftime("%Y%m").starts_with? prefix
72
+ }
73
+ end
74
+
75
+ haml :archive, :locals => { :posts => posts, :year => year, :month => month }
76
+ end
77
+
78
+
79
+ # route for post paging
80
+ get %r{^\/page\/(\d+)$} do
56
81
  current_page = params[:captures][0].to_i
57
- total_pages = (PostIndex.instance.size + settings.page_size - 1) / settings.page_size
58
-
82
+ total_pages = (FileMapper.instance.posts.size + settings.page_size - 1) / settings.page_size
83
+
59
84
  if (current_page <= total_pages)
60
- posts = PostIndex.instance[(current_page - 1) * settings.page_size, settings.page_size]
61
-
62
- render_view(:page, { :posts => posts, :current_page => current_page, :total_pages => total_pages })
85
+ posts = FileMapper.instance.posts[(current_page - 1) * settings.page_size, settings.page_size]
86
+
87
+ haml :post_paging, :locals => { :posts => posts, :current_page => current_page, :total_pages => total_pages }
63
88
  else
64
89
  pass
65
90
  end
66
91
  end
67
-
68
-
69
- get %r{^\/tag\/([\w,-]+$)} do
70
- posts = TagIndex.instance[params[:captures][0]]
71
-
92
+
93
+
94
+ # route for list of posts tagged with a particular tag
95
+ get %r{^\/tag\/([\w,\-]+)$} do
96
+ posts = FileMapper.instance.tags[params[:captures][0]]
97
+
72
98
  if (posts != nil)
73
- render_view(:tag, { :posts => posts })
99
+ haml :tag, :locals => { :posts => posts }
74
100
  else
75
101
  pass
76
102
  end
77
103
  end
78
104
 
79
105
 
80
- get %r{^\/[\w,-]+$} do
81
- begin
82
- render_view(request.path.to_sym, { :posts => PostIndex.instance })
83
- rescue
84
- pass
85
- end
86
- end
87
-
88
-
89
- def render_view(view, locals)
106
+ # make all requests cached for a day
107
+ after do
90
108
  expires(86400, :public)
91
-
92
- haml view, :locals => locals
93
109
  end
94
110
  end
95
111
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gidget
3
3
  version: !ruby/object:Gem::Version
4
- hash: 21
4
+ hash: 19
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
- - 2
9
- - 1
10
- version: 0.2.1
8
+ - 3
9
+ - 0
10
+ version: 0.3.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Forrest Robertson
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-01-09 00:00:00 -07:00
18
+ date: 2011-02-08 00:00:00 -07:00
19
19
  default_executable: gidget
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -139,19 +139,21 @@ files:
139
139
  - _stub_/Gemfile
140
140
  - _stub_/config.dev.ru
141
141
  - _stub_/config.ru
142
+ - _stub_/pages/about.txt
142
143
  - _stub_/posts/first-post.txt
143
144
  - _stub_/views/about.haml
144
145
  - _stub_/views/archive.haml
145
146
  - _stub_/views/index.haml
146
147
  - _stub_/views/page.haml
147
148
  - _stub_/views/post.haml
149
+ - _stub_/views/post_paging.haml
148
150
  - _stub_/views/tag.haml
149
151
  - lib/gidget.rb
150
152
  - lib/gidget/ext.rb
153
+ - lib/gidget/file_mapper.rb
154
+ - lib/gidget/page.rb
151
155
  - lib/gidget/post.rb
152
- - lib/gidget/post_index.rb
153
156
  - lib/gidget/server.rb
154
- - lib/gidget/tag_index.rb
155
157
  - LICENSE.txt
156
158
  - README.rdoc
157
159
  - bin/gidget
@@ -1,28 +0,0 @@
1
- require 'singleton'
2
- require 'gidget/post'
3
- require 'gidget/tag_index'
4
-
5
-
6
- module Gidget
7
- class PostIndex < Array
8
- include Singleton
9
-
10
-
11
- def load
12
- paths = Dir.glob("posts/**/*.txt")
13
-
14
- # add all the posts to the array
15
- paths.each { |file_path|
16
- self << Post.new(file_path)
17
- }
18
-
19
- # sort the array by the request path, descending (newest by date will be first)
20
- self.replace self.sort_by { |p| p.request_path }.reverse!
21
-
22
- puts "Post Index created, size = " + self.size.to_s
23
-
24
- # load the tag index
25
- TagIndex.instance.load self
26
- end
27
- end
28
- end
@@ -1,30 +0,0 @@
1
- require 'singleton'
2
- require 'gidget/post'
3
-
4
-
5
- module Gidget
6
- class TagIndex < Hash
7
- include Singleton
8
-
9
-
10
- def load posts
11
- posts.each { |post|
12
- tags = nil
13
-
14
- if (post.meta_data.has_key? :tags)
15
- tags = post.meta_data[:tags].split(',')
16
-
17
- tags.each { |tag|
18
- tag.strip!
19
-
20
- if (!self.has_key? tag)
21
- self[tag] = []
22
- end
23
-
24
- self[tag] << post
25
- }
26
- end
27
- }
28
- end
29
- end
30
- end