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,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
+