swissmatch-directories 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE.txt +8 -0
- data/README.markdown +58 -0
- data/Rakefile +10 -0
- data/lib/swissmatch/directories.rb +66 -0
- data/lib/swissmatch/directories/address.rb +41 -0
- data/lib/swissmatch/directories/service.rb +52 -0
- data/lib/swissmatch/directories/telsearch.rb +105 -0
- data/lib/swissmatch/directories/version.rb +15 -0
- data/swissmatch-directories.gemspec +41 -0
- metadata +70 -0
data/LICENSE.txt
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
Copyright (c) 2012, Stefan Rusterholz <stefan.rusterholz@gmail.com>
|
2
|
+
All rights reserved.
|
3
|
+
|
4
|
+
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
5
|
+
|
6
|
+
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
7
|
+
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
8
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
data/README.markdown
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
README
|
2
|
+
======
|
3
|
+
|
4
|
+
|
5
|
+
Summary
|
6
|
+
-------
|
7
|
+
Query address data from swiss directory providers.
|
8
|
+
|
9
|
+
|
10
|
+
Installation
|
11
|
+
------------
|
12
|
+
Install the gem: `gem install swissmatch-directories`
|
13
|
+
Depending on how you installed rubygems, you have to use `sudo`:
|
14
|
+
`sudo gem install swissmatch-directories`
|
15
|
+
In Ruby: `require 'swissmatch/directories'`
|
16
|
+
|
17
|
+
|
18
|
+
Usage
|
19
|
+
-----
|
20
|
+
require 'swissmatch/directories'
|
21
|
+
directories = SwissMatch::Directories.create(:telsearch, api_token: your_token)
|
22
|
+
params = {first_name: 'Stefan', last_name: 'Rusterholz'}
|
23
|
+
directories.addresses(params).each do |address|
|
24
|
+
puts address,""
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
Relevant Classes and Modules
|
29
|
+
----------------------------
|
30
|
+
* __{SwissMatch::Directories}__
|
31
|
+
Convenience methods to create and access directory services
|
32
|
+
* __{SwissMatch::Directories::Service}__
|
33
|
+
The basic API to use directory services
|
34
|
+
|
35
|
+
|
36
|
+
Links
|
37
|
+
-----
|
38
|
+
|
39
|
+
* [Main Project](https://github.com/apeiros/swissmatch)
|
40
|
+
* [Online API Documentation](http://rdoc.info/github/apeiros/swissmatch-directories/)
|
41
|
+
* [Public Repository](https://github.com/apeiros/swissmatch-directories)
|
42
|
+
* [Bug Reporting](https://github.com/apeiros/swissmatch-directories/issues)
|
43
|
+
* [RubyGems Site](https://rubygems.org/gems/swissmatch-directories)
|
44
|
+
* [Swiss Posts MAT[CH]](http://www.post.ch/match)
|
45
|
+
|
46
|
+
|
47
|
+
License
|
48
|
+
-------
|
49
|
+
|
50
|
+
You can use this code under the {file:LICENSE.txt BSD-2-Clause License}, free of charge.
|
51
|
+
If you need a different license, please ask the author.
|
52
|
+
|
53
|
+
|
54
|
+
Credits
|
55
|
+
-------
|
56
|
+
|
57
|
+
* [Simon Hürlimann](https://github.com/huerlisi) for contributions
|
58
|
+
* [AWD Switzerland](http://www.awd.ch/) for donating time to work on this gem.
|
data/Rakefile
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.expand_path('../rake/lib', __FILE__))
|
2
|
+
Dir.glob(File.expand_path('../rake/tasks/**/*.{rake,task,rb}', __FILE__)) do |task_file|
|
3
|
+
begin
|
4
|
+
import task_file
|
5
|
+
rescue LoadError => e
|
6
|
+
warn "Failed to load task file #{task_file}"
|
7
|
+
warn " #{e.class} #{e.message}"
|
8
|
+
warn " #{e.backtrace.first}"
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
|
4
|
+
|
5
|
+
require 'swissmatch/directories/service'
|
6
|
+
require 'swissmatch/directories/version'
|
7
|
+
|
8
|
+
|
9
|
+
|
10
|
+
# __{SwissMatch::Directories}__
|
11
|
+
# Query address data from swiss online directory providers.
|
12
|
+
#
|
13
|
+
# @note
|
14
|
+
# All strings passed to SwissMatch are expected to be utf-8. All strings
|
15
|
+
# returned by SwissMatch are also in utf-8.
|
16
|
+
#
|
17
|
+
module SwissMatch
|
18
|
+
|
19
|
+
# Query address data from swiss online directory providers.
|
20
|
+
#
|
21
|
+
# @example Usage
|
22
|
+
# require 'swissmatch/directories'
|
23
|
+
# directories = SwissMatch::Directories.create(:telsearch, api_token: your_token)
|
24
|
+
# params = {first_name: 'Stefan', last_name: 'Rusterholz'}
|
25
|
+
# directories.addresses(params).each do |address|
|
26
|
+
# puts address,""
|
27
|
+
# end
|
28
|
+
module Directories
|
29
|
+
@services = Hash.new { |hash, key|
|
30
|
+
if key.respond_to?(:from_configuration)
|
31
|
+
key
|
32
|
+
else
|
33
|
+
raise ArgumentError, "Unknown service: #{key.inspect}"
|
34
|
+
end
|
35
|
+
}.merge(
|
36
|
+
telsearch: SwissMatch::Directories::TelSearch
|
37
|
+
)
|
38
|
+
|
39
|
+
class <<self
|
40
|
+
|
41
|
+
# @return [Hash] The available back-ends.
|
42
|
+
attr_reader :services
|
43
|
+
end
|
44
|
+
|
45
|
+
# @return [Class] A SwissMatch::Directories::Service compatible service class.
|
46
|
+
def self.service(name)
|
47
|
+
services[name]
|
48
|
+
end
|
49
|
+
|
50
|
+
# @return [SwissMatch::Directories::Service] A directory service
|
51
|
+
def self.create(name, options)
|
52
|
+
Service.new(name, options)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
@directory_service = nil
|
57
|
+
|
58
|
+
class <<self
|
59
|
+
|
60
|
+
# @return [SwissMatch::Directories::Service, nil]
|
61
|
+
# The directory service used to search for addresses
|
62
|
+
# You have to set this one yourself. It exists to provide a standard way to
|
63
|
+
#
|
64
|
+
attr_accessor :directory_service
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
|
4
|
+
|
5
|
+
module SwissMatch
|
6
|
+
module Directories
|
7
|
+
|
8
|
+
# Represents a swiss address. Used by directory service interfaces to return search
|
9
|
+
# results.
|
10
|
+
Address = Struct.new(:gender, :first_name, :last_name, :maiden_name, :street_name, :street_number, :zip_code, :city) do
|
11
|
+
|
12
|
+
# @return [String]
|
13
|
+
# The street and street number
|
14
|
+
def street
|
15
|
+
[street_name, street_number].compact.join(" ")
|
16
|
+
end
|
17
|
+
|
18
|
+
# @return [String]
|
19
|
+
# The full name, consisting of first_name and family_name.
|
20
|
+
def full_name
|
21
|
+
"#{first_name} #{family_name}"
|
22
|
+
end
|
23
|
+
|
24
|
+
# @return [String]
|
25
|
+
# The full family name, including the maiden name.
|
26
|
+
#
|
27
|
+
# @note
|
28
|
+
# I (stefan.rusterholz@gmail.com) am not sure whether "last_name (-maiden_name)"
|
29
|
+
# is the proper form. The output might be changed in a future version
|
30
|
+
# The current output is based on how tel.search.ch displays the name.
|
31
|
+
def family_name
|
32
|
+
maiden_name ? "#{last_name} (-#{maiden_name})" : last_name
|
33
|
+
end
|
34
|
+
|
35
|
+
# @return [String] A halfway readable textual representation
|
36
|
+
def to_s
|
37
|
+
"#{full_name}\n#{street}\n#{zip_code} #{city}"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
|
4
|
+
|
5
|
+
require 'swissmatch/directories/address'
|
6
|
+
require 'swissmatch/directories/telsearch'
|
7
|
+
|
8
|
+
|
9
|
+
|
10
|
+
module SwissMatch
|
11
|
+
module Directories
|
12
|
+
|
13
|
+
# Common directory service API.
|
14
|
+
#
|
15
|
+
# @see SwissMatch::Directories Usage examples
|
16
|
+
class Service
|
17
|
+
|
18
|
+
# @param [Class, Symbol, #from_configuration] back_end
|
19
|
+
# A valid back-end. Valid in vanilla swissmatch-directories:
|
20
|
+
# * :telsearch
|
21
|
+
# * SwissMatch::Directories::TelSearch (same as :telsearch)
|
22
|
+
# @param [Object] config
|
23
|
+
# A back-end specific configuration object.
|
24
|
+
def initialize(back_end, config=nil)
|
25
|
+
@service = SwissMatch::Directories.service(back_end).from_config(config)
|
26
|
+
end
|
27
|
+
|
28
|
+
# Query for addresses matching a set of given search parameters
|
29
|
+
#
|
30
|
+
# Note that not all back-ends will treat these parameters with the same strictness.
|
31
|
+
# The tel.search.ch back-end for example will search for a last name anywhere in the name.
|
32
|
+
#
|
33
|
+
# @param [Hash] params
|
34
|
+
# The abstract API search parameters.
|
35
|
+
# Valid parameters:
|
36
|
+
# * :first_name
|
37
|
+
# * :family_name
|
38
|
+
# * :last_name
|
39
|
+
# * :maiden_name
|
40
|
+
# * :name
|
41
|
+
# * :phone
|
42
|
+
# * :street
|
43
|
+
# * :street_name
|
44
|
+
# * :street_number
|
45
|
+
# * :zip_code
|
46
|
+
# * :city
|
47
|
+
def addresses(params, options={})
|
48
|
+
@service.addresses(params, options)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
|
4
|
+
|
5
|
+
require 'swissmatch/directories/service'
|
6
|
+
require 'uri'
|
7
|
+
require 'open-uri'
|
8
|
+
require 'nokogiri'
|
9
|
+
|
10
|
+
|
11
|
+
|
12
|
+
module SwissMatch
|
13
|
+
module Directories
|
14
|
+
|
15
|
+
# A Directory service, using tel.search.ch's API.
|
16
|
+
# Also see http://tel.search.ch/api/help
|
17
|
+
#
|
18
|
+
# You need an API key in order to use this library. You can get one on
|
19
|
+
# http://admin.tel.search.ch/api/getkey
|
20
|
+
#
|
21
|
+
# @see SwissMatch::Directories Usage examples
|
22
|
+
class TelSearch
|
23
|
+
|
24
|
+
# Create a TelSearch instance from the common interface.
|
25
|
+
# TelSearch requires the :api_token option to be set.
|
26
|
+
def self.from_config(config)
|
27
|
+
new(config.fetch(:api_token))
|
28
|
+
end
|
29
|
+
|
30
|
+
# @private
|
31
|
+
# XML Namespaces, used to parse the data returned by tel.search.ch
|
32
|
+
NS = {'t' => 'http://tel.search.ch/api/spec/result/1.0/'}
|
33
|
+
|
34
|
+
# @private
|
35
|
+
# The url of the API of tel.search.ch
|
36
|
+
API_URI = URI.parse('http://tel.search.ch/api')
|
37
|
+
|
38
|
+
# @param [String] key
|
39
|
+
# The API key for the telsearch service.
|
40
|
+
# You can get one on http://admin.tel.search.ch/api/getkey
|
41
|
+
def initialize(key)
|
42
|
+
@key = key
|
43
|
+
@uri = API_URI
|
44
|
+
end
|
45
|
+
|
46
|
+
# @private
|
47
|
+
# Convert the abstracted APIs options to tel.search.ch's search params
|
48
|
+
#
|
49
|
+
# @param [Hash] params
|
50
|
+
# The abstract API search parameters
|
51
|
+
def search_ch_mapping(params)
|
52
|
+
{
|
53
|
+
:was => params.values_at(:first_name, :family_name, :last_name, :maiden_name, :phone).compact.join(' '),
|
54
|
+
:wo => params.values_at(:street, :street_name, :street_number, :zip_code, :city).compact.join(' '),
|
55
|
+
}.reject { |k,v| v.empty? }
|
56
|
+
end
|
57
|
+
|
58
|
+
# @see SwissMatch::Directories#addresses
|
59
|
+
def addresses(params, options = {})
|
60
|
+
return [] if params.empty? # short-cut
|
61
|
+
|
62
|
+
# tel.search.ch parameters
|
63
|
+
search_params = {'key' => @key}
|
64
|
+
|
65
|
+
# Handle pagination parameters
|
66
|
+
per_page = options[:per_page] || 10
|
67
|
+
search_params['maxnum'] = per_page
|
68
|
+
|
69
|
+
page = options[:page] || 1
|
70
|
+
pos = (page - 1) * per_page + 1
|
71
|
+
search_params['pos'] = pos
|
72
|
+
|
73
|
+
# Request
|
74
|
+
uri = @uri.dup
|
75
|
+
uri.query = URI.encode_www_form(search_ch_mapping(params).merge(search_params))
|
76
|
+
feed = Nokogiri.XML(open(uri, &:read))
|
77
|
+
|
78
|
+
# Parse result
|
79
|
+
feed.css('entry').map { |entry|
|
80
|
+
Address.new(
|
81
|
+
nil,
|
82
|
+
extract(entry, 't|firstname'),
|
83
|
+
extract(entry, 't|name'),
|
84
|
+
extract(entry, 't|maidenname'),
|
85
|
+
extract(entry, 't|street'),
|
86
|
+
extract(entry, 't|streetno'),
|
87
|
+
extract(entry, 't|zip', &:to_i),
|
88
|
+
extract(entry, 't|city'),
|
89
|
+
)
|
90
|
+
}
|
91
|
+
end
|
92
|
+
|
93
|
+
private
|
94
|
+
|
95
|
+
# @private
|
96
|
+
# Get the text from a node with the given selector
|
97
|
+
def extract(node, selector)
|
98
|
+
subnode = node.at_css(selector, NS)
|
99
|
+
text = subnode && subnode.text
|
100
|
+
|
101
|
+
block_given? ? yield(text) : text
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'rubygems/version' # newer rubygems use this
|
5
|
+
rescue LoadError
|
6
|
+
require 'gem/version' # older rubygems use this
|
7
|
+
end
|
8
|
+
|
9
|
+
module SwissMatch
|
10
|
+
module Directories
|
11
|
+
|
12
|
+
# The version of the swissmatch-directories gem.
|
13
|
+
Version = Gem::Version.new("0.0.1")
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = "swissmatch-directories"
|
5
|
+
s.version = "0.0.1"
|
6
|
+
s.authors = "Stefan Rusterholz"
|
7
|
+
s.email = "stefan.rusterholz@gmail.com"
|
8
|
+
s.homepage = "http://github.com/apeiros/swissmatch-directories"
|
9
|
+
|
10
|
+
s.description = <<-DESCRIPTION.gsub(/^ /, '').chomp
|
11
|
+
Query address data from swiss directory providers.
|
12
|
+
DESCRIPTION
|
13
|
+
|
14
|
+
s.summary = <<-SUMMARY.gsub(/^ /, '').chomp
|
15
|
+
Query address data from swiss directory providers.
|
16
|
+
SUMMARY
|
17
|
+
|
18
|
+
s.files =
|
19
|
+
Dir['bin/**/*'] +
|
20
|
+
Dir['data/**/*'] +
|
21
|
+
Dir['lib/**/*'] +
|
22
|
+
Dir['rake/**/*'] +
|
23
|
+
Dir['test/**/*'] +
|
24
|
+
Dir['*.gemspec'] +
|
25
|
+
%w[
|
26
|
+
LICENSE.txt
|
27
|
+
Rakefile
|
28
|
+
README.markdown
|
29
|
+
]
|
30
|
+
|
31
|
+
if File.directory?('bin') then
|
32
|
+
executables = Dir.chdir('bin') { Dir.glob('**/*').select { |f| File.executable?(f) } }
|
33
|
+
s.executables = executables unless executables.empty?
|
34
|
+
end
|
35
|
+
|
36
|
+
s.add_dependency "nokogiri", ">= 1.5.0"
|
37
|
+
|
38
|
+
s.required_rubygems_version = Gem::Requirement.new("> 1.3.1")
|
39
|
+
s.rubygems_version = "1.3.1"
|
40
|
+
s.specification_version = 3
|
41
|
+
end
|
metadata
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: swissmatch-directories
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Stefan Rusterholz
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-08-08 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: nokogiri
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 1.5.0
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 1.5.0
|
30
|
+
description: Query address data from swiss directory providers.
|
31
|
+
email: stefan.rusterholz@gmail.com
|
32
|
+
executables: []
|
33
|
+
extensions: []
|
34
|
+
extra_rdoc_files: []
|
35
|
+
files:
|
36
|
+
- lib/swissmatch/directories/address.rb
|
37
|
+
- lib/swissmatch/directories/service.rb
|
38
|
+
- lib/swissmatch/directories/telsearch.rb
|
39
|
+
- lib/swissmatch/directories/version.rb
|
40
|
+
- lib/swissmatch/directories.rb
|
41
|
+
- swissmatch-directories.gemspec
|
42
|
+
- LICENSE.txt
|
43
|
+
- Rakefile
|
44
|
+
- README.markdown
|
45
|
+
homepage: http://github.com/apeiros/swissmatch-directories
|
46
|
+
licenses: []
|
47
|
+
post_install_message:
|
48
|
+
rdoc_options: []
|
49
|
+
require_paths:
|
50
|
+
- lib
|
51
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
52
|
+
none: false
|
53
|
+
requirements:
|
54
|
+
- - ! '>='
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: '0'
|
57
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
58
|
+
none: false
|
59
|
+
requirements:
|
60
|
+
- - ! '>'
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: 1.3.1
|
63
|
+
requirements: []
|
64
|
+
rubyforge_project:
|
65
|
+
rubygems_version: 1.8.24
|
66
|
+
signing_key:
|
67
|
+
specification_version: 3
|
68
|
+
summary: Query address data from swiss directory providers.
|
69
|
+
test_files: []
|
70
|
+
has_rdoc:
|