epo-ops 0.2.6 → 0.3.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 +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
|