yuzu 0.2.1.pre

Sign up to get free protection for your applications and to get access to all the features.
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
+