reittiopas 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt CHANGED
@@ -1,4 +1,4 @@
1
- === 0.0.1 2010-03-29
1
+ === 0.0.1 2010-04-05
2
2
 
3
3
  * 1 major enhancement:
4
4
  * Initial release
data/Manifest.txt CHANGED
@@ -2,9 +2,9 @@ History.txt
2
2
  Manifest.txt
3
3
  README.rdoc
4
4
  Rakefile
5
- deps.rip
6
5
  lib/reittiopas.rb
7
6
  lib/reittiopas/coordinates.rb
7
+ lib/reittiopas/exceptions.rb
8
8
  lib/reittiopas/geocoding.rb
9
9
  lib/reittiopas/http.rb
10
10
  lib/reittiopas/location.rb
@@ -14,8 +14,10 @@ script/console
14
14
  script/destroy
15
15
  script/generate
16
16
  spec/fixtures/key.xml
17
+ spec/fixtures/no_access
17
18
  spec/fixtures/reverse_geocoding.xml
18
19
  spec/reittiopas_spec.rb
19
20
  spec/spec.opts
20
21
  spec/spec_helper.rb
22
+ tasks/rdoc.rake
21
23
  tasks/rspec.rake
data/README.rdoc CHANGED
@@ -1,6 +1,7 @@
1
1
  = Reittiopas
2
2
 
