class DataPackage::Package
Attributes
errors[R]
Public
profile[R]
Public
Public Class Methods
new(descriptor = nil, opts: {})
click to toggle source
Parse or create a data package Supports reading data from JSON file, directory, and a URL
- descriptor
-
Hash or String
- opts
-
Options used to customize reading and parsing
# File lib/datapackage/package.rb, line 15 def initialize(descriptor = nil, opts: {}) @opts = opts @dead_resources = [] self.merge! parse_package(descriptor) @profile = DataPackage::Profile.new(self.fetch('profile', DataPackage::DEFAULTS[:package][:profile])) self['profile'] = @profile.name define_properties! load_resources! rescue OpenURI::HTTPError, SocketError => e raise PackageException.new "Package URL returned #{e.message}" rescue JSON::ParserError raise PackageException.new 'Package descriptor is not valid JSON' end
Public Instance Methods
add_resource(resource)
click to toggle source
# File lib/datapackage/package.rb, line 70 def add_resource(resource) resource = load_resource(resource) self['resources'].push(resource) begin self.validate resource rescue DataPackage::ValidationError self['resources'].pop nil end end
base()
click to toggle source
Returns the directory for a local file package or base url for a remote Returns nil for an in-memory object (because it has no base as yet)
# File lib/datapackage/package.rb, line 99 def base # user can override base return @opts[:base] if @opts[:base] return '' unless @location # work out base directory or uri if local? return File.dirname(@location) else return @location.split('/')[0..-2].join('/') end end
descriptor()
click to toggle source
# File lib/datapackage/package.rb, line 51 def descriptor self.to_h end
get_resource(resource_name)
click to toggle source
# File lib/datapackage/package.rb, line 65 def get_resource(resource_name) update_resources! self['resources'].find{ |resource| resource.name == resource_name } end
infer(base_path: nil, directory: nil)
click to toggle source
# File lib/datapackage/package.rb, line 122 def infer(base_path: nil, directory: nil) raise PackageException.new('Base path is required for infer') unless base_path raise PackageException.new('Directory is required for infer') unless directory dir_path = File.join(base_path, directory) Dir.glob("#{dir_path}/*.csv") do |filename| resource = Resource.infer(filename) add_resource(resource) end # If there were CSVs, this is a tabular data package if resources.count > 0 self['profile'] = 'tabular-data-package' end descriptor end
iter_errors() { |error| ... }
click to toggle source
# File lib/datapackage/package.rb, line 43 def iter_errors errors = @profile.iter_errors(self){ |err| err } self['resources'].each do |resource| resource.iter_errors{ |err| errors << err } end errors.each{ |error| yield error } end
local?()
click to toggle source
Is this a local package? Returns true if created from an in-memory object or a file/directory reference
# File lib/datapackage/package.rb, line 112 def local? return @local if @local return false if @location =~ /\A#{URI::regexp}\z/ true end
property(property, default = nil)
click to toggle source
# File lib/datapackage/package.rb, line 118 def property(property, default = nil) self[property] || default end
remove_resource(resource_name)
click to toggle source
# File lib/datapackage/package.rb, line 82 def remove_resource(resource_name) update_resources! resource = get_resource(resource_name) self['resources'].reject!{ |resource| resource.name == resource_name } resource end
resource_names()
click to toggle source
# File lib/datapackage/package.rb, line 60 def resource_names update_resources! self['resources'].map{|res| res.name} end
resources()
click to toggle source
# File lib/datapackage/package.rb, line 55 def resources update_resources! self['resources'] end
save(target=@location)
click to toggle source
# File lib/datapackage/package.rb, line 89 def save(target=@location) update_resources! File.open(target, "w") { |file| file << JSON.pretty_generate(self) } true end
valid?()
click to toggle source
# File lib/datapackage/package.rb, line 29 def valid? return false unless @profile.valid?(self) return false if self['resources'].map{ |resource| resource.valid? }.include?(false) true end
Also aliased as: valid
validate()
click to toggle source
# File lib/datapackage/package.rb, line 37 def validate @profile.validate(self) self['resources'].each { |resource| resource.validate } true end
Private Instance Methods
default_value(field_data)
click to toggle source
# File lib/datapackage/package.rb, line 176 def default_value(field_data) case field_data['type'] when 'array' [] when 'object' {} else nil end end
define_properties!()
click to toggle source
Private
# File lib/datapackage/package.rb, line 144 def define_properties! (@profile['properties'] || {}).each do |k, v| next if k == 'resources' || k == 'profile' define_singleton_method("#{k.to_sym}=", proc { |p| set_property(k, p) }) define_singleton_method(k.to_sym.to_s, proc { property k, default_value(v) }) end end
load_resource(resource)
click to toggle source
# File lib/datapackage/package.rb, line 168 def load_resource(resource) if resource.is_a?(Resource) resource else Resource.new(resource, base) end end
load_resources!()
click to toggle source
# File lib/datapackage/package.rb, line 152 def load_resources! self['resources'] ||= [] update_resources! end
parse_package(descriptor)
click to toggle source
# File lib/datapackage/package.rb, line 191 def parse_package(descriptor) # TODO: base directory/url if descriptor.nil? {} elsif descriptor.class == Hash descriptor else read_package(descriptor) end end
read_package(descriptor)
click to toggle source
# File lib/datapackage/package.rb, line 202 def read_package(descriptor) if File.extname(descriptor) == '.zip' unzip_package(descriptor) else @location = descriptor.to_s load_json(descriptor) end end
set_property(key, value)
click to toggle source
# File lib/datapackage/package.rb, line 187 def set_property(key, value) self[key] = value end
unzip_package(descriptor)
click to toggle source
# File lib/datapackage/package.rb, line 211 def unzip_package(descriptor) descriptor = write_to_tempfile(descriptor) if descriptor =~ /\A#{URI::regexp}\z/ dir = Dir.mktmpdir package = {} Zip::File.open(descriptor) do |zip_file| # Extract all the files zip_file.each { |entry| entry.extract("#{dir}/#{File.basename entry.name}") } # Get and parse the datapackage metadata entry = zip_file.glob("*/#{@opts[:default_filename] || 'datapackage.json'}").first package = JSON.parse(entry.get_input_stream.read) end # Set the base dir to the directory we unzipped to @opts[:base] = dir # This is now a local file, not a URL @local = true package end
update_resources!()
click to toggle source
# File lib/datapackage/package.rb, line 157 def update_resources! self['resources'].map! do |resource| begin load_resource(resource) rescue ResourceException @dead_resources << resource nil end end.compact! end
write_to_tempfile(url)
click to toggle source
# File lib/datapackage/package.rb, line 229 def write_to_tempfile(url) tempfile = Tempfile.new('datapackage') tempfile.write(open(url).read) tempfile.rewind tempfile end