datapackage 0.0.4 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/LICENSE.md +4 -2
- data/README.md +82 -143
- data/lib/datapackage/exceptions.rb +12 -0
- data/lib/datapackage/package.rb +177 -156
- data/lib/datapackage/registry.rb +81 -0
- data/lib/datapackage/resource.rb +79 -0
- data/lib/datapackage/schema.rb +111 -0
- data/lib/datapackage/version.rb +1 -1
- data/lib/datapackage.rb +7 -2
- metadata +131 -31
- data/etc/README.md +0 -18
- data/etc/csvddf-dialect-schema.json +0 -24
- data/etc/datapackage-schema.json +0 -208
- data/etc/jsontable-schema.json +0 -34
- data/lib/datapackage/validator.rb +0 -229
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0dbfa361366c6830bb4624347821cc07c754d903
|
4
|
+
data.tar.gz: 4fc8b53abca06e6885d686cde540a21ad591aa49
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 53d75e66e0b49d2a92350d826f8e33e371f76b162fd8c94ecccf566064aa3e0e5c6f98aa2ec89deafa7126a359d804383df03163e91035721f7f4c22efcbcda9
|
7
|
+
data.tar.gz: 4e4b96bef09d7e46f06e7eac048ebacf45aebf3bcb50a6b9f44bf1ff578e7153fc49e5cb64239b76d84a6c936128c5e8394d2f50c67de25203565f0d997cc7df
|
data/LICENSE.md
CHANGED
@@ -1,4 +1,6 @@
|
|
1
|
-
Copyright
|
1
|
+
##Copyright (c) 2016 The Open Data Institute
|
2
|
+
|
3
|
+
#MIT License
|
2
4
|
|
3
5
|
Permission is hereby granted, free of charge, to any person obtaining
|
4
6
|
a copy of this software and associated documentation files (the
|
@@ -17,4 +19,4 @@ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
17
19
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
20
|
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
21
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
-
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
CHANGED
@@ -1,11 +1,14 @@
|
|
1
|
+
[![Build Status](http://img.shields.io/travis/theodi/datapackage.rb.svg?style=flat-square)](https://travis-ci.org/theodi/datapackage.rb)
|
2
|
+
[![Dependency Status](http://img.shields.io/gemnasium/theodi/datapackage.rb.svg?style=flat-square)](https://gemnasium.com/theodi/datapackage.rb)
|
3
|
+
[![Coverage Status](http://img.shields.io/coveralls/theodi/datapackage.rb.svg?style=flat-square)](https://coveralls.io/r/theodi/datapackage.rb)
|
4
|
+
[![Code Climate](http://img.shields.io/codeclimate/github/theodi/datapackage.rb.svg?style=flat-square)](https://codeclimate.com/github/theodi/datapackage.rb)
|
5
|
+
[![Gem Version](http://img.shields.io/gem/v/datapackage.svg?style=flat-square)](https://rubygems.org/gems/datapackage)
|
6
|
+
[![License](http://img.shields.io/:license-mit-blue.svg?style=flat-square)](http://theodi.mit-license.org)
|
7
|
+
|
1
8
|
# DataPackage.rb
|
2
9
|
|
3
10
|
A ruby library for working with [Data Packages](http://dataprotocols.org/data-packages/).
|
4
11
|
|
5
|
-
[![Build Status](http://jenkins.theodi.org/job/datapackage.rb-master/badge/icon)](http://jenkins.theodi.org/job/datapackage.rb-master/)
|
6
|
-
[![Code Climate](https://codeclimate.com/github/theodi/datapackage.rb.png)](https://codeclimate.com/github/theodi/datapackage.rb)
|
7
|
-
[![Dependency Status](https://gemnasium.com/theodi/datapackage.rb.png)](https://gemnasium.com/theodi/datapackage.rb)
|
8
|
-
|
9
12
|
The library is intending to support:
|
10
13
|
|
11
14
|
* Parsing and using data package metadata and data
|
@@ -15,179 +18,115 @@ The library is intending to support:
|
|
15
18
|
|
16
19
|
Add the gem into your Gemfile:
|
17
20
|
|
18
|
-
|
21
|
+
```
|
22
|
+
gem 'datapackage.rb'
|
23
|
+
```
|
19
24
|
|
20
25
|
Or:
|
21
26
|
|
22
|
-
|
27
|
+
```
|
28
|
+
gem install datapackage
|
29
|
+
```
|
23
30
|
|
24
|
-
##
|
31
|
+
## Reading a Data Package
|
25
32
|
|
26
33
|
Require the gem, if you need to:
|
27
34
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
package = DataPackage::Package.new( "http://example.org/datasets/a" )
|
33
|
-
|
34
|
-
This assumes that `http://example.org/datasets/a/datapackage.json` exists, or specifically load a JSON file:
|
35
|
-
|
36
|
-
package = DataPackage::Package.new( "http://example.org/datasets/a/datapackage.json" )
|
37
|
-
|
38
|
-
Similarly you can load a package from a local JSON file, or specify a directory:
|
39
|
-
|
40
|
-
package = DataPackage::Package.new( "/my/data/package" )
|
41
|
-
package = DataPackage::Package.new( "/my/data/package/datapackage.json" )
|
42
|
-
|
43
|
-
There are a set of helper methods for accessing data from the package, e.g:
|
44
|
-
|
45
|
-
package = DataPackage::Package.new( "/my/data/package" )
|
46
|
-
package.name
|
47
|
-
package.title
|
48
|
-
package.licenses
|
49
|
-
package.resources
|
50
|
-
|
51
|
-
These currently just return the raw JSON structure, but this might change in future.
|
52
|
-
|
53
|
-
## Package Validation
|
54
|
-
|
55
|
-
The library supports validating packages. It can be used to validate both the metadata for the package (`datapackage.json`)
|
56
|
-
and the integrity of the package itself, e.g. whether the data files exist.
|
57
|
-
|
58
|
-
### Validating a Package
|
59
|
-
|
60
|
-
Quickly checking the validity of a package can be achieve as follows:
|
35
|
+
```ruby
|
36
|
+
require 'datapackage.rb'
|
37
|
+
```
|
61
38
|
|
62
|
-
|
63
|
-
|
64
|
-
To expose more detail on errors and warnings:
|
39
|
+
Parsing a Data Package from a remote location:
|
65
40
|
|
66
|
-
|
41
|
+
```ruby
|
42
|
+
package = DataPackage::Package.new( "http://example.org/datasets/a" )
|
43
|
+
```
|
67
44
|
|
68
|
-
This
|
69
|
-
Message objects are formatted as follows:
|
70
|
-
|
71
|
-
{
|
72
|
-
:type => :metadata|:integrity,
|
73
|
-
:message => "message for user",
|
74
|
-
:fragment => "/path/to/responsible/element"
|
75
|
-
}
|
76
|
-
|
77
|
-
It is possible to treat all warnings as errors by performing strict validation:
|
78
|
-
|
79
|
-
package.valid?(true)
|
80
|
-
|
81
|
-
Examples of warnings might include notes on missing metadata elements (e.g. package `licenses`) which are not required by the
|
82
|
-
DataPackage specification but which SHOULD be included.
|
83
|
-
|
84
|
-
Warnings are currently generated for:
|
85
|
-
|
86
|
-
* Missing `README.md` files from packages
|
87
|
-
* Missing `licenses` key from `datapackage.json`
|
88
|
-
* Missing `datapackage_version` key from `datapackage.json`
|
89
|
-
|
90
|
-
### Selecting a Validation Profile
|
91
|
-
|
92
|
-
The library contains two validation classes, one for the core Data Package specification and the other for the Simple Data Format
|
93
|
-
rules. By default the library uses the more liberal Data Package rules.
|
94
|
-
|
95
|
-
The required profile can be specified in one of two ways. Either as a parameter to the validation methods:
|
96
|
-
|
97
|
-
package.valid?(:datapackage)
|
98
|
-
package.valid?(:simpledataformat)
|
99
|
-
package.validate(:datapackage)
|
100
|
-
package.validate(:simpledataformat)
|
101
|
-
|
102
|
-
Or, by using a `DataPackage::Validation` class:
|
45
|
+
This assumes that `http://example.org/datasets/a/datapackage.json` exists, or specifically load a JSON file:
|
103
46
|
|
104
|
-
|
105
|
-
|
106
|
-
|
47
|
+
```ruby
|
48
|
+
package = DataPackage::Package.new( "http://example.org/datasets/a/datapackage.json" )
|
49
|
+
```
|
107
50
|
|
108
|
-
|
51
|
+
Similarly you can load a package from a local JSON file, or specify a directory:
|
109
52
|
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
SDF is essentially a profile of DataPackage which includes some additional restrictions on
|
115
|
-
how data should be published and described. For example all data is to be published as CSV files.
|
53
|
+
```ruby
|
54
|
+
package = DataPackage::Package.new( "/my/data/package" )
|
55
|
+
package = DataPackage::Package.new( "/my/data/package/datapackage.json" )
|
56
|
+
```
|
116
57
|
|
117
|
-
|
58
|
+
There are a set of helper methods for accessing data from the package, e.g:
|
118
59
|
|
119
|
-
|
120
|
-
|
60
|
+
```ruby
|
61
|
+
package = DataPackage::Package.new( "/my/data/package" )
|
62
|
+
package.name
|
63
|
+
package.title
|
64
|
+
package.description
|
65
|
+
package.homepage
|
66
|
+
package.license
|
67
|
+
```
|
121
68
|
|
122
|
-
|
69
|
+
## Creating a Data Package
|
123
70
|
|
124
|
-
|
125
|
-
|
71
|
+
```ruby
|
72
|
+
package = DataPackage::Package.new
|
126
73
|
|
127
|
-
|
128
|
-
|
74
|
+
package.name = 'my_sleep_duration'
|
75
|
+
package.resources = [
|
76
|
+
{'name': 'data'}
|
77
|
+
]
|
129
78
|
|
130
|
-
|
79
|
+
resource = package.resources[0]
|
80
|
+
resource.descriptor['data'] = [
|
81
|
+
7, 8, 5, 6, 9, 7, 8
|
82
|
+
]
|
131
83
|
|
132
|
-
|
133
|
-
|
84
|
+
File.open('datapackage.json', 'w') do |f|
|
85
|
+
f.write(package.to_json)
|
86
|
+
end
|
134
87
|
|
135
|
-
|
88
|
+
# {"name": "my_sleep_duration", "resources": [{"name": "data", "data": [7, 8, 5, 6, 9, 7, 8]}]}
|
89
|
+
```
|
136
90
|
|
137
|
-
|
138
|
-
* (`:simpledataformat`) All resources must be CSV files
|
139
|
-
* (`:simpledataformat`) All resources must have a valid JSON Table Schema
|
140
|
-
* (`:simpledataformat`) CSV `dialect` descriptions must be valid
|
141
|
-
* (`:simpledataformat`) All fields declared in the schema must be present in the CSV file
|
142
|
-
* (`:simpledataformat`) All fields present in the CSV file must be present in the schema
|
91
|
+
## Validating a Data Package
|
143
92
|
|
144
|
-
|
93
|
+
```ruby
|
94
|
+
package = DataPackage::Package.new('http://data.okfn.org/data/core/gdp/datapackage.json')
|
145
95
|
|
146
|
-
|
96
|
+
package.valid?
|
97
|
+
#=> true
|
98
|
+
package.errors
|
99
|
+
#=> [] # An array of errors
|
100
|
+
```
|
147
101
|
|
148
|
-
|
102
|
+
## Using a different schema
|
149
103
|
|
150
|
-
|
151
|
-
provided to the constructor of a `DataPackage::Validator` object, this can be used to map schema names to custom
|
152
|
-
schemas.
|
104
|
+
By default, the gem uses the standard [Data Package Schema](http://specs.frictionlessdata.io/data-packages/), but alternative schemas are available.
|
153
105
|
|
154
|
-
|
155
|
-
|
156
|
-
For example to create a new validation profile called `my-validation-rules` and then apply it:
|
106
|
+
### Schemas in the local cache
|
157
107
|
|
158
|
-
|
159
|
-
:schema => {
|
160
|
-
:my-validation-rules => "/path/to/json/schema.json"
|
161
|
-
}
|
162
|
-
}
|
163
|
-
package = DataPackage::Package.new( url )
|
164
|
-
package.valid?(:my-validation-rules)
|
108
|
+
The gem comes with schemas for the standard Data Package Schema, as well as the [Tabular Data Package Schema](http://specs.frictionlessdata.io/tabular-data-package/), and the [Fiscal Data Package Schema](http://fiscal.dataprotocols.org/spec/). These can be referred to via an identifier, expressed as a symbol.
|
165
109
|
|
166
|
-
|
167
|
-
|
110
|
+
```ruby
|
111
|
+
package = DataPackage::Package.new(nil, :tabular) # Or :fiscal
|
112
|
+
```
|
168
113
|
|
169
|
-
|
114
|
+
### Schemas from elsewhere
|
170
115
|
|
171
|
-
|
172
|
-
:schema => {
|
173
|
-
:my-validation-rules => "/path/to/json/schema.json"
|
174
|
-
}
|
175
|
-
}
|
176
|
-
validator = DataPackage::SimpleDataFormatValidator(:my-validation-rules, opts)
|
177
|
-
validator.valid?( package )
|
116
|
+
If you have a schema stored in an alternative registry, you can pass a `registry_url` option to the initializer.
|
178
117
|
|
179
|
-
|
180
|
-
|
118
|
+
```ruby
|
119
|
+
package = DataPackage::Package.new(nil, :identifier, {registry_url: 'http://example.org/my-registry.csv'} )
|
120
|
+
```
|
181
121
|
|
182
|
-
|
183
|
-
|
184
|
-
The built-in schema files can also be overridden in this way, e.g. by specifying an alternate location for the `:datapackage` schema.
|
122
|
+
## Developer notes
|
185
123
|
|
186
|
-
|
124
|
+
These notes are intended to help people that want to contribute to this package itself. If you just want to use it, you can safely ignore them.
|
187
125
|
|
188
|
-
|
126
|
+
### Updating the local schemas cache
|
189
127
|
|
190
|
-
|
128
|
+
We cache the schemas from https://github.com/dataprotocols/schemas using git-subtree. To update it, use:
|
191
129
|
|
192
|
-
|
193
|
-
|
130
|
+
```
|
131
|
+
git subtree pull --prefix datapackage/schemas https://github.com/dataprotocols/schemas.git master --squash
|
132
|
+
```
|
data/lib/datapackage/package.rb
CHANGED
@@ -1,160 +1,181 @@
|
|
1
1
|
require 'open-uri'
|
2
2
|
|
3
3
|
module DataPackage
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
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
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
4
|
+
class Package < Hash
|
5
|
+
attr_reader :opts, :errors
|
6
|
+
attr_writer :resources
|
7
|
+
|
8
|
+
# Parse or create a data package
|
9
|
+
#
|
10
|
+
# Supports reading data from JSON file, directory, and a URL
|
11
|
+
#
|
12
|
+
# package:: Hash or a String
|
13
|
+
# schema:: Hash, Symbol or String
|
14
|
+
# opts:: Options used to customize reading and parsing
|
15
|
+
def initialize(package = nil, schema = :base, opts = {})
|
16
|
+
@opts = opts
|
17
|
+
@schema = DataPackage::Schema.new(schema || :base)
|
18
|
+
@dead_resources = []
|
19
|
+
|
20
|
+
self.merge! parse_package(package)
|
21
|
+
define_properties!
|
22
|
+
load_resources!
|
23
|
+
end
|
24
|
+
|
25
|
+
def parse_package(package)
|
26
|
+
# TODO: base directory/url
|
27
|
+
if package.nil?
|
28
|
+
{}
|
29
|
+
elsif package.class == Hash
|
30
|
+
package
|
31
|
+
else
|
32
|
+
read_package(package)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# Returns the directory for a local file package or base url for a remote
|
37
|
+
# Returns nil for an in-memory object (because it has no base as yet)
|
38
|
+
def base
|
39
|
+
# user can override base
|
40
|
+
return @opts[:base] if @opts[:base]
|
41
|
+
return '' unless @location
|
42
|
+
# work out base directory or uri
|
43
|
+
if local?
|
44
|
+
return File.dirname(@location)
|
45
|
+
else
|
46
|
+
return @location.split('/')[0..-2].join('/')
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# Is this a local package? Returns true if created from an in-memory object or a file/directory reference
|
51
|
+
def local?
|
52
|
+
return @local if @local
|
53
|
+
return !@location.start_with?('http') if @location
|
54
|
+
true
|
55
|
+
end
|
56
|
+
|
57
|
+
def resources
|
58
|
+
update_resources!
|
59
|
+
@resources
|
60
|
+
end
|
61
|
+
|
62
|
+
def property(property, default = nil)
|
63
|
+
self[property] || default
|
64
|
+
end
|
65
|
+
|
66
|
+
def valid?
|
67
|
+
validate
|
68
|
+
@valid
|
69
|
+
end
|
70
|
+
|
71
|
+
def validate
|
72
|
+
@errors = @schema.validation_errors(self)
|
73
|
+
@valid = @schema.valid?(self)
|
74
|
+
end
|
75
|
+
|
76
|
+
def resource_exists?(location)
|
77
|
+
@dead_resources.include?(location)
|
78
|
+
end
|
79
|
+
|
80
|
+
def to_json
|
81
|
+
self.to_json
|
82
|
+
end
|
83
|
+
|
84
|
+
private
|
85
|
+
|
86
|
+
def define_properties!
|
87
|
+
(@schema['properties'] || {}).each do |k, v|
|
88
|
+
next if k == 'resources'
|
89
|
+
define_singleton_method("#{k.to_sym}=", proc { |p| set_property(k, p) })
|
90
|
+
define_singleton_method(k.to_sym.to_s, proc { property k, default_value(v) })
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def load_resources!
|
95
|
+
@resources = (self['resources'] || [])
|
96
|
+
update_resources!
|
97
|
+
end
|
98
|
+
|
99
|
+
def update_resources!
|
100
|
+
@resources.map! do |resource|
|
101
|
+
begin
|
102
|
+
load_resource(resource)
|
103
|
+
rescue
|
104
|
+
@dead_resources << resource['path']
|
105
|
+
nil
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def load_resource(resource)
|
111
|
+
if resource.is_a?(Resource)
|
112
|
+
resource
|
113
|
+
else
|
114
|
+
Resource.load(resource, base)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def default_value(schema_data)
|
119
|
+
case schema_data['type']
|
120
|
+
when 'string'
|
121
|
+
nil
|
122
|
+
when 'array'
|
123
|
+
[]
|
124
|
+
when 'object'
|
125
|
+
{}
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def set_property(key, value)
|
130
|
+
self[key] = value
|
131
|
+
end
|
132
|
+
|
133
|
+
def read_package(package)
|
134
|
+
if is_directory?(package)
|
135
|
+
package = File.join(package, opts[:default_filename] || 'datapackage.json')
|
136
|
+
elsif is_containing_url?(package)
|
137
|
+
package = URI.join(package, 'datapackage.json')
|
138
|
+
end
|
139
|
+
|
140
|
+
@location = package.to_s
|
141
|
+
|
142
|
+
if File.extname(package.to_s) == '.zip'
|
143
|
+
unzip_package(package)
|
144
|
+
else
|
145
|
+
JSON.parse open(package).read
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
def is_directory?(package)
|
150
|
+
!package.start_with?('http') && File.directory?(package)
|
151
|
+
end
|
152
|
+
|
153
|
+
def is_containing_url?(package)
|
154
|
+
package.start_with?('http') && !package.end_with?('datapackage.json', 'datapackage.zip')
|
155
|
+
end
|
156
|
+
|
157
|
+
def write_to_tempfile(url)
|
158
|
+
tempfile = Tempfile.new('datapackage')
|
159
|
+
tempfile.write(open(url).read)
|
160
|
+
tempfile.rewind
|
161
|
+
tempfile
|
162
|
+
end
|
163
|
+
|
164
|
+
def unzip_package(package)
|
165
|
+
package = write_to_tempfile(package) if package.start_with?('http')
|
166
|
+
dir = Dir.mktmpdir
|
167
|
+
Zip::File.open(package) do |zip_file|
|
168
|
+
# Extract all the files
|
169
|
+
zip_file.each { |entry| entry.extract("#{dir}/#{File.basename entry.name}") }
|
170
|
+
# Get and parse the datapackage metadata
|
171
|
+
entry = zip_file.glob("*/#{opts[:default_filename] || 'datapackage.json'}").first
|
172
|
+
package = JSON.parse(entry.get_input_stream.read)
|
173
|
+
end
|
174
|
+
# Set the base dir to the directory we unzipped to
|
175
|
+
@opts[:base] = dir
|
176
|
+
# This is now a local file, not a URL
|
177
|
+
@local = true
|
178
|
+
package
|
159
179
|
end
|
160
|
-
end
|
180
|
+
end
|
181
|
+
end
|