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
id
is 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
search
hash. -
#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
weblog
passed 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). -
#last_updated(entries) ⇒ Object
Returns a Time object for the latest updated 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.
- #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
e
and 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 updated time current.
-
#updated(entry_id) ⇒ Object
Returns a Time object representing the
updated
time for the entry identified byentry_id
.
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 ) @updated = {} @basepath = weblog.entry_path @default_author = 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.
401 402 403 404 405 |
# File 'lib/hobix/storage/filesys.rb', line 401 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
id
which 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.
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 302 |
# File 'lib/hobix/storage/filesys.rb', line 258 def find( search = {} ) load_index _index = @index if _index.empty? e = default_entry( @default_author ) @updated[e.id] = e.updated _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
.
363 364 365 366 367 368 369 |
# File 'lib/hobix/storage/filesys.rb', line 363 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.
342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 |
# File 'lib/hobix/storage/filesys.rb', line 342 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/" ) ] unless find( :after => start, :before => month_end).empty? 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).
322 323 324 325 326 |
# File 'lib/hobix/storage/filesys.rb', line 322 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).
314 315 316 317 318 |
# File 'lib/hobix/storage/filesys.rb', line 314 def last_modified( entries ) entries.collect do |entry| entry.modified end.max end |
#last_updated(entries) ⇒ Object
Returns a Time object for the latest updated time for a group of entries
(pass in an Array of IndexEntry objects).
306 307 308 309 310 |
# File 'lib/hobix/storage/filesys.rb', line 306 def last_updated( entries ) entries.collect do |entry| updated( 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.
373 374 375 376 377 378 379 380 381 382 383 384 |
# File 'lib/hobix/storage/filesys.rb', line 373 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.
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 |
# File 'lib/hobix/storage/filesys.rb', line 115 def load_entry( id ) return default_entry( @default_author ) 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.updated = updated( id ) unless e.created e.created = @index[id].created e.modified = @index[id].modified 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.
154 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 205 |
# File 'lib/hobix/storage/filesys.rb', line 154 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( '/' ) @updated[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?( :updated ) or # it's new ( index_entry.updated != @updated[entry_id] ) # it's changed # or 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 puts "++ Reloaded #{ entry_id }" 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.updated = @updated[entry_id] end # catalog_search_entry( e ) modified = true end index_entry.id = entry_id @index[entry_id] = index_entry end end sort_index( modified ) true 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
.
222 223 224 225 226 227 228 229 230 231 232 233 234 235 |
# File 'lib/hobix/storage/filesys.rb', line 222 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 @updated.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
.
388 389 390 391 392 393 394 395 396 |
# File 'lib/hobix/storage/filesys.rb', line 388 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 |
# 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 ) unless create_category and File.exists? @basepath FileUtils.makedirs File.dirname( path ) end File.open( path, 'w' ) { |f| YAML::dump( e, f ) } @entry_cache ||= {} e.id = id e.link = e.class.url_link e, @link, @weblog.central_ext e.updated = e.modified = now @entry_cache[id] = e @index[id] = @weblog.index_class.new( e ) do |i| i.updated = e.updated end @updated[id] = e.updated # 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’.
240 241 242 243 244 |
# File 'lib/hobix/storage/filesys.rb', line 240 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.)
208 209 210 211 212 213 214 215 216 217 218 |
# File 'lib/hobix/storage/filesys.rb', line 208 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 updated time current.
79 80 81 82 83 |
# File 'lib/hobix/storage/filesys.rb', line 79 def touch_entry( id ) check_id( id ) @updated[id] = Time.now FileUtils.touch entry_path( id ) end |
#updated(entry_id) ⇒ Object
Returns a Time object representing the updated
time for the entry identified by entry_id
. Takes into account attachments which have been updated.
331 332 333 334 335 336 |
# File 'lib/hobix/storage/filesys.rb', line 331 def updated( entry_id ) find_attached( entry_id ).inject( @updated[entry_id] ) do |max, ext| mtime = File.mtime( entry_path( entry_id, ext ) ) mtime > max ? mtime : max end end |