Add initial RBS support with Steep and TypeProf

This commit is contained in:
Wilson Silva 2023-01-22 17:42:59 +07:00
parent 59e058d511
commit 8f6a7547f5
No known key found for this signature in database
GPG Key ID: 65135F94E23F82C8
19 changed files with 290 additions and 1 deletions

View File

@ -27,7 +27,6 @@ All examples below assume that the gem has been required.
require 'nostr' require 'nostr'
``` ```
### Generating a keypair ### Generating a keypair
```ruby ```ruby
@ -221,6 +220,13 @@ rake yard:junk # Check the junk in your YARD Documentation
rake yardstick_measure # Measure docs in lib/**/*.rb with yardstick rake yardstick_measure # Measure docs in lib/**/*.rb with yardstick
``` ```
### Type checking
This gem leverages [RBS](https://github.com/ruby/rbs), a language to describe the structure of Ruby programs. It is
used to provide type checking and autocompletion in your editor. Run `bundle exec typeprof FILENAME` to generate
an RBS definition for the given Ruby file. And validate all definitions using [Steep](https://github.com/soutaro/steep)
with the command `bundle exec steep check`.
## Contributing ## Contributing
Bug reports and pull requests are welcome on GitHub at https://github.com/wilsonsilva/nostr. Bug reports and pull requests are welcome on GitHub at https://github.com/wilsonsilva/nostr.

14
Steepfile Normal file
View File

@ -0,0 +1,14 @@
# frozen_string_literal: true
target :lib do
signature 'sig'
check 'lib'
# Core libraries
library 'digest'
library 'securerandom'
# Gems
library 'json'
end

View File

@ -50,12 +50,15 @@ Gem::Specification.new do |spec|
spec.add_development_dependency 'puma', '~> 5.6' spec.add_development_dependency 'puma', '~> 5.6'
spec.add_development_dependency 'rack', '~> 3.0' spec.add_development_dependency 'rack', '~> 3.0'
spec.add_development_dependency 'rake', '~> 13.0' spec.add_development_dependency 'rake', '~> 13.0'
spec.add_development_dependency 'rbs', '~> 2.8'
spec.add_development_dependency 'rspec', '~> 3.12' spec.add_development_dependency 'rspec', '~> 3.12'
spec.add_development_dependency 'rubocop', '~> 1.42' spec.add_development_dependency 'rubocop', '~> 1.42'
spec.add_development_dependency 'rubocop-rake', '~> 0.6' spec.add_development_dependency 'rubocop-rake', '~> 0.6'
spec.add_development_dependency 'rubocop-rspec', '2.16' spec.add_development_dependency 'rubocop-rspec', '2.16'
spec.add_development_dependency 'simplecov', '= 0.17' spec.add_development_dependency 'simplecov', '= 0.17'
spec.add_development_dependency 'simplecov-console', '~> 0.9' spec.add_development_dependency 'simplecov-console', '~> 0.9'
spec.add_development_dependency 'steep', '~> 1.3'
spec.add_development_dependency 'typeprof', '~> 0.21'
spec.add_development_dependency 'yard', '~> 0.9' spec.add_development_dependency 'yard', '~> 0.9'
spec.add_development_dependency 'yard-junk', '~> 0.0.9' spec.add_development_dependency 'yard-junk', '~> 0.0.9'
spec.add_development_dependency 'yardstick', '~> 0.9' spec.add_development_dependency 'yardstick', '~> 0.9'

20
sig/nostr/client.rbs Normal file
View File

@ -0,0 +1,20 @@
module Nostr
class Client
include EventEmitter
def initialize: -> void
def connect: (Relay relay) -> Thread
def subscribe: (?subscription_id: String, ?filter: Filter) -> Subscription
def unsubscribe: (String subscription_id) -> untyped
def publish: (Event event) -> untyped
private
attr_reader subscriptions: Hash[String, Subscription]
attr_reader parent_to_child_channel: untyped
attr_reader child_to_parent_channel: untyped
def execute_within_an_em_thread: { -> untyped } -> Thread
def initialize_channels: -> untyped
end
end

View File

@ -0,0 +1,7 @@
module Nostr
module ClientMessageType
EVENT: String
REQ: String
CLOSE: String
end
end

24
sig/nostr/event.rbs Normal file
View File

@ -0,0 +1,24 @@
module Nostr
class Event < EventFragment
attr_reader id: String
attr_reader sig: String
def initialize: (id: String, sig: String,
created_at: Integer,
kind: Integer,
tags: Array[String],
content: String,
) -> void
def to_h: -> {
id: String,
pubkey: String,
created_at: Integer,
kind: Integer,
tags: Array[String],
content: String,
sig: String
}
def ==: (Event other) -> bool
end
end

View File

@ -0,0 +1,12 @@
module Nostr
class EventFragment
attr_reader pubkey: String
attr_reader created_at: Integer
attr_reader kind: Integer
attr_reader tags: Array[String]
attr_reader content: String
def initialize: (pubkey: String, kind: Integer, content: String, ?created_at: Integer, ?tags: Array[String]) -> void
def serialize: -> [Integer, String, Integer, Integer, Array[String], String]
end
end

8
sig/nostr/event_kind.rbs Normal file
View File

@ -0,0 +1,8 @@
module Nostr
module EventKind
SET_METADATA: Integer
TEXT_NOTE: Integer
RECOMMEND_SERVER: Integer
CONTACTS: Integer
end
end

25
sig/nostr/filter.rbs Normal file
View File

@ -0,0 +1,25 @@
module Nostr
class Filter
attr_reader ids: Array[String]
attr_reader authors: Array[String]
attr_reader kinds: Array[Integer]
attr_reader e: String
attr_reader p: String
attr_reader since: Integer
attr_reader until: Integer
attr_reader limit: Integer
def initialize: (**untyped) -> void
def to_h: -> {
ids: Array[String],
authors: Array[String],
kinds: Array[Integer],
e: String,
p: String,
since: Integer,
until: Integer,
limit: Integer
}
def ==: (Filter other) -> bool
end
end

9
sig/nostr/key_pair.rbs Normal file
View File

@ -0,0 +1,9 @@
# Classes
module Nostr
class KeyPair
attr_reader private_key: String
attr_reader public_key: String
def initialize: (private_key: String, public_key: String) -> void
end
end

13
sig/nostr/keygen.rbs Normal file
View File

@ -0,0 +1,13 @@
# Classes
module Nostr
class Keygen
def initialize: -> void
def generate_key_pair: -> KeyPair
def generate_private_key: -> String
def extract_public_key: (String private_key) -> String
private
attr_reader group: untyped
end
end

9
sig/nostr/relay.rbs Normal file
View File

@ -0,0 +1,9 @@
# Classes
module Nostr
class Relay
attr_reader url: String
attr_reader name: String
def initialize: (url: String, name: String) -> void
end
end

View File

@ -0,0 +1,9 @@
module Nostr
class Subscription
attr_reader id: String
attr_reader filter: Filter
def initialize: (filter: Filter, ?id: String) -> void
def ==: (Subscription other) -> bool
end
end

24
sig/nostr/user.rbs Normal file
View File

@ -0,0 +1,24 @@
# Classes
module Nostr
class User
attr_reader keypair: KeyPair
def initialize: (?keypair: KeyPair | nil, ?keygen: Keygen) -> void
def create_event: (
{
id: String,
pubkey: String,
created_at: Integer,
kind: Integer,
tags: Array[String],
content: String,
created_at: Integer,
sig: String
}
) -> Event
private
def sign: (String event_sha256) -> String
end
end

6
sig/vendor/ecsda/group/secp256k1.rbs vendored Normal file
View File

@ -0,0 +1,6 @@
# Added only to satisfy the Steep requirements. Not 100% reliable.
module ECDSA
class Group
Secp256k1: Group
end
end

9
sig/vendor/event_emitter.rbs vendored Normal file
View File

@ -0,0 +1,9 @@
# Added only to satisfy the Steep requirements. Not 100% reliable.
module EventEmitter
def add_listener: (untyped `type`, ?{once: true} params) -> Integer
alias on add_listener
def remove_listener: (untyped id_or_type) -> Array[untyped]?
def emit: (untyped `type`, *untyped data) -> Array[untyped]
def once: (untyped `type`) -> Integer
end

69
sig/vendor/event_machine.rbs vendored Normal file
View File

@ -0,0 +1,69 @@
# Added only to satisfy the Steep requirements. Not 100% reliable.
module EventMachine
ERRNOS: Hash[untyped, untyped]
P: untyped
self.@next_tick_mutex: Thread::Mutex
self.@reactor_running: bool
self.@next_tick_queue: Array[^-> untyped]
self.@tails: Array[nil]
self.@resultqueue: (Array[untyped] | Thread::Queue)?
self.@threadqueue: Thread::Queue?
self.@threadpool: Array[untyped]?
self.@all_threads_spawned: bool
self.@reactor_pid: Integer
self.@conns: Hash[untyped, untyped]
self.@acceptors: Hash[untyped, Array[(Array[untyped] | Integer)?]]
self.@timers: Hash[untyped, Integer | ^-> untyped | false]
self.@wrapped_exception: Exception?
self.@reactor_thread: Thread?
self.@threadpool_size: bot
self.@error_handler: bot
def self.run: (?untyped blk, ?nil tail) ?{ -> untyped } -> nil
def self.run_block: -> nil
def self.reactor_thread?: -> bool
def self.schedule: (*untyped a) -> nil
def self.fork_reactor: -> Integer?
def self.cleanup_machine: -> Array[untyped]
def self.add_shutdown_hook: -> Array[nil]
def self.add_timer: (*Integer | ^-> untyped args) ?{ -> untyped } -> nil
def self.add_periodic_timer: (*untyped args) -> untyped
def self.cancel_timer: (untyped timer_or_sig) -> false?
def self.stop_event_loop: -> untyped
def self.start_server: (untyped server, ?nil port, ?nil handler, *untyped args) -> untyped
def self.attach_server: (untyped sock, ?nil handler, *untyped args) -> untyped
def self.stop_server: (untyped signature) -> untyped
def self.start_unix_domain_server: (untyped filename, *untyped args) -> untyped
def self.connect: (untyped server, ?nil port, ?nil handler, *untyped args) -> untyped
def self.bind_connect: (nil bind_addr, nil bind_port, untyped server, ?nil port, ?nil handler, *untyped args) -> untyped
def self.watch: (untyped io, ?nil handler, *untyped args) -> untyped
def self.attach: (untyped io, ?nil handler, *untyped args) -> untyped
def self.attach_io: (untyped io, bool watch_mode, ?nil handler, *untyped args) -> untyped
def self.reconnect: (untyped server, untyped port, untyped handler) -> untyped
def self.connect_unix_domain: (untyped socketname, *untyped args) -> untyped
def self.open_datagram_socket: (untyped address, untyped port, ?nil handler, *untyped args) -> untyped
def self.set_quantum: (untyped mills) -> untyped
def self.set_max_timers: (untyped ct) -> untyped
def self.get_max_timers: -> untyped
def self.connection_count: -> untyped
def self.run_deferred_callbacks: -> Integer
def self.defer: (?nil op, ?nil callback, ?nil errback) -> untyped
def self.spawn_threadpool: -> true
def self.defers_finished?: -> bool
def self.next_tick: (?nil pr) { -> nil } -> nil
def self.set_effective_user: (untyped username) -> untyped
def self.set_descriptor_table_size: (?nil n_descriptors) -> untyped
def self.popen: (untyped cmd, ?nil handler, *untyped args) -> untyped
def self.reactor_running?: -> bool
def self.open_keyboard: (?nil handler, *untyped args) -> untyped
def self.watch_file: (untyped filename, ?nil handler, *untyped args) -> untyped
def self.watch_process: (untyped pid, ?nil handler, *untyped args) -> untyped
def self.error_handler: (?nil cb) -> nil
def self.enable_proxy: (untyped from, untyped to, ?Integer bufsize, ?Integer length) -> untyped
def self.disable_proxy: (untyped from) -> untyped
def self.heartbeat_interval: -> untyped
def self.heartbeat_interval=: (untyped time) -> untyped
def self.event_callback: (untyped conn_binding, untyped opcode, untyped data) -> Integer?
def self._open_file_for_writing: (untyped filename, ?nil handler) -> untyped
def self.klass_from_handler: (?untyped klass, ?Integer? handler, *nil args) -> Integer
end

18
sig/vendor/event_machine/channel.rbs vendored Normal file
View File

@ -0,0 +1,18 @@
# Added only to satisfy the Steep requirements. Not 100% reliable.
module EventMachine
class Channel
@subs: Hash[untyped, untyped]
@uid: Integer
def initialize: -> void
def num_subscribers: -> Integer
def subscribe: (*untyped a) ?{ -> untyped } -> Integer
def unsubscribe: (untyped name) -> untyped
def push: (*untyped items) -> untyped
alias << push
def pop: (*untyped a) -> untyped
private
def gen_id: -> Integer
end
end

4
sig/vendor/schnorr.rbs vendored Normal file
View File

@ -0,0 +1,4 @@
# Added only to satisfy the Steep requirements. Not 100% reliable.
module Schnorr
def self.sign: (String message, String private_key, ?String aux_rand) -> untyped
end