zine 0.1.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.
- checksums.yaml +7 -0
 - data/CHANGELOG.md +241 -0
 - data/LICENSE +21 -0
 - data/README.md +82 -0
 - data/bin/console +14 -0
 - data/bin/setup +8 -0
 - data/bin/zine +5 -0
 - data/lib/zine.rb +156 -0
 - data/lib/zine/cli.rb +57 -0
 - data/lib/zine/data_page.rb +23 -0
 - data/lib/zine/feed.rb +44 -0
 - data/lib/zine/page.rb +118 -0
 - data/lib/zine/post.rb +40 -0
 - data/lib/zine/server.rb +40 -0
 - data/lib/zine/skeleton/source/about.md +5 -0
 - data/lib/zine/skeleton/source/posts/2017-01-25-my-new-blog.md +11 -0
 - data/lib/zine/skeleton/source/screen.css +1 -0
 - data/lib/zine/skeleton/source/templates/default.erb +8 -0
 - data/lib/zine/skeleton/source/templates/footer_partial.erb +11 -0
 - data/lib/zine/skeleton/source/templates/header_partial.erb +23 -0
 - data/lib/zine/skeleton/source/templates/home.erb +18 -0
 - data/lib/zine/skeleton/source/templates/new_post.erb +11 -0
 - data/lib/zine/skeleton/source/templates/post.erb +16 -0
 - data/lib/zine/skeleton/source/templates/post_index.erb +15 -0
 - data/lib/zine/skeleton/source/templates/tag.erb +15 -0
 - data/lib/zine/skeleton/source/templates/tag_index.erb +15 -0
 - data/lib/zine/skeleton/zine.yaml +26 -0
 - data/lib/zine/tag.rb +57 -0
 - data/lib/zine/templates.rb +14 -0
 - data/lib/zine/version.rb +3 -0
 - metadata +200 -0
 
    
        data/lib/zine/cli.rb
    ADDED
    
    | 
         @@ -0,0 +1,57 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'thor'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'rainbow'
         
     | 
| 
      
 3 
     | 
    
         
            +
            require 'time'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'yaml'
         
     | 
| 
      
 5 
     | 
    
         
            +
            require 'zine'
         
     | 
| 
      
 6 
     | 
    
         
            +
            require 'zine/version'
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
            module Zine
         
     | 
| 
      
 9 
     | 
    
         
            +
              # CLI for zine
         
     | 
| 
      
 10 
     | 
    
         
            +
              class CLI < Thor
         
     | 
| 
      
 11 
     | 
    
         
            +
                include Thor::Actions
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                no_commands do
         
     | 
| 
      
 14 
     | 
    
         
            +
                  def init_site
         
     | 
| 
      
 15 
     | 
    
         
            +
                    @site ||= Zine::Site.new
         
     | 
| 
      
 16 
     | 
    
         
            +
                  end
         
     | 
| 
      
 17 
     | 
    
         
            +
                end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                desc 'build', 'Build the site'
         
     | 
| 
      
 20 
     | 
    
         
            +
                def build
         
     | 
| 
      
 21 
     | 
    
         
            +
                  init_site
         
     | 
| 
      
 22 
     | 
    
         
            +
                  @site.build_site
         
     | 
| 
      
 23 
     | 
    
         
            +
                  puts Rainbow('Site built').green
         
     | 
| 
      
 24 
     | 
    
         
            +
                end
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                desc 'nuke', 'Delete the build folder'
         
     | 
| 
      
 27 
     | 
    
         
            +
                def nuke
         
     | 
| 
      
 28 
     | 
    
         
            +
                  init_site
         
     | 
| 
      
 29 
     | 
    
         
            +
                  FileUtils.remove_dir @site.options['directories']['build'], force: true
         
     | 
| 
      
 30 
     | 
    
         
            +
                  puts Rainbow('Site nuked. It\'s the only way to be sure.').green
         
     | 
| 
      
 31 
     | 
    
         
            +
                end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                desc 'post TITLE', 'Create the file for a new blog post, titled TITLE'
         
     | 
| 
      
 34 
     | 
    
         
            +
                def post(name)
         
     | 
| 
      
 35 
     | 
    
         
            +
                  init_site
         
     | 
| 
      
 36 
     | 
    
         
            +
                  option_dir = @site.options['directories']
         
     | 
| 
      
 37 
     | 
    
         
            +
                  Zine::CLI.source_root option_dir['templates']
         
     | 
| 
      
 38 
     | 
    
         
            +
                  @date = DateTime.now
         
     | 
| 
      
 39 
     | 
    
         
            +
                  @name = name
         
     | 
| 
      
 40 
     | 
    
         
            +
                  file = "#{@date.strftime('%Y-%m-%d')}-#{Zine::Page.slug(name)}.md"
         
     | 
| 
      
 41 
     | 
    
         
            +
                  template 'new_post.erb',
         
     | 
| 
      
 42 
     | 
    
         
            +
                           File.join(Dir.pwd, option_dir['posts'], file)
         
     | 
| 
      
 43 
     | 
    
         
            +
                end
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                desc 'site', 'Create the skeleton of a new site (overwriting files)'
         
     | 
| 
      
 46 
     | 
    
         
            +
                def site
         
     | 
| 
      
 47 
     | 
    
         
            +
                  @skeleton_dir = File.join File.dirname(__FILE__), 'skeleton', '/.'
         
     | 
| 
      
 48 
     | 
    
         
            +
                  FileUtils.cp_r @skeleton_dir, Dir.pwd
         
     | 
| 
      
 49 
     | 
    
         
            +
                  puts Rainbow('New skeleton site created').green
         
     | 
| 
      
 50 
     | 
    
         
            +
                end
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
                desc 'version', 'Show the version number'
         
     | 
| 
      
 53 
     | 
    
         
            +
                def version
         
     | 
| 
      
 54 
     | 
    
         
            +
                  puts VERSION
         
     | 
| 
      
 55 
     | 
    
         
            +
                end
         
     | 
| 
      
 56 
     | 
    
         
            +
              end
         
     | 
| 
      
 57 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,23 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'zine/page'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Zine
         
     | 
| 
      
 4 
     | 
    
         
            +
              # A page where the content comes from an array, usually an array of
         
     | 
| 
      
 5 
     | 
    
         
            +
              # links to other pages, eg an index page like the home page
         
     | 
| 
      
 6 
     | 
    
         
            +
              class DataPage < Zine::Page
         
     | 
| 
      
 7 
     | 
    
         
            +
                def initialize(data, templates, site_options)
         
     | 
| 
      
 8 
     | 
    
         
            +
                  init_templates(templates)
         
     | 
| 
      
 9 
     | 
    
         
            +
                  @formatted_data = FormattedData.new({}, site_options)
         
     | 
| 
      
 10 
     | 
    
         
            +
                  @formatted_data.page[:title] = data[:title]
         
     | 
| 
      
 11 
     | 
    
         
            +
                  @formatted_data.data = data[:post_array]
         
     | 
| 
      
 12 
     | 
    
         
            +
                  @dest_path = File.join(data[:build_dir],
         
     | 
| 
      
 13 
     | 
    
         
            +
                                         Zine::Page.slug(data[:name]) + '.html')
         
     | 
| 
      
 14 
     | 
    
         
            +
                  write
         
     | 
| 
      
 15 
     | 
    
         
            +
                end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                def write
         
     | 
| 
      
 18 
     | 
    
         
            +
                  html = template_the_html
         
     | 
| 
      
 19 
     | 
    
         
            +
                  compressor = HtmlCompressor::Compressor.new
         
     | 
| 
      
 20 
     | 
    
         
            +
                  File.write(@dest_path, compressor.compress(html))
         
     | 
| 
      
 21 
     | 
    
         
            +
                end
         
     | 
| 
      
 22 
     | 
    
         
            +
              end
         
     | 
| 
      
 23 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/zine/feed.rb
    ADDED
    
    | 
         @@ -0,0 +1,44 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'rss'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'uri'
         
     | 
| 
      
 3 
     | 
    
         
            +
            # require 'zine/page'
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            module Zine # < Zine::Page
         
     | 
| 
      
 6 
     | 
    
         
            +
              # produce the RSS/Atom feed for the site
         
     | 
| 
      
 7 
     | 
    
         
            +
              class Feed
         
     | 
| 
      
 8 
     | 
    
         
            +
                def initialize(post_array, options)
         
     | 
| 
      
 9 
     | 
    
         
            +
                  @post_array = post_array
         
     | 
| 
      
 10 
     | 
    
         
            +
                  @options = options['options']
         
     | 
| 
      
 11 
     | 
    
         
            +
                  @rss = create_rss
         
     | 
| 
      
 12 
     | 
    
         
            +
                  @dest_path = File.join(options['directories']['build'], 'rss.xml')
         
     | 
| 
      
 13 
     | 
    
         
            +
                end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                def create_rss
         
     | 
| 
      
 16 
     | 
    
         
            +
                  RSS::Maker.make('atom') do |maker|
         
     | 
| 
      
 17 
     | 
    
         
            +
                    maker.channel.author = @options['site_author']
         
     | 
| 
      
 18 
     | 
    
         
            +
                    maker.channel.updated = @post_array[0].formatted_data
         
     | 
| 
      
 19 
     | 
    
         
            +
                                                          .page[:date_rfc3339].to_s
         
     | 
| 
      
 20 
     | 
    
         
            +
                    maker.channel.about = (URI.join @options['site_URL'], 'rss.xml').to_s
         
     | 
