patentscope 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,45 @@
1
+ module Patentscope
2
+
3
+ class PctAppNumber < String
4
+
5
+ def initialize(number = "")
6
+ raise NoNumberError,
7
+ "Patent application number was not entered" if number.nil?
8
+ super(number.strip)
9
+ end
10
+
11
+ def valid?
12
+ self.match(/\A(([Pp][Cc][Tt]\/?)?[a-zA-Z]{2}\d{4}\/?\d{6})\Z/)
13
+ end
14
+
15
+ def validate
16
+ raise WrongNumberFormatError,
17
+ "PCT application number is not in correct format (PCT/CCYYYY/NNNNNN)" unless valid?
18
+ end
19
+
20
+ def to_ia_number
21
+ self.upcase!
22
+ self.gsub!('/', '')
23
+ self.gsub!('PCT', '')
24
+ self
25
+ end
26
+ end
27
+
28
+ class PctPubNumber < String
29
+
30
+ def initialize(number = "")
31
+ raise NoNumberError,
32
+ "Patent publication number was not entered" if number.nil?
33
+ super(number.strip)
34
+ end
35
+
36
+ def valid?
37
+ self.match(/\A(([Ww][Oo]\/?)?\s?\d{4}\/?\s?\d{6})\Z/)
38
+ end
39
+
40
+ def validate
41
+ raise WrongNumberFormatError,
42
+ "PCT publication number is not in correct format (WO/YYYY/NNNNNN)" unless valid?
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,5 @@
1
+ module Patentscope
2
+
3
+ VERSION = "0.0.1"
4
+
5
+ end
@@ -0,0 +1,74 @@
1
+ module Patentscope
2
+
3
+ class Webservice
4
+
5
+ PATENTSCOPE_WEBSERVICE_LOCATION = "http://www.wipo.int/patentscope-webservice/servicesPatentScope"
6
+
7
+ def wsdl
8
+ send_wsdl_request
9
+ end
10
+
11
+ def get_available_documents(args = {})
12
+ ia_number = PctAppNumber.new(args[:ia_number]).to_ia_number
13
+ perform_operation(:getAvailableDocuments, { iaNumber: ia_number })
14
+ end
15
+
16
+ def get_document_content(args = {})
17
+ doc_id = args[:doc_id]
18
+ perform_operation(:getDocumentContent, { docId: doc_id })
19
+ end
20
+
21
+ def get_document_ocr_content(args = {})
22
+ doc_id = args[:doc_id]
23
+ perform_operation(:getDocumentOcrContent, { docId: doc_id })
24
+ end
25
+
26
+ def get_iasr(args = {})
27
+ ia_number = PctAppNumber.new(args[:ia_number]).to_ia_number
28
+ perform_operation(:getIASR, { iaNumber: ia_number })
29
+ end
30
+
31
+ def get_document_table_of_contents(args = {})
32
+ doc_id = args[:doc_id]
33
+ perform_operation(:getDocumentTableOfContents, { docId: doc_id })
34
+ end
35
+
36
+ def get_document_content_page(args = {})
37
+ doc_id = args[:doc_id]
38
+ page_id = args[:page_id]
39
+ perform_operation(:getDocumentContentPage, { docId: doc_id, pageId: page_id })
40
+ end
41
+
42
+ private
43
+
44
+ def perform_operation(operation, options_hash)
45
+ soap_envelope = soapbuilder.build_envelope(operation, options_hash)
46
+ response = send_soap_request(soap_envelope)
47
+ if response.include?('This request requires HTTP authentication')
48
+ raise WrongCredentialsError
49
+ elsif response.include?('Business error during the execution of service')
50
+ raise BusinessError
51
+ else
52
+ soapbuilder.strip_envelope(response, operation)
53
+ end
54
+ end
55
+
56
+ def send_soap_request(soap_envelope_xml)
57
+ client.post_url(PATENTSCOPE_WEBSERVICE_LOCATION, "text/xml", soap_envelope_xml)
58
+ end
59
+
60
+ def send_wsdl_request
61
+ client.get_url(PATENTSCOPE_WEBSERVICE_LOCATION + '?wsdl')
62
+ end
63
+
64
+ def client
65
+ raise NoCredentialsError unless Patentscope.configured?
66
+ Client.new(username: Patentscope.configuration.username,
67
+ password: Patentscope.configuration.password)
68
+ end
69
+
70
+ def soapbuilder
71
+ WebserviceSoapBuilder.new
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,43 @@
1
+ module Patentscope
2
+
3
+ class WebserviceSoapBuilder
4
+
5
+ def build_envelope(operation, options_hash)
6
+ builder = Nokogiri::XML::Builder.new do |xml|
7
+ xml.Envelope do
8
+ ns = xml.doc.root.add_namespace_definition('S', 'http://schemas.xmlsoap.org/soap/envelope/')
9
+ xml.doc.root.namespace = ns
10
+ xml.Body do
11
+ xml.send(operation, :'xmlns' => 'http://www.wipo.org/wsdl/ps') do
12
+ options_hash.each do |key, value|
13
+ xml.send(key, value)
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end.to_xml
19
+ end
20
+
21
+ def strip_envelope(response, operation)
22
+ case operation
23
+ when :getAvailableDocuments
24
+ result_tag = 'doc'
25
+ when :getDocumentContent
26
+ result_tag = 'documentContent'
27
+ when :getDocumentOcrContent
28
+ result_tag = 'documentContent'
29
+ when :getIASR
30
+ result_tag = 'wo-international-application-status'
31
+ when :getDocumentTableOfContents
32
+ result_tag = 'content'
33
+ when :getDocumentContentPage
34
+ result_tag = 'pageContent'
35
+ end
36
+ doc = Nokogiri::XML(response)
37
+ stripped_response = doc.xpath("//iasr:#{result_tag}", 'iasr' => "http://www.wipo.org/wsdl/ps").to_xml
38
+ # this seems to be the only way to add back the XML declaration to the XML!
39
+ stripped_response_with_declaration = Nokogiri::XML(stripped_response).to_s
40
+ stripped_response_with_declaration
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,27 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'patentscope/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "patentscope"
8
+ gem.version = Patentscope::VERSION
9
+ gem.authors = ["Chong-Yee Khoo"]
10
+ gem.email = ["mail@cykhoo.com"]
11
+ gem.description = %q{Ruby interface to the Patentscope Webservice provided by the World Intellectual Property Organisation. Requires a subscription to the Patentscope Web Service}
12
+ gem.summary = %q{Ruby interface with WIPO Patentscope Webservice}
13
+ gem.homepage = "http://www.cantab-ip.com"
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ["lib"]
19
+
20
+ gem.add_development_dependency 'rake'
21
+ gem.add_development_dependency 'rspec', '~> 3.0.0.beta1'
22
+ gem.add_development_dependency 'vcr'
23
+ gem.add_development_dependency 'webmock'
24
+
25
+ gem.add_runtime_dependency 'nokogiri'
26
+ gem.add_runtime_dependency 'unicode_titlecase'
27
+ end
@@ -0,0 +1,75 @@
1
+ require 'spec_helper'
2
+
3
+ module Patentscope
4
+
5
+ describe Client, :core, :vcr do
6
+
7
+ before { Patentscope.configure_from_env}
8
+
9
+ let(:client) { Client.new(username: Patentscope.configuration.username, password: Patentscope.configuration.password) }
10
+
11
+ it "exists" do
12
+ expect(client).to_not be_nil
13
+ end
14
+
15
+ describe "methods" do
16
+
17
+ it "has its own attribute reader methods" do
18
+ expect(client).to respond_to(:username)
19
+ expect(client).to respond_to(:password)
20
+ end
21
+
22
+ it "has other methods" do
23
+ expect(client).to respond_to(:get_url)
24
+ expect(client).to respond_to(:post_url)
25
+ end
26
+ end
27
+
28
+ describe "attribute reader methods" do
29
+
30
+ describe "username method" do
31
+ it "returns the right username" do
32
+ expect(client.username).to eq(Patentscope.configuration.username)
33
+ end
34
+ end
35
+
36
+ describe "password method" do
37
+ it "returns the right password" do
38
+ expect(client.password).to eq(Patentscope.configuration.password)
39
+ end
40
+ end
41
+ end
42
+
43
+ describe "attribute writer methods" do
44
+
45
+ it "is not possible to set username" do
46
+ expect { client.username = 'foo' }.to raise_error()
47
+ end
48
+
49
+ it "is not possible to set password" do
50
+ expect { client.password = 'foo' }.to raise_error()
51
+ end
52
+ end
53
+
54
+ describe "get_url method" do
55
+ it "fetches the Cantab website by GET" do
56
+ site = client.get_url('http://www.cantab-ip.com')
57
+ expect(site).to include('<html')
58
+ end
59
+
60
+ it "fetches the Patentscope WSDL by GET" do
61
+ site = client.get_url('http://www.wipo.int/patentscope-webservice/servicesPatentScope?wsdl')
62
+ expect(site).to include('<?xml')
63
+ end
64
+ end
65
+
66
+ describe "post_url method" do
67
+ it "fetches a URL by POST" do
68
+ Patentscope.configure_from_env
69
+ soap_envelope_xml = '<?xml version="1.0"?><S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"><S:Body><getIASR xmlns="http://www.wipo.org/wsdl/ps"><iaNumber>SG2009000062</iaNumber></getIASR></S:Body></S:Envelope>'
70
+ site = client.post_url('http://www.wipo.int/patentscope-webservice/servicesPatentScope', 'text/xml', soap_envelope_xml)
71
+ expect(site).to include('<?xml')
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,138 @@
1
+ require 'spec_helper'
2
+
3
+ module Patentscope
4
+
5
+ describe Patentscope do
6
+
7
+ it 'has a configure class method' do
8
+ expect(Patentscope).to respond_to(:configure)
9
+ end
10
+
11
+ it 'has a configure_from_env class method' do
12
+ expect(Patentscope).to respond_to(:configure_from_env)
13
+ end
14
+
15
+ it 'has a configured? class method' do
16
+ expect(Patentscope).to respond_to(:configured?)
17
+ end
18
+
19
+ it 'has a reset_configuration class method' do
20
+ expect(Patentscope).to respond_to(:reset_configuration)
21
+ end
22
+
23
+ it 'has a configuration class method' do
24
+ expect(Patentscope).to respond_to(:configuration)
25
+ end
26
+ end
27
+
28
+ describe 'Patentscope::Configuration class' do
29
+
30
+ it 'has a username instance method' do
31
+ expect(Patentscope::Configuration.new).to respond_to(:username)
32
+ end
33
+
34
+ it 'has a password instance method' do
35
+ expect(Patentscope::Configuration.new).to respond_to(:password)
36
+ end
37
+ end
38
+
39
+ describe 'Patentscope before configuration' do
40
+
41
+ before { Patentscope.reset_configuration }
42
+
43
+ it 'configuration object is nil if configure not called' do
44
+ expect(Patentscope.configuration).to be_nil
45
+ end
46
+
47
+ it 'is not configured' do
48
+ expect(Patentscope.configured?).to be_falsey
49
+ end
50
+
51
+ it 'raises an error during client operations' do
52
+ expect do
53
+ Webservice.new.get_iasr(ia_number: 'SG2009000062')
54
+ end.to raise_error(Patentscope::NoCredentialsError)
55
+ end
56
+ end
57
+
58
+ describe 'Patentscope with configuration but no specific credentials given' do
59
+
60
+ before { Patentscope.reset_configuration }
61
+
62
+ it 'username defaults to null string if not explicitly set in the configure block' do
63
+ Patentscope.configure
64
+ expect(Patentscope.configuration.username).to eq('')
65
+ end
66
+
67
+ it 'password defaults to null string if not explicitly set in the configure block' do
68
+ Patentscope.configure
69
+ expect(Patentscope.configuration.password).to eq('')
70
+ end
71
+
72
+ it 'raises an error during client operations' do
73
+ expect do
74
+ Webservice.new.get_iasr(ia_number: 'SG2009000062')
75
+ end.to raise_error(Patentscope::NoCredentialsError)
76
+ end
77
+ end
78
+
79
+ describe 'Patentscope with configuration using configuration block' do
80
+
81
+ before do
82
+ Patentscope.configure do |config|
83
+ config.username = 'joe_bloggs'
84
+ config.password = 'b10ggsy'
85
+ end
86
+ end
87
+
88
+ after(:each) do
89
+ Patentscope.reset_configuration
90
+ end
91
+
92
+ it 'configures the username and password in a block in the configure method' do
93
+ expect(Patentscope.configuration.username).to eq('joe_bloggs')
94
+ expect(Patentscope.configuration.password).to eq('b10ggsy')
95
+ end
96
+ end
97
+
98
+ describe "Patentscope with configuration loading from environment variables" do
99
+
100
+ after(:each) do
101
+ Patentscope.reset_configuration
102
+ end
103
+
104
+ describe 'where a configuration has already been set' do
105
+ before do
106
+ Patentscope.configure do |config|
107
+ config.username = 'joe_bloggs'
108
+ config.password = 'b10ggsy'
109
+ end
110
+ end
111
+
112
+ it 'loading operation fails' do
113
+ expect(Patentscope.configure_from_env).to be false
114
+ end
115
+
116
+ it 'does not overwrite existing configuration' do
117
+ expect(Patentscope.configuration.username).to eq('joe_bloggs')
118
+ expect(Patentscope.configuration.password).to eq('b10ggsy')
119
+
120
+ expect(Patentscope.configuration.username).to_not eq(ENV['PATENTSCOPE_WEBSERVICE_USERNAME'])
121
+ expect(Patentscope.configuration.password).to_not eq(ENV['PATENTSCOPE_WEBSERVICE_PASSWORD'])
122
+ end
123
+ end
124
+
125
+ describe 'where there is no existing configuration' do
126
+
127
+ it 'loading operation succeeds' do
128
+ expect(Patentscope.configure_from_env).to be true
129
+ end
130
+
131
+ it 'assigns the configuration from environment variables' do
132
+ Patentscope.configure_from_env
133
+ expect(Patentscope.configuration.username).to eq(ENV['PATENTSCOPE_WEBSERVICE_USERNAME'])
134
+ expect(Patentscope.configuration.password).to eq(ENV['PATENTSCOPE_WEBSERVICE_PASSWORD'])
135
+ end
136
+ end
137
+ end
138
+ end
@@ -0,0 +1,91 @@
1
+ require 'spec_helper'
2
+
3
+ module Patentscope
4
+
5
+ describe Patentscope, :core, :vcr do
6
+
7
+ before { Patentscope.configure_from_env }
8
+
9
+ let(:patentscope) { Patentscope }
10
+
11
+ it "exists" do
12
+ expect(patentscope).to_not be_nil
13
+ end
14
+
15
+ it "has the right methods" do
16
+ expect(patentscope).to respond_to(:wsdl)
17
+ expect(patentscope).to respond_to(:get_available_documents)
18
+ expect(patentscope).to respond_to(:get_document_content)
19
+ expect(patentscope).to respond_to(:get_document_ocr_content)
20
+ expect(patentscope).to respond_to(:get_iasr)
21
+ expect(patentscope).to respond_to(:get_document_table_of_contents)
22
+ expect(patentscope).to respond_to(:get_document_content_page)
23
+ end
24
+
25
+ describe "wsdl method" do
26
+ it "returns a wsdl document" do
27
+ response = patentscope.wsdl
28
+ expect(response).to include('<?xml')
29
+ expect(response).to include('<wsdl:definitions')
30
+ end
31
+ end
32
+
33
+ describe "get_available_documents method" do
34
+ it 'returns an appropriate XML document for the get_available_documents operation' do
35
+ response = patentscope.get_available_documents('SG2009000062')
36
+ expect(response).to include('<?xml version="1.0"?>')
37
+ expect(response).to include('<doc ocrPresence="no" docType="RO101" docId="id00000008679651"/>')
38
+ expect(response).to_not include('<getAvailableDocumentsResponse xmlns="http://www.wipo.org/wsdl/ps">')
39
+ end
40
+ end
41
+
42
+ describe "get_document_content method" do
43
+ it 'returns an appropriate XML document for the get_document_content operation' do
44
+ response = patentscope.get_document_content('090063618004ca88')
45
+ expect(response).to include('<?xml version="1.0"?>')
46
+ expect(response).to include('<documentContent>')
47
+ expect(response).to include('nRpZsy7ezxU2/8/fk5JM6HIXReMWymXUCmhYcRgUIjjNk2pDAkdlxox7xiSLm')
48
+ expect(response).to_not include('<getDocumentContentResponse xmlns="http://www.wipo.org/wsdl/ps">')
49
+ end
50
+ end
51
+
52
+ describe "get_document_ocr_content method" do
53
+ it 'returns an appropriate XML document for the get_document_ocr_content operation' do
54
+ response = patentscope.get_document_ocr_content('id00000015801579')
55
+ expect(response).to include('<?xml version="1.0"?>')
56
+ expect(response).to include('<documentContent>')
57
+ expect(response).to include('XdDb9Ain4kev61wgZc36X022QPCEZZASS2Rwpcy4Hx7I5GYHhriRwpsDwoX9tgjgZwcEGGEksgthsHsNtkFmyGZYQIGGCCX3dhggRDTgEEDNgVgkvuw2ECDDSYMEF')
58
+ expect(response).to_not include('<getDocumentOcrContentResponse xmlns="http://www.wipo.org/wsdl/ps">')
59
+ end
60
+ end
61
+
62
+ describe "get_iasr method" do
63
+ it 'returns an appropriate XML document for the get_iasr operation' do
64
+ response = patentscope.get_iasr('SG2009000062')
65
+ expect(response).to include('<?xml version="1.0"?>')
66
+ expect(response).to include('<wo-international-application-status>')
67
+ expect(response).to include('MESENCHYMAL STEM CELL PARTICLES')
68
+ expect(response).to_not include('<getIASRResponse xmlns="http://www.wipo.org/wsdl/ps">')
69
+ end
70
+ end
71
+
72
+ describe "get_document_table_of_contents method" do
73
+ it 'returns an appropriate XML document for the get_document_table_of_contents operation' do
74
+ response = patentscope.get_document_table_of_contents('090063618004ca88')
75
+ expect(response).to include('<?xml version="1.0"?>')
76
+ expect(response).to include('<content>')
77
+ expect(response).to include('<content>000001.tif</content>')
78
+ expect(response).to_not include('<getDocumentTableOfContentsResponse xmlns="http://www.wipo.org/wsdl/ps">')
79
+ end
80
+ end
81
+
82
+ describe "get_document_content_page method" do
83
+ it 'returns an appropriate XML document for the get_document_content_page operation' do
84
+ response = patentscope.get_document_content_page('090063618004ca88', '000001.tif')
85
+ expect(response).to include('<?xml version="1.0"?>')
86
+ expect(response).to include('+GP0kv9dhgiY7Rb5h2q4RN6Jj9NpDCJjuMImO0l0TfLe7QRO2yFceTvvTu6C6qTH')
87
+ expect(response).to_not include('<getDocumentContentPageResponse xmlns="http://www.wipo.org/wsdl/ps">')
88
+ end
89
+ end
90
+ end
91
+ end