Rospatent

Gem Version

A comprehensive Ruby client for the Rospatent patent search API with advanced features including intelligent caching, input validation, structured logging, and robust error handling.

πŸ‡·πŸ‡Ί ДокумСнтация Π½Π° русском языкС доступна Π½ΠΈΠΆΠ΅

✨ Key Features

  • πŸ” Complete API Coverage - Search, retrieve patents, media files, and datasets
  • πŸ›‘οΈ Robust Error Handling - Comprehensive error types with detailed context
  • ⚑ Intelligent Caching - In-memory caching with TTL and LRU eviction
  • βœ… Input Validation - Automatic parameter validation with helpful error messages
  • πŸ“Š Structured Logging - JSON/text logging with request/response tracking
  • πŸš€ Batch Operations - Process multiple patents concurrently
  • βš™οΈ Environment-Aware - Different configurations for dev/staging/production
  • πŸ§ͺ Comprehensive Testing - 96% test coverage with integration tests
  • πŸ“š Excellent Documentation - Detailed examples and API documentation

Installation

Add this line to your application's Gemfile:

gem 'rospatent'

And then execute:

$ bundle install

Or install it yourself as:

$ gem install rospatent

Quick Start

# Basic configuration
Rospatent.configure do |config|
  config.token = "your_jwt_token"
end

# Create a client and search
client = Rospatent.client
results = client.search(q: "Ρ€Π°ΠΊΠ΅Ρ‚Π°", limit: 10)

puts "Found #{results.total} results"
results.hits.each do |hit|
  puts "Patent: #{hit['id']} - #{hit.dig('biblio', 'ru', 'title')}"
end

Configuration

Basic Configuration

Rospatent.configure do |config|
  # Required
  config.token = "your_jwt_token"

  # API settings
  config.api_url = "https://searchplatform.rospatent.gov.ru/patsearch/v0.2"
  config.timeout = 30
  config.retry_count = 3

  # Environment (development, staging, production)
  config.environment = "production"
end

Advanced Configuration

Rospatent.configure do |config|
  config.token = "your_jwt_token"

  # Caching (enabled by default)
  config.cache_enabled = true
  config.cache_ttl = 300              # 5 minutes
  config.cache_max_size = 1000        # Maximum cached items

  # Logging
  config.log_level = :info             # :debug, :info, :warn, :error
  config.log_requests = true           # Log API requests
  config.log_responses = true          # Log API responses

  # Connection settings
  config.connection_pool_size = 5
  config.connection_keep_alive = true

  # Token management
  config.token_expires_at = Time.now + 3600
  config.token_refresh_callback = -> { refresh_token! }
end

Environment Variables

Configure via environment variables:

ROSPATENT_ENV=production
ROSPATENT_CACHE_ENABLED=true
ROSPATENT_CACHE_TTL=600
ROSPATENT_LOG_LEVEL=info
ROSPATENT_POOL_SIZE=10

Environment-Specific Defaults

The gem automatically adjusts settings based on environment:

  • Development: Fast timeouts, verbose logging, short cache TTL
  • Staging: Moderate settings for testing
  • Production: Longer timeouts, optimized for reliability

Basic Usage

Searching Patents

client = Rospatent.client

# Simple text search
results = client.search(q: "Ρ€Π°ΠΊΠ΅Ρ‚Π°")

# Natural language search
results = client.search(qn: "rocket engine design")

# Advanced search with all options
results = client.search(
  q: "Ρ€Π°ΠΊΠ΅Ρ‚Π° AND Π΄Π²ΠΈΠ³Π°Ρ‚Π΅Π»ΡŒ",
  limit: 20,
  offset: 0,
  filter: {
    "classification.ipc_group": { "values": ["F02K9"] },
    "biblio.application_date": { "from": "2020-01-01" }
  },
  sort: :pub_date,
  group_by: :patent_family,
  include_facets: true,
  highlight: true,
  pre_tag: "<mark>",
  post_tag: "</mark>"
)

# Process results
puts "Found #{results.total} total results (#{results.available} available)"
puts "Showing #{results.count} results"

results.hits.each do |hit|
  puts "ID: #{hit['id']}"
  puts "Title: #{hit.dig('biblio', 'ru', 'title')}"
  puts "Date: #{hit.dig('biblio', 'publication_date')}"
  puts "IPC: #{hit.dig('classification', 'ipc')}"
  puts "---"
end

Retrieving Patent Documents

# Get patent by document ID
patent_doc = client.patent("RU134694U1_20131120")

# Get patent by components
patent_doc = client.patent_by_components(
  "RU",                    # country_code
  "134694",               # number
  "U1",                   # doc_type
  Date.new(2013, 11, 20)  # date (String or Date object)
)

# Access patent data
title = patent_doc.dig('biblio', 'ru', 'title')
abstract = patent_doc.dig('abstract', 'ru')
inventors = patent_doc.dig('biblio', 'ru', 'inventor')

Parsing Patent Content

Extract clean text or structured content from patents:

# Parse abstract
abstract_text = client.parse_abstract(patent_doc)
abstract_html = client.parse_abstract(patent_doc, format: :html)
abstract_en = client.parse_abstract(patent_doc, language: "en")

# Parse description
description_text = client.parse_description(patent_doc)
description_html = client.parse_description(patent_doc, format: :html)

# Get structured sections
sections = client.parse_description(patent_doc, format: :sections)
sections.each do |section|
  puts "Section #{section[:number]}: #{section[:content]}"
end

Finding Similar Patents

# Find similar patents by ID
similar = client.similar_patents_by_id("RU134694U1_20131120", count: 50)

# Find similar patents by text description
similar = client.similar_patents_by_text(
  "Π Π°ΠΊΠ΅Ρ‚Π½Ρ‹ΠΉ Π΄Π²ΠΈΠ³Π°Ρ‚Π΅Π»ΡŒ с ΡƒΠ»ΡƒΡ‡ΡˆΠ΅Π½Π½ΠΎΠΉ тягой ...", # 50 words in request minimum
  count: 25
)

# Process similar patents
similar["data"]&.each do |patent|
  puts "Similar: #{patent['id']} (score: #{patent['similarity']} (#{patent['similarity_norm']}))"
end

Search within patent classification systems (IPC and CPC) and get detailed information about classification codes:

