rospatent 1.3.1 โ†’ 1.4.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 01cd0ab72ae339b3dab5372eebb311b6aef97fbc17f4fe8c4c00466aee363abe
4
- data.tar.gz: d279cbbe0944f3f55890b62593b4480359222bae51b2c3c132baaf07d55c0347
3
+ metadata.gz: 415bcf677cca43f775fb9ddca9d7c11093a7f2bce4cc0298be375ffe1f1912fc
4
+ data.tar.gz: e7c9111a4230c5624137f380511e248e8b177dfd30fa583133c4788fc0e09917
5
5
  SHA512:
6
- metadata.gz: d9f33a05a5c1b57b87baf0091300c0b46587b0567ba4def4ae1e635449a9ac7ec0d077bb630b32b2445111429ce7e86c9291daceb5ac75182bf44eb1beb5d16c
7
- data.tar.gz: 950400777375b018839a8a1090db421994c36a28d0e3881b783236e50d6d5dd43ef5d0a65f9c010cd878f54aa31cb55af74b540c8240676dbcf65bc74ea39743
6
+ metadata.gz: c74bd899f8263fee6097bb7157d6a628f922ac4a43e36264639892b5e1d9359850b4b1cba869711a764d4ec4d55dabd81efa9432b51507bbae2c0f30c0af40e8
7
+ data.tar.gz: e5a9b87840af75812374e881e00184527c5c82a5d0d7589c1512c838524b958063e200366d44a70b0f1e8bf020227a3e5a72ed99abafad3bd65e0e357927422c
data/CHANGELOG.md CHANGED
@@ -5,6 +5,43 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.4.0] - 2025-06-09
9
+
10
+ ### Added
11
+ - **Optional Filename Parameter**: Enhanced `patent_media` and `patent_media_by_id` methods with optional filename parameter
12
+ - Auto-generated filenames using formatted publication number + ".pdf" extension (e.g., "0000134694.pdf")
13
+ - Leverages existing `format_publication_number` logic for reliable API compatibility
14
+ - Provides convenient default behavior while maintaining full backward compatibility
15
+ - **Safe Binary File Handling**: New `save_binary_file` method for proper encoding of binary data
16
+ - Ensures binary data (PDFs, images, etc.) is written correctly with ASCII-8BIT encoding
17
+ - Prevents encoding conversion errors when saving media files
18
+ - Includes comprehensive documentation and examples
19
+
20
+ ### Fixed
21
+ - **Binary Data Encoding Issues**: Enhanced `handle_binary_response` method to properly handle binary data encoding
22
+ - Forces ASCII-8BIT encoding to prevent UTF-8 conversion errors
23
+ - Resolves `Encoding::UndefinedConversionError` when saving PDF and image files
24
+ - Maintains proper binary data integrity throughout the request lifecycle
25
+
26
+ ### Changed
27
+ - **Enhanced Media Method Documentation**: Updated documentation with auto-generated filename examples
28
+ - Added examples showing both convenience (auto-filename) and explicit filename approaches
29
+ - Enhanced code examples in both English and Russian README sections
30
+ - Improved documentation structure with clear usage recommendations
31
+ - **Comprehensive Test Coverage**: Enhanced test suite with auto-generated filename functionality
32
+ - Added specific tests for optional filename parameter behavior
33
+ - Updated existing tests to accommodate new method signatures
34
+ - Enhanced integration tests with fallback filename strategies
35
+ - **README Improvements**: Updated Key Features section to remove hardcoded test counts
36
+ - Replaced specific numbers with qualitative descriptions of testing coverage
37
+ - Improved maintainability by removing numbers that become outdated quickly
38
+ - Enhanced focus on testing quality rather than raw metrics
39
+
40
+ ## [1.3.2] - 2025-06-07
41
+
42
+ ### Added
43
+ - Notes about logger `formatter` parameter behavior when using `Rails.logger` as `output`
44
+
8
45
  ## [1.3.1] - 2025-06-06
9
46
 
10
47
  ### Fixed
data/README.md CHANGED
@@ -15,7 +15,7 @@ A comprehensive Ruby client for the Rospatent patent search API with advanced fe
15
15
  - ๐Ÿ“Š **Structured Logging** - JSON/text logging with request/response tracking
16
16
  - ๐Ÿš€ **Batch Operations** - Process multiple patents concurrently
17
17
  - โš™๏ธ **Environment-Aware** - Different configurations for dev/staging/production
