jsonrpc-middleware 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.aiexclude +4 -0
- data/.claude/commands/document.md +105 -0
- data/.claude/docs/yard.md +602 -0
- data/.claude/settings.local.json +2 -1
- data/.env.example +5 -0
- data/CHANGELOG.md +22 -2
- data/CLAUDE.md +114 -0
- data/README.md +42 -102
- data/Rakefile +59 -1
- data/examples/README.md +37 -0
- data/examples/procedures.rb +6 -1
- data/examples/rack/README.md +26 -1
- data/examples/rack/app.rb +1 -1
- data/examples/rack-echo/README.md +23 -1
- data/examples/rack-single-file/README.md +37 -0
- data/examples/rack-single-file/config.ru +54 -0
- data/examples/rails/.gitignore +21 -0
- data/examples/rails/.ruby-version +1 -0
- data/examples/rails/Gemfile +15 -0
- data/examples/rails/Gemfile.lock +261 -0
- data/examples/rails/README.md +32 -0
- data/examples/rails/Rakefile +8 -0
- data/examples/rails/app/controllers/application_controller.rb +4 -0
- data/examples/rails/app/controllers/jsonrpc_controller.rb +44 -0
- data/examples/rails/bin/dev +4 -0
- data/examples/rails/bin/rails +6 -0
- data/examples/rails/bin/rake +6 -0
- data/examples/rails/bin/setup +28 -0
- data/examples/rails/config/application.rb +47 -0
- data/examples/rails/config/boot.rb +5 -0
- data/examples/rails/config/credentials.yml.enc +1 -0
- data/examples/rails/config/environment.rb +7 -0
- data/examples/rails/config/environments/development.rb +42 -0
- data/examples/rails/config/environments/production.rb +60 -0
- data/examples/rails/config/environments/test.rb +44 -0
- data/examples/rails/config/initializers/cors.rb +18 -0
- data/examples/rails/config/initializers/filter_parameter_logging.rb +10 -0
- data/examples/rails/config/initializers/inflections.rb +18 -0
- data/examples/rails/config/initializers/jsonrpc.rb +62 -0
- data/examples/rails/config/locales/en.yml +31 -0
- data/examples/rails/config/puma.rb +40 -0
- data/examples/rails/config/routes.rb +14 -0
- data/examples/rails/config.ru +8 -0
- data/examples/rails/public/robots.txt +1 -0
- data/examples/rails-single-file/config.ru +71 -0
- data/examples/sinatra-classic/Gemfile +9 -0
- data/examples/sinatra-classic/Gemfile.lock +95 -0
- data/examples/sinatra-classic/README.md +32 -0
- data/examples/sinatra-classic/app.rb +54 -0
- data/examples/sinatra-classic/config.ru +6 -0
- data/examples/sinatra-modular/Gemfile +9 -0
- data/examples/sinatra-modular/Gemfile.lock +95 -0
- data/examples/sinatra-modular/README.md +32 -0
- data/examples/sinatra-modular/app.rb +57 -0
- data/examples/sinatra-modular/config.ru +6 -0
- data/lib/jsonrpc/batch_request.rb +67 -2
- data/lib/jsonrpc/batch_response.rb +56 -0
- data/lib/jsonrpc/configuration.rb +156 -14
- data/lib/jsonrpc/error.rb +83 -2
- data/lib/jsonrpc/errors/internal_error.rb +14 -2
- data/lib/jsonrpc/errors/invalid_params_error.rb +13 -1
- data/lib/jsonrpc/errors/invalid_request_error.rb +8 -0
- data/lib/jsonrpc/errors/method_not_found_error.rb +8 -0
- data/lib/jsonrpc/errors/parse_error.rb +8 -0
- data/lib/jsonrpc/helpers.rb +212 -21
- data/lib/jsonrpc/middleware.rb +211 -5
- data/lib/jsonrpc/notification.rb +58 -0
- data/lib/jsonrpc/parser.rb +30 -0
- data/lib/jsonrpc/railtie.rb +57 -0
- data/lib/jsonrpc/request.rb +68 -1
- data/lib/jsonrpc/response.rb +76 -0
- data/lib/jsonrpc/validator.rb +67 -6
- data/lib/jsonrpc/version.rb +11 -1
- data/lib/jsonrpc.rb +53 -1
- metadata +49 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ea48adea36c2a7f311bb0b5c8d1868999f9ec7b6530a2b933600f8433655b63c
|
4
|
+
data.tar.gz: 8e4abe926bb02da6155650d2296d5df0b07562de6ce08163ad433df09ac40e1d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 90b63747650ce423ae7f5f881db75c0c8fceabc05e627fa0fd6647cd6b67c1445eab3a09dfc19cac3b5d62d9814e9a692b96e50e0bbdc41bd8b83d9d3582b6bc
|
7
|
+
data.tar.gz: 64c40bf854999ce3c0cdc8261a921d603ed8ec664c46a6e0d4578afbc9404e693f7b8ff5456385fdcb671867049d4e07028efa51ac48276a5adfd5c4a24b194d
|
data/.aiexclude
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
# Document
|
2
|
+
|
3
|
+
Generates documentation for Ruby code using YARD with 100% coverage enforcement.
|
4
|
+
|
5
|
+
## Commands
|
6
|
+
|
7
|
+
Generate documentation:
|
8
|
+
```bash
|
9
|
+
bundle exec rake yard
|
10
|
+
```
|
11
|
+
|
12
|
+
Format YARD comments:
|
13
|
+
```bash
|
14
|
+
bundle exec rake yard:format
|
15
|
+
```
|
16
|
+
|
17
|
+
Verify 100% documentation coverage:
|
18
|
+
```bash
|
19
|
+
bundle exec rake verify_measurements
|
20
|
+
```
|
21
|
+
|
22
|
+
Check for documentation quality issues:
|
23
|
+
```bash
|
24
|
+
bundle exec rake yard:junk
|
25
|
+
```
|
26
|
+
|
27
|
+
Generate coverage report:
|
28
|
+
```bash
|
29
|
+
bundle exec rake yardstick_measure
|
30
|
+
```
|
31
|
+
|
32
|
+
## Configuration
|
33
|
+
|
34
|
+
Requires `.yardstick.yml` in project root with 100% threshold:
|
35
|
+
```yaml
|
36
|
+
threshold: 100
|
37
|
+
rules:
|
38
|
+
ApiTag::Presence: { enabled: true }
|
39
|
+
ApiTag::Inclusion: { enabled: true }
|
40
|
+
ApiTag::ProtectedMethod: { enabled: true }
|
41
|
+
ApiTag::PrivateMethod: { enabled: true }
|
42
|
+
ExampleTag: { enabled: true }
|
43
|
+
ReturnTag: { enabled: true }
|
44
|
+
Summary::Presence: { enabled: true }
|
45
|
+
Summary::Delimiter: { enabled: true }
|
46
|
+
```
|
47
|
+
|
48
|
+
## Coverage Report
|
49
|
+
|
50
|
+
After running measurement, check detailed line-by-line issues:
|
51
|
+
```bash
|
52
|
+
cat measurements/report.txt
|
53
|
+
```
|
54
|
+
|
55
|
+
Report shows specific file, line number, method, and documentation issues that need fixing.
|
56
|
+
|
57
|
+
## Documentation Standards
|
58
|
+
|
59
|
+
### Required Tags
|
60
|
+
- Every public/private method, class, and module requires `@api public` or `@api private`
|
61
|
+
- All parameters: `@param name [Type] Description`
|
62
|
+
- All returns: `@return [Type] Description` (use `[void]` if no return)
|
63
|
+
- Examples required for all public methods: `@example Description`
|
64
|
+
- Error conditions: `@raise [ExceptionClass] When this occurs`
|
65
|
+
|
66
|
+
### Type Notation
|
67
|
+
- Use `String` not `string`
|
68
|
+
- Arrays: `Array<String>` for string arrays
|
69
|
+
- Hashes: `Hash{String=>Object}` for hash types
|
70
|
+
- Use `Boolean` not `bool`, `Integer` not `int`
|
71
|
+
- Nullable types: `String, nil` or `String|nil`
|
72
|
+
|
73
|
+
### Formatting Rules
|
74
|
+
- Blank lines required between YARD tag groups
|
75
|
+
- Exception: `@param` and `@option` tags can be grouped together
|
76
|
+
- Wrap class/method names in `+` markers: `+PrivateKey+`
|
77
|
+
- Cross-reference related methods: `@see #other_method`
|
78
|
+
|
79
|
+
### Documentation Structure
|
80
|
+
```ruby
|
81
|
+
# Brief one-line summary ending with period.
|
82
|
+
#
|
83
|
+
# @api public
|
84
|
+
#
|
85
|
+
# @example Description of example
|
86
|
+
# code_example
|
87
|
+
# result # => expected_output
|
88
|
+
#
|
89
|
+
# @param name [Type] Description
|
90
|
+
# @param other [Type] Other description
|
91
|
+
#
|
92
|
+
# @return [Type] Description
|
93
|
+
#
|
94
|
+
# @raise [ExceptionClass] When this exception occurs
|
95
|
+
#
|
96
|
+
def method_name
|
97
|
+
end
|
98
|
+
```
|
99
|
+
|
100
|
+
## Integration
|
101
|
+
|
102
|
+
Documentation verification is included in the quality assurance pipeline:
|
103
|
+
```bash
|
104
|
+
bundle exec rake qa
|
105
|
+
```
|
@@ -0,0 +1,602 @@
|
|
1
|
+
# Ruby YARD Documentation Guidelines
|
2
|
+
|
3
|
+
This document outlines the comprehensive documentation standards for Ruby projects, based on the best practices demonstrated in professional Ruby gems. These guidelines ensure 100% documentation coverage and maintainable, professional-quality code documentation.
|
4
|
+
|
5
|
+
## Table of Contents
|
6
|
+
|
7
|
+
- [Documentation Philosophy](#documentation-philosophy)
|
8
|
+
- [YARD Configuration](#yard-configuration)
|
9
|
+
- [Basic Documentation Structure](#basic-documentation-structure)
|
10
|
+
- [API Visibility Tags](#api-visibility-tags)
|
11
|
+
- [Method Documentation](#method-documentation)
|
12
|
+
- [Class and Module Documentation](#class-and-module-documentation)
|
13
|
+
- [Attribute Documentation](#attribute-documentation)
|
14
|
+
- [Examples](#examples)
|
15
|
+
- [Parameter and Return Documentation](#parameter-and-return-documentation)
|
16
|
+
- [Error Documentation](#error-documentation)
|
17
|
+
- [Constants Documentation](#constants-documentation)
|
18
|
+
- [Inheritance Documentation](#inheritance-documentation)
|
19
|
+
- [Quality Enforcement](#quality-enforcement)
|
20
|
+
- [Best Practices](#best-practices)
|
21
|
+
|
22
|
+
## Documentation Philosophy
|
23
|
+
|
24
|
+
Every piece of public and private code must be documented. Documentation serves multiple purposes:
|
25
|
+
- **API Contract**: Clearly defines what methods do and how to use them
|
26
|
+
- **Maintenance**: Helps future developers (including yourself) understand the code
|
27
|
+
- **Testing Guide**: Examples serve as additional test cases
|
28
|
+
- **User Experience**: Enables IDE autocompletion and contextual help
|
29
|
+
|
30
|
+
## YARD Configuration
|
31
|
+
|
32
|
+
Create a `.yardstick.yml` file in your project root with 100% coverage requirements:
|
33
|
+
|
34
|
+
```yaml
|
35
|
+
threshold: 100
|
36
|
+
rules:
|
37
|
+
ApiTag::Presence:
|
38
|
+
enabled: true
|
39
|
+
ApiTag::Inclusion:
|
40
|
+
enabled: true
|
41
|
+
ApiTag::ProtectedMethod:
|
42
|
+
enabled: true
|
43
|
+
ApiTag::PrivateMethod:
|
44
|
+
enabled: true
|
45
|
+
ExampleTag:
|
46
|
+
enabled: true
|
47
|
+
ReturnTag:
|
48
|
+
enabled: true
|
49
|
+
Summary::Presence:
|
50
|
+
enabled: true
|
51
|
+
Summary::Length:
|
52
|
+
enabled: false
|
53
|
+
Summary::Delimiter:
|
54
|
+
enabled: true
|
55
|
+
Summary::SingleLine:
|
56
|
+
enabled: false
|
57
|
+
```
|
58
|
+
|
59
|
+
## Basic Documentation Structure
|
60
|
+
|
61
|
+
Every documented element follows this structure:
|
62
|
+
|
63
|
+
```ruby
|
64
|
+
# Brief one-line summary ending with a period
|
65
|
+
#
|
66
|
+
# @api public|private
|
67
|
+
#
|
68
|
+
# @example Description of example
|
69
|
+
# code_example
|
70
|
+
# result # => expected_output
|
71
|
+
#
|
72
|
+
# @param name [Type] Description
|
73
|
+
# @param other_name [Type] Other description
|
74
|
+
#
|
75
|
+
# @return [Type] Description
|
76
|
+
#
|
77
|
+
# @raise [ExceptionClass] When this exception occurs
|
78
|
+
#
|
79
|
+
```
|
80
|
+
|
81
|
+
### YARD Tag Spacing Rules
|
82
|
+
|
83
|
+
**IMPORTANT**: All YARD tags must have a blank line between them, with the following exceptions:
|
84
|
+
- `@param` tags can be grouped together without blank lines
|
85
|
+
- `@option` tags can be grouped together without blank lines
|
86
|
+
- `@param` and `@option` tags can be grouped together without blank lines when they relate to the same parameter
|
87
|
+
|
88
|
+
This ensures readable documentation while allowing logical grouping of parameter-related tags.
|
89
|
+
|
90
|
+
## API Visibility Tags
|
91
|
+
|
92
|
+
**REQUIRED**: Every public and private method, class, and module must have an `@api` tag.
|
93
|
+
|
94
|
+
### Public API
|
95
|
+
```ruby
|
96
|
+
# @api public
|
97
|
+
```
|
98
|
+
Use for:
|
99
|
+
- Public methods intended for external use
|
100
|
+
- Public classes and modules
|
101
|
+
- Public attributes and constants
|
102
|
+
|
103
|
+
### Private API
|
104
|
+
```ruby
|
105
|
+
# @api private
|
106
|
+
```
|
107
|
+
Use for:
|
108
|
+
- Private methods
|
109
|
+
- Internal implementation details
|
110
|
+
- Protected methods
|
111
|
+
- Private attributes
|
112
|
+
|
113
|
+
## Method Documentation
|
114
|
+
|
115
|
+
### Public Method Example
|
116
|
+
```ruby
|
117
|
+
# Generates a pair of private and public keys
|
118
|
+
#
|
119
|
+
# @api public
|
120
|
+
#
|
121
|
+
# @example
|
122
|
+
# keypair = keygen.generate_key_pair
|
123
|
+
# keypair # #<Nostr::KeyPair:0x0000000107bd3550
|
124
|
+
# @private_key="893c4cc8088924796b41dc788f7e2f746734497010b1a9f005c1faad7074b900",
|
125
|
+
# @public_key="2d7661527d573cc8e84f665fa971dd969ba51e2526df00c149ff8e40a58f9558">
|
126
|
+
#
|
127
|
+
# @return [KeyPair] An object containing a private key and a public key.
|
128
|
+
#
|
129
|
+
def generate_key_pair
|
130
|
+
# implementation
|
131
|
+
end
|
132
|
+
```
|
133
|
+
|
134
|
+
### Private Method Example
|
135
|
+
```ruby
|
136
|
+
# Validates the keys
|
137
|
+
#
|
138
|
+
# @api private
|
139
|
+
#
|
140
|
+
# @param private_key [PrivateKey] 32-bytes hex-encoded private key.
|
141
|
+
# @param public_key [PublicKey] 32-bytes hex-encoded public key.
|
142
|
+
#
|
143
|
+
# @raise ArgumentError when the private key is not a +PrivateKey+
|
144
|
+
# @raise ArgumentError when the public key is not a +PublicKey+
|
145
|
+
#
|
146
|
+
# @return [void]
|
147
|
+
#
|
148
|
+
def validate_keys(private_key, public_key)
|
149
|
+
# implementation
|
150
|
+
end
|
151
|
+
```
|
152
|
+
|
153
|
+
### Constructor Documentation
|
154
|
+
```ruby
|
155
|
+
# Instantiates a new Event
|
156
|
+
#
|
157
|
+
# @api public
|
158
|
+
#
|
159
|
+
# @example Instantiating a new event
|
160
|
+
# Nostr::Event.new(
|
161
|
+
# id: 'ccf9fdf3e1466d7c20969c71ec98defcf5f54aee088513e1b73ccb7bd770d460',
|
162
|
+
# pubkey: '48df4af6e240ac5f7c5de89bf5941b249880be0e87d03685b178ccb1a315f52e',
|
163
|
+
# created_at: 1230981305,
|
164
|
+
# kind: 1,
|
165
|
+
# tags: [],
|
166
|
+
# content: 'Your feedback is appreciated, now pay $8',
|
167
|
+
# sig: '123ac2923b792ce730b3da34f16155470ab13c8f97f9c53eaeb334f1fb3a5dc9a7f643'
|
168
|
+
# )
|
169
|
+
#
|
170
|
+
# @param id [String|nil] 32-bytes sha256 of the the serialized event data.
|
171
|
+
# @param sig [String|nil] 64-bytes signature of the sha256 hash.
|
172
|
+
# @param pubkey [String] 32-bytes hex-encoded public key of the event creator.
|
173
|
+
# @param created_at [Integer] Date of the creation. A UNIX timestamp, in seconds.
|
174
|
+
# @param kind [Integer] The kind of the event. An integer from 0 to 3.
|
175
|
+
# @param tags [Array<Array>] An array of tags. Each tag is an array of strings.
|
176
|
+
# @param content [String] Arbitrary string.
|
177
|
+
#
|
178
|
+
def initialize(pubkey:, kind:, content:, created_at: Time.now.to_i, tags: [], id: nil, sig: nil)
|
179
|
+
# implementation
|
180
|
+
end
|
181
|
+
```
|
182
|
+
|
183
|
+
### Methods with Keyword Arguments
|
184
|
+
```ruby
|
185
|
+
# Instantiates a new Filter
|
186
|
+
#
|
187
|
+
# @api public
|
188
|
+
#
|
189
|
+
# @example
|
190
|
+
# Nostr::Filter.new(
|
191
|
+
# ids: ['c24881c305c5cfb7c1168be7e9b0e150'],
|
192
|
+
# authors: ['000000001c5c45196786e79f83d21fe801549fdc98e2c26f96dcef068a5dbcd7'],
|
193
|
+
# kinds: [0, 1, 2],
|
194
|
+
# since: 1230981305,
|
195
|
+
# until: 1292190341
|
196
|
+
# )
|
197
|
+
#
|
198
|
+
# @param kwargs [Hash]
|
199
|
+
# @option kwargs [Array<String>, nil] ids A list of event ids
|
200
|
+
# @option kwargs [Array<String>, nil] authors A list of pubkeys
|
201
|
+
# @option kwargs [Array<Integer>, nil] kinds A list of a kind numbers
|
202
|
+
# @option kwargs [Integer, nil] since A timestamp, events must be newer than this
|
203
|
+
# @option kwargs [Integer, nil] until A timestamp, events must be older than this
|
204
|
+
# @option kwargs [Integer, nil] limit Maximum number of events to be returned
|
205
|
+
#
|
206
|
+
def initialize(**kwargs)
|
207
|
+
# implementation
|
208
|
+
end
|
209
|
+
```
|
210
|
+
|
211
|
+
## Class and Module Documentation
|
212
|
+
|
213
|
+
### Class Documentation
|
214
|
+
```ruby
|
215
|
+
# The only object type that exists in Nostr is an event. Events are immutable.
|
216
|
+
class Event
|
217
|
+
# class body
|
218
|
+
end
|
219
|
+
```
|
220
|
+
|
221
|
+
### Module Documentation
|
222
|
+
```ruby
|
223
|
+
# Performs cryptographic operations.
|
224
|
+
class Crypto
|
225
|
+
# class body
|
226
|
+
end
|
227
|
+
```
|
228
|
+
|
229
|
+
### Inheritance Documentation
|
230
|
+
```ruby
|
231
|
+
# 32-bytes lowercase hex-encoded private key
|
232
|
+
class PrivateKey < Key
|
233
|
+
# class body
|
234
|
+
end
|
235
|
+
```
|
236
|
+
|
237
|
+
### Namespace Module
|
238
|
+
```ruby
|
239
|
+
# Encapsulates all the gem's logic
|
240
|
+
module Nostr
|
241
|
+
# module body
|
242
|
+
end
|
243
|
+
```
|
244
|
+
|
245
|
+
## Attribute Documentation
|
246
|
+
|
247
|
+
### Reader Attributes
|
248
|
+
```ruby
|
249
|
+
# 32-bytes hex-encoded public key of the event creator
|
250
|
+
#
|
251
|
+
# @api public
|
252
|
+
#
|
253
|
+
# @example
|
254
|
+
# event.pubkey # => '48df4af6e240ac5f7c5de89bf5941b249880be0e87d03685b178ccb1a315f52e'
|
255
|
+
#
|
256
|
+
# @return [String]
|
257
|
+
#
|
258
|
+
attr_reader :pubkey
|
259
|
+
```
|
260
|
+
|
261
|
+
### Accessor Attributes
|
262
|
+
```ruby
|
263
|
+
# 64-bytes signature of the sha256 hash of the serialized event data
|
264
|
+
#
|
265
|
+
# @api public
|
266
|
+
#
|
267
|
+
# @example Getting the event signature
|
268
|
+
# event.sig # => '058613f8d34c053294cc28b7f9e1f8f0e80fd1ac94fb20f2da6ca514e7360b39'
|
269
|
+
#
|
270
|
+
# @example Setting the event signature
|
271
|
+
# event.sig = '058613f8d34c053294cc28b7f9e1f8f0e80fd1ac94fb20f2da6ca514e7360b39'
|
272
|
+
# event.sig # => '058613f8d34c053294cc28b7f9e1f8f0e80fd1ac94fb20f2da6ca514e7360b39'
|
273
|
+
#
|
274
|
+
# @return [String|nil]
|
275
|
+
#
|
276
|
+
attr_accessor :sig
|
277
|
+
```
|
278
|
+
|
279
|
+
### Private Attributes
|
280
|
+
```ruby
|
281
|
+
# The elliptic curve group. Used to generate public and private keys
|
282
|
+
#
|
283
|
+
# @api private
|
284
|
+
#
|
285
|
+
# @return [ECDSA::Group]
|
286
|
+
#
|
287
|
+
attr_reader :group
|
288
|
+
```
|
289
|
+
|
290
|
+
## Examples
|
291
|
+
|
292
|
+
### Multiple Examples
|
293
|
+
```ruby
|
294
|
+
# Subscribes to a set of events using a filter
|
295
|
+
#
|
296
|
+
# @api public
|
297
|
+
#
|
298
|
+
# @example Creating a subscription with no id and no filters
|
299
|
+
# subscription = client.subscribe
|
300
|
+
#
|
301
|
+
# @example Creating a subscription with an ID
|
302
|
+
# subscription = client.subscribe(subscription_id: 'my-subscription')
|
303
|
+
#
|
304
|
+
# @example Subscribing to all events created after a certain time
|
305
|
+
# subscription = client.subscribe(filter: Nostr::Filter.new(since: 1230981305))
|
306
|
+
#
|
307
|
+
# @param subscription_id [String] The subscription id
|
308
|
+
# @param filter [Filter] A set of attributes representing events of interest
|
309
|
+
#
|
310
|
+
# @return [Subscription] The subscription object
|
311
|
+
#
|
312
|
+
def subscribe(subscription_id: SecureRandom.hex, filter: Filter.new)
|
313
|
+
# implementation
|
314
|
+
end
|
315
|
+
```
|
316
|
+
|
317
|
+
### Complex Examples
|
318
|
+
```ruby
|
319
|
+
# Allows array destructuring of the KeyPair
|
320
|
+
#
|
321
|
+
# @api public
|
322
|
+
#
|
323
|
+
# @example Implicit usage of `to_ary` for destructuring
|
324
|
+
# keypair = Nostr::KeyPair.new(
|
325
|
+
# private_key: Nostr::PrivateKey.new('7d1e4219a5e7d8342654c675085bfbdee143f0eb0f0921f5541ef1705a2b407d'),
|
326
|
+
# public_key: Nostr::PublicKey.new('15678d8fbc126fa326fac536acd5a6dcb5ef64b3d939abe31d6830cba6cd26d6'),
|
327
|
+
# )
|
328
|
+
# # The `to_ary` method can be implicitly used for array destructuring:
|
329
|
+
# private_key, public_key = keypair
|
330
|
+
# # Now `private_key` and `public_key` hold the respective values.
|
331
|
+
#
|
332
|
+
# @example Explicit usage of `to_ary`
|
333
|
+
# array_representation = keypair.to_ary
|
334
|
+
# # array_representation is now an array: [PrivateKey, PublicKey]
|
335
|
+
#
|
336
|
+
# @return [Array<PrivateKey, PublicKey>] An array containing the keys in order
|
337
|
+
#
|
338
|
+
def to_ary
|
339
|
+
# implementation
|
340
|
+
end
|
341
|
+
```
|
342
|
+
|
343
|
+
## Parameter and Return Documentation
|
344
|
+
|
345
|
+
### Parameter Types
|
346
|
+
```ruby
|
347
|
+
# @param event [Event] The event to be signed
|
348
|
+
# @param private_key [PrivateKey] 32-bytes hex-encoded private key
|
349
|
+
# @param kwargs [Hash] Configuration options
|
350
|
+
# @param subscription_id [String] The subscription id
|
351
|
+
# @param filter [Filter, nil] Optional filter for events
|
352
|
+
# @param items [Array<String>] List of string items
|
353
|
+
# @param enabled [Boolean] Whether feature is enabled
|
354
|
+
# @param count [Integer] Number of items
|
355
|
+
# @param rate [Float] Processing rate
|
356
|
+
```
|
357
|
+
|
358
|
+
### Return Types
|
359
|
+
```ruby
|
360
|
+
# @return [Event] A signed event
|
361
|
+
# @return [String] The generated private key
|
362
|
+
# @return [Array<Event>] List of matching events
|
363
|
+
# @return [Hash{String=>Object}] Configuration mapping
|
364
|
+
# @return [Boolean] True if valid, false otherwise
|
365
|
+
# @return [void] This method does not return a value
|
366
|
+
# @return [String, nil] The result or nil if not found
|
367
|
+
```
|
368
|
+
|
369
|
+
### Complex Return Types
|
370
|
+
```ruby
|
371
|
+
# @return [Array<PrivateKey, PublicKey>] An array containing the PrivateKey and PublicKey in that order
|
372
|
+
# @return [Hash{String=>Subscription}] Mapping of subscription IDs to objects
|
373
|
+
```
|
374
|
+
|
375
|
+
## Error Documentation
|
376
|
+
|
377
|
+
### Exception Handling
|
378
|
+
```ruby
|
379
|
+
# Validates the hex value of the private key
|
380
|
+
#
|
381
|
+
# @api private
|
382
|
+
#
|
383
|
+
# @param hex_value [String] The private key in hex format
|
384
|
+
#
|
385
|
+
# @raise InvalidKeyTypeError when the private key is not a string
|
386
|
+
# @raise InvalidKeyLengthError when the private key's length is not 64 characters
|
387
|
+
# @raise InvalidKeyFormatError when the private key is in an invalid format
|
388
|
+
#
|
389
|
+
# @return [void]
|
390
|
+
#
|
391
|
+
def validate_hex_value(hex_value)
|
392
|
+
# implementation
|
393
|
+
end
|
394
|
+
```
|
395
|
+
|
396
|
+
### Error Class Documentation
|
397
|
+
```ruby
|
398
|
+
# Raised when the private key's length is not 64 characters
|
399
|
+
#
|
400
|
+
# @api public
|
401
|
+
#
|
402
|
+
class InvalidKeyLengthError < KeyValidationError
|
403
|
+
# Initializes the error
|
404
|
+
#
|
405
|
+
# @example
|
406
|
+
# InvalidKeyLengthError.new('private')
|
407
|
+
#
|
408
|
+
# @param key_kind [String] The kind of key that is invalid (public or private)
|
409
|
+
#
|
410
|
+
def initialize(key_kind)
|
411
|
+
super("Invalid #{key_kind} key length. It should have 64 characters.")
|
412
|
+
end
|
413
|
+
end
|
414
|
+
```
|
415
|
+
|
416
|
+
## Constants Documentation
|
417
|
+
|
418
|
+
### Simple Constants
|
419
|
+
```ruby
|
420
|
+
# Numeric base of the OpenSSL big number used in an event content's encryption.
|
421
|
+
#
|
422
|
+
# @return [Integer]
|
423
|
+
#
|
424
|
+
BN_BASE = 16
|
425
|
+
```
|
426
|
+
|
427
|
+
### Complex Constants
|
428
|
+
```ruby
|
429
|
+
# The regular expression for hexadecimal lowercase characters
|
430
|
+
#
|
431
|
+
# @return [Regexp] The regular expression for hexadecimal lowercase characters
|
432
|
+
#
|
433
|
+
FORMAT = /^[a-f0-9]+$/
|
434
|
+
```
|
435
|
+
|
436
|
+
## Inheritance Documentation
|
437
|
+
|
438
|
+
### Subclass with Custom Behavior
|
439
|
+
```ruby
|
440
|
+
# 64-bytes lowercase hex of the signature of the sha256 hash of the serialized event data,
|
441
|
+
# which is the same as the "id" field
|
442
|
+
class Signature < String
|
443
|
+
# Custom implementation
|
444
|
+
end
|
445
|
+
```
|
446
|
+
|
447
|
+
### Module Inclusion
|
448
|
+
```ruby
|
449
|
+
# Clients can talk with relays and can subscribe to any set of events using a subscription filters.
|
450
|
+
#
|
451
|
+
# There is no sign-up or account creation for a client. Every time a client connects to a relay, it submits its
|
452
|
+
# subscription filters and the relay streams the "interested events" to the client as long as they are connected.
|
453
|
+
#
|
454
|
+
class Client
|
455
|
+
include EventEmitter
|
456
|
+
|
457
|
+
# class body
|
458
|
+
end
|
459
|
+
```
|
460
|
+
|
461
|
+
## Quality Enforcement
|
462
|
+
|
463
|
+
Our project enforces 100% documentation coverage using the `yardstick` gem and maintains documentation quality with the `yard:junk` task. This ensures that all code is thoroughly documented, maintainable, and easy for developers to use.
|
464
|
+
|
465
|
+
### How it Works
|
466
|
+
|
467
|
+
1. **Configuration**: A `.yardstick.yml` file in the project root sets the documentation coverage threshold to 100% and defines specific documentation rules.
|
468
|
+
|
469
|
+
2. **Measurement**: The `yardstick_measure` Rake task measures the current documentation coverage against the configured rules. Run it using:
|
470
|
+
|
471
|
+
```bash
|
472
|
+
bundle exec rake yardstick_measure
|
473
|
+
```
|
474
|
+
|
475
|
+
This task generates a detailed report in `measurements/report.txt` that lists all documentation issues that need to be addressed.
|
476
|
+
|
477
|
+
3. **Verification**: The `verify_measurements` Rake task checks if the coverage meets the 100% threshold. Run it using:
|
478
|
+
|
479
|
+
```bash
|
480
|
+
bundle exec rake verify_measurements
|
481
|
+
```
|
482
|
+
|
483
|
+
This task will fail if coverage is below 100%, displaying the current coverage percentage and indicating that documentation improvements are needed.
|
484
|
+
|
485
|
+
4. **Review Report**: Always check the contents of `measurements/report.txt` after running measurement tasks. This file contains specific details about:
|
486
|
+
- Missing method documentation
|
487
|
+
- Incomplete parameter descriptions
|
488
|
+
- Missing return value documentation
|
489
|
+
- Missing examples
|
490
|
+
- Incorrect API tags
|
491
|
+
|
492
|
+
Each line in the report shows the file, line number, method, and specific issue that needs to be addressed to achieve 100% documentation compliance.
|
493
|
+
|
494
|
+
### Rake Integration
|
495
|
+
|
496
|
+
The `Rakefile` integrates `yardstick` into our development workflow. The `qa` task, which runs a full suite of tests and checks, includes the documentation verification step.
|
497
|
+
|
498
|
+
```ruby
|
499
|
+
# Rakefile
|
500
|
+
require 'yardstick/rake/measurement'
|
501
|
+
require 'yardstick/rake/verify'
|
502
|
+
|
503
|
+
yardstick_options = YAML.load_file('.yardstick.yml')
|
504
|
+
|
505
|
+
Yardstick::Rake::Measurement.new(:yardstick_measure, yardstick_options)
|
506
|
+
Yardstick::Rake::Verify.new
|
507
|
+
|
508
|
+
desc 'Test, lint and perform security and documentation audits'
|
509
|
+
task qa: %w[spec rubocop yard:junk verify_measurements bundle:audit]
|
510
|
+
```
|
511
|
+
|
512
|
+
### CI Integration
|
513
|
+
|
514
|
+
Continuous Integration (CI) automatically enforces our documentation standard on every commit by running:
|
515
|
+
|
516
|
+
```bash
|
517
|
+
bundle exec rake verify_measurements
|
518
|
+
```
|
519
|
+
|
520
|
+
This prevents any code with incomplete documentation from being merged.
|
521
|
+
|
522
|
+
## Best Practices
|
523
|
+
|
524
|
+
### 1. **Always Use @api Tags**
|
525
|
+
Every method, class, and module must have an `@api public` or `@api private` tag.
|
526
|
+
|
527
|
+
### 2. **Provide Meaningful Examples**
|
528
|
+
Examples should show real usage, not trivial cases:
|
529
|
+
|
530
|
+
```ruby
|
531
|
+
# GOOD
|
532
|
+
# @example Subscribing to text notes from the last hour
|
533
|
+
# filter = Nostr::Filter.new(
|
534
|
+
# kinds: [Nostr::EventKind::TEXT_NOTE],
|
535
|
+
# since: Time.now.to_i - 3600
|
536
|
+
# )
|
537
|
+
# subscription = client.subscribe(filter: filter)
|
538
|
+
|
539
|
+
# BAD
|
540
|
+
# @example
|
541
|
+
# client.subscribe
|
542
|
+
```
|
543
|
+
|
544
|
+
### 3. **Document All Parameters**
|
545
|
+
Even obvious parameters should be documented:
|
546
|
+
|
547
|
+
```ruby
|
548
|
+
# @param id [String] The unique identifier
|
549
|
+
# @param name [String] The human-readable name
|
550
|
+
```
|
551
|
+
|
552
|
+
### 4. **Use Consistent Type Notation**
|
553
|
+
- `String` not `string`
|
554
|
+
- `Array<String>` for arrays of strings
|
555
|
+
- `Hash{String=>Object}` for hash types
|
556
|
+
- `Boolean` not `bool`
|
557
|
+
- `Integer` not `int`
|
558
|
+
|
559
|
+
### 5. **Document Return Values**
|
560
|
+
Every method must have a `@return` tag, even if it returns `void`.
|
561
|
+
|
562
|
+
### 6. **Cross-Reference Related Methods**
|
563
|
+
```ruby
|
564
|
+
# @see #valid_sig?
|
565
|
+
# @see Crypto#check_sig!
|
566
|
+
```
|
567
|
+
|
568
|
+
### 7. **Use Code Formatting**
|
569
|
+
Wrap class names and method names in `+` markers:
|
570
|
+
```ruby
|
571
|
+
# @raise ArgumentError when the private key is not a +PrivateKey+
|
572
|
+
```
|
573
|
+
|
574
|
+
### 8. **Document Inheritance Clearly**
|
575
|
+
When a class inherits behavior, mention it:
|
576
|
+
```ruby
|
577
|
+
# Base error class for all signature validation errors
|
578
|
+
class SignatureValidationError < Error; end
|
579
|
+
```
|
580
|
+
|
581
|
+
### 9. **Version Constants**
|
582
|
+
```ruby
|
583
|
+
# The version of the gem
|
584
|
+
VERSION = '0.7.0'
|
585
|
+
```
|
586
|
+
|
587
|
+
### 10. **Multi-line Examples**
|
588
|
+
For complex examples, use proper formatting:
|
589
|
+
```ruby
|
590
|
+
# @example Creating a comprehensive filter
|
591
|
+
# filter = Nostr::Filter.new(
|
592
|
+
# kinds: [
|
593
|
+
# Nostr::EventKind::TEXT_NOTE,
|
594
|
+
# Nostr::EventKind::ENCRYPTED_DIRECT_MESSAGE
|
595
|
+
# ],
|
596
|
+
# since: Time.now.to_i - 3600, # 1 hour ago
|
597
|
+
# until: Time.now.to_i,
|
598
|
+
# limit: 20,
|
599
|
+
# )
|
600
|
+
```
|
601
|
+
|
602
|
+
This documentation standard ensures that your Ruby projects maintain professional-quality documentation that supports both development and maintenance activities while providing excellent IDE integration and user experience.
|