# Search for classification codes related to rockets in IPC
ipc_results = client.classification_search("ipc", query: "Ρ€Π°ΠΊΠ΅Ρ‚Π°", lang: "ru")
puts "Found #{ipc_results.size} IPC codes"

ipc_results&.each do |result|
  puts "#{result['Code']}: #{result['Description']}"
end

# Search for rocket-related codes in CPC using English
cpc_results = client.classification_search("cpc", query: "rocket", lang: "en")

# Get detailed information about a specific classification code
code, info = client.classification_code("ipc", code: "F02K9/00", lang: "ru")&.first
puts "Code: #{code}"
puts "Description: #{info&.first['Description']}"
puts "Hierarchy: #{info&.map{|level| level['Code']}&.join(' β†’ ')}"

# Get CPC code information in English
cpc_info = client.classification_code("cpc", code: "B63H11/00", lang: "en")

Supported Classification Systems:

  • "ipc" - International Patent Classification (МПК)
  • "cpc" - Cooperative Patent Classification (БПК)

Supported Languages:

  • "ru" - Russian
  • "en" - English

Media and Documents

# Download patent PDF
pdf_data = client.patent_media(
  "National",        # collection_id
  "RU",             # country_code
  "U1",             # doc_type
  "2013/11/20",     # pub_date
  "134694",         # pub_number
  "document.pdf"    # filename
)
File.write("patent.pdf", pdf_data)

# Simplified method using patent ID
pdf_data = client.patent_media_by_id(
  "RU134694U1_20131120",
  "National",
  "document.pdf"
)

# Get available datasets
datasets.each do |category|
  puts "Category: #{category['name_en']}"
  category.children.each do |dataset|
    puts "  #{dataset['id']}: #{dataset['name_en']}"
  end
end

Advanced Features

Batch Operations

Process multiple patents efficiently with concurrent requests:

document_ids = ["RU134694U1_20131120", "RU2358138C1_20090610", "RU2756123C1_20210927"]

# Process patents in batches
client.batch_patents(document_ids, batch_size: 5) do |patent_doc|
  if patent_doc[:error]
    puts "Error for #{patent_doc[:document_id]}: #{patent_doc[:error]}"
  else
    puts "Retrieved patent: #{patent_doc['id']}"
    # Process patent document
  end
end

# Or collect all results
patents = []
client.batch_patents(document_ids) { |doc| patents << doc }

Caching

Automatic intelligent caching improves performance:

# Caching is automatic and transparent
patent1 = client.patent("RU134694U1_20131120")  # API call
patent2 = client.patent("RU134694U1_20131120")  # Cached result

# Check cache statistics
stats = client.statistics
puts "Cache hit rate: #{stats[:cache_stats][:hit_rate_percent]}%"
puts "Total requests: #{stats[:requests_made]}"
puts "Average response time: #{stats[:average_request_time]}s"

# Use shared cache across clients
shared_cache = Rospatent.shared_cache
client1 = Rospatent.client(cache: shared_cache)
client2 = Rospatent.client(cache: shared_cache)

# Manual cache management
shared_cache.clear                    # Clear all cached data
expired_count = shared_cache.cleanup_expired  # Remove expired entries
cache_stats = shared_cache.statistics # Get detailed cache statistics

Custom Logging

Configure detailed logging for monitoring and debugging:

# Create custom logger
logger = Rospatent::Logger.new(
  output: Rails.logger,  # Or any IO object
  level: :info,
  formatter: :json      # :json or :text
)

client = Rospatent.client(logger: logger)

# Logs include:
# - API requests/responses with timing
# - Cache operations (hits/misses)
# - Error details with context
# - Performance metrics

# Access shared logger
shared_logger = Rospatent.shared_logger(level: :debug)

Error Handling

Comprehensive error handling with specific error types:

begin
  patent = client.patent("INVALID_ID")
rescue Rospatent::Errors::ValidationError => e
  puts "Invalid input: #{e.message}"
  puts "Field errors: #{e.errors}" if e.errors.any?
rescue Rospatent::Errors::NotFoundError => e
  puts "Patent not found: #{e.message}"
rescue Rospatent::Errors::RateLimitError => e
  puts "Rate limited. Retry after: #{e.retry_after} seconds"
rescue Rospatent::Errors::AuthenticationError => e
  puts "Authentication failed: #{e.message}"
rescue Rospatent::Errors::ApiError => e
  puts "API error (#{e.status_code}): #{e.message}"
  puts "Request ID: #{e.request_id}" if e.request_id
  retry if e.retryable?
rescue Rospatent::Errors::ConnectionError => e
  puts "Connection error: #{e.message}"
  puts "Original error: #{e.original_error}"
end

Input Validation

All inputs are automatically validated with helpful error messages:

# These will raise ValidationError with specific messages:
client.search(limit: 0)                    # "Limit must be at least 1"
client.patent("")                          # "Document_id cannot be empty"
client.similar_patents_by_text("", count: -1)  # Multiple validation errors

# Validation includes:
# - Parameter types and formats
# - Patent ID format validation
# - Date format validation
# - Enum value validation
# - Required field validation

Performance Monitoring

Track performance and usage statistics:

# Client-specific statistics
stats = client.statistics
puts "Requests made: #{stats[:requests_made]}"
puts "Total duration: #{stats[:total_duration_seconds]}s"
puts "Average request time: #{stats[:average_request_time]}s"
puts "Cache hit rate: #{stats[:cache_stats][:hit_rate_percent]}%"

# Global statistics
global_stats = Rospatent.statistics
puts "Environment: #{global_stats[:configuration][:environment]}"
puts "Cache enabled: #{global_stats[:configuration][:cache_enabled]}"
puts "API URL: #{global_stats[:configuration][:api_url]}"

Environment Configuration

Development Environment

# Optimized for development
Rospatent.configure do |config|
  config.environment = "development"
  config.token = ENV['ROSPATENT_DEV_TOKEN']
  config.log_level = :debug
  config.log_requests = true
  config.log_responses = true
  config.cache_ttl = 60          # Short cache for development
  config.timeout = 10            # Fast timeouts for quick feedback
end

Staging Environment

# Optimized for staging
Rospatent.configure do |config|
  config.environment = "staging"
  config.token = ENV['ROSPATENT_TOKEN']
  config.log_level = :info
  config.cache_ttl = 300         # Longer cache for performance
  config.timeout = 45            # Longer timeouts for reliability
  config.retry_count = 3         # More retries for resilience
