ox-tender-abstract 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 83274157e46a8de668555603f4627528bbd27d091cf682157e24d5b47474fa98
4
+ data.tar.gz: 6f4465d33a0b748e02803495259fa30d66c23c5cc9a2f8de0ec7ff56cb2787b7
5
+ SHA512:
6
+ metadata.gz: 628bc14dadbd989cae0eef11bb608c05219e2432f59b9342b3dcfae22172db6e6dafcba6caf163477fb5e5792a659454243d02c413d2127dfafb0e11941b3923
7
+ data.tar.gz: 70ecc6574d26ce57653540c420684718beaca51e485ab2c9c788a1575d07f1a8c6de0df2a2dcccf05287372c7b4d2f3cc3b8428a340e4f8b7c77f3a94a19823b
@@ -0,0 +1,11 @@
1
+ ---
2
+ description:
3
+ globs:
4
+ alwaysApply: true
5
+ ---
6
+ # Overview
7
+
8
+ ## Code Conventions
9
+
10
+ - Use `snake_case` for method and variable names
11
+ - All code comments, CHANGELOG, README, and other documentation must be written in English
@@ -0,0 +1,62 @@
1
+ ---
2
+ description: Guidelines for writing clean, maintainable, and human-readable code. Apply these rules when writing or reviewing code to ensure consistency and quality.
3
+ globs:
4
+ alwaysApply: false
5
+ ---
6
+
7
+ # Clean Code Guidelines
8
+
9
+ ## Constants Over Magic Numbers
10
+
11
+ - Replace hard-coded values with named constants
12
+ - Use descriptive constant names that explain the value's purpose
13
+ - Keep constants at the top of the file or in a dedicated constants file
14
+
15
+ ## Meaningful Names
16
+
17
+ - Variables, functions, and classes should reveal their purpose
18
+ - Names should explain why something exists and how it's used
19
+ - Avoid abbreviations unless they're universally understood
20
+
21
+ ## Smart Comments
22
+
23
+ - Don't comment on what the code does - make the code self-documenting
24
+ - Use comments to explain why something is done a certain way
25
+ - Document APIs, complex algorithms, and non-obvious side effects
26
+
27
+ ## Single Responsibility
28
+
29
+ - Each function should do exactly one thing
30
+ - Functions should be small and focused
31
+ - If a function needs a comment to explain what it does, it should be split
32
+
33
+ ## DRY (Don't Repeat Yourself)
34
+
35
+ - Extract repeated code into reusable functions
36
+ - Share common logic through proper abstraction
37
+ - Maintain single sources of truth
38
+
39
+ ## Clean Structure
40
+
41
+ - Keep related code together
42
+ - Organize code in a logical hierarchy
43
+ - Use consistent file and folder naming conventions
44
+
45
+ ## Encapsulation
46
+
47
+ - Hide implementation details
48
+ - Expose clear interfaces
49
+ - Move nested conditionals into well-named functions
50
+
51
+ ## Code Quality Maintenance
52
+
53
+ - Refactor continuously
54
+ - Fix technical debt early
55
+ - Leave code cleaner than you found it
56
+ - Follow the "Fail fast" principle for early error detection
57
+
58
+ ## Version Control
59
+
60
+ - Write clear commit messages
61
+ - Make small, focused commits
62
+ - Use meaningful branch names
@@ -0,0 +1,132 @@
1
+ ---
2
+ description:
3
+ globs: *.mdc,**/*.mdc
4
+ alwaysApply: false
5
+ ---
6
+ # MDC File Format Guide
7
+
8
+ MDC (Markdown Configuration) files are used by Cursor to provide context-specific instructions to AI assistants. This guide explains how to create and maintain these files properly.
9
+
10
+ ## File Structure
11
+
12
+ Each MDC file consists of two main parts:
13
+
14
+ 1. **Frontmatter** - Configuration metadata at the top of the file
15
+ 2. **Markdown Content** - The actual instructions in Markdown format
16
+
17
+ ### Frontmatter
18
+
19
+ The frontmatter must be the first thing in the file and must be enclosed between triple-dash lines (`---`). Configuration should be based on the intended behavior:
20
+
21
+ ```
22
+ ---
23
+ # Configure your rule based on desired behavior:
24
+
25
+ description: Brief description of what the rule does
26
+ globs: **/*.js, **/*.ts # Optional: Comma-separated list, not an array
27
+ alwaysApply: false # Set to true for global rules
28
+ ---
29
+ ```
30
+
31
+ > **Important**: Despite the appearance, the frontmatter is not strictly YAML formatted. The `globs` field is a comma-separated list and should NOT include brackets `[]` or quotes `"`.
32
+
33
+ #### Guidelines for Setting Fields
34
+
35
+ - **description**: Should be agent-friendly and clearly describe when the rule is relevant. Format as `<topic>: <details>` for best results.
36
+ - **globs**:
37
+ - If a rule is only relevant in very specific situations, leave globs empty so it's loaded only when applicable to the user request.
38
+ - If the only glob would match all files (like `**/*`), leave it empty and set `alwaysApply: true` instead.
39
+ - Otherwise, be as specific as possible with glob patterns to ensure rules are only applied with relevant files.
40
+ - **alwaysApply**: Use sparingly for truly global guidelines.
41
+
42
+ #### Glob Pattern Examples
43
+
44
+ - **/*.js - All JavaScript files
45
+ - src/**/*.jsx - All JSX files in the src directory
46
+ - **/components/**/*.vue - All Vue files in any components directory
47
+
48
+ ### Markdown Content
49
+
50
+ After the frontmatter, the rest of the file should be valid Markdown:
51
+
52
+ ```markdown
53
+ # Title of Your Rule
54
+
55
+ ## Section 1
56
+ - Guidelines and information
57
+ - Code examples
58
+
59
+ ## Section 2
60
+ More detailed information...
61
+ ```
62
+
63
+ ## Special Features
64
+
65
+ ### File References
66
+
67
+ You can reference other files from within an MDC file using the markdown link syntax:
68
+
69
+ ```
70
+ [rule-name.mdc](mdc:location/of/the/rule.mdc)
71
+ ```
72
+
73
+ When this rule is activated, the referenced file will also be included in the context.
74
+
75
+ ### Code Blocks
76
+
77
+ Use fenced code blocks for examples:
78
+
79
+ ````markdown
80
+ ```javascript
81
+ // Example code
82
+ function example() {
83
+ return "This is an example";
84
+ }
85
+ ```
86
+ ````
87
+
88
+ ## Best Practices
89
+
90
+ 1. **Clear Organization**
91
+ - Use numbered prefixes (e.g., `01-workflow.mdc`) for sorting rules logically
92
+ - Place task-specific rules in the `tasks/` subdirectory
93
+ - Use descriptive filenames that indicate the rule's purpose
94
+
95
+ 2. **Frontmatter Specificity**
96
+ - Be specific with glob patterns to ensure rules are only applied in relevant contexts
97
+ - Use `alwaysApply: true` for truly global guidelines
98
+ - Make descriptions clear and concise so AI knows when to apply the rule
99
+
100
+ 3. **Content Structure**
101
+ - Start with a clear title (H1)
102
+ - Use hierarchical headings (H2, H3, etc.) to organize content
103
+ - Include examples where appropriate
104
+ - Keep instructions clear and actionable
105
+
106
+ 4. **File Size Considerations**
107
+ - Keep files focused on a single topic or closely related topics
108
+ - Split very large rule sets into multiple files and link them with references
109
+ - Aim for under 300 lines per file when possible
110
+
111
+ ## Usage in Cursor
112
+
113
+ When working with files in Cursor, rules are automatically applied when:
114
+
115
+ 1. The file you're working on matches a rule's glob pattern
116
+ 2. A rule has `alwaysApply: true` set in its frontmatter
117
+ 3. The agent thinks the rule's description matches the user request
118
+ 4. You explicitly reference a rule in a conversation with Cursor's AI
119
+
120
+ ## Creating/Renaming/Removing Rules
121
+
122
+ - When a rule file is added/renamed/removed, update also the list under 010-workflow.mdc.
123
+ - When changs are made to multiple `mdc` files from a single request, review also [999-mdc-format]((mdc:.cursor/rules/999-mdc-format.mdc)) to consider whether to update it too.
124
+
125
+ ## Updating Rules
126
+
127
+ When updating existing rules:
128
+
129
+ 1. Maintain the frontmatter format
130
+ 2. Keep the same glob patterns unless intentionally changing the rule's scope
131
+ 3. Update the description if the purpose of the rule changes
132
+ 4. Consider whether changes should propagate to related rules (e.g., CE versions)
@@ -0,0 +1,63 @@
1
+ # Zakupki.gov.ru API Integration Guide
2
+
3
+ ## SOAP API Workflow
4
+
5
+ 1. **Authentication**: Use `individualPerson_token` header
6
+ 2. **Request**: Call `get_docs_by_org_region` or `get_docs_by_reestr_number`
7
+ 3. **Response**: Receive archive URLs in SOAP response
8
+ 4. **Download**: Fetch archives (GZIP compressed ZIP files)
9
+ 5. **Extract**: Decompress GZIP → Extract ZIP → Parse XML files
10
+
11
+ ## Key API Methods
12
+
13
+ - `get_docs_by_org_region` - Search by region and date
14
+ - `get_docs_by_reestr_number` - Search by registry number
15
+
16
+ ## Document Types ([document_types.rb](mdc:lib/oxtenderabstract/document_types.rb))
17
+
18
+ - **PRIZ**: Procurement procedures (default)
19
+ - **RPEC**: Registry of procurement participants
20
+ - **RCON**: Registry of contracts
21
+ - **Other**: Various subsystem types
22
+
23
+ ## XML Structure Handling
24
+
25
+ - Use multiple XPath expressions for reliability
26
+ - Handle namespaces properly with `extract_namespaces`
27
+ - Support both namespaced (ns5:) and non-namespaced elements
28
+ - Extract dates, prices, and text with specific helper methods
29
+
30
+ ## Archive Processing
31
+
32
+ - Support GZIP and ZIP formats
33
+ - Limit file sizes (100MB max)
34
+ - Handle network errors gracefully
35
+ - Extract all XML files from archives
36
+
37
+ ## Error Handling Patterns
38
+
39
+ ```ruby
40
+ # Network errors
41
+ rescue SocketError, Timeout::Error => e
42
+ Result.failure("Network error: #{e.message}")
43
+
44
+ # SOAP errors
45
+ rescue Savon::SOAPFault => e
46
+ Result.failure("SOAP Fault: #{e.message}")
47
+
48
+ # Archive errors
49
+ rescue Zip::Error => e
50
+ raise ArchiveError, "ZIP extraction error: #{e.message}"
51
+ ```
52
+
53
+ ## Configuration Requirements
54
+
55
+ - API token is required for authentication
56
+ - Configurable timeouts for network operations
57
+ - SSL verification can be disabled for testing
58
+ - Logger for debugging API interactions
59
+ description:
60
+ globs:
61
+ alwaysApply: false
62
+
63
+ ---
@@ -0,0 +1,113 @@
1
+ ---
2
+ alwaysApply: true
3
+ ---
4
+
5
+ # OxTenderAbstract Project Structure
6
+
7
+ This is a Ruby gem for working with Russian tender system (zakupki.gov.ru) SOAP API.
8
+
9
+ ## Main Entry Point
10
+
11
+ The main entry point is [lib/ox-tender-abstract.rb](mdc:lib/ox-tender-abstract.rb), which loads all modules and provides convenience methods.
12
+
13
+ ## Core Architecture
14
+
15
+ ### Main Library Modules (lib/oxtenderabstract/)
16
+
17
+ - [client.rb](mdc:lib/oxtenderabstract/client.rb) - Main SOAP API client with search and download methods
18
+ - [xml_parser.rb](mdc:lib/oxtenderabstract/xml_parser.rb) - XML document parser for tender data extraction
19
+ - [archive_processor.rb](mdc:lib/oxtenderabstract/archive_processor.rb) - Archive download and extraction (GZIP/ZIP)
20
+ - [result.rb](mdc:lib/oxtenderabstract/result.rb) - Result wrapper for success/failure responses
21
+ - [configuration.rb](mdc:lib/oxtenderabstract/configuration.rb) - Library configuration and global settings
22
+ - [errors.rb](mdc:lib/oxtenderabstract/errors.rb) - Custom error classes hierarchy
23
+ - [document_types.rb](mdc:lib/oxtenderabstract/document_types.rb) - Constants for API document types
24
+ - [logger.rb](mdc:lib/oxtenderabstract/logger.rb) - Contextual logging module
25
+ - [version.rb](mdc:lib/oxtenderabstract/version.rb) - Gem version definition
26
+
27
+ ### Tests Structure (spec/)
28
+
29
+ - [spec/spec_helper.rb](mdc:spec/spec_helper.rb) - RSpec configuration and setup
30
+ - [spec/oxtenderabstract_spec.rb](mdc:spec/oxtenderabstract_spec.rb) - Main module tests
31
+ - [spec/oxtenderabstract/](mdc:spec/oxtenderabstract/) - Individual module tests
32
+
33
+ ### Configuration Files
34
+
35
+ - [ox-tender-abstract.gemspec](mdc:ox-tender-abstract.gemspec) - Gem specification and dependencies
36
+ - [Gemfile](mdc:Gemfile) - Development dependencies
37
+ - [README.md](mdc:README.md) - Project documentation
38
+
39
+ ## Data Flow
40
+
41
+ 1. **API Request**: Client → SOAP API → Archive URLs
42
+ 2. **Archive Processing**: ArchiveProcessor → Download → Extract (GZIP→ZIP→XML)
43
+ 3. **XML Parsing**: XmlParser → Structured tender data
44
+ 4. **Result**: Result wrapper with success/failure status
45
+
46
+ ## Key Dependencies
47
+
48
+ - `savon` - SOAP client
49
+ - `nokogiri` - XML parsing
50
+ - `rubyzip` - ZIP archive handling
51
+ - `net-http` - HTTP client
52
+
53
+ ## Usage Pattern
54
+
55
+ ```ruby
56
+ OxTenderAbstract.configure { |config| config.token = 'token' }
57
+ result = OxTenderAbstract.search_tenders(org_region: '77', exact_date: '2024-01-01')
58
+ ```
59
+
60
+ # OxTenderAbstract Project Structure
61
+
62
+ This is a Ruby gem for working with Russian tender system (zakupki.gov.ru) SOAP API.
63
+
64
+ ## Main Entry Point
65
+
66
+ The main entry point is [lib/ox-tender-abstract.rb](mdc:lib/ox-tender-abstract.rb), which loads all modules and provides convenience methods.
67
+
68
+ ## Core Architecture
69
+
70
+ ### Main Library Modules (lib/oxtenderabstract/)
71
+
72
+ - [client.rb](mdc:lib/oxtenderabstract/client.rb) - Main SOAP API client with search and download methods
73
+ - [xml_parser.rb](mdc:lib/oxtenderabstract/xml_parser.rb) - XML document parser for tender data extraction
74
+ - [archive_processor.rb](mdc:lib/oxtenderabstract/archive_processor.rb) - Archive download and extraction (GZIP/ZIP)
75
+ - [result.rb](mdc:lib/oxtenderabstract/result.rb) - Result wrapper for success/failure responses
76
+ - [configuration.rb](mdc:lib/oxtenderabstract/configuration.rb) - Library configuration and global settings
77
+ - [errors.rb](mdc:lib/oxtenderabstract/errors.rb) - Custom error classes hierarchy
78
+ - [document_types.rb](mdc:lib/oxtenderabstract/document_types.rb) - Constants for API document types
79
+ - [logger.rb](mdc:lib/oxtenderabstract/logger.rb) - Contextual logging module
80
+ - [version.rb](mdc:lib/oxtenderabstract/version.rb) - Gem version definition
81
+
82
+ ### Tests Structure (spec/)
83
+
84
+ - [spec/spec_helper.rb](mdc:spec/spec_helper.rb) - RSpec configuration and setup
85
+ - [spec/oxtenderabstract_spec.rb](mdc:spec/oxtenderabstract_spec.rb) - Main module tests
86
+ - [spec/oxtenderabstract/](mdc:spec/oxtenderabstract/) - Individual module tests
87
+
88
+ ### Configuration Files
89
+
90
+ - [ox-tender-abstract.gemspec](mdc:ox-tender-abstract.gemspec) - Gem specification and dependencies
91
+ - [Gemfile](mdc:Gemfile) - Development dependencies
92
+ - [README.md](mdc:README.md) - Project documentation
93
+
94
+ ## Data Flow
95
+
96
+ 1. **API Request**: Client → SOAP API → Archive URLs
97
+ 2. **Archive Processing**: ArchiveProcessor → Download → Extract (GZIP→ZIP→XML)
98
+ 3. **XML Parsing**: XmlParser → Structured tender data
99
+ 4. **Result**: Result wrapper with success/failure status
100
+
101
+ ## Key Dependencies
102
+
103
+ - `savon` - SOAP client
104
+ - `nokogiri` - XML parsing
105
+ - `rubyzip` - ZIP archive handling
106
+ - `net-http` - HTTP client
107
+
108
+ ## Usage Pattern
109
+
110
+ ```ruby
111
+ OxTenderAbstract.configure { |config| config.token = 'token' }
112
+ result = OxTenderAbstract.search_tenders(org_region: '77', exact_date: '2024-01-01')
113
+ ```
@@ -0,0 +1,121 @@
1
+ ---
2
+ alwaysApply: true
3
+ ---
4
+
5
+ # Ruby Coding Conventions
6
+
7
+ ## Naming Conventions
8
+
9
+ - Use `snake_case` for method and variable names
10
+ - Use `PascalCase` for class and module names
11
+ - Use `SCREAMING_SNAKE_CASE` for constants
12
+
13
+ ## Documentation
14
+
15
+ - All code comments, CHANGELOG, README, and other documentation must be written in English
16
+ - Use YARD-style documentation for public methods
17
+ - Include examples in documentation when appropriate
18
+
19
+ ## Code Organization
20
+
21
+ - Each class should be in its own file
22
+ - Follow the single responsibility principle
23
+ - Use modules for shared functionality (like ContextualLogger)
24
+
25
+ ## Error Handling
26
+
27
+ - Use custom error classes that inherit from the base Error class
28
+ - Return Result objects for operations that can fail
29
+ - Handle exceptions gracefully and provide meaningful error messages
30
+
31
+ ## Method Structure
32
+
33
+ - Public methods should be well-documented
34
+ - Private methods should be clearly marked with `private`
35
+ - Use descriptive method names that explain what they do
36
+
37
+ ## Testing
38
+
39
+ - Use RSpec for testing
40
+ - Test both success and failure cases
41
+ - Use descriptive test names that explain the expected behavior
42
+ - Mock external dependencies appropriately
43
+
44
+ ## Dependencies
45
+
46
+ - Prefer standard library when possible
47
+ - Use well-maintained gems for complex functionality
48
+ - Keep dependencies minimal and justified
49
+
50
+ ## Result Pattern
51
+
52
+ Use the Result pattern for operations that can fail:
53
+
54
+ ```ruby
55
+ def some_operation
56
+ # success case
57
+ Result.success(data)
58
+ rescue => e
59
+ # failure case
60
+ Result.failure(e.message)
61
+ end
62
+ ```
63
+
64
+ # Ruby Coding Conventions
65
+
66
+ ## Naming Conventions
67
+
68
+ - Use `snake_case` for method and variable names
69
+ - Use `PascalCase` for class and module names
70
+ - Use `SCREAMING_SNAKE_CASE` for constants
71
+
72
+ ## Documentation
73
+
74
+ - All code comments, CHANGELOG, README, and other documentation must be written in English
75
+ - Use YARD-style documentation for public methods
76
+ - Include examples in documentation when appropriate
77
+
78
+ ## Code Organization
79
+
80
+ - Each class should be in its own file
81
+ - Follow the single responsibility principle
82
+ - Use modules for shared functionality (like ContextualLogger)
83
+
84
+ ## Error Handling
85
+
86
+ - Use custom error classes that inherit from the base Error class
87
+ - Return Result objects for operations that can fail
88
+ - Handle exceptions gracefully and provide meaningful error messages
89
+
90
+ ## Method Structure
91
+
92
+ - Public methods should be well-documented
93
+ - Private methods should be clearly marked with `private`
94
+ - Use descriptive method names that explain what they do
95
+
96
+ ## Testing
97
+
98
+ - Use RSpec for testing
99
+ - Test both success and failure cases
100
+ - Use descriptive test names that explain the expected behavior
101
+ - Mock external dependencies appropriately
102
+
103
+ ## Dependencies
104
+
105
+ - Prefer standard library when possible
106
+ - Use well-maintained gems for complex functionality
107
+ - Keep dependencies minimal and justified
108
+
109
+ ## Result Pattern
110
+
111
+ Use the Result pattern for operations that can fail:
112
+
113
+ ```ruby
114
+ def some_operation
115
+ # success case
116
+ Result.success(data)
117
+ rescue => e
118
+ # failure case
119
+ Result.failure(e.message)
120
+ end
121
+ ```
@@ -0,0 +1,169 @@
1
+ ---
2
+ alwaysApply: true
3
+ ---
4
+
5
+ # Testing Patterns
6
+
7
+ ## RSpec Configuration
8
+
9
+ - Use [spec/spec_helper.rb](mdc:spec/spec_helper.rb) for global test setup
10
+ - Configure RSpec with `--require spec_helper` in [.rspec](mdc:.rspec)
11
+ - Load path includes `lib/` directory for proper module loading
12
+
13
+ ## Test Structure
14
+
15
+ - One test file per main class: `spec/oxtenderabstract/class_name_spec.rb`
16
+ - Group related tests with `describe` and `context` blocks
17
+ - Use descriptive test names that explain expected behavior
18
+
19
+ ## Mocking Patterns
20
+
21
+ ```ruby
22
+ # Mock external dependencies
23
+ let(:mock_response) { instance_double(Net::HTTPResponse) }
24
+ allow(mock_response).to receive(:is_a?).with(Net::HTTPSuccess).and_return(true)
25
+ allow(mock_response).to receive(:body).and_return('content')
26
+ allow(mock_response).to receive(:[]).with('content-type').and_return('application/zip')
27
+
28
+ # Mock internal classes
29
+ let(:client_double) { instance_double(OxTenderAbstract::Client) }
30
+ allow(OxTenderAbstract::Client).to receive(:new).and_return(client_double)
31
+ ```
32
+
33
+ ## Configuration Reset
34
+
35
+ Always reset configuration in tests:
36
+
37
+ ```ruby
38
+ after { OxTenderAbstract.reset_configuration! }
39
+ ```
40
+
41
+ ## Testing Result Objects
42
+
43
+ Test both success and failure cases:
44
+
45
+ ```ruby
46
+ it 'returns success result' do
47
+ result = subject.some_method
48
+ expect(result).to be_success
49
+ expect(result.data[:key]).to eq('value')
50
+ end
51
+
52
+ it 'returns failure result' do
53
+ result = subject.failing_method
54
+ expect(result).to be_failure
55
+ expect(result.error).to include('expected error message')
56
+ end
57
+ ```
58
+
59
+ ## Testing Private Methods
60
+
61
+ Use `send` to test private methods when necessary:
62
+
63
+ ```ruby
64
+ expect(parser.send(:extract_price_from_text, '1000.50')).to eq('1000.50')
65
+ ```
66
+
67
+ ## Mock Network Dependencies
68
+
69
+ Always mock network calls to avoid external dependencies:
70
+
71
+ ```ruby
72
+ before do
73
+ allow(Net::HTTP).to receive(:new).and_return(mock_http)
74
+ allow(mock_http).to receive(:request).and_return(mock_response)
75
+ end
76
+ ```
77
+
78
+ ## Test Data
79
+
80
+ Use realistic but minimal test data that covers edge cases:
81
+
82
+ - Empty/nil values
83
+ - Malformed XML
84
+ - Network errors
85
+ - Large file sizes
86
+ - Invalid configurations
87
+
88
+ # Testing Patterns
89
+
90
+ ## RSpec Configuration
91
+
92
+ - Use [spec/spec_helper.rb](mdc:spec/spec_helper.rb) for global test setup
93
+ - Configure RSpec with `--require spec_helper` in [.rspec](mdc:.rspec)
94
+ - Load path includes `lib/` directory for proper module loading
95
+
96
+ ## Test Structure
97
+
98
+ - One test file per main class: `spec/oxtenderabstract/class_name_spec.rb`
99
+ - Group related tests with `describe` and `context` blocks
100
+ - Use descriptive test names that explain expected behavior
101
+
102
+ ## Mocking Patterns
103
+
104
+ ```ruby
105
+ # Mock external dependencies
106
+ let(:mock_response) { instance_double(Net::HTTPResponse) }
107
+ allow(mock_response).to receive(:is_a?).with(Net::HTTPSuccess).and_return(true)
108
+ allow(mock_response).to receive(:body).and_return('content')
109
+ allow(mock_response).to receive(:[]).with('content-type').and_return('application/zip')
110
+
111
+ # Mock internal classes
112
+ let(:client_double) { instance_double(OxTenderAbstract::Client) }
113
+ allow(OxTenderAbstract::Client).to receive(:new).and_return(client_double)
114
+ ```
115
+
116
+ ## Configuration Reset
117
+
118
+ Always reset configuration in tests:
119
+
120
+ ```ruby
121
+ after { OxTenderAbstract.reset_configuration! }
122
+ ```
123
+
124
+ ## Testing Result Objects
125
+
126
+ Test both success and failure cases:
127
+
128
+ ```ruby
129
+ it 'returns success result' do
130
+ result = subject.some_method
131
+ expect(result).to be_success
132
+ expect(result.data[:key]).to eq('value')
133
+ end
134
+
135
+ it 'returns failure result' do
136
+ result = subject.failing_method
137
+ expect(result).to be_failure
138
+ expect(result.error).to include('expected error message')
139
+ end
140
+ ```
141
+
142
+ ## Testing Private Methods
143
+
144
+ Use `send` to test private methods when necessary:
145
+
146
+ ```ruby
147
+ expect(parser.send(:extract_price_from_text, '1000.50')).to eq('1000.50')
148
+ ```
149
+
150
+ ## Mock Network Dependencies
151
+
152
+ Always mock network calls to avoid external dependencies:
153
+
154
+ ```ruby
155
+ before do
156
+ allow(Net::HTTP).to receive(:new).and_return(mock_http)
157
+ allow(mock_http).to receive(:request).and_return(mock_response)
158
+ end
159
+ ```
160
+
161
+ ## Test Data
162
+
163
+ Use realistic but minimal test data that covers edge cases:
164
+
165
+ - Empty/nil values
166
+ - Malformed XML
167
+ - Network errors
168
+ - Large file sizes
169
+ - Invalid configurations
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --require spec_helper
2
+ --format documentation
3
+ --color