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,70 @@
1
+ #require 'fssm'
2
+
3
+ #def rebuild_site(base, relative_path, config)
4
+ # $stderr.puts ">>> Change Detected to: #{relative_path} <<<"
5
+
6
+ # if File.directory?(relative_path)
7
+ # if relative_path.includes_one_of?(config.folder_blacklist)
8
+ # $stderr.puts ">>> Blacklisted folder found. No update."
9
+ # return
10
+ # elsif relative_path.include?(config.template_dir)
11
+ # $stderr.puts ">>> Change in a template found. No update (yet)."
12
+ # return
13
+ # end
14
+ # else
15
+ # file_ext = File.extname(relative_path)
16
+ # #if relative_path.includes_one_of?(config.folder_blacklist)
17
+ # # puts ">>> Blacklisted folder found. No update."
18
+ # # return
19
+ # #els
20
+ # if file_ext.includes_one_of?(config.extension_blacklist)
21
+ # $stderr.puts ">>> Blacklisted extension found. No update."
22
+ # return
23
+ # elsif relative_path.include?(config.template_dir)
24
+ # $stderr.puts ">>> Change in a template found. No update (yet)."
25
+ # return
26
+ # end
27
+ # end
28
+
29
+ # IO.popen("yuzu preview #{relative_path}") do |io|
30
+ # $stderr.print( io.readpartial(512) ) until io.eof?
31
+ # end
32
+
33
+ # $stderr.puts '>>> Update Complete <<<'
34
+ #end
35
+
36
+
37
+ module Yuzu::Command
38
+
39
+ class Watch < Base
40
+ # Method to start the watcher.
41
+ def index
42
+ $stder.puts "The watcher has been temporarily disabled. Please use yuzu preview."
43
+
44
+ #$stderr.puts ">>> Yuzu is watching for changes <<<"
45
+
46
+ ## The block below doesn't have the current Watch object in its scope,
47
+ ## so we can't pass in @config directly. Pass it into the *args parameter
48
+ ## and the hash becomes part of the @options instance variable in the
49
+ ## FSSM implementation. Then unpack it and pass the YuzuConfig(@config)
50
+ ## to the rebuild_site method.
51
+ #FSSM.monitor("#{Dir.pwd}", '**/*', :config => @config) do
52
+ # update {|base, relative| rebuild_site(base, relative, @options[:config])}
53
+ # delete {|base, relative| rebuild_site(base, relative, @options[:config])}
54
+ # create {|base, relative| rebuild_site(base, relative, @options[:config])}
55
+ #end
56
+
57
+ end
58
+
59
+ def self.help method
60
+ case method
61
+ when :index
62
+ "Watches the current directory for changes and automatically updates the preview of changed files."
63
+ else
64
+
65
+ end
66
+ end
67
+ end
68
+
69
+ end
70
+
@@ -0,0 +1,45 @@
1
+
2
+ module Yuzu::Content
3
+ class BlogPost
4
+ def initialize(postname, config)
5
+ @postname = postname
6
+ @filename = postname.dasherize.downcase
7
+ @config = config
8
+ end
9
+
10
+ def deliver!
11
+ date = Time.now.strftime("%Y-%m-%d")
12
+ full_filename = "#{date}-#{@filename}.md"
13
+
14
+ file_path = File.join(@config.blog_dir, full_filename)
15
+
16
+ if File.exists?(file_path)
17
+ $stderr.puts "Warning: File #{@filename} already exists!"
18
+
19
+ else
20
+ $stderr.puts "Creating file: #{@filename}"
21
+
22
+ File.open(file_path, "w+") do |f|
23
+ f.puts(contents)
24
+ end
25
+
26
+ end
27
+ end
28
+
29
+ def contents
30
+ return %Q{# #{@postname}
31
+
32
+ The title of this post is #{@postname}.
33
+
34
+ Lorem ipsum dolor sit amet, consectetur adipisicing elit,
35
+ sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim
36
+ ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip
37
+ ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate
38
+ velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat
39
+ cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id
40
+ est laborum.
41
+ }
42
+ end
43
+ end
44
+
45
+ end
@@ -0,0 +1,130 @@
1
+ require 'yaml'
2
+ require 'etc'
3
+
4
+ module Yuzu::Content
5
+ class ProjectNotFound < Exception; end
6
+ class ThemeNotFound < Exception; end
7
+ class SampleContentNotFound < Exception; end
8
+ class ConfigNotFound < Exception; end
9
+
10
+ class SampleProject
11
+ def self.registered_projects
12
+ @@registry ||= YAML.load_file(registry_file)
13
+ end
14
+
15
+ def self.registry_file
16
+ File.join(resources_folder, "sample_projects.yml")
17
+ end
18
+
19
+ def initialize(sample_project_name)
20
+ @name = sample_project_name
21
+
22
+ if SampleProject.registered_projects.has_key?(@name)
23
+ @project_info = SampleProject.registered_projects[@name]
24
+ else
25
+ raise ProjectNotFound, "#{@name} is not a known sample project."
26
+ end
27
+ end
28
+
29
+ def deliver!
30
+ copy_theme!
31
+ copy_content!
32
+ copy_config!
33
+ end
34
+
35
+ def theme_name
36
+ @project_info['theme']
37
+ end
38
+
39
+ def sample_content_name
40
+ @project_info['content']
41
+ end
42
+
43
+ def copy_theme!
44
+ theme_folder = File.join(SampleProject.theme_folder, theme_name)
45
+ if File.exists?(theme_folder)
46
+ copy_folder_contents!(theme_folder)
47
+ else
48
+ throw ThemeNotFound, "#{theme_name} is not a known theme."
49
+ end
50
+ end
51
+
52
+ def copy_content!
53
+ content_folder = File.join(SampleProject.sample_content_folder, sample_content_name)
54
+ if File.exists?(content_folder)
55
+ copy_folder_contents!(content_folder)
56
+ else
57
+ throw SampleContentNotFound, "#{sample_content_name} is not a known set of sample content."
58
+ end
59
+ end
60
+
61
+ def copy_config!
62
+ config_folder = File.join(SampleProject.resources_folder, "config")
63
+ copy_folder!(config_folder)
64
+ post_process_config!
65
+ end
66
+
67
+ def copy_folder!(folder_name)
68
+ FileUtils.cp_r(folder_name, SampleProject.destination_folder)
69
+ end
70
+
71
+ def copy_folder_contents!(folder)
72
+ source = File.join(folder, "*")
73
+ FileUtils.cp_r(Dir[source], SampleProject.destination_folder)
74
+ end
75
+
76
+ def post_process_config!
77
+ destination_config = File.join(SampleProject.destination_folder, "config", "yuzu.yml")
78
+ if File.exists?(destination_config)
79
+ user_home_folder = File.expand_path("~")
80
+ username = Etc.getlogin
81
+
82
+ config_contents = File.read(destination_config)
83
+
84
+ config_contents.gsub!("HOME", user_home_folder)
85
+ config_contents.gsub!("USERNAME", username)
86
+
87
+ File.open(destination_config, "w") do |config|
88
+ config.puts(config_contents)
89
+ end
90
+
91
+ load_new_config!(destination_config)
92
+ else
93
+ raise ConfigNotFound, "The yuzu.yml file wasn't found in the expected place: #{destination_config}."
94
+ end
95
+ end
96
+
97
+ def load_new_config!(destination_config_path)
98
+ @new_config ||= YAML.load_file(destination_config_path)
99
+ end
100
+
101
+ def new_config
102
+ if @new_config.nil?
103
+ raise ConfigNotFound, "New config file not found."
104
+ else
105
+ @new_config
106
+ end
107
+ end
108
+
109
+ def self.theme_folder
110
+ File.join(resources_folder, "themes")
111
+ end
112
+
113
+ def self.sample_content_folder
114
+ File.join(resources_folder, "sample_content")
115
+ end
116
+
117
+ def self.resources_folder
118
+ File.join(File.dirname(__FILE__), "..", "..", "..", "resources")
119
+ end
120
+
121
+ def self.destination_folder
122
+ Dir.pwd
123
+ end
124
+
125
+ def self.exists?(sample_project_name)
126
+ registered_projects.has_key?(sample_project_name)
127
+ end
128
+ end # SampleProject
129
+
130
+ end
@@ -0,0 +1,154 @@
1
+ require 'pathname'
2
+ require 'helpers/path'
3
+ require 'helpers/string'
4
+ require 'helpers/system_checks'
5
+
6
+ module Yuzu::Core
7
+ class Config
8
+ include Helpers
9
+
10
+ attr_reader :config_hash, :service
11
+
12
+ def initialize(config_hash, service_override=nil, parsed_options=[])
13
+ @config_hash = config_hash
14
+ @service = service_override || config_hash['connection']
15
+ @options = parsed_options
16
+
17
+ # Create a method for every top-level key in the configuration dictionary.
18
+ (class << self; self; end).class_eval do
19
+ config_hash.each_pair do |key, value|
20
+ instance_variable = "@#{key}".to_sym
21
+
22
+ define_method key do
23
+ if instance_variable_get(instance_variable).nil?
24
+ instance_variable_set(instance_variable, value)
25
+ end
26
+ instance_variable_get(instance_variable)
27
+ end
28
+
29
+ define_method "set_#{key}" do |other|
30
+ instance_variable_set(instance_variable, other)
31
+ end
32
+
33
+ end
34
+ end
35
+
36
+ check_for_gems
37
+ end
38
+
39
+ OPTIONAL_GEMS = ['compass']
40
+
41
+ # Provides information about installed gems for optional features, like Compass integration, git
42
+ # integration,
43
+ def check_for_gems
44
+
45
+ OPTIONAL_GEMS.each do |gem_name|
46
+ method_name = "has_#{gem_name.underline}?".to_sym
47
+
48
+ (class << self; self; end).class_eval do
49
+ instance_variable_name = "@has_#{gem_name.underline}".to_sym
50
+
51
+ define_method method_name do
52
+ if instance_variable_get(instance_variable_name).nil?
53
+ gem_installed = SystemChecks.gem_available?(gem_name)
54
+ instance_variable_set(instance_variable_name, gem_installed)
55
+ end
56
+ instance_variable_get(instance_variable_name)
57
+ end # define_method
58
+
59
+ end # class_eval
60
+
61
+ end # OPTIONAL_GEMS
62
+ end
63
+
64
+ def verbose?
65
+ @options.output == :verbose
66
+ end
67
+
68
+ def pwd
69
+ Path.new
70
+ end
71
+
72
+ def processable?(path)
73
+ check_extension(path.extension, processable_extensions)
74
+ end
75
+
76
+ def resource?(path)
77
+ check_extension(path.extension, resource_extensions)
78
+ end
79
+
80
+ def image?(path)
81
+ check_extension(path.extension, image_extensions)
82
+ end
83
+
84
+ def asset?(path)
85
+ check_extension(path.extension, asset_extensions)
86
+ end
87
+
88
+ def check_extension(extension, extensions)
89
+ return false if extension_blacklist.include?(extension)
90
+ return extensions.include?(extension)
91
+ end
92
+
93
+ def can_index_folder?(path)
94
+ absolute_no_index_paths = (no_index_folders + folder_blacklist + system_folders).collect {|p| Path.new(p)}
95
+
96
+ tr = false
97
+ absolute_no_index_paths.each do |folder|
98
+ tr ||= folder.contains?(path)
99
+ end
100
+ not tr
101
+ end
102
+
103
+ def system_folders
104
+ ["config", ".git"]
105
+ end
106
+
107
+ def link_root_for_service(service)
108
+ @config_hash['services'][service]['link_root'].to_s
109
+ end
110
+
111
+ def link_root
112
+ link_root_for_service(@service)
113
+ end
114
+
115
+ def linkroot
116
+ link_root
117
+ end
118
+
119
+ def domain
120
+ domain_for_service @service
121
+ end
122
+
123
+ def domain_for_service service
124
+ @config_hash[service]['domain'].to_s
125
+ end
126
+
127
+ def possible_indices
128
+ @processable_indices ||= processable_extensions.collect {|e| "index#{e}"}
129
+ end
130
+
131
+ def preview?
132
+ @service == 'preview'
133
+ end
134
+
135
+ def stage?
136
+ @service == 'stage'
137
+ end
138
+
139
+ # Checks to see whether file should be considered hidden. By default, all
140
+ # filenames and folders starting with an underscore are hidden.
141
+ def is_hidden?(path)
142
+ parts = path.split(File::SEPARATOR)
143
+ hidden = parts.collect do |f|
144
+ f[0].chr == "_"
145
+ end
146
+ hidden.any?
147
+ end
148
+
149
+ def is_blacklisted?(path)
150
+ path.includes_one_of?(folder_blacklist)
151
+ end
152
+ end
153
+
154
+ end
@@ -0,0 +1,85 @@
1
+ require 'core/template'
2
+
3
+ module Yuzu::Core
4
+ # A Layout is a Template that lays out an entire page. It consists of a collection of partial
5
+ # templates, namely for the HTML <head>, but also for a page header, footer, and navigation menu.
6
+ # In the future, this will be generalized.
7
+ class Layout < Yuzu::Core::HamlTemplate
8
+ # The standard page partials.
9
+ #def self.partial_names
10
+ # #%w(head header footer menu)
11
+ #end
12
+
13
+ # A hash of partial name to filename.
14
+ #
15
+ # @return [Hash]
16
+ def self.partial_filenames
17
+ relative_paths = Dir[(@@template_dir + "*").to_s]
18
+ files = relative_paths.collect {|p| File.basename(p)}
19
+ files.select {|filename| filename[0].chr == "_"}
20
+ end
21
+
22
+ # A hash of partial name to the corresponding HamlTemplate object for that partial.
23
+ #
24
+ # @return [Hash] of String => HamlTemplate
25
+ def self.partials
26
+ @@partials ||= get_partials
27
+ end
28
+
29
+ # Calculates the Hash for self.partials.
30
+ def self.get_partials
31
+ tr = {}
32
+ partial_filenames.each do |filename|
33
+ partial_name = filename[1...-5]
34
+ tr[partial_name] = HamlTemplate.new(filename)
35
+ end
36
+ tr
37
+ end
38
+
39
+ # A Hash of all the local variables passed into the Haml engine when the layout is rendered.
40
+ #
41
+ # @param [WebsiteFile] website_file The website file being rendered.
42
+ # @return [Hash] of local variables available in the template.
43
+ def layout_locals(website_file)
44
+ {:layout => PageLayout.new(website_file, Layout.partials)}
45
+ end
46
+
47
+ # Actually renders the layout for the given file.
48
+ #
49
+ # @param [WebsiteFile] website_file The website_file being rendered in the layout.
50
+ # @return [String] A string containing the HTML rendered contents of the file as a webpage.
51
+ def render(website_file)
52
+ # Contains the standard local variables `post` and `config`.
53
+ local_variables = locals(website_file)
54
+
55
+ # Add `layout` to the mix.
56
+ layout_local_variables = layout_locals(website_file)
57
+
58
+ engine.render(
59
+ Yuzu::Core::TemplateMethods.new(website_file.root),
60
+ local_variables.merge(layout_local_variables)
61
+ )
62
+ end
63
+ end
64
+
65
+
66
+ # A class that encapsulates the variables in the `layout` namespace in the Haml layout. This means
67
+ # that the user can access variables passed into the `kwds` hash with dot notation on `layout`.
68
+ # For example:
69
+ #
70
+ # layout.head - Refers to the rendered contents of _head.haml
71
+ #
72
+ class PageLayout
73
+ def initialize(website_file, kwds={})
74
+ kwds.each_pair do |method_name, template_obj|
75
+ (class << self; self; end).class_eval do
76
+ define_method method_name.to_sym do
77
+ template_obj.render(website_file)
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
83
+
84
+ end
85
+