end

Production Environment

# Optimized for production
Rospatent.configure do |config|
  config.environment = "production"
  config.token = ENV['ROSPATENT_TOKEN']
  config.log_level = :warn
  config.cache_ttl = 600         # Longer cache for performance
  config.timeout = 60            # Longer timeouts for reliability
  config.retry_count = 5         # More retries for resilience
end

Configuration Validation

# Validate current configuration
errors = Rospatent.validate_configuration
if errors.any?
  puts "Configuration errors:"
  errors.each { |error| puts "  - #{error}" }
else
  puts "Configuration is valid βœ“"
end

Rails Integration

Generator

$ rails generate rospatent:install

This creates config/initializers/rospatent.rb:

Rospatent.configure do |config|
  config.token = Rails.application.credentials.rospatent_token
  config.environment = Rails.env
  config.cache_enabled = Rails.env.production?
  config.log_level = Rails.env.production? ? :warn : :debug
end

Using with Rails Logger

# In config/initializers/rospatent.rb
Rospatent.configure do |config|
  config.token = Rails.application.credentials.rospatent_token
end

# Create client with Rails logger
logger = Rospatent::Logger.new(
  output: Rails.logger,
  level: Rails.env.production? ? :warn : :debug,
  formatter: :text
)

# Use in controllers/services
class PatentService
  def initialize
    @client = Rospatent.client(logger: logger)
  end

  def search_patents(query)
    @client.search(q: query, limit: 20)
  rescue Rospatent::Errors::ApiError => e
    Rails.logger.error "Patent search failed: #{e.message}"
    raise
  end
end

Testing

Running Tests

# Run all tests
$ bundle exec rake test

# Run specific test file
$ bundle exec ruby -Itest test/unit/client_test.rb

# Run integration tests (requires API token)
$ ROSPATENT_INTEGRATION_TESTS=true ROSPATENT_TEST_TOKEN=your_token bundle exec rake test_integration

# Run with coverage
$ bundle exec rake coverage

Test Configuration

For testing, reset and configure in each test's setup method:

# test/test_helper.rb - Base setup for unit tests
module Minitest
  class Test
    def setup
      Rospatent.reset  # Clean state between tests
      Rospatent.configure do |config|
        config.token = ENV.fetch("ROSPATENT_TEST_TOKEN", "test_token")
        config.environment = "development"
        config.cache_enabled = false  # Disable cache for predictable tests
        config.log_level = :error     # Reduce test noise
      end
    end
  end
end

# For integration tests - stable config, no reset needed
class IntegrationTest < Minitest::Test
  def setup
    skip unless ENV["ROSPATENT_INTEGRATION_TESTS"]

    @token = ENV.fetch("ROSPATENT_TEST_TOKEN", nil)
    skip "ROSPATENT_TEST_TOKEN not set" unless @token

    # No reset needed - integration tests use consistent configuration
    Rospatent.configure do |config|
      config.token = @token
      config.environment = "development"
      config.cache_enabled = true
      config.log_level = :debug
    end
  end
end

Custom Assertions (Minitest)

# test/test_helper.rb
module Minitest
  class Test
    def assert_valid_patent_id(patent_id, message = nil)
      message ||= "Expected #{patent_id} to be a valid patent ID (format: XX12345Y1_YYYYMMDD)"
      assert patent_id.match?(/^[A-Z]{2}[A-Z0-9]+[A-Z]\d*_\d{8}$/), message
    end
  end
end

# Usage in tests
def test_patent_id_validation
  assert_valid_patent_id("RU134694U1_20131120")
  assert_valid_patent_id("RU134694A_20131120")
end

Known API Limitations

The library uses Faraday as the HTTP client with redirect support for all endpoints:

  • All endpoints (/search, /docs/{id}, /similar_search, /datasets/tree, etc.) - βœ… Working perfectly with Faraday
  • Redirect handling: Configured with faraday-follow_redirects middleware to handle server redirects automatically

⚠️ Minor server-side limitations:

  • Similar Patents by Text: Occasionally returns 503 Service Unavailable (a server-side issue, not a client implementation issue) ⚠️ Documentation inconsistencies:
  • Similar Patents: According to the documentation, the array of hits is named hits, but the real implementation uses the name data
  • Available Datasets: The name key in the real implementation has the localization suffix β€” name_ru, name_en

All core functionality works perfectly and is production-ready with a unified HTTP approach.

Error Reference

Error Hierarchy

Rospatent::Errors::Error (base)
β”œβ”€β”€ MissingTokenError
β”œβ”€β”€ ApiError
β”‚   β”œβ”€β”€ AuthenticationError (401)
β”‚   β”œβ”€β”€ NotFoundError (404)
β”‚   β”œβ”€β”€ RateLimitError (429)
β”‚   └── ServiceUnavailableError (503)
β”œβ”€β”€ ConnectionError
β”‚   └── TimeoutError
β”œβ”€β”€ InvalidRequestError
└── ValidationError

Common Error Scenarios

# Missing or invalid token
Rospatent::Errors::MissingTokenError
Rospatent::Errors::AuthenticationError

# Invalid input parameters
Rospatent::Errors::ValidationError

# Resource not found
Rospatent::Errors::NotFoundError

# Rate limiting
Rospatent::Errors::RateLimitError  # Check retry_after

# Network issues
Rospatent::Errors::ConnectionError
Rospatent::Errors::TimeoutError

# Server problems
Rospatent::Errors::ServiceUnavailableError

Rake Tasks

Useful development and maintenance tasks:

# Validate configuration
$ bundle exec rake validate

# Cache management
$ bundle exec rake cache:stats
$ bundle exec rake cache:clear

# Generate documentation
$ bundle exec rake doc

# Run integration tests
$ bundle exec rake test_integration

# Performance benchmarks
$ bundle exec rake benchmark

# Setup development environment
$ bundle exec rake setup

# Pre-release checks
$ bundle exec rake release_check

Performance Tips

  1. Use Caching: Enable caching for repeated requests
  2. Batch Operations: Use batch_patents for multiple documents
  3. Appropriate Limits: Don't request more data than needed
  4. Connection Reuse: Use the same client instance when possible
  5. Environment Configuration: Use production settings in production
