patentscope 0.0.1

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.
@@ -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