Last active
January 4, 2016 14:29
-
-
Save maksar/8634372 to your computer and use it in GitHub Desktop.
identification service
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class IdentificationStrategy | |
def initialize origin, priorities | |
@origin = origin | |
@priorities = [priorities].flatten | |
end | |
def branch candidates | |
case candidates.length | |
when 0 | |
zero | |
when 1 | |
return candidates.first | |
when 2...Float::INFINITY | |
many candidates | |
end | |
end | |
def search company | |
database_results = query(:PAYINDEX, extract_attributes(company).collect(&extract_from(company))) | |
candidates = database_results.select(&confidently_identified(company)) | |
branch candidates | |
end | |
def extract_attributes company | |
@origin.attributes.select(&by_priority_from(company)) | |
end | |
def classify weight | |
case weight | |
when [email protected]_threshold | |
NegativeIdentification | |
when @[email protected]_threshold | |
SuspiciousIdentification | |
when @origin.identification_threshold...Float::INFINITY | |
ConfidentIdentification | |
end | |
end | |
private | |
def extract_from company | |
->(attribute) { | |
[attribute.name, company.send(attribute.name)] | |
} | |
end | |
def matching candidate, company | |
->(attribute) { | |
company.send(attribute.name) == candidate.send(attribute.name) | |
} | |
end | |
def by_priority_from candidate | |
->(attribute) { | |
@priorities.include?(attribute.priority) && candidate.send(attribute.name) | |
} | |
end | |
def confidently_identified company | |
-> (candidate) { | |
equal_attributes = extract_attributes(candidate).select(&matching(candidate, company)) | |
ConfidentIdentification == classify(equal_attributes.sum(&:weight)) | |
} | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require_relative '../spec_helper' | |
require_relative '../../lib/strategies/identification_strategy' | |
require_relative '../../lib/classification/confident_identification' | |
require_relative '../../lib/classification/suspicious_identification' | |
require_relative '../../lib/classification/negative_identification' | |
require_relative '../../lib/company' | |
require_relative '../../lib/company_attribute' | |
describe IdentificationStrategy do | |
describe 'branching' do | |
let(:candidate) { Object.new } | |
subject { IdentificationStrategy.new(nil, nil) } | |
it 'returns single candidate' do | |
subject.branch([candidate]).must_equal candidate | |
end | |
it 'executes zero branch when no candidates provided' do | |
zero = Object.new | |
stub(subject).zero { zero } | |
subject.branch([]).must_equal zero | |
end | |
it 'executes many branch when many candidates provided' do | |
candidates = [candidate, candidate] | |
many = Object.new | |
stub(subject).many(candidates) { many } | |
subject.branch(candidates).must_equal many | |
end | |
end | |
describe 'attribute extraction' do | |
let(:candidate) { Company.new inn: '123', kpp: nil, okpo: '123', short_name: '123' } | |
let(:origin) { OpenStruct.new attributes: [ | |
CompanyAttribute.new(name: :inn, weight: 20, priority: 1), | |
CompanyAttribute.new(name: :kpp, weight: 10, priority: 1), | |
CompanyAttribute.new(name: :okpo, weight: 5, priority: 1), | |
CompanyAttribute.new(name: :short_name, weight: 3, priority: 2), | |
CompanyAttribute.new(name: :full_name, weight: 1, priority: 2)]} | |
it 'extracts non empty attributes with single priority' do | |
IdentificationStrategy.new(origin, 1).extract_attributes(candidate).sum(&:weight).must_equal 25 | |
end | |
it 'extracts non empty attributes with multiple priorities' do | |
IdentificationStrategy.new(origin, [1, 2]).extract_attributes(candidate).sum(&:weight).must_equal 28 | |
end | |
end | |
describe 'classification' do | |
let(:origin) { OpenStruct.new identification_threshold: 10, suspicious_threshold: 5 } | |
subject { IdentificationStrategy.new(origin, nil) } | |
it 'confidently identifies candidate' do | |
subject.classify(11).must_equal ConfidentIdentification | |
end | |
it 'suspiciously identifies candidate' do | |
subject.classify(7).must_equal SuspiciousIdentification | |
end | |
it 'cannot identify candidate' do | |
subject.classify(3).must_equal NegativeIdentification | |
end | |
end | |
describe 'searching' do | |
let(:company) { Company.new inn: '123', kpp: nil, okpo: 'abc', short_name: 'xyz' } | |
let(:candidate1) { Company.new inn: '123', kpp: nil, okpo: '___', short_name: 'xyz' } #Will be scored 23, which makes it confidently identified | |
let(:candidate2) { Company.new inn: '___', kpp: nil, okpo: 'abc', short_name: '__' } #Will be scored 5, which makes it suspiciously identified | |
let(:candidate3) { Company.new inn: '___', kpp: nil, okpo: '___', short_name: 'xyz' } #Will be scored 3, which makes it negatively identified | |
let(:origin) { OpenStruct.new identification_threshold: 10, suspicious_threshold: 5, attributes: [ | |
CompanyAttribute.new(name: :inn, weight: 20, priority: 1), | |
CompanyAttribute.new(name: :kpp, weight: 10, priority: 1), | |
CompanyAttribute.new(name: :okpo, weight: 5, priority: 1), | |
CompanyAttribute.new(name: :short_name, weight: 3, priority: 2)]} | |
subject { IdentificationStrategy.new(origin, [1, 2]) } | |
it 'identifies only first company' do | |
stub(subject).query(:PAYINDEX, {inn: '123', okpo: 'abc', short_name: 'xyz'}.to_a) { [candidate1, candidate2, candidate3] } | |
subject.search(company).must_equal candidate1 | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment