retter 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +1 -0
- data/.travis.yml +1 -0
- data/README.md +54 -4
- data/bin/retter +2 -0
- data/lib/retter/command.rb +37 -41
- data/lib/retter/config.rb +94 -84
- data/lib/retter/entries.rb +93 -0
- data/lib/retter/entry.rb +46 -9
- data/lib/retter/generator/skel/images/orange/ic_li01.gif +0 -0
- data/lib/retter/generator/skel/layouts/article.html.haml +16 -3
- data/lib/retter/generator/skel/layouts/entries.html.haml +2 -2
- data/lib/retter/generator/skel/layouts/entry.html.haml +17 -3
- data/lib/retter/generator/skel/layouts/index.html.haml +14 -4
- data/lib/retter/generator/skel/stylesheets/base.css +1 -1
- data/lib/retter/generator/skel/stylesheets/orange.css +17 -2
- data/lib/retter/page/view_helper.rb +33 -0
- data/lib/retter/page.rb +86 -0
- data/lib/retter/pages/archive.rb +13 -0
- data/lib/retter/pages/article.rb +35 -0
- data/lib/retter/pages/entry.rb +28 -0
- data/lib/retter/pages/feed.rb +46 -0
- data/lib/retter/pages/index.rb +13 -0
- data/lib/retter/pages/profile.rb +13 -0
- data/lib/retter/pages.rb +40 -0
- data/lib/retter/preprint.rb +21 -0
- data/lib/retter/{stationery/renderer.rb → renderer.rb} +1 -1
- data/lib/retter/repository.rb +21 -0
- data/lib/retter/version.rb +1 -1
- data/lib/retter.rb +36 -3
- data/retter.gemspec +31 -0
- data/spec/command/callback_spec.rb +1 -1
- data/spec/command/commit_spec.rb +1 -1
- data/spec/command/edit_spec.rb +1 -1
- data/spec/command/invoke_after_spec.rb +2 -2
- data/spec/command/list_spec.rb +47 -0
- data/spec/command/open_spec.rb +1 -1
- data/spec/command/preview_spec.rb +1 -1
- data/spec/command/rebind_spec.rb +8 -8
- data/spec/spec_helper.rb +2 -0
- data/spec/support/stream_capture.rb +16 -0
- metadata +84 -39
- data/lib/retter/stationery/binder.rb +0 -150
- data/lib/retter/stationery/previewer.rb +0 -64
- data/lib/retter/stationery/view.rb +0 -68
- data/lib/retter/stationery.rb +0 -47
    
        data/.gitignore
    CHANGED
    
    
    
        data/.travis.yml
    CHANGED
    
    
    
        data/README.md
    CHANGED
    
    | @@ -66,7 +66,7 @@ You can use `retter` command anywhere, If you set `$RETTER_HOME` variable. | |
| 66 66 |  | 
| 67 67 | 
             
            作業ディレクトリにRetterfileがある場合は、そのディレクトリが`$RETTER_HOME`に指定されているものとして動作します。
         | 
| 68 68 |  | 
| 69 | 
            -
            ### 記事を書く - Write an  | 
| 69 | 
            +
            ### 記事を書く - Write an entry
         | 
| 70 70 |  | 
| 71 71 | 
             
            `retter`コマンドは設定されているエディタを起動します。今のところMarkdown形式で記事を書くことができます。
         | 
| 72 72 |  | 
| @@ -151,15 +151,65 @@ To publish, use the git command. Or, upload the file to your server. | |
| 151 151 |  | 
| 152 152 | 
             
            後述するコールバックを設定しておくことで、さらに手数を減らすことも可能です。
         | 
| 153 153 |  | 
| 154 | 
            -
            ### 特定の日付の記事を編集する - Edit  | 
| 154 | 
            +
            ### 特定の日付の記事を編集する - Edit entry (specific date).
         | 
| 155 155 |  | 
| 156 156 | 
             
            昨日、明日、過去や未来の日付を指定して記事を編集・プレビューするには、 `--date` オプションを用います。
         | 
| 157 157 |  | 
| 158 158 | 
             
            `--date` option is available in `edit` `preview` sub-command.
         | 
| 159 159 |  | 
| 160 160 | 
             
            ~~~~
         | 
| 161 | 
            -
              retter  | 
| 162 | 
            -
              retter preview --date 20110101
         | 
| 161 | 
            +
              retter --date 20110101         # 編集
         | 
| 162 | 
            +
              retter preview --date 20110101 # プレビュー
         | 
| 163 | 
            +
            ~~~~
         | 
| 164 | 
            +
             | 
| 165 | 
            +
            サブコマンドを明示する場合は、日付の指定は引数のように指定することもできます(`--date`が不要になります)。
         | 
| 166 | 
            +
             | 
| 167 | 
            +
            ~~~~
         | 
| 168 | 
            +
              retter edit 20110101
         | 
| 169 | 
            +
              retter preview 20110101
         | 
| 170 | 
            +
            ~~~~
         | 
| 171 | 
            +
             | 
| 172 | 
            +
            日付は相対的に指定することができます。以下のような形式をサポートします。
         | 
| 173 | 
            +
             | 
| 174 | 
            +
            ~~~~
         | 
| 175 | 
            +
              retter edit yesterday    # 昨日
         | 
| 176 | 
            +
              retter edit today        # 今日
         | 
| 177 | 
            +
              retter edit tommorow     # 明日
         | 
| 178 | 
            +
             | 
| 179 | 
            +
              retter edit '3 days ago' # 3日前
         | 
| 180 | 
            +
              retter edit 3.days.ago   # 3日前
         | 
| 181 | 
            +
              retter edit 3.days.since # 3日後
         | 
| 182 | 
            +
              retter edit 1.week.ago   # 1週間前
         | 
| 183 | 
            +
              retter edit 3.weeks.ago  # 3週間前
         | 
| 184 | 
            +
              retter edit 3.months.ago # 3カ月前
         | 
| 185 | 
            +
              retter edit 3.years.ago  # 3年前
         | 
| 186 | 
            +
            ~~~~
         | 
| 187 | 
            +
             | 
| 188 | 
            +
            ### 記事の一覧を出力する - Browse entries
         | 
| 189 | 
            +
             | 
| 190 | 
            +
            これまでに書いた記事の一覧を出力することができます。すべての一覧を出力するため、`less`や`lv`、`grep`などで適宜フィルタしてください。
         | 
| 191 | 
            +
             | 
| 192 | 
            +
            ~~~~
         | 
| 193 | 
            +
              retter list
         | 
| 194 | 
            +
              [e0] 2011-10-12
         | 
| 195 | 
            +
                記事ごとにPermlinkがつくようにした, retter 0.1.0
         | 
| 196 | 
            +
             | 
| 197 | 
            +
              [e1] 2011-10-10
         | 
| 198 | 
            +
                Rubyのトップレベルについて整理する
         | 
| 199 | 
            +
             | 
| 200 | 
            +
              [e2] 2011-10-03
         | 
| 201 | 
            +
                モジュール関数がprivateな理由
         | 
| 202 | 
            +
             | 
| 203 | 
            +
              [e3] 2011-09-19
         | 
| 204 | 
            +
                スタイルシートを追加してテーマを変えられるようにした
         | 
| 205 | 
            +
            ~~~~
         | 
| 206 | 
            +
             | 
| 207 | 
            +
            日付の左側に表示されている文字列は、編集やプレビューの際の記事の指定に使うことができます。
         | 
| 208 | 
            +
             | 
| 209 | 
            +
            ~~~~
         | 
| 210 | 
            +
              retter edit e3
         | 
| 211 | 
            +
              retter preview e3
         | 
| 212 | 
            +
              retter preview --key e3
         | 
| 163 213 | 
             
            ~~~~
         | 
| 164 214 |  | 
| 165 215 | 
             
            ### コールバック - Callbacks
         | 
    
        data/bin/retter
    CHANGED
    
    
    
        data/lib/retter/command.rb
    CHANGED
    
    | @@ -1,47 +1,50 @@ | |
| 1 1 | 
             
            # coding: utf-8
         | 
| 2 2 |  | 
| 3 3 | 
             
            class Retter::Command < Thor
         | 
| 4 | 
            +
              include Retter::Stationery
         | 
| 5 | 
            +
             | 
| 4 6 | 
             
              map '-v' => :version,
         | 
| 5 7 | 
             
                  '-e' => :edit,
         | 
| 6 8 | 
             
                  '-p' => :preview,
         | 
| 7 9 | 
             
                  '-o' => :open,
         | 
| 8 10 | 
             
                  '-r' => :rebind,
         | 
| 9 | 
            -
                  '-b' => :bind | 
| 10 | 
            -
                  '-h' => :home
         | 
| 11 | 
            +
                  '-b' => :bind
         | 
| 11 12 |  | 
| 12 13 | 
             
              desc 'edit', 'Open $EDITOR. Write an article with Markdown.'
         | 
| 13 | 
            -
              method_options date: :string, silent: :boolean
         | 
| 14 | 
            -
              def edit
         | 
| 15 | 
            -
                 | 
| 14 | 
            +
              method_options date: :string, key: :string, silent: :boolean
         | 
| 15 | 
            +
              def edit(date_or_index = options[:date] || options[:key])
         | 
| 16 | 
            +
                entry = entries.detect_by_string(date_or_index)
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                system config.editor, entry.path
         | 
| 16 19 |  | 
| 17 | 
            -
                invoke_after :edit unless  | 
| 20 | 
            +
                invoke_after :edit unless silent?
         | 
| 18 21 | 
             
              end
         | 
| 19 22 |  | 
| 20 23 | 
             
              default_task :edit
         | 
| 21 24 |  | 
| 22 25 | 
             
              desc 'preview', 'Preview the draft article (browser will open).'
         | 
| 23 | 
            -
              method_options date: :string
         | 
| 24 | 
            -
              def preview
         | 
| 25 | 
            -
                 | 
| 26 | 
            +
              method_options date: :string, key: :string
         | 
| 27 | 
            +
              def preview(date_or_index = options[:date] || options[:key])
         | 
| 28 | 
            +
                entry = entries.detect_by_string(date_or_index)
         | 
| 26 29 |  | 
| 27 | 
            -
                 | 
| 28 | 
            -
             | 
| 30 | 
            +
                preprint.print entry
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                Launchy.open preprint.path
         | 
| 29 33 | 
             
              end
         | 
| 30 34 |  | 
| 31 35 | 
             
              desc 'open', 'Open your (static) site top page (browser will open).'
         | 
| 32 36 | 
             
              def open
         | 
| 33 | 
            -
                Launchy.open  | 
| 37 | 
            +
                Launchy.open pages.index.path
         | 
| 34 38 | 
             
              end
         | 
| 35 39 |  | 
| 36 40 | 
             
              desc 'rebind', 'Bind the draft article, re-generate all html pages.'
         | 
| 37 41 | 
             
              method_options silent: :boolean
         | 
| 38 42 | 
             
              def rebind
         | 
| 39 | 
            -
                 | 
| 43 | 
            +
                entries.commit_wip_entry!
         | 
| 40 44 |  | 
| 41 | 
            -
                 | 
| 42 | 
            -
                binder.rebind!
         | 
| 45 | 
            +
                pages.bind!
         | 
| 43 46 |  | 
| 44 | 
            -
                unless  | 
| 47 | 
            +
                unless silent?
         | 
| 45 48 | 
             
                  invoke_after :bind
         | 
| 46 49 | 
             
                  invoke_after :rebind
         | 
| 47 50 | 
             
                end
         | 
| @@ -54,14 +57,21 @@ class Retter::Command < Thor | |
| 54 57 | 
             
              desc 'commit', "cd $RETTER_HOME && git add . && git commit -m 'Retter commit'"
         | 
| 55 58 | 
             
              method_options silent: :boolean
         | 
| 56 59 | 
             
              def commit
         | 
| 57 | 
            -
                 | 
| 58 | 
            -
             | 
| 59 | 
            -
             | 
| 60 | 
            +
                repository.open do |git|
         | 
| 61 | 
            +
                  say git.add(config.retter_home), :green
         | 
| 62 | 
            +
                  say git.commit_all('Retter commit'), :green
         | 
| 63 | 
            +
                end
         | 
| 60 64 |  | 
| 61 | 
            -
                 | 
| 62 | 
            -
             | 
| 65 | 
            +
                invoke_after :commit unless silent?
         | 
| 66 | 
            +
              end
         | 
| 63 67 |  | 
| 64 | 
            -
             | 
| 68 | 
            +
              desc 'list', 'List retters'
         | 
| 69 | 
            +
              def list
         | 
| 70 | 
            +
                entries.each_with_index do |entry, n|
         | 
| 71 | 
            +
                  say "[e#{n}] #{entry.date}"
         | 
| 72 | 
            +
                  say "  #{entry.articles.map(&:title).join(', ')}"
         | 
| 73 | 
            +
                  say
         | 
| 74 | 
            +
                end
         | 
| 65 75 | 
             
              end
         | 
| 66 76 |  | 
| 67 77 | 
             
              desc 'home', 'Open a new shell in $RETTER_HOME'
         | 
| @@ -81,6 +91,9 @@ class Retter::Command < Thor | |
| 81 91 | 
             
              desc 'new', 'Create a new site'
         | 
| 82 92 | 
             
              def new; end
         | 
| 83 93 |  | 
| 94 | 
            +
              desc 'gen', 'Generate initial files'
         | 
| 95 | 
            +
              def gen; end
         | 
| 96 | 
            +
             | 
| 84 97 | 
             
              desc 'usage', 'Show usage.'
         | 
| 85 98 | 
             
              def usage
         | 
| 86 99 | 
             
                say Retter::Command.usage, :green
         | 
| @@ -93,25 +106,8 @@ class Retter::Command < Thor | |
| 93 106 |  | 
| 94 107 | 
             
              private
         | 
| 95 108 |  | 
| 96 | 
            -
              def  | 
| 97 | 
            -
                 | 
| 98 | 
            -
                  config.retter_file(Date.parse(options[:date]))
         | 
| 99 | 
            -
                else
         | 
| 100 | 
            -
                  todays_file = config.retter_file(Date.today)
         | 
| 101 | 
            -
                  todays_file.exist? ? todays_file : config.wip_file
         | 
| 102 | 
            -
                end
         | 
| 103 | 
            -
              end
         | 
| 104 | 
            -
             | 
| 105 | 
            -
              def detected_date
         | 
| 106 | 
            -
                options[:date] ? Date.parse(options[:date]) : Date.today
         | 
| 107 | 
            -
              end
         | 
| 108 | 
            -
             | 
| 109 | 
            -
              def config
         | 
| 110 | 
            -
                @retter_config ||= Retter::Config.new(ENV)
         | 
| 111 | 
            -
              rescue Retter::EnvError
         | 
| 112 | 
            -
                say 'Set $RETTER_HOME and $EDITOR, first.', :red
         | 
| 113 | 
            -
                say Retter::Command.usage, :green
         | 
| 114 | 
            -
                exit 1
         | 
| 109 | 
            +
              def silent?
         | 
| 110 | 
            +
                !options[:silent].nil?
         | 
| 115 111 | 
             
              end
         | 
| 116 112 |  | 
| 117 113 | 
             
              def invoke_after(name)
         | 
    
        data/lib/retter/config.rb
    CHANGED
    
    | @@ -1,102 +1,112 @@ | |
| 1 1 | 
             
            # coding: utf-8
         | 
| 2 2 |  | 
| 3 | 
            -
             | 
| 4 | 
            -
               | 
| 5 | 
            -
                :editor,
         | 
| 6 | 
            -
                :shell,
         | 
| 7 | 
            -
                :title,
         | 
| 8 | 
            -
                :description,
         | 
| 9 | 
            -
                :url,
         | 
| 10 | 
            -
                :author,
         | 
| 11 | 
            -
                :retters_dir,
         | 
| 12 | 
            -
                :wip_file,
         | 
| 13 | 
            -
                :layouts_dir,
         | 
| 14 | 
            -
                :layout_file,
         | 
| 15 | 
            -
                :profile_layout_file,
         | 
| 16 | 
            -
                :entry_layout_file,
         | 
| 17 | 
            -
                :article_layout_file,
         | 
| 18 | 
            -
                :entries_layout_file,
         | 
| 19 | 
            -
                :index_layout_file,
         | 
| 20 | 
            -
                :entries_dir,
         | 
| 21 | 
            -
                :profile_file,
         | 
| 22 | 
            -
                :index_file,
         | 
| 23 | 
            -
                :entries_file,
         | 
| 24 | 
            -
                :feed_file
         | 
| 25 | 
            -
              ]
         | 
| 3 | 
            +
            module Retter
         | 
| 4 | 
            +
              class EnvError < RuntimeError; end
         | 
| 26 5 |  | 
| 27 | 
            -
               | 
| 28 | 
            -
                 | 
| 29 | 
            -
                   | 
| 30 | 
            -
             | 
| 31 | 
            -
                   | 
| 32 | 
            -
             | 
| 33 | 
            -
             | 
| 6 | 
            +
              class Config
         | 
| 7 | 
            +
                ATTRIBUTES = [
         | 
| 8 | 
            +
                  :editor,
         | 
| 9 | 
            +
                  :shell,
         | 
| 10 | 
            +
                  :title,
         | 
| 11 | 
            +
                  :description,
         | 
| 12 | 
            +
                  :url,
         | 
| 13 | 
            +
                  :author,
         | 
| 14 | 
            +
                  :retters_dir,
         | 
| 15 | 
            +
                  :wip_file,
         | 
| 16 | 
            +
                  :layouts_dir,
         | 
| 17 | 
            +
                  :layout_file,
         | 
| 18 | 
            +
                  :profile_layout_file,
         | 
| 19 | 
            +
                  :entry_layout_file,
         | 
| 20 | 
            +
                  :article_layout_file,
         | 
| 21 | 
            +
                  :entries_layout_file,
         | 
| 22 | 
            +
                  :index_layout_file,
         | 
| 23 | 
            +
                  :entries_dir,
         | 
| 24 | 
            +
                  :profile_file,
         | 
| 25 | 
            +
                  :index_file,
         | 
| 26 | 
            +
                  :entries_file,
         | 
| 27 | 
            +
                  :feed_file
         | 
| 28 | 
            +
                ]
         | 
| 34 29 |  | 
| 35 | 
            -
             | 
| 30 | 
            +
                ATTRIBUTES.each do |att|
         | 
| 31 | 
            +
                  class_eval <<-EOM
         | 
| 32 | 
            +
                    def #{att}(val = nil)
         | 
| 33 | 
            +
                      val ? @options[:#{att}] = val : @options[:#{att}]
         | 
| 34 | 
            +
                    end
         | 
| 35 | 
            +
                  EOM
         | 
| 36 | 
            +
                end
         | 
| 36 37 |  | 
| 37 | 
            -
             | 
| 38 | 
            -
                @env, @options = env, {}
         | 
| 39 | 
            -
                @after_callbacks = {}
         | 
| 38 | 
            +
                attr_reader :retter_home
         | 
| 40 39 |  | 
| 41 | 
            -
                 | 
| 42 | 
            -
             | 
| 40 | 
            +
                def initialize(env)
         | 
| 41 | 
            +
                  @env, @options = env, {}
         | 
| 42 | 
            +
                  @after_callbacks = {}
         | 
| 43 43 |  | 
| 44 | 
            -
             | 
| 45 | 
            -
             | 
| 46 | 
            -
             | 
| 47 | 
            -
             | 
| 44 | 
            +
                  detect_retter_home
         | 
| 45 | 
            +
                  unless env.values_at('EDITOR', 'RETTER_HOME').all?
         | 
| 46 | 
            +
                    raise Retter::EnvError, 'Set $RETTER_HOME and $EDITOR, first.'
         | 
| 47 | 
            +
                  end
         | 
| 48 48 |  | 
| 49 | 
            -
             | 
| 50 | 
            -
             | 
| 51 | 
            -
             | 
| 52 | 
            -
             | 
| 53 | 
            -
             | 
| 54 | 
            -
             | 
| 55 | 
            -
             | 
| 56 | 
            -
                 | 
| 57 | 
            -
                profile_layout_file layouts_dir.join('profile.html.haml')
         | 
| 58 | 
            -
                entry_layout_file   layouts_dir.join('entry.html.haml')
         | 
| 59 | 
            -
                article_layout_file layouts_dir.join('article.html.haml')
         | 
| 60 | 
            -
                entries_layout_file layouts_dir.join('entries.html.haml')
         | 
| 61 | 
            -
                index_layout_file   layouts_dir.join('index.html.haml')
         | 
| 62 | 
            -
                entries_dir         retter_home.join('entries/')
         | 
| 63 | 
            -
                profile_file        retter_home.join('profile.html')
         | 
| 64 | 
            -
                index_file          retter_home.join('index.html')
         | 
| 65 | 
            -
                entries_file        retter_home.join('entries.html')
         | 
| 66 | 
            -
                feed_file           retter_home.join('entries.rss')
         | 
| 67 | 
            -
              end
         | 
| 49 | 
            +
                  @retter_home = Pathname.new(@env['RETTER_HOME'])
         | 
| 50 | 
            +
                  load_defaults
         | 
| 51 | 
            +
                  load_retterfile_if_exists
         | 
| 52 | 
            +
                  rescue Retter::EnvError
         | 
| 53 | 
            +
                    $stderr.puts 'Set $RETTER_HOME and $EDITOR, first.'
         | 
| 54 | 
            +
                    say Retter::Command.usage, :green
         | 
| 55 | 
            +
                    exit 1
         | 
| 56 | 
            +
                end
         | 
| 68 57 |  | 
| 69 | 
            -
             | 
| 70 | 
            -
             | 
| 71 | 
            -
             | 
| 72 | 
            -
             | 
| 58 | 
            +
                def load_defaults
         | 
| 59 | 
            +
                  editor              @env['EDITOR']
         | 
| 60 | 
            +
                  shell               @env['SHELL']
         | 
| 61 | 
            +
                  url                 'http://example.com'
         | 
| 62 | 
            +
                  retters_dir         retter_home.join('retters/')
         | 
| 63 | 
            +
                  wip_file            retters_dir.join('today.md')
         | 
| 64 | 
            +
                  layouts_dir         retter_home.join('layouts/')
         | 
| 65 | 
            +
                  layout_file         layouts_dir.join('retter.html.haml')
         | 
| 66 | 
            +
                  profile_layout_file layouts_dir.join('profile.html.haml')
         | 
| 67 | 
            +
                  entry_layout_file   layouts_dir.join('entry.html.haml')
         | 
| 68 | 
            +
                  article_layout_file layouts_dir.join('article.html.haml')
         | 
| 69 | 
            +
                  entries_layout_file layouts_dir.join('entries.html.haml')
         | 
| 70 | 
            +
                  index_layout_file   layouts_dir.join('index.html.haml')
         | 
| 71 | 
            +
                  entries_dir         retter_home.join('entries/')
         | 
| 72 | 
            +
                  profile_file        retter_home.join('profile.html')
         | 
| 73 | 
            +
                  index_file          retter_home.join('index.html')
         | 
| 74 | 
            +
                  entries_file        retter_home.join('entries.html')
         | 
| 75 | 
            +
                  feed_file           retter_home.join('entries.rss')
         | 
| 76 | 
            +
                end
         | 
| 73 77 |  | 
| 74 | 
            -
             | 
| 75 | 
            -
             | 
| 76 | 
            -
             | 
| 77 | 
            -
             | 
| 78 | 
            +
                def load_retterfile_if_exists
         | 
| 79 | 
            +
                  retterfile = retter_home.join('Retterfile')
         | 
| 80 | 
            +
                  instance_eval retterfile.read, retterfile.to_s if retterfile.exist?
         | 
| 81 | 
            +
                end
         | 
| 78 82 |  | 
| 79 | 
            -
             | 
| 80 | 
            -
             | 
| 81 | 
            -
             | 
| 83 | 
            +
                def detect_retter_home
         | 
| 84 | 
            +
                  # TODO こういうの上のディレクトリも見て判断するのを何か参考にして書く
         | 
| 85 | 
            +
                  @env['RETTER_HOME'] = Dir.pwd if File.exist? 'Retterfile'
         | 
| 86 | 
            +
                end
         | 
| 82 87 |  | 
| 83 | 
            -
             | 
| 84 | 
            -
             | 
| 85 | 
            -
             | 
| 88 | 
            +
                def retter_file(date)
         | 
| 89 | 
            +
                  retters_dir.join(date ? date.strftime("%Y%m%d.md") : "today.md")
         | 
| 90 | 
            +
                end
         | 
| 86 91 |  | 
| 87 | 
            -
             | 
| 88 | 
            -
             | 
| 89 | 
            -
             | 
| 92 | 
            +
                def entry_file(date)
         | 
| 93 | 
            +
                  entries_dir.join date.strftime('%Y%m%d.html')
         | 
| 94 | 
            +
                end
         | 
| 90 95 |  | 
| 91 | 
            -
             | 
| 92 | 
            -
             | 
| 93 | 
            -
             | 
| 96 | 
            +
                def entry_dir(date)
         | 
| 97 | 
            +
                  entries_dir.join date.strftime('%Y%m%d')
         | 
| 98 | 
            +
                end
         | 
| 94 99 |  | 
| 95 | 
            -
             | 
| 96 | 
            -
             | 
| 97 | 
            -
             | 
| 98 | 
            -
             | 
| 99 | 
            -
             | 
| 100 | 
            +
                def self.delegatables
         | 
| 101 | 
            +
                  ATTRIBUTES + [:retter_file, :entry_file, :entry_dir]
         | 
| 102 | 
            +
                end
         | 
| 103 | 
            +
             | 
| 104 | 
            +
                def after(name, sym = nil, &block)
         | 
| 105 | 
            +
                  if callback = sym || block
         | 
| 106 | 
            +
                    @after_callbacks[name] = callback
         | 
| 107 | 
            +
                  else
         | 
| 108 | 
            +
                    @after_callbacks[name]
         | 
| 109 | 
            +
                  end
         | 
| 100 110 | 
             
                end
         | 
| 101 111 | 
             
              end
         | 
| 102 112 | 
             
            end
         | 
| @@ -0,0 +1,93 @@ | |
| 1 | 
            +
            # coding: utf-8
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require 'active_support/core_ext/object'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            module Retter
         | 
| 6 | 
            +
              class Entries < Array
         | 
| 7 | 
            +
                include Retter::Stationery
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                def initialize
         | 
| 10 | 
            +
                  load_entries config.retters_dir
         | 
| 11 | 
            +
                end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                def detect_by_string(str)
         | 
| 14 | 
            +
                  case str
         | 
| 15 | 
            +
                  when nil, ''
         | 
| 16 | 
            +
                    detect_by_today or wip_entry
         | 
| 17 | 
            +
                  when /^e([0-9]+)$/
         | 
| 18 | 
            +
                    index = $1.to_i
         | 
| 19 | 
            +
                    self[index] or wip_entry
         | 
| 20 | 
            +
                  else
         | 
| 21 | 
            +
                    date = parse_date_string(str)
         | 
| 22 | 
            +
                    detect_by_date(date) || wip_entry(date)
         | 
| 23 | 
            +
                  end
         | 
| 24 | 
            +
                end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                def detect_by_today
         | 
| 27 | 
            +
                  detect_by_date(Date.today)
         | 
| 28 | 
            +
                end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                def detect_by_date(date)
         | 
| 31 | 
            +
                  detect {|e| e.date == date }
         | 
| 32 | 
            +
                end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                def parse_date_string(date_str)
         | 
| 35 | 
            +
                  case date_str
         | 
| 36 | 
            +
                  when /^yesterday$/i then 1.day.ago
         | 
| 37 | 
            +
                  when /^today$/i     then 0.day.ago
         | 
| 38 | 
            +
                  when /^tomorrow$/i  then 1.day.since
         | 
| 39 | 
            +
                  when /^[0-9]+[\.\s](?:days?|weeks?|months?|years?)[\.\s](?:ago|since)$/i
         | 
| 40 | 
            +
                    eval(date_str.gsub(/\s+/, '.')).to_date
         | 
| 41 | 
            +
                  else
         | 
| 42 | 
            +
                    Date.parse(date_str)
         | 
| 43 | 
            +
                  end
         | 
| 44 | 
            +
                end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                def wip_entry(date = nil)
         | 
| 47 | 
            +
                  wip_file = config.retter_file(date)
         | 
| 48 | 
            +
                  wip_date = date || Date.today
         | 
| 49 | 
            +
                  wip_body = wip_file.exist? ? wip_file.read : ''
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                  Retter::Entry.new date: wip_date, body: markupper.render(wip_body), pathname: wip_file
         | 
| 52 | 
            +
                end
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                def commit_wip_entry!
         | 
| 55 | 
            +
                  if config.wip_file.exist?
         | 
| 56 | 
            +
                    copy = config.wip_file.read
         | 
| 57 | 
            +
                    config.retter_file(Date.today).open('a') {|f| f.puts copy }
         | 
| 58 | 
            +
                    config.wip_file.unlink
         | 
| 59 | 
            +
                  end
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                  Retter.reset_entries!
         | 
| 62 | 
            +
                end
         | 
| 63 | 
            +
             | 
| 64 | 
            +
                def load_entries(path)
         | 
| 65 | 
            +
                  date_files = find_markup_files(path).map {|file|
         | 
| 66 | 
            +
                    date_str = file.basename('.*').to_s
         | 
| 67 | 
            +
                    [Date.parse(date_str), file]
         | 
| 68 | 
            +
                  }.sort_by(&:first)
         | 
| 69 | 
            +
             | 
| 70 | 
            +
                  date_files.reverse_each {|date, file|
         | 
| 71 | 
            +
                    self << Retter::Entry.new(date: date, body: markupper.render(file.read))
         | 
| 72 | 
            +
                  }
         | 
| 73 | 
            +
                end
         | 
| 74 | 
            +
             | 
| 75 | 
            +
                def find_markup_files(path)
         | 
| 76 | 
            +
                  path = Pathname.new(path).realpath
         | 
| 77 | 
            +
                  Dir.open(path, &:to_a).grep(/^\d{4}(?:0[1-9]|1[012])(?:0[1-9]|[12][0-9]|3[01])\.(md)$/).map {|f| path.join f }
         | 
| 78 | 
            +
                end
         | 
| 79 | 
            +
             | 
| 80 | 
            +
                def markupper
         | 
| 81 | 
            +
                  @markupper ||= ::Redcarpet::Markdown.new(
         | 
| 82 | 
            +
                    Renderer,
         | 
| 83 | 
            +
                    autolink: true,
         | 
| 84 | 
            +
                    space_after_headers: true,
         | 
| 85 | 
            +
                    fenced_code_blocks: true,
         | 
| 86 | 
            +
                    strikethrough: true,
         | 
| 87 | 
            +
                    superscript: true,
         | 
| 88 | 
            +
                    fenced_code_blocks: true,
         | 
| 89 | 
            +
                    tables: true
         | 
| 90 | 
            +
                  )
         | 
| 91 | 
            +
                end
         | 
| 92 | 
            +
              end
         | 
| 93 | 
            +
            end
         | 
    
        data/lib/retter/entry.rb
    CHANGED
    
    | @@ -4,25 +4,67 @@ class Retter::Entry | |
| 4 4 | 
             
              class Article
         | 
| 5 5 | 
             
                attr_accessor :entry, :id, :title, :body
         | 
| 6 6 |  | 
| 7 | 
            +
                def initialize(attrs = {})
         | 
| 8 | 
            +
                  @id, @entry, @title, @body = attrs.values_at(:id, :entry, :title, :body)
         | 
| 9 | 
            +
                end
         | 
| 10 | 
            +
             | 
| 7 11 | 
             
                def to_s
         | 
| 8 12 | 
             
                  body
         | 
| 9 13 | 
             
                end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                def next
         | 
| 16 | 
            +
                  articles[index.next] || (entry.next && entry.next.articles.first)
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                def prev
         | 
| 20 | 
            +
                  index.pred < 0 ? (entry.prev && entry.prev.articles.last) : articles[index.pred]
         | 
| 21 | 
            +
                end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                def index
         | 
| 24 | 
            +
                  articles.index(self)
         | 
| 25 | 
            +
                end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                def articles
         | 
| 28 | 
            +
                  @articles ||= entry.articles
         | 
| 29 | 
            +
                end
         | 
| 10 30 | 
             
              end
         | 
| 11 31 |  | 
| 32 | 
            +
              include Retter::Stationery
         | 
| 33 | 
            +
             | 
| 12 34 | 
             
              attr_accessor :date, :lede, :body, :articles
         | 
| 35 | 
            +
              attr_reader :pathname
         | 
| 13 36 |  | 
| 14 37 | 
             
              def initialize(attrs={})
         | 
| 15 38 | 
             
                @date, @body = attrs.values_at(:date, :body)
         | 
| 16 39 |  | 
| 40 | 
            +
                pathname_by_date = Retter.config.retters_dir.join(date.strftime('%Y%m%d.md'))
         | 
| 41 | 
            +
                @pathname = attrs[:pathname] || pathname_by_date
         | 
| 42 | 
            +
             | 
| 17 43 | 
             
                attach_titles
         | 
| 18 44 | 
             
                extract_articles
         | 
| 19 45 | 
             
                load_lede
         | 
| 20 46 | 
             
              end
         | 
| 21 47 |  | 
| 48 | 
            +
              def path
         | 
| 49 | 
            +
                pathname.to_s
         | 
| 50 | 
            +
              end
         | 
| 51 | 
            +
             | 
| 22 52 | 
             
              def to_s
         | 
| 23 53 | 
             
                body
         | 
| 24 54 | 
             
              end
         | 
| 25 55 |  | 
| 56 | 
            +
              def next
         | 
| 57 | 
            +
                entries[index.next]
         | 
| 58 | 
            +
              end
         | 
| 59 | 
            +
             | 
| 60 | 
            +
              def prev
         | 
| 61 | 
            +
                entries[index.pred] unless index.pred < 0
         | 
| 62 | 
            +
              end
         | 
| 63 | 
            +
             | 
| 64 | 
            +
              def index
         | 
| 65 | 
            +
                entries.index(self) || 0
         | 
| 66 | 
            +
              end
         | 
| 67 | 
            +
             | 
| 26 68 | 
             
              private
         | 
| 27 69 |  | 
| 28 70 | 
             
              def body_elements
         | 
| @@ -41,16 +83,11 @@ class Retter::Entry | |
| 41 83 | 
             
              def extract_articles
         | 
| 42 84 | 
             
                @articles = body_elements.search('body > *').each_with_object([]) {|c, r|
         | 
| 43 85 | 
             
                  if c.name == 'h1'
         | 
| 44 | 
            -
                     | 
| 45 | 
            -
                    article.entry = self
         | 
| 46 | 
            -
                    article.id = c.attr('id')
         | 
| 47 | 
            -
                    article.title = c.text
         | 
| 48 | 
            -
                    article.body  = ''
         | 
| 49 | 
            -
                    r << article
         | 
| 86 | 
            +
                    r << Article.new(entry: self, id: c.attr('id'), title: c.text, body: '')
         | 
| 50 87 | 
             
                  else
         | 
| 51 | 
            -
                     | 
| 52 | 
            -
                    next if article.nil?
         | 
| 88 | 
            +
                    next if r.empty?
         | 
| 53 89 |  | 
| 90 | 
            +
                    article = r.last
         | 
| 54 91 | 
             
                    article.body += c.to_s
         | 
| 55 92 | 
             
                  end
         | 
| 56 93 | 
             
                } || []
         | 
| @@ -59,7 +96,7 @@ class Retter::Entry | |
| 59 96 | 
             
              def load_lede
         | 
| 60 97 | 
             
                @lede = body_elements.search('body > *').each_with_object('') {|c, r|
         | 
| 61 98 | 
             
                  break r if c.name == 'h1'
         | 
| 62 | 
            -
                  r<< c.to_s
         | 
| 99 | 
            +
                  r << c.to_s
         | 
| 63 100 | 
             
                }
         | 
| 64 101 | 
             
              end
         | 
| 65 102 | 
             
            end
         | 
| Binary file | 
| @@ -1,6 +1,19 @@ | |
| 1 | 
            -
            %article
         | 
| 1 | 
            +
            %article.autopagerize_page_element
         | 
| 2 2 | 
             
              %h1.date
         | 
| 3 | 
            -
                %a{href: entry_path(entry | 
| 3 | 
            +
                %a{href: entry_path(entry)}= entry.date
         | 
| 4 | 
            +
             | 
| 4 5 | 
             
              %h1{id: article.id}
         | 
| 5 | 
            -
                %a{href: article_path( | 
| 6 | 
            +
                %a{href: article_path(article)}= article.title
         | 
| 7 | 
            +
             | 
| 6 8 | 
             
              = article
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            .nav
         | 
| 11 | 
            +
              .prev
         | 
| 12 | 
            +
                - if prev_article = article.prev
         | 
| 13 | 
            +
                  %link{href: article_path(prev_article), rel: :prev}
         | 
| 14 | 
            +
             | 
| 15 | 
            +
              .next
         | 
| 16 | 
            +
                - if next_article = article.next
         | 
| 17 | 
            +
                  %link{href: article_path(next_article), rel: :next}
         | 
| 18 | 
            +
             | 
| 19 | 
            +
            .autopagerize_insert_before
         | 
| @@ -2,8 +2,8 @@ | |
| 2 2 | 
             
              %ul#entries
         | 
| 3 3 | 
             
                - entries.each do |entry|
         | 
| 4 4 | 
             
                  %li
         | 
| 5 | 
            -
                    %a.entry{href: entry_path(entry | 
| 5 | 
            +
                    %a.entry{href: entry_path(entry)}= entry.date
         | 
| 6 6 | 
             
                    %ul.titles
         | 
| 7 7 | 
             
                      - entry.articles.each do |article|
         | 
| 8 8 | 
             
                        %li
         | 
| 9 | 
            -
                          %a.title{href: article_path( | 
| 9 | 
            +
                          %a.title{href: article_path(article)}= article.title
         | 
| @@ -1,9 +1,23 @@ | |
| 1 | 
            -
            %article
         | 
| 1 | 
            +
            %article.autopagerize_page_element
         | 
| 2 2 | 
             
              %h1.date
         | 
| 3 | 
            -
                %a{href: entry_path(entry | 
| 3 | 
            +
                %a{href: entry_path(entry)}= entry.date
         | 
| 4 | 
            +
             | 
| 4 5 | 
             
              - unless entry.lede.empty?
         | 
| 5 6 | 
             
                = entry.lede
         | 
| 7 | 
            +
             | 
| 6 8 | 
             
              - entry.articles.each do |article|
         | 
| 7 9 | 
             
                %h1{id: article.id}
         | 
| 8 | 
            -
                  %a{href: article_path( | 
| 10 | 
            +
                  %a{href: article_path(article)}= article.title
         | 
| 11 | 
            +
             | 
| 9 12 | 
             
                = article
         | 
| 13 | 
            +
             | 
| 14 | 
            +
            .nav
         | 
| 15 | 
            +
              .prev
         | 
| 16 | 
            +
                - if prev_entry = entry.prev
         | 
| 17 | 
            +
                  %link{href: entry_path(prev_entry), rel: :prev}
         | 
| 18 | 
            +
             | 
| 19 | 
            +
              .next
         | 
| 20 | 
            +
                - if next_entry = entry.next
         | 
| 21 | 
            +
                  %link{href: entry_path(next_entry), rel: :next}
         | 
| 22 | 
            +
             | 
| 23 | 
            +
            .autopagerize_insert_before
         |