3
3
  * {Documentation at Github}[http://raneksi.github.com/reittiopas/]
4
+ * {Specifications}[http://raneksi.github.com/reittiopas/specdoc]
4
5
 
5
6
  == DESCRIPTION:
6
7
 
@@ -27,11 +28,27 @@ Search for a location by KKJ[http://fi.wikipedia.org/wiki/Kartastokoordinaattij%
27
28
  puts "#{location}, #{location.city}"
28
29
  Otakaari 9, Espoo
29
30
 
31
+ == INSTALLATION:
32
+
33
+ gem install reittiopas
34
+
35
+ or for the latest git:
36
+
37
+ git clone git://github.com/raneksi/reittiopas.git
38
+ cd reittiopas
39
+ rake newb
40
+ rake install_gem
41
+
30
42
  == REQUIREMENTS:
31
43
 
32
44
  * Nokogiri[http://nokogiri.org/]
33
45
  * Addressable[http://github.com/sporkmonger/addressable]
34
46
 
47
+ == TODO:
48
+
49
+ * Support for determining the closest stop within radius
50
+ * Routing
51
+
35
52
  == LICENSE:
36
53
 
37
54
  (The MIT License)
data/Rakefile CHANGED
@@ -2,33 +2,26 @@ require 'rubygems'
2
2
  gem 'hoe', '>= 2.1.0'
3
3
  require 'hoe'
4
4
  require 'fileutils'
5
- require './lib/reittiopas'
6
5
 
7
6
  Hoe.plugin :newgem
8
7
 
9
8
  $hoe = Hoe.spec 'reittiopas' do
10
9
  developer 'Raine Virta', 'raine.virta@gmail.com'
11
- self.rubyforge_name = self.name
10
+ self.rubyforge_name = self.name
12
11
 
13
12
  %w{ addressable nokogiri }.each do |dep|
14
- self.extra_dev_deps << [dep, '>= 0']
13
+ self.extra_deps << [dep, '>= 0']
15
14
  end
16
15
 
17
16
  self.url = "http://github.com/raneksi/reittiopas"
18
- self.extra_dev_deps = [['webmock', ">= 0"]]
17
+ self.extra_dev_deps = [
18
+ ['webmock', ">= 0.9.1"],
19
+ ['rspec', ">= 0"],
20
+ ['darkfish-rdoc', ">= 0"]
21
+ ]
19
22
  self.readme_file = "README.rdoc"
20
23
  self.extra_rdoc_files = FileList['*.rdoc']
21
24
  end
22
25
 
23
26
  require 'newgem/tasks'
24
27
  Dir['tasks/**/*.rake'].each { |t| load t }
25
-
26
- # remove_task :default
27
- # task :default => [:spec, :features]
28
-
29
- require 'gokdok'
30
- Gokdok::Dokker.new do |gd|
31
- gd.repo_url = "git@github.com:raneksi/reittiopas.git"
32
- gd.rdoc_task = :docs
33
- gd.doc_home = 'doc'
34
- end
data/lib/reittiopas.rb CHANGED
@@ -1,13 +1,13 @@
1
- $:.unshift(File.dirname(__FILE__)) unless
2
- $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
-
4
- require 'rubygems'
5
1
  require 'uri'
6
2
  require 'cgi'
7
3
  require 'net/http'
8
4
  require 'nokogiri'
9
5
  require 'addressable/uri'
10
6
 
7
+ $:.unshift(File.dirname(__FILE__)) unless
8
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
9
+
10
+ require 'reittiopas/exceptions'
11
11
  require 'reittiopas/utils'
12
12
  require 'reittiopas/coordinates'
13
13
  require 'reittiopas/location'
@@ -17,7 +17,7 @@ require 'reittiopas/http'
17
17
 
18
18
  class Reittiopas
19
19
  # The version of Reittiopas you are using.
20
- VERSION = "0.0.1"
20
+ VERSION = "0.0.2"
21
21
  end
22
22
 
23
23
  # Shorter way for Reittiopas instance creation.
@@ -0,0 +1,4 @@
1
+ class Reittiopas
2
+ class AccessError < ::StandardError
3
+ end
4
+ end
@@ -6,9 +6,11 @@ module Geocoding
6
6
 
7
7
  # Send a geocode location query to the API.
8
8
  # Both geocoding, and reverse geocoding data is accessed through this method.
9
- #
10
9
  # Returns results as an array containing Reittiopas::Location objects.
11
10
  #
11
+ # [opts] Either a keyword string, or a hash containing KKJ coordinates
12
+ # presented as rectangular grid coordinates.
13
+ #
12
14
  # === Examples:
13
15
  # * Search for location by keyword _tee_.
14
16
  # reittiopas.location('tee')
@@ -20,6 +22,7 @@ module Geocoding
20
22
  params = if opts.is_a? String
21
23
  {:key => opts}
22
24
  elsif opts.is_a? Hash
25
+ opts.assert_required_and_valid_keys :x, :y
23
26
  opts
24
27
  end
25
28
 
@@ -28,6 +31,8 @@ module Geocoding
28
31
 
29
32
  private
30
33
  # Parse XML received from a geocoding API query.
34
+ #
35
+ # [xml] Raw XML received from API.
31
36
  def parse(xml, opts)
32
37
  doc = Nokogiri::XML(xml)
33
38
 
@@ -18,7 +18,8 @@ class HTTP
18
18
 
19
19
  # Create a new Reittiopas::HTTP object.
20
20
  #
21
- # +account+ should be a hash containing +:username+ and +:password+.
21
+ # [account] A hash containing the keys +:username+ and +:password+ with
22
+ # their respective values.
22
23
  def initialize(account)
23
24
  @api_uri = Addressable::URI.parse(API_BASE_URI)
24
25
  @api_uri.query_values = {:user => account[:username], :pass => account[:password]}
@@ -27,14 +28,23 @@ class HTTP
27
28
  # Send a GET request to the API with account details and +opts+ as query
28
29
  # parameters.
29
30
  #
30
- # * +opts+ A hash containing query parameters. Values are automatically
31
- # encoded by Addressable::URI.
31
+ # [opts] A hash containing query parameters. Values are automatically
32
+ # encoded by Addressable::URI.
32
33
  def get(opts)
33
34
  raise ArgumentError if opts.empty?
34
35
  uri = @api_uri.dup
35
36
  opts.merge!(opts){ |k,ov| ov.to_s } # Coordinates to string
36
37
  uri.query_values = uri.query_values.merge(opts)
37
- return Net::HTTP.get(uri)
38
+
39
+ # TODO ugly workaround until addressable's author updates the game
40
+ body = Net::HTTP.get(URI.parse(uri.to_s))
41
+
42
+ # API responses with 200 OK in case of invalid account, so...
43
+ if body =~ /No rights to access API./
44
+ raise AccessError, 'Most likely due to invalid account details'
45
+ end
46
+
47
+ body
38
48
  end
39
49
  end
40
50
  end
@@ -3,13 +3,15 @@
3
3
  #
4
4
  class Reittiopas
5
5
  include Geocoding
6
-
6
+
7
7
  # Instantiate a Reittiopas object.
8
8
  #
9
- # +account+ should be a hash containing +:username+ and +:password+.
9
+ # [account] A hash containing the keys +:username+ and +:password+ with
10
+ # their respective values.
10
11
  #
11
12
  # Reittiopas.new(:username => 'exampleuser', :password => 'lolcat')
12
13
  def initialize(account)
14
+ account.assert_required_and_valid_keys :username, :password
13
15
  @http = Reittiopas::HTTP.new(account)
14
16
  end
15
17
  end
@@ -9,3 +9,34 @@ class Element
9
9
  end
10
10
  end
11
11
  end
12
+
13
+ class Hash
14
+ # Raise ArgumentError if the hash has keys other than +keys+.
15
+ def assert_valid_keys(*valid_keys)
16
+ unknown_keys = keys - [valid_keys].flatten
17
+ raise(ArgumentError, "Unknown key(s): #{unknown_keys.join(", ")}") unless unknown_keys.empty?
18
+ end
19
+
20
+ # Raise ArgumentError if the hash is missing required keys.
21
+ def assert_required_keys(*required_keys)
22
+ missing_keys = [required_keys].flatten - keys
23
+ raise(ArgumentError, "Missing required key(s) in the argument hash: #{missing_keys.join(", ")}") unless missing_keys.empty?
24
+ end
25
+
26
+ # Both assert_valid_keys and assert_required_keys combined.
27
+ #
28
+ # Expect certain keys and none else.
29
+ def assert_required_and_valid_keys(*keys)
30
+ assert_valid_keys(keys)
31
+ assert_required_keys(keys)
32
+ end
33
+
34
+ def assert_valid_values(hash)
35
+ self.each do |key, value|
36
+ next unless hash[key]
37
+ unless value.to_s =~ hash[key]
38
+ raise(ArgumentError, "Invalid value for #{key}: #{value.inspect}")
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,8 @@
1
+ HTTP/1.1 200 OK
2
+ Date: Wed, 07 Apr 2010 13:33:08 GMT
3
+ Server: Apache/2
4
+ X-Powered-By: PHP/5.2.6-1+lenny8
5
+ Content-Length: 27
6
+ Content-Type: text/html; charset=iso-8859-1
7
+
8
+ No rights to access API.<P>
@@ -15,6 +15,20 @@ end
15
15
  describe Reittiopas do
16
16
  before { @account = {:username => 'foo', :password => 'bar'} }
17
17
 
18
+ context "when initializing with missing arguments" do
19
+ it "should raise ArgumentError if password is missing" do
20
+ lambda do
21
+ Reittiopas.new(:username => 'foo')
22
+ end.should raise_error ArgumentError
23
+ end
24
+
25
+ it "should raise ArgumentError if username is missing" do
26
+ lambda do
27
+ Reittiopas.new(:password => 'foo')
28
+ end.should raise_error ArgumentError
29
+ end
30
+ end
31
+
18
32
  context "when initialized with an account" do
19
33
  subject { Reittiopas.new(@account) }
20
34
 
@@ -86,6 +100,17 @@ describe Reittiopas::HTTP do
86
100
  end
87
101
 
88
102
  describe "#get" do
103
+ context "when making a request with invalid account details" do
104
+ before do
105
+ no_access_response = File.open(File.dirname(__FILE__) + '/fixtures/no_access')
106
+ stub_request(:get, Regexp.new(BASE_URI)).to_return(no_access_response)
107
+ end
108
+
109
+ it "should raise AccessError" do
110
+ lambda { @http.get(:foo => 'bar') }.should raise_error(Reittiopas::AccessError)
111
+ end
112
+ end
113
+
89
114
  context "with empty hash as argument" do
90
115
  it { lambda { @http.get({}) }.should raise_error(ArgumentError) }
91
116
  end
@@ -240,6 +265,38 @@ describe Reittiopas::Location::Coordinates::WGS do
240
265
 
241
266
  it { should respond_to :latitude }
242
267
  it { should respond_to :longitude }
243
-
268
+
244
269
  it { subject.to_s.should eql '60.23245, 24.74568' }
245
270
  end
271
+
272
+ describe Hash do
273
+ describe "#assert_valid_keys" do
274
+ context "when invalid keys are found" do
275
+ it "should raise ArgumentError when invalid keys are found" do
276
+ lambda do
277
+ { :name => "Rob", :years => "28" }.assert_valid_keys :name, :age
278
+ end.should raise_error(ArgumentError, "Unknown key(s): years")
279
+ end
280
+ end
281
+ end
282
+
283
+ describe "#assert_required_keys" do
284
+ context "when required keys are missing" do
285
+ it "should raise ArgumentError" do
286
+ lambda do
287
+ { :name => "Rob", :years => "28" }.assert_required_keys :weight
288
+ end.should raise_error(ArgumentError, "Missing required key(s) in the argument hash: weight")
289
+ end
290
+ end
291
+ end
292
+
293
+ describe "#assert_required_and_valid_keys" do
294
+ context "when invalid keys are found and required keys are missing" do
295
+ it "should raise ArgumentError" do
296
+ lambda do
297
+ { :name => "Rob"}.assert_required_and_valid_keys :weight
298
+ end.should raise_error(ArgumentError)
299
+ end
300
+ end
301
+ end
302
+ end
data/spec/spec_helper.rb CHANGED
@@ -16,4 +16,4 @@ BASE_URI = "http://api.reittiopas.fi/public-ytv/fi/api/"
16
16
 
17
17
  def parse_elem(xml)
18
18
  Nokogiri::XML(xml).children[0]
19
- end
19
+ end
data/tasks/rdoc.rake ADDED
@@ -0,0 +1,8 @@
1
+ namespace :docs do
2
+ desc "Publish rdoc to Github pages"
3
+ task :publish => "docs" do
4
+ sh 'cp doc/README_rdoc.html doc/index.html'
5
+ sh 'cp -R doc/* .gh_pages/'
6
+ sh 'cd .gh_pages; git add .; git commit -m "Update docs"; git push origin gh-pages'
7
+ end
8
+ end
data/tasks/rspec.rake CHANGED
@@ -29,10 +29,22 @@ namespace :spec do
29
29
  '--exclude', 'spec'
30
30
  ]
31
31
  end
32
-
32
+
33
33
  desc "Browse the code coverage report."
34
34
  task :browse => "spec:rcov" do
35
35
  require "launchy"
36
36
  Launchy::Browser.run("coverage/index.html")
37
37
  end
38
- end
38
+
39
+ desc "Generate HTML Specdocs for all specs"
40
+ Spec::Rake::SpecTask.new(:specdoc) do |t|
41
+ specdoc_path = File.expand_path(File.join(File.dirname(__FILE__), '..', 'specdoc'))
42
+ Dir.mkdir(specdoc_path) if !File.exist?(specdoc_path)
43
+
44
+ output_file = File.join(specdoc_path, 'index.html')
45
+ t.libs = %w[lib spec]
46
+ t.spec_files = FileList['spec/**/*_spec.rb']
47
+ t.spec_opts = ["--format", "\"html:#{output_file}\"", "--diff"]
48
+ t.fail_on_error = false
49
+ end
50
+ end
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 0
8
- - 1
9
- version: 0.0.1
8
+ - 2
9
+ version: 0.0.2
10
10
  platform: ruby
11
11
  authors:
12
12
  - Raine Virta
@@ -14,11 +14,11 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-04-05 00:00:00 +03:00
17
+ date: 2010-04-22 00:00:00 +03:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
- name: webmock
21
+ name: addressable
22
22
  prerelease: false
23
23
  requirement: &id001 !ruby/object:Gem::Requirement
24
24
  requirements:
@@ -27,12 +27,62 @@ dependencies:
27
27
  segments:
28
28
  - 0
29
29
  version: "0"
30
- type: :development
30
+ type: :runtime
31
31
  version_requirements: *id001
32
32
  - !ruby/object:Gem::Dependency
33
- name: hoe
33
+ name: nokogiri
34
34
  prerelease: false
35
35
  requirement: &id002 !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ segments:
40
+ - 0
41
+ version: "0"
42
+ type: :runtime
43
+ version_requirements: *id002
44
+ - !ruby/object:Gem::Dependency
45
+ name: webmock
46
+ prerelease: false
47
+ requirement: &id003 !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ segments:
52
+ - 0
53
+ - 9
54
+ - 1
55
+ version: 0.9.1
56
+ type: :development
57
+ version_requirements: *id003
58
+ - !ruby/object:Gem::Dependency
59
+ name: rspec
60
+ prerelease: false
61
+ requirement: &id004 !ruby/object:Gem::Requirement
62
+ requirements:
63
+ - - ">="
64
+ - !ruby/object:Gem::Version
65
+ segments:
66
+ - 0
67
+ version: "0"
68
+ type: :development
69
+ version_requirements: *id004
70
+ - !ruby/object:Gem::Dependency
71
+ name: darkfish-rdoc
72
+ prerelease: false
73
+ requirement: &id005 !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ segments:
78
+ - 0
79
+ version: "0"
80
+ type: :development
81
+ version_requirements: *id005
82
+ - !ruby/object:Gem::Dependency
83
+ name: hoe
84
+ prerelease: false
85
+ requirement: &id006 !ruby/object:Gem::Requirement
36
86
  requirements:
37
87
  - - ">="
38
88
  - !ruby/object:Gem::Version
@@ -42,7 +92,7 @@ dependencies:
42
92
  - 0
43
93
  version: 2.6.0
44
94
  type: :development
45
- version_requirements: *id002
95
+ version_requirements: *id006
46
96
  description: |-
47
97
  Reittiopas is a Ruby library for accessing the {Reittiopas Developer API}[http://developer.reittiopas.fi/pages/fi/reittiopas-api.php].
48
98
 
@@ -62,9 +112,9 @@ files:
62
112
  - Manifest.txt
63
113
  - README.rdoc
64
114
  - Rakefile
65
- - deps.rip
66
115
  - lib/reittiopas.rb
67
116
  - lib/reittiopas/coordinates.rb
117
+ - lib/reittiopas/exceptions.rb
68
118
  - lib/reittiopas/geocoding.rb
69
119
  - lib/reittiopas/http.rb
70
120
  - lib/reittiopas/location.rb
@@ -74,10 +124,12 @@ files:
74
124
  - script/destroy
75
125
  - script/generate
76
126
  - spec/fixtures/key.xml
127
+ - spec/fixtures/no_access
77
128
  - spec/fixtures/reverse_geocoding.xml
78
129
  - spec/reittiopas_spec.rb
79
130
  - spec/spec.opts
80
131
  - spec/spec_helper.rb
132
+ - tasks/rdoc.rake
81
133
  - tasks/rspec.rake
82
134
  has_rdoc: true
83
135
  homepage: http://github.com/raneksi/reittiopas
data/deps.rip DELETED
@@ -1 +0,0 @@
1
- http://github.com/sporkmonger/addressable.git