Class | Hobix::Weblog |
In: |
lib/hobix/weblog.rb
lib/hobix/base.rb |
Parent: | Object |
placed here to avoid dependency cycle between base.rb and weblog.rb
hobix_yaml | [R] | |
path | [RW] |
# File lib/hobix/base.rb, line 295 295: def self.add_entry_class( c ) 296: @@entry_classes << c 297: end
# File lib/hobix/weblog.rb, line 834 834: def authorize( user, pass ) 835: require 'digest/sha1' 836: authors[user]['password'] == Digest::SHA1.new( pass ) 837: end
Used by regenerate to construct the vars hash by calling the appropriate skel method for each page.
# File lib/hobix/weblog.rb, line 425 425: def build_pages( page_name ) 426: vars = {} 427: paths = page_name.split( '/' ) 428: loop do 429: try_page = paths.join( '_' ).gsub('-','_') 430: if respond_to? "skel_#{ try_page }" 431: section_path = File.dirname( page_name ) 432: path_storage = storage.path_storage( section_path ) 433: method( "skel_#{ try_page }" ).call( path_storage, section_path ) do |vars| 434: vars[:weblog] = self 435: raise TypeError, "No `page' variable returned from skel_#{ try_page }." unless vars[:page] 436: yield vars 437: end 438: return 439: end 440: break unless paths.slice!( -2 ) ## go up a directory 441: end 442: vars[:weblog] = self 443: vars[:page] = Page.new( page_name ) 444: vars[:page].timestamp = Time.now 445: yield vars 446: end
# File lib/hobix/weblog.rb, line 359 359: def central_ext; @central_ext =~ /^\w*$/ ? @central_ext.untaint : default_central_ext; end
# File lib/hobix/weblog.rb, line 358 358: def central_prefix; @central_prefix =~ /^[\w\.]+$/ ? @central_prefix.untaint : default_central_prefix; end
# File lib/hobix/weblog.rb, line 360 360: def entry_class( tag = nil ) 361: tag = @entry_class =~ /^[\w:]+$/ ? @entry_class.untaint : default_entry_class unless tag 362: 363: found_class = nil 364: if @@entry_classes 365: found_class = @@entry_classes.find do |c| 366: tag == c.name.split( '::' ).last.downcase 367: end 368: end 369: 370: begin 371: found_class || Hobix.const_find( tag ) 372: rescue NameError => e 373: raise NameError, "No such entry class #{ tag }" 374: end 375: end
# File lib/hobix/weblog.rb, line 354 354: def entry_path; File.expand_path( @entry_path || default_entry_path, @path ).untaint; end
Translate paths relative to the weblahhg‘s URL. This is especially important if a weblog isn‘t at the root directory for a domain.
# File lib/hobix/weblog.rb, line 399 399: def expand_path( path ) 400: File.expand_path( path.gsub( /^\/+/, '' ), self.link.path.gsub( /\/*$/, '/' ) ) 401: end
# File lib/hobix/weblog.rb, line 482 482: def facet_for( app ) 483: facets.each { |p| return if p.get app } 484: Hobix::BaseFacet.not_found app 485: end
Returns an Array of all facet plugins in use. (There can be many.)
# File lib/hobix/weblog.rb, line 478 478: def facets 479: @plugins.find_all { |p| p.is_a? BaseFacet } 480: end
# File lib/hobix/weblog.rb, line 376 376: def index_class( tag = nil ) 377: tag = @index_class =~ /^[\w:]+$/ ? @index_class.untaint : default_index_class unless tag 378: begin 379: Hobix.const_find( tag ) 380: rescue NameError => e 381: raise NameError, "No such index class #{ tag }" 382: end 383: end
# File lib/hobix/weblog.rb, line 813 813: def join_path( prefix, suffix ) 814: case prefix 815: when '', '.' 816: suffix 817: else 818: "#{ prefix }/#{ suffix }" 819: end 820: end
# File lib/hobix/weblog.rb, line 357 357: def lib_path; File.expand_path( @lib_path || default_lib_path, @path ).untaint; end
# File lib/hobix/weblog.rb, line 385 385: def link 386: URI::parse( @link.gsub( /\/$/, '' ) ).extend Hobix::UriStr 387: end
# File lib/hobix/weblog.rb, line 389 389: def linklist 390: if @linklist.class == ::Array 391: YAML::transfer( 'hobix.com,2004/linklist', {'links' => @linklist} ) 392: else 393: @linklist 394: end 395: end
Loads an entry from storage, first validating that the author is listed in the weblog config.
# File lib/hobix/weblog.rb, line 826 826: def load_and_validate_entry( entry_id ) 827: entry = storage.load_entry( entry_id ) 828: unless authors.has_key?( entry.author ) 829: raise AuthorNotFound, "Invalid author '#{ entry.author }' found in entry #{ entry_id }" 830: end 831: entry 832: end
For convenience, storage queries can be made through the Weblog class. Queries will return the full Entry data, though, so it‘s best to use this only when you‘re scripting and need data quick.
# File lib/hobix/weblog.rb, line 842 842: def method_missing( methId, *args ) 843: if storage.respond_to? methId 844: storage.method( methId ).call( *args ).collect do |e| 845: load_and_validate_entry( e.id ) 846: end 847: end 848: end
Built from the map of output destinations described by output_map, this map pairs entry IDs against their canonical destinations. The @central_prefix and @central_ext variables determine what output is canonical.
# File lib/hobix/weblog.rb, line 545 545: def output_entry_map 546: output_map 547: @output_entry_map 548: end
Reads skel_path for templates and builds a hash of all the various output files which will be generated. This method will cache the output_map once. Subsequent calls to output_map will quickly return the cached hash. To reset the cache, use reset_output_map.
# File lib/hobix/weblog.rb, line 494 494: def output_map 495: @output_map ||= nil 496: return @output_map if @output_map 497: path_watch = {} 498: @output_entry_map = {} 499: Find::find( skel_path ) do |path| 500: path.untaint 501: if File.basename(path)[0] == ?. 502: Find.prune 503: elsif not FileTest.directory? path 504: tpl_path = path.gsub( /^#{ Regexp::quote( skel_path ) }\/?/, '' ) 505: output = outputs.detect { |p| if tpl_path =~ /\.#{ p.extension }$/; tpl_path = $`; end } 506: if output 507: ## Figure out template extension and output filename 508: page_name, tpl_ext = tpl_path.dup, '' 509: while page_name =~ /\.\w+$/; page_name = $`; tpl_ext = $& + tpl_ext; end 510: next if tpl_ext.empty? 511: ## Build the output pages 512: build_pages( page_name ) do |vars| 513: ## Extension and Path 514: vars[:page].add_ext( tpl_ext ) 515: vars[:template] = path 516: vars[:output] = output 517: eid = ( vars[:entry] && vars[:entry].id ) || page_name 518: if not @output_entry_map[ eid ] 519: @output_entry_map[ eid ] = vars 520: elsif tpl_ext.split( '.' )[1] == central_ext 521: @output_entry_map[ eid ] = vars 522: end 523: 524: ## If output by a deeper page, skip 525: pub_name, = path_watch[vars[:page].link] 526: next if pub_name and !( vars[:page].link.index( page_name ) == 0 and 527: page_name.length > pub_name.length ) 528: 529: path_watch[vars[:page].link] = [page_name, vars] 530: end 531: end 532: end 533: end 534: @output_map = {} 535: path_watch.each_value do |page_name, vars| 536: @output_map[page_name] ||= [] 537: @output_map[page_name] << vars 538: end 539: @output_map 540: end
# File lib/hobix/weblog.rb, line 356 356: def output_path; File.expand_path( @output_path || default_output_path, @path ).untaint; end
Returns an Array of all output plugins in use. (There can be many.)
# File lib/hobix/weblog.rb, line 466 466: def outputs 467: @plugins.find_all { |p| p.is_a? BaseOutput } 468: end
Prints publication information the screen. Override this if you want to suppress output or change the display.
# File lib/hobix/weblog.rb, line 852 852: def p_publish( obj ) 853: puts "## Page: #{ obj.link }, updated #{ obj.updated }" 854: end
Returns an Array of all publisher plugins in use. (There can be many.)
# File lib/hobix/weblog.rb, line 472 472: def publishers 473: @plugins.find_all { |p| p.is_a? BasePublish } 474: end
Regenerates the weblog, processing templates in skel_path with the data found in entry_path, storing output in output_path.
The how parameter dictates how this is done, Currently, if how is nil the weblog is completely regen‘d. If it is :update, the weblog is only upgen‘d.
It‘s very important to know how updates work, especially if you are writing custom skel methods or devious new kinds of templates. When performing an update, this method will skip pages if the following conditions are met:
To ensure that your custom methods and templates are qualifying to be skipped on an upgen, be sure to set the updated timestamp of the Page object to the latest date of the content‘s modification.
# File lib/hobix/weblog.rb, line 578 578: def regenerate( how = nil ) 579: retouch nil, how 580: end
Clears the hash used to cache the results of output_map.
# File lib/hobix/weblog.rb, line 488 488: def reset_output_map; @output_map = nil; end
# File lib/hobix/weblog.rb, line 581 581: def retouch( only_path = nil, how = nil ) 582: published = {} 583: published_types = [] 584: output_map.each do |page_name, outputs| 585: puts "[Building #{ page_name } pages]" 586: outputs.each do |vars| 587: full_out_path = File.join( output_path, vars[:page].link.split( '/' ) ) 588: ## If retouching, skip pages outside of path 589: next if only_path and vars[:page].link.index( "/" + only_path ) != 0 590: 591: ## If updating, skip any that are unchanged 592: next if how == :update and 593: File.exists?( full_out_path ) and 594: File.mtime( vars[:template] ) < File.mtime( full_out_path ) and 595: ( vars[:page].updated.nil? or 596: vars[:page].updated < File.mtime( full_out_path ) ) 597: 598: p_publish vars[:page] 599: vars.keys.each do |var_name| 600: case var_name.to_s 601: when /entry$/ 602: unless vars[:no_load] 603: vars[var_name] = load_and_validate_entry( vars[var_name].id ) 604: end 605: when /entries$/ 606: unless vars[:no_load] 607: vars[var_name].collect! do |e| 608: load_and_validate_entry( e.id ) 609: end 610: end 611: vars[var_name].extend Hobix::EntryEnum 612: end 613: end 614: 615: ## Publish the page 616: vars = vars.dup 617: output = vars.delete( :output ) 618: template = vars.delete( :template ) 619: txt = output.load( template, vars ) 620: ## A plugin perhaps needs to change the output page name 621: full_out_path = File.join( output_path, vars[:page].link.split( '/' ) ) 622: saved_umask = File.umask( 0002 ) rescue nil 623: begin 624: File.makedirs( File.dirname( full_out_path ) ) 625: File.open( full_out_path, 'w' ) do |f| 626: f << txt 627: end 628: ensure 629: File.umask( saved_umask ) rescue nil 630: end 631: published[vars[:page].link] = vars[:page] 632: published_types << page_name 633: end 634: end 635: published_types.uniq! 636: publishers.each do |p| 637: if p.respond_to? :watch 638: if p.watch & published_types != [] 639: p.publish( published ) 640: end 641: else 642: p.publish( published ) 643: end 644: end 645: reset_output_map 646: end
Save the weblog configuration to its hobix.yaml (or optionally provide a path where you would like to save.)
# File lib/hobix/weblog.rb, line 413 413: def save( file = @hobix_yaml ) 414: unless file 415: raise ArgumentError, "Missing argument: path to save configuration (0 of 1)" 416: end 417: File::open( file, 'w' ) do |f| 418: YAML::dump( self, f ) 419: end 420: self 421: end
Receive a Hash pairing all section ids with the options for that section.
# File lib/hobix/weblog.rb, line 767 767: def sections( opts = nil ) 768: sections = Marshal::load( Marshal::dump( @sections ) ) 769: observes = !sections.values.detect { |s| s['observe'] } 770: storage.sections.each do |s| 771: sections[s] ||= {} 772: sections[s]['observe'] ||= sections[s].has_key?( 'ignore' ) ? !sections[s]['ignore'] : observes 773: sections[s]['ignore'] ||= !sections[s]['observe'] 774: end 775: sections 776: end
Returns an Array of entry paths ignored by general querying. Storage plugins must withhold these entries from queries, unless the :all => true setting is passed to the query.
# File lib/hobix/weblog.rb, line 792 792: def sections_ignored 793: sections.collect do |k, v| 794: k if v['ignore'] 795: end.compact 796: end
Returns a hash of special sorting cases. Key is the entry path, value is the sorting method. Storage plugins must honor these default sorts.
# File lib/hobix/weblog.rb, line 781 781: def sections_sorts 782: @sections.inject( {} ) do |sorts, set| 783: k, v = set 784: sorts[k] = v['sort_by'] if v['sort_by'] 785: sorts 786: end 787: end
Handler for templates with `daily’ prefix. These templates will receive a list of entries for each day that has at least one entry created in its time period. This handler requests daily pages to be output as `/%Y/%m/%d.ext’.
# File lib/hobix/weblog.rb, line 664 664: def skel_daily( path_storage, section_path ) 665: entry_range = path_storage.find 666: first_time, last_time = entry_range.last.created, entry_range.first.created 667: start = Time.mktime( first_time.year, first_time.month, first_time.day, 0, 0, 0 ) + 1 668: stop = Time.mktime( last_time.year, last_time.month, last_time.day, 23, 59, 59 ) 669: days = [] 670: one_day = 24 * 60 * 60 671: until start > stop 672: day_entries = path_storage.within( start, start + one_day - 1 ) 673: days << [day_entries.last.created, day_entries] unless day_entries.empty? 674: start += one_day 675: end 676: days.extend Hobix::Enumerable 677: days.each_with_neighbors do |prev, curr, nextd| 678: page = Page.new( curr[0].strftime( "%Y/%m/%d" ), section_path ) 679: page.prev = prev[0].strftime( "%Y/%m/%d" ) if prev 680: page.next = nextd[0].strftime( "%Y/%m/%d" ) if nextd 681: page.timestamp = curr[0] 682: page.updated = path_storage.last_updated( curr[1] ) 683: yield :page => page, :entries => curr[1] 684: end 685: end
Handler for templates with `entry’ prefix. These templates will receive one entry for each entry in the weblog. The handler requests entry pages to be output as `/shortName.ext’.
# File lib/hobix/weblog.rb, line 730 730: def skel_entry( path_storage, section_path ) 731: all_entries = [path_storage.find] 732: all_entries += sections_ignored.collect { |ign| path_storage.find( :all => true, :inpath => ign ) } 733: all_entries.each do |entry_set| 734: entry_set.extend Hobix::Enumerable 735: entry_set.each_with_neighbors do |nexte, entry, prev| 736: page = Page.new( entry.id ) 737: page.prev = prev.id if prev 738: page.next = nexte.id if nexte 739: page.timestamp = entry.created 740: page.updated = path_storage.updated( entry.id ) 741: yield :page => page, :entry => entry 742: end 743: end 744: end
Handler for templates with `index’ prefix. These templates will receive entries loaded by +Hobix::BaseStorage#lastn+. Only one index page is requested by this handler.
# File lib/hobix/weblog.rb, line 651 651: def skel_index( path_storage, section_path ) 652: index_entries = path_storage.lastn( @lastn ) 653: page = Page.new( 'index', section_path ) 654: page.prev = index_entries.last.created.strftime( "%Y/%m/index" ) 655: page.timestamp = index_entries.first.created 656: page.updated = path_storage.last_updated( index_entries ) 657: yield :page => page, :entries => index_entries 658: end
Handler for templates with `monthly’ prefix. These templates will receive a list of entries for each month that has at least one entry created in its time period. This handler requests monthly pages to be output as `/%Y/%m/index.ext’.
# File lib/hobix/weblog.rb, line 691 691: def skel_monthly( path_storage, section_path ) 692: months = path_storage.get_months( path_storage.find ) 693: months.extend Hobix::Enumerable 694: months.each_with_neighbors do |prev, curr, nextm| 695: entries = path_storage.within( curr[0], curr[1] ) 696: page = Page.new( curr[0].strftime( "%Y/%m/index" ), section_path ) 697: page.prev = prev[0].strftime( "%Y/%m/index" ) if prev 698: page.next = nextm[0].strftime( "%Y/%m/index" ) if nextm 699: page.timestamp = curr[1] 700: page.updated = path_storage.last_updated( entries ) 701: yield :page => page, :entries => entries 702: end 703: end
# File lib/hobix/weblog.rb, line 355 355: def skel_path; File.expand_path( @skel_path || default_skel_path, @path ).untaint; end
Handler for templates with `section’ prefix. These templates will receive all entries below a given directory. The handler requests will be output as `/section/index.ext’.
# File lib/hobix/weblog.rb, line 749 749: def skel_section( path_storage, section_path ) 750: section_map = {} 751: path_storage.all.each do |entry| 752: dirs = entry.id.split( '/' ) 753: while ( dirs.pop; dirs.first ) 754: section = dirs.join( '/' ) 755: section_map[ section ] ||= [] 756: section_map[ section ] << entry 757: end 758: end 759: section_map.each do |section, entries| 760: page = Page.new( "/#{ section }/index" ) 761: page.updated = path_storage.last_updated( entries ) 762: yield :page => page, :entries => entries 763: end 764: end
Handler for templates with `tags’ prefix. These templates will receive a tag with all entries tagged with it. The handler requests will be output as `/tags/<tag>/index.ext’.
# File lib/hobix/weblog.rb, line 801 801: def skel_tags( path_storage, section_path ) 802: # Get a list of all known tags 803: tags = path_storage.find( :all => true ).map { |e| e.tags }.flatten.uniq 804: 805: tags.each do |tag| 806: entries = path_storage.find.find_all { |e| e.tags.member? tag } 807: page = Page.new( File::join( 'tags',tag,'index' ), section_path ) 808: page.updated = path_storage.last_updated( entries ) 809: yield :page => page, :entries => entries 810: end 811: end
Handler for templates with `yearly’ prefix. These templates will receive a list of entries for each month that has at least one entry created in its time period. This handler requests yearly pages to be output as `/%Y/index.ext’.
# File lib/hobix/weblog.rb, line 709 709: def skel_yearly( path_storage, section_path ) 710: entry_range = path_storage.find 711: first_time, last_time = entry_range.last.created, entry_range.first.created 712: years = (first_time.year..last_time.year).collect do |y| 713: [ Time.mktime( y, 1, 1 ), Time.mktime( y + 1, 1, 1 ) - 1 ] 714: end 715: years.extend Hobix::Enumerable 716: years.each_with_neighbors do |prev, curr, nextm| 717: entries = path_storage.within( curr[0], curr[1] ) 718: page = Page.new( curr[0].strftime( "%Y/index" ), section_path ) 719: page.prev = prev[0].strftime( "%Y/index" ) if prev 720: page.next = nextm[0].strftime( "%Y/index" ) if nextm 721: page.timestamp = curr[1] 722: page.updated = path_storage.last_updated( entries ) 723: yield :page => page, :entries => entries 724: end 725: end
After the weblog is initialize, the start method is called with the full system path to the directory containing the configuration.
This method sets up all the paths and loads the plugins.
# File lib/hobix/weblog.rb, line 318 318: def start( hobix_yaml ) 319: @hobix_yaml = hobix_yaml 320: @path = File.dirname( hobix_yaml ) 321: @sections ||= {} 322: if File.exists?( lib_path ) 323: $LOAD_PATH << lib_path 324: end 325: @plugins = [] 326: @requires.each do |req| 327: opts = nil 328: unless req.respond_to? :to_str 329: req, opts = req.to_a.first 330: end 331: plugin_conf = File.join( @path, req.gsub( /\W+/, '.' ) ) 332: if File.exists? plugin_conf 333: puts "*** Loading #{ plugin_conf }" 334: plugin_conf = YAML::load_file plugin_conf 335: if opts 336: opts.merge! plugin_conf 337: else 338: opts = plugin_conf 339: end 340: end 341: @plugins += Hobix::BasePlugin::start( req, opts, self ) 342: end 343: end