| 
      
 21 
     | 
    
         
            +
                    maker.channel.title = @options['site_name']
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                    @post_array.each do |post|
         
     | 
| 
      
 24 
     | 
    
         
            +
                      maker.items.new_item do |item|
         
     | 
| 
      
 25 
     | 
    
         
            +
                        data = post.formatted_data
         
     | 
| 
      
 26 
     | 
    
         
            +
                        meta = data.page
         
     | 
| 
      
 27 
     | 
    
         
            +
                        item.link = data.uri
         
     | 
| 
      
 28 
     | 
    
         
            +
                        item.title = meta[:title]
         
     | 
| 
      
 29 
     | 
    
         
            +
                        item.updated = meta[:date_rfc3339].to_s
         
     | 
| 
      
 30 
     | 
    
         
            +
                        # item.content.content = data.html
         
     | 
| 
      
 31 
     | 
    
         
            +
                        # item.content.type = 'html'
         
     | 
| 
      
 32 
     | 
    
         
            +
                        # =><content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">
         
     | 
| 
      
 33 
     | 
    
         
            +
                        item.content.type = 'xhtml'
         
     | 
| 
      
 34 
     | 
    
         
            +
                        item.content.xml_content = data.html
         
     | 
| 
      
 35 
     | 
    
         
            +
                      end
         
     | 
| 
      
 36 
     | 
    
         
            +
                    end
         
     | 
| 
      
 37 
     | 
    
         
            +
                  end # rss
         
     | 
| 
      
 38 
     | 
    
         
            +
                end # fn
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
                def process
         
     | 
| 
      
 41 
     | 
    
         
            +
                  File.write(@dest_path, @rss)
         
     | 
| 
      
 42 
     | 
    
         
            +
                end
         
     | 
| 
      
 43 
     | 
    
         
            +
              end
         
     | 
| 
      
 44 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/zine/page.rb
    ADDED
    
    | 
         @@ -0,0 +1,118 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'erb'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'date'
         
     | 
| 
      
 3 
     | 
    
         
            +
            require 'htmlcompressor'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'kramdown'
         
     | 
| 
      
 5 
     | 
    
         
            +
            require 'pathname'
         
     | 
| 
      
 6 
     | 
    
         
            +
            require 'rainbow'
         
     | 
| 
      
 7 
     | 
    
         
            +
            require 'yaml'
         
     | 
| 
      
 8 
     | 
    
         
            +
            require 'zine'
         
     | 
| 
      
 9 
     | 
    
         
            +
            require 'zine/templates'
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
            module Zine
         
     | 
| 
      
 12 
     | 
    
         
            +
              # A page on the site where the content comes from a file's markdown, and the
         
     | 
| 
      
 13 
     | 
    
         
            +
              # destination's location mirrors its own
         
     | 
| 
      
 14 
     | 
    
         
            +
              class Page
         
     | 
| 
      
 15 
     | 
    
         
            +
                attr_reader :formatted_data
         
     | 
| 
      
 16 
     | 
    
         
            +
                # the meta data, passed formatted to the template
         
     | 
| 
      
 17 
     | 
    
         
            +
                class FormattedData
         
     | 
| 
      
 18 
     | 
    
         
            +
                  attr_accessor :data
         
     | 
| 
      
 19 
     | 
    
         
            +
                  attr_accessor :footer_partial
         
     | 
| 
      
 20 
     | 
    
         
            +
                  attr_accessor :header_partial
         
     | 
| 
      
 21 
     | 
    
         
            +
                  attr_accessor :html
         
     | 
| 
      
 22 
     | 
    
         
            +
                  attr_reader :page
         
     | 
| 
      
 23 
     | 
    
         
            +
                  attr_accessor :uri
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                  def initialize(front_matter, site_opt)
         
     | 
| 
      
 26 
     | 
    
         
            +
                    @page = { date_rfc3339: front_matter['date'],
         
     | 
| 
      
 27 
     | 
    
         
            +
                              date_us: parse_date(front_matter['date']),
         
     | 
| 
      
 28 
     | 
    
         
            +
                              github_name: site_opt['options']['github_name'],
         
     | 
| 
      
 29 
     | 
    
         
            +
                              num_items_on_home: site_opt['options']['num_items_on_home'],
         
     | 
| 
      
 30 
     | 
    
         
            +
                              site_author: site_opt['options']['site_author'],
         
     | 
| 
      
 31 
     | 
    
         
            +
                              site_description: site_opt['options']['site_description'],
         
     | 
| 
      
 32 
     | 
    
         
            +
                              site_name: site_opt['options']['site_name'],
         
     | 
| 
      
 33 
     | 
    
         
            +
                              site_URL: site_opt['options']['site_URL'],
         
     | 
| 
      
 34 
     | 
    
         
            +
                              tags: slugify_tags(front_matter['tags']),
         
     | 
| 
      
 35 
     | 
    
         
            +
                              title: front_matter['title'],
         
     | 
| 
      
 36 
     | 
    
         
            +
                              twitter_name: site_opt['options']['twitter_name'] }
         
     | 
| 
      
 37 
     | 
    
         
            +
                  end
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                  def parse_date(_d)
         
     | 
| 
      
 40 
     | 
    
         
            +
                    DateTime.rfc3339(front_matter['date']).strftime('%B %-d, %Y')
         
     | 
| 
      
 41 
     | 
    
         
            +
                  rescue
         
     | 
| 
      
 42 
     | 
    
         
            +
                    ''
         
     | 
| 
      
 43 
     | 
    
         
            +
                  end
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                  def public_binding
         
     | 
| 
      
 46 
     | 
    
         
            +
                    binding
         
     | 
| 
      
 47 
     | 
    
         
            +
                  end
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
                  def slugify_tags(tags)
         
     | 
| 
      
 50 
     | 
    
         
            +
                    return unless tags && tags.any?
         
     | 
| 
      
 51 
     | 
    
         
            +
                    tags.map { |tag| { name: tag, tag_slug: Page.slug(tag) } }
         
     | 
| 
      
 52 
     | 
    
         
            +
                  end
         
     | 
| 
      
 53 
     | 
    
         
            +
                end
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
                # the Tags on a Post
         
     | 
| 
      
 56 
     | 
    
         
            +
                TagData = Struct.new(:tagsArray, :destURL, :pageTitle, :pageDate,
         
     | 
| 
      
 57 
     | 
    
         
            +
                                     :pageDateUS)
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
                def initialize(md_file_name, dest, templates, site_options)
         
     | 
| 
      
 60 
     | 
    
         
            +
                  file_parts = File.open(md_file_name, 'r').read.split('---')
         
     | 
| 
      
 61 
     | 
    
         
            +
                  @formatted_data = FormattedData.new(parse_yaml(file_parts[1]),
         
     | 
| 
      
 62 
     | 
    
         
            +
                                                      site_options)
         
     | 
| 
      
 63 
     | 
    
         
            +
                  @dest_path = dest
         
     | 
| 
      
 64 
     | 
    
         
            +
                  @raw_text = file_parts[2]
         
     | 
| 
      
 65 
     | 
    
         
            +
                  init_templates(templates)
         
     | 
| 
      
 66 
     | 
    
         
            +
                end
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
                def init_templates(templates)
         
     | 
| 
      
 69 
     | 
    
         
            +
                  @header_partial = templates.header
         
     | 
| 
      
 70 
     | 
    
         
            +
                  @footer_partial = templates.footer
         
     | 
| 
      
 71 
     | 
    
         
            +
                  @template = templates.body
         
     | 
| 
      
 72 
     | 
    
         
            +
                end
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
      
 74 
     | 
    
         
            +
                def parse_markdown
         
     | 
| 
      
 75 
     | 
    
         
            +
                  @formatted_data.html = Kramdown::Document.new(
         
     | 
| 
      
 76 
     | 
    
         
            +
                    @raw_text,
         
     | 
| 
      
 77 
     | 
    
         
            +
                    input: 'GFM',
         
     | 
| 
      
 78 
     | 
    
         
            +
                    auto_ids: false,
         
     | 
| 
      
 79 
     | 
    
         
            +
                    smart_quotes: %w(apos apos quot quot),
         
     | 
| 
      
 80 
     | 
    
         
            +
                    syntax_highlighter: 'rouge'
         
     | 
| 
      
 81 
     | 
    
         
            +
                  ).to_html
         
     | 
| 
      
 82 
     | 
    
         
            +
                end
         
     | 
| 
      
 83 
     | 
    
         
            +
             
     | 
| 
      
 84 
     | 
    
         
            +
                def parse_yaml(text)
         
     | 
| 
      
 85 
     | 
    
         
            +
                  YAML.safe_load text
         
     | 
| 
      
 86 
     | 
    
         
            +
                rescue Psych::Exception
         
     | 
| 
      
 87 
     | 
    
         
            +
                  puts Rainbow("Could not parse front matter for: #{md_file_name}").red
         
     | 
| 
      
 88 
     | 
    
         
            +
                  { 'date' => DateTime.now.to_s, 'title' => md_file_name, 'tags' => [] }
         
     | 
| 
      
 89 
     | 
    
         
            +
                end
         
     | 
| 
      
 90 
     | 
    
         
            +
             
     | 
| 
      
 91 
     | 
    
         
            +
                def rel_path_from_build_dir(path)
         
     | 
| 
      
 92 
     | 
    
         
            +
                  full = Pathname(path)
         
     | 
| 
      
 93 
     | 
    
         
            +
                  full.relative_path_from(Pathname(@build_dir))
         
     | 
| 
      
 94 
     | 
    
         
            +
                end
         
     | 
