epo-ops 0.2.6 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +3 -0
- data/.travis.yml +6 -0
- data/README.md +78 -38
- data/epo-ops.gemspec +2 -2
- data/lib/epo_ops.rb +46 -0
- data/lib/epo_ops/client.rb +46 -0
- data/lib/epo_ops/error.rb +87 -0
- data/lib/epo_ops/factories.rb +9 -0
- data/lib/epo_ops/factories/name_and_address_factory.rb +54 -0
- data/lib/epo_ops/factories/patent_application_factory.rb +116 -0
- data/lib/epo_ops/factories/register_search_result_factory.rb +42 -0
- data/lib/epo_ops/ipc_class_hierarchy.rb +146 -0
- data/lib/epo_ops/ipc_class_hierarchy_loader.rb +60 -0
- data/lib/epo_ops/ipc_class_util.rb +71 -0
- data/lib/epo_ops/limits.rb +20 -0
- data/lib/epo_ops/logger.rb +15 -0
- data/lib/epo_ops/name_and_address.rb +58 -0
- data/lib/epo_ops/patent_application.rb +159 -0
- data/lib/epo_ops/rate_limit.rb +47 -0
- data/lib/epo_ops/register.rb +100 -0
- data/lib/epo_ops/register_search_result.rb +40 -0
- data/lib/epo_ops/search_query_builder.rb +65 -0
- data/lib/epo_ops/token_store.rb +33 -0
- data/lib/epo_ops/token_store/redis.rb +45 -0
- data/lib/epo_ops/util.rb +52 -0
- data/lib/epo_ops/version.rb +3 -0
- metadata +26 -20
- data/lib/epo/ops.rb +0 -43
- data/lib/epo/ops/address.rb +0 -60
- data/lib/epo/ops/bibliographic_document.rb +0 -196
- data/lib/epo/ops/client.rb +0 -27
- data/lib/epo/ops/error.rb +0 -89
- data/lib/epo/ops/ipc_class_hierarchy.rb +0 -148
- data/lib/epo/ops/ipc_class_hierarchy_loader.rb +0 -62
- data/lib/epo/ops/ipc_class_util.rb +0 -73
- data/lib/epo/ops/limits.rb +0 -22
- data/lib/epo/ops/logger.rb +0 -11
- data/lib/epo/ops/rate_limit.rb +0 -49
- data/lib/epo/ops/register.rb +0 -152
- data/lib/epo/ops/search_query_builder.rb +0 -65
- data/lib/epo/ops/token_store.rb +0 -35
- data/lib/epo/ops/token_store/redis.rb +0 -47
- data/lib/epo/ops/util.rb +0 -32
- data/lib/epo/ops/version.rb +0 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 598720d94ba023a3a3e6b0e2b3f4b018a7f1983e
|
4
|
+
data.tar.gz: d6861675f8ef8abd67a13664c881406a9a8e711a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 31e1b55be1850539337a550d831d1b63881b4248e8456dcbc1c6a4af1b32e6e289d92a76833434038f53dc97612bf214a1680388f955d7220bee2046e423b25c
|
7
|
+
data.tar.gz: 50f29328406d721d8515cc0436cad653d1cf2e0fdf6f725f372b950c12401968ddaed942b1d57483ab594778b04c26533d5c3f5a8c47ba7606bd6e7240339dfb
|
data/.gitignore
CHANGED
data/.travis.yml
ADDED
data/README.md
CHANGED
@@ -4,68 +4,108 @@
|
|
4
4
|
# epo-ops
|
5
5
|
Ruby interface to the EPO Open Patent Services (OPS).
|
6
6
|
|
7
|
-
[
|
7
|
+
[Full documentation can be found here](http://www.rubydoc.info/gems/epo-ops/)
|
8
|
+
|
8
9
|
|
9
|
-
The EPO provides [playground](https://developers.epo.org/), where you can try
|
10
|
-
out the methods. As well as [Documentation](https://www.epo.org/searching-for-patents/technical/espacenet/ops.html)
|
11
|
-
of the different endpoints and detailed usage (see the 'Downloads' section).
|
12
10
|
|
13
11
|
# Usage
|
14
12
|
|
15
|
-
##
|
16
|
-
|
17
|
-
|
18
|
-
|
13
|
+
## Quickstart
|
14
|
+
Simply install this gem and start a ruby console.
|
15
|
+
```
|
16
|
+
$ gem install epo-ops
|
17
|
+
$ irb
|
18
|
+
```
|
19
|
+
|
20
|
+
and start querying the API
|
19
21
|
|
20
22
|
```ruby
|
21
|
-
|
23
|
+
require 'epo_ops'
|
24
|
+
|
25
|
+
patent_application = EpoOps::PatentApplication.find("EP14731659")
|
26
|
+
patent_application.title # "DEVICE AND METHOD FOR INTRODUCING FIBRES INTO AN EXTRUDER"
|
27
|
+
patent_application.classifications # ["B29C47/10", "B29C47/68", "B29C47/92", "B29C45/00", "B01D46/24"]
|
28
|
+
patent_application.applicants.first.name # "Fraunhofer-Gesellschaft zur Förderung der angewandten Forschung e.V."
|
29
|
+
```
|
30
|
+
|
31
|
+
## Advanced Usage
|
32
|
+
|
33
|
+
### OAuth
|
34
|
+
|
35
|
+
EPO offers an anonymous developer access to their API with very little quota. To get extended quotas you can register
|
36
|
+
an account at the [EPO for OAuth](https://developers.epo.org/user/register)
|
37
|
+
|
38
|
+
After your account has been approved configure your credentials
|
39
|
+
|
40
|
+
```ruby
|
41
|
+
|
42
|
+
EpoOps.configure do |conf|
|
43
|
+
conf.authentication = :oauth
|
22
44
|
conf.consumer_key = "YOUR_KEY"
|
23
45
|
conf.consumer_secret = "YOUR_SECRET"
|
24
46
|
end
|
47
|
+
|
25
48
|
```
|
26
49
|
|
27
|
-
|
28
|
-
|
50
|
+
The temporary access token is kept in memory for subsequent retrievals. To share this between several processes the
|
51
|
+
token storage strategy may be changed as shown in `epo/ops/token_store` for redis.
|
29
52
|
|
30
|
-
Get references to all Patents on a given date and IPC-class:
|
31
53
|
|
32
|
-
|
33
|
-
Epo::Ops::Register.search("A", Date.new(2016,2 ,3))
|
34
|
-
# or for all ipc classes
|
35
|
-
Epo::Ops::Register.search(nil, Date.new(2016,2 ,3))
|
36
|
-
```
|
54
|
+
### Querying and searching patent applications
|
37
55
|
|
38
|
-
|
56
|
+
Currently this gem focuses mostly around patent applications.
|
57
|
+
It is possible to search for specific applications by application number and to search for applications using a
|
58
|
+
CQL search query
|
59
|
+
|
60
|
+
For example to find all applications in IPC Class _A01_ (and all subclasses) that were updated on 2016-01-01
|
39
61
|
|
40
62
|
```ruby
|
41
|
-
|
42
|
-
|
63
|
+
query = EpoOps::SearchQueryBuilder.build("A01", Date.parse("2016-01-02"))
|
64
|
+
applications = EpoOps::PatentApplication.search(query)
|
65
|
+
puts applications.count # 1234
|
66
|
+
applications.map {|application| puts application.application_nr } # print all application numbers
|
67
|
+
applications.map {|application| application.fetch} # fetch complete bibliographic data for each document
|
68
|
+
|
43
69
|
```
|
44
|
-
This will return an object that helps parsing the result. See the documentation
|
45
|
-
for more information
|
46
70
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
71
|
+
The Request will return a search result containing the number of all applications matching the search. By default the
|
72
|
+
search will return 10 documents (max is 100). You can use `start_rang` and `end_range` of `EpoOps::SearchQueryBuilder.build`
|
73
|
+
to page through all results
|
74
|
+
|
75
|
+
**Note: EPO will always only return up to 2000 documents even if the search would return more**
|
51
76
|
|
52
|
-
## Custom Retrieval
|
53
77
|
|
54
|
-
###
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
parse it yourself.
|
78
|
+
### Search for all Patents on a given Date
|
79
|
+
|
80
|
+
To circumvent the restriction of max 2000 search results this gem
|
81
|
+
offers a convenient method to search for all patents updated on a given date and/or a given IPC class
|
59
82
|
|
60
83
|
```ruby
|
61
|
-
|
84
|
+
EpoOps::Register.search("A", Date.new(2016,2 ,3))
|
85
|
+
# or for all ipc classes
|
86
|
+
EpoOps::Register.search(nil, Date.new(2016,2 ,3))
|
62
87
|
```
|
63
88
|
|
64
|
-
|
65
|
-
If you do not want to retrieve via the `application` endpoint (say you want
|
66
|
-
`publication`) this method gives you more fine-grained control. Make sure the
|
67
|
-
`reference_id` you use matches the type.
|
89
|
+
You can now retrieve the bibliographic entries of all these:
|
68
90
|
|
69
91
|
```ruby
|
70
|
-
|
92
|
+
references = EpoOps::Register.search(nil, Date.new(2016,2 ,3))
|
93
|
+
references.map { |ref| EpoOps::Register.biblio(ref) }
|
71
94
|
```
|
95
|
+
|
96
|
+
**Note: Both operations take a considerable amount of time. Also you may not
|
97
|
+
want to develop and test with many of these requests, as they can quite quickly exceed your limits.**
|
98
|
+
|
99
|
+
|
100
|
+
# Further Reading
|
101
|
+
|
102
|
+
The EPO provides [a developer playground](https://developers.epo.org/), where you can test-drive the OPS-API.
|
103
|
+
They also provide extensive [documentation](https://www.epo.org/searching-for-patents/technical/espacenet/ops.html)
|
104
|
+
of the different endpoints and how to use them (see the 'Downloads' section).
|
105
|
+
|
106
|
+
|
107
|
+
# Development
|
108
|
+
|
109
|
+
This gem is still an early version and it is far from covering the whole API.
|
110
|
+
If you are interested to include different API endpoints than the register it should be easy to include those and we
|
111
|
+
are happy to accept pull requests.
|
data/epo-ops.gemspec
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
lib = File.expand_path('../lib', __FILE__)
|
3
3
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
-
require '
|
4
|
+
require 'epo_ops/version'
|
5
5
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
7
|
spec.name = 'epo-ops'
|
8
|
-
spec.version =
|
8
|
+
spec.version = EpoOps::VERSION
|
9
9
|
spec.authors = ['Max Kießling', 'Robert Terbach', 'Michael Prilop']
|
10
10
|
|
11
11
|
spec.summary = 'Ruby interface to the European Patent Office API (OPS)'
|
data/lib/epo_ops.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'epo_ops/version'
|
2
|
+
require 'epo_ops/token_store'
|
3
|
+
require 'epo_ops/register'
|
4
|
+
require 'epo_ops/search_query_builder'
|
5
|
+
require 'epo_ops/ipc_class_hierarchy_loader'
|
6
|
+
require 'epo_ops/ipc_class_util'
|
7
|
+
require 'epo_ops/patent_application'
|
8
|
+
require 'epo_ops/name_and_address'
|
9
|
+
require 'epo_ops/factories'
|
10
|
+
require 'epo_ops/register_search_result'
|
11
|
+
|
12
|
+
module EpoOps
|
13
|
+
# Configure authentication method and credentials
|
14
|
+
# @example
|
15
|
+
# EpoOps.configure do |conf|
|
16
|
+
# conf.consumer_key = "foo"
|
17
|
+
# conf.consumer_secret = "bar"
|
18
|
+
# conf.token_store = EpoOps::TokenStore::Redis # (defaults to EpoOps::TokenStore)
|
19
|
+
# conf.authentication :oauth # or :plain (defaults to :plain)
|
20
|
+
# end
|
21
|
+
# @yieldparam [Configuration] configuration that is yielded.
|
22
|
+
def self.configure
|
23
|
+
yield(config)
|
24
|
+
end
|
25
|
+
|
26
|
+
# The {Configuration} used. You may want to call {EpoOps#configure} first.
|
27
|
+
# @return [Configuration] the configuration used.
|
28
|
+
def self.config
|
29
|
+
@configuration ||= Configuration.new
|
30
|
+
end
|
31
|
+
|
32
|
+
class Configuration
|
33
|
+
attr_accessor :consumer_key, :consumer_secret, :token_store, :authentication
|
34
|
+
|
35
|
+
def initialize
|
36
|
+
@consumer_key = ''
|
37
|
+
@consumer_secret = ''
|
38
|
+
@token_store = EpoOps::TokenStore.new
|
39
|
+
@authentication = :plain
|
40
|
+
|
41
|
+
OAuth2::Response.register_parser(:xml, ['application/xml']) do |body|
|
42
|
+
MultiXml.parse(body)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'epo_ops/token_store'
|
2
|
+
require 'epo_ops/error'
|
3
|
+
|
4
|
+
module EpoOps
|
5
|
+
|
6
|
+
# This is a wrapper for OAuth
|
7
|
+
class Client
|
8
|
+
|
9
|
+
|
10
|
+
# @return [OAuth2::Response]
|
11
|
+
# @option options [Hash] :params query parameter for the request
|
12
|
+
# @option options [Hash, String] :body the body of the request
|
13
|
+
# @option options [Hash] :headers http request headers
|
14
|
+
# @raise [EpoOps::Error] API Error if request was not successful
|
15
|
+
def self.request(verb, url, options = {})
|
16
|
+
response = case EpoOps.config.authentication
|
17
|
+
when :oauth then do_oauth_request(verb, url, options)
|
18
|
+
when :plain then do_plain_request(verb,url,options)
|
19
|
+
else raise('Unknown authentication strategy!')
|
20
|
+
end
|
21
|
+
fail Error.from_response(response) unless response.status == 200
|
22
|
+
response
|
23
|
+
rescue Error::AccessTokenExpired
|
24
|
+
EpoOps.config.token_store.reset
|
25
|
+
request(verb, url, options)
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
# Make an oauth request to the EPO API
|
31
|
+
# @return [OAuth2::Response]
|
32
|
+
def self.do_oauth_request(verb, url, options = {})
|
33
|
+
token = EpoOps.config.token_store.token
|
34
|
+
token.request(verb, URI.encode(url), options)
|
35
|
+
end
|
36
|
+
|
37
|
+
# Make an anonymous request to the EPO API
|
38
|
+
# @return [OAuth2::Response] OAuth2::Reponse is used for convenience and consistency
|
39
|
+
def self.do_plain_request(verb, url, options = {})
|
40
|
+
conn = Faraday.new("https://ops.epo.org/")
|
41
|
+
url = conn.build_url(url, options[:params]).to_s
|
42
|
+
response = conn.run_request(verb,url,options[:body], options[:header])
|
43
|
+
OAuth2::Response.new(response)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'epo_ops/rate_limit'
|
2
|
+
|
3
|
+
module EpoOps
|
4
|
+
class Error < StandardError
|
5
|
+
# @return [Integer]
|
6
|
+
attr_reader :code, :rate_limit
|
7
|
+
|
8
|
+
# Raised when EPO returns a 4xx HTTP status code
|
9
|
+
ClientError = Class.new(self)
|
10
|
+
# Raised when EPO returns the HTTP status code 400
|
11
|
+
BadRequest = Class.new(ClientError)
|
12
|
+
# Raised when EPO returns the HTTP status code 401
|
13
|
+
Unauthorized = Class.new(ClientError)
|
14
|
+
# Raised when EPO returns the HTTP status code 403
|
15
|
+
Forbidden = Class.new(ClientError)
|
16
|
+
# Raised when EPO returns the HTTP status code 404
|
17
|
+
NotFound = Class.new(ClientError)
|
18
|
+
# Raised when EPO returns the HTTP status code 406
|
19
|
+
NotAcceptable = Class.new(ClientError)
|
20
|
+
# Raised when EPO returns the HTTP status code 422
|
21
|
+
UnprocessableEntity = Class.new(ClientError)
|
22
|
+
# Raised when EPO returns the HTTP status code 429
|
23
|
+
TooManyRequests = Class.new(ClientError)
|
24
|
+
# Raised when EPO returns a 5xx HTTP status code
|
25
|
+
ServerError = Class.new(self)
|
26
|
+
# Raised when EPO returns the HTTP status code 500
|
27
|
+
InternalServerError = Class.new(ServerError)
|
28
|
+
# Raised when EPO returns the HTTP status code 502
|
29
|
+
BadGateway = Class.new(ServerError)
|
30
|
+
# Raised when EPO returns the HTTP status code 503
|
31
|
+
ServiceUnavailable = Class.new(ServerError)
|
32
|
+
# Raised when EPO returns the HTTP status code 504
|
33
|
+
GatewayTimeout = Class.new(ServerError)
|
34
|
+
# AccessToken has expired
|
35
|
+
AccessTokenExpired = Class.new(ClientError)
|
36
|
+
|
37
|
+
ERRORS = {
|
38
|
+
400 => EpoOps::Error::BadRequest,
|
39
|
+
401 => EpoOps::Error::Unauthorized,
|
40
|
+
403 => EpoOps::Error::Forbidden,
|
41
|
+
404 => EpoOps::Error::NotFound,
|
42
|
+
406 => EpoOps::Error::NotAcceptable,
|
43
|
+
422 => EpoOps::Error::UnprocessableEntity,
|
44
|
+
429 => EpoOps::Error::TooManyRequests,
|
45
|
+
500 => EpoOps::Error::InternalServerError,
|
46
|
+
502 => EpoOps::Error::BadGateway,
|
47
|
+
503 => EpoOps::Error::ServiceUnavailable,
|
48
|
+
504 => EpoOps::Error::GatewayTimeout
|
49
|
+
}.freeze
|
50
|
+
FORBIDDEN_MESSAGES = {
|
51
|
+
'This request has been rejected due to the violation of Fair Use policy' => EpoOps::Error::TooManyRequests
|
52
|
+
}.freeze
|
53
|
+
|
54
|
+
class << self
|
55
|
+
# Parses an error from the given response
|
56
|
+
# @return [Error]
|
57
|
+
def from_response(response)
|
58
|
+
code = response.status
|
59
|
+
message = parse_error(response.parsed)
|
60
|
+
|
61
|
+
if code == 403 && FORBIDDEN_MESSAGES[message]
|
62
|
+
FORBIDDEN_MESSAGES[message].new(message, response.headers, code)
|
63
|
+
elsif code == 400 && response.headers['www-authenticate'] && response.headers['www-authenticate'].include?('Access Token expired')
|
64
|
+
Error::AccessTokenExpired.new('Access Token expired', response.headers, code)
|
65
|
+
else
|
66
|
+
ERRORS[code].new(message, response.headers, code)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
def parse_error(body)
|
73
|
+
if body.nil? || body.empty?
|
74
|
+
nil
|
75
|
+
elsif body['error'] && body['error']['message']
|
76
|
+
body['error']['message']
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def initialize(message = '', rate_limit = {}, code = nil)
|
82
|
+
super(message)
|
83
|
+
@code = code
|
84
|
+
@rate_limit = RateLimit.new(rate_limit)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module EpoOps
|
2
|
+
module Factories
|
3
|
+
# Parses the addressbook data from EPO Ops into an 'NameAndAddress' object
|
4
|
+
class NameAndAddressFactory
|
5
|
+
class << self
|
6
|
+
|
7
|
+
# @param raw_data [Hash] raw addressbook data as retrieved included in Epo Ops biblio data
|
8
|
+
# @return [EpoOps::NameAndAddress] NameAndAddress filled with parsed data
|
9
|
+
def build(raw_data)
|
10
|
+
factory = new(raw_data)
|
11
|
+
|
12
|
+
EpoOps::NameAndAddress.new(
|
13
|
+
factory.name,
|
14
|
+
factory.address_1,
|
15
|
+
factory.address_2,
|
16
|
+
factory.address_3,
|
17
|
+
factory.address_4,
|
18
|
+
factory.address_5,
|
19
|
+
factory.country_code,
|
20
|
+
factory.cdsid
|
21
|
+
)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
attr_reader :raw_data,
|
26
|
+
:name,
|
27
|
+
:address_1,
|
28
|
+
:address_2,
|
29
|
+
:address_3,
|
30
|
+
:address_4,
|
31
|
+
:address_5,
|
32
|
+
:country_code,
|
33
|
+
:cdsid
|
34
|
+
|
35
|
+
|
36
|
+
def initialize(raw_data)
|
37
|
+
@raw_data = raw_data
|
38
|
+
|
39
|
+
@name = raw_data['name']
|
40
|
+
|
41
|
+
if raw_data['address'].is_a? Hash
|
42
|
+
@address_1 = raw_data['address']['address_1']
|
43
|
+
@address_2 = raw_data['address']['address_2']
|
44
|
+
@address_3 = raw_data['address']['address_3']
|
45
|
+
@address_4 = raw_data['address']['address_4']
|
46
|
+
@address_5 = raw_data['address']['address_5']
|
47
|
+
@country_code = raw_data['address']['country']
|
48
|
+
end
|
49
|
+
|
50
|
+
@cdsid = raw_data['cdsid']
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
module EpoOps
|
2
|
+
module Factories
|
3
|
+
# Parses the patent application data from EPO Ops into an PatentApplication object
|
4
|
+
class PatentApplicationFactory
|
5
|
+
class << self
|
6
|
+
|
7
|
+
# @param raw_data [Hash] raw application data as retrieved from Epo Ops
|
8
|
+
# @return [EpoOps::PatentApplication] PatentApplication filled with parsed data
|
9
|
+
def build(raw_data)
|
10
|
+
factory = new(raw_data)
|
11
|
+
|
12
|
+
EpoOps::PatentApplication.new(
|
13
|
+
factory.application_number,
|
14
|
+
|
15
|
+
raw_data: raw_data,
|
16
|
+
title: factory.title,
|
17
|
+
status: factory.status,
|
18
|
+
agents: factory.agents,
|
19
|
+
applicants: factory.applicants,
|
20
|
+
inventors: factory.inventors,
|
21
|
+
classifications: factory.classifications,
|
22
|
+
priority_claims: factory.priority_claims,
|
23
|
+
publication_references: factory.publication_references,
|
24
|
+
effective_date: factory.effective_date
|
25
|
+
)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
attr_reader :raw_data
|
30
|
+
|
31
|
+
def initialize(raw_data)
|
32
|
+
@raw_data = raw_data
|
33
|
+
end
|
34
|
+
|
35
|
+
# @return [String] Application Number
|
36
|
+
# @see EpoOps::PatentApplication#application_nr
|
37
|
+
def application_number
|
38
|
+
document_id = EpoOps::Util.flat_dig raw_data, data_path('application_reference', 'document_id')
|
39
|
+
document_id = document_id.first if document_id.is_a?(Array)
|
40
|
+
|
41
|
+
"#{document_id['country']}#{document_id['doc_number']}"
|
42
|
+
end
|
43
|
+
|
44
|
+
# @return [Hash] List of titles in different languages
|
45
|
+
# @see EpoOps::PatentApplication#title
|
46
|
+
def title
|
47
|
+
titles = EpoOps::Util.flat_dig raw_data, data_path('invention_title')
|
48
|
+
titles.inject({}) do |hash, title|
|
49
|
+
hash[title['lang']] = title['__content__'] if title.is_a? Hash
|
50
|
+
hash
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# @return [Array] List of {EpoOps::NameAndAddress}
|
55
|
+
# @see EpoOps::PatentApplication#agents
|
56
|
+
def agents
|
57
|
+
EpoOps::Util.flat_dig(raw_data, data_path('parties', 'agents', 'agent', 'addressbook')).map do |agent|
|
58
|
+
EpoOps::Factories::NameAndAddressFactory.build(agent)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# @return [Array] List of {EpoOps::NameAndAddress}
|
63
|
+
# @see EpoOps::PatentApplication#applicants
|
64
|
+
def applicants
|
65
|
+
EpoOps::Util.flat_dig(raw_data, data_path('parties', 'applicants', 'applicant', 'addressbook')).map do |applicant|
|
66
|
+
EpoOps::Factories::NameAndAddressFactory.build(applicant)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# @return [Array] List of {EpoOps::NameAndAddress}
|
71
|
+
# @see EpoOps::PatentApplication#inventors
|
72
|
+
def inventors
|
73
|
+
EpoOps::Util.flat_dig(raw_data, data_path('parties', 'inventors', 'inventor', 'addressbook')).map do |inventor|
|
74
|
+
EpoOps::Factories::NameAndAddressFactory.build(inventor)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# @return [Array] List of IPC classes
|
79
|
+
# @see EpoOps::PatentApplication#classifications
|
80
|
+
def classifications
|
81
|
+
EpoOps::Util.dig(raw_data, data_path('classifications_ipcr', 'classification_ipcr', 'text')).split(",").map(&:strip)
|
82
|
+
end
|
83
|
+
|
84
|
+
# @return [String] Application status as described by EPO
|
85
|
+
# @see EpoOps::PatentApplication#status
|
86
|
+
def status
|
87
|
+
EpoOps::Util.dig raw_data, data_path('status')
|
88
|
+
end
|
89
|
+
|
90
|
+
# @return [Array] Hashes of priority claims
|
91
|
+
# @see EpoOps::PatentApplication#priority_claims
|
92
|
+
def priority_claims
|
93
|
+
EpoOps::Util.flat_dig raw_data, data_path('priority_claims','priority_claim')
|
94
|
+
end
|
95
|
+
|
96
|
+
# @return [Array]
|
97
|
+
# @see EpoOps::PatentApplication#publication_references
|
98
|
+
def publication_references
|
99
|
+
EpoOps::Util.flat_dig raw_data, data_path('publication_reference', 'document_id')
|
100
|
+
end
|
101
|
+
|
102
|
+
# @return [Date]
|
103
|
+
# @see EpoOps::PatentApplication#effective_date
|
104
|
+
def effective_date
|
105
|
+
dates = EpoOps::Util.flat_dig raw_data, data_path('dates_rights_effective', 'request_for_examination')
|
106
|
+
dates.first.nil? ? nil : dates.first['date']
|
107
|
+
end
|
108
|
+
|
109
|
+
private
|
110
|
+
def data_path(*path)
|
111
|
+
%w(bibliographic_data) + path
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|