18
- - ๐Ÿงช **Comprehensive Testing** - 232 tests with 483 assertions, comprehensive integration testing
18
+ - ๐Ÿงช **Comprehensive Testing** - Extensive unit and integration test coverage with robust error handling validation
19
19
  - ๐Ÿ“š **Excellent Documentation** - Detailed examples and API documentation
20
20
 
21
21
  ## Installation
@@ -583,23 +583,48 @@ end
583
583
  ### Media and Documents
584
584
 
585
585
  ```ruby
586
- # Download patent PDF
586
+ # โœ… Recommended: Download patent PDF with auto-generated filename
587
+ # Automatically uses the formatted publication number (e.g., "0000134694.pdf")
588
+ pdf_data = client.patent_media(
589
+ "National", # collection_id
590
+ "RU", # country_code
591
+ "U1", # doc_type
592
+ "2013/11/20", # pub_date
593
+ "134694" # pub_number (filename auto-generated)
594
+ )
595
+ client.save_binary_file(pdf_data, "patent.pdf")
596
+
597
+ # โœ… Alternative: Download with explicit filename
587
598
  pdf_data = client.patent_media(
588
599
  "National", # collection_id
589
600
  "RU", # country_code
590
601
  "U1", # doc_type
591
602
  "2013/11/20", # pub_date
592
603
  "134694", # pub_number
593
- "document.pdf" # filename
604
+ "document.pdf" # explicit filename
594
605
  )
595
- File.write("patent.pdf", pdf_data)
606
+ client.save_binary_file(pdf_data, "patent_explicit.pdf")
596
607
 
597
- # Simplified method using patent ID
608
+ # โœ… Simplified method using patent ID (auto-generated filename)
598
609
  pdf_data = client.patent_media_by_id(
599
610
  "RU134694U1_20131120",
600
- "National",
601
- "document.pdf"
611
+ "National" # filename auto-generated as "0000134694.pdf"
612
+ )
613
+ client.save_binary_file(pdf_data, "patent_by_id.pdf")
614
+
615
+ # โœ… Or with explicit filename for specific files
616
+ image_data = client.patent_media_by_id(
617
+ "RU134694U1_20131120",
618
+ "National",
619
+ "image.png" # explicit filename for non-PDF files
602
620
  )
621
+ client.save_binary_file(image_data, "patent_image.png")
622
+
623
+ # โœ… Safe file saving options:
624
+ File.binwrite("patent.pdf", pdf_data) # Manual binary write
625
+
626
+ # โŒ Avoid: File.write can cause encoding errors with binary data
627
+ # File.write("patent.pdf", pdf_data) # This may fail!
603
628
  ```
604
629
 
605
630
  ## Advanced Features
@@ -676,6 +701,10 @@ client = Rospatent.client(logger: logger)
676
701
  shared_logger = Rospatent.shared_logger(level: :debug)