# Good: Reuse client instance
client = Rospatent.client
patents = patent_ids.map { |id| client.patent(id) }

# Better: Use batch operations
patents = []
client.batch_patents(patent_ids) { |doc| patents << doc }

# Best: Use caching with shared instance
shared_client = Rospatent.client(cache: Rospatent.shared_cache)

Troubleshooting

Common Issues

Authentication Errors:

# Check token validity
errors = Rospatent.validate_configuration
puts errors if errors.any?

Network Timeouts:

# Increase timeout for slow connections
Rospatent.configure do |config|
  config.timeout = 120
  config.retry_count = 5
end

Memory Usage:

# Limit cache size for memory-constrained environments
Rospatent.configure do |config|
  config.cache_max_size = 100
  config.cache_ttl = 300
end

Debug API Calls:

# Enable detailed logging
Rospatent.configure do |config|
  config.log_level = :debug
  config.log_requests = true
  config.log_responses = true
end

Development

After checking out the repo, run bin/setup to install dependencies. Then, run rake test to run the tests.

Development Setup

$ git clone https://hub.mos.ru/ad/rospatent.git
$ cd rospatent
$ bundle install
$ bundle exec rake setup

Running Tests

# Unit tests
$ bundle exec rake test

# Integration tests (requires API token)
$ ROSPATENT_INTEGRATION_TESTS=true ROSPATENT_TEST_TOKEN=your_token bundle exec rake test_integration

# Code style
$ bundle exec rubocop

# All checks
$ bundle exec rake ci

Interactive Console

$ bin/console

Contributing

Bug reports and pull requests are welcome on MosHub at https://hub.mos.ru/ad/rospatent.

Development Guidelines

  1. Write Tests: Ensure all new features have corresponding tests
  2. Follow Style: Run rubocop and fix any style issues
  3. Document Changes: Update README and CHANGELOG
  4. Validate Configuration: Run rake validate before submitting

Release Process

# Pre-release checks
$ bundle exec rake release_check

# Update version and release
$ bundle exec rake release

πŸ“– ДокумСнтация Π½Π° русском языкС

ОписаниС

Rospatent β€” это комплСксный Ruby-ΠΊΠ»ΠΈΠ΅Π½Ρ‚ для взаимодСйствия с API поиска ΠΏΠ°Ρ‚Π΅Π½Ρ‚ΠΎΠ² РоспатСнта. Π‘ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ° прСдоставляСт ΡƒΠ΄ΠΎΠ±Π½Ρ‹ΠΉ интСрфСйс для поиска, получСния ΠΈ Π°Π½Π°Π»ΠΈΠ·Π° ΠΏΠ°Ρ‚Π΅Π½Ρ‚Π½ΠΎΠΉ ΠΈΠ½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΠΈ с автоматичСским ΠΊΠ΅ΡˆΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ΠΌ, Π²Π°Π»ΠΈΠ΄Π°Ρ†ΠΈΠ΅ΠΉ запросов ΠΈ ΠΏΠΎΠ΄Ρ€ΠΎΠ±Π½Ρ‹ΠΌ Π»ΠΎΠ³ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ΠΌ.

✨ ΠšΠ»ΡŽΡ‡Π΅Π²Ρ‹Π΅ возмоТности

  • πŸ” ПолноС ΠΏΠΎΠΊΡ€Ρ‹Ρ‚ΠΈΠ΅ API - поиск, ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½ΠΈΠ΅ ΠΏΠ°Ρ‚Π΅Π½Ρ‚ΠΎΠ², ΠΌΠ΅Π΄ΠΈΠ°Ρ„Π°ΠΉΠ»Ρ‹ ΠΈ датасСты
  • πŸ›‘οΈ НадСТная ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° ошибок - комплСксныС Ρ‚ΠΈΠΏΡ‹ ошибок с Π΄Π΅Ρ‚Π°Π»ΡŒΠ½Ρ‹ΠΌ контСкстом
  • ⚑ Π˜Π½Ρ‚Π΅Π»Π»Π΅ΠΊΡ‚ΡƒΠ°Π»ΡŒΠ½ΠΎΠ΅ ΠΊΠ΅ΡˆΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ - ΠΊΠ΅ΡˆΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ Π² памяти с TTL ΠΈ LRU ΠΈΡΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ΠΌ
  • βœ… Валидация Π²Ρ…ΠΎΠ΄Π½Ρ‹Ρ… Π΄Π°Π½Π½Ρ‹Ρ… - автоматичСская валидация ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ΠΎΠ² с ΠΏΠΎΠ»Π΅Π·Π½Ρ‹ΠΌΠΈ сообщСниями
  • πŸ“Š Π‘Ρ‚Ρ€ΡƒΠΊΡ‚ΡƒΡ€ΠΈΡ€ΠΎΠ²Π°Π½Π½ΠΎΠ΅ Π»ΠΎΠ³ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ - JSON/тСкстовоС Π»ΠΎΠ³ΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ с отслСТиваниСм запросов/ΠΎΡ‚Π²Π΅Ρ‚ΠΎΠ²
  • πŸš€ ΠŸΠ°ΠΊΠ΅Ρ‚Π½Ρ‹Π΅ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ - ΠΏΠ°Ρ€Π°Π»Π»Π΅Π»ΡŒΠ½Π°Ρ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° мноТСства ΠΏΠ°Ρ‚Π΅Π½Ρ‚ΠΎΠ²
  • βš™οΈ АдаптивныС окруТСния - Ρ€Π°Π·Π»ΠΈΡ‡Π½Ρ‹Π΅ ΠΊΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΠΈ для development/staging/production
  • πŸ§ͺ КомплСксноС тСстированиС - 96% ΠΏΠΎΠΊΡ€Ρ‹Ρ‚ΠΈΠ΅ тСстами с ΠΈΠ½Ρ‚Π΅Π³Ρ€Π°Ρ†ΠΈΠΎΠ½Π½Ρ‹ΠΌΠΈ тСстами
  • πŸ“š ΠžΡ‚Π»ΠΈΡ‡Π½Π°Ρ докумСнтация - ΠΏΠΎΠ΄Ρ€ΠΎΠ±Π½Ρ‹Π΅ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Ρ‹ ΠΈ докумСнтация API

Быстрый старт

Установка

Π”ΠΎΠ±Π°Π²ΡŒΡ‚Π΅ Π² ваш Gemfile:

gem 'rospatent'

Или установитС Π½Π°ΠΏΡ€ΡΠΌΡƒΡŽ:

$ gem install rospatent

Базовая настройка

require 'rospatent'

# Настройка ΠΊΠ»ΠΈΠ΅Π½Ρ‚Π°
Rospatent.configure do |config|
  config.token = "ваш_jwt_Ρ‚ΠΎΠΊΠ΅Π½"
end

# Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅ ΠΊΠ»ΠΈΠ΅Π½Ρ‚Π°
client = Rospatent.client

ОсновноС использованиС

Поиск ΠΏΠ°Ρ‚Π΅Π½Ρ‚ΠΎΠ²

# ΠŸΡ€ΠΎΡΡ‚ΠΎΠΉ поиск
results = client.search(q: "солнСчная батарСя")

# Π Π°ΡΡˆΠΈΡ€Π΅Π½Π½Ρ‹ΠΉ поиск с Ρ„ΠΈΠ»ΡŒΡ‚Ρ€Π°ΠΌΠΈ
results = client.search(
  q: "искусствСнный ΠΈΠ½Ρ‚Π΅Π»Π»Π΅ΠΊΡ‚",
  limit: 50,
  offset: 100,
  datasets: ["ru_since_1994"],
  sort: "pub_date:desc",
  highlight: true
)

# ΠžΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ΠΎΠ²
puts "НайдСно: #{results.total} ΠΏΠ°Ρ‚Π΅Π½Ρ‚ΠΎΠ²"
results.hits.each do |patent|
  puts "#{patent['id']}: #{patent['title']}"
end

ΠŸΠΎΠ»ΡƒΡ‡Π΅Π½ΠΈΠ΅ Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚ΠΎΠ² ΠΏΠ°Ρ‚Π΅Π½Ρ‚ΠΎΠ²

# По ΠΈΠ΄Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ‚ΠΎΡ€Ρƒ Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°
patent = client.patent("RU134694U1_20131120")

# ΠŸΠ°Ρ€ΡΠΈΠ½Π³ содСрТимого
abstract = client.parse_abstract(patent)
description = client.parse_description(patent, format: :text)

puts "Π Π΅Ρ„Π΅Ρ€Π°Ρ‚: #{abstract}"
puts "ОписаниС: #{description}"

Поиск ΠΏΠΎΡ…ΠΎΠΆΠΈΡ… ΠΏΠ°Ρ‚Π΅Π½Ρ‚ΠΎΠ²

# Поиск ΠΏΠΎΡ…ΠΎΠΆΠΈΡ… ΠΏΠ°Ρ‚Π΅Π½Ρ‚ΠΎΠ² ΠΏΠΎ ID
similar = client.similar_patents_by_id("RU134694U1_20131120", count: 50)

# Поиск ΠΏΠΎΡ…ΠΎΠΆΠΈΡ… ΠΏΠ°Ρ‚Π΅Π½Ρ‚ΠΎΠ² ΠΏΠΎ описанию тСкста
similar = client.similar_patents_by_text(
  "Π Π°ΠΊΠ΅Ρ‚Π½Ρ‹ΠΉ Π΄Π²ΠΈΠ³Π°Ρ‚Π΅Π»ΡŒ с ΡƒΠ»ΡƒΡ‡ΡˆΠ΅Π½Π½ΠΎΠΉ тягой ...", # ΠΌΠΈΠ½ΠΈΠΌΡƒΠΌ 50 слов Π² запросС
  count: 25
)

# ΠžΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° ΠΏΠΎΡ…ΠΎΠΆΠΈΡ… ΠΏΠ°Ρ‚Π΅Π½Ρ‚ΠΎΠ²
similar["data"]&.each do |patent|
  puts "ΠŸΠΎΡ…ΠΎΠΆΠΈΠΉ: #{patent['id']} (ΠΎΡ†Π΅Π½ΠΊΠ°: #{patent['similarity']} (#{patent['similarity_norm']}))"
end

Поиск ΠΏΠΎ классификаторам

Поиск Π² систСмах ΠΏΠ°Ρ‚Π΅Π½Ρ‚Π½ΠΎΠΉ классификации (IPC ΠΈ CPC) ΠΈ ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½ΠΈΠ΅ ΠΏΠΎΠ΄Ρ€ΠΎΠ±Π½ΠΎΠΉ ΠΈΠ½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΠΈ ΠΎ классификационных ΠΊΠΎΠ΄Π°Ρ…:

# Поиск классификационных ΠΊΠΎΠ΄ΠΎΠ², связанных с Ρ€Π°ΠΊΠ΅Ρ‚Π°ΠΌΠΈ Π² IPC
ipc_results = client.classification_search("ipc", query: "Ρ€Π°ΠΊΠ΅Ρ‚Π°", lang: "ru")
puts "НайдСно #{ipc_results.size} кодов IPC"

ipc_results&.each do |result|
  puts "#{result['Code']}: #{result['Description']}"
end

# Поиск ΠΊΠΎΠ΄ΠΎΠ², связанных с Ρ€Π°ΠΊΠ΅Ρ‚Π°ΠΌΠΈ Π² CPC Π½Π° английском
cpc_results = client.classification_search("cpc", query: "rocket", lang: "en")

# ΠŸΠΎΠ»ΡƒΡ‡Π΅Π½ΠΈΠ΅ ΠΏΠΎΠ΄Ρ€ΠΎΠ±Π½ΠΎΠΉ ΠΈΠ½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΠΈ ΠΎ ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½ΠΎΠΌ классификационном ΠΊΠΎΠ΄Π΅
code, info = client.classification_code("ipc", code: "F02K9/00", lang: "ru")&.first
puts "Код: #{code}"
puts "ОписаниС: #{info&.first['Description']}"
puts "Π˜Π΅Ρ€Π°Ρ€Ρ…ΠΈΡ: #{info&.map{|level| level['Code']}&.join(' β†’ ')}"

# ΠŸΠΎΠ»ΡƒΡ‡Π΅Π½ΠΈΠ΅ ΠΈΠ½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΠΈ ΠΎ ΠΊΠΎΠ΄Π΅ CPC Π½Π° английском
cpc_info = client.classification_code("cpc", code: "B63H11/00", lang: "en")

ΠŸΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΈΠ²Π°Π΅ΠΌΡ‹Π΅ систСмы классификации:

  • "ipc" - ΠœΠ΅ΠΆΠ΄ΡƒΠ½Π°Ρ€ΠΎΠ΄Π½Π°Ρ патСнтная классификация (МПК)
  • "cpc" - БовмСстная патСнтная классификация (БПК)

ΠŸΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΈΠ²Π°Π΅ΠΌΡ‹Π΅ языки:

  • "ru" - Русский
  • "en" - Английский

ΠœΠ΅Π΄ΠΈΠ°Ρ„Π°ΠΉΠ»Ρ‹ ΠΈ Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Ρ‹

# Π‘ΠΊΠ°Ρ‡ΠΈΠ²Π°Π½ΠΈΠ΅ PDF ΠΏΠ°Ρ‚Π΅Π½Ρ‚Π°
pdf_data = client.patent_media(
  "National",        # collection_id
  "RU",             # country_code
  "U1",             # doc_type
  "2013/11/20",     # pub_date
  "134694",         # pub_number
  "document.pdf"    # filename
)
File.write("patent.pdf", pdf_data)

# Π£ΠΏΡ€ΠΎΡ‰Π΅Π½Π½Ρ‹ΠΉ ΠΌΠ΅Ρ‚ΠΎΠ΄ с использованиСм ID ΠΏΠ°Ρ‚Π΅Π½Ρ‚Π°
pdf_data = client.patent_media_by_id(
  "RU134694U1_20131120",
  "National",
  "document.pdf"
)

# ΠŸΠΎΠ»ΡƒΡ‡Π΅Π½ΠΈΠ΅ доступных датасСтов
datasets = client.datasets_tree
datasets.each do |category|
  puts "ΠšΠ°Ρ‚Π΅Π³ΠΎΡ€ΠΈΡ: #{category['name_ru']}"
  category.children.each do |dataset|
    puts "  #{dataset['id']}: #{dataset['name_ru']}"
  end
end

Π Π°ΡΡˆΠΈΡ€Π΅Π½Π½Ρ‹Π΅ возмоТности

ΠŸΠ°ΠΊΠ΅Ρ‚Π½Ρ‹Π΅ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ

patent_ids = ["RU134694U1_20131120", "RU2358138C1_20090610"]

client.batch_patents(patent_ids) do |patent|
  puts "ΠžΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ°: #{patent['id']}"
  # Π’Π°ΡˆΠ° Π»ΠΎΠ³ΠΈΠΊΠ° ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ
end

ΠšΠ΅ΡˆΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅

# ΠšΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΡ кСша
Rospatent.configure do |config|
  config.cache_enabled = true
  config.cache_ttl = 600        # 10 ΠΌΠΈΠ½ΡƒΡ‚
  config.cache_max_size = 1000  # ΠœΠ°ΠΊΡΠΈΠΌΡƒΠΌ элСмСнтов
end

# Бтатистика кСша
stats = client.statistics
puts "Попаданий в кСш: #{stats[:cache_stats][:hits]}"

ΠžΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° ошибок

begin
  results = client.search(q: "поисковый запрос")
rescue Rospatent::Errors::AuthenticationError => e
  puts "Ошибка Π°ΡƒΡ‚Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ†ΠΈΠΈ: #{e.message}"
rescue Rospatent::Errors::RateLimitError => e
  puts "ΠŸΡ€Π΅Π²Ρ‹ΡˆΠ΅Π½ Π»ΠΈΠΌΠΈΡ‚ запросов: #{e.message}"
rescue Rospatent::Errors::ApiError => e
  puts "Ошибка API: #{e.message}"
end

Настройка окруТСния

Π Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠ°

# ΠžΠΏΡ‚ΠΈΠΌΠΈΠ·ΠΈΡ€ΠΎΠ²Π°Π½ΠΎ для Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ
Rospatent.configure do |config|
  config.environment = "development"
  config.token = ENV['ROSPATENT_DEV_TOKEN']
  config.log_level = :debug
  config.log_requests = true
  config.log_responses = true
  config.cache_ttl = 60          # ΠšΠΎΡ€ΠΎΡ‚ΠΊΠΈΠΉ кСш для Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ
  config.timeout = 10            # БыстрыС Ρ‚Π°ΠΉΠΌΠ°ΡƒΡ‚Ρ‹ для быстрой ΠΎΠ±Ρ€Π°Ρ‚Π½ΠΎΠΉ связи
end

Staging

# ΠžΠΏΡ‚ΠΈΠΌΠΈΠ·ΠΈΡ€ΠΎΠ²Π°Π½ΠΎ для staging
Rospatent.configure do |config|
  config.environment = "staging"
  config.token = ENV['ROSPATENT_TOKEN']
  config.log_level = :info
  config.cache_ttl = 300         # Π‘ΠΎΠ»Π΅Π΅ Π΄Π»ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹ΠΉ кСш для ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ
  config.timeout = 45            # Π‘ΠΎΠ»Π΅Π΅ Π΄Π»ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹Π΅ Ρ‚Π°ΠΉΠΌΠ°ΡƒΡ‚Ρ‹ для надСТности
  config.retry_count = 3         # Π‘ΠΎΠ»ΡŒΡˆΠ΅ ΠΏΠΎΠ²Ρ‚ΠΎΡ€ΠΎΠ² для устойчивости
end

ΠŸΡ€ΠΎΠ΄Π°ΠΊΡˆΠ½

# ΠžΠΏΡ‚ΠΈΠΌΠΈΠ·ΠΈΡ€ΠΎΠ²Π°Π½ΠΎ для ΠΏΡ€ΠΎΠ΄Π°ΠΊΡˆΠ½Π°
Rospatent.configure do |config|
  config.environment = "production"
  config.token = ENV['ROSPATENT_TOKEN']
  config.log_level = :warn
  config.cache_ttl = 600         # Π‘ΠΎΠ»Π΅Π΅ Π΄Π»ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹ΠΉ кСш для ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ
  config.timeout = 60            # Π‘ΠΎΠ»Π΅Π΅ Π΄Π»ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹Π΅ Ρ‚Π°ΠΉΠΌΠ°ΡƒΡ‚Ρ‹ для надСТности
  config.retry_count = 5         # Π‘ΠΎΠ»ΡŒΡˆΠ΅ ΠΏΠΎΠ²Ρ‚ΠΎΡ€ΠΎΠ² для устойчивости