| 
      
 95 
     | 
    
         
            +
             
     | 
| 
      
 96 
     | 
    
         
            +
                def process
         
     | 
| 
      
 97 
     | 
    
         
            +
                  parse_markdown
         
     | 
| 
      
 98 
     | 
    
         
            +
                  html = template_the_html
         
     | 
| 
      
 99 
     | 
    
         
            +
             
     | 
| 
      
 100 
     | 
    
         
            +
                  compressor = HtmlCompressor::Compressor.new
         
     | 
| 
      
 101 
     | 
    
         
            +
                  File.write(@dest_path, compressor.compress(html))
         
     | 
| 
      
 102 
     | 
    
         
            +
                end
         
     | 
| 
      
 103 
     | 
    
         
            +
             
     | 
| 
      
 104 
     | 
    
         
            +
                def self.slug(text)
         
     | 
| 
      
 105 
     | 
    
         
            +
                  text.downcase
         
     | 
| 
      
 106 
     | 
    
         
            +
                      .gsub(/[^a-z0-9]+/, '-')
         
     | 
| 
      
 107 
     | 
    
         
            +
                      .gsub(/^-|-$/, '')
         
     | 
| 
      
 108 
     | 
    
         
            +
                end
         
     | 
| 
      
 109 
     | 
    
         
            +
             
     | 
| 
      
 110 
     | 
    
         
            +
                def template_the_html
         
     | 
| 
      
 111 
     | 
    
         
            +
                  @formatted_data.header_partial = @header_partial.result(@formatted_data
         
     | 
| 
      
 112 
     | 
    
         
            +
                    .public_binding)
         
     | 
| 
      
 113 
     | 
    
         
            +
                  @formatted_data.footer_partial = @footer_partial.result(@formatted_data
         
     | 
| 
      
 114 
     | 
    
         
            +
                    .public_binding)
         
     | 
| 
      
 115 
     | 
    
         
            +
                  @template.result(@formatted_data.public_binding)
         
     | 
| 
      
 116 
     | 
    
         
            +
                end
         
     | 
| 
      
 117 
     | 
    
         
            +
              end
         
     | 
| 
      
 118 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/zine/post.rb
    ADDED
    
    | 
         @@ -0,0 +1,40 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'uri'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Zine
         
     | 
| 
      
 4 
     | 
    
         
            +
              # A post - content comes from the markdown, and the destination from the date
         
     | 
| 
      
 5 
     | 
    
         
            +
              class Post < Page
         
     | 
| 
      
 6 
     | 
    
         
            +
                def initialize(md_file_name, templates, site_options)
         
     | 
| 
      
 7 
     | 
    
         
            +
                  file_parts = File.open(md_file_name, 'r').read.split('---')
         
     | 
| 
      
 8 
     | 
    
         
            +
                  @formatted_data = FormattedData.new(parse_yaml(file_parts[1]),
         
     | 
| 
      
 9 
     | 
    
         
            +
                                                      site_options)
         
     | 
| 
      
 10 
     | 
    
         
            +
                  @raw_text = file_parts[2]
         
     | 
| 
      
 11 
     | 
    
         
            +
                  init_templates(templates)
         
     | 
| 
      
 12 
     | 
    
         
            +
                  option_dir = site_options['directories']
         
     | 
| 
      
 13 
     | 
    
         
            +
                  @build_dir = option_dir['build'] # for tags
         
     | 
| 
      
 14 
     | 
    
         
            +
                  @dest_path = make_path_from_date option_dir['blog']
         
     | 
| 
      
 15 
     | 
    
         
            +
                end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                def make_path_from_date(build_dir)
         
     | 
| 
      
 18 
     | 
    
         
            +
                  page_data = @formatted_data.page
         
     | 
| 
      
 19 
     | 
    
         
            +
                  date = DateTime.parse(page_data[:date_rfc3339])
         
     | 
| 
      
 20 
     | 
    
         
            +
                  dest_dir = File.join(build_dir,
         
     | 
| 
      
 21 
     | 
    
         
            +
                                       date.strftime('%Y'),
         
     | 
| 
      
 22 
     | 
    
         
            +
                                       date.strftime('%-m'))
         
     | 
| 
      
 23 
     | 
    
         
            +
                  FileUtils.mkdir_p dest_dir
         
     | 
| 
      
 24 
     | 
    
         
            +
                  slg = Zine::Page.slug(page_data[:title]) + '.html'
         
     | 
| 
      
 25 
     | 
    
         
            +
                  @dest_path = File.join(dest_dir, slg)
         
     | 
| 
      
 26 
     | 
    
         
            +
                end
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                def process
         
     | 
| 
      
 29 
     | 
    
         
            +
                  super
         
     | 
| 
      
 30 
     | 
    
         
            +
                  page_data = @formatted_data.page
         
     | 
| 
      
 31 
     | 
    
         
            +
                  file_path = rel_path_from_build_dir(@dest_path).to_s
         
     | 
| 
      
 32 
     | 
    
         
            +
                  @formatted_data.uri = URI.join(page_data[:site_URL], file_path).to_s
         
     | 
| 
      
 33 
     | 
    
         
            +
                  TagData.new(page_data[:tags],
         
     | 
| 
      
 34 
     | 
    
         
            +
                              file_path,
         
     | 
| 
      
 35 
     | 
    
         
            +
                              page_data[:title],
         
     | 
| 
      
 36 
     | 
    
         
            +
                              page_data[:date_rfc3339],
         
     | 
| 
      
 37 
     | 
    
         
            +
                              page_data[:date_us])
         
     | 
| 
      
 38 
     | 
    
         
            +
                end
         
     | 
| 
      
 39 
     | 
    
         
            +
              end
         
     | 
| 
      
 40 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/zine/server.rb
    ADDED
    
    | 
         @@ -0,0 +1,40 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'rainbow'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'rack'
         
     | 
| 
      
 3 
     | 
    
         
            +
            require 'thin'
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            module Zine
         
     | 
| 
      
 6 
     | 
    
         
            +
              # Local preview web server
         
     | 
| 
      
 7 
     | 
    
         
            +
              class Server
         
     | 
| 
      
 8 
     | 
    
         
            +
                def initialize(root)
         
     | 
| 
      
 9 
     | 
    
         
            +
                  motd
         
     | 
| 
      
 10 
     | 
    
         
            +
                  Thin::Server.start('127.0.0.1', 8080) do
         
     | 
| 
      
 11 
     | 
    
         
            +
                    use Rack::Static,
         
     | 
| 
      
 12 
     | 
    
         
            +
                        urls: ['/'],
         
     | 
| 
      
 13 
     | 
    
         
            +
                        index: 'index.html',
         
     | 
| 
      
 14 
     | 
    
         
            +
                        root: root
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                    now = Time.now
         
     | 
| 
      
 17 
     | 
    
         
            +
                    a_long_time = 100**4
         
     | 
| 
      
 18 
     | 
    
         
            +
                    run lambda { |_env|
         
     | 
| 
      
 19 
     | 
    
         
            +
                      [200,
         
     | 
| 
      
 20 
     | 
    
         
            +
                       {
         
     | 
| 
      
 21 
     | 
    
         
            +
                         'Content-Type'  => 'text/html',
         
     | 
| 
      
 22 
     | 
    
         
            +
                         'ETag'          => nil,
         
     | 
| 
      
 23 
     | 
    
         
            +
                         'Last-Modified' => now + a_long_time,
         
     | 
| 
      
 24 
     | 
    
         
            +
                         'Cache-Control' =>
         
     | 
| 
      
 25 
     | 
    
         
            +
                          'no-store, no-cache, must-revalidate, post-check=0, pre-check=0',
         
     | 
| 
      
 26 
     | 
    
         
            +
                         'Pragma'        => 'no-cache',
         
     | 
| 
      
 27 
     | 
    
         
            +
                         'Expires'       => now - a_long_time
         
     | 
| 
      
 28 
     | 
    
         
            +
                       },
         
     | 
| 
      
 29 
     | 
    
         
            +
                       File.open(File.join(root, 'index.html'), File::RDONLY)]
         
     | 
| 
      
 30 
     | 
    
         
            +
                    }
         
     | 
| 
      
 31 
     | 
    
         
            +
                  end
         
     | 
| 
      
 32 
     | 
    
         
            +
                end
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                def motd
         
     | 
| 
      
 35 
     | 
    
         
            +
                  puts "\nPreview running on " +
         
     | 
| 
      
 36 
     | 
    
         
            +
                       Rainbow('http://127.0.0.1:8080/').blue.underline +
         
     | 
| 
      
 37 
     | 
    
         
            +
                       "\nCommand double click the URL to open, Control C to quit\n"
         
     | 
| 
      
 38 
     | 
    
         
            +
                end
         
     | 
| 
      
 39 
     | 
    
         
            +
              end
         
     | 
| 
      
 40 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            *{margin:0;padding:0}html,body{height:100%}body{background-color:#fff;font-family:GillSansRegular,'Gill Sans MT','Gill Sans','Century Gothic',Calibri,'Trebuchet MS',sans-serif;line-height:1.618;color:#333;text-align:center;font-weight:300}h1,h2,h3,h4,h5,h6{color:#333;letter-spacing:.1em}h1 a,h2 a,h3 a,h4 a,h5 a,h6 a{color:#414f7c;text-decoration:none}h1 a:hover,h2 a:hover,h3 a:hover,h4 a:hover,h5 a:hover,h6 a:hover{color:#212721}h1{font-weight:300;font-size:2.618em;margin:1.809em 0 .809em}h2{font-weight:300;font-size:1.618em;margin:1.809em 0 .809em}h3,h4,h5,h6{font-weight:400;font-size:1em;margin:1.809em 0 .809em}p{margin:1em 0}a{color:#414f7c}a:hover{color:#212721}section{margin-bottom:1.618em}section>section{margin-bottom:3.236em}body>header{width:43em;text-align:center;margin:0 auto 0}body>header a{text-decoration:none;margin-left:.5em;margin-right:.5em}body>header,body>main,body>footer{display:block}body>header a{color:#414f7c}body>header a:hover{color:#212721}body>header a.extra{color:#414f7c;margin-left:1em}body>header a.extra:hover{color:#212721}body>header nav ul li{display:inline;list-style:none}.button{width:30px;height:30px;display:inline-block;background-size:100%;text-indent:-999em;text-align:left;margin:20px}.twitter{background:url('/assets/webicon-twitter-m.png');background-image:url('/assets/webicon-twitter.svg'),none}.rss{background:url('/assets/webicon-rss-m.png');background-image:url('/assets/webicon-rss.svg'),none}main{text-align:left;width:43em;margin:3em auto 2em}main li{margin-left:2.618em}.meta{color:#667}footer{width:43em;color:#667;border-top:4px solid #ddd;margin:3em auto 2em;overflow:hidden}footer .contact{float:left;margin-right:3em}footer .contact a,.tags a{color:#414f7c;text-decoration:none}footer .contact a:hover,.tags a:hover{color:#212721;text-decoration:none}.tags ul li{list-style:none;display:inline;font-variant:small-caps;font-size:1.2em}.archive a{text-decoration:none}ul.archive,ul.archive ul{margin-left:0}ul.archive li,ul.archive ul li{list-style:none;margin-left:0}.post pre{border:1px solid #ddd;background-color:#fff;padding:0 .4em}p.date{color:#667}pre{background-color:#eee;padding:1em;white-space:pre-wrap;white-space:-moz-pre-wrap;white-space:-pre-wrap;white-space:-o-pre-wrap;word-wrap:break-word}code{font-family:Consolas,Menlo,Monaco,'Lucida Console','Courier New',monospace,serif;font-size:.8em}blockquote{margin:2em 2em 2em 1em;padding:0 .75em 0 1.25em;border-left:2px solid #ddd;border-right:0 solid #ddd}@media all and (max-width:736px){body>header,main,footer{width:86%;margin:0 auto 0;padding:12px 24px 12px}p{margin-bottom:2em}.button{width:50px;height:50px;margin:20px}}
         
     | 
| 
         @@ -0,0 +1,11 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
              <footer>
         
     | 
| 
      
 2 
     | 
    
         
            +
                <div class="contact">
         
     | 
| 
      
 3 
     | 
    
         
            +
                  <p>Twitter: <a href="https://twitter.com/<%= page[:twitter_name] %>">@<%= page[:twitter_name] %></a></p>
         
     | 
| 
      
 4 
     | 
    
         
            +
                </div>
         
     | 
| 
      
 5 
     | 
    
         
            +
                <div class="contact">
         
     | 
| 
      
 6 
     | 
    
         
            +
                  <p>© 2017<span> <%= page[:site_author] %></span>
         
     | 
| 
      
 7 
     | 
    
         
            +
                  </p>
         
     | 
| 
      
 8 
     | 
    
         
            +
                </div>
         
     | 
| 
      
 9 
     | 
    
         
            +
              </footer>
         
     | 
| 
      
 10 
     | 
    
         
            +
              </body>
         
     | 
| 
      
 11 
     | 
    
         
            +
            </html>
         
     | 
| 
         @@ -0,0 +1,23 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            <!DOCTYPE html>
         
     | 
| 
      
 2 
     | 
    
         
            +
            <html lang="en">
         
     | 
| 
      
 3 
     | 
    
         
            +
              <head>
         
     | 
| 
      
 4 
     | 
    
         
            +
                <meta charset="utf-8">
         
     | 
| 
      
 5 
     | 
    
         
            +
                <meta name="viewport" content="width=device-width,user-scalable=yes">
         
     | 
| 
      
 6 
     | 
    
         
            +
                <meta name="description" content="<%= page[:site_description] %>">
         
     | 
| 
      
 7 
     | 
    
         
            +
                <title><%= page[:site_name] %> | <%= page[:title] %></title>
         
     | 
| 
      
 8 
     | 
    
         
            +
                <link rel="home" href="<%= page[:site_URL] %>/rss.xml" type="application/rss+xml" title="<%= page[:site_name] %>">
         
     | 
| 
      
 9 
     | 
    
         
            +
                <link rel="stylesheet" href="/screen.css">
         
     | 
| 
      
 10 
     | 
    
         
            +
                <link rel="apple-touch-icon" href="/apple-touch-icon.png">
         
     | 
| 
      
 11 
     | 
    
         
            +
              </head>
         
     | 
| 
      
 12 
     | 
    
         
            +
              <body>
         
     | 
| 
      
 13 
     | 
    
         
            +
                <header>
         
     | 
| 
      
 14 
     | 
    
         
            +
                  <div class="logo"></div>
         
     | 
| 
      
 15 
     | 
    
         
            +
                  <h1><a href="<%= page[:site_URL] %>"><%= page[:site_name] %></a></h1>
         
     | 
| 
      
 16 
     | 
    
         
            +
                  <nav>
         
     | 
| 
      
 17 
     | 
    
         
            +
                    <ul>
         
     | 
| 
      
 18 
     | 
    
         
            +
                      <li><a href="<%= page[:site_URL] %>">Home</a></li>
         
     | 
| 
      
 19 
     | 
    
         
            +
                      <li><a href="/articles.html">Articles</a></li>
         
     | 
| 
      
 20 
     | 
    
         
            +
                      <li><a href="/about.html">About</a></li>
         
     | 
| 
      
 21 
     | 
    
         
            +
                    </ul><a href="https://twitter.com/<%= page[:twitter_name] %>" class="button twitter">Argue with me on Twitter</a><a href="<%= page[:site_URL] %>/rss.xml" rel="home" type="application/rss+xml" class="button rss">RSS Feed</a>
         
     | 
| 
      
 22 
     | 
    
         
            +
                  </nav>
         
     | 
| 
      
 23 
     | 
    
         
            +
                </header>
         
     | 
| 
         @@ -0,0 +1,18 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            <%= header_partial %>
         
     | 
| 
      
 2 
     | 
    
         
            +
            <main>
         
     | 
| 
      
 3 
     | 
    
         
            +
              <section>
         
     | 
| 
      
 4 
     | 
    
         
            +
                <% for @post in data %>
         
     | 
| 
      
 5 
     | 
    
         
            +
                  <h2><%= @post[:page][:title] %></h2>
         
     | 
| 
      
 6 
     | 
    
         
            +
                  <p class="date"><%= @post[:page][:date_us] %></p>
         
     | 
| 
      
 7 
     | 
    
         
            +
                  <%= @post[:html] %>
         
     | 
| 
      
 8 
     | 
    
         
            +
                  <div class="tags">Tags:
         
     | 
| 
      
 9 
     | 
    
         
            +
                    <ul>
         
     | 
| 
      
 10 
     | 
    
         
            +
                      <% for @tag in @post[:page][:tags] %>
         
     | 
| 
      
 11 
     | 
    
         
            +
                        <li><a href="/tags/<%= @tag[:tag_slug] %>.html"><%= @tag[:name] %></a></li>
         
     | 
| 
      
 12 
     | 
    
         
            +
                      <% end %>
         
     | 
| 
      
 13 
     | 
    
         
            +
                    </ul>
         
     | 
| 
      
 14 
     | 
    
         
            +
                  </div>
         
     | 
| 
      
 15 
     | 
    
         
            +
                <% end %>
         
     | 
| 
      
 16 
     | 
    
         
            +
              </section>
         
     | 
| 
      
 17 
     | 
    
         
            +
            </main>
         
     | 
| 
      
 18 
     | 
    
         
            +
            <%= footer_partial %>
         
     | 
| 
         @@ -0,0 +1,16 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            <%= header_partial %>
         
     | 
| 
      
 2 
     | 
    
         
            +
            <main>
         
     | 
| 
      
 3 
     | 
    
         
            +
              <section>
         
     | 
| 
      
 4 
     | 
    
         
            +
                <h2><%= page[:title] %></h2>
         
     | 
| 
      
 5 
     | 
    
         
            +
                <p class="date"><%= page[:date_us] %></p>
         
     | 
| 
      
 6 
     | 
    
         
            +
                <%= html %>
         
     | 
| 
      
 7 
     | 
    
         
            +
                <div class="tags">Tags:
         
     | 
| 
      
 8 
     | 
    
         
            +
                  <ul>
         
     | 
| 
      
 9 
     | 
    
         
            +
                    <% for @tag in page[:tags] %>
         
     | 
| 
      
 10 
     | 
    
         
            +
                      <li><a href="/tags/<%= @tag[:tag_slug] %>.html"><%= @tag[:name] %></a></li>
         
     | 
| 
      
 11 
     | 
    
         
            +
                    <% end %>
         
     | 
| 
      
 12 
     | 
    
         
            +
                  </ul>
         
     | 
| 
      
 13 
     | 
    
         
            +
                </div>
         
     | 
| 
      
 14 
     | 
    
         
            +
              </section>
         
     | 
| 
      
 15 
     | 
    
         
            +
            </main>
         
     | 
| 
      
 16 
     | 
    
         
            +
            <%= footer_partial %>
         
     |