677
702
  ```
678
703
 
704
+ **Notes**:
705
+ - When using `Rails.logger`, formatting is controlled by Rails configuration, `formatter` parameter ignored
706
+ - When using IO objects, `formatter` parameter controls output format
707
+
679
708
  ### Error Handling
680
709
 
681
710
  Comprehensive error handling with specific error types and improved error message extraction:
@@ -1101,7 +1130,7 @@ $ bundle exec rake release
1101
1130
  - ๐Ÿ“Š **ะกั‚ั€ัƒะบั‚ัƒั€ะธั€ะพะฒะฐะฝะฝะพะต ะปะพะณะธั€ะพะฒะฐะฝะธะต** - JSON/ั‚ะตะบัั‚ะพะฒะพะต ะปะพะณะธั€ะพะฒะฐะฝะธะต ั ะพั‚ัะปะตะถะธะฒะฐะฝะธะตะผ ะทะฐะฟั€ะพัะพะฒ/ะพั‚ะฒะตั‚ะพะฒ
1102
1131
  - ๐Ÿš€ **ะŸะฐะบะตั‚ะฝั‹ะต ะพะฟะตั€ะฐั†ะธะธ** - ะฟะฐั€ะฐะปะปะตะปัŒะฝะฐั ะพะฑั€ะฐะฑะพั‚ะบะฐ ะผะฝะพะถะตัั‚ะฒะฐ ะฟะฐั‚ะตะฝั‚ะพะฒ
1103
1132
  - โš™๏ธ **ะะดะฐะฟั‚ะธะฒะฝั‹ะต ะพะบั€ัƒะถะตะฝะธั** - ั€ะฐะทะปะธั‡ะฝั‹ะต ะบะพะฝั„ะธะณัƒั€ะฐั†ะธะธ ะดะปั development/staging/production
1104
- - ๐Ÿงช **ะšะพะผะฟะปะตะบัะฝะพะต ั‚ะตัั‚ะธั€ะพะฒะฐะฝะธะต** - 232 ั‚ะตัั‚ะฐ ั 483 ะฟั€ะพะฒะตั€ะบะฐะผะธ, ะบะพะผะฟะปะตะบัะฝะพะต ะธะฝั‚ะตะณั€ะฐั†ะธะพะฝะฝะพะต ั‚ะตัั‚ะธั€ะพะฒะฐะฝะธะต
1133
+ - ๐Ÿงช **ะšะพะผะฟะปะตะบัะฝะพะต ั‚ะตัั‚ะธั€ะพะฒะฐะฝะธะต** - ะžะฑัˆะธั€ะฝะพะต ะฟะพะบั€ั‹ั‚ะธะต ะผะพะดัƒะปัŒะฝั‹ะผะธ ะธ ะธะฝั‚ะตะณั€ะฐั†ะธะพะฝะฝั‹ะผะธ ั‚ะตัั‚ะฐะผะธ ั ะฒะฐะปะธะดะฐั†ะธะตะน ะพะฑั€ะฐะฑะพั‚ะบะธ ะพัˆะธะฑะพะบ
1105
1134
  - ๐Ÿ“š **ะžั‚ะปะธั‡ะฝะฐั ะดะพะบัƒะผะตะฝั‚ะฐั†ะธั** - ะฟะพะดั€ะพะฑะฝั‹ะต ะฟั€ะธะผะตั€ั‹ ะธ ะดะพะบัƒะผะตะฝั‚ะฐั†ะธั API
1106
1135
 
1107
1136
  ## ะฃัั‚ะฐะฝะพะฒะบะฐ
@@ -1665,23 +1694,48 @@ end
1665
1694
  ### ะœะตะดะธะฐั„ะฐะนะปั‹ ะธ ะดะพะบัƒะผะตะฝั‚ั‹
1666
1695
 
1667
1696
  ```ruby
1668
- # ะกะบะฐั‡ะธะฒะฐะฝะธะต PDF ะฟะฐั‚ะตะฝั‚ะฐ
1697
+ # โœ… ะ ะตะบะพะผะตะฝะดัƒะตั‚ัั: ะกะบะฐั‡ะธะฒะฐะฝะธะต PDF ะฟะฐั‚ะตะฝั‚ะฐ ั ะฐะฒั‚ะพะผะฐั‚ะธั‡ะตัะบะธ ะณะตะฝะตั€ะธั€ัƒะตะผั‹ะผ ะธะผะตะฝะตะผ ั„ะฐะนะปะฐ
1698
+ # ะะฒั‚ะพะผะฐั‚ะธั‡ะตัะบะธ ะธัะฟะพะปัŒะทัƒะตั‚ ะพั‚ั„ะพั€ะผะฐั‚ะธั€ะพะฒะฐะฝะฝั‹ะน ะฝะพะผะตั€ ะฟัƒะฑะปะธะบะฐั†ะธะธ (ะฝะฐะฟั€ะธะผะตั€, "0000134694.pdf")
1699
+ pdf_data = client.patent_media(
1700
+ "National", # collection_id
1701
+ "RU", # country_code
1702
+ "U1", # doc_type
1703
+ "2013/11/20", # pub_date
1704
+ "134694" # pub_number (ะธะผั ั„ะฐะนะปะฐ ะณะตะฝะตั€ะธั€ัƒะตั‚ัั ะฐะฒั‚ะพะผะฐั‚ะธั‡ะตัะบะธ)
1705
+ )
1706
+ client.save_binary_file(pdf_data, "patent.pdf")
1707
+
1708
+ # โœ… ะะปัŒั‚ะตั€ะฝะฐั‚ะธะฒะฐ: ะกะบะฐั‡ะธะฒะฐะฝะธะต ั ัะฒะฝั‹ะผ ัƒะบะฐะทะฐะฝะธะตะผ ะธะผะตะฝะธ ั„ะฐะนะปะฐ
1669
1709
  pdf_data = client.patent_media(
1670
1710
  "National", # collection_id
1671
1711
  "RU", # country_code
1672
1712
  "U1", # doc_type
1673
1713
  "2013/11/20", # pub_date
1674
1714
  "134694", # pub_number
1675
- "document.pdf" # filename
1715
+ "document.pdf" # ัะฒะฝะพะต ะธะผั ั„ะฐะนะปะฐ
1676
1716
  )
1677
- File.write("patent.pdf", pdf_data)
1717
+ client.save_binary_file(pdf_data, "patent_explicit.pdf")
1678
1718
 
1679
- # ะฃะฟั€ะพั‰ะตะฝะฝั‹ะน ะผะตั‚ะพะด ั ะธัะฟะพะปัŒะทะพะฒะฐะฝะธะตะผ ID ะฟะฐั‚ะตะฝั‚ะฐ
1719
+ # โœ… ะฃะฟั€ะพั‰ะตะฝะฝั‹ะน ะผะตั‚ะพะด ั ะธัะฟะพะปัŒะทะพะฒะฐะฝะธะตะผ ID ะฟะฐั‚ะตะฝั‚ะฐ (ะฐะฒั‚ะพะณะตะฝะตั€ะธั€ัƒะตะผะพะต ะธะผั)
1680
1720
  pdf_data = client.patent_media_by_id(
1681
1721
  "RU134694U1_20131120",
1682
- "National",
1683
- "document.pdf"
1722
+ "National" # ะธะผั ั„ะฐะนะปะฐ ะฐะฒั‚ะพะผะฐั‚ะธั‡ะตัะบะธ ะณะตะฝะตั€ะธั€ัƒะตั‚ัั ะบะฐะบ "0000134694.pdf"
1723
+ )
1724
+ client.save_binary_file(pdf_data, "patent_by_id.pdf")
1725
+
1726
+ # โœ… ะ˜ะปะธ ั ัะฒะฝั‹ะผ ะธะผะตะฝะตะผ ั„ะฐะนะปะฐ ะดะปั ะบะพะฝะบั€ะตั‚ะฝั‹ั… ั„ะฐะนะปะพะฒ
1727
+ image_data = client.patent_media_by_id(
1728
+ "RU134694U1_20131120",
1729
+ "National",
1730
+ "image.png" # ัะฒะฝะพะต ะธะผั ั„ะฐะนะปะฐ ะดะปั ั„ะฐะนะปะพะฒ ะฝะต-PDF
1684
1731
  )
1732
+ client.save_binary_file(image_data, "patent_image.png")
1733
+
1734
+ # โœ… ะ’ะฐั€ะธะฐะฝั‚ั‹ ะฑะตะทะพะฟะฐัะฝะพะณะพ ัะพั…ั€ะฐะฝะตะฝะธั ั„ะฐะนะปะพะฒ:
1735
+ File.binwrite("patent.pdf", pdf_data) # ะ ัƒั‡ะฝะฐั ะฑะธะฝะฐั€ะฝะฐั ะทะฐะฟะธััŒ
1736
+
1737
+ # โŒ ะ˜ะทะฑะตะณะฐะนั‚ะต: File.write ะผะพะถะตั‚ ะฒั‹ะทะฒะฐั‚ัŒ ะพัˆะธะฑะบะธ ะบะพะดะธั€ะพะฒะบะธ ั ะฑะธะฝะฐั€ะฝั‹ะผะธ ะดะฐะฝะฝั‹ะผะธ
1738
+ # File.write("patent.pdf", pdf_data) # ะญั‚ะพ ะผะพะถะตั‚ ะฝะต ัั€ะฐะฑะพั‚ะฐั‚ัŒ!
1685
1739
  ```
1686
1740
 
1687
1741
  ## ะ ะฐััˆะธั€ะตะฝะฝั‹ะต ะฒะพะทะผะพะถะฝะพัั‚ะธ
@@ -1758,6 +1812,10 @@ client = Rospatent.client(logger: logger)
1758
1812
  shared_logger = Rospatent.shared_logger(level: :debug)
1759
1813
  ```
1760
1814
 
1815
+ **ะšะพะผะผะตะฝั‚ะฐั€ะธะธ**:
1816
+ - ะŸั€ะธ ะธัะฟะพะปัŒะทะพะฒะฐะฝะธะธ `Rails.logger`, ั„ะพั€ะผะฐั‚ะธั€ะพะฒะฐะฝะธะต ะบะพะฝั‚ั€ะพะปะธั€ัƒะตั‚ัั ะบะพะฝั„ะธะณัƒั€ะฐั†ะธะตะน Rails, ะฟะฐั€ะฐะผะตั‚ั€ `formatter` ะธะณะฝะพั€ะธั€ัƒะตั‚ัั
1817
+ - ะŸั€ะธ ะธัะฟะพะปัŒะทะพะฒะฐะฝะธะธ IO ะพะฑัŠะตะบั‚ะฐ, ั„ะพั€ะผะฐั‚ ะพะฟั€ะตะดะตะปัะตั‚ัั ะฟะฐั€ะฐะผะตั‚ั€ะพะผ `formatter`
1818
+
1761
1819
  ### ะžะฑั€ะฐะฑะพั‚ะบะฐ ะพัˆะธะฑะพะบ
