Class: Hobix::Storage::FileSys
- Inherits:
-
BaseStorage
- Object
- BasePlugin
- BaseStorage
- Hobix::Storage::FileSys
- Defined in:
- lib/hobix/storage/filesys.rb
Overview
The FileSys class is a storage plugin, it manages the loading and dumping of Hobix entries and attachments. The FileSys class also keeps an index of entry information, to keep the system from loading unneeded entries.
Instance Method Summary collapse
-
#append_to_attachment(entry_id, attachment_type, *items) ⇒ Object
Appends the given items to an entry attachment with the given type, and then saves the modified attachment.
-
#check_id(id) ⇒ Object
Determine if
idis a valid entry identifier, untaint if so. -
#entry_path(id, ext = extension) ⇒ Object
Build an entry’s complete path based on its
id. -
#extension ⇒ Object
The default extension for entries.
-
#find(search = {}) ⇒ Object
Find entries based on criteria from the
searchhash. -
#find_attached(id) ⇒ Object
Discovers attachments to an entry identified by
id. -
#get_months(entries) ⇒ Object
Returns an Array of Arrays representing the months which contain
entries(pass in an Array of IndexEntry objects). -
#initialize(weblog) ⇒ FileSys
constructor
Start the storage plugin for the
weblogpassed in. -
#last_created(entries) ⇒ Object
Returns a Time object for the latest creation time for a group of
entries(pass in an Array of IndexEntry objects). -
#last_modified(entries) ⇒ Object
Returns a Time object for the latest modified time for a group of
entries(pass in an Array of IndexEntry objects). -
#load_attached(id, ext) ⇒ Object
Loads an attachment to an entry identified by
id. -
#load_entry(id) ⇒ Object
Loads the entry object identified by
id. -
#load_index ⇒ Object
Load the internal index (saved at @entry_path/index.hobix) and refresh any timestamps which may be stale.
-
#modified(entry_id) ⇒ Object
Returns a Time object representing the
modifiedtime for the entry identified byentry_id. - #now ⇒ Object
-
#path_storage(p) ⇒ Object
Returns a Hobix::Storage::FileSys object with its scope limited to entries inside a certain path
p. -
#save_attached(id, ext, e) ⇒ Object
Saves an attachment to an entry identified by
id. -
#save_entry(id, e, create_category = false) ⇒ Object
Save the entry object
eand identify it asid. -
#sections(opts = nil) ⇒ Object
Returns an Array all ‘sections’, or directories which contain entries.
-
#sort_index(modified) ⇒ Object
Sorts the internal entry index (used by load_index.).
-
#touch_entry(id) ⇒ Object
Brings an entry’s modified time current.
Methods inherited from BaseStorage
#after, #all, #before, #default_entry, #default_entry_id, #inpath, #lastn, #match, #within
Methods inherited from BasePlugin
Constructor Details
#initialize(weblog) ⇒ FileSys
Start the storage plugin for the weblog passed in.
52 53 54 55 56 57 58 |
# File 'lib/hobix/storage/filesys.rb', line 52 def initialize( weblog ) super( weblog ) @modified = {} @basepath = weblog.entry_path = weblog..keys.first @weblog = weblog end |
Instance Method Details
#append_to_attachment(entry_id, attachment_type, *items) ⇒ Object
Appends the given items to an entry attachment with the given type, and then saves the modified attachment. If an attachment of the given type does not exist, it will be created.
391 392 393 394 395 |
# File 'lib/hobix/storage/filesys.rb', line 391 def ( entry_id, , *items ) = load_attached( entry_id, ) rescue [] += items save_attached( entry_id, , ) end |
#check_id(id) ⇒ Object
Determine if id is a valid entry identifier, untaint if so.
68 69 70 |
# File 'lib/hobix/storage/filesys.rb', line 68 def check_id( id ) id.untaint if id.tainted? and id =~ /^[\w\/\\]+$/ end |
#entry_path(id, ext = extension) ⇒ Object
Build an entry’s complete path based on its id. Optionally, extension ext can be used to find the path of attachments.
74 75 76 |
# File 'lib/hobix/storage/filesys.rb', line 74 def entry_path( id, ext = extension ) File.join( @basepath, id.split( '/' ) ) + "." + ext end |
#extension ⇒ Object
The default extension for entries. Defaults to: yaml.
63 64 65 |
# File 'lib/hobix/storage/filesys.rb', line 63 def extension 'yaml' end |
#find(search = {}) ⇒ Object
Find entries based on criteria from the search hash. Possible criteria include:
- :after
-
Select entries created after a given Time.
- :before
-
Select entries created before a given Time.
- :inpath
-
Select entries contained within a path.
- :match
-
Select entries with an
idwhich match a Regexp. - :search
-
Fulltext search of entries for search words.
- :lastn
-
Limit the search to include only a given number of entries.
This method returns an Array of IndexEntry objects for use in skel_* methods.
257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 |
# File 'lib/hobix/storage/filesys.rb', line 257 def find( search = {} ) load_index _index = @index if _index.empty? e = default_entry( ) @modified[e.id] = e.modified _index = {e.id => @weblog.index_class.new(e)} end # if search[:search] # sr = @search_index.find_words( search[:search] ) # end unless search[:all] ignore_test = nil ignored = @weblog.sections_ignored unless ignored.empty? ignore_test = /^(#{ ignored.collect { |i| Regexp.quote( i ) }.join( '|' ) })/ end end entries = _index.collect do |id, entry| skip = false if ignore_test and not search[:all] skip = entry.id =~ ignore_test end search.each do |skey, sval| break if skip skip = case skey when :after entry.created < sval when :before entry.created > sval when :inpath entry.id.index( sval ) != 0 when :match not entry.id.match sval # when :search # not sr.results[entry.id] else false end end if skip then nil else entry end end.compact entries.slice!( search[:lastn]..-1 ) if search[:lastn] and entries.length > search[:lastn] entries end |
#find_attached(id) ⇒ Object
Discovers attachments to an entry identified by id.
353 354 355 356 357 358 359 |
# File 'lib/hobix/storage/filesys.rb', line 353 def find_attached( id ) check_id( id ) Dir[ entry_path( id, '*' ) ].collect do |att| atp = att.match( /#{ Regexp::quote( id ) }\.(?!#{ extension }$)/ ) atp.post_match if atp end.compact end |
#get_months(entries) ⇒ Object
Returns an Array of Arrays representing the months which contain entries (pass in an Array of IndexEntry objects).
See Hobix::Weblog.skel_month for an example of this method’s usage.
332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 |
# File 'lib/hobix/storage/filesys.rb', line 332 def get_months( entries ) return [] if entries.empty? first_time = entries.collect { |e| e.created }.min last_time = entries.collect { |e| e.created }.max start = Time.mktime( first_time.year, first_time.month, 1 ) stop = Time.mktime( last_time.year, last_time.month, last_time.day ) months = [] until start > stop next_year, next_month = start.year, start.month + 1 if next_month > 12 next_year += next_month / 12 next_month %= 12 end month_end = Time.mktime( next_year, next_month, 1 ) - 1 months << [ start, month_end, start.strftime( "/%Y/%m/" ) ] start = month_end + 1 end months end |
#last_created(entries) ⇒ Object
Returns a Time object for the latest creation time for a group of entries (pass in an Array of IndexEntry objects).
313 314 315 316 317 |
# File 'lib/hobix/storage/filesys.rb', line 313 def last_created( entries ) entries.collect do |entry| entry.created end.max end |
#last_modified(entries) ⇒ Object
Returns a Time object for the latest modified time for a group of entries (pass in an Array of IndexEntry objects).
305 306 307 308 309 |
# File 'lib/hobix/storage/filesys.rb', line 305 def last_modified( entries ) entries.collect do |entry| modified( entry.id ) end.max end |
#load_attached(id, ext) ⇒ Object
Loads an attachment to an entry identified by id. Entries can have any kind of YAML attachment, each which a specific extension.
363 364 365 366 367 368 369 370 371 372 373 374 |
# File 'lib/hobix/storage/filesys.rb', line 363 def load_attached( id, ext ) check_id( id ) @attach_cache ||= {} file_id = "#{ id }.#{ ext }" unless @attach_cache.has_key? file_id @attach_cache[id] = File.open( entry_path( id, ext ) ) do |f| YAML::load( f ) end else @attach_cache[id] end end |
#load_entry(id) ⇒ Object
Loads the entry object identified by id. Entries are cached for future loading.
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 |
# File 'lib/hobix/storage/filesys.rb', line 117 def load_entry( id ) return default_entry( ) if id == default_entry_id load_index check_id( id ) @entry_cache ||= {} unless @entry_cache.has_key? id entry_file = entry_path( id ) e = Hobix::Entry::load( entry_file ) e.id = id e.link = e.class.url_link e, @link, @weblog.central_ext e.modified = modified( id ) unless e.created e.created = @index[id].created File.open( entry_file, 'w' ) { |f| YAML::dump( e, f ) } end @entry_cache[id] = e else @entry_cache[id] end end |
#load_index ⇒ Object
Load the internal index (saved at @entry_path/index.hobix) and refresh any timestamps which may be stale.
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 |
# File 'lib/hobix/storage/filesys.rb', line 155 def load_index return false if @index index_path = File.join( @basepath, 'index.hobix' ) index = if File.exists? index_path YAML::load( File.open( index_path ) ) else YAML::Omap::new end @index = YAML::Omap::new # load_search_index( index.length == 0 ) modified = false index_fields = @weblog.index_class.properties.keys Find::find( @basepath ) do |path| path.untaint if FileTest.directory? path Find.prune if File.basename(path)[0] == ?. else entry_path = path.gsub( /^#{ Regexp::quote( @basepath ) }\/?/, '' ) next if entry_path !~ /\.#{ Regexp::quote( extension ) }$/ entry_paths = File.split( $` ) entry_paths.shift if entry_paths.first == '.' entry_id = entry_paths.join( '/' ) @modified[entry_id] = File.mtime( path ) index_entry = nil if ( index.has_key? entry_id ) and !( index[entry_id].is_a? ::Time ) # pre-0.4 index format index_entry = index[entry_id] end ## we will (re)load the entry if: if not index_entry.respond_to?( :modified ) or # it's new ( index_entry.modified != @modified[entry_id] ) or # it's changed index_fields.detect { |f| index_entry.send( f ).nil? } # index fields have been added # or search_needs_update? index_entry # entry is old or not available in search db efile = entry_path( entry_id ) e = Hobix::Entry::load( efile ) e.id = entry_id index_entry = @weblog.index_class.new( e, index_fields ) do |i| i.modified = @modified[entry_id] end # catalog_search_entry( e ) modified = true end @index[index_entry.id] = index_entry end end sort_index( modified ) true end |
#modified(entry_id) ⇒ Object
Returns a Time object representing the modified time for the entry identified by entry_id.
321 322 323 324 325 326 |
# File 'lib/hobix/storage/filesys.rb', line 321 def modified( entry_id ) find_attached( entry_id ).inject( @modified[entry_id] ) do |max, ext| mtime = File.mtime( entry_path( entry_id, ext ) ) mtime > max ? mtime : max end end |
#now ⇒ Object
60 |
# File 'lib/hobix/storage/filesys.rb', line 60 def now; Time.at( Time.now.to_i ); end |
#path_storage(p) ⇒ Object
Returns a Hobix::Storage::FileSys object with its scope limited to entries inside a certain path p.
221 222 223 224 225 226 227 228 229 230 231 232 233 234 |
# File 'lib/hobix/storage/filesys.rb', line 221 def path_storage( p ) return self if ['', '.'].include? p load_index path_storage = self.dup path_storage.instance_eval do @index = @index.dup.delete_if do |id, entry| if id.index( p ) != 0 @modified.delete( p ) true end end end path_storage end |
#save_attached(id, ext, e) ⇒ Object
Saves an attachment to an entry identified by id. The attachment e is saved with an extension ext.
378 379 380 381 382 383 384 385 386 |
# File 'lib/hobix/storage/filesys.rb', line 378 def save_attached( id, ext, e ) check_id( id ) File.open( entry_path( id, ext ), 'w' ) do |f| YAML::dump( e, f ) end @attach_cache ||= {} @attach_cache[id] = e end |
#save_entry(id, e, create_category = false) ⇒ Object
Save the entry object e and identify it as id. The create_category flag will forcefully make the needed directories.
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 |
# File 'lib/hobix/storage/filesys.rb', line 87 def save_entry( id, e, create_category=false ) load_index check_id( id ) e.created ||= (@index.has_key?( id ) ? @index[id].created : now) path = entry_path( id ) begin File.open( path, 'w' ) { |f| YAML::dump( e, f ) } rescue Errno::ENOENT raise unless create_category and File.exists? @basepath FileUtils.makedirs File.dirname( path ) retry end @entry_cache ||= {} e.id = id e.link = e.class.url_link e, @link, @weblog.central_ext e.modified = now @entry_cache[id] = e @index[id] = @weblog.index_class.new( e ) do |i| i.modified = e.modified end @modified[id] = e.modified # catalog_search_entry( e ) sort_index( true ) e end |
#sections(opts = nil) ⇒ Object
Returns an Array all ‘sections’, or directories which contain entries. If you have three entries: ‘news/article1’, ‘about/me’, and ‘news/misc/article2’, then you have three sections: ‘news’, ‘about’, ‘news/misc’.
239 240 241 242 243 |
# File 'lib/hobix/storage/filesys.rb', line 239 def sections( opts = nil ) load_index hsh = {} @index.collect { |id, e| e.section_id }.uniq.sort end |
#sort_index(modified) ⇒ Object
Sorts the internal entry index (used by load_index.)
207 208 209 210 211 212 213 214 215 216 217 |
# File 'lib/hobix/storage/filesys.rb', line 207 def sort_index( modified ) return unless @index index_path = File.join( @basepath, 'index.hobix' ) @index.sort! { |x,y| y[1].created <=> x[1].created } if modified File.open( index_path, 'w' ) do |f| YAML::dump( @index, f ) end # @search_index.dump end end |
#touch_entry(id) ⇒ Object
Brings an entry’s modified time current.
79 80 81 82 83 |
# File 'lib/hobix/storage/filesys.rb', line 79 def touch_entry( id ) check_id( id ) @modified[id] = Time.now FileUtils.touch entry_path( id ) end |