serif 0.2.3 → 0.3
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/Gemfile.lock +2 -0
- data/README.md +72 -7
- data/lib/serif/admin_server.rb +1 -1
- data/lib/serif/config.rb +1 -1
- data/lib/serif/content_file.rb +9 -2
- data/lib/serif/draft.rb +5 -0
- data/lib/serif/site.rb +20 -5
- data/lib/serif.rb +1 -0
- data/rakefile +28 -0
- data/serif.gemspec +3 -2
- data/statics/assets/js/attachment.js +33 -0
- data/test/draft_spec.rb +33 -0
- data/test/filters_spec.rb +17 -0
- data/test/site_dir/_site/drafts/another-sample-draft/{cdc8037ed098e34a19fc6671ab652f908dd94009ff642d4e5ee80fa566fa.html → f340ff2dd6aa78f819d547ee908fe7410e6153559b47265dcbc58598bb4a.html} +0 -0
- data/test/site_dir/_site/drafts/sample-draft/{f828e5f22d76b04c586e90680ac814e6b233d3d380f6be6975beba75081b.html → ed883ce827f757888e2900ce0e155a960cb45f832fcc24791c054013b71c.html} +0 -0
- data/test/site_dir/_site/index.html +3 -3
- data/test/site_dir/_site/test-smarty-filter.html +8 -0
- data/test/site_dir/_trash/1361224983-autopublish-draft +5 -0
- data/test/site_dir/_trash/{1361047797-test-draft → 1361224983-test-draft} +1 -1
- data/test/site_dir/test-smarty-filter.html +3 -0
- data/test/site_generation_spec.rb +5 -0
- metadata +24 -6
- data/test/site_dir/_trash/1361047797-autopublish-draft +0 -5
    
        data/Gemfile.lock
    CHANGED
    
    | @@ -10,6 +10,7 @@ PATH | |
| 10 10 | 
             
                  redhead (~> 0.0.8)
         | 
| 11 11 | 
             
                  sinatra (~> 1.3)
         | 
| 12 12 | 
             
                  slop (~> 3.3)
         | 
| 13 | 
            +
                  timeout_cache
         | 
| 13 14 |  | 
| 14 15 | 
             
            GEM
         | 
| 15 16 | 
             
              remote: http://rubygems.org/
         | 
| @@ -47,6 +48,7 @@ GEM | |
| 47 48 | 
             
                slop (3.4.3)
         | 
| 48 49 | 
             
                tilt (1.3.3)
         | 
| 49 50 | 
             
                timecop (0.5.9.2)
         | 
| 51 | 
            +
                timeout_cache (0.0.2)
         | 
| 50 52 | 
             
                yajl-ruby (1.1.0)
         | 
| 51 53 |  | 
| 52 54 | 
             
            PLATFORMS
         | 
    
        data/README.md
    CHANGED
    
    | @@ -6,7 +6,16 @@ Serif is a file-based blogging engine intended for simple sites. It compiles Mar | |
| 6 6 |  | 
| 7 7 | 
             
            # Changes and what's new
         | 
| 8 8 |  | 
| 9 | 
            -
            ## Latest release
         | 
| 9 | 
            +
            ## Latest release (v0.3)
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            * Add some caching to improve performance of post generation. (#29)
         | 
| 12 | 
            +
            * Remove super-linear performance cost of file_digest, reducing site generation time by > 85% for 50+ posts. (#30 -- charts available in the issue)
         | 
| 13 | 
            +
            * Make `site` available to both preview templates and archive templates. (c3e2f28)
         | 
| 14 | 
            +
            * Intelligently add blank lines before the markdown image text strings. (#27)
         | 
| 15 | 
            +
            * Add a `smarty` filter to do smarty processing without full Markdown. (#28)
         | 
| 16 | 
            +
            * Fix broken URL renames for drafts in the admin interface. (#31)
         | 
| 17 | 
            +
             | 
| 18 | 
            +
            ## v0.2.3
         | 
| 10 19 |  | 
| 11 20 | 
             
            * Support drag-and-drop image uploading in the admin interface, with customisable paths. (#18)
         | 
| 12 21 | 
             
            * Generate private preview files for drafts, and generate the site on every draft change. (#19, #24)
         | 
| @@ -29,6 +38,7 @@ See `CHANGELOG` for more. | |
| 29 38 | 
             
            * [Customising the admin interface](#customising-the-admin-interface)
         | 
| 30 39 | 
             
            * [Custom tags](#custom-tags)
         | 
| 31 40 | 
             
            * [Template variables](#template-variables)
         | 
| 41 | 
            +
            * [Developing Serif](#developing-serif)
         | 
| 32 42 |  | 
| 33 43 | 
             
            # Intro
         | 
| 34 44 |  | 
| @@ -61,6 +71,8 @@ The quickest way to get changes contributed: | |
| 61 71 | 
             
            3. Check out a branch on the latest master for your change: `git checkout -b master new-feature` --- do not make changes on `master`! Make sure that anything added or changed has a test in the `test/` directory. Use the existing files as examples. All tests for new/changed behaviour should pass.
         | 
| 62 72 | 
             
            4. [Send a pull request on GitHub](https://help.github.com/articles/fork-a-repo), including a description of what you've changed. (Note: your contribution will be assumed to be under the same terms of the project by default.)
         | 
| 63 73 |  | 
| 74 | 
            +
            For more info on development, see the section at the bottom of this README.
         | 
| 75 | 
            +
             | 
| 64 76 | 
             
            # Basics
         | 
| 65 77 |  | 
| 66 78 | 
             
            ## First time use
         | 
| @@ -218,7 +230,7 @@ admin: | |
| 218 230 | 
             
              username: username
         | 
| 219 231 | 
             
              password: password
         | 
| 220 232 | 
             
            permalink: /blog/:year/:month/:title
         | 
| 221 | 
            -
             | 
| 233 | 
            +
            image_upload_path: /images/:timestamp_:name
         | 
| 222 234 | 
             
            ```
         | 
| 223 235 |  | 
| 224 236 | 
             
            If a permalink setting is not given in the configuration, the default is `/:title`. There are the following options available for permalinks:
         | 
| @@ -232,7 +244,7 @@ Placeholder | Value | |
| 232 244 |  | 
| 233 245 | 
             
            ### Admin drag-and-drop upload path
         | 
| 234 246 |  | 
| 235 | 
            -
            The ` | 
| 247 | 
            +
            The `image_upload_path` configuration setting is an _absolute path_ and will be relative to the base directory of your site, used in the admin interface to control where files are sent. The default value is `/images/:timestamp_:name`. Similar to permalinks, the following placeholders are available:
         | 
| 236 248 |  | 
| 237 249 | 
             
            Placeholder | Value
         | 
| 238 250 | 
             
            ----------- |:-----
         | 
| @@ -243,13 +255,13 @@ Placeholder | Value | |
| 243 255 | 
             
            `:name`     | Original filename string of the image being uploaded
         | 
| 244 256 | 
             
            `:timestamp`| Unix timestamp, e.g., "1361057832685"
         | 
| 245 257 |  | 
| 246 | 
            -
            Any slashes in ` | 
| 258 | 
            +
            Any slashes in `image_upload_path` are converted to directories.
         | 
| 247 259 |  | 
| 248 260 | 
             
            ## Other files
         | 
| 249 261 |  | 
| 250 262 | 
             
            Any other file in the directory's root will be copied over exactly as-is, with two caveats.
         | 
| 251 263 |  | 
| 252 | 
            -
            First, `images/` is used for the drag-and-drop file uploads from the admin interface. Files are named with `< | 
| 264 | 
            +
            First, `images/` (by default) is used for the drag-and-drop file uploads from the admin interface. Files are named with `<timestamp>_ <name>.<extension>`. This is configurable, see the section on configuration.
         | 
| 253 265 |  | 
| 254 266 | 
             
            Second, for any file ending in `.html` or `.xml`:
         | 
| 255 267 |  | 
| @@ -386,14 +398,54 @@ The admin interface is intended to be a minimal place to focus on writing conten | |
| 386 398 | 
             
            /* more customisation below */
         | 
| 387 399 | 
             
            ```
         | 
| 388 400 |  | 
| 389 | 
            -
            # Custom tags
         | 
| 401 | 
            +
            # Custom tags and filters
         | 
| 390 402 |  | 
| 391 | 
            -
            These tags can be used in templates. For example:
         | 
| 403 | 
            +
            These tags can be used in templates, in addition to the [standard Liquid filters and tags](https://github.com/Shopify/liquid/wiki/Liquid-for-Designers). For example:
         | 
| 392 404 |  | 
| 393 405 | 
             
            ```
         | 
| 406 | 
            +
            {{ post.title | smarty }}
         | 
| 407 | 
            +
             | 
| 408 | 
            +
            {{ post.content | markdown }}
         | 
| 409 | 
            +
             | 
| 394 410 | 
             
            {% file_digest foo.css prefix:- %}
         | 
| 395 411 | 
             
            ```
         | 
| 396 412 |  | 
| 413 | 
            +
            ## List of filters
         | 
| 414 | 
            +
             | 
| 415 | 
            +
            * `date` with `'now'`
         | 
| 416 | 
            +
              
         | 
| 417 | 
            +
              This is a standard filter, but there is a [workaround](https://github.com/Shopify/liquid/pull/117) for
         | 
| 418 | 
            +
              `{{ 'now' | date: "%Y" }}` to work, so you can use this in templates.
         | 
| 419 | 
            +
             | 
| 420 | 
            +
            * `markdown`
         | 
| 421 | 
            +
              
         | 
| 422 | 
            +
              e.g., `{{ post.content | markdown }}`.
         | 
| 423 | 
            +
             | 
| 424 | 
            +
              This runs the given input through a Markdown + SmartyPants renderer, with fenced codeblocks enabled.
         | 
| 425 | 
            +
             | 
| 426 | 
            +
            * `strip`
         | 
| 427 | 
            +
              
         | 
| 428 | 
            +
              Strips trailing and leading whitespace.
         | 
| 429 | 
            +
             | 
| 430 | 
            +
              e.g., `{{ " hello " | strip }}` will render as `hello`.
         | 
| 431 | 
            +
             | 
| 432 | 
            +
            * `xmlschema`
         | 
| 433 | 
            +
              
         | 
| 434 | 
            +
              e.g., `{{ post.created | xmlschema }}`.
         | 
| 435 | 
            +
             | 
| 436 | 
            +
              Takes a Time value and returns an ISO8601-format string, as per Ruby's `Time#xmlschema` definition.
         | 
| 437 | 
            +
             | 
| 438 | 
            +
              Example output: 2013-02-16T23:55:22+01:00
         | 
| 439 | 
            +
             | 
| 440 | 
            +
              If the time value is in UTC: 2013-02-16T22:55:22Z
         | 
| 441 | 
            +
             | 
| 442 | 
            +
            * `encode_uri_component`
         | 
| 443 | 
            +
              
         | 
| 444 | 
            +
              e.g., `example.com/foo?url=http://mysite.com{{ post.url | encode_uri_component }}`
         | 
| 445 | 
            +
             | 
| 446 | 
            +
              Intended to provide the functionality of JavaScript's `encode_uri_component()` function. Essentially:
         | 
| 447 | 
            +
              encodes the entire input so it is usable as a query string parameter.
         | 
| 448 | 
            +
             | 
| 397 449 | 
             
            ## List of tags
         | 
| 398 450 |  | 
| 399 451 | 
             
            * `file_digest <path> [prefix:<prefix>]`
         | 
| @@ -415,3 +467,16 @@ These are available on individual post pages, in `_template/post.html`. | |
| 415 467 | 
             
            * `{{ post }}` --- the post being processed. Allows access to variables like `post.url`, `post.title`, `post.slug`, `post.created` and `post.content`.
         | 
| 416 468 | 
             
            * `{{ prev_post }}` --- the post published chronologically before `post`.
         | 
| 417 469 | 
             
            * `{{ next_post }}` --- the post published chronologically after `post`.
         | 
| 470 | 
            +
             | 
| 471 | 
            +
            # Developing Serif
         | 
| 472 | 
            +
             | 
| 473 | 
            +
            ## Broad outline
         | 
| 474 | 
            +
             | 
| 475 | 
            +
            * `./bin/serif {dev,admin,generate}` to run Serif commands.
         | 
| 476 | 
            +
            * `rake test` to run the tests.
         | 
| 477 | 
            +
            * Unit tests are written in RSpec.
         | 
| 478 | 
            +
             | 
| 479 | 
            +
            ## Directory structure
         | 
| 480 | 
            +
             | 
| 481 | 
            +
            * `lib/serif/` is generally where files go.
         | 
| 482 | 
            +
            * `test/` contains the test files. Any new files should have `require "test_helper"` at the top of the, which pulls in `test/test_helper.rb`.
         | 
    
        data/lib/serif/admin_server.rb
    CHANGED
    
    | @@ -87,7 +87,7 @@ class AdminServer | |
| 87 87 | 
             
                      # not the new one that was attempted to be saved.
         | 
| 88 88 | 
             
                      content = Draft.from_slug(site, params[:original_slug])
         | 
| 89 89 | 
             
                    else
         | 
| 90 | 
            -
                      Draft.rename(params[:original_slug], params[:slug])
         | 
| 90 | 
            +
                      Draft.rename(site, params[:original_slug], params[:slug])
         | 
| 91 91 |  | 
| 92 92 | 
             
                      # re-load after the rename
         | 
| 93 93 | 
             
                      content = Draft.from_slug(site, params[:slug])
         | 
    
        data/lib/serif/config.rb
    CHANGED
    
    
    
        data/lib/serif/content_file.rb
    CHANGED
    
    | @@ -49,6 +49,8 @@ class ContentFile | |
| 49 49 | 
             
                else
         | 
| 50 50 | 
             
                  @source.headers[:title] = new_title
         | 
| 51 51 | 
             
                end
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                @cached_headers = nil
         | 
| 52 54 | 
             
              end
         | 
| 53 55 |  | 
| 54 56 | 
             
              def draft?
         | 
| @@ -82,7 +84,9 @@ class ContentFile | |
| 82 84 | 
             
              end
         | 
| 83 85 |  | 
| 84 86 | 
             
              def headers
         | 
| 85 | 
            -
                return  | 
| 87 | 
            +
                return @cached_headers if @cached_headers
         | 
| 88 | 
            +
             | 
| 89 | 
            +
                return (@cached_headers = {}) unless @source
         | 
| 86 90 |  | 
| 87 91 | 
             
                headers = @source.headers
         | 
| 88 92 | 
             
                converted_headers = {}
         | 
| @@ -97,7 +101,7 @@ class ContentFile | |
| 97 101 | 
             
                  converted_headers[key] = value
         | 
| 98 102 | 
             
                end
         | 
| 99 103 |  | 
| 100 | 
            -
                converted_headers
         | 
| 104 | 
            +
                @cached_headers = converted_headers
         | 
| 101 105 | 
             
              end
         | 
| 102 106 |  | 
| 103 107 | 
             
              def save(markdown = nil)
         | 
| @@ -131,10 +135,12 @@ class ContentFile | |
| 131 135 |  | 
| 132 136 | 
             
              def set_publish_time(time)
         | 
| 133 137 | 
             
                @source.headers[:created] = time.xmlschema
         | 
| 138 | 
            +
                @cached_headers = nil
         | 
| 134 139 | 
             
              end
         | 
| 135 140 |  | 
| 136 141 | 
             
              def set_updated_time(time)
         | 
| 137 142 | 
             
                @source.headers[:updated] = time.xmlschema
         | 
| 143 | 
            +
                @cached_headers = nil
         | 
| 138 144 | 
             
              end
         | 
| 139 145 |  | 
| 140 146 | 
             
              private
         | 
| @@ -143,6 +149,7 @@ class ContentFile | |
| 143 149 | 
             
                source = File.read(path).gsub(/\r?\n/, "\n")
         | 
| 144 150 | 
             
                source.force_encoding("UTF-8")
         | 
| 145 151 | 
             
                @source = Redhead::String[source]
         | 
| 152 | 
            +
                @cached_headers = nil
         | 
| 146 153 | 
             
              end
         | 
| 147 154 | 
             
            end
         | 
| 148 155 | 
             
            end
         | 
    
        data/lib/serif/draft.rb
    CHANGED
    
    | @@ -6,6 +6,11 @@ class Draft < ContentFile | |
| 6 6 | 
             
                "_drafts"
         | 
| 7 7 | 
             
              end
         | 
| 8 8 |  | 
| 9 | 
            +
              def self.rename(site, original_slug, new_slug)
         | 
| 10 | 
            +
                raise if File.exist?("#{site.directory}/#{dirname}/#{new_slug}")
         | 
| 11 | 
            +
                File.rename("#{site.directory}/#{dirname}/#{original_slug}", "#{site.directory}/#{dirname}/#{new_slug}")
         | 
| 12 | 
            +
              end
         | 
| 13 | 
            +
             | 
| 9 14 | 
             
              def delete!
         | 
| 10 15 | 
             
                FileUtils.mkdir_p("#{site.directory}/_trash")
         | 
| 11 16 | 
             
                File.rename(@path, File.expand_path("#{site.directory}/_trash/#{Time.now.to_i}-#{slug}"))
         | 
    
        data/lib/serif/site.rb
    CHANGED
    
    | @@ -30,6 +30,11 @@ module Filters | |
| 30 30 | 
             
                CGI.escape(string)
         | 
| 31 31 | 
             
              end
         | 
| 32 32 |  | 
| 33 | 
            +
              def smarty(text)
         | 
| 34 | 
            +
                text.gsub!('`', '\\\\`')
         | 
| 35 | 
            +
                Redcarpet::Render::SmartyPants.render(text)
         | 
| 36 | 
            +
              end
         | 
| 37 | 
            +
             | 
| 33 38 | 
             
              def markdown(body)
         | 
| 34 39 | 
             
                Redcarpet::Markdown.new(Serif::MarkupRenderer, fenced_code_blocks: true).render(body).strip
         | 
| 35 40 | 
             
              end
         | 
| @@ -105,7 +110,7 @@ class Site | |
| 105 110 | 
             
              end
         | 
| 106 111 |  | 
| 107 112 | 
             
              def config
         | 
| 108 | 
            -
                Serif::Config.new(File.join(@source_directory, "_config.yml"))
         | 
| 113 | 
            +
                @config ||= Serif::Config.new(File.join(@source_directory, "_config.yml"))
         | 
| 109 114 | 
             
              end
         | 
| 110 115 |  | 
| 111 116 | 
             
              def site_path(path)
         | 
| @@ -221,7 +226,12 @@ class Site | |
| 221 226 | 
             
              end
         | 
| 222 227 |  | 
| 223 228 | 
             
              def to_liquid
         | 
| 224 | 
            -
                 | 
| 229 | 
            +
                @liquid_cache_store ||= TimeoutCache.new
         | 
| 230 | 
            +
             | 
| 231 | 
            +
                cached_value = @liquid_cache_store[:liquid]
         | 
| 232 | 
            +
                return cached_value if cached_value
         | 
| 233 | 
            +
             | 
| 234 | 
            +
                @liquid_cache_store[:liquid] = {
         | 
| 225 235 | 
             
                  "posts" => posts,
         | 
| 226 236 | 
             
                  "latest_update_time" => latest_update_time,
         | 
| 227 237 | 
             
                  "archive" => self.class.stringify_keys(archives),
         | 
| @@ -273,8 +283,12 @@ class Site | |
| 273 283 | 
             
                      if layout_option == "none"
         | 
| 274 284 | 
             
                        f.puts Liquid::Template.parse(file.to_s).render!("site" => self)
         | 
| 275 285 | 
             
                      else
         | 
| 276 | 
            -
                         | 
| 277 | 
            -
             | 
| 286 | 
            +
                        if layout_option == :default
         | 
| 287 | 
            +
                          layout = default_layout
         | 
| 288 | 
            +
                        else
         | 
| 289 | 
            +
                          layout_file = File.join(self.directory, "_layouts", "#{layout_option}.html")
         | 
| 290 | 
            +
                          layout = Liquid::Template.parse(File.read(layout_file))
         | 
| 291 | 
            +
                        end
         | 
| 278 292 | 
             
                        f.puts layout.render!("site" => self, "page" => { "title" => [title].compact }, "content" => Liquid::Template.parse(file.to_s).render!("site" => self))
         | 
| 279 293 | 
             
                      end
         | 
| 280 294 | 
             
                    end
         | 
| @@ -356,6 +370,7 @@ class Site | |
| 356 370 |  | 
| 357 371 | 
             
                  File.open(live_preview_file + ".html", "w") do |f|
         | 
| 358 372 | 
             
                    f.puts layout.render!(
         | 
| 373 | 
            +
                      "site" => self,
         | 
| 359 374 | 
             
                      "draft_preview" => true,
         | 
| 360 375 | 
             
                      "page" => { "title" => [ "Draft Preview", draft.title ] },
         | 
| 361 376 | 
             
                      "content" => template.render!("site" => self, "post" => draft)
         | 
| @@ -391,7 +406,7 @@ class Site | |
| 391 406 | 
             
                  FileUtils.mkdir_p(archive_path)
         | 
| 392 407 |  | 
| 393 408 | 
             
                  File.open(File.join(archive_path, "index.html"), "w") do |f|
         | 
| 394 | 
            -
                    f.puts layout.render!("content" => template.render!("site" => self, "month" => month, "posts" => posts))
         | 
| 409 | 
            +
                    f.puts layout.render!("site" => self, "content" => template.render!("site" => self, "month" => month, "posts" => posts))
         | 
| 395 410 | 
             
                  end
         | 
| 396 411 | 
             
                end
         | 
| 397 412 | 
             
              end
         | 
    
        data/lib/serif.rb
    CHANGED
    
    
    
        data/rakefile
    CHANGED
    
    | @@ -1,5 +1,7 @@ | |
| 1 1 | 
             
            require "rake"
         | 
| 2 | 
            +
            require "time"
         | 
| 2 3 | 
             
            require "rspec/core/rake_task"
         | 
| 4 | 
            +
            require "benchmark"
         | 
| 3 5 |  | 
| 4 6 | 
             
            RSpec::Core::RakeTask.new(:test) do |t|
         | 
| 5 7 | 
             
              t.rspec_opts = "-I test --color --format nested"
         | 
| @@ -9,3 +11,29 @@ RSpec::Core::RakeTask.new(:test) do |t| | |
| 9 11 | 
             
            end
         | 
| 10 12 |  | 
| 11 13 | 
             
            task :default => :test
         | 
| 14 | 
            +
             | 
| 15 | 
            +
            task :stress, [:n] do |t, args|
         | 
| 16 | 
            +
              iterations = args[:n] || 250
         | 
| 17 | 
            +
              iterations = iterations.to_i
         | 
| 18 | 
            +
             | 
| 19 | 
            +
              d = Dir.pwd
         | 
| 20 | 
            +
              cd "/tmp"
         | 
| 21 | 
            +
              rm_rf ".test-site"
         | 
| 22 | 
            +
              mkdir ".test-site"
         | 
| 23 | 
            +
              cd ".test-site"
         | 
| 24 | 
            +
              `#{d}/bin/serif new`
         | 
| 25 | 
            +
             | 
| 26 | 
            +
              File.open("_layouts/default.html", "a") { |f| f.puts "\n\ndigest: {% file_digest style.css prefix:- %}" }
         | 
| 27 | 
            +
              File.open("style.css", "w") { |f| f.puts("body {}") }
         | 
| 28 | 
            +
             | 
| 29 | 
            +
              iterations.times do |n|
         | 
| 30 | 
            +
                File.open("_posts/#{Date.today + n}-sample-post-#{n}", "w") do |f|
         | 
| 31 | 
            +
                  f.puts %Q{title: sample-post
         | 
| 32 | 
            +
            created: #{(Time.now + 60*n).xmlschema}
         | 
| 33 | 
            +
             | 
| 34 | 
            +
            Dummy content #{n}}
         | 
| 35 | 
            +
                end
         | 
| 36 | 
            +
              end
         | 
| 37 | 
            +
             | 
| 38 | 
            +
              puts Benchmark.realtime { system({ "ENV" => ENV["ENV"] }, "#{d}/bin/serif generate") }
         | 
| 39 | 
            +
            end
         | 
    
        data/serif.gemspec
    CHANGED
    
    | @@ -1,6 +1,6 @@ | |
| 1 1 | 
             
            Gem::Specification.new do |s|
         | 
| 2 2 | 
             
              s.name         = "serif"
         | 
| 3 | 
            -
              s.version      = "0. | 
| 3 | 
            +
              s.version      = "0.3"
         | 
| 4 4 | 
             
              s.authors      = ["Adam Prescott"]
         | 
| 5 5 | 
             
              s.email        = ["adam@aprescott.com"]
         | 
| 6 6 | 
             
              s.homepage     = "https://github.com/aprescott/serif"
         | 
| @@ -20,7 +20,8 @@ Gem::Specification.new do |s| | |
| 20 20 | 
             
                "sinatra", "~> 1.3",
         | 
| 21 21 | 
             
                "redhead", "~> 0.0.8",
         | 
| 22 22 | 
             
                "liquid", "~> 2.4",
         | 
| 23 | 
            -
                "slop", "~> 3.3"
         | 
| 23 | 
            +
                "slop", "~> 3.3",
         | 
| 24 | 
            +
                "timeout_cache"
         | 
| 24 25 | 
             
              ].each_slice(2) do |name, version|
         | 
| 25 26 | 
             
                s.add_runtime_dependency(name, version)
         | 
| 26 27 | 
             
              end
         | 
| @@ -67,6 +67,39 @@ var createAttachment = function(file, element) { | |
| 67 67 | 
             
            	});
         | 
| 68 68 |  | 
| 69 69 | 
             
            	var absText = '';
         | 
| 70 | 
            +
             | 
| 71 | 
            +
            	// for some reason this is necessary to avoid the following
         | 
| 72 | 
            +
            	// giving an undefined result:
         | 
| 73 | 
            +
            	//
         | 
| 74 | 
            +
            	//   1. load a new draft page with an empty textarea
         | 
| 75 | 
            +
            	//   2. at this point element.value is undefined.
         | 
| 76 | 
            +
            	//   3. drag an image, calling insertAtCaret
         | 
| 77 | 
            +
            	//   4. element.value (3) in this method is still undefined (confusing!)
         | 
| 78 | 
            +
            	//   5. in the browser console, $("[data-attachify]").get(0).value
         | 
| 79 | 
            +
            	//      is correct. (confusing!)
         | 
| 80 | 
            +
            	//   6. on a _second drag_, element.value is undefined (very confusing)
         | 
| 81 | 
            +
            	//   7. in the same second drag event, $(element).get(0).value is
         | 
| 82 | 
            +
            	//      correct, hence this "reloading" to allow element.value
         | 
| 83 | 
            +
            	//      below to not be undefined.
         | 
| 84 | 
            +
            	element = $(element).get(0);
         | 
| 85 | 
            +
             | 
| 86 | 
            +
            	if (typeof element.value != "undefined") {
         | 
| 87 | 
            +
            		var pos    = element.selectionStart;
         | 
| 88 | 
            +
            		var text   = element.value;
         | 
| 89 | 
            +
            		var before = text.slice(0, pos);
         | 
| 90 | 
            +
            		var after  = text.slice(pos);
         | 
| 91 | 
            +
            		
         | 
| 92 | 
            +
            		// if there is only a single newline, add one more for a blank
         | 
| 93 | 
            +
            		// line.
         | 
| 94 | 
            +
            		if (/[^\n]\n$/.test(before)) {
         | 
| 95 | 
            +
            			absText = "\n" + absText;
         | 
| 96 | 
            +
            		// if there aren't two new lines, add a full two
         | 
| 97 | 
            +
            		} else if (! /\n\n$/.test(before)) {
         | 
| 98 | 
            +
            			absText = "\n\n" + absText;
         | 
| 99 | 
            +
            		}
         | 
| 100 | 
            +
             | 
| 101 | 
            +
            	}
         | 
| 102 | 
            +
            	
         | 
| 70 103 | 
             
            	$(element).insertAtCaret(absText);
         | 
| 71 104 | 
             
            };
         | 
| 72 105 |  | 
    
        data/test/draft_spec.rb
    CHANGED
    
    | @@ -7,6 +7,39 @@ describe Serif::Draft do | |
| 7 7 | 
             
                FileUtils.rm_rf(testing_dir("_trash"))
         | 
| 8 8 | 
             
              end
         | 
| 9 9 |  | 
| 10 | 
            +
              describe ".rename" do
         | 
| 11 | 
            +
                it "moves the draft to a new file" do
         | 
| 12 | 
            +
                  draft = D.new(@site)
         | 
| 13 | 
            +
                  draft.slug = "test-draft"
         | 
| 14 | 
            +
                  draft.title = "Some draft title"
         | 
| 15 | 
            +
                  draft.save("some content")
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                  D.rename(@site, "test-draft", "foo-bar")
         | 
| 18 | 
            +
                  d = D.from_slug(@site, "foo-bar")
         | 
| 19 | 
            +
                  d.should_not be_nil
         | 
| 20 | 
            +
                  File.exist?(testing_dir("_drafts/foo-bar")).should be_true
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                  d.delete!
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                it "raises if there is an existing draft" do
         | 
| 26 | 
            +
                  draft = D.new(@site)
         | 
| 27 | 
            +
                  draft.slug = "test-draft"
         | 
| 28 | 
            +
                  draft.title = "Some draft title"
         | 
| 29 | 
            +
                  draft.save("some content")
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                  draft2 = D.new(@site)
         | 
| 32 | 
            +
                  draft2.slug = "test-draft-2"
         | 
| 33 | 
            +
                  draft2.title = "Some draft title"
         | 
| 34 | 
            +
                  draft2.save("some content")
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                  expect { D.rename(@site, draft2.slug, draft.slug) }.to raise_error
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                  draft.delete!
         | 
| 39 | 
            +
                  draft2.delete!
         | 
| 40 | 
            +
                end
         | 
| 41 | 
            +
              end
         | 
| 42 | 
            +
             | 
| 10 43 | 
             
              describe "#delete!" do
         | 
| 11 44 | 
             
                it "moves the file to _trash" do
         | 
| 12 45 | 
             
                  draft = D.new(@site)
         | 
    
        data/test/filters_spec.rb
    CHANGED
    
    | @@ -18,6 +18,23 @@ describe Serif::Filters do | |
| 18 18 | 
             
                end
         | 
| 19 19 | 
             
              end
         | 
| 20 20 |  | 
| 21 | 
            +
              describe "#smarty" do
         | 
| 22 | 
            +
                it "runs the input through a SmartyPants processor" do
         | 
| 23 | 
            +
                  subject.smarty("Testing").should == "Testing"
         | 
| 24 | 
            +
                  subject.smarty("Testing's").should == "Testing’s"
         | 
| 25 | 
            +
                  subject.smarty("\"Testing\" some \"text's\" input...").should == "“Testing” some “text’s” input…"
         | 
| 26 | 
            +
                end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                it "does not do any markdown processing" do
         | 
| 29 | 
            +
                  subject.smarty("# Heading").should == "# Heading"
         | 
| 30 | 
            +
                  subject.smarty("Testing `code blocks` input").should == "Testing `code blocks` input"
         | 
| 31 | 
            +
                end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                it "deals with HTML appropriately" do
         | 
| 34 | 
            +
                  subject.smarty("<p>Testing's <span>span</span> testing</p>").should == "<p>Testing’s <span>span</span> testing</p>"
         | 
| 35 | 
            +
                end
         | 
| 36 | 
            +
              end
         | 
| 37 | 
            +
             | 
| 21 38 | 
             
              describe "#encode_uri_component" do
         | 
| 22 39 | 
             
                it "percent-encodes various characters for use in a URI" do
         | 
| 23 40 | 
             
                  {
         | 
| 
            File without changes
         | 
| 
            File without changes
         | 
| @@ -9,10 +9,10 @@ | |
| 9 9 |  | 
| 10 10 | 
             
            <ul>
         | 
| 11 11 |  | 
| 12 | 
            -
            		<li><a href="/test-blog/second-post">Second post</a> (posted 2013-01-01T00:00: | 
| 12 | 
            +
            		<li><a href="/test-blog/second-post">Second post</a> (posted 2013-01-01T00:00:00Z)</li>
         | 
| 13 13 |  | 
| 14 | 
            -
            		<li><a href="/test-blog/post-to-be-published-on-generate">Some draft title</a> (posted 2012-12-21T15:30: | 
| 14 | 
            +
            		<li><a href="/test-blog/post-to-be-published-on-generate">Some draft title</a> (posted 2012-12-21T15:30:00Z)</li>
         | 
| 15 15 |  | 
| 16 | 
            -
            		<li><a href="/test-blog/sample-post">Sample post</a> (posted 2012-11-21T17:07: | 
| 16 | 
            +
            		<li><a href="/test-blog/sample-post">Sample post</a> (posted 2012-11-21T17:07:09Z)</li>
         | 
| 17 17 |  | 
| 18 18 | 
             
            </ul>
         | 
| @@ -23,6 +23,11 @@ describe Serif::Site do | |
| 23 23 | 
             
                  File.read("_site/page-alt-layout.html").lines.first.should =~ /<h1.+?>Alternate layout<\/h1>/
         | 
| 24 24 | 
             
                end
         | 
| 25 25 |  | 
| 26 | 
            +
                it "supports a smarty filter" do
         | 
| 27 | 
            +
                  subject.generate
         | 
| 28 | 
            +
                  File.read("_site/test-smarty-filter.html").should =~ /testing’s for a “heading’s” `with code` in it…/
         | 
| 29 | 
            +
                end
         | 
| 30 | 
            +
             | 
| 26 31 | 
             
                it "correctly handles file_digest calls" do
         | 
| 27 32 | 
             
                  subject.generate
         | 
| 28 33 |  | 
    
        metadata
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: serif
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0. | 
| 4 | 
            +
              version: '0.3'
         | 
| 5 5 | 
             
              prerelease: 
         | 
| 6 6 | 
             
            platform: ruby
         | 
| 7 7 | 
             
            authors:
         | 
| @@ -9,7 +9,7 @@ authors: | |
| 9 9 | 
             
            autorequire: 
         | 
| 10 10 | 
             
            bindir: bin
         | 
| 11 11 | 
             
            cert_chain: []
         | 
| 12 | 
            -
            date: 2013-02- | 
| 12 | 
            +
            date: 2013-02-18 00:00:00.000000000 Z
         | 
| 13 13 | 
             
            dependencies:
         | 
| 14 14 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 15 15 | 
             
              name: rack
         | 
| @@ -139,6 +139,22 @@ dependencies: | |
| 139 139 | 
             
                - - ~>
         | 
| 140 140 | 
             
                  - !ruby/object:Gem::Version
         | 
| 141 141 | 
             
                    version: '3.3'
         | 
| 142 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 143 | 
            +
              name: timeout_cache
         | 
| 144 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 145 | 
            +
                none: false
         | 
| 146 | 
            +
                requirements:
         | 
| 147 | 
            +
                - - ! '>='
         | 
| 148 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 149 | 
            +
                    version: '0'
         | 
| 150 | 
            +
              type: :runtime
         | 
| 151 | 
            +
              prerelease: false
         | 
| 152 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 153 | 
            +
                none: false
         | 
| 154 | 
            +
                requirements:
         | 
| 155 | 
            +
                - - ! '>='
         | 
| 156 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 157 | 
            +
                    version: '0'
         | 
| 142 158 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 143 159 | 
             
              name: rake
         | 
| 144 160 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| @@ -261,8 +277,8 @@ files: | |
| 261 277 | 
             
            - test/site_dir/_site/test-archive/2013/01/index.html
         | 
| 262 278 | 
             
            - test/site_dir/_site/test-archive/2012/12/index.html
         | 
| 263 279 | 
             
            - test/site_dir/_site/test-archive/2012/11/index.html
         | 
| 264 | 
            -
            - test/site_dir/_site/drafts/another-sample-draft/ | 
| 265 | 
            -
            - test/site_dir/_site/drafts/sample-draft/ | 
| 280 | 
            +
            - test/site_dir/_site/drafts/another-sample-draft/f340ff2dd6aa78f819d547ee908fe7410e6153559b47265dcbc58598bb4a.html
         | 
| 281 | 
            +
            - test/site_dir/_site/drafts/sample-draft/ed883ce827f757888e2900ce0e155a960cb45f832fcc24791c054013b71c.html
         | 
| 266 282 | 
             
            - test/site_dir/_site/index.html
         | 
| 267 283 | 
             
            - test/site_dir/_site/file-digest-test.html
         | 
| 268 284 | 
             
            - test/site_dir/_site/page-alt-layout.html
         | 
| @@ -271,11 +287,13 @@ files: | |
| 271 287 | 
             
            - test/site_dir/_site/test-blog/post-to-be-published-on-generate.html
         | 
| 272 288 | 
             
            - test/site_dir/_site/test-blog/second-post.html
         | 
| 273 289 | 
             
            - test/site_dir/_site/test-blog/sample-post.html
         | 
| 290 | 
            +
            - test/site_dir/_site/test-smarty-filter.html
         | 
| 274 291 | 
             
            - test/site_dir/_site/archive.html
         | 
| 275 | 
            -
            - test/site_dir/_trash/ | 
| 276 | 
            -
            - test/site_dir/_trash/ | 
| 292 | 
            +
            - test/site_dir/_trash/1361224983-test-draft
         | 
| 293 | 
            +
            - test/site_dir/_trash/1361224983-autopublish-draft
         | 
| 277 294 | 
             
            - test/site_dir/_posts/2012-01-05-sample-post
         | 
| 278 295 | 
             
            - test/site_dir/_posts/2013-01-01-second-post
         | 
| 296 | 
            +
            - test/site_dir/test-smarty-filter.html
         | 
| 279 297 | 
             
            - test/site_dir/_layouts/alt-layout.html
         | 
| 280 298 | 
             
            - test/site_dir/_layouts/default.html
         | 
| 281 299 | 
             
            - test/site_dir/archive.html
         |