1762
1820
 
1763
1821
  ะšะพะผะฟะปะตะบัะฝะฐั ะพะฑั€ะฐะฑะพั‚ะบะฐ ะพัˆะธะฑะพะบ ั ะบะพะฝะบั€ะตั‚ะฝั‹ะผะธ ั‚ะธะฟะฐะผะธ ะพัˆะธะฑะพะบ ะธ ัƒะปัƒั‡ัˆะตะฝะฝั‹ะผ ะธะทะฒะปะตั‡ะตะฝะธะตะผ ัะพะพะฑั‰ะตะฝะธะน ะพะฑ ะพัˆะธะฑะบะฐั…:
@@ -214,18 +214,23 @@ module Rospatent
214
214
  # @param doc_type [String] Document type code (e.g., "U1")
215
215
  # @param pub_date [String, Date] Publication date in format YYYY/MM/DD
216
216
  # @param pub_number [String] Publication number
217
- # @param filename [String] Media file name (e.g., "document.pdf")
218
- # @return [String] Binary content of the requested file
217
+ # @param filename [String, nil] Media file name (optional, defaults to "<formatted_number>.pdf")
218
+ # @return [String] Binary content with ASCII-8BIT encoding
219
219
  # @raise [Rospatent::Errors::InvalidRequestError] If any required parameter is missing
220
+ # @example Retrieve and save a PDF with auto-generated filename
221
+ # pdf_data = client.patent_media("National", "RU", "U1", "2013/11/20", "134694")
222
+ # client.save_binary_file(pdf_data, "patent.pdf")
223
+ # @example Retrieve and save a specific file
224
+ # pdf_data = client.patent_media("National", "RU", "U1", "2013/11/20", "134694", "document.pdf")
225
+ # client.save_binary_file(pdf_data, "patent.pdf")
220
226
  def patent_media(collection_id, country_code, doc_type, pub_date, pub_number,
221
- filename)
227
+ filename = nil)
222
228
  # Validate and normalize inputs
223
229
  validated_collection = validate_required_string(collection_id, "collection_id")
224
230
  validated_country = validate_required_string(country_code, "country_code", max_length: 2)
225
231
  validated_doc_type = validate_required_string(doc_type, "doc_type", max_length: 3)
226
232
  validated_date = validate_required_date(pub_date, "pub_date")
227
233
  validated_number = validate_required_string(pub_number, "pub_number")
228
- validated_filename = validate_required_string(filename, "filename")
229
234
 
230
235
  # Format publication date
231
236
  formatted_date = validated_date.strftime("%Y/%m/%d")
@@ -233,6 +238,13 @@ module Rospatent
233
238
  # Format publication number with appropriate padding
234
239
  formatted_number = format_publication_number(validated_number, validated_country)
235
240
 
241
+ # Generate default filename if not provided
242
+ validated_filename = if filename.nil?
243
+ "#{formatted_number}.pdf"
244
+ else
245
+ validate_required_string(filename, "filename")
246
+ end
247
+
236
248
  # Construct the path
237
249
  path = "/media/#{validated_collection}/#{validated_country}/" \
238
250
  "#{validated_doc_type}/#{formatted_date}/#{formatted_number}/" \
@@ -245,15 +257,23 @@ module Rospatent
245
257
  # Retrieve media using simplified patent ID format
246
258
  # @param document_id [String] Patent document ID (e.g., "RU134694U1_20131120")
247
259
  # @param collection_id [String] Collection identifier (e.g., "National")
248
- # @param filename [String] Filename to retrieve (e.g., "document.pdf")
249
- # @return [String] Binary content of the requested file
260
+ # @param filename [String, nil] Filename to retrieve (optional, defaults to "<formatted_number>.pdf")
261
+ # @return [String] Binary content with ASCII-8BIT encoding
250
262
  # @raise [Rospatent::Errors::InvalidRequestError] If document_id format is invalid
251
263
  # or parameters are missing
