data_package 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +18 -0
- data/.rspec +2 -0
- data/.travis.yml +7 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +53 -0
- data/LICENSE +20 -0
- data/README.md +32 -0
- data/Rakefile +6 -0
- data/data_package.gemspec +33 -0
- data/lib/attr_helper/base_attr.rb +36 -0
- data/lib/attr_helper/required_attr.rb +46 -0
- data/lib/attr_helper/serialization.rb +25 -0
- data/lib/attr_helper.rb +105 -0
- data/lib/data_package/base.rb +10 -0
- data/lib/data_package/dialect.rb +9 -0
- data/lib/data_package/field.rb +20 -0
- data/lib/data_package/license.rb +8 -0
- data/lib/data_package/package.rb +100 -0
- data/lib/data_package/person.rb +7 -0
- data/lib/data_package/resource.rb +75 -0
- data/lib/data_package/schema.rb +13 -0
- data/lib/data_package/source.rb +7 -0
- data/lib/data_package/version.rb +3 -0
- data/lib/data_package.rb +17 -0
- data/spec/attr_helper_spec.rb +60 -0
- data/spec/attr_helpers/base_attr_spec.rb +62 -0
- data/spec/attr_helpers/required_attr_spec.rb +49 -0
- data/spec/attr_helpers/serialization_spec.rb +9 -0
- data/spec/data_package/base_spec.rb +10 -0
- data/spec/data_package/dialect_spec.rb +35 -0
- data/spec/data_package/field_spec.rb +29 -0
- data/spec/data_package/license_spec.rb +18 -0
- data/spec/data_package/package_spec.rb +59 -0
- data/spec/data_package/person_spec.rb +21 -0
- data/spec/data_package/resource_spec.rb +57 -0
- data/spec/data_package/schema_spec.rb +25 -0
- data/spec/data_package/source_spec.rb +22 -0
- data/spec/fixtures/package/datapackage.json +94 -0
- data/spec/fixtures/package/standard.csv +11 -0
- data/spec/fixtures/standard.csv +11 -0
- data/spec/klass_helper.rb +41 -0
- data/spec/resource_helper.rb +113 -0
- data/spec/spec_helper.rb +19 -0
- metadata +233 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 994a99398c2b3da0d8b872cd4b2382595c15fe29
|
4
|
+
data.tar.gz: 11992961b82bb22855285f7448752bab21c624de
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: bd0f314c6d0528939160c4363b2bc75c86b1d9a5a69092502a5a1c848c4b3d70514627d63dc6c5b3b788d46587e11cb47a02d8008edfb2ac6bd7afd076ce85ac
|
7
|
+
data.tar.gz: a93cd9c42b6cdd905a99ced9f1ac2f103419f5b47e8f123807e936aca0d2ca77f2da76ce193bc846e428765756c4c793121f98379d0030d65f7e4609a34a0fe4
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
data_package (0.0.1)
|
5
|
+
active_support
|
6
|
+
data_kit
|
7
|
+
rcsv
|
8
|
+
rubyzip
|
9
|
+
yajl-ruby
|
10
|
+
|
11
|
+
GEM
|
12
|
+
remote: https://rubygems.org/
|
13
|
+
specs:
|
14
|
+
active_support (3.0.0)
|
15
|
+
activesupport (= 3.0.0)
|
16
|
+
activesupport (3.0.0)
|
17
|
+
codeclimate-test-reporter (0.2.0)
|
18
|
+
simplecov (>= 0.7.1, < 1.0.0)
|
19
|
+
data_kit (0.0.2)
|
20
|
+
rcsv
|
21
|
+
timeliness
|
22
|
+
diff-lcs (1.2.5)
|
23
|
+
docile (1.1.1)
|
24
|
+
multi_json (1.8.2)
|
25
|
+
rake (10.1.0)
|
26
|
+
rcsv (0.1.1)
|
27
|
+
rspec (2.14.1)
|
28
|
+
rspec-core (~> 2.14.0)
|
29
|
+
rspec-expectations (~> 2.14.0)
|
30
|
+
rspec-mocks (~> 2.14.0)
|
31
|
+
rspec-core (2.14.7)
|
32
|
+
rspec-expectations (2.14.4)
|
33
|
+
diff-lcs (>= 1.1.3, < 2.0)
|
34
|
+
rspec-mocks (2.14.4)
|
35
|
+
rubyzip (1.1.0)
|
36
|
+
simplecov (0.8.2)
|
37
|
+
docile (~> 1.1.0)
|
38
|
+
multi_json
|
39
|
+
simplecov-html (~> 0.8.0)
|
40
|
+
simplecov-html (0.8.0)
|
41
|
+
timeliness (0.3.7)
|
42
|
+
yajl-ruby (1.1.0)
|
43
|
+
|
44
|
+
PLATFORMS
|
45
|
+
ruby
|
46
|
+
|
47
|
+
DEPENDENCIES
|
48
|
+
bundler (~> 1.3)
|
49
|
+
codeclimate-test-reporter
|
50
|
+
data_package!
|
51
|
+
rake
|
52
|
+
rspec
|
53
|
+
simplecov
|
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2013 Mode
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
6
|
+
this software and associated documentation files (the "Software"), to deal in
|
7
|
+
the Software without restriction, including without limitation the rights to
|
8
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
9
|
+
the Software, and to permit persons to whom the Software is furnished to do so,
|
10
|
+
subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
17
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
18
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
19
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
20
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
Data Package
|
2
|
+
============
|
3
|
+
|
4
|
+
Library of classes and utilities for reading and writing data packages
|
5
|
+
|
6
|
+
### Attribute Helpers
|
7
|
+
|
8
|
+
#### Usage
|
9
|
+
|
10
|
+
attr_required :name
|
11
|
+
attr_required :path, :if => lamda {|obj|
|
12
|
+
obj.attr_missing?(:url) && obj.attr_missing?(:data)
|
13
|
+
}
|
14
|
+
|
15
|
+
attr_optional :title
|
16
|
+
attr_optional :sources, :default => [], :key => 'sources',
|
17
|
+
:serialize => lambda { |source| source.collect(&:to_hash) }
|
18
|
+
|
19
|
+
key is not required for attr_optional as it defaults to name of the attribute
|
20
|
+
|
21
|
+
#### Instance Methods
|
22
|
+
|
23
|
+
required_attrs => [...]
|
24
|
+
optional_attrs => [...]
|
25
|
+
serializable_attrs => [...]
|
26
|
+
|
27
|
+
attr_required?(attr_name) #=> boolean
|
28
|
+
|
29
|
+
valid? #=> boolean, Are all required fields present?
|
30
|
+
|
31
|
+
attr_missing?(attr_name) #=> boolean
|
32
|
+
attr_present?(attr_name) #=> boolean
|
data/Rakefile
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'data_package/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "data_package"
|
8
|
+
spec.version = DataPackage::VERSION
|
9
|
+
spec.authors = ["Mode Analytics"]
|
10
|
+
spec.email = ["support@modeanalytics.com"]
|
11
|
+
spec.description = %q{Library for reading and writing data packages}
|
12
|
+
spec.summary = %q{Provides a set of classes for reading and writing data packages}
|
13
|
+
spec.homepage = "http://www.modeanalytics.com/"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
# Runtime Dependencies
|
22
|
+
spec.add_runtime_dependency 'rcsv'
|
23
|
+
spec.add_runtime_dependency 'rubyzip'
|
24
|
+
spec.add_runtime_dependency 'yajl-ruby'
|
25
|
+
spec.add_runtime_dependency 'data_kit'
|
26
|
+
spec.add_runtime_dependency 'active_support'
|
27
|
+
|
28
|
+
# Development Dependencies
|
29
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
30
|
+
spec.add_development_dependency "rake"
|
31
|
+
spec.add_development_dependency "rspec"
|
32
|
+
spec.add_development_dependency "simplecov"
|
33
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module AttrHelper
|
2
|
+
class BaseAttr
|
3
|
+
attr_reader :name
|
4
|
+
attr_reader :key
|
5
|
+
attr_reader :default
|
6
|
+
attr_reader :serialize
|
7
|
+
|
8
|
+
def initialize(name, options = {})
|
9
|
+
@name = name
|
10
|
+
@default = options[:default]
|
11
|
+
@key = options[:key] || name.to_s
|
12
|
+
|
13
|
+
if options[:serialize] == false
|
14
|
+
@serialize = false
|
15
|
+
else
|
16
|
+
@serialize = options[:serialize] || true
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def serializable?
|
21
|
+
!@serialize.nil? && @serialize != false
|
22
|
+
end
|
23
|
+
|
24
|
+
def serialized(parent)
|
25
|
+
value = parent.send(name.to_sym) || default
|
26
|
+
|
27
|
+
if @serialize == true
|
28
|
+
value
|
29
|
+
elsif @serialize.is_a?(Symbol)
|
30
|
+
parent.send(@serialize, value)
|
31
|
+
elsif serialize.is_a?(Proc)
|
32
|
+
@serialize.call(value)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module AttrHelper
|
2
|
+
class RequiredAttr < BaseAttr
|
3
|
+
attr_reader :if_cond
|
4
|
+
attr_reader :unless_cond
|
5
|
+
|
6
|
+
def initialize(name, options = {})
|
7
|
+
super(name, options)
|
8
|
+
@if_cond = options[:if]
|
9
|
+
@unless_cond = options[:unless]
|
10
|
+
end
|
11
|
+
|
12
|
+
def required?(parent)
|
13
|
+
if conditions_empty?
|
14
|
+
true
|
15
|
+
else
|
16
|
+
included?(parent) && !excluded?(parent)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def conditions_empty?
|
23
|
+
if_cond.nil? && unless_cond.nil?
|
24
|
+
end
|
25
|
+
|
26
|
+
def included?(parent)
|
27
|
+
if if_cond.nil?
|
28
|
+
true
|
29
|
+
elsif if_cond.is_a?(Symbol)
|
30
|
+
parent.send(if_cond)
|
31
|
+
else
|
32
|
+
if_cond.call(parent)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def excluded?(parent)
|
37
|
+
if unless_cond.nil?
|
38
|
+
false
|
39
|
+
elsif unless_cond.is_a?(Symbol)
|
40
|
+
parent.send(unless_cond)
|
41
|
+
else
|
42
|
+
unless_cond.call(parent)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'yajl'
|
2
|
+
|
3
|
+
module AttrHelper
|
4
|
+
module Serialization
|
5
|
+
def to_hash
|
6
|
+
{}.tap do |hsh|
|
7
|
+
attributes.each do |attribute|
|
8
|
+
next unless attribute.serializable?
|
9
|
+
|
10
|
+
value = attribute.serialized(self)
|
11
|
+
|
12
|
+
if value.respond_to?(:empty?)
|
13
|
+
hsh[attribute.key] = value unless value.empty?
|
14
|
+
else
|
15
|
+
hsh[attribute.key] = value unless value.nil?
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_json(options = {})
|
22
|
+
Yajl::Encoder.encode(to_hash, options.reverse_merge(:pretty => true))
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/attr_helper.rb
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
require 'attr_helper/base_attr'
|
2
|
+
require 'attr_helper/required_attr'
|
3
|
+
require 'attr_helper/serialization'
|
4
|
+
|
5
|
+
module AttrHelper
|
6
|
+
def self.included(klass)
|
7
|
+
klass.send :extend, ClassMethods
|
8
|
+
end
|
9
|
+
|
10
|
+
module ClassMethods
|
11
|
+
def inherited(klass)
|
12
|
+
super
|
13
|
+
|
14
|
+
# we might want to undef here so
|
15
|
+
# that child classes can override
|
16
|
+
|
17
|
+
unless required_attributes.empty?
|
18
|
+
required_attributes.each do |attribute|
|
19
|
+
klass.attr_required attribute.name, {
|
20
|
+
:name => attribute.name,
|
21
|
+
:key => attribute.key,
|
22
|
+
:default => attribute.default,
|
23
|
+
:serialize => attribute.serialize,
|
24
|
+
:if => attribute.if_cond,
|
25
|
+
:unless => attribute.unless_cond
|
26
|
+
}
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
unless optional_attributes.empty?
|
31
|
+
optional_attributes.each do |attribute|
|
32
|
+
klass.attr_optional attribute.name, {
|
33
|
+
:name => attribute.name,
|
34
|
+
:key => attribute.key,
|
35
|
+
:default => attribute.default,
|
36
|
+
:serialize => attribute.serialize
|
37
|
+
}
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def attr_optional(name, options = {})
|
43
|
+
optional_attributes << BaseAttr.new(name.to_sym, options)
|
44
|
+
attr_accessor name.to_sym
|
45
|
+
end
|
46
|
+
|
47
|
+
def optional_attributes
|
48
|
+
@optional_attributes ||= []
|
49
|
+
end
|
50
|
+
|
51
|
+
def attr_required(name, options = {})
|
52
|
+
required_attributes << RequiredAttr.new(name.to_sym, options)
|
53
|
+
attr_accessor name.to_sym
|
54
|
+
end
|
55
|
+
|
56
|
+
def required_attributes
|
57
|
+
@required_attributes ||= []
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def attributes
|
62
|
+
required_attributes + optional_attributes
|
63
|
+
end
|
64
|
+
|
65
|
+
def required_attributes
|
66
|
+
self.class.required_attributes.select do |attribute|
|
67
|
+
attribute.required?(self)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def optional_attributes
|
72
|
+
self.class.optional_attributes
|
73
|
+
end
|
74
|
+
|
75
|
+
def missing_attributes
|
76
|
+
required_attributes.select do |attribute|
|
77
|
+
value = send(attribute.name)
|
78
|
+
value.respond_to?(:empty?) ? value.empty? : value.nil?
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def attr_required?(name)
|
83
|
+
required_attributes.any?{|a| a.name == name}
|
84
|
+
end
|
85
|
+
|
86
|
+
def attr_missing?(name)
|
87
|
+
missing_attributes.any?{|a| a.name == name}
|
88
|
+
end
|
89
|
+
|
90
|
+
def attr_present?(name)
|
91
|
+
!attr_missing?(name)
|
92
|
+
end
|
93
|
+
|
94
|
+
def write_attribute(name, value)
|
95
|
+
self.instance_variable_set("@#{name}", value)
|
96
|
+
end
|
97
|
+
|
98
|
+
def write_attributes(attrs = {})
|
99
|
+
attrs = attrs.symbolize_keys
|
100
|
+
attributes.each do |attribute|
|
101
|
+
value = attrs[attribute.key.to_sym] || attribute.default
|
102
|
+
self.send("#{attribute.name}=", value) unless value.nil?
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
module DataPackage
|
2
|
+
class Dialect < Base
|
3
|
+
attr_optional :delimiter, :default => ','
|
4
|
+
attr_optional :double_quote, :key => 'doublequote', :default => false
|
5
|
+
attr_optional :line_terminator, :key => 'lineterminator', :default => "\n"
|
6
|
+
attr_optional :quote_char, :key => 'quotechar', :default => "\""
|
7
|
+
attr_optional :skip_initial_space, :key => 'skipinitialspace', :default => false
|
8
|
+
end
|
9
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module DataPackage
|
2
|
+
class Field < Base
|
3
|
+
Types = Set.new([
|
4
|
+
:any, :string, :number, :integer,
|
5
|
+
:date, :time, :datetime, :boolean, :binary,
|
6
|
+
:object, :geopoint, :geojson, :array
|
7
|
+
])
|
8
|
+
|
9
|
+
attr_required :name
|
10
|
+
attr_optional :title
|
11
|
+
attr_optional :description
|
12
|
+
attr_optional :type, :default => :string,
|
13
|
+
:serialize => Proc.new{ |type| type && type.to_s }
|
14
|
+
attr_optional :format
|
15
|
+
|
16
|
+
def type=(value)
|
17
|
+
write_attribute(:type, value.to_sym)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
module DataPackage
|
2
|
+
class Package < Base
|
3
|
+
attr_required :name
|
4
|
+
|
5
|
+
attr_optional :path
|
6
|
+
attr_optional :title
|
7
|
+
attr_optional :version
|
8
|
+
attr_optional :description
|
9
|
+
attr_optional :last_modified
|
10
|
+
attr_optional :datapackage_version
|
11
|
+
|
12
|
+
attr_optional :sources, :serialize => Proc.new { |source|
|
13
|
+
source && source.collect(&:to_hash)
|
14
|
+
}
|
15
|
+
|
16
|
+
attr_optional :licenses, :serialize => Proc.new { |licenses|
|
17
|
+
licenses && licenses.collect(&:to_hash)
|
18
|
+
}
|
19
|
+
|
20
|
+
attr_optional :maintainers, :serialize => Proc.new { |maintainers|
|
21
|
+
maintainers && maintainers.collect(&:to_hash)
|
22
|
+
}
|
23
|
+
|
24
|
+
attr_optional :contributors, :serialize => Proc.new { |contributors|
|
25
|
+
contributors && contributors.collect(&:to_hash)
|
26
|
+
}
|
27
|
+
|
28
|
+
attr_optional :resources, :serialize => Proc.new { |resources|
|
29
|
+
resources && resources.collect(&:to_hash)
|
30
|
+
}
|
31
|
+
|
32
|
+
attr_accessor :base_path
|
33
|
+
|
34
|
+
def initialize(base_path, attrs = {})
|
35
|
+
@base_path = base_path
|
36
|
+
super(attrs)
|
37
|
+
end
|
38
|
+
|
39
|
+
def save
|
40
|
+
File.open(full_path, 'w+') do |file|
|
41
|
+
file.write(self.to_json)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def sources=(json)
|
46
|
+
@sources = json.collect{|s| Source.new(s)}
|
47
|
+
end
|
48
|
+
|
49
|
+
def licenses=(json)
|
50
|
+
@licenses = json.collect{|l| License.new(l)}
|
51
|
+
end
|
52
|
+
|
53
|
+
def maintainers=(json)
|
54
|
+
@maintainers = json.collect{|m| Person.new(m)}
|
55
|
+
end
|
56
|
+
|
57
|
+
def contributors=(json)
|
58
|
+
@contributors = json.collect{|c| Person.new(c)}
|
59
|
+
end
|
60
|
+
|
61
|
+
def resources=(json)
|
62
|
+
@resources = json.collect{|r| Resource.new(path, r)}
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
def full_path
|
68
|
+
File.join(base_path, 'datapackage.json')
|
69
|
+
end
|
70
|
+
|
71
|
+
class << self
|
72
|
+
def exist?(base_path)
|
73
|
+
File.exist?(full_path(base_path))
|
74
|
+
end
|
75
|
+
|
76
|
+
def full_path(base_path)
|
77
|
+
File.join(File.expand_path(base_path), 'datapackage.json')
|
78
|
+
end
|
79
|
+
|
80
|
+
def init(base_path, name)
|
81
|
+
pkg = new(base_path, :name => name, :version => '0.0.1')
|
82
|
+
pkg.save
|
83
|
+
|
84
|
+
open(base_path)
|
85
|
+
end
|
86
|
+
|
87
|
+
def open(base_path)
|
88
|
+
full_path = full_path(base_path)
|
89
|
+
base_path = File.expand_path(base_path)
|
90
|
+
|
91
|
+
if File.exist?(full_path)
|
92
|
+
file = File.open(full_path)
|
93
|
+
new(base_path, Yajl::Parser.parse(file))
|
94
|
+
else
|
95
|
+
raise "Couldn't find datapackage.json at #{path}"
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'data_kit'
|
2
|
+
|
3
|
+
module DataPackage
|
4
|
+
class Resource < Base
|
5
|
+
attr_optional :name
|
6
|
+
|
7
|
+
attr_required :data,
|
8
|
+
:if => Proc.new{ |resource| resource.path.nil? && resource.url.nil? }
|
9
|
+
|
10
|
+
attr_required :path,
|
11
|
+
:if => Proc.new{ |resource| resource.data.nil? && resource.url.nil? }
|
12
|
+
|
13
|
+
attr_required :url,
|
14
|
+
:if => Proc.new{ |resource| resource.data.nil? && resource.path.nil? }
|
15
|
+
|
16
|
+
attr_required :schema, :serialize => Proc.new { |schema| schema.to_hash }
|
17
|
+
attr_optional :dialect, :serialize => Proc.new { |dialect| dialect && dialect.to_hash }
|
18
|
+
|
19
|
+
attr_optional :format, :default => 'csv'
|
20
|
+
attr_optional :media_type, :key => 'mediaType'
|
21
|
+
|
22
|
+
attr_optional :size
|
23
|
+
attr_optional :hash
|
24
|
+
attr_optional :last_modified, :key => 'lastModified'
|
25
|
+
|
26
|
+
attr_accessor :base_path
|
27
|
+
|
28
|
+
def initialize(base_path, attrs = {})
|
29
|
+
@base_path = base_path
|
30
|
+
super(attrs)
|
31
|
+
end
|
32
|
+
|
33
|
+
def schema=(json)
|
34
|
+
@schema = Schema.new(json)
|
35
|
+
end
|
36
|
+
|
37
|
+
def dialect=(json)
|
38
|
+
@dialect = Dialect.new(json)
|
39
|
+
end
|
40
|
+
|
41
|
+
def each_row(&block)
|
42
|
+
case data_source_type
|
43
|
+
when :data
|
44
|
+
data.each(&block)
|
45
|
+
when :path
|
46
|
+
case format
|
47
|
+
when 'csv'
|
48
|
+
DataKit::CSV::Parser.new(full_path).each_row(&block)
|
49
|
+
else
|
50
|
+
raise "Unrecognized resource format #{format} for resource #{name}."
|
51
|
+
end
|
52
|
+
when :url
|
53
|
+
raise "URL based resources are not yet supported"
|
54
|
+
else
|
55
|
+
raise "Resources require one of data, path or url keys to be specified"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
def full_path
|
62
|
+
File.join(base_path, path)
|
63
|
+
end
|
64
|
+
|
65
|
+
def data_source_type
|
66
|
+
if data
|
67
|
+
:data
|
68
|
+
elsif path
|
69
|
+
:path
|
70
|
+
elsif url
|
71
|
+
:url
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module DataPackage
|
2
|
+
class Schema < Base
|
3
|
+
attr_required :fields, :serialize => Proc.new { |fields|
|
4
|
+
fields.collect(&:to_hash)
|
5
|
+
}
|
6
|
+
|
7
|
+
attr_optional :primary_key, :key => 'primaryKey'
|
8
|
+
|
9
|
+
def fields=(json)
|
10
|
+
@fields = json.collect{|f| Field.new(f)}
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|