class Zenweb::Page
Page represents pretty much any type of file that goes on your website or is needed by other pages to build your website. Each page can have a YAML header that contains configuration data or variables used in the page.
Attributes
The parent page of this page. Can be nil.
The path to this source file.
The shared site instance.
The pages directly below this page. Can be empty.
Public Class Methods
Source
# File lib/zenweb/page.rb, line 46 def self.renderers_re @renderers_re ||= begin ext = instance_methods.grep(/^render_/).map { |s| s.to_s.sub(/render_/, '') } /(?:\.(#{ext.join "|"}))+$/ end end
Returns a regexp that will match file extensions for all known renderer types.
Public Instance Methods
Source
# File lib/zenweb/page.rb, line 72 def [] k warn("#{self.url} does not define #{k.inspect}") unless config.key?(k) config[k] end
Helper method to access the config value named k.
Source
# File lib/zenweb/page.rb, line 80 def all_subpages reversed = false dated, normal = subpages.partition(&:dated_path?) dated = dated.reverse if reversed (normal + dated).map { |p| [p, p.all_subpages(reversed)] } end
All pages below this page, possibly reversed, recursively.
Source
# File lib/zenweb/page.rb, line 91 def all_subpages_by_level reversed = false self.all_subpages(reversed).deep_each.map { |n, p| [(n-1)/2, p] } end
All pages below this page, possibly reversed, recursively, with the depth of each subpage relative to the current page.
Source
# File lib/zenweb/plugins/google.rb, line 64 def analytics [google_analytics, gauges_analytics].compact.join "\n\n" end
Source
# File lib/zenweb/page.rb, line 98 def body # TODO: add a test for something with --- without a yaml header. @body ||= begin thing = File.file?(path) ? path : self _, body = Zenweb::Config.split thing body.strip end end
Returns the actual content of the file minus the optional YAML header.
Source
# File lib/zenweb/page.rb, line 193 def change_frequency return config["change_frequency"] if config["change_frequency"] days_old = (Time.now - self.date).to_i / 86400 case days_old when 0...14 then "daily" when 14...56 then "weekly" when 56...365 then "monthly" else "yearly" end end
Source
# File lib/zenweb/page.rb, line 132 def clean_url url.sub(/\/index.html$/, '/') end
Return the url as users normally enter them (ie, no index.html).
Source
# File lib/zenweb/page.rb, line 141 def config unless defined? @config then @config = Config.new site, path @config = @config.parent unless content.start_with? "---" end @config end
Returns the closest Config instance for this file. That could be the YAML prefix in the file or it could be a _config.yml file in the fileās directory or above.
Source
# File lib/zenweb/page.rb, line 152 def content # TODO: this has the same drawbacks as Config.split @content ||= File.read path end
Returns the entire (raw) content of the file.
Source
# File lib/zenweb/page.rb, line 164 def date config['date'] || date_from_path || File.stat(path).mtime end
Returns either:
+ The value of the date config value + The date embedded in the filename itself (eg: 2012-01-02-blah.html). + The last modified timestamp of the file itself.
Source
# File lib/zenweb/page.rb, line 174 def date_str fmt ||= self.config["date_fmt"] || "%Y-%m" # REFACTOR: yuck self.date.strftime fmt end
Source
# File lib/zenweb/page.rb, line 182 def dated? config['date'] || date_from_path end
Returns true if this page has a date (via config or within the path).
Source
# File lib/zenweb/page.rb, line 189 def dated_path? path[/\d\d\d\d[-\/]\d\d[-\/]\d\d/] || path[/\d\d\d\d(?:[-\/]\d\d)?\/index/] end
Is this a dated page? (ie, does it have YYYY-MM-DD in the path?)
Source
# File lib/zenweb/page.rb, line 222 def depends_on deps if String === deps then file self.path => deps else deps = deps.values if Hash === deps deps = Array(deps) file self.url_path => deps.map(&:url_path) - [self.url_path] end end
Wires up additional dependencies for this Page. from_deps may be a Hash (eg site.pages), an Array (eg. site.categories.blog), or a single page.
Source
# File lib/zenweb/plugins/disqus.rb, line 6 def disqus shortname '<div id="disqus_thread"></div>' + run_js_script("https://#{shortname}.disqus.com/embed.js") end
Returns a javascript blob to add a disqus comments block to the page.
Source
# File lib/zenweb/plugins/disqus.rb, line 15 def disqus_counts shortname run_js_script "https://#{shortname}.disqus.com/count.js" end
Returns a javascript blob to convert properly formatted links to disqus comment counts.
Source
# File lib/zenweb/plugins/erb.rb, line 24 def erb content, source, binding = TOPLEVEL_BINDING require 'erb' extend ERB::Util unless defined? @erb then content = content. gsub(/\{\{/, "<%="). gsub(/\}\}/, "%>"). gsub(/\{%/, "<%"). gsub(/%\}/, "%>"). gsub(/\\([{}%])/, '\1') @erb = if RUBY_VERSION >= "2.6.0" then ERB.new(content, trim_mode:"-") else ERB.new(content, nil, "-") end end @erb.filename = source.inspect @erb.result binding end
Render erb in content for source with +binding.
Personally, I find erbās delimiters a bit annoying, so for now, Iāve added additional gsubās to the content to make it a bit more palatable.
{{ ... }} becomes <%= ... %>
{% ... %} becomes <% ... %>
Unfortunately, those are the delimiters from liquid, so if someone goes and makes a liquid plugin it could clash. But why youād have liquid and erb on the same file is beyond me⦠so it prolly wonāt become a legitimate issue.
Source
# File lib/zenweb/plugins/markdown.rb, line 26 def extend_md extend Zenweb::Page::MarkdownHelpers end
Source
# File lib/zenweb/page.rb, line 237 def filetype name = self.path File.extname(name)[1..-1] end
Returns the extension (without the ā.ā) of name, defaulting to self.path.
Source
# File lib/zenweb/page.rb, line 251 def filetypes @filetypes ||= path[self.class.renderers_re].split(/\./)[1..-1].reverse rescue [] end
Returns an array of extensions (in reverse order) of this page that match known renderers. For example:
Given renderer methods render_erb and render_md, the file āindex.html.md.erbā would return %w[erb md], but the file āindex.htmlā would return [].
Additional renderers can be added via Site.load_plugins.
Source
# File lib/zenweb/page.rb, line 260 def format_date s fmt = self.config["date_fmt"] || "%Y/%m/%d" Time.local(*s.split(/-/).map(&:to_i)).strftime(fmt) end
Format a date string s using the config value date_fmt or YYYY/MM/DD.
Source
# File lib/zenweb/plugins/google.rb, line 44 def gauges_analytics if site.config["gauges_id"] then <<-"EOM".gsub(/^ {8}/, '') <script type="text/javascript"> var _gauges = _gauges || []; (function() { var t = document.createElement('script'); t.type = 'text/javascript'; t.async = true; t.id = 'gauges-tracker'; t.setAttribute('data-site-id', '#{site.gauges_id}'); t.src = '//secure.gaug.es/track.js'; var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(t, s); })(); </script> EOM end end
Source
# File lib/zenweb/page.rb, line 268 def generate warn "Rendering #{url_path}" content = self.render open url_path, "w" do |f| f.puts content end end
Render and write the result to url_path.
Source
# File lib/zenweb/plugins/google.rb, line 7 def google_ad slot, width = 468, height = 60 <<-"EOM".gsub(/^ {6}/, '') <script><!-- google_ad_client = "#{self["google_ad_client"]}"; google_ad_slot = "#{slot}"; google_ad_width = #{width}; google_ad_height = #{height}; //--> </script> <script src="http://pagead2.googlesyndication.com/pagead/show_ads.js"> </script> EOM end
Returns a javascript blob to add a google ad to the page. You need to provide the configuration param āgoogle_ad_clientā to your site config for this to work.
Source
# File lib/zenweb/plugins/google.rb, line 21 def google_analytics if site.config["google_ua"] then <<-"EOM".gsub(/^ {8}/, '') <script type="text/javascript"> var _gaq = _gaq || []; _gaq.push(['_setAccount', '#{site.google_ua}']); _gaq.push(['_trackPageview']); (function() { var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true; ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'; (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(ga); })(); </script> EOM end end
Source
# File lib/zenweb/page.rb, line 213 def html? path =~ /\.html/ end
Returns true if this is an html page.
Source
# File lib/zenweb/page.rb, line 283 def include name, page incl = Page.new(site, File.join("_includes", name)) incl.subrender page end
Render a named file from _includes. You must pass in the current page. This can make its configuration available accessing it via page.
Source
# File lib/zenweb/page.rb, line 291 def index? url.end_with? "index.html" end
Returns true if this page is an index page.
Source
# File lib/zenweb/page.rb, line 304 def layout unless defined? @layout then @layout = site.layout self.config["layout"] end @layout rescue => e raise e.exception "%s for page %p" % [e.message, path] end
Return a layout Page named in the config key layout.
Source
# File lib/zenweb/page.rb, line 331 def link_head **kws %(<link #{kws.map { |k,v| "#{k}=#{v.inspect}" }.join " "} />) end
Stupid helper method to make declaring header link lines cleaner
Source
# File lib/zenweb/page.rb, line 316 def link_html title = self.title %(<a href="#{clean_url}">#{title}</a>) end
Convenience function to create an html link for this page.
Source
# File lib/zenweb/plugins/markdown.rb, line 36 def markdown content, no_line_numbers = false require "kramdown" require "kramdown-parser-gfm" require "kramdown-syntax-coderay" require "coderay/zenweb_extensions" config = KRAMDOWN_CONFIG.dup if no_line_numbers then config[:syntax_highlighter_opts] = config[:syntax_highlighter_opts].dup config[:syntax_highlighter_opts][:line_numbers] = nil end Kramdown::Document.new(content, config).to_html end
Render markdown content.
I cheated and added some additional gsubs. I prefer āāā langā so that works now.
Source
# File lib/zenweb/page.rb, line 323 def meta key, name=key, label="name" val = self.config[key] %(<meta #{label}="#{name}" content="#{val}">) if val end
Stupid helper method to make declaring header meta lines cleaner
Source
# File lib/zenweb/page.rb, line 110 def parent_url url = self.url url = File.dirname url if File.basename(url) == "index.html" File.join File.dirname(url), "index.html" end
Returns the parent url of a particular url (or self).
Source
# File lib/zenweb/page.rb, line 361 def render page = self, content = nil content = subrender page, content layout = self.layout # TODO: make nullpage to avoid 'if layout' tests content = layout.render page, content if layout content end
Render this page as a whole. This includes rendering the pageās content into a layout if one has been specified via config.
Source
# File lib/zenweb/plugins/erb.rb, line 5 def render_erb page, content erb body, self, binding end
Render a pageās erb and return the result
Source
# File lib/zenweb/plugins/less.rb, line 5 def render_less page, content require "less" Less::Parser.new.parse(content || body).to_css end
Render less source to css.
Source
# File lib/zenweb/plugins/markdown.rb, line 21 def render_md page, content no_line_numbers = page.config["no_line_numbers"] markdown(content || self.body, no_line_numbers) end
Render markdown page content using kramdown.
Source
# File lib/zenweb/page.rb, line 395 def run_js_script url <<-"EOM".gsub(/^ {6}/, '') <script type="text/javascript"> (function() { var s = document.createElement('script'); s.type = 'text/javascript'; s.async = true; s.src = '#{url}'; (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(s); })(); </script> EOM end
TODO: move this and others to plugins/html_toys.rb (or something)
Source
# File lib/zenweb/page.rb, line 440 def series_page series = self.config[:series] Zenweb::SeriesPage.all[series] if series end
Source
# File lib/zenweb/page.rb, line 377 def stylesheet name link_head rel:"stylesheet", type:"text/css", href:"/css/#{name}.css" end
Stupid helper method to make declaring stylesheets cleaner
Source
# File lib/zenweb/page.rb, line 387 def subrender page = self, content = nil self.filetypes.inject(content) { |cont, type| send "render_#{type}", page, cont } || self.body end
Render a Page instance based on its filetypes. For example, index.html.md.erb will essentially call:
render_md(render_erb(content))
Source
# File lib/zenweb/page.rb, line 436 def tag_pages (self.config[:tags] || []).map { |t| Zenweb::TagDetail.all[t] }.compact end
Source
# File lib/zenweb/page.rb, line 415 def url @url ||= self.path. sub(/^/, '/'). sub(/(\d\d\d\d)-(\d\d)-(\d\d)-/) { |s| "#{format_date s}/" }. gsub(self.class.renderers_re, '') end
Return the url for this page. The url is based entirely on its location in the file-system.
TODO: expand
Source
# File lib/zenweb/page.rb, line 425 def url_dir File.dirname url_path end
The directory portion of the url.
Source
# File lib/zenweb/page.rb, line 432 def url_path @url_path ||= File.join(".site", self.url) end
The real file path for the generated file.
Source
# File lib/zenweb/page.rb, line 460 def wire @wired ||= false # HACK return if @wired @wired = true file self.path conf = self.config conf = conf.parent if self.path == conf.path file self.path => conf.path if conf.path conf.wire if self.layout then file self.path => self.layout.path self.layout.wire end file url_path => all_subpages.flatten.map(&:url_path) if url =~ /index.html/ unless url_dir =~ %r%/_% then directory url_dir file url_path => url_dir file url_path => path do self.generate end task :site => url_path end end
Wire up this page to the rest of the rake dependencies. If you have extra dependencies for this file (ie, an index page that links to many other pages) you can add them by creating a rake task named :extra_wirings and using depends_on. Eg:
task :extra_wirings do |x| site = $website page = site.pages page["sitemap.xml.erb"]. depends_on site.html_pages page["atom.xml.erb"]. depends_on site.pages_by_date.first(30) page["blog/index.html.erb"].depends_on site.categories.blog end