252
- def patent_media_by_id(document_id, collection_id, filename)
264
+ # @example Retrieve and save a PDF with auto-generated filename
265
+ # pdf_data = client.patent_media_by_id("RU134694U1_20131120", "National")
266
+ # client.save_binary_file(pdf_data, "patent.pdf")
267
+ # @example Retrieve and save a specific file
268
+ # pdf_data = client.patent_media_by_id("RU134694U1_20131120", "National", "document.pdf")
269
+ # client.save_binary_file(pdf_data, "patent.pdf")
270
+ def patent_media_by_id(document_id, collection_id, filename = nil)
253
271
  # Validate inputs
254
272
  validated_id = validate_patent_id(document_id)
255
273
  validated_collection = validate_required_string(collection_id, "collection_id")
256
- validated_filename = validate_required_string(filename, "filename")
274
+
275
+ # Validate filename if provided
276
+ validated_filename = filename ? validate_required_string(filename, "filename") : nil
257
277
 
258
278
  # Parse the patent ID to extract components
259
279
  id_parts = parse_patent_id(validated_id)
@@ -261,12 +281,10 @@ module Rospatent
261
281
  # Format the date from YYYYMMDD to YYYY/MM/DD
262
282
  formatted_date = id_parts[:date].gsub(/^(\d{4})(\d{2})(\d{2})$/, '\1/\2/\3')
263
283
 
264
- # Format publication number with appropriate padding
265
- formatted_number = format_publication_number(id_parts[:number], id_parts[:country_code])
266
-
267
284
  # Call the base method with extracted components
285
+ # If no filename provided, patent_media will generate default using format_publication_number
268
286
  patent_media(validated_collection, id_parts[:country_code], id_parts[:doc_type],
269
- formatted_date, formatted_number, validated_filename)
287
+ formatted_date, id_parts[:number], validated_filename)
270
288
  end
271
289
 
272
290
  # Extract and parse the abstract content from a patent document
@@ -496,6 +514,29 @@ module Rospatent
496
514
  }
497
515
  end
498
516
 
517
+ # Save binary data to a file with proper encoding handling
518
+ # This method ensures that binary data (PDFs, images, etc.) is written correctly
519
+ # @param binary_data [String] Binary data returned from patent_media methods
520
+ # @param file_path [String] Path where to save the file
521
+ # @return [Integer] Number of bytes written
522
+ # @raise [SystemCallError] If file cannot be written
523
+ # @example Save a PDF file with auto-generated filename
524
+ # pdf_data = client.patent_media_by_id("RU134694U1_20131120", "National")
525
+ # client.save_binary_file(pdf_data, "patent.pdf")
526
+ # @example Save a specific file
527
+ # pdf_data = client.patent_media_by_id("RU134694U1_20131120", "National", "document.pdf")
528
+ # client.save_binary_file(pdf_data, "patent.pdf")
529
+ def save_binary_file(binary_data, file_path)
530
+ validate_required_string(binary_data, "binary_data")
531
+ validate_required_string(file_path, "file_path")
532
+
533
+ # Ensure data is properly encoded as binary
534
+ data_to_write = binary_data.dup.force_encoding(Encoding::ASCII_8BIT)
535
+
536
+ # Write in binary mode to prevent any encoding conversions
537
+ File.binwrite(file_path, data_to_write)
538
+ end
539
+
499
540
  private
500
541
 
501
542
  # Validate search parameters
@@ -662,10 +703,15 @@ module Rospatent
662
703
  # Process binary API response (for media files)
663
704
  # @param response [Faraday::Response] Raw response from the API
664
705
  # @param request_id [String] Request ID for tracking
665
- # @return [String] Binary response data
706
+ # @return [String] Binary response data with proper encoding
666
707
  # @raise [Rospatent::Errors::ApiError] If the response is not successful
667
708
  def handle_binary_response(response, request_id = nil)
668
- return response.body if response.success?
709
+ if response.success?
710
+ # Ensure binary data is properly encoded as ASCII-8BIT to prevent encoding issues
711
+ binary_data = response.body.dup
712
+ binary_data.force_encoding(Encoding::ASCII_8BIT)
713
+ return binary_data
714
+ end
669
715
 
670
716
  # For binary endpoints, error responses might still be JSON
671
717
  error_msg = begin
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Rospatent
4
- VERSION = "1.3.1"
4
+ VERSION = "1.4.0"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rospatent
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.1
4
+ version: 1.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aleksandr Dryzhuk
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-06-06 00:00:00.000000000 Z
11
+ date: 2025-06-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday