spinto-jekyll 0.11.2.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.
Files changed (108) hide show
  1. data/Gemfile +2 -0
  2. data/History.txt +321 -0
  3. data/LICENSE +21 -0
  4. data/README.textile +41 -0
  5. data/Rakefile +166 -0
  6. data/bin/jekyll +289 -0
  7. data/cucumber.yml +1 -0
  8. data/features/create_sites.feature +112 -0
  9. data/features/embed_filters.feature +60 -0
  10. data/features/markdown.feature +30 -0
  11. data/features/pagination.feature +27 -0
  12. data/features/permalinks.feature +65 -0
  13. data/features/post_data.feature +153 -0
  14. data/features/site_configuration.feature +145 -0
  15. data/features/site_data.feature +82 -0
  16. data/features/step_definitions/jekyll_steps.rb +145 -0
  17. data/features/support/env.rb +19 -0
  18. data/lib/jekyll.rb +136 -0
  19. data/lib/jekyll/converter.rb +50 -0
  20. data/lib/jekyll/converters/identity.rb +22 -0
  21. data/lib/jekyll/converters/markdown.rb +125 -0
  22. data/lib/jekyll/converters/textile.rb +50 -0
  23. data/lib/jekyll/convertible.rb +112 -0
  24. data/lib/jekyll/core_ext.rb +52 -0
  25. data/lib/jekyll/errors.rb +6 -0
  26. data/lib/jekyll/filters.rb +118 -0
  27. data/lib/jekyll/generator.rb +7 -0
  28. data/lib/jekyll/generators/pagination.rb +113 -0
  29. data/lib/jekyll/layout.rb +44 -0
  30. data/lib/jekyll/migrators/csv.rb +26 -0
  31. data/lib/jekyll/migrators/drupal.rb +103 -0
  32. data/lib/jekyll/migrators/enki.rb +49 -0
  33. data/lib/jekyll/migrators/joomla.rb +53 -0
  34. data/lib/jekyll/migrators/marley.rb +52 -0
  35. data/lib/jekyll/migrators/mephisto.rb +84 -0
  36. data/lib/jekyll/migrators/mt.rb +86 -0
  37. data/lib/jekyll/migrators/posterous.rb +67 -0
  38. data/lib/jekyll/migrators/rss.rb +47 -0
  39. data/lib/jekyll/migrators/textpattern.rb +58 -0
  40. data/lib/jekyll/migrators/tumblr.rb +195 -0
  41. data/lib/jekyll/migrators/typo.rb +51 -0
  42. data/lib/jekyll/migrators/wordpress.rb +294 -0
  43. data/lib/jekyll/migrators/wordpressdotcom.rb +70 -0
  44. data/lib/jekyll/page.rb +155 -0
  45. data/lib/jekyll/plugin.rb +77 -0
  46. data/lib/jekyll/post.rb +257 -0
  47. data/lib/jekyll/site.rb +337 -0
  48. data/lib/jekyll/static_file.rb +72 -0
  49. data/lib/jekyll/tags/highlight.rb +76 -0
  50. data/lib/jekyll/tags/include.rb +37 -0
  51. data/lib/jekyll/tags/post_url.rb +38 -0
  52. data/lib/spinto-jekyll.rb +3 -0
  53. data/spinto-jekyll.gemspec +155 -0
  54. data/test/helper.rb +34 -0
  55. data/test/source/.htaccess +8 -0
  56. data/test/source/_includes/sig.markdown +3 -0
  57. data/test/source/_layouts/default.html +27 -0
  58. data/test/source/_layouts/simple.html +1 -0
  59. data/test/source/_posts/2008-02-02-not-published.textile +8 -0
  60. data/test/source/_posts/2008-02-02-published.textile +8 -0
  61. data/test/source/_posts/2008-10-18-foo-bar.textile +8 -0
  62. data/test/source/_posts/2008-11-21-complex.textile +8 -0
  63. data/test/source/_posts/2008-12-03-permalinked-post.textile +9 -0
  64. data/test/source/_posts/2008-12-13-include.markdown +8 -0
  65. data/test/source/_posts/2009-01-27-array-categories.textile +10 -0
  66. data/test/source/_posts/2009-01-27-categories.textile +7 -0
  67. data/test/source/_posts/2009-01-27-category.textile +7 -0
  68. data/test/source/_posts/2009-01-27-empty-categories.textile +7 -0
  69. data/test/source/_posts/2009-01-27-empty-category.textile +7 -0
  70. data/test/source/_posts/2009-03-12-hash-#1.markdown +6 -0
  71. data/test/source/_posts/2009-05-18-empty-tag.textile +6 -0
  72. data/test/source/_posts/2009-05-18-empty-tags.textile +6 -0
  73. data/test/source/_posts/2009-05-18-tag.textile +6 -0
  74. data/test/source/_posts/2009-05-18-tags.textile +9 -0
  75. data/test/source/_posts/2009-06-22-empty-yaml.textile +3 -0
  76. data/test/source/_posts/2009-06-22-no-yaml.textile +1 -0
  77. data/test/source/_posts/2010-01-08-triple-dash.markdown +5 -0
  78. data/test/source/_posts/2010-01-09-date-override.textile +7 -0
  79. data/test/source/_posts/2010-01-09-time-override.textile +7 -0
  80. data/test/source/_posts/2010-01-09-timezone-override.textile +7 -0
  81. data/test/source/_posts/2010-01-16-override-data.textile +4 -0
  82. data/test/source/_posts/2011-04-12-md-extension.md +7 -0
  83. data/test/source/_posts/2011-04-12-text-extension.text +0 -0
  84. data/test/source/about.html +6 -0
  85. data/test/source/category/_posts/2008-9-23-categories.textile +6 -0
  86. data/test/source/contacts.html +5 -0
  87. data/test/source/css/screen.css +76 -0
  88. data/test/source/deal.with.dots.html +7 -0
  89. data/test/source/foo/_posts/bar/2008-12-12-topical-post.textile +8 -0
  90. data/test/source/index.html +22 -0
  91. data/test/source/sitemap.xml +32 -0
  92. data/test/source/win/_posts/2009-05-24-yaml-linebreak.markdown +7 -0
  93. data/test/source/z_category/_posts/2008-9-23-categories.textile +6 -0
  94. data/test/suite.rb +11 -0
  95. data/test/test_configuration.rb +29 -0
  96. data/test/test_core_ext.rb +66 -0
  97. data/test/test_filters.rb +62 -0
  98. data/test/test_generated_site.rb +72 -0
  99. data/test/test_kramdown.rb +23 -0
  100. data/test/test_page.rb +117 -0
  101. data/test/test_pager.rb +113 -0
  102. data/test/test_post.rb +456 -0
  103. data/test/test_rdiscount.rb +18 -0
  104. data/test/test_redcarpet.rb +21 -0
  105. data/test/test_redcloth.rb +86 -0
  106. data/test/test_site.rb +220 -0
  107. data/test/test_tags.rb +201 -0
  108. metadata +336 -0
@@ -0,0 +1,50 @@
1
+ module Jekyll
2
+
3
+ class TextileConverter < Converter
4
+ safe true
5
+
6
+ pygments_prefix '<notextile>'
7
+ pygments_suffix '</notextile>'
8
+
9
+ def setup
10
+ return if @setup
11
+ require 'redcloth'
12
+ @setup = true
13
+ rescue LoadError
14
+ STDERR.puts 'You are missing a library required for Textile. Please run:'
15
+ STDERR.puts ' $ [sudo] gem install RedCloth'
16
+ raise FatalException.new("Missing dependency: RedCloth")
17
+ end
18
+
19
+ def matches(ext)
20
+ rgx = '(' + @config['textile_ext'].gsub(',','|') +')'
21
+ ext =~ Regexp.new(rgx, Regexp::IGNORECASE)
22
+ end
23
+
24
+ def output_ext(ext)
25
+ ".html"
26
+ end
27
+
28
+ def convert(content)
29
+ setup
30
+
31
+ # Shortcut if config doesn't contain RedCloth section
32
+ return RedCloth.new(content).to_html if @config['redcloth'].nil?
33
+
34
+ # List of attributes defined on RedCloth
35
+ # (from http://redcloth.rubyforge.org/classes/RedCloth/TextileDoc.html)
36
+ attrs = ['filter_classes', 'filter_html', 'filter_ids', 'filter_styles',
37
+ 'hard_breaks', 'lite_mode', 'no_span_caps', 'sanitize_html']
38
+
39
+ r = RedCloth.new(content)
40
+
41
+ # Set attributes in r if they are NOT nil in the config
42
+ attrs.each do |attr|
43
+ r.instance_variable_set("@#{attr}".to_sym, @config['redcloth'][attr]) unless @config['redcloth'][attr].nil?
44
+ end
45
+
46
+ r.to_html
47
+ end
48
+ end
49
+
50
+ end
@@ -0,0 +1,112 @@
1
+ require 'set'
2
+
3
+ # Convertible provides methods for converting a pagelike item
4
+ # from a certain type of markup into actual content
5
+ #
6
+ # Requires
7
+ # self.site -> Jekyll::Site
8
+ # self.content
9
+ # self.content=
10
+ # self.data=
11
+ # self.ext=
12
+ # self.output=
13
+ # self.name
14
+ module Jekyll
15
+ module Convertible
16
+ # Returns the contents as a String.
17
+ def to_s
18
+ self.content || ''
19
+ end
20
+
21
+ # Read the YAML frontmatter.
22
+ #
23
+ # base - The String path to the dir containing the file.
24
+ # name - The String filename of the file.
25
+ #
26
+ # Returns nothing.
27
+ def read_yaml(base, name)
28
+ self.content = File.read(File.join(base, name))
29
+
30
+ begin
31
+ if self.content =~ /^(---\s*\n.*?\n?)^(---\s*$\n?)/m
32
+ self.content = $POSTMATCH
33
+ self.data = YAML.load($1)
34
+ end
35
+ rescue => e
36
+ puts "YAML Exception reading #{name}: #{e.message}"
37
+ end
38
+
39
+ self.data ||= {}
40
+ end
41
+
42
+ # Transform the contents based on the content type.
43
+ #
44
+ # Returns nothing.
45
+ def transform
46
+ self.content = converter.convert(self.content)
47
+ end
48
+
49
+ # Determine the extension depending on content_type.
50
+ #
51
+ # Returns the String extension for the output file.
52
+ # e.g. ".html" for an HTML output file.
53
+ def output_ext
54
+ converter.output_ext(self.ext)
55
+ end
56
+
57
+ # Determine which converter to use based on this convertible's
58
+ # extension.
59
+ #
60
+ # Returns the Converter instance.
61
+ def converter
62
+ @converter ||= self.site.converters.find { |c| c.matches(self.ext) }
63
+ end
64
+
65
+ # Add any necessary layouts to this convertible document.
66
+ #
67
+ # payload - The site payload Hash.
68
+ # layouts - A Hash of {"name" => "layout"}.
69
+ #
70
+ # Returns nothing.
71
+ def do_layout(payload, layouts)
72
+ info = { :filters => [Jekyll::Filters], :registers => { :site => self.site } }
73
+
74
+ # render and transform content (this becomes the final content of the object)
75
+ payload["pygments_prefix"] = converter.pygments_prefix
76
+ payload["pygments_suffix"] = converter.pygments_suffix
77
+
78
+ begin
79
+ self.content = Liquid::Template.parse(self.content).render(payload, info)
80
+ rescue => e
81
+ puts "Liquid Exception: #{e.message} in #{self.name}"
82
+ end
83
+
84
+ self.transform
85
+
86
+ # output keeps track of what will finally be written
87
+ self.output = self.content
88
+
89
+ # recursively render layouts
90
+ layout = layouts[self.data["layout"]]
91
+ used = Set.new([layout])
92
+
93
+ while layout
94
+ payload = payload.deep_merge({"content" => self.output, "page" => layout.data})
95
+
96
+ begin
97
+ self.output = Liquid::Template.parse(layout.content).render(payload, info)
98
+ rescue => e
99
+ puts "Liquid Exception: #{e.message} in #{self.data["layout"]}"
100
+ end
101
+
102
+ if layout = layouts[layout.data["layout"]]
103
+ if used.include?(layout)
104
+ layout = nil # avoid recursive chain
105
+ else
106
+ used << layout
107
+ end
108
+ end
109
+ end
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,52 @@
1
+ class Hash
2
+ # Merges self with another hash, recursively.
3
+ #
4
+ # This code was lovingly stolen from some random gem:
5
+ # http://gemjack.com/gems/tartan-0.1.1/classes/Hash.html
6
+ #
7
+ # Thanks to whoever made it.
8
+ def deep_merge(hash)
9
+ target = dup
10
+
11
+ hash.keys.each do |key|
12
+ if hash[key].is_a? Hash and self[key].is_a? Hash
13
+ target[key] = target[key].deep_merge(hash[key])
14
+ next
15
+ end
16
+
17
+ target[key] = hash[key]
18
+ end
19
+
20
+ target
21
+ end
22
+
23
+ # Read array from the supplied hash favouring the singular key
24
+ # and then the plural key, and handling any nil entries.
25
+ # +hash+ the hash to read from
26
+ # +singular_key+ the singular key
27
+ # +plural_key+ the singular key
28
+ #
29
+ # Returns an array
30
+ def pluralized_array(singular_key, plural_key)
31
+ hash = self
32
+ if hash.has_key?(singular_key)
33
+ array = [hash[singular_key]] if hash[singular_key]
34
+ elsif hash.has_key?(plural_key)
35
+ case hash[plural_key]
36
+ when String
37
+ array = hash[plural_key].split
38
+ when Array
39
+ array = hash[plural_key].compact
40
+ end
41
+ end
42
+ array || []
43
+ end
44
+ end
45
+
46
+ # Thanks, ActiveSupport!
47
+ class Date
48
+ # Converts datetime to an appropriate format for use in XML
49
+ def xmlschema
50
+ strftime("%Y-%m-%dT%H:%M:%S%Z")
51
+ end if RUBY_VERSION < '1.9'
52
+ end
@@ -0,0 +1,6 @@
1
+ module Jekyll
2
+
3
+ class FatalException < StandardError
4
+ end
5
+
6
+ end
@@ -0,0 +1,118 @@
1
+ require 'uri'
2
+
3
+ module Jekyll
4
+
5
+ module Filters
6
+ # Convert a Textile string into HTML output.
7
+ #
8
+ # input - The Textile String to convert.
9
+ #
10
+ # Returns the HTML formatted String.
11
+ def textilize(input)
12
+ site = @context.registers[:site]
13
+ converter = site.getConverterImpl(Jekyll::TextileConverter)
14
+ converter.convert(input)
15
+ end
16
+
17
+ # Convert a Markdown string into HTML output.
18
+ #
19
+ # input - The Markdown String to convert.
20
+ #
21
+ # Returns the HTML formatted String.
22
+ def markdownify(input)
23
+ site = @context.registers[:site]
24
+ converter = site.getConverterImpl(Jekyll::MarkdownConverter)
25
+ converter.convert(input)
26
+ end
27
+
28
+ # Format a date in short format e.g. "27 Jan 2011".
29
+ #
30
+ # date - the Time to format.
31
+ #
32
+ # Returns the formatting String.
33
+ def date_to_string(date)
34
+ date.strftime("%d %b %Y")
35
+ end
36
+
37
+ # Format a date in long format e.g. "27 January 2011".
38
+ #
39
+ # date - The Time to format.
40
+ #
41
+ # Returns the formatted String.
42
+ def date_to_long_string(date)
43
+ date.strftime("%d %B %Y")
44
+ end
45
+
46
+ # Format a date for use in XML.
47
+ #
48
+ # date - The Time to format.
49
+ #
50
+ # Examples
51
+ #
52
+ # date_to_xmlschema(Time.now)
53
+ # # => "2011-04-24T20:34:46+08:00"
54
+ #
55
+ # Returns the formatted String.
56
+ def date_to_xmlschema(date)
57
+ date.xmlschema
58
+ end
59
+
60
+ def xml_escape(input)
61
+ CGI.escapeHTML(input)
62
+ end
63
+
64
+ # CGI escape a string for use in a URL. Replaces any special characters
65
+ # with appropriate %XX replacements.
66
+ #
67
+ # input - The String to escape.
68
+ #
69
+ # Examples
70
+ #
71
+ # cgi_escape('foo,bar;baz?')
72
+ # # => "foo%2Cbar%3Bbaz%3F"
73
+ #
74
+ # Returns the escaped String.
75
+ def cgi_escape(input)
76
+ CGI::escape(input)
77
+ end
78
+
79
+ def uri_escape(input)
80
+ URI.escape(input)
81
+ end
82
+
83
+ # Count the number of words in the input string.
84
+ #
85
+ # input - The String on which to operate.
86
+ #
87
+ # Returns the Integer word count.
88
+ def number_of_words(input)
89
+ input.split.length
90
+ end
91
+
92
+ # Join an array of things into a string by separating with commes and the
93
+ # word "and" for the last one.
94
+ #
95
+ # array - The Array of Strings to join.
96
+ #
97
+ # Examples
98
+ #
99
+ # array_to_sentence_string(["apples", "oranges", "grapes"])
100
+ # # => "apples, oranges, and grapes"
101
+ #
102
+ # Returns the formatted String.
103
+ def array_to_sentence_string(array)
104
+ connector = "and"
105
+ case array.length
106
+ when 0
107
+ ""
108
+ when 1
109
+ array[0].to_s
110
+ when 2
111
+ "#{array[0]} #{connector} #{array[1]}"
112
+ else
113
+ "#{array[0...-1].join(', ')}, #{connector} #{array[-1]}"
114
+ end
115
+ end
116
+
117
+ end
118
+ end
@@ -0,0 +1,7 @@
1
+ module Jekyll
2
+
3
+ class Generator < Plugin
4
+
5
+ end
6
+
7
+ end
@@ -0,0 +1,113 @@
1
+ module Jekyll
2
+
3
+ class Pagination < Generator
4
+ # This generator is safe from arbitrary code execution.
5
+ safe true
6
+
7
+ # Generate paginated pages if necessary.
8
+ #
9
+ # site - The Site.
10
+ #
11
+ # Returns nothing.
12
+ def generate(site)
13
+ site.pages.dup.each do |page|
14
+ paginate(site, page) if Pager.pagination_enabled?(site.config, page.name)
15
+ end
16
+ end
17
+
18
+ # Paginates the blog's posts. Renders the index.html file into paginated
19
+ # directories, e.g.: page2/index.html, page3/index.html, etc and adds more
20
+ # site-wide data.
21
+ #
22
+ # site - The Site.
23
+ # page - The index.html Page that requires pagination.
24
+ #
25
+ # {"paginator" => { "page" => <Number>,
26
+ # "per_page" => <Number>,
27
+ # "posts" => [<Post>],
28
+ # "total_posts" => <Number>,
29
+ # "total_pages" => <Number>,
30
+ # "previous_page" => <Number>,
31
+ # "next_page" => <Number> }}
32
+ def paginate(site, page)
33
+ all_posts = site.site_payload['site']['posts']
34
+ pages = Pager.calculate_pages(all_posts, site.config['paginate'].to_i)
35
+ (1..pages).each do |num_page|
36
+ pager = Pager.new(site.config, num_page, all_posts, pages)
37
+ if num_page > 1
38
+ newpage = Page.new(site, site.source, page.dir, page.name)
39
+ newpage.pager = pager
40
+ newpage.dir = File.join(page.dir, "page#{num_page}")
41
+ site.pages << newpage
42
+ else
43
+ page.pager = pager
44
+ end
45
+ end
46
+ end
47
+ end
48
+
49
+ class Pager
50
+ attr_reader :page, :per_page, :posts, :total_posts, :total_pages, :previous_page, :next_page
51
+
52
+ # Calculate the number of pages.
53
+ #
54
+ # all_posts - The Array of all Posts.
55
+ # per_page - The Integer of entries per page.
56
+ #
57
+ # Returns the Integer number of pages.
58
+ def self.calculate_pages(all_posts, per_page)
59
+ (all_posts.size.to_f / per_page.to_i).ceil
60
+ end
61
+
62
+ # Determine if pagination is enabled for a given file.
63
+ #
64
+ # config - The configuration Hash.
65
+ # file - The String filename of the file.
66
+ #
67
+ # Returns true if pagination is enabled, false otherwise.
68
+ def self.pagination_enabled?(config, file)
69
+ file == 'index.html' && !config['paginate'].nil?
70
+ end
71
+
72
+ # Initialize a new Pager.
73
+ #
74
+ # config - The Hash configuration of the site.
75
+ # page - The Integer page number.
76
+ # all_posts - The Array of all the site's Posts.
77
+ # num_pages - The Integer number of pages or nil if you'd like the number
78
+ # of pages calculated.
79
+ def initialize(config, page, all_posts, num_pages = nil)
80
+ @page = page
81
+ @per_page = config['paginate'].to_i
82
+ @total_pages = num_pages || Pager.calculate_pages(all_posts, @per_page)
83
+
84
+ if @page > @total_pages
85
+ raise RuntimeError, "page number can't be greater than total pages: #{@page} > #{@total_pages}"
86
+ end
87
+
88
+ init = (@page - 1) * @per_page
89
+ offset = (init + @per_page - 1) >= all_posts.size ? all_posts.size : (init + @per_page - 1)
90
+
91
+ @total_posts = all_posts.size
92
+ @posts = all_posts[init..offset]
93
+ @previous_page = @page != 1 ? @page - 1 : nil
94
+ @next_page = @page != @total_pages ? @page + 1 : nil
95
+ end
96
+
97
+ # Convert this Pager's data to a Hash suitable for use by Liquid.
98
+ #
99
+ # Returns the Hash representation of this Pager.
100
+ def to_liquid
101
+ {
102
+ 'page' => page,
103
+ 'per_page' => per_page,
104
+ 'posts' => posts,
105
+ 'total_posts' => total_posts,
106
+ 'total_pages' => total_pages,
107
+ 'previous_page' => previous_page,
108
+ 'next_page' => next_page
109
+ }
110
+ end
111
+ end
112
+
113
+ end