Class: IMW::Resource
- Inherits:
-
Object
- Object
- IMW::Resource
- Defined in:
- lib/imw/resource.rb
Overview
A resource can be anything addressable via a URI. Examples include local files, remote files, webpages, &c.
The IMW::Resource class takes a URI as input and then dynamically extends itself with appropriate modules from IMW. As an example, calling
my_archive = IMW::Resource.new('/path/to/my/archive.tar.bz2')
would return an IMW::Resource extended by IMW::Archives::Tarbz2 (among other modules) which therefore has methods for extracting, listing, and appending to the archive.
Modules are so extended based on handlers defined in the imw/resources
directory and accessible via IMW::Resource.handlers. You can define your own handlers by defining the constant IMW::Resource::USER_DEFINED_HANDLERS in your configuration file.
The modules extending a particular IMW::Resource instance can be listed as follows
my_archive.resource_modules #=> [IMW::Local::Base, IMW::Local::File, IMW::Local::Compressible, IMW::Archives::Tarbz2]
By default, resources are opened for reading. Passing in the appropriate :mode
option changes this:
IMW::Resource.new('/path/to/my_new_file', :mode => 'w')
If the :skip_modules
option is passed in then the resource will not extend itself with any modules and will essentially only retain the bare functionality of a URI. This can be useful when subclassing IMW::Resource or dealing with a very strange kind of resource.
Read the documentation for modules in IMW::Resources to learn more about the various behaviors an IMW::Resource can acquire.
You can also instantiate an IMW::Resource using IMW.open, which accepts all the same arguments as IMW::Resource.new.
Instance Attribute Summary collapse
-
#mode ⇒ Object
readonly
Returns the value of attribute mode.
-
#uri ⇒ Object
Returns the value of attribute uri.
Class Method Summary collapse
-
.extend_resource!(resource, options = {}) ⇒ IMW::Resource
Iterate through IMW::Resource.handlers and extend the given
resource
with modules whose handler conditions match the resource. -
.handlers ⇒ Array
A list of handlers to match against each new resource.
Instance Method Summary collapse
-
#basename ⇒ String
The basename of this resource’s path.
-
#dirname ⇒ String
The directory name of this resource’s path.
-
#extend(mod) ⇒ Object
Works just like Object#extend except it keeps track of the modules it has extended, see Resource#resource_modules.
-
#extend_appropriately!(options = {}) ⇒ Object
Extend this resource with modules by passing it through a collection of handlers defined by IMW::Resource.handlers.
-
#extension ⇒ String
Returns the extension (WITHOUT the ‘.’) of this resource’s path.
-
#extname ⇒ String
Returns the extension (INCLUDING the ‘.’) of this resource’s path.
-
#initialize(uri, options = {}) ⇒ IMW::Resource
constructor
Create a new resource representing
uri
. -
#method_missing(method, *args) ⇒ Object
If
method
begins with the stringsis
,on
, orvia
and ends with a question mark then we interpret it as a question this resource doesn’t know how to answer – so we have it answerfalse
. -
#name ⇒ String
Returns the basename of the file with its extension removed.
-
#reopen ⇒ IMW::Resource
Open a copy of this resource.
-
#resource_modules ⇒ Array
Return the modules this resource has been extended by.
-
#scheme ⇒ String
The scheme of this resource.
-
#should_exist!(message = nil) ⇒ Object
Raise an error unless this resource exists.
- #to_s ⇒ Object
Constructor Details
#initialize(uri, options = {}) ⇒ IMW::Resource
Create a new resource representing uri
.
IMW will automatically extend the resulting IMW::Resourcen instance with modules appropriate to the given URI.
r = IMW::Resource.new("http://www.infochimps.com")
r.resource_modules
=> [IMW::Schemes::Remote::Base, IMW::Schemes::Remote::RemoteFile, IMW::Schemes::HTTP, IMW::Formats::Html]
You can prevent this altogether by passing in :no_modules
:
r = IMW::Resource.new("http://www.infochimps.com")
r.resource_modules
=> [IMW::Schemes::Remote::Base, IMW::Schemes::Remote::RemoteFile, IMW::Schemes::HTTP, IMW::Formats::Html]
And you can exert more fine-grained control with the :use_modules
and :skip_modules
options, see IMW::Resource.extend_resource! for details.
79 80 81 82 83 |
# File 'lib/imw/resource.rb', line 79 def initialize uri, ={} self.uri = uri @mode = [:mode] || 'r' extend_appropriately!() unless [:no_modules] end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(method, *args) ⇒ Object
If method
begins with the strings is
, on
, or via
and ends with a question mark then we interpret it as a question this resource doesn’t know how to answer – so we have it answer false
.
As an example, consider the following loop:
IMW.open('/tmp').all_contents.each do |obj|
if obj.is_archive?
# ... do something
end
end
When obj
is initialized and it _isn’t_ an archive, then it doesn’t know about the is_archive?
method – but it should therefore answer false anyway.
This lets a basic text file answer questions about whether it’s an archive (or on S3, or accessed via some user-defined scheme, &c.) without needing to know anything about archives (or S3 or the user-defined scheme).
214 215 216 217 218 219 220 221 |
# File 'lib/imw/resource.rb', line 214 def method_missing method, *args if args.empty? && method.to_s =~ /(is|on|via)_.*\?$/ # querying for a boolean response so answer false return false else raise IMW::NoMethodError, "undefined method `#{method}' for #{self}, extended by #{resource_modules.join(', ')}" end end |
Instance Attribute Details
#mode ⇒ Object (readonly)
Returns the value of attribute mode.
52 53 54 |
# File 'lib/imw/resource.rb', line 52 def mode @mode end |
#uri ⇒ Object
Returns the value of attribute uri.
52 53 54 |
# File 'lib/imw/resource.rb', line 52 def uri @uri end |
Class Method Details
.extend_resource!(resource, options = {}) ⇒ IMW::Resource
Iterate through IMW::Resource.handlers and extend the given resource
with modules whose handler conditions match the resource.
Passing in :use_modules
or :skip_modules
allows overriding the default behavior of handlers.
235 236 237 238 239 240 241 242 243 244 245 246 247 248 |
# File 'lib/imw/resource.rb', line 235 def self.extend_resource! resource, ={} .reverse_merge!(:use_modules => [], :skip_modules => []) handlers.each do |mod_name, handler| case handler when Regexp then extend_resource_with_mod_or_string!(resource, mod_name, [:skip_modules]) if handler =~ resource.uri.to_s when Proc then extend_resource_with_mod_or_string!(resource, mod_name, [:skip_modules]) if handler.call(resource) when TrueClass then extend_resource_with_mod_or_string!(resource, mod_name, [:skip_modules]) else raise IMW::TypeError("A handler must be Regexp, Proc, or true") end end [:use_modules].each { |mod_name| extend_resource_with_mod_or_string!(resource, mod_name, [:skip_modules]) } resource end |
.handlers ⇒ Array
A list of handlers to match against each new resource.
When an IMW::Resource is instantiated it eventually calls IMW::Resource.extend_resource! which will iterate through the handlers in IMW::Resource.handlers, extending the resource with modules whose handler conditions are satisfied.
A handler is just an Array with two elements. The first should be a module or a string identifying a module.
If the second element is a Regexp, the corresponding module will be used if the regexp matches the resource’s URI (as a string)
If the second element is a Proc, it will be called with the resource as its only argument and if it returns true then the module will be used.
You can define your own handlers by appending them to IMW::Resource::USER_DEFINED_HANDLERS in your .imwrc
file.
The order in which handlers appear is significant – IMW::CompressedFiles::HANDLERS must be before IMW::Archives::HANDLERS, for example, because of (say) .tar.bz2
files.
277 278 279 280 281 282 283 284 285 |
# File 'lib/imw/resource.rb', line 277 def self.handlers # order is important! # # # #CompressedFiles must come before # Archives because of tar.bz2 type files IMW::Schemes::HANDLERS + IMW::CompressedFiles::HANDLERS + IMW::Archives::HANDLERS + IMW::Formats::HANDLERS + USER_DEFINED_HANDLERS end |
Instance Method Details
#basename ⇒ String
The basename of this resource’s path.
141 142 143 |
# File 'lib/imw/resource.rb', line 141 def basename @basename ||= File.basename(path) end |
#dirname ⇒ String
The directory name of this resource’s path.
134 135 136 |
# File 'lib/imw/resource.rb', line 134 def dirname @dirname ||= File.dirname(path) end |
#extend(mod) ⇒ Object
Works just like Object#extend except it keeps track of the modules it has extended, see Resource#resource_modules.
94 95 96 97 |
# File 'lib/imw/resource.rb', line 94 def extend mod resource_modules << mod super mod end |
#extend_appropriately!(options = {}) ⇒ Object
Extend this resource with modules by passing it through a collection of handlers defined by IMW::Resource.handlers.
Accepts the same options as Resource.extend_resource!.
103 104 105 |
# File 'lib/imw/resource.rb', line 103 def extend_appropriately! ={} self.class.extend_resource!(self, ) end |
#extension ⇒ String
Returns the extension (WITHOUT the ‘.’) of this resource’s path.
157 158 159 |
# File 'lib/imw/resource.rb', line 157 def extension @extension ||= extname[1..-1] || '' end |
#extname ⇒ String
Returns the extension (INCLUDING the ‘.’) of this resource’s path. Redefine this in an including class for which this is weird (‘.tar.gz’ I’m talking to you…)
150 151 152 |
# File 'lib/imw/resource.rb', line 150 def extname @extname ||= File.extname(path) end |
#name ⇒ String
166 167 168 |
# File 'lib/imw/resource.rb', line 166 def name @name ||= extname ? basename[0,basename.length - extname.length] : basename end |
#reopen ⇒ IMW::Resource
Open a copy of this resource.
This is useful when wanting to reset file handles. Though – be warned – it does not close any file handles itself…
189 190 191 |
# File 'lib/imw/resource.rb', line 189 def reopen IMW.open(self.uri.to_s) end |
#resource_modules ⇒ Array
Return the modules this resource has been extended by.
88 89 90 |
# File 'lib/imw/resource.rb', line 88 def resource_modules @resource_modules ||= [] end |
#scheme ⇒ String
The scheme of this resource. Will be nil
for local resources.
127 128 129 |
# File 'lib/imw/resource.rb', line 127 def scheme @scheme ||= uri.scheme end |
#should_exist!(message = nil) ⇒ Object
Raise an error unless this resource exists.
177 178 179 180 181 |
# File 'lib/imw/resource.rb', line 177 def should_exist!(=nil) raise IMW::Error.new([, "No path defined for #{self.inspect} extended by #{resource_modules.join(' ')}"].compact.join(', ')) unless respond_to?(:path) raise IMW::Error.new([, "No exist? method defined for #{self.inspect} extended by #{resource_modules.join(' ')}"].compact.join(', ')) unless respond_to?(:exist?) raise IMW::PathError.new([, "#{path} does not exist"].compact.join(', ')) unless exist? end |
#to_s ⇒ Object
170 171 172 |
# File 'lib/imw/resource.rb', line 170 def to_s uri.to_s end |