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 +7 -0
- data/.cursor/rules/010-project-structure.mdc +11 -0
- data/.cursor/rules/998-clean-code.mdc +62 -0
- data/.cursor/rules/999-mdc-format.mdc +132 -0
- data/.cursor/rules/api-integration.mdc +63 -0
- data/.cursor/rules/project-structure.mdc +113 -0
- data/.cursor/rules/ruby-conventions.mdc +121 -0
- data/.cursor/rules/testing-patterns.mdc +169 -0
- data/.rspec +3 -0
- data/.rspec_status +73 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +3 -0
- data/CODE_OF_CONDUCT.md +84 -0
- data/LICENSE +21 -0
- data/README.md +297 -0
- data/Rakefile +12 -0
- data/lib/ox-tender-abstract.rb +39 -0
- data/lib/oxtenderabstract/archive_processor.rb +175 -0
- data/lib/oxtenderabstract/client.rb +347 -0
- data/lib/oxtenderabstract/compatibility.rb +11 -0
- data/lib/oxtenderabstract/configuration.rb +60 -0
- data/lib/oxtenderabstract/document_types.rb +42 -0
- data/lib/oxtenderabstract/engine.rb +11 -0
- data/lib/oxtenderabstract/errors.rb +24 -0
- data/lib/oxtenderabstract/logger.rb +42 -0
- data/lib/oxtenderabstract/result.rb +31 -0
- data/lib/oxtenderabstract/version.rb +5 -0
- data/lib/oxtenderabstract/xml_parser.rb +529 -0
- data/lib/ruby/ox-tender-abstract.rb +2 -0
- metadata +229 -0
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,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