Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 100 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
# Copilot Code Review Guidelines

---
This file configures GitHub Copilot Code Review according to GitHub’s official guidance: [Use Copilot Code Review](https://docs.github.com/en/copilot/how-tos/use-copilot-agents/request-a-code-review/use-code-review).

## Project Context

**Language:** Ruby ~> 4
**Framework:** [trailblazer](https://trailblazer.to/)
**Testing:** [minitest](https://docs.seattlerb.org/minitest/) following [BetterSpecs](https://evenbetterspecs.github.io/) guidelines

---

## Purpose & Scope

Focused inline review guidance for Ruby pull requests—style, tests, performance, and tone. (CI setup, contributor workflows, and documentation policies belong in separate docs.)

---

## 1. Style Guides

> ⚠️ **Be constructive:** Frame style feedback as suggestions (e.g., “Consider using…”).

All standard rules follow the [Shopify Ruby Style Guide](https://ruby-style-guide.shopify.dev/); only team-specific overrides are listed below:
- Indentation and line length enforced by RuboCop per project config.
- Use guard clauses, and explicit receivers.
- Prefer Railway Oriented Programming (ROP) for error handling and flow.
- Leverage dry-rb conventions and Trailblazer patterns for clarity and maintainability.
- Keep methods short. 1 line is fine. 5 is a lot. At 7, you should consider extracting a method.

---

## 2. Tone and Delivery

> 🤝 **Be succinct:** Don't overwhelm with too many minor issues; prioritize key improvements.

- Use phrasing like “Consider extracting…” or “You might simplify…” rather than absolutes.
- Keep comments concise—2–3 sentences max.

---

## 3. Conventions & Readability

> ✨ **Keep it clear:** Propose naming and structure that clarify intent.

- **SOLID principles:** Single responsibility; inject dependencies via initializers.
- **Descriptive names:** Recommend clear class, method, and variable names.
- **DRY:** Suggest extracting duplicate logic into modules or service objects.
- **Method size:** Flag methods >= 8 lines; suggest splitting into helpers.
- Ensure files have EOF newline.
- Flag trailing white space in code and comments.
- Always ensure rubocop runs cleanly.

---

## 4. Testing and Coverage

> 🧪 **Be thorough:** Highlight gaps in meaningful test coverage.

- Flag missing or outdated specs for changed behaviors (unit, integration, request).
- Suggest tests for edge cases: error conditions, invalid inputs, boundary values, and potential `nil` handling or pointer exceptions. Follow best practices from the [BetterSpecs style guide](https://evenbetterspecs.github.io/).
- Encourage descriptive `context` blocks and example names per [BetterSpecs](https://evenbetterspecs.github.io/).
- Flag missing specs when logic is updated but no tests were added or modified
---

## 5. Performance and Security

> 🚀 **Guard quality:** Call out patterns that may hurt performance or security.

- Detect potential N+1 queries; suggest `includes` or batching.
- Attempt to identify O(n^2) or O(n log n) algorithms; recommend more efficient alternatives.
- Flag raw SQL, unsanitized interpolation, or other patterns that could introduce potential SQL injection vulnerabilities; recommend parameter binding and Sequel-based alternatives. Build these into a model, avoid raw sequel unless absolutely necessary.
- Identify unescaped user input in route methods

---

## 6. Commit Message and PR title guidelines

> 📝 **Be clear:** Ensure commit messages and PR titles reflect changes accurately.

- We use Conventional Commits. Ensure commit messages follow the format: `<type>(<scope>): <description>`.
- We use Semantic PR titles as well, ensure PR titles also match the conventional commit format.

## 7. Balancing Feedback

> ⚖️ **Be selective:** Focus on the highest-impact issues.

- Limit critical suggestions to the top 3–5 items per review.
- Combine minor style tweaks into a single comment when possible.

---

## 8. Quick Reference

- **Max comment length:** 2–3 sentences.
- **Severity tags:** `[Major]`, `[Medium]`, `[Minor]`.
- **Mandatory header:** `Enable frozen-string-literal`.
- **Top issues:** 3–5 critical comments.

---
51 changes: 43 additions & 8 deletions Readme.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ Access Polymarket endpoints via the `polymarket` namespace.

==== Markets

[API Reference](https://docs.domeapi.io/api-reference/endpoint/get-markets)
https://docs.domeapi.io/api-reference/endpoint/get-markets[API Reference]

List markets with optional filtering:

Expand All @@ -69,7 +69,7 @@ price = client.polymarket.markets.price(token_id: 'token_id')

==== Candlesticks

[API Reference](https://docs.domeapi.io/api-reference/endpoint/get-candlesticks)
https://docs.domeapi.io/api-reference/endpoint/get-candlesticks[API Reference]

Get candlesticks:

Expand All @@ -85,7 +85,7 @@ candlesticks = client.polymarket.candlesticks.list(

==== Trade History

[API Reference](https://docs.domeapi.io/api-reference/endpoint/get-trade-history)
https://docs.domeapi.io/api-reference/endpoint/get-trade-history[API Reference]

Get trade history:

Expand All @@ -99,7 +99,7 @@ trades = client.polymarket.trade_history.list(

==== Orderbook

[API Reference](https://docs.domeapi.io/api-reference/endpoint/get-orderbook-history)
https://docs.domeapi.io/api-reference/endpoint/get-orderbook-history[API Reference]

Get orderbook history:

Expand All @@ -114,7 +114,7 @@ snapshots = client.polymarket.orderbook.list(

==== Activity

[API Reference](https://docs.domeapi.io/api-reference/endpoint/get-activity)
https://docs.domeapi.io/api-reference/endpoint/get-activity[API Reference]

Get activity:

Expand All @@ -128,7 +128,7 @@ activity = client.polymarket.activity.list(

==== Market Price

[API Reference](https://docs.domeapi.io/api-reference/endpoint/get-market-price)
https://docs.domeapi.io/api-reference/endpoint/get-market-price[API Reference]

Get market price history:

Expand All @@ -142,7 +142,7 @@ prices = client.polymarket.market_price.list(

==== Wallet

[API Reference](https://docs.domeapi.io/api-reference/endpoint/get-wallet)
https://docs.domeapi.io/api-reference/endpoint/get-wallet[API Reference]

Get wallet information:

Expand All @@ -155,7 +155,7 @@ wallet = client.polymarket.wallet.list(

==== Wallet Profit and Loss

[API Reference](https://docs.domeapi.io/api-reference/endpoint/get-wallet-pnl)
https://docs.domeapi.io/api-reference/endpoint/get-wallet-pnl[API Reference]

Get wallet profit and loss:

Expand All @@ -167,6 +167,41 @@ pnl = client.polymarket.wallet_profit_and_loss.list(
)
----

=== Matching Markets

Access Matching Markets endpoints via the `matching_markets` namespace.

==== Sports

https://docs.domeapi.io/api-reference/endpoint/get-matching-markets-sports[API Reference]

List matching markets for a specific sport and date:

[source,ruby]
----
# Using dynamic methods
markets = client.matching_markets.nfl_on(Date.today)
markets = client.matching_markets.nba_on('2023-12-25')

# Using sports_by_date method
markets = client.matching_markets.sports_by_date(sport: 'nfl', date: Date.today)
----

==== Markets

https://docs.domeapi.io/api-reference/endpoint/get-matching-markets[API Reference]

List matching markets by slug or ticker:

[source,ruby]
----
# By Polymarket slug
markets = client.matching_markets.sports(polymarket_market_slug: 'super-bowl-lviii-winner')

# By Kalshi ticker
markets = client.matching_markets.sports(kalshi_event_ticker: 'SB58')
----

== Development

After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
Expand Down
4 changes: 4 additions & 0 deletions lib/domeapi/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ def polymarket
@polymarket ||= Polymarket::Client.new(clone)
end

def matching_markets
@matching_markets ||= MatchingMarkets.new(self)
end
Comment on lines +31 to +33
Copy link

Copilot AI Jan 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing test coverage for the new matching_markets method added to the Client class. Similar to the existing test for polymarket on line 32-34, there should be a test verifying that client.matching_markets returns an instance of Rubyists::Domeapi::MatchingMarkets.

Copilot uses AI. Check for mistakes.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot open a new pull request to apply changes based on this feedback

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot open a new pull request to apply changes based on this feedback. Make sure all of your commit messages and PR titles pass the Conventional Commits action check.


private

def full_url(path)
Expand Down
92 changes: 92 additions & 0 deletions lib/domeapi/matching_markets.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# frozen_string_literal: true

module Rubyists
module Domeapi
# Matching Markets API endpoints
class MatchingMarkets
SPORTS = %w[nfl mlb cfb nba nhl cbb].freeze

# Filter for matching markets sports
class SportsFilter < Contract
propertize(%i[sport date])

validation do
params do
required(:sport).filled(:string, included_in?: SPORTS)
required(:date).filled(:string, format?: /\A\d{4}-\d{2}-\d{2}\z/)
end
end
end

# Filter for matching markets
class Filter < Contract
propertize(%i[polymarket_market_slug kalshi_event_ticker])

validation do
params do
optional(:polymarket_market_slug).maybe(Types::PolymarketMarketSlug)
optional(:kalshi_event_ticker).maybe(Types::KalshiEventTicker)
end

rule(:polymarket_market_slug, :kalshi_event_ticker) do
if !values[:polymarket_market_slug] && !values[:kalshi_event_ticker]
key.failure('Either polymarket_market_slug or kalshi_event_ticker must be provided')
end
end
end
end

attr_reader :client

# @param client [Rubyists::Domeapi::Client]
#
# @return [void]
def initialize(client = Rubyists::Domeapi::Client.new)
@client = client
end

# List matching markets
#
# @param filter [Filter|Hash] Filter options
#
# @return [Hash|Array] resource data
def sports(filter = Filter.new(Filter::Properties.new))
filter = Filter.new(Filter::Properties.new(**filter)) if filter.is_a?(Hash)
raise ArgumentError, filter.errors.full_messages.join(', ') unless filter.validate({})

client.get('matching-markets/sports', params: filter.to_h)
end

# List matching markets for a specific sport and date
#
# @param filter [SportsFilter|Hash] Filter options
#
# @return [Hash|Array] resource data
def sports_by_date(filter = SportsFilter.new(SportsFilter::Properties.new))
filter = prepare_sports_filter(filter)
raise ArgumentError, filter.errors.full_messages.join(', ') unless filter.validate({})

client.get("matching-markets/sports/#{filter.sport}", params: { date: filter.date })
end

SPORTS.each do |sport|
define_method("#{sport}_on") do |date|
sports_by_date(sport: sport, date: date)
end

define_singleton_method("#{sport}_on") do |date|
new.send("#{sport}_on", date)
end
end

private

def prepare_sports_filter(filter)
return filter unless filter.is_a?(Hash)

filter[:date] = filter[:date].strftime('%Y-%m-%d') if filter[:date].respond_to?(:strftime)
SportsFilter.new(SportsFilter::Properties.new(**filter))
end
end
end
end
2 changes: 0 additions & 2 deletions lib/domeapi/polymarket/activity.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ class Filter < Contract
propertize(%i[user start_time end_time market_slug condition_id limit offset])

validation do
# :nocov:
params do
required(:user).filled(:string)
optional(:start_time).maybe(:integer)
Expand All @@ -24,7 +23,6 @@ class Filter < Contract
optional(:limit).maybe(:integer, gteq?: 1, lteq?: 1000)
optional(:offset).maybe(:integer, gteq?: 0)
end
# :nocov:
end
end
end
Expand Down
2 changes: 0 additions & 2 deletions lib/domeapi/polymarket/candlesticks.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,12 @@ class Filter < Contract
propertize(%i[condition_id start_time end_time interval])

validation do
# :nocov:
params do
required(:condition_id).filled(:string)
required(:start_time).filled(:integer)
required(:end_time).filled(:integer)
optional(:interval).maybe(:integer, gteq?: 1, lteq?: 1440)
end
# :nocov:
end
end
end
Expand Down
2 changes: 0 additions & 2 deletions lib/domeapi/polymarket/market_price.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,10 @@ class Filter < Contract
propertize(%i[token_id at_time])

validation do
# :nocov:
params do
required(:token_id).filled(:string)
optional(:at_time).maybe(:integer)
end
# :nocov:
end
end
end
Expand Down
2 changes: 0 additions & 2 deletions lib/domeapi/polymarket/markets.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,10 @@ class Filter < Contract
propertize(%i[market_slug event_slug condition_id tags status min_volume limit offset start_time end_time])

validation do
# :nocov:
params do
optional(:status).maybe(:string, included_in?: %w[open closed])
optional(:offset).maybe(:integer, gteq?: 0, lteq?: 100)
end
# :nocov:
end
end

Expand Down
2 changes: 0 additions & 2 deletions lib/domeapi/polymarket/orderbook.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,13 @@ class Filter < Contract
propertize(%i[token_id start_time end_time limit offset])

validation do
# :nocov:
params do
required(:token_id).filled(:string)
required(:start_time).filled(:integer)
required(:end_time).filled(:integer)
optional(:limit).maybe(:integer, gteq?: 1, lteq?: 1000)
optional(:offset).maybe(:integer, gteq?: 0)
end
# :nocov:
end
end
end
Expand Down
Loading