lib/shinmun/blog.rb in shinmun-0.2 vs lib/shinmun/blog.rb in shinmun-0.5
- old
+ new
@@ -1,319 +1,181 @@
module Shinmun
+ ROOT = File.expand_path(File.dirname(__FILE__) + '/../..')
- class Blog
+ class Blog < Kontrol::Application
+ include Helpers
- # Define reader methods for configuration.
- def self.config_reader(file, *names)
- names.each do |name|
- name = name.to_s
- define_method(name) { @config[file][name] }
- end
+ attr_accessor :config, :store, :posts, :pages
+
+ %w[ base_path title description language author categories ].each do |name|
+ define_method(name) { @config[name.to_sym] }
end
- attr_reader :root, :posts, :pages, :aggregations
-
- config_reader 'config/assets.yml', :javascript_files, :stylesheet_files, :base_path, :images_path, :javascripts_path, :stylesheets_path
- config_reader 'config/blog.yml', :title, :description, :language, :author, :url, :repository
- config_reader 'config/categories.yml', :categories
+ # Initialize the blog
+ def initialize(path)
+ super
- # Initialize the blog, load the config file and write the index files.
- def initialize
- @config = Cache.new do |file|
- YAML.load(File.read(file))
- end
-
- @stylesheets = Cache.new
-
- @templates = Cache.new do |file|
- ERB.new(File.read(file))
- end
-
- @javascripts = Cache.new do |file|
- script = File.read(file)
- script = Packr.pack(script) if defined?(Packr)
- "/* #{file} */\n #{script}\n"
- end
-
- @posts_cache = Cache.new do |file|
- Post.new(:filename => file).load
- end
-
- @pages_cache = Cache.new do |file|
- Post.new(:filename => file).load
- end
-
- Dir['pages/**/*'].each do |file|
- @pages_cache.load(file) if File.file?(file) and file[-1, 1] != '~'
- end
-
- Dir['posts/**/*'].each do |file|
- @posts_cache.load(file) if File.file?(file) and file[-1, 1] != '~'
- end
-
- @config.load('config/aggregations.yml')
- @config.load('config/assets.yml')
- @config.load('config/blog.yml')
- @config.load('config/categories.yml')
-
- @aggregations = {}
-
- load_aggregations
-
- Thread.start do
- sleep 300
- load_aggregations
- end
+ @config = {}
+ @store = GitStore.new(path)
+ @store.handler['md'] = PostHandler.new
+ @store.handler['rhtml'] = ERBHandler.new
+ @store.handler['rxml'] = ERBHandler.new
end
- def load_aggregations
- @config['config/aggregations.yml'].to_a.each do |c|
- @aggregations[c['name']] = Object.const_get(c['class']).new(c['url'])
- end
- end
+ def self.init(path)
+ path = File.expand_path(path)
+ Dir.mkdir(path)
- # Reload config, assets and posts.
- def reload
- if @config.dirty? || @templates.dirty?
- @config.reload!
- @templates.reload!
- @posts_cache.reload!
- @pages_cache.reload!
- else
- @config.reload_dirty!
- @templates.reload_dirty!
- @posts_cache.reload_dirty!
- @pages_cache.reload_dirty!
- end
+ FileUtils.cp_r "#{ROOT}/assets", path
+ FileUtils.cp_r "#{ROOT}/templates", path
+ FileUtils.cp "#{ROOT}/config.ru", path
- @posts = @posts_cache.values.sort_by { |p| p.date }.reverse
- @pages = @pages_cache.values
+ Dir.mkdir("#{path}/posts")
+ Dir.mkdir("#{path}/pages")
+ Dir.mkdir("#{path}/comments")
+ Dir.mkdir("#{path}/public")
- pack_javascripts if @javascripts.dirty? or @javascripts.empty?
- pack_stylesheets if @stylesheets.dirty? or @stylesheets.empty?
+ FileUtils.ln_s("../assets", "#{path}/public/assets")
- load 'templates/helpers.rb'
- end
-
- # Use rsync to synchronize the rendered blog to web server.
- def push
- system "rsync -avz public/ #{repository}"
- end
-
- def urlify(string)
- string.downcase.gsub(/[ -]+/, '-').gsub(/[^-a-z0-9_]+/, '')
- end
-
- # Compress the javascripts using PackR and write them to one file called 'all.js'.
- def pack_javascripts
- @javascripts.reload_dirty!
- File.open("assets/#{javascripts_path}/all.js", "wb") do |io|
- for file in javascript_files
- io << @javascripts["assets/#{javascripts_path}/#{file.strip}.js"] << "\n\n"
- end
+ Dir.chdir(path) do
+ `git init`
+ `git add .`
+ `git commit -m 'init'`
end
end
- # Pack the stylesheets and write them to one file called 'all.css'.
- def pack_stylesheets
- @stylesheets.reload_dirty!
- File.open("assets/#{stylesheets_path}/all.css", "wb") do |io|
- for file in stylesheet_files
- io << @stylesheets["assets/#{stylesheets_path}/#{file.strip}.css"] << "\n\n"
- end
- end
+ def load_template(file)
+ store['templates/' + file]
end
- # Write a file to output directory.
- def write_file(path, data)
- FileUtils.mkdir_p("public/#{base_path}/#{File.dirname path}")
-
- open("public/#{base_path}/#{path}", 'wb') do |file|
- file << data
- end
+ def render(name, vars = {})
+ super(name, vars.merge(:blog => self))
end
- # Return all posts for a given month.
- def posts_for_month(year, month)
- posts.select { |p| p.year == year and p.month == month }
+ def pages
+ store.tree('pages').values.select { |v| Post === v }
end
- # Return all posts in given category.
- def posts_for_category(category)
- name = category['name']
- posts.select { |p| p.category == name }
+ def posts
+ store.tree('posts').values.select { |v| Post === v }.sort_by { |p| p.date.to_s }.reverse
end
- # Return all posts with any of given tags.
- def posts_with_tags(tags)
- return [] if tags.nil?
- tags = tags.split(',').map { |t| t.strip } if tags.is_a?(String)
- posts.select do |post|
- tags.any? do |tag|
- post.tags.to_s.include?(tag)
- end
+ def call(env)
+ if ENV['RACK_ENV'] == 'production'
+ store.load if store.changed?
+ else
+ store.load(true)
end
+
+ super
end
- # Return all months as tuples of [year, month].
- def months
- posts.map { |p| [p.year, p.month] }.uniq.sort
+ def url
+ "http://#{request.host}"
end
- # Create a new post with given title.
- def create_post(title)
- date = Date.today
- name = urlify(title)
- path = "#{date.year}/#{date.month}/#{name}.md"
-
- if File.exist?(file)
- raise "#{file} exists"
- else
- Post.new(:path => path,
- :title => title,
- :date => date).save
+ def symbolize_keys(hash)
+ hash.inject({}) do |h, (k, v)|
+ h[k.to_sym] = v
+ h
end
end
- def find_page(path)
- pages.find { |p| p.path == path }
+ def transaction(message, &block)
+ store.transaction(message, &block)
end
- def find_post(path)
- posts.find { |p| p.path == path }
+ def post_file(post)
+ 'posts' + post_path(post) + '.' + post.type
end
- def find_category(category)
- category = urlify(category)
- categories.find { |c| urlify(c['name']) == category }
+ def page_file(post)
+ 'pages' + page_path(post) + '.' + post.type
end
- # Render template with given variables.
- def render_template(name, vars)
- template = Template.new(@templates["templates/#{name}"], name)
- template.set_variables(vars)
- template.render
+ def comment_file(post)
+ 'comments/' + post_path(post) + '.yml'
end
- def render_layout(vars)
- render_template("layout.rhtml", vars.merge(:blog => self))
- end
+ def create_post(attr)
+ post = Post.new(attr)
+ path = post_file(post)
- # Render named template and insert into layout with given variables.
- def render(name, vars)
- render_layout(vars.merge(:content => render_template(name, vars.merge(:blog => self))))
- end
+ transaction "create post `#{post.title}'" do
+ store[path] = post
+ end
- # Render given post using the post template and the layout template.
- def render_post(post)
- render('post.rhtml', post.variables.merge(:header => post.category))
+ post
end
- # Render given page using only the layout template.
- def render_page(page)
- render_layout(page.variables.merge(:content => page.body_html))
- end
+ def create_page(attr)
+ post = Post.new(attr)
+ path = page_file(post)
- # Render comments.
- def render_comments(comments)
- render_template('comments.rhtml', :comments => comments)
- end
+ transaction "create page `#{post.title}'" do
+ store[path] = post
+ end
- # Render index page using the index and the layout template.
- def render_index_page
- render('index.rhtml',
- :header => 'Home',
- :posts => posts)
+ post
end
- # Render the category summary for given category.
- def render_category(category)
- posts = posts_for_category(category)
- render("category.rhtml",
- :header => category['name'],
- :category => category,
- :posts => posts)
+ def comments_for(post)
+ store[comment_file post] || []
end
- # Render the archive summary for given month.
- def render_month(year, month)
- path = "#{year}/#{month}"
- month_name = Date::MONTHNAMES[month]
- posts = posts_for_month(year, month)
- render("month.rhtml",
- :header => "#{month_name} #{year}",
- :year => year,
- :month => month_name,
- :posts => posts)
+ def create_comment(post, params)
+ path = comment_file(post)
+ comments = comments_for(post)
+ comment = Comment.new(params)
+
+ transaction "new comment for `#{post.title}'" do
+ store[path] = comments + [comment]
+ end
+
+ comment
end
- # Render index feed using the feed template.
- def render_index_feed
- render_template("index.rxml",
- :blog => self,
- :posts => posts)
+ def find_page(name)
+ pages.find { |p| p.name == name }
end
- # Render category feed for given category using the feed template .
- def render_category_feed(category)
- render_template("category.rxml",
- :blog => self,
- :category => category,
- :posts => posts_for_category(category))
+ def find_post(year, month, name)
+ posts.find { |p| p.year == year and p.month == month and p.name == name }
end
- def write_index_page
- write_file("index.html", render_index_page)
+ def find_category(permalink)
+ name = categories.find { |name| urlify(name) == permalink }
+
+ { :name => name,
+ :posts => posts.select { |p| p.category == name },
+ :permalink => permalink }
end
- # Write all pages.
- def write_pages
- for page in pages
- write_file("#{page.path}.html", render_page(page))
- end
+ def recent_posts
+ posts[0, 20]
end
- # Write all posts.
- def write_posts
- for post in posts
- write_file("#{post.path}.html", render_post(post))
- end
+ # Return all posts for a given month.
+ def posts_for_month(year, month)
+ posts.select { |p| p.year == year and p.month == month }
end
- # Write archive summaries.
- def write_archives
- for year, month in months
- write_file("#{year}/#{month}/index.html", render_month(year, month))
+ # Return all posts with any of given tags.
+ def posts_with_tags(tags)
+ return [] if tags.nil? or tags.empty?
+ tags = tags.split(',').map { |t| t.strip } if tags.is_a?(String)
+
+ posts.select do |post|
+ tags.any? do |tag|
+ post.tag_list.include?(tag)
+ end
end
end
- # Write category summaries.
- def write_categories
- for category in categories
- write_file("categories/#{urlify category['name']}.html", render_category(category))
- end
+ # Return all archives as tuples of [year, month].
+ def archives
+ posts.map { |p| [p.year, p.month] }.uniq.sort
end
- # Write rss feeds for index page and categories.
- def write_feeds
- write_file("index.rss", render_index_feed)
- for category in categories
- write_file("categories/#{urlify category['name']}.rss", render_category_feed(category))
- end
- end
-
- # Render everything to public folder.
- def write_all
- load_aggregations
- reload
-
- write_index_page
- write_pages
- write_posts
- write_archives
- write_categories
- write_feeds
- end
-
end
-
+
end