firmenwissen 1.0.0

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 479f8a1bea375d5c4af1c8980981c1fc2f0d4d0bfe7c8b7ac60cf17821b76672
4
+ data.tar.gz: e4aa6079c3be8d66819ff0d49e8f7c8fef9261c61f4b5353174c4227788593c2
5
+ SHA512:
6
+ metadata.gz: c877c1e82ffde13a74f956d72d94d5b7eb7106e27dabb66e377c40d7983076706a34276be83bb0c325d7fa3dde0b735f5164b62a86666c380e31d20851fb2acb
7
+ data.tar.gz: '095e5255d2bb6c45cea6151bd5acafeba67fc07fa074db666c56e06c0c7c9748690bded252489748ed23c0f913c038af9e3e6be7a4258e02712735c96f2cbc5e'
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2017 Gerrit Seger
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ 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.
data/README.md ADDED
@@ -0,0 +1,97 @@
1
+ # Firmenwissen
2
+ A ruby gem to conveniently access the [Firmenwissen](www.firmenwissen.de) Smart Sign-Up API.
3
+
4
+ ## Installation
5
+ Add this line to your application's Gemfile:
6
+
7
+ ```ruby
8
+ gem 'firmenwissen'
9
+ ```
10
+
11
+ And then execute:
12
+ ```bash
13
+ $ bundle
14
+ ```
15
+
16
+ Or install it yourself as:
17
+ ```bash
18
+ $ gem install firmenwissen
19
+ ```
20
+
21
+ ## Usage
22
+ ### Searching
23
+ ```ruby
24
+ response = Firmenwissen.search('company xyz')
25
+
26
+ if response.successful?
27
+ suggestions = response.suggestions
28
+ ...
29
+ end
30
+ ```
31
+
32
+ will give you an array of suggestions from Firmenwissen, if any, for the specified query string.
33
+
34
+ ```ruby
35
+ suggestion = suggestions.first
36
+
37
+ suggestion.crefo_id # => '1234567890'
38
+ suggestion.name # => 'COMPEON GmbH'
39
+ suggestion.trade_name # => 'Compeon'
40
+ suggestion.country # => 'DE'
41
+ suggestion.state # => 'Nordrhein-Westfalen'
42
+ suggestion.zip_code # => '40211'
43
+ suggestion.city # => 'Düsseldorf'
44
+ suggestion.address # => 'Louise-Dumon-Straße 5'
45
+
46
+ suggestion.to_h # => { crefo_id: '1234567890', name: 'COMPEON GmbH', ... }
47
+ ```
48
+ ### Configuration
49
+ ```ruby
50
+ Firmenwissen.configure do |config|
51
+ config.user = 'username' # Username for Firmenwissen basic auth (required)
52
+ config.password = 'password' # Password for Firmenwissen basic auth (required)
53
+ config.timeout = 5 # Request timeout in seconds
54
+
55
+ # Configure the endpoint yourself. %s will be replaced by the actual query
56
+ config.endpoint = 'https://example.com/search?query=%s'
57
+ end
58
+ ```
59
+ ### Mocking results
60
+ In a non production-like environment you will not want to perform real requests to the API. Thus you can configure the gem to respond with mocked data.
61
+
62
+ ```ruby
63
+ Firmenwissen.configure do |config|
64
+ config.mock_requests = true
65
+
66
+ # respond with a fixed array
67
+ config.mock_data = [{ crefo_id: '1111111111', name: 'Test GmbH', ... }, { ... }, ...]
68
+
69
+ # respond when a query matches an exact keyword
70
+ # this will return a result mock when you search for 'compeon' or 'test', otherwise an empty result
71
+ mock_data = {
72
+ 'compeon' => [{ crefo_id: '1234567890', name: 'COMPEON GmbH', ... }],
73
+ 'test' => [{ crefo_id: '1111111111', ... }]
74
+ }
75
+
76
+ config.mock_data = mock_data
77
+
78
+ # generate your own dynamic response
79
+ config.mock_data = Proc.new do |query|
80
+ # your code for mock data generation here
81
+ end
82
+
83
+ # or
84
+
85
+ class DynamicMockData
86
+ def call(query)
87
+ # your code for mock data generation here
88
+ end
89
+ end
90
+
91
+ config.mock_data = DynamicMockData.new
92
+ end
93
+ ```
94
+ **Note:** All configuration options can be overridden on a per-request basis by passing an options hash to the `search` method.
95
+
96
+ ## License
97
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task default: :spec
@@ -0,0 +1,30 @@
1
+ require 'json'
2
+ require 'net/http'
3
+ require 'addressable/template'
4
+
5
+ require 'firmenwissen/configuration'
6
+ require 'firmenwissen/http_request'
7
+ require 'firmenwissen/key_mapper'
8
+ require 'firmenwissen/request'
9
+ require 'firmenwissen/suggestion'
10
+ require 'firmenwissen/version'
11
+
12
+ require 'firmenwissen/errors/credentials_error'
13
+
14
+ require 'firmenwissen/request/base'
15
+ require 'firmenwissen/request/mock'
16
+
17
+ require 'firmenwissen/response/base'
18
+ require 'firmenwissen/response/mock'
19
+
20
+ module Firmenwissen
21
+ extend Configuration::Accessors
22
+
23
+ class << self
24
+ def search(query, options = {})
25
+ strategy = configuration.mock_requests? ? :mock : :base
26
+
27
+ Request.from_strategy(strategy, query, options).execute
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,50 @@
1
+ module Firmenwissen
2
+ class Configuration
3
+ module Accessors
4
+ def configuration
5
+ @config ||= Configuration.new
6
+ end
7
+
8
+ def configure
9
+ yield configuration
10
+ end
11
+ end
12
+
13
+ SETTINGS = %i[endpoint password mock_data mock_requests timeout user]
14
+
15
+ DEFAULT_SETTINGS = {
16
+ endpoint: 'https://www.firmenwissen.de/search/suggest/companywithaddress/{query}{?country}',
17
+ mock_requests: false,
18
+ mock_data: [],
19
+ timeout: 5
20
+ }.freeze
21
+
22
+ SETTINGS.each do |setting|
23
+ define_method(setting) do
24
+ settings[setting]
25
+ end
26
+
27
+ define_method("#{setting}=") do |value|
28
+ settings[setting] = value
29
+ end
30
+ end
31
+
32
+ attr_reader :settings
33
+
34
+ def initialize(options = {})
35
+ @settings = DEFAULT_SETTINGS.dup.merge(options)
36
+ end
37
+
38
+ def merge(options)
39
+ Configuration.new(settings.merge(options))
40
+ end
41
+
42
+ def credentials_present?
43
+ [user, password].all? { |setting| setting.is_a?(String) && !setting.empty? }
44
+ end
45
+
46
+ def mock_requests?
47
+ mock_requests
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,7 @@
1
+ module Firmenwissen
2
+ class CredentialsError < StandardError
3
+ def initialize(message = 'Firmenwissen credentials are missing')
4
+ super
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,33 @@
1
+ module Firmenwissen
2
+ class HttpRequest
3
+ def initialize(uri, options = {})
4
+ @uri = uri
5
+ @options = options
6
+ end
7
+
8
+ def execute
9
+ http = Net::HTTP.start(uri.host)
10
+ http.read_timeout = config.timeout
11
+ http.request(request)
12
+ ensure
13
+ http.finish
14
+ http
15
+ end
16
+
17
+ protected
18
+
19
+ attr_reader :uri, :options, :params
20
+
21
+ def request
22
+ @request ||= begin
23
+ Net::HTTP::Get.new(uri).tap do |req|
24
+ req.basic_auth(config.user, config.password)
25
+ end
26
+ end
27
+ end
28
+
29
+ def config
30
+ @config ||= Firmenwissen.configuration.merge(options)
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,38 @@
1
+ module Firmenwissen
2
+ module KeyMapper
3
+ KEY_MAPPINGS = {
4
+ crefo_id: 'crefonummer',
5
+ name: 'name',
6
+ trade_name: 'handelsName',
7
+ country: 'land',
8
+ state: 'bundesland',
9
+ zip_code: 'plz',
10
+ city: 'ort',
11
+ address: 'strasseHausnummer'
12
+ }.freeze
13
+
14
+ class << self
15
+ def from_api(hash)
16
+ map(hash, :from_api)
17
+ end
18
+
19
+ def to_api(hash)
20
+ map(hash, :to_api)
21
+ end
22
+
23
+ private
24
+
25
+ def map(hash, direction)
26
+ {}.tap do |result|
27
+ mapping_for(direction).each do |key, value|
28
+ result[key] = hash[value]
29
+ end
30
+ end
31
+ end
32
+
33
+ def mapping_for(direction)
34
+ direction == :from_api ? KEY_MAPPINGS : KEY_MAPPINGS.invert
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,11 @@
1
+ module Firmenwissen
2
+ module Request
3
+ class << self
4
+ def from_strategy(strategy, query, options = {})
5
+ strategy_name = strategy.to_s.capitalize
6
+
7
+ self.const_get(strategy_name).new(query, options)
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,34 @@
1
+ module Firmenwissen
2
+ module Request
3
+ class Base
4
+ def initialize(query, options = {})
5
+ @query = query
6
+ @options = options
7
+ @params = options.fetch(:params, {})
8
+
9
+ raise CredentialsError unless config.credentials_present?
10
+ end
11
+
12
+ def execute
13
+ Response::Base.new(http_request.execute)
14
+ end
15
+
16
+ protected
17
+
18
+ attr_reader :options, :query, :params
19
+
20
+ def http_request
21
+ HttpRequest.new(uri, options)
22
+ end
23
+
24
+ def uri
25
+ template = Addressable::Template.new(config.endpoint)
26
+ template.expand(query: query, **params)
27
+ end
28
+
29
+ def config
30
+ @config ||= Firmenwissen.configuration.merge(options)
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,9 @@
1
+ module Firmenwissen
2
+ module Request
3
+ class Mock < Base
4
+ def execute
5
+ Response::Mock.new(config.mock_data, query, params)
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,37 @@
1
+ module Firmenwissen
2
+ module Response
3
+ class Base
4
+ def initialize(http_response)
5
+ @http_response = http_response
6
+ end
7
+
8
+ def suggestions
9
+ @suggestions ||= data.map { |suggestion| Suggestion.new(suggestion) }
10
+ end
11
+
12
+ def data
13
+ api_response = JSON.parse(http_response.body).fetch('companyNameSuggestions', [])
14
+
15
+ map_response(api_response)
16
+ end
17
+
18
+ def status_code
19
+ http_response.code
20
+ end
21
+
22
+ def successful?
23
+ status_code == '200'
24
+ end
25
+
26
+ private
27
+
28
+ attr_reader :http_response
29
+
30
+ def map_response(api_response)
31
+ api_response.map do |hash|
32
+ KeyMapper.from_api(hash)
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,38 @@
1
+ module Firmenwissen
2
+ module Response
3
+ class Mock < Base
4
+ def initialize(mock_data, query, params = {})
5
+ @mock_data = mock_data
6
+ @query = query
7
+ @params = params
8
+
9
+ raise ArgumentError, 'mock data must either be an array, a hash or respond to `call`' unless mock_data_valid?
10
+ end
11
+
12
+ def data
13
+ return mock_data.call(query, params) if mock_data.respond_to?(:call)
14
+
15
+ case mock_data
16
+ when Array
17
+ mock_data
18
+ when Hash
19
+ mock_data[query] || []
20
+ else
21
+ []
22
+ end
23
+ end
24
+
25
+ def status_code
26
+ '200'
27
+ end
28
+
29
+ private
30
+
31
+ attr_reader :mock_data, :query, :params
32
+
33
+ def mock_data_valid?
34
+ mock_data.respond_to?(:call) || mock_data.is_a?(Array) || mock_data.is_a?(Hash)
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,21 @@
1
+ module Firmenwissen
2
+ class Suggestion
3
+ KeyMapper::KEY_MAPPINGS.keys.each do |key|
4
+ define_method(key) do
5
+ suggestion[key]
6
+ end
7
+ end
8
+
9
+ def initialize(suggestion)
10
+ @suggestion = suggestion
11
+ end
12
+
13
+ def to_h
14
+ suggestion.dup
15
+ end
16
+
17
+ private
18
+
19
+ attr_reader :suggestion
20
+ end
21
+ end
@@ -0,0 +1,3 @@
1
+ module Firmenwissen
2
+ VERSION = '1.0.0'
3
+ end
metadata ADDED
@@ -0,0 +1,129 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: firmenwissen
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Gerrit Seger
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-11-30 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: addressable
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: pry
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: vcr
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: webmock
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ description:
84
+ email:
85
+ - gerrit.seger@gmail.com
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - MIT-LICENSE
91
+ - README.md
92
+ - Rakefile
93
+ - lib/firmenwissen.rb
94
+ - lib/firmenwissen/configuration.rb
95
+ - lib/firmenwissen/errors/credentials_error.rb
96
+ - lib/firmenwissen/http_request.rb
97
+ - lib/firmenwissen/key_mapper.rb
98
+ - lib/firmenwissen/request.rb
99
+ - lib/firmenwissen/request/base.rb
100
+ - lib/firmenwissen/request/mock.rb
101
+ - lib/firmenwissen/response/base.rb
102
+ - lib/firmenwissen/response/mock.rb
103
+ - lib/firmenwissen/suggestion.rb
104
+ - lib/firmenwissen/version.rb
105
+ homepage:
106
+ licenses:
107
+ - MIT
108
+ metadata: {}
109
+ post_install_message:
110
+ rdoc_options: []
111
+ require_paths:
112
+ - lib
113
+ required_ruby_version: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ required_rubygems_version: !ruby/object:Gem::Requirement
119
+ requirements:
120
+ - - ">="
121
+ - !ruby/object:Gem::Version
122
+ version: '0'
123
+ requirements: []
124
+ rubyforge_project:
125
+ rubygems_version: 2.7.3
126
+ signing_key:
127
+ specification_version: 4
128
+ summary: Ruby client for the FirmenWissen API
129
+ test_files: []