end

Π˜Π½Ρ‚Π΅Π³Ρ€Π°Ρ†ΠΈΡ с Rails

# config/initializers/rospatent.rb
Rospatent.configure do |config|
  config.token = Rails.application.credentials.rospatent_token
  config.environment = Rails.env
  config.cache_enabled = Rails.env.production?
  config.log_level = Rails.env.production? ? :warn : :debug
end

# Π’ ΠΊΠΎΠ½Ρ‚Ρ€ΠΎΠ»Π»Π΅Ρ€Π΅ ΠΈΠ»ΠΈ сСрвисС
class PatentService
  def initialize
    @client = Rospatent.client
  end

  def search_patents(query, **options)
    @client.search(q: query, **options)
  end
end

Π˜Π·Π²Π΅ΡΡ‚Π½Ρ‹Π΅ ограничСния API

Π‘ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ° ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ Faraday Π² качСствС HTTP-ΠΊΠ»ΠΈΠ΅Π½Ρ‚Π° с ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΊΠΎΠΉ Ρ€Π΅Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΎΠ² для всСх endpoints:

  • ВсС endpoints (/search, /docs/{id}, /similar_search, /datasets/tree, ΠΈ Ρ‚.Π΄.) - βœ… Π Π°Π±ΠΎΡ‚Π°ΡŽΡ‚ идСально с Faraday
  • ΠžΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ° Ρ€Π΅Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΎΠ²: НастроСна с middleware faraday-follow_redirects для автоматичСской ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ сСрвСрных Ρ€Π΅Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΎΠ²

⚠️ ΠΠ΅Π·Π½Π°Ρ‡ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹Π΅ сСрвСрныС ограничСния:

  • Поиск ΠΏΠΎΡ…ΠΎΠΆΠΈΡ… ΠΏΠ°Ρ‚Π΅Π½Ρ‚ΠΎΠ² ΠΏΠΎ тСксту: Иногда Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ 503 Service Unavailable (ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΠ° сСрвСра, Π½Π΅ клиСнтской Ρ€Π΅Π°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ) ⚠️ НСточности Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°Ρ†ΠΈΠΈ:
  • Поиск ΠΏΠΎΡ…ΠΎΠΆΠΈΡ… ΠΏΠ°Ρ‚Π΅Π½Ρ‚ΠΎΠ²: Массив совпадСний Π² Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°Ρ†ΠΈΠΈ Π½Π°Π·Π²Π°Π½ hits, фактичСская рСализация ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ data
  • ΠŸΠ΅Ρ€Π΅Ρ‡Π΅Π½ΡŒ датасСтов: ΠšΠ»ΡŽΡ‡ name Π² фактичСской Ρ€Π΅Π°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ содСрТит ΠΏΡ€ΠΈΠ·Π½Π°ΠΊ Π»ΠΎΠΊΠ°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ β€” name_ru, name_en

Вся основная Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΎΠ½Π°Π»ΡŒΠ½ΠΎΡΡ‚ΡŒ Ρ€Π΅Π°Π»ΠΈΠ·ΠΎΠ²Π°Π½Π° ΠΈ Π³ΠΎΡ‚ΠΎΠ²Π° для ΠΏΡ€ΠΎΠ΄Π°ΠΊΡˆΠ΅Π½Π°.

Π‘ΠΏΡ€Π°Π²ΠΎΡ‡Π½ΠΈΠΊ ошибок

Π˜Π΅Ρ€Π°Ρ€Ρ…ΠΈΡ ошибок

Rospatent::Errors::Error (базовая)
β”œβ”€β”€ MissingTokenError
β”œβ”€β”€ ApiError
β”‚   β”œβ”€β”€ AuthenticationError (401)
β”‚   β”œβ”€β”€ NotFoundError (404)
β”‚   β”œβ”€β”€ RateLimitError (429)
β”‚   └── ServiceUnavailableError (503)
β”œβ”€β”€ ConnectionError
β”‚   └── TimeoutError
β”œβ”€β”€ InvalidRequestError
└── ValidationError

РаспространСнныС сцСнарии ошибок

# ΠžΡ‚ΡΡƒΡ‚ΡΡ‚Π²ΡƒΡŽΡ‰ΠΈΠΉ ΠΈΠ»ΠΈ Π½Π΅Π΄Π΅ΠΉΡΡ‚Π²ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹ΠΉ Ρ‚ΠΎΠΊΠ΅Π½
Rospatent::Errors::MissingTokenError
Rospatent::Errors::AuthenticationError

# ΠΠ΅Π΄Π΅ΠΉΡΡ‚Π²ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹Π΅ Π²Ρ…ΠΎΠ΄Π½Ρ‹Π΅ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Ρ‹
Rospatent::Errors::ValidationError

# РСсурс Π½Π΅ Π½Π°ΠΉΠ΄Π΅Π½
Rospatent::Errors::NotFoundError

# ΠžΠ³Ρ€Π°Π½ΠΈΡ‡Π΅Π½ΠΈΠ΅ скорости
Rospatent::Errors::RateLimitError  # ΠŸΡ€ΠΎΠ²Π΅Ρ€ΡŒΡ‚Π΅ retry_after

# ΠŸΡ€ΠΎΠ±Π»Π΅ΠΌΡ‹ с ΡΠ΅Ρ‚ΡŒΡŽ
Rospatent::Errors::ConnectionError
Rospatent::Errors::TimeoutError

# ΠŸΡ€ΠΎΠ±Π»Π΅ΠΌΡ‹ сСрвСра
Rospatent::Errors::ServiceUnavailableError

ВСстированиС

Запуск тСстов

# ВсС тСсты
$ bundle exec rake test

# ΠšΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½Ρ‹ΠΉ тСстовый Ρ„Π°ΠΉΠ»
$ bundle exec ruby -Itest test/unit/client_test.rb

# Π˜Π½Ρ‚Π΅Π³Ρ€Π°Ρ†ΠΈΠΎΠ½Π½Ρ‹Π΅ тСсты (трСбуСтся API Ρ‚ΠΎΠΊΠ΅Π½)
$ ROSPATENT_INTEGRATION_TESTS=true ROSPATENT_TEST_TOKEN=ваш_Ρ‚ΠΎΠΊΠ΅Π½ bundle exec rake test_integration

# Запуск с ΠΏΠΎΠΊΡ€Ρ‹Ρ‚ΠΈΠ΅ΠΌ
$ bundle exec rake coverage

Настройка тСстов

# test/test_helper.rb
module Minitest
  class Test
    def setup
      Rospatent.reset
      Rospatent.configure do |config|
        config.token = ENV.fetch("ROSPATENT_TEST_TOKEN", "test_token")
        config.environment = "development"
        config.cache_enabled = false
        config.log_level = :error
      end
    end
  end
end

Π‘ΠΎΠ²Π΅Ρ‚Ρ‹ ΠΏΠΎ ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ

  1. Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉΡ‚Π΅ ΠΊΠ΅ΡˆΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅: Π’ΠΊΠ»ΡŽΡ‡ΠΈΡ‚Π΅ ΠΊΠ΅ΡˆΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ для ΠΏΠΎΠ²Ρ‚ΠΎΡ€ΡΡŽΡ‰ΠΈΡ…ΡΡ запросов
  2. ΠŸΠ°ΠΊΠ΅Ρ‚Π½Ρ‹Π΅ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ: Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉΡ‚Π΅ batch_patents для мноТСства Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚ΠΎΠ²
  3. ΠŸΠΎΠ΄Ρ…ΠΎΠ΄ΡΡ‰ΠΈΠ΅ Π»ΠΈΠΌΠΈΡ‚Ρ‹: НС Π·Π°ΠΏΡ€Π°ΡˆΠΈΠ²Π°ΠΉΡ‚Π΅ большС Π΄Π°Π½Π½Ρ‹Ρ…, Ρ‡Π΅ΠΌ Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ
  4. ΠŸΠ΅Ρ€Π΅ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Π½ΠΈΠ΅ соСдинСний: Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉΡ‚Π΅ ΠΎΠ΄ΠΈΠ½ экзСмпляр ΠΊΠ»ΠΈΠ΅Π½Ρ‚Π° ΠΊΠΎΠ³Π΄Π° Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎ
  5. ΠšΠΎΠ½Ρ„ΠΈΠ³ΡƒΡ€Π°Ρ†ΠΈΡ окруТСния: Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉΡ‚Π΅ ΠΏΡ€ΠΎΠ΄Π°ΠΊΡˆΠ½ настройки Π² ΠΏΡ€ΠΎΠ΄Π°ΠΊΡˆΠ½Π΅
# Π₯ΠΎΡ€ΠΎΡˆΠΎ: ΠŸΠ΅Ρ€Π΅ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Π½ΠΈΠ΅ экзСмпляра ΠΊΠ»ΠΈΠ΅Π½Ρ‚Π°
client = Rospatent.client
patents = patent_ids.map { |id| client.patent(id) }

# Π›ΡƒΡ‡ΡˆΠ΅: ИспользованиС ΠΏΠ°ΠΊΠ΅Ρ‚Π½Ρ‹Ρ… ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΉ
patents = []
client.batch_patents(patent_ids) { |doc| patents << doc }

# ΠžΡ‚Π»ΠΈΡ‡Π½ΠΎ: ИспользованиС ΠΊΠ΅ΡˆΠΈΡ€ΠΎΠ²Π°Π½ΠΈΡ с ΠΎΠ±Ρ‰ΠΈΠΌ экзСмпляром
shared_client = Rospatent.client(cache: Rospatent.shared_cache)

УстранСниС Π½Π΅ΠΏΠΎΠ»Π°Π΄ΠΎΠΊ

ЧастыС ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΡ‹

Ошибки Π°ΡƒΡ‚Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ†ΠΈΠΈ:

# ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° валидности Ρ‚ΠΎΠΊΠ΅Π½Π°
errors = Rospatent.validate_configuration
puts errors if errors.any?

Π’Π°ΠΉΠΌΠ°ΡƒΡ‚Ρ‹ сСти:

# Π£Π²Π΅Π»ΠΈΡ‡Π΅Π½ΠΈΠ΅ Ρ‚Π°ΠΉΠΌΠ°ΡƒΡ‚Π° для ΠΌΠ΅Π΄Π»Π΅Π½Π½Ρ‹Ρ… соСдинСний
Rospatent.configure do |config|
  config.timeout = 120
  config.retry_count = 5
end

ИспользованиС памяти:

# ΠžΠ³Ρ€Π°Π½ΠΈΡ‡Π΅Π½ΠΈΠ΅ Ρ€Π°Π·ΠΌΠ΅Ρ€Π° кСша для ΠΎΠΊΡ€ΡƒΠΆΠ΅Π½ΠΈΠΉ с ΠΎΠ³Ρ€Π°Π½ΠΈΡ‡Π΅Π½Π½ΠΎΠΉ ΠΏΠ°ΠΌΡΡ‚ΡŒΡŽ
Rospatent.configure do |config|
  config.cache_max_size = 100
  config.cache_ttl = 300
end

ΠžΡ‚Π»Π°Π΄ΠΊΠ° API Π²Ρ‹Π·ΠΎΠ²ΠΎΠ²:

# Π’ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ ΠΏΠΎΠ΄Ρ€ΠΎΠ±Π½ΠΎΠ³ΠΎ логирования
Rospatent.configure do |config|
  config.log_level = :debug
  config.log_requests = true
  config.log_responses = true
end

Changelog

See CHANGELOG.md for detailed version history.

License

The gem is available as open source under the terms of the MIT License.


API Reference

For detailed API documentation, see the generated documentation or run:

$ bundle exec rake doc
$ open doc/index.html

Key Classes:

  • Rospatent::Client - Main API client
  • Rospatent::Configuration - Configuration management
  • Rospatent::Cache - Caching system
  • Rospatent::Logger - Structured logging
  • Rospatent::SearchResult - Search result wrapper
  • Rospatent::PatentParser - Patent content parsing

Classification Features:

  • Classification system search (IPC/CPC)
  • Detailed classification code information
  • Multi-language support (Russian/English)
  • Automatic caching of classification data

Patent Features:

  • Patent search by text
  • Patent details retrieval
  • Patent classification retrieval
  • Patent content parsing
  • Patent media retrieval
  • Patent similarity search by text
  • Patent similarity search by ID

Supported Ruby Versions: Ruby 3.3.0+