undata 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.
@@ -0,0 +1,5 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="Encoding" useUTFGuessing="true" native2AsciiForPropertiesFiles="false" />
4
+ </project>
5
+
data/.idea/misc.xml ADDED
@@ -0,0 +1,8 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="DependencyValidationManager">
4
+ <option name="SKIP_IMPORT_STATEMENTS" value="false" />
5
+ </component>
6
+ <component name="ProjectRootManager" version="2" project-jdk-name="Ruby SDK 1.8.7-p330" project-jdk-type="RUBY_SDK" />
7
+ </project>
8
+
data/.idea/modules.xml ADDED
@@ -0,0 +1,9 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="ProjectModuleManager">
4
+ <modules>
5
+ <module fileurl="file://$PROJECT_DIR$/.idea/undata.iml" filepath="$PROJECT_DIR$/.idea/undata.iml" />
6
+ </modules>
7
+ </component>
8
+ </project>
9
+
data/.idea/undata.iml ADDED
@@ -0,0 +1,21 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <module type="RUBY_MODULE" version="4">
3
+ <component name="GemRequirementsHolder" version="3">
4
+ <requirement>
5
+ <requirement>
6
+ <dependency name="mocha" version="0" bound="GREATER_OR_EQUAL" git="false" path="false" doRequire="true" />
7
+ </requirement>
8
+ <source from="test/helper.rb" />
9
+ </requirement>
10
+ </component>
11
+ <component name="NewModuleRootManager">
12
+ <content url="file://$MODULE_DIR$" />
13
+ <orderEntry type="inheritedJdk" />
14
+ <orderEntry type="sourceFolder" forTests="false" />
15
+ <orderEntry type="library" scope="PROVIDED" name="[gem] rake (v0.8.7, /Users/gcb/.gem/ruby/1.8/gems/rake-0.8.7)" level="application" />
16
+ <orderEntry type="library" scope="PROVIDED" name="[gem] mocha (v0.9.12, /opt/local/lib/ruby/gems/1.8/gems/mocha-0.9.12)" level="application" />
17
+ <orderEntry type="library" scope="PROVIDED" name="[gem] test-unit (v2.2.0, /opt/local/lib/ruby/gems/1.8/gems/test-unit-2.2.0)" level="application" />
18
+ </component>
19
+ <component name="RModuleSettingsStorage" number="2" string0="$MODULE_DIR$/lib" string1="$MODULE_DIR$/test" />
20
+ </module>
21
+
data/.idea/vcs.xml ADDED
@@ -0,0 +1,7 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="VcsDirectoryMappings">
4
+ <mapping directory="$PROJECT_DIR$" vcs="Git" />
5
+ </component>
6
+ </project>
7
+
data/README.rdoc ADDED
@@ -0,0 +1,42 @@
1
+ = toxic
2
+
3
+ * http://github.com/grahambrooks/undata
4
+
5
+ == DESCRIPTION:
6
+
7
+ This gem provides a client side interface for accessing UN data provided by the http://www.undata-api.org/ service. A user registration key is required to access the data.
8
+
9
+ == FEATURES/PROBLEMS:
10
+
11
+ * None
12
+
13
+ == SYNOPSIS:
14
+
15
+ == REQUIREMENTS:
16
+
17
+ *
18
+
19
+ == INSTALL:
20
+
21
+ == LICENSE:
22
+
23
+ Copyright (c) 2011 Graham Brooks
24
+
25
+ Permission is hereby granted, free of charge, to any person obtaining
26
+ a copy of this software and associated documentation files (the
27
+ 'Software'), to deal in the Software without restriction, including
28
+ without limitation the rights to use, copy, modify, merge, publish,
29
+ distribute, sublicense, and/or sell copies of the Software, and to
30
+ permit persons to whom the Software is furnished to do so, subject to
31
+ the following conditions:
32
+
33
+ The above copyright notice and this permission notice shall be
34
+ included in all copies or substantial portions of the Software.
35
+
36
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
37
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
38
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
39
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
40
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
41
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
42
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,36 @@
1
+ require 'rake/testtask'
2
+ require 'metric_fu'
3
+
4
+ Rake::TestTask.new(:test) do |test|
5
+ test.libs << 'test'
6
+ test.pattern = 'test/**/test_*.rb'
7
+ test.verbose = false
8
+ end
9
+
10
+ task :default => :test
11
+
12
+ namespace :test do
13
+ desc 'Measures test coverage'
14
+ task :coverage do
15
+ rm_f "coverage"
16
+ rm_f "coverage.data"
17
+ system 'rcov --aggregate coverage.data --text-summary -Ilib:test test/unit/un/data/*.rb'
18
+ system 'rcov --aggregate coverage.data --text-summary -Ilib:test test/integration/un/data/*.rb'
19
+ end
20
+ end
21
+
22
+ begin
23
+ require 'jeweler'
24
+ Jeweler::Tasks.new do |gem|
25
+ gem.version
26
+ gem.name = "undata"
27
+ gem.summary = %Q{undata - UN Data client library}
28
+ gem.description = %Q{The UN have a number of initiatives to make data readily accessible. This library is intended to help in consuming and using that data.}
29
+ gem.homepage = "http://github.com/grahambrooks/undata"
30
+ gem.email = ["graham@grahambrooks.com"]
31
+ gem.authors = ["Graham Brooks"]
32
+ gem.add_development_dependency "mocha", ">= 0"
33
+ end
34
+ rescue LoadError
35
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
36
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
@@ -0,0 +1,60 @@
1
+ require 'un/data/host_adaptor'
2
+
3
+ module UN
4
+ module Data
5
+ UNDATA_USER_KEY_NAME = 'UNDATA_USER_KEY'
6
+ HOST_NAME = 'undata-api.appspot.com'
7
+
8
+ class Client
9
+ def initialize(options = {})
10
+ @host_adpator = options[:host_adpator] || UN::Data::HostAdaptor.new
11
+ @response_parser = options[:response_parser] || UN::Data::ResponseParser.new
12
+
13
+ configure_user_key(options)
14
+ end
15
+
16
+ def configure_user_key(options)
17
+ @user_key = ENV[UNDATA_USER_KEY_NAME]
18
+
19
+ @user_key = options[:user_key] || @user_key || raise("User key (#{@user_key}) not specified")
20
+ end
21
+
22
+ def user_key
23
+ @user_key
24
+ end
25
+
26
+ def data_sets
27
+ uri = user_uri :path => '/data/index'
28
+
29
+ response = @host_adpator.get(uri)
30
+
31
+ @response_parser.parse_data_sets response
32
+ end
33
+
34
+ def general_query(name)
35
+ uri = user_uri :path => "/data/query/#{URI.escape(name, Regexp.new('[^#{URI::PATTERN::UNRESERVED}]'))}"
36
+
37
+ response = @host_adpator.get(uri)
38
+
39
+ @response_parser.parse_query_results response
40
+ end
41
+
42
+ def filtered_query(parameters = {})
43
+ path = '/data/query/'
44
+ path << URI.escape(parameters[:name], Regexp.new('[^#{URI::PATTERN::UNRESERVED}]')) || raise('Dataset parameter required for general queries')
45
+ path << '/' << URI.escape(parameters[:year]) unless parameters[:year].nil?
46
+ path << '/' << URI.escape(parameters[:country]) unless parameters[:country].nil?
47
+
48
+ uri = user_uri :path => path
49
+
50
+ response = @host_adpator.get(uri)
51
+
52
+ @response_parser.parse_filter_query response
53
+ end
54
+
55
+ def user_uri(options = {})
56
+ URI::HTTP.build :host => HOST_NAME, :path => options[:path], :query => "user_key=#{@user_key}"
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,16 @@
1
+ require 'net/http'
2
+
3
+
4
+ module UN
5
+ module Data
6
+ class HostAdaptor
7
+ def get(uri)
8
+ result = Net::HTTP.start(uri.host, uri.port) do |http|
9
+ http.get "#{uri.path}?#{uri.query}"
10
+ end
11
+
12
+ result.body
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,100 @@
1
+ require 'rexml/document'
2
+ require 'ostruct'
3
+
4
+ module UN
5
+ module Data
6
+ class QueryResult
7
+ def initialize(values)
8
+ @data = {}
9
+ values.each do |key, value|
10
+ @data[key] = value
11
+ end
12
+ end
13
+
14
+ def [](key)
15
+ @data[key]
16
+ end
17
+
18
+ def length
19
+ @data.length
20
+ end
21
+
22
+ def to_s
23
+ result = ""
24
+ @data.each do |key, value|
25
+ result << "#{key} = #{value}\n"
26
+ end
27
+ result
28
+ end
29
+ end
30
+
31
+ class ResponseParser
32
+ def initialize(options={})
33
+ end
34
+
35
+ def check_for_errors(document)
36
+ document.elements.each("/error") do |element|
37
+ raise element.text
38
+ end
39
+ end
40
+
41
+ def parse_data_sets(data)
42
+ document = REXML::Document.new data
43
+
44
+ check_for_errors document
45
+
46
+ result = []
47
+ document.elements.each("/datasets/dataset") do |element|
48
+ result << OpenStruct.new(:organisation => element.attributes['organisation'],
49
+ :category => element.attributes['category'],
50
+ :name => element.attributes['name'])
51
+ end
52
+
53
+ result
54
+ end
55
+
56
+
57
+ def parse_query_results(data)
58
+ document = REXML::Document.new data
59
+
60
+ check_for_errors document
61
+
62
+ result = []
63
+
64
+ document.elements.each("/data/record") do |element|
65
+
66
+ fields ={}
67
+
68
+ element.elements.each do |e|
69
+ fields[e.attributes['name']] = e.text
70
+ end
71
+
72
+ result << QueryResult.new(fields)
73
+ end
74
+
75
+ result
76
+ end
77
+
78
+ def parse_filter_query(data)
79
+ document = REXML::Document.new data
80
+
81
+ check_for_errors document
82
+
83
+ result = []
84
+
85
+ document.elements.each("/data/record") do |element|
86
+
87
+ fields ={}
88
+
89
+ element.elements.each do |e|
90
+ fields[e.attributes['name']] = e.text
91
+ end
92
+
93
+ result << QueryResult.new(fields)
94
+ end
95
+
96
+ result
97
+ end
98
+ end
99
+ end
100
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,64 @@
1
+ begin
2
+ require 'rubygems'
3
+ gem 'mocha'
4
+ rescue LoadError
5
+ end
6
+ require 'rubygems'
7
+ require 'stringio'
8
+ require 'test/unit'
9
+ require 'mocha'
10
+
11
+ module DeclarativeTestMethods
12
+ def self.extended(klass)
13
+ klass.class_eval do
14
+
15
+ unless method_defined?(:describe)
16
+ def self.describe(text)
17
+ class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
18
+ def self.name
19
+ "#{text}"
20
+ end
21
+ RUBY_EVAL
22
+ end
23
+ end
24
+
25
+ end
26
+ end
27
+
28
+ unless defined?(Spec)
29
+ # test "verify something" do
30
+ # ...
31
+ # end
32
+ def test(name, &block)
33
+ test_name = "test_#{name.gsub(/\s+/, '_')}".to_sym
34
+ defined = instance_method(test_name) rescue false
35
+ raise "#{test_name} is already defined in #{self}" if defined
36
+ if block_given?
37
+ define_method(test_name, &block)
38
+ else
39
+ define_method(test_name) do
40
+ fail "No implementation provided for #{name}"
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+
47
+ class TestCase < Test::Unit::TestCase
48
+ extend DeclarativeTestMethods
49
+
50
+ def default_test
51
+ end
52
+ end
53
+
54
+ module StdioHelper
55
+ def capture_stdout
56
+ s = StringIO.new
57
+ old_stdout = $stdout
58
+ $stdout = s
59
+ yield
60
+ s.string
61
+ ensure
62
+ $stdout = old_stdout
63
+ end
64
+ end
@@ -0,0 +1,39 @@
1
+ require 'helper'
2
+ require 'un/data/client'
3
+
4
+ class TestClient < TestCase
5
+ test "user key read from environment" do
6
+ client = UN::Data::Client.new
7
+
8
+ assert_equal 32, client.user_key.length
9
+ end
10
+
11
+ test 'retrieve datasets' do
12
+ client = UN::Data::Client.new
13
+
14
+ assert client.data_sets.length > 1
15
+ end
16
+
17
+ test 'query data' do
18
+ client = UN::Data::Client.new
19
+
20
+ data_sets = client.data_sets
21
+
22
+ result = client.general_query data_sets.first.name
23
+
24
+ assert result.length > 0
25
+ end
26
+
27
+ test 'filtered query' do
28
+ client = UN::Data::Client.new
29
+
30
+ data_sets = client.data_sets
31
+ general = client.general_query data_sets.first.name
32
+
33
+ result = client.filtered_query(:name => data_sets[0].name,
34
+ :country => general[0]['Country or Area'],
35
+ :year => general[0]['Year(s)'])
36
+
37
+ assert result.length > 0
38
+ end
39
+ end
@@ -0,0 +1,65 @@
1
+ require 'helper'
2
+ require 'un/data/client'
3
+
4
+ class TestClient < TestCase
5
+ test 'can instanciate a client' do
6
+ UN::Data::Client.new :user_key => ''
7
+ end
8
+
9
+ def using_environment(options, &block)
10
+ original = {}
11
+ options.each do |key, value|
12
+ original[key] = ENV[key]
13
+ ENV[key] = value
14
+ end
15
+ yield
16
+ original.each do |key, value|
17
+ ENV[key] = value
18
+ end
19
+ end
20
+
21
+ test 'client requires a user key' do
22
+ using_environment UN::Data::UNDATA_USER_KEY_NAME => nil do
23
+ assert_raises RuntimeError do
24
+ UN::Data::Client.new
25
+ end
26
+ end
27
+ end
28
+
29
+ test 'client reads user key from environment if not specified' do
30
+
31
+ using_environment UN::Data::UNDATA_USER_KEY_NAME => 'foo' do
32
+ client = UN::Data::Client.new
33
+
34
+ assert_equal 'foo', client.user_key
35
+ end
36
+ end
37
+
38
+ test 'client requests appropriate URL' do
39
+ mock_host_adaptor = mock('host adaptor')
40
+
41
+ mock_host_adaptor.expects(:get).with(any_parameters)
42
+
43
+ client = UN::Data::Client.new :user_key => 'foo', :host_adpator => mock_host_adaptor
44
+
45
+ client.data_sets
46
+ end
47
+
48
+ test 'user uri include the user key' do
49
+ client = UN::Data::Client.new :user_key => 'foo'
50
+
51
+ uri = client.user_uri :path => '/'
52
+
53
+ assert_equal 'undata-api.appspot.com', uri.host
54
+ assert_equal '/', uri.path
55
+ end
56
+
57
+ test 'client parses response' do
58
+ mock_parser = mock('response parser')
59
+ mock_parser.expects(:parse_data_sets).with('some xml')
60
+
61
+ client = UN::Data::Client.new :user_key => 'foo', :host_adpator => stub(:get => "some xml"), :response_parser => mock_parser
62
+
63
+ client.data_sets
64
+ end
65
+ end
@@ -0,0 +1,8 @@
1
+ require 'helper'
2
+
3
+
4
+ class TestHostAdaptor < TestCase
5
+ test 'can instantiate a host adaptor' do
6
+ UN::Data::HostAdaptor.new
7
+ end
8
+ end
@@ -0,0 +1,16 @@
1
+ require 'helper'
2
+ require 'un/data/response_parser'
3
+
4
+ class TestQueryResult < TestCase
5
+ test 'results contain value' do
6
+ result = UN::Data::QueryResult.new 'key' => 'value'
7
+
8
+ assert_equal 'value', result['key']
9
+ end
10
+
11
+ test 'results can be represented as text' do
12
+ result = UN::Data::QueryResult.new 'key' => 'value'
13
+
14
+ assert_equal "key = value\n", result.to_s
15
+ end
16
+ end
@@ -0,0 +1,84 @@
1
+ require 'helper'
2
+ require 'un/data/response_parser'
3
+
4
+ class TestResponseParser < TestCase
5
+
6
+ test 'can instantiate a parser' do
7
+ UN::Data::ResponseParser.new
8
+ end
9
+
10
+ test 'parses basic datasets' do
11
+ single_entry = <<EOD
12
+ <datasets>
13
+ <dataset organisation='IMF' category='International Financial statistics' name='BOP: capital account credit, US$' />
14
+ </datasets>
15
+ EOD
16
+ parser = UN::Data::ResponseParser.new
17
+
18
+ data = parser.parse_data_sets single_entry
19
+
20
+ assert_equal 1, data.length
21
+ assert_equal 'IMF', data[0].organisation
22
+ assert_equal 'International Financial statistics', data[0].category
23
+ assert_equal 'BOP: capital account credit, US$', data[0].name
24
+ end
25
+
26
+ test "parses general query results" do
27
+ query_result = <<EOD
28
+ <data>
29
+ <record>
30
+ <field name="Country or Area">Afghanistan</field>
31
+ <field name="Year(s)">2001</field>
32
+ <field name="Value">151</field>
33
+ </record>
34
+ </data>
35
+ EOD
36
+ parser = UN::Data::ResponseParser.new
37
+
38
+ data = parser.parse_query_results query_result
39
+
40
+ assert_equal 1, data.length
41
+ assert_equal 3, data[0].length
42
+ assert_equal 'Afghanistan', data[0]["Country or Area"]
43
+ assert_equal '2001', data[0]['Year(s)']
44
+ assert_equal '151', data[0]['Value']
45
+ end
46
+
47
+ test "handles error elements as exceptions" do
48
+ error_data = <<EOD
49
+ <?xml version="1.0" encoding="utf-8"?><error id="user.invalid_key">user_key is invalid</error>
50
+ EOD
51
+
52
+ parser = UN::Data::ResponseParser.new
53
+
54
+ assert_raises RuntimeError do
55
+ parser.parse_data_sets error_data
56
+ end
57
+
58
+ assert_raises RuntimeError do
59
+ parser.parse_query_results error_data
60
+ end
61
+ end
62
+
63
+ test 'handles filtered query results' do
64
+ query_result = <<EOD
65
+ <data organisation="WHO"
66
+ category="Demographic and socioeconomic statistics"
67
+ name="Adolescent fertility rate">
68
+ <record>
69
+ <field name="Country or Area">Albania</field>
70
+ <field name="Year(s)">2001</field>
71
+ <field name="Value">98.7</field>
72
+ </record>
73
+ </data>
74
+ EOD
75
+ parser = UN::Data::ResponseParser.new
76
+
77
+ data = parser.parse_filter_query query_result
78
+
79
+ assert_equal 1, data.length
80
+ assert_equal 'Albania', data[0]['Country or Area']
81
+ assert_equal '2001', data[0]['Year(s)']
82
+ assert_equal '98.7', data[0]['Value']
83
+ end
84
+ end
metadata ADDED
@@ -0,0 +1,81 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: undata
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.0.1
6
+ platform: ruby
7
+ authors:
8
+ - Graham Brooks
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2011-05-15 00:00:00 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: mocha
17
+ prerelease: false
18
+ requirement: &id001 !ruby/object:Gem::Requirement
19
+ none: false
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ type: :development
25
+ version_requirements: *id001
26
+ description: The UN have a number of initiatives to make data readily accessible. This library is intended to help in consuming and using that data.
27
+ email:
28
+ - graham@grahambrooks.com
29
+ executables: []
30
+
31
+ extensions: []
32
+
33
+ extra_rdoc_files:
34
+ - README.rdoc
35
+ files:
36
+ - .idea/encodings.xml
37
+ - .idea/misc.xml
38
+ - .idea/modules.xml
39
+ - .idea/undata.iml
40
+ - .idea/vcs.xml
41
+ - README.rdoc
42
+ - Rakefile
43
+ - VERSION
44
+ - lib/un/data/client.rb
45
+ - lib/un/data/host_adaptor.rb
46
+ - lib/un/data/response_parser.rb
47
+ - test/helper.rb
48
+ - test/integration/un/data/test_client_integration.rb
49
+ - test/unit/un/data/test_client.rb
50
+ - test/unit/un/data/test_host_adaptor.rb
51
+ - test/unit/un/data/test_query_result.rb
52
+ - test/unit/un/data/test_response_parser.rb
53
+ homepage: http://github.com/grahambrooks/undata
54
+ licenses: []
55
+
56
+ post_install_message:
57
+ rdoc_options: []
58
+
59
+ require_paths:
60
+ - lib
61
+ required_ruby_version: !ruby/object:Gem::Requirement
62
+ none: false
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: "0"
67
+ required_rubygems_version: !ruby/object:Gem::Requirement
68
+ none: false
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: "0"
73
+ requirements: []
74
+
75
+ rubyforge_project:
76
+ rubygems_version: 1.7.2
77
+ signing_key:
78
+ specification_version: 3
79
+ summary: undata - UN Data client library
80
+ test_files: []
81
+