yuzu 0.2.1.pre

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 (116) hide show
  1. data/.document +5 -0
  2. data/.yardopts +7 -0
  3. data/ChangeLog.md +8 -0
  4. data/Gemfile +26 -0
  5. data/Gemfile.lock +30 -0
  6. data/LICENSE.txt +20 -0
  7. data/README.md +52 -0
  8. data/Rakefile +62 -0
  9. data/bin/yuzu +17 -0
  10. data/docs/About.md +19 -0
  11. data/docs/GettingStarted.md +48 -0
  12. data/docs/Reference.md +97 -0
  13. data/lib/helpers/object.rb +19 -0
  14. data/lib/helpers/path.rb +296 -0
  15. data/lib/helpers/string.rb +35 -0
  16. data/lib/helpers/system_checks.rb +10 -0
  17. data/lib/helpers/url.rb +64 -0
  18. data/lib/html/base.rb +187 -0
  19. data/lib/uploader/base.rb +59 -0
  20. data/lib/uploader/config.rb +19 -0
  21. data/lib/uploader/filesystem_service.rb +72 -0
  22. data/lib/uploader/ftp_service.rb +90 -0
  23. data/lib/uploader/s3_service.rb +135 -0
  24. data/lib/uploader/service.rb +57 -0
  25. data/lib/uploader/suppressor.rb +25 -0
  26. data/lib/yuzu.rb +6 -0
  27. data/lib/yuzu/argparse.rb +60 -0
  28. data/lib/yuzu/command.rb +104 -0
  29. data/lib/yuzu/commands/base.rb +150 -0
  30. data/lib/yuzu/commands/create.rb +68 -0
  31. data/lib/yuzu/commands/generate.rb +95 -0
  32. data/lib/yuzu/commands/help.rb +20 -0
  33. data/lib/yuzu/commands/preview.rb +58 -0
  34. data/lib/yuzu/commands/publish.rb +43 -0
  35. data/lib/yuzu/commands/stage.rb +62 -0
  36. data/lib/yuzu/commands/watch.rb +70 -0
  37. data/lib/yuzu/content/blog_post.rb +45 -0
  38. data/lib/yuzu/content/sample_project.rb +130 -0
  39. data/lib/yuzu/core/config.rb +154 -0
  40. data/lib/yuzu/core/layout.rb +85 -0
  41. data/lib/yuzu/core/paginated_file.rb +69 -0
  42. data/lib/yuzu/core/registrar.rb +32 -0
  43. data/lib/yuzu/core/siteroot.rb +57 -0
  44. data/lib/yuzu/core/template.rb +158 -0
  45. data/lib/yuzu/core/updater.rb +123 -0
  46. data/lib/yuzu/core/visitor.rb +44 -0
  47. data/lib/yuzu/core/website_base.rb +150 -0
  48. data/lib/yuzu/core/website_file.rb +270 -0
  49. data/lib/yuzu/core/website_folder.rb +176 -0
  50. data/lib/yuzu/filters/base.rb +86 -0
  51. data/lib/yuzu/filters/catalog.rb +248 -0
  52. data/lib/yuzu/filters/categories.rb +58 -0
  53. data/lib/yuzu/filters/currentpath.rb +35 -0
  54. data/lib/yuzu/filters/description.rb +16 -0
  55. data/lib/yuzu/filters/extension.rb +16 -0
  56. data/lib/yuzu/filters/images.rb +32 -0
  57. data/lib/yuzu/filters/linkroot.rb +35 -0
  58. data/lib/yuzu/filters/post_date.rb +45 -0
  59. data/lib/yuzu/filters/post_title.rb +66 -0
  60. data/lib/yuzu/filters/post_title_removed.rb +28 -0
  61. data/lib/yuzu/filters/sidebar.rb +26 -0
  62. data/lib/yuzu/filters/template.rb +16 -0
  63. data/lib/yuzu/generators/base.rb +44 -0
  64. data/lib/yuzu/generators/category_folders.rb +91 -0
  65. data/lib/yuzu/generators/index.rb +108 -0
  66. data/lib/yuzu/generators/paginate.rb +136 -0
  67. data/lib/yuzu/postprocessors/all_categories.rb +48 -0
  68. data/lib/yuzu/postprocessors/base.rb +34 -0
  69. data/lib/yuzu/postprocessors/contents_without_first_paragraph.rb +20 -0
  70. data/lib/yuzu/postprocessors/excerpt.rb +23 -0
  71. data/lib/yuzu/postprocessors/first_paragraph.rb +16 -0
  72. data/lib/yuzu/postprocessors/pagination.rb +35 -0
  73. data/lib/yuzu/postprocessors/recent_posts.rb +27 -0
  74. data/lib/yuzu/postprocessors/thumbnails.rb +48 -0
  75. data/lib/yuzu/preprocessors/base.rb +71 -0
  76. data/lib/yuzu/preprocessors/insert_contents.rb +57 -0
  77. data/lib/yuzu/renderers/base.rb +23 -0
  78. data/lib/yuzu/renderers/breadcrumb.rb +163 -0
  79. data/lib/yuzu/renderers/gallery.rb +24 -0
  80. data/lib/yuzu/renderers/title.rb +21 -0
  81. data/lib/yuzu/translators/base.rb +57 -0
  82. data/lib/yuzu/translators/markdown.rb +21 -0
  83. data/lib/yuzu/translators/plaintext.rb +17 -0
  84. data/lib/yuzu/version.rb +12 -0
  85. data/resources/config/compass.rb +6 -0
  86. data/resources/config/yuzu.yml +166 -0
  87. data/resources/git/post-commit +42 -0
  88. data/resources/sample_content/introduction/_snippets/about_insert_contents.md +3 -0
  89. data/resources/sample_content/introduction/about.md +6 -0
  90. data/resources/sample_content/introduction/advanced-posts.md +18 -0
  91. data/resources/sample_content/introduction/blog/blog-folder-is-special.md +8 -0
  92. data/resources/sample_content/introduction/getting-started.md +14 -0
  93. data/resources/sample_content/introduction/index.md +6 -0
  94. data/resources/sample_content/introduction/sample-post.md +13 -0
  95. data/resources/sample_projects.yml +7 -0
  96. data/resources/themes/minimal/_sass/print.sass +0 -0
  97. data/resources/themes/minimal/_sass/screen.sass +81 -0
  98. data/resources/themes/minimal/_templates/_block.haml +4 -0
  99. data/resources/themes/minimal/_templates/_blog.haml +3 -0
  100. data/resources/themes/minimal/_templates/_footer.haml +2 -0
  101. data/resources/themes/minimal/_templates/_gallery.haml +25 -0
  102. data/resources/themes/minimal/_templates/_head.haml +12 -0
  103. data/resources/themes/minimal/_templates/_header.haml +1 -0
  104. data/resources/themes/minimal/_templates/_menu.haml +6 -0
  105. data/resources/themes/minimal/_templates/blog.haml +21 -0
  106. data/resources/themes/minimal/_templates/generic.haml +26 -0
  107. data/resources/themes/minimal/_templates/home.haml +15 -0
  108. data/resources/themes/minimal/_templates/index.haml +21 -0
  109. data/resources/themes/minimal/css/print.css +0 -0
  110. data/resources/themes/minimal/css/screen.css +133 -0
  111. data/resources/themes/minimal/img/favicon.png +0 -0
  112. data/resources/yard/default/fulldoc/html/css/common.css +16 -0
  113. data/test/helper.rb +18 -0
  114. data/test/test_yuzu.rb +8 -0
  115. data/yuzu.gemspec +182 -0
  116. metadata +302 -0
@@ -0,0 +1,16 @@
1
+ require 'filters/base'
2
+
3
+ module Yuzu::Filters
4
+ class ExtensionFilter < Filter
5
+ def initialize
6
+ @name = :extension
7
+ @directive = "OUTPUT"
8
+ end
9
+
10
+ def default(website_file=nil)
11
+ ".html"
12
+ end
13
+ end
14
+ Filter.register(:extension => ExtensionFilter)
15
+ end
16
+
@@ -0,0 +1,32 @@
1
+ require 'filters/base'
2
+
3
+ module Yuzu::Filters
4
+ class ImagesFilter < Filter
5
+ def initialize
6
+ @name = :images
7
+ @directive = "IMAGES"
8
+ end
9
+
10
+ def default(website_file=nil)
11
+ []
12
+ end
13
+
14
+ def get_value(website_file)
15
+ m = match(website_file.raw_contents)
16
+ return default if m.nil?
17
+
18
+ images = m.split(",")
19
+ images = images.collect {|img| img.strip}
20
+ images = images.reject {|img| img.empty?}
21
+
22
+ images = images.collect {|img|
23
+ img = Filter.filters[:linkroot].process(website_file, img)
24
+ Filter.filters[:currentpath].process(website_file, img)
25
+ }
26
+
27
+ images
28
+ end
29
+ end
30
+ Filter.register(:images => ImagesFilter)
31
+ end
32
+
@@ -0,0 +1,35 @@
1
+ require 'filters/base'
2
+
3
+ module Yuzu::Filters
4
+ class LinkrootFilter < Filter
5
+ def initialize
6
+ @name = :linkroot
7
+ @directive = "LINKROOT"
8
+ end
9
+
10
+ def filter_type
11
+ # Filter the LINKROOT in IMAGES and other path-dependent tags first, so they have the proper
12
+ # paths to search for. Then process LINKROOT afterwards.
13
+ [:prefilter, :postfilter]
14
+ end
15
+
16
+ def regex
17
+ /LINKROOT/
18
+ end
19
+
20
+ def get_value(website_file)
21
+ website_file.config.linkroot
22
+ end
23
+
24
+ def get_match(contents)
25
+ m = contents.match(regex)
26
+ m.nil? ? nil : m[0]
27
+ end
28
+
29
+ def replacement(website_file, processing_contents=nil)
30
+ website_file.config.linkroot
31
+ end
32
+ end
33
+ Filter.register(:linkroot => LinkrootFilter)
34
+ end
35
+
@@ -0,0 +1,45 @@
1
+ require 'filters/base'
2
+
3
+ module Yuzu::Filters
4
+ class PostDateFilter < Filter
5
+ def initialize
6
+ @directive = "DATE"
7
+ @name = :post_date
8
+ end
9
+
10
+ def default(website_file)
11
+ website_file.modified_at
12
+ end
13
+
14
+ def get_value(website_file)
15
+ date = match(website_file.raw_contents)
16
+
17
+ if not date.nil?
18
+ begin
19
+ date = Time.parse(date)
20
+ rescue
21
+ date = nil
22
+ end
23
+ end
24
+
25
+ date ||= extract_date_from_filename(website_file)
26
+ date ||= extract_date_from_folder_structure(website_file)
27
+ date ||= default(website_file)
28
+ date
29
+ end
30
+
31
+ def extract_date_from_filename(website_file)
32
+ post_filename = website_file.filename
33
+ m = post_filename.match(/[0-9]{4}\-[0-9]{2}\-[0-9]{2}/)
34
+ m.nil? ? nil : Time.parse(m[0])
35
+ end
36
+
37
+ def extract_date_from_folder_structure(website_file)
38
+ m = website_file.path.relative.match(/[0-9]{4}\/[0-9]{2}\/[0-9]{2}/)
39
+ m.nil? ? nil : Time.parse(m[0].gsub("/", "-"))
40
+ end
41
+
42
+ end
43
+ Filter.register(:post_date => PostDateFilter)
44
+ end
45
+
@@ -0,0 +1,66 @@
1
+ require 'filters/base'
2
+
3
+ module Yuzu::Filters
4
+ class PostTitleFilter < Filter
5
+ def initialize
6
+ @directive = "TITLE"
7
+ @name = :post_title
8
+ end
9
+
10
+ def default(website_file)
11
+ extract_title_from_filename(website_file.path)
12
+ end
13
+
14
+ def get_value(website_file)
15
+ contents = website_file.raw_contents
16
+
17
+ title = match(contents)
18
+
19
+ if title.nil? and website_file.markdown?
20
+ m = contents.match(/^#\s+.*?\n/)
21
+ title = m.nil? ? nil : m[0].sub("#", "").strip
22
+ end
23
+ return title
24
+ end
25
+
26
+ def extract_title_from_filename(path)
27
+ post_filename = nil
28
+ name = path.rootname
29
+ raw_path = path.relative
30
+
31
+ if name.include?("index")
32
+ # If we're looking at an index, grab the folder name instead.
33
+ post_filename = path.parent.rootname
34
+ return post_filename.blank? ? "Home" : post_filename.titlecase
35
+ end
36
+
37
+ if post_filename.nil?
38
+ # Look for the YYYY/MM/DD-title-here.md pattern.
39
+ m = raw_path.match(/[0-9]{4}\/[0-9]{2}\/[0-9]{2}\-/)
40
+ if not m.nil?
41
+ post_filename = name[3..-1]
42
+ end
43
+ end
44
+
45
+ if post_filename.nil?
46
+ # Look for the YYYY/MM/title-here.md pattern.
47
+ m = raw_path.match(/[0-9]{4}\/[0-9]{2}\//)
48
+ if not m.nil?
49
+ post_filename = name
50
+ end
51
+ end
52
+
53
+ if post_filename.nil?
54
+ post_filename = name
55
+ end
56
+
57
+ # Remove the YYYY-MM-DD- date prefix if present.
58
+ post_filename = post_filename.sub(/[0-9]{4}\-[0-9]{2}\-[0-9]{2}\-/, "")
59
+
60
+ return post_filename.titlecase
61
+ end
62
+
63
+ end
64
+ Filter.register(:post_title => PostTitleFilter)
65
+ end
66
+
@@ -0,0 +1,28 @@
1
+ require 'filters/base'
2
+
3
+ module Yuzu::Filters
4
+ class PostTitleRemovedFilter < Filter
5
+ def initialize
6
+ @directive = "POSTTITLEREMOVED"
7
+ @name = :post_title_removed
8
+ end
9
+
10
+ def default(website_file)
11
+ ""
12
+ end
13
+
14
+ def regex
15
+ /^#\s+.*?\n/
16
+ end
17
+
18
+ def replacement(website_file, processing_contents=nil)
19
+ if website_file.config.remove_h1_tags
20
+ ""
21
+ else
22
+ processing_contents.match(regex)
23
+ end
24
+ end
25
+ end
26
+ Filter.register(:post_title_removed => PostTitleRemovedFilter)
27
+ end
28
+
@@ -0,0 +1,26 @@
1
+ require 'filters/base'
2
+ require 'translators/base'
3
+
4
+ module Yuzu::Filters
5
+ class SidebarFilter < Filter
6
+ def initialize
7
+ @name = :sidebar
8
+ @directive = "SIDEBAR"
9
+ end
10
+
11
+ def regex
12
+ /SIDEBAR\s*\{([\w\W]*?)\}/
13
+ end
14
+
15
+ def default(website_file=nil)
16
+ ""
17
+ end
18
+
19
+ def get_value(website_file)
20
+ sidebar = match(website_file.raw_contents).to_s
21
+ Yuzu::Translators::Translator.translate(sidebar, website_file.path.extension)
22
+ end
23
+ end
24
+ Filter.register(:sidebar => SidebarFilter)
25
+ end
26
+
@@ -0,0 +1,16 @@
1
+ require 'filters/base'
2
+
3
+ module Yuzu::Filters
4
+ class TemplateFilter < Filter
5
+ def initialize
6
+ @directive = "TEMPLATE"
7
+ @name = :template
8
+ end
9
+
10
+ def default(website_file)
11
+ "generic.haml"
12
+ end
13
+ end
14
+ Filter.register(:template => TemplateFilter)
15
+ end
16
+
@@ -0,0 +1,44 @@
1
+ require 'filters/base'
2
+
3
+ module Yuzu::Generators
4
+ include Yuzu::Registrar
5
+ include Yuzu::Filters
6
+
7
+ # Generators are like filters but they have the ability to produce new files and folders in the
8
+ # website tree.
9
+ class Generator < Filter
10
+ @@generators = {}
11
+ def self.registry
12
+ :generators
13
+ end
14
+ def self.generators
15
+ @@generators
16
+ end
17
+
18
+ attr_reader :name, :directive
19
+
20
+ def initialize
21
+ @name = :generator
22
+ @directive = "GENERATOR"
23
+ end
24
+
25
+ def should_generate?(website_file)
26
+ false
27
+ end
28
+
29
+ def visitor_filter
30
+ proc {|c| true}
31
+ end
32
+
33
+ # generate!() is called on the first pass by a visitor in the siteroot.
34
+ #
35
+ # @param [WebsiteFile, WebsiteFolder] website_obj The seed page that requires generation.
36
+ def generate!(website_obj)
37
+ # Produce new children and add them to the tree, if necessary.
38
+ end
39
+ end
40
+
41
+ end
42
+
43
+
44
+
@@ -0,0 +1,91 @@
1
+ require 'generators/base'
2
+ require 'generators/index'
3
+ require 'helpers/path'
4
+
5
+ module Yuzu::Generators
6
+ class CategoryFoldersGenerator < Generator
7
+ include Helpers
8
+
9
+ def initialize
10
+ @name = :category_folders
11
+ @directive = "CATEGORYFOLDERS"
12
+ end
13
+
14
+ def should_generate?(website_folder)
15
+ website_folder.is_blog?
16
+ end
17
+
18
+ def visitor_filter
19
+ proc do |c|
20
+ if c.file?
21
+ @all_categories = c.all_categories
22
+ end
23
+ c.folder?
24
+ end
25
+ end
26
+
27
+ def generate!(website_folder)
28
+ @all_categories.each do |category|
29
+ generate_folder_for_category!(category, website_folder.blog_folder)
30
+ end
31
+ end
32
+
33
+ def generate_folder_for_category!(category, blog_folder)
34
+ blog_folder.append_child(folder_for_category(category, blog_folder))
35
+ end
36
+
37
+ def folder_for_category(category, blog_folder)
38
+ category_folder = GeneratedFolder.new(category.path, blog_folder)
39
+ index_child = index_for_category(category, category_folder, blog_folder)
40
+ category_folder.append_child(index_child)
41
+ category_folder
42
+ end
43
+
44
+ def index_for_category(category, parent_folder, blog_folder)
45
+ GeneratedIndex.new(
46
+ parent_folder,
47
+ Yuzu::Generators.category_index_template(blog_folder.path.relative, category.name)
48
+ )
49
+ end
50
+
51
+ end
52
+ Generator.register(:category_folders => CategoryFoldersGenerator)
53
+
54
+
55
+ class GeneratedFolder < WebsiteFolder
56
+ include Helpers
57
+
58
+ def initialize(path, parent, children=[])
59
+ raise ArgumentError, "Not a Path object." if not path.is_a?(Path)
60
+ @path = path
61
+ raise "@path is nil for #{self}" if @path.nil?
62
+
63
+ @parent = parent
64
+ @children = children
65
+
66
+ @kind = :folder
67
+ end
68
+
69
+ def to_s
70
+ "GeneratedFolder(#{@path})"
71
+ end
72
+
73
+ def children
74
+ @children.nil? ? [] : @children
75
+ end
76
+
77
+ def files
78
+ @children.select {|c| c.file?}
79
+ end
80
+
81
+ def folders
82
+ @children.select {|c| c.folder?}
83
+ end
84
+
85
+ def all_files
86
+ files
87
+ end
88
+ end
89
+
90
+ end
91
+
@@ -0,0 +1,108 @@
1
+ require 'generators/base'
2
+
3
+ module Yuzu::Generators
4
+ class IndexGenerator < Generator
5
+
6
+ @@indexed_folders = []
7
+ def self.get_indexed
8
+ @@index_folders
9
+ end
10
+
11
+ def self.add_indexed_folder(folder)
12
+ @@indexed_folders.push(folder)
13
+ end
14
+
15
+ def self.is_indexed?(folder)
16
+ @@indexed_folders.include?(folder)
17
+ end
18
+
19
+ def initialize
20
+ @name = "index"
21
+ @directive = "INDEX"
22
+ end
23
+
24
+ def should_generate?(website_folder)
25
+ not IndexGenerator.is_indexed?(website_folder) and \
26
+ not website_folder.has_index?
27
+ end
28
+
29
+ def visitor_filter
30
+ proc {|c| c.folder? and c.config.can_index_folder?(c.path)}
31
+ end
32
+
33
+ def generate!(website_folder)
34
+ return if IndexGenerator.is_indexed?(website_folder)
35
+
36
+ generate_index_at_path!(website_folder)
37
+ end
38
+
39
+ def generate_index_at_path!(website_folder)
40
+ new_index = GeneratedIndex.new(website_folder)
41
+
42
+ website_folder.append_child(new_index)
43
+ IndexGenerator.add_indexed_folder(website_folder)
44
+ end
45
+ end
46
+
47
+
48
+ class GeneratedIndex < WebsiteFile
49
+ def initialize(parent_folder, raw_contents=nil)
50
+ @raw_contents = raw_contents
51
+
52
+ index_path = parent_folder.path + default_index_filename
53
+ @path = index_path
54
+ @path.make_file!
55
+ raise "@path is nil for #{self}" if @path.nil?
56
+ @parent = parent_folder
57
+ @page = 1
58
+
59
+ @kind = :file
60
+ end
61
+
62
+ def to_s
63
+ "GeneratedIndex(#{@path.relative})"
64
+ end
65
+
66
+ def default_index_filename
67
+ "index.md"
68
+ end
69
+
70
+ def get_raw_contents
71
+ # Only becomes @raw_contents if it is still nil when raw_contents is first called.
72
+ Yuzu::Generators.default_index_template(@path.dirname)
73
+ end
74
+
75
+ def created_at
76
+ @created_at ||= Time.now
77
+ end
78
+
79
+ def modified_at
80
+ @modified_at ||= Time.now
81
+ end
82
+
83
+ def load_file_info!
84
+ end
85
+
86
+ def generated?
87
+ true
88
+ end
89
+ end
90
+ Generator.register(:index => IndexGenerator)
91
+
92
+ # TODO Put the auto-generated index contents in their own files.
93
+ def default_index_template(relative_contents_path)
94
+ "TEMPLATE(index.haml)
95
+
96
+ INSERTCATALOG(path:#{relative_contents_path}, page:1, per_page:10, per_col:1, template:_block.haml)"
97
+ end
98
+ module_function :default_index_template
99
+
100
+ def category_index_template(relative_contents_path, category_name)
101
+ "TEMPLATE(blog.haml)
102
+
103
+ INSERTCATALOG(path:#{relative_contents_path}, page:1, per_page:10, per_col:1, template:_blog.haml, category:#{category_name})"
104
+ end
105
+ module_function :category_index_template
106
+
107
+ end
108
+