"], "crystal" => "0.25.0", "license" => "MIT"}
-```
-
-#### Binary Data
-
-Store binary data (eg, `application/octet-stream`) to file, you can use [streaming requests](#streaming-requests):
-
-```crystal
-Halite.get("https://github.com/icyleaf/halite/archive/master.zip") do |response|
- filename = response.filename || "halite-master.zip"
- File.open(filename, "w") do |file|
- IO.copy(response.body_io, file)
- end
-end
-```
-
-### Error Handling
-
-- For any status code, a `Halite::Response` will be returned.
-- If request timeout, a `Halite::TimeoutError` will be raised.
-- If a request exceeds the configured number of maximum redirections, a `Halite::TooManyRedirectsError` will raised.
-- If request uri is http and configured tls context, a `Halite::RequestError` will raised.
-- If request uri is invalid, a `Halite::ConnectionError`/`Halite::UnsupportedMethodError`/`Halite::UnsupportedSchemeError` will raised.
-
-#### Raise for status code
-
-If we made a bad request(a 4xx client error or a 5xx server error response), we can raise with `Halite::Response.raise_for_status`.
-
-But, since our `status_code` was not `4xx` or `5xx`, it returns `nil` when we call it:
-
-```crystal
-urls = [
- "https://httpbin.org/status/404",
- "https://httpbin.org/status/500?foo=bar",
- "https://httpbin.org/status/200",
-]
-
-urls.each do |url|
- r = Halite.get url
- begin
- r.raise_for_status
- p r.body
- rescue ex : Halite::ClientError | Halite::ServerError
- p "[#{ex.status_code}] #{ex.status_message} (#{ex.class})"
- end
-end
-
-# => "[404] not found error with url: https://httpbin.org/status/404 (Halite::Exception::ClientError)"
-# => "[500] internal server error error with url: https://httpbin.org/status/500?foo=bar (Halite::Exception::ServerError)"
-# => ""
-```
-
-## Middleware
-
-Halite now has middleware (a.k.a features) support providing a simple way to plug in intermediate custom logic
-in your HTTP client, allowing you to monitor outgoing requests, incoming responses, and use it as an interceptor.
-
-Available features:
-
-- [Logging](#logging) (Yes, logging is based on feature, cool, aha!)
-- [Local Cache](#local-cache) (local storage, speed up in development)
-
-### Write a simple feature
-
-Let's implement simple middleware that prints each request:
-
-```crystal
-class RequestMonister < Halite::Feature
- @label : String
- def initialize(**options)
- @label = options.fetch(:label, "")
- end
-
- def request(request) : Halite::Request
- puts @label
- puts request.verb
- puts request.uri
- puts request.body
-
- request
- end
-
- Halite.register_feature "request_monster", self
-end
-```
-
-Then use it in Halite:
-
-```crystal
-Halite.use("request_monster", label: "testing")
- .post("http://httpbin.org/post", form: {name: "foo"})
-
-# Or configure to client
-client = Halite::Client.new do
- use "request_monster", label: "testing"
-end
-
-client.post("http://httpbin.org/post", form: {name: "foo"})
-
-# => testing
-# => POST
-# => http://httpbin.org/post
-# => name=foo
-```
-
-### Write a interceptor
-
-Halite's killer feature is the **interceptor**, Use `Halite::Feature::Chain` to process with two result:
-
-- `next`: perform and run next interceptor
-- `return`: perform and return
-
-So, you can intercept and turn to the following registered features.
-
-```crystal
-class AlwaysNotFound < Halite::Feature
- def intercept(chain)
- response = chain.perform
- response = Halite::Response.new(chain.request.uri, 404, response.body, response.headers)
- chain.next(response)
- end
-
- Halite.register_feature "404", self
-end
-
-class PoweredBy < Halite::Feature
- def intercept(chain)
- if response = chain.response
- response.headers["X-Powered-By"] = "Halite"
- chain.return(response)
- else
- chain
- end
- end
-
- Halite.register_feature "powered_by", self
-end
-
-r = Halite.use("404").use("powered_by").get("http://httpbin.org/user-agent")
-r.status_code # => 404
-r.headers["X-Powered-By"] # => Halite
-r.body # => {"user-agent":"Halite/0.6.0"}
-```
-
-For more implementation details about the feature layer, see the [Feature](https://github.com/icyleaf/halite/blob/master/src/halite/feature.cr#L2) class and [examples](https://github.com/icyleaf/halite/tree/master/src/halite/features) and [specs](https://github.com/icyleaf/halite/blob/master/spec/spec_helper.cr#L23).
-
-## Advanced Usage
-
-### Configuring
-
-Halite provides a traditional way to instance client, and you can configure any chainable methods with block:
-
-```crystal
-client = Halite::Client.new do
- # Set basic auth
- basic_auth "username", "password"
-
- # Enable logging
- logging true
-
- # Set timeout
- timeout 10.seconds
-
- # Set user agent
- headers user_agent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36"
-end
-
-# You also can configure in this way
-client.accept("application/json")
-
-r = client.get("http://httpbin.org/get")
-```
-
-### Endpoint
-
-No more given endpoint per request, use `endpoint` will make the request URI shorter, you can set it in flexible way:
-
-```crystal
-client = Halite::Client.new do
- endpoint "https://gitlab.org/api/v4"
- user_agent "Halite"
-end
-
-client.get("users") # GET https://gitlab.org/api/v4/users
-
-# You can override the path by using an absolute path
-client.get("/users") # GET https://gitlab.org/users
-```
-
-### Sessions
-
-As like [requests.Session()](http://docs.python-requests.org/en/master/user/advanced/#session-objects), Halite built-in session by default.
-
-Let's persist some cookies across requests:
-
-```crystal
-client = Halite::Client.new
-client.get("http://httpbin.org/cookies/set?private_token=6abaef100b77808ceb7fe26a3bcff1d0")
-client.get("http://httpbin.org/cookies")
-# => 2018-06-25 18:41:05 +08:00 | request | GET | http://httpbin.org/cookies/set?private_token=6abaef100b77808ceb7fe26a3bcff1d0
-# => 2018-06-25 18:41:06 +08:00 | response | 302 | http://httpbin.org/cookies/set?private_token=6abaef100b77808ceb7fe26a3bcff1d0 | text/html
-# =>
-# => Redirecting...
-# => Redirecting...
-# => You should be redirected automatically to target URL: /cookies. If not click the link.
-# => 2018-06-25 18:41:06 +08:00 | request | GET | http://httpbin.org/cookies
-# => 2018-06-25 18:41:07 +08:00 | response | 200 | http://httpbin.org/cookies | application/json
-# => {"cookies":{"private_token":"6abaef100b77808ceb7fe26a3bcff1d0"}}
-```
-
-All it support with [chainable methods](https://icyleaf.github.io/halite/Halite/Chainable.html) in the other examples list in [requests.Session](http://docs.python-requests.org/en/master/user/advanced/#session-objects).
-
-Note, however, that chainable methods will not be persisted across requests, even if using a session. This example will only send the cookies or headers with the first request, but not the second:
-
-```crystal
-client = Halite::Client.new
-r = client.cookies("username": "foobar").get("http://httpbin.org/cookies")
-r.body # => {"cookies":{"username":"foobar"}}
-
-r = client.get("http://httpbin.org/cookies")
-r.body # => {"cookies":{}}
-```
-
-If you want to manually add cookies, headers (even features etc) to your session, use the methods start with `with_` in `Halite::Options`
-to manipulate them:
-
-```crystal
-r = client.get("http://httpbin.org/cookies")
-r.body # => {"cookies":{}}
-
-client.options.with_cookie("username": "foobar")
-r = client.get("http://httpbin.org/cookies")
-r.body # => {"cookies":{"username":"foobar"}}
-```
-
-### Streaming Requests
-
-Similar to [HTTP::Client](https://crystal-lang.org/api/0.36.1/HTTP/Client.html#streaming) usage with a block,
-you can easily use same way, but Halite returns a `Halite::Response` object:
-
-```crystal
-r = Halite.get("http://httpbin.org/stream/5") do |response|
- response.status_code # => 200
- response.body_io.each_line do |line|
- puts JSON.parse(line) # => {"url" => "http://httpbin.org/stream/5", "args" => {}, "headers" => {"Host" => "httpbin.org", "Connection" => "close", "User-Agent" => "Halite/0.8.0", "Accept" => "*/*", "Accept-Encoding" => "gzip, deflate"}, "id" => 0_i64}
- end
-end
-```
-
-> **Warning**:
->
-> `body_io` is avaiabled as an `IO` and not reentrant safe. Might throws a "Nil assertion failed" exception if there is no data in the `IO`
-(such like `head` requests). Calling this method multiple times causes some of the received data being lost.
->
-> One more thing, use streaming requests the response will always [enable redirect](#redirects-and-history) automatically.
-
-### Logging
-
-Halite does not enable logging on each request and response too.
-We can enable per operation logging by configuring them through the chaining API.
-
-By default, Halite will logging all outgoing HTTP requests and their responses(without binary stream) to `STDOUT` on DEBUG level.
-You can configuring the following options:
-
-- `logging`: Instance your `Halite::Logging::Abstract`, check [Use the custom logging](#use-the-custom-logging).
-- `format`: Output format, built-in `common` and `json`, you can write your own.
-- `file`: Write to file with path, works with `format`.
-- `filemode`: Write file mode, works with `format`, by default is `a`. (append to bottom, create it if file is not exist)
-- `skip_request_body`: By default is `false`.
-- `skip_response_body`: By default is `false`.
-- `skip_benchmark`: Display elapsed time, by default is `false`.
-- `colorize`: Enable colorize in terminal, only apply in `common` format, by default is `true`.
-
-> **NOTE**: `format` (`file` and `filemode`) and `logging` are conflict, you can not use both.
-
-Let's try with it:
-
-```crystal
-# Logging json request
-Halite.logging
- .get("http://httpbin.org/get", params: {name: "foobar"})
-
-# => 2018-06-25 18:33:14 +08:00 | request | GET | http://httpbin.org/get?name=foobar
-# => 2018-06-25 18:33:15 +08:00 | response | 200 | http://httpbin.org/get?name=foobar | 381.32ms | application/json
-# => {"args":{"name":"foobar"},"headers":{"Accept":"*/*","Accept-Encoding":"gzip, deflate","Connection":"close","Host":"httpbin.org","User-Agent":"Halite/0.3.2"},"origin":"60.206.194.34","url":"http://httpbin.org/get?name=foobar"}
-
-# Logging image request
-Halite.logging
- .get("http://httpbin.org/image/png")
-
-# => 2018-06-25 18:34:15 +08:00 | request | GET | http://httpbin.org/image/png
-# => 2018-06-25 18:34:15 +08:00 | response | 200 | http://httpbin.org/image/png | image/png
-
-# Logging with options
-Halite.logging(skip_request_body: true, skip_response_body: true)
- .post("http://httpbin.org/get", form: {image: File.open("halite-logo.png")})
-
-# => 2018-08-28 14:33:19 +08:00 | request | POST | http://httpbin.org/post
-# => 2018-08-28 14:33:21 +08:00 | response | 200 | http://httpbin.org/post | 1.61s | application/json
-```
-
-#### JSON-formatted logging
-
-It has JSON formatted for developer friendly logging.
-
-```
-Halite.logging(format: "json")
- .get("http://httpbin.org/get", params: {name: "foobar"})
-```
-
-#### Write to a log file
-
-```crystal
-# Write plain text to a log file
-Log.setup("halite.file", backend: Log::IOBackend.new(File.open("/tmp/halite.log", "a")))
-Halite.logging(for: "halite.file", skip_benchmark: true, colorize: false)
- .get("http://httpbin.org/get", params: {name: "foobar"})
-
-# Write json data to a log file
-Log.setup("halite.file", backend: Log::IOBackend.new(File.open("/tmp/halite.log", "a")))
-Halite.logging(format: "json", for: "halite.file")
- .get("http://httpbin.org/get", params: {name: "foobar"})
-
-# Redirect *all* logging from Halite to a file:
-Log.setup("halite", backend: Log::IOBackend.new(File.open("/tmp/halite.log", "a")))
-```
-
-#### Use the custom logging
-
-Creating the custom logging by integration `Halite::Logging::Abstract` abstract class.
-Here has two methods must be implement: `#request` and `#response`.
-
-```crystal
-class CustomLogging < Halite::Logging::Abstract
- def request(request)
- @logger.info { "| >> | %s | %s %s" % [request.verb, request.uri, request.body] }
- end
-
- def response(response)
- @logger.info { "| << | %s | %s %s" % [response.status_code, response.uri, response.content_type] }
- end
-end
-
-# Add to adapter list (optional)
-Halite::Logging.register "custom", CustomLogging.new
-
-Halite.logging(logging: CustomLogging.new)
- .get("http://httpbin.org/get", params: {name: "foobar"})
-
-# We can also call it use format name if you added it.
-Halite.logging(format: "custom")
- .get("http://httpbin.org/get", params: {name: "foobar"})
-
-# => 2017-12-13 16:40:13 +08:00 | >> | GET | http://httpbin.org/get?name=foobar
-# => 2017-12-13 16:40:15 +08:00 | << | 200 | http://httpbin.org/get?name=foobar application/json
-```
-
-### Local Cache
-
-Local cache feature is caching responses easily with Halite through an chainable method that is simple and elegant
-yet powerful. Its aim is to focus on the HTTP part of caching and do not worrying about how stuff stored, api rate limiting
-even works without network(offline).
-
-It has the following options:
-
-- `file`: Load cache from file. it conflict with `path` and `expires`.
-- `path`: The path of cache, default is "/tmp/halite/cache/"
-- `expires`: The expires time of cache, default is never expires.
-- `debug`: The debug mode of cache, default is `true`
-
-With debug mode, cached response it always included some headers information:
-
-- `X-Halite-Cached-From`: Cache source (cache or file)
-- `X-Halite-Cached-Key`: Cache key with verb, uri and body (return with cache, not `file` passed)
-- `X-Halite-Cached-At`: Cache created time
-- `X-Halite-Cached-Expires-At`: Cache expired time (return with cache, not `file` passed)
-
-```crystal
-Halite.use("cache").get "http://httpbin.org/anything" # request a HTTP
-r = Halite.use("cache").get "http://httpbin.org/anything" # request from local storage
-r.headers # => {..., "X-Halite-Cached-At" => "2018-08-30 10:41:14 UTC", "X-Halite-Cached-By" => "Halite", "X-Halite-Cached-Expires-At" => "2018-08-30 10:41:19 UTC", "X-Halite-Cached-Key" => "2bb155e6c8c47627da3d91834eb4249a"}}
-```
-
-### Link Headers
-
-Many HTTP APIs feature [Link headers](https://tools.ietf.org/html/rfc5988). GitHub uses
-these for [pagination](https://developer.github.com/v3/#pagination) in their API, for example:
-
-```crystal
-r = Halite.get "https://api.github.com/users/icyleaf/repos?page=1&per_page=2"
-r.links
-# => {"next" =>
-# => Halite::HeaderLink(
-# => @params={},
-# => @rel="next",
-# => @target="https://api.github.com/user/17814/repos?page=2&per_page=2"),
-# => "last" =>
-# => Halite::HeaderLink(
-# => @params={},
-# => @rel="last",
-# => @target="https://api.github.com/user/17814/repos?page=41&per_page=2")}
-
-r.links["next"]
-# => "https://api.github.com/user/17814/repos?page=2&per_page=2"
-
-r.links["next"].params
-# => {}
-```
-
-## Help and Discussion
-
-You can browse the API documents:
-
-https://icyleaf.github.io/halite/
-
-You can browse the all chainable methods:
-
-https://icyleaf.github.io/halite/Halite/Chainable.html
-
-You can browse the Changelog:
-
-https://github.com/icyleaf/halite/blob/master/CHANGELOG.md
-
-If you have found a bug, please create a issue here:
-
-https://github.com/icyleaf/halite/issues/new
-
-## Donate
-
-Halite is a open source, collaboratively funded project. If you run a business and are using Halite in a revenue-generating product,
-it would make business sense to sponsor Halite development. Individual users are also welcome to make a one time donation
-if Halite has helped you in your work or personal projects.
-
-You can donate via [Paypal](https://www.paypal.me/icyleaf/5).
-
-## How to Contribute
-
-Your contributions are always welcome! Please submit a pull request or create an issue to add a new question, bug or feature to the list.
-
-All [Contributors](https://github.com/icyleaf/halite/graphs/contributors) are on the wall.
-
-## You may also like
-
-- [totem](https://github.com/icyleaf/totem) - Load and parse a configuration file or string in JSON, YAML, dotenv formats.
-- [markd](https://github.com/icyleaf/markd) - Yet another markdown parser built for speed, Compliant to CommonMark specification.
-- [poncho](https://github.com/icyleaf/poncho) - A .env parser/loader improved for performance.
-- [popcorn](https://github.com/icyleaf/popcorn) - Easy and Safe casting from one type to another.
-- [fast-crystal](https://github.com/icyleaf/fast-crystal) - ๐จ Writing Fast Crystal ๐ -- Collect Common Crystal idioms.
-
-## License
-
-[MIT License](https://github.com/icyleaf/halite/blob/master/LICENSE) ยฉ icyleaf
diff --git a/lib/octokit/lib/halite/benchmarks/.gitignore b/lib/octokit/lib/halite/benchmarks/.gitignore
deleted file mode 100644
index fa22f9c..0000000
--- a/lib/octokit/lib/halite/benchmarks/.gitignore
+++ /dev/null
@@ -1,17 +0,0 @@
-doc/
-docs/
-lib/
-bin/
-logs/
-.shards/
-
-# Local test file
-main.cr
-
-# Temporay ignore
-benchmarks
-
-# Libraries don't need dependency lock
-# Dependencies will be locked in application that uses them
-shard.lock
-.history/
diff --git a/lib/octokit/lib/halite/benchmarks/README.md b/lib/octokit/lib/halite/benchmarks/README.md
deleted file mode 100644
index b79406e..0000000
--- a/lib/octokit/lib/halite/benchmarks/README.md
+++ /dev/null
@@ -1,30 +0,0 @@
-# About this benchmarks
-
-Benchmarks performed inspired from excon's benchmarking tool.
-
-## Environments
-
-- MacBook Pro (Retina, 15-inch, Mid 2015), 2.2 GHz Intel Core i7, 16 GB 1600 MHz DDR3.
-- Crystal 0.35.1 (2020-06-19) LLVM: 10.0.0
-- Clients
- - buit-in HTTP::Client
- - create v0.26.1
- - halite v0.10.8
-
-## Result
-
-```
-Tach times: 10000
- Tach Total
- crest 8.0365ms
- halite 7.9538ms (fastest)
- halite (persistent) 8.0205ms
- built-in HTTP::Client 8.0256ms
-```
-
-## Test yourself
-
-```crystal
-$ shards build --release --no-debug
-$ ./bin/run_benchmark
-```
diff --git a/lib/octokit/lib/halite/benchmarks/shard.yml b/lib/octokit/lib/halite/benchmarks/shard.yml
deleted file mode 100644
index aac4f20..0000000
--- a/lib/octokit/lib/halite/benchmarks/shard.yml
+++ /dev/null
@@ -1,20 +0,0 @@
-name: benchmarks
-version: 0.1.0
-
-authors:
- - icyleaf
-
-targets:
- run_benchmark:
- main: src/run_benchmark.cr
-
-dependencies:
- crest:
- github: mamantoha/crest
- version: ~> 0.26.1
- halite:
- path: ../
-
-crystal: 0.35.1
-
-license: MIT
diff --git a/lib/octokit/lib/halite/benchmarks/src/clients/crest.cr b/lib/octokit/lib/halite/benchmarks/src/clients/crest.cr
deleted file mode 100644
index daeab1d..0000000
--- a/lib/octokit/lib/halite/benchmarks/src/clients/crest.cr
+++ /dev/null
@@ -1,10 +0,0 @@
-require "crest"
-
-module Client
- MEMBERS << {
- name: "crest",
- proc: ->(url : String) {
- Crest.get(url).body
- },
- }
-end
diff --git a/lib/octokit/lib/halite/benchmarks/src/clients/halite.cr b/lib/octokit/lib/halite/benchmarks/src/clients/halite.cr
deleted file mode 100644
index 733989c..0000000
--- a/lib/octokit/lib/halite/benchmarks/src/clients/halite.cr
+++ /dev/null
@@ -1,17 +0,0 @@
-require "halite"
-
-module Client
- MEMBERS << {
- name: "halite",
- proc: ->(url : String) {
- Halite::Client.new.request("get", url).body
- },
- }
-
- MEMBERS << {
- name: "halite (persistent)",
- proc: ->(url : String) {
- Halite.get(url).body
- },
- }
-end
diff --git a/lib/octokit/lib/halite/benchmarks/src/clients/http_client.cr b/lib/octokit/lib/halite/benchmarks/src/clients/http_client.cr
deleted file mode 100644
index aab267d..0000000
--- a/lib/octokit/lib/halite/benchmarks/src/clients/http_client.cr
+++ /dev/null
@@ -1,10 +0,0 @@
-require "http/server"
-
-module Client
- MEMBERS << {
- name: "built-in HTTP::Client",
- proc: ->(url : String) {
- HTTP::Client.get(url).body
- },
- }
-end
diff --git a/lib/octokit/lib/halite/benchmarks/src/run_benchmark.cr b/lib/octokit/lib/halite/benchmarks/src/run_benchmark.cr
deleted file mode 100644
index 8e37635..0000000
--- a/lib/octokit/lib/halite/benchmarks/src/run_benchmark.cr
+++ /dev/null
@@ -1,18 +0,0 @@
-require "./support/**"
-require "./clients/**"
-
-module Client
- MEMBERS = [] of NamedTuple(name: String, proc: Proc(String, String))
-end
-
-url = run_server
-
-sleep 1
-
-Benchmark.tach(10_000) do |x|
- Client::MEMBERS.each do |client|
- x.report(client["name"]) do
- client["proc"].call(url)
- end
- end
-end
diff --git a/lib/octokit/lib/halite/benchmarks/src/support/http_server.cr b/lib/octokit/lib/halite/benchmarks/src/support/http_server.cr
deleted file mode 100644
index 46030a9..0000000
--- a/lib/octokit/lib/halite/benchmarks/src/support/http_server.cr
+++ /dev/null
@@ -1,16 +0,0 @@
-require "http/server"
-
-def run_server
- port = 12381
- server = HTTP::Server.new do |context|
- context.response.content_type = "text/plain"
- text = "x" * 10000
- context.response.print text
- end
-
- spawn do
- server.listen(port)
- end
-
- "http://localhost:#{port}"
-end
diff --git a/lib/octokit/lib/halite/benchmarks/src/support/tach_benchmark.cr b/lib/octokit/lib/halite/benchmarks/src/support/tach_benchmark.cr
deleted file mode 100644
index 1aad9d1..0000000
--- a/lib/octokit/lib/halite/benchmarks/src/support/tach_benchmark.cr
+++ /dev/null
@@ -1,77 +0,0 @@
-module Benchmark
- def self.tach(times : Int32)
- {% if !flag?(:release) %}
- puts "Warning: benchmarking without the `--release` flag won't yield useful results"
- {% end %}
-
- job = Tach::Job.new(times)
- yield job
- job.execute
- job.report
- job
- end
-
- module Tach
- class Job
- def initialize(@times : Int32 = 1)
- @benchmarks = [] of {String, ->}
- @results = {} of String => Float64
- end
-
- def report(label : String, &block)
- @benchmarks << {label, block}
- end
-
- def execute
- @benchmarks.each do |benchmark|
- GC.collect
-
- label, block = benchmark
- durations = [] of Float64
- @times.times do
- before = Time.utc
- block.call
- after = Time.utc
-
- durations << (after - before).total_seconds
- end
-
- average = durations.sum.to_f / @times.to_f
-
- @results[label] = average
- end
- end
-
- def report
- fastest = @results.min_by { |_, value| value }
-
- puts "Tach times: #{@times}"
- printf "%30s %20s\n", "Tach", "Total"
- @results.each do |label, result|
- mark = label == fastest.first ? " (fastest)" : ""
-
- printf "%30s %20s%s\n", label, human_mean(result), mark
- end
- end
-
- private def human_mean(iteration_time)
- case Math.log10(iteration_time)
- when 0..Float64::MAX
- digits = iteration_time
- suffix = "s"
- when -3..0
- digits = iteration_time * 1000
- suffix = "ms"
- when -6..-3
- digits = iteration_time * 1_000_000
- suffix = "ยตs"
- else
- digits = iteration_time * 1_000_000_000
- suffix = "ns"
- end
-
- "#{digits.round(4).to_s.rjust(6)}#{suffix}"
- end
- end
- end
-end
diff --git a/lib/octokit/lib/halite/halite-logo-small.png b/lib/octokit/lib/halite/halite-logo-small.png
deleted file mode 100644
index 3e6a65e..0000000
Binary files a/lib/octokit/lib/halite/halite-logo-small.png and /dev/null differ
diff --git a/lib/octokit/lib/halite/halite-logo.png b/lib/octokit/lib/halite/halite-logo.png
deleted file mode 100644
index 214813f..0000000
Binary files a/lib/octokit/lib/halite/halite-logo.png and /dev/null differ
diff --git a/lib/octokit/lib/halite/lib b/lib/octokit/lib/halite/lib
deleted file mode 120000
index a96aa0e..0000000
--- a/lib/octokit/lib/halite/lib
+++ /dev/null
@@ -1 +0,0 @@
-..
\ No newline at end of file
diff --git a/lib/octokit/lib/halite/shard.yml b/lib/octokit/lib/halite/shard.yml
deleted file mode 100644
index 6174cf2..0000000
--- a/lib/octokit/lib/halite/shard.yml
+++ /dev/null
@@ -1,9 +0,0 @@
-name: halite
-version: 0.12.0
-
-authors:
- - icyleaf
-
-crystal: ">= 0.36.1, < 2.0.0"
-
-license: MIT
diff --git a/lib/octokit/lib/halite/src/halite.cr b/lib/octokit/lib/halite/src/halite.cr
deleted file mode 100644
index 512e114..0000000
--- a/lib/octokit/lib/halite/src/halite.cr
+++ /dev/null
@@ -1,53 +0,0 @@
-require "./halite/*"
-require "./halite/ext/*"
-
-module Halite
- extend Chainable
-
- VERSION = "0.12.0"
-
- module Helper
- # Parses a `Time` into a [RFC 3339](https://tools.ietf.org/html/rfc3339) datetime format string
- # ([ISO 8601](http://xml.coverpages.org/ISO-FDIS-8601.pdf) profile).
- #
- # > Load Enviroment named "TZ" as high priority
- def self.to_rfc3339(time : Time, *, timezone = ENV["TZ"]?, fraction_digits : Int = 0)
- Time::Format::RFC_3339.format(time.in(configure_location(timezone)), fraction_digits: fraction_digits)
- end
-
- # Parses a `Time` into a [RFC 3339](https://tools.ietf.org/html/rfc3339) datetime format string to `IO`
- # ([ISO 8601](http://xml.coverpages.org/ISO-FDIS-8601.pdf) profile).
- #
- # > Load Enviroment named "TZ" as high priority
- def self.to_rfc3339(time : Time, io : IO, *, timezone = ENV["TZ"]?, fraction_digits : Int = 0)
- Time::Format::RFC_3339.format(time.in(configure_location(timezone)), io, fraction_digits)
- end
-
- # :nodoc:
- private def self.configure_location(timezone = ENV["TZ"]?)
- timezone ? Time::Location.load(timezone.not_nil!) : Time::Location::UTC
- end
- end
-
- @@features = {} of String => Feature.class
-
- module FeatureRegister
- def register_feature(name : String, klass : Feature.class)
- @@features[name] = klass
- end
-
- def feature(name : String)
- @@features[name]
- end
-
- def feature?(name : String)
- @@features[name]?
- end
-
- def has_feature?(name)
- @@features.keys.includes?(name)
- end
- end
-
- extend FeatureRegister
-end
diff --git a/lib/octokit/lib/halite/src/halite/chainable.cr b/lib/octokit/lib/halite/src/halite/chainable.cr
deleted file mode 100644
index 4f35d8e..0000000
--- a/lib/octokit/lib/halite/src/halite/chainable.cr
+++ /dev/null
@@ -1,537 +0,0 @@
-require "base64"
-
-module Halite
- module Chainable
- {% for verb in %w(get head) %}
- # {{ verb.id.capitalize }} a resource
- #
- # ```
- # Halite.{{ verb.id }}("http://httpbin.org/anything", params: {
- # first_name: "foo",
- # last_name: "bar"
- # })
- # ```
- def {{ verb.id }}(uri : String, *,
- headers : (Hash(String, _) | NamedTuple)? = nil,
- params : (Hash(String, _) | NamedTuple)? = nil,
- raw : String? = nil,
- tls : OpenSSL::SSL::Context::Client? = nil) : Halite::Response
- request({{ verb }}, uri, headers: headers, params: params, raw: raw, tls: tls)
- end
-
- # {{ verb.id.capitalize }} a streaming resource
- #
- # ```
- # Halite.{{ verb.id }}("http://httpbin.org/anything") do |response|
- # puts response.status_code
- # while line = response.body_io.gets
- # puts line
- # end
- # end
- # ```
- def {{ verb.id }}(uri : String, *,
- headers : (Hash(String, _) | NamedTuple)? = nil,
- params : (Hash(String, _) | NamedTuple)? = nil,
- raw : String? = nil,
- tls : OpenSSL::SSL::Context::Client? = nil,
- &block : Halite::Response ->)
- request({{ verb }}, uri, headers: headers, params: params, raw: raw, tls: tls, &block)
- end
- {% end %}
-
- {% for verb in %w(put post patch delete options) %}
- # {{ verb.id.capitalize }} a resource
- #
- # ### Request with form data
- #
- # ```
- # Halite.{{ verb.id }}("http://httpbin.org/anything", form: {
- # first_name: "foo",
- # last_name: "bar"
- # })
- # ```
- #
- # ### Request with json data
- #
- # ```
- # Halite.{{ verb.id }}("http://httpbin.org/anything", json: {
- # first_name: "foo",
- # last_name: "bar"
- # })
- # ```
- #
- # ### Request with raw string
- #
- # ```
- # Halite.{{ verb.id }}("http://httpbin.org/anything", raw: "name=Peter+Lee&address=%23123+Happy+Ave&Language=C%2B%2B")
- # ```
- def {{ verb.id }}(uri : String, *,
- headers : (Hash(String, _) | NamedTuple)? = nil,
- params : (Hash(String, _) | NamedTuple)? = nil,
- form : (Hash(String, _) | NamedTuple)? = nil,
- json : (Hash(String, _) | NamedTuple)? = nil,
- raw : String? = nil,
- tls : OpenSSL::SSL::Context::Client? = nil) : Halite::Response
- request({{ verb }}, uri, headers: headers, params: params, form: form, json: json, raw: raw, tls: tls)
- end
-
- # {{ verb.id.capitalize }} a streaming resource
- #
- # ```
- # Halite.{{ verb.id }}("http://httpbin.org/anything") do |response|
- # puts response.status_code
- # while line = response.body_io.gets
- # puts line
- # end
- # end
- # ```
- def {{ verb.id }}(uri : String, *,
- headers : (Hash(String, _) | NamedTuple)? = nil,
- params : (Hash(String, _) | NamedTuple)? = nil,
- form : (Hash(String, _) | NamedTuple)? = nil,
- json : (Hash(String, _) | NamedTuple)? = nil,
- raw : String? = nil,
- tls : OpenSSL::SSL::Context::Client? = nil,
- &block : Halite::Response ->)
- request({{ verb }}, uri, headers: headers, params: params, form: form, json: json, raw: raw, tls: tls, &block)
- end
- {% end %}
-
- # Adds a endpoint to the request.
- #
- #
- # ```
- # Halite.endpoint("https://httpbin.org")
- # .get("/get")
- # ```
- def endpoint(endpoint : String | URI) : Halite::Client
- branch(default_options.with_endpoint(endpoint))
- end
-
- # Make a request with the given Basic authorization header
- #
- # ```
- # Halite.basic_auth("icyleaf", "p@ssw0rd")
- # .get("http://httpbin.org/get")
- # ```
- #
- # See Also: [http://tools.ietf.org/html/rfc2617](http://tools.ietf.org/html/rfc2617)
- def basic_auth(user : String, pass : String) : Halite::Client
- auth("Basic " + Base64.strict_encode(user + ":" + pass))
- end
-
- # Make a request with the given Authorization header
- #
- # ```
- # Halite.auth("private-token", "6abaef100b77808ceb7fe26a3bcff1d0")
- # .get("http://httpbin.org/get")
- # ```
- def auth(value : String) : Halite::Client
- headers({"Authorization" => value})
- end
-
- # Accept the given MIME type
- #
- # ```
- # Halite.accept("application/json")
- # .get("http://httpbin.org/get")
- # ```
- def accept(value : String) : Halite::Client
- headers({"Accept" => value})
- end
-
- # Set requests user agent
- #
- # ```
- # Halite.user_agent("Custom User Agent")
- # .get("http://httpbin.org/get")
- # ```
- def user_agent(value : String) : Halite::Client
- headers({"User-Agent" => value})
- end
-
- # Make a request with the given headers
- #
- # ```
- # Halite.headers({"Content-Type", "application/json", "Connection": "keep-alive"})
- # .get("http://httpbin.org/get")
- # # Or
- # Halite.headers({content_type: "application/json", connection: "keep-alive"})
- # .get("http://httpbin.org/get")
- # ```
- def headers(headers : Hash(String, _) | NamedTuple) : Halite::Client
- branch(default_options.with_headers(headers))
- end
-
- # Make a request with the given headers
- #
- # ```
- # Halite.headers(content_type: "application/json", connection: "keep-alive")
- # .get("http://httpbin.org/get")
- # ```
- def headers(**kargs) : Halite::Client
- branch(default_options.with_headers(kargs))
- end
-
- # Make a request with the given cookies
- #
- # ```
- # Halite.cookies({"private-token", "6abaef100b77808ceb7fe26a3bcff1d0"})
- # .get("http://httpbin.org/get")
- # # Or
- # Halite.cookies({private-token: "6abaef100b77808ceb7fe26a3bcff1d0"})
- # .get("http://httpbin.org/get")
- # ```
- def cookies(cookies : Hash(String, _) | NamedTuple) : Halite::Client
- branch(default_options.with_cookies(cookies))
- end
-
- # Make a request with the given cookies
- #
- # ```
- # Halite.cookies(name: "icyleaf", "gender": "male")
- # .get("http://httpbin.org/get")
- # ```
- def cookies(**kargs) : Halite::Client
- branch(default_options.with_cookies(kargs))
- end
-
- # Make a request with the given cookies
- #
- # ```
- # cookies = HTTP::Cookies.from_client_headers(headers)
- # Halite.cookies(cookies)
- # .get("http://httpbin.org/get")
- # ```
- def cookies(cookies : HTTP::Cookies) : Halite::Client
- branch(default_options.with_cookies(cookies))
- end
-
- # Adds a timeout to the request.
- #
- # How long to wait for the server to send data before giving up, as a int, float or time span.
- # The timeout value will be applied to both the connect and the read timeouts.
- #
- # Set `nil` to timeout to ignore timeout.
- #
- # ```
- # Halite.timeout(5.5).get("http://httpbin.org/get")
- # # Or
- # Halite.timeout(2.minutes)
- # .post("http://httpbin.org/post", form: {file: "file.txt"})
- # ```
- def timeout(timeout : (Int32 | Float64 | Time::Span)?)
- timeout ? timeout(timeout, timeout, timeout) : branch
- end
-
- # Adds a timeout to the request.
- #
- # How long to wait for the server to send data before giving up, as a int, float or time span.
- # The timeout value will be applied to both the connect and the read timeouts.
- #
- # ```
- # Halite.timeout(3, 3.minutes, 5)
- # .post("http://httpbin.org/post", form: {file: "file.txt"})
- # # Or
- # Halite.timeout(3.04, 64, 10.0)
- # .get("http://httpbin.org/get")
- # ```
- def timeout(connect : (Int32 | Float64 | Time::Span)? = nil,
- read : (Int32 | Float64 | Time::Span)? = nil,
- write : (Int32 | Float64 | Time::Span)? = nil)
- branch(default_options.with_timeout(connect, read, write))
- end
-
- # Returns `Options` self with automatically following redirects.
- #
- # ```
- # # Automatically following redirects.
- # Halite.follow
- # .get("http://httpbin.org/relative-redirect/5")
- #
- # # Always redirect with any request methods
- # Halite.follow(strict: false)
- # .get("http://httpbin.org/get")
- # ```
- def follow(strict = Halite::Options::Follow::STRICT) : Halite::Client
- branch(default_options.with_follow(strict: strict))
- end
-
- # Returns `Options` self with given max hops of redirect times.
- #
- # ```
- # # Max hops 3 times
- # Halite.follow(3)
- # .get("http://httpbin.org/relative-redirect/3")
- #
- # # Always redirect with any request methods
- # Halite.follow(4, strict: false)
- # .get("http://httpbin.org/relative-redirect/4")
- # ```
- def follow(hops : Int32, strict = Halite::Options::Follow::STRICT) : Halite::Client
- branch(default_options.with_follow(hops, strict))
- end
-
- # Returns `Options` self with enable or disable logging.
- #
- # #### Enable logging
- #
- # Same as call `logging` method without any argument.
- #
- # ```
- # Halite.logging.get("http://httpbin.org/get")
- # ```
- #
- # #### Disable logging
- #
- # ```
- # Halite.logging(false).get("http://httpbin.org/get")
- # ```
- def logging(enable : Bool = true)
- options = default_options
- options.logging = enable
- branch(options)
- end
-
- # Returns `Options` self with given the logging which it integration from `Halite::Logging`.
- #
- # #### Simple logging
- #
- # ```
- # Halite.logging
- # .get("http://httpbin.org/get", params: {name: "foobar"})
- #
- # => 2018-08-28 14:33:19 +08:00 | request | POST | http://httpbin.org/post
- # => 2018-08-28 14:33:21 +08:00 | response | 200 | http://httpbin.org/post | 1.61s | application/json
- # { ... }
- # ```
- #
- # #### Logger configuration
- #
- # By default, Halite will logging all outgoing HTTP requests and their responses(without binary stream) to `STDOUT` on DEBUG level.
- # You can configuring the following options:
- #
- # - `skip_request_body`: By default is `false`.
- # - `skip_response_body`: By default is `false`.
- # - `skip_benchmark`: Display elapsed time, by default is `false`.
- # - `colorize`: Enable colorize in terminal, only apply in `common` format, by default is `true`.
- #
- # ```
- # Halite.logging(skip_request_body: true, skip_response_body: true)
- # .post("http://httpbin.org/get", form: {image: File.open("halite-logo.png")})
- #
- # # => 2018-08-28 14:33:19 +08:00 | request | POST | http://httpbin.org/post
- # # => 2018-08-28 14:33:21 +08:00 | response | 200 | http://httpbin.org/post | 1.61s | application/json
- # ```
- #
- # #### Use custom logging
- #
- # Creating the custom logging by integration `Halite::Logging::Abstract` abstract class.
- # Here has two methods must be implement: `#request` and `#response`.
- #
- # ```
- # class CustomLogger < Halite::Logging::Abstract
- # def request(request)
- # @logger.info "| >> | %s | %s %s" % [request.verb, request.uri, request.body]
- # end
- #
- # def response(response)
- # @logger.info "| << | %s | %s %s" % [response.status_code, response.uri, response.content_type]
- # end
- # end
- #
- # # Add to adapter list (optional)
- # Halite::Logging.register_adapter "custom", CustomLogger.new
- #
- # Halite.logging(logging: CustomLogger.new)
- # .get("http://httpbin.org/get", params: {name: "foobar"})
- #
- # # We can also call it use format name if you added it.
- # Halite.logging(format: "custom")
- # .get("http://httpbin.org/get", params: {name: "foobar"})
- #
- # # => 2017-12-13 16:40:13 +08:00 | >> | GET | http://httpbin.org/get?name=foobar
- # # => 2017-12-13 16:40:15 +08:00 | << | 200 | http://httpbin.org/get?name=foobar application/json
- # ```
- def logging(logging : Halite::Logging::Abstract = Halite::Logging::Common.new)
- branch(default_options.with_logging(logging))
- end
-
- # Returns `Options` self with given the file with the path.
- #
- # #### JSON-formatted logging
- #
- # ```
- # Halite.logging(format: "json")
- # .get("http://httpbin.org/get", params: {name: "foobar"})
- # ```
- #
- # #### create a http request and log to file
- #
- # ```
- # Log.setup("halite.file", backend: Log::IOBackend.new(File.open("/tmp/halite.log", "a")))
- # Halite.logging(for: "halite.file")
- # .get("http://httpbin.org/get", params: {name: "foobar"})
- # ```
- #
- # #### Always create new log file and store data to JSON formatted
- #
- # ```
- # Log.setup("halite.file", backend: Log::IOBackend.new(File.open("/tmp/halite.log", "w"))
- # Halite.logging(for: "halite.file", format: "json")
- # .get("http://httpbin.org/get", params: {name: "foobar"})
- # ```
- #
- # Check the log file content: **/tmp/halite.log**
- def logging(format : String = "common", *, for : String = "halite",
- skip_request_body = false, skip_response_body = false,
- skip_benchmark = false, colorize = true)
- opts = {
- for: for,
- skip_request_body: skip_request_body,
- skip_response_body: skip_response_body,
- skip_benchmark: skip_benchmark,
- colorize: colorize,
- }
- branch(default_options.with_logging(format, **opts))
- end
-
- # Turn on given features and its options.
- #
- # Available features to review all subclasses of `Halite::Feature`.
- #
- # #### Use JSON logging
- #
- # ```
- # Halite.use("logging", format: "json")
- # .get("http://httpbin.org/get", params: {name: "foobar"})
- #
- # # => { ... }
- # ```
- #
- # #### Use common format logging and skip response body
- # ```
- # Halite.use("logging", format: "common", skip_response_body: true)
- # .get("http://httpbin.org/get", params: {name: "foobar"})
- #
- # # => 2018-08-28 14:58:26 +08:00 | request | GET | http://httpbin.org/get
- # # => 2018-08-28 14:58:27 +08:00 | response | 200 | http://httpbin.org/get | 615.8ms | application/json
- # ```
- def use(feature : String, **opts)
- branch(default_options.with_features(feature, **opts))
- end
-
- # Turn on given the name of features.
- #
- # Available features to review all subclasses of `Halite::Feature`.
- #
- # ```
- # Halite.use("logging", "your-custom-feature-name")
- # .get("http://httpbin.org/get", params: {name: "foobar"})
- # ```
- def use(*features)
- branch(default_options.with_features(*features))
- end
-
- # Make an HTTP request with the given verb
- #
- # ```
- # Halite.request("get", "http://httpbin.org/get", {
- # "headers" = { "user_agent" => "halite" },
- # "params" => { "nickname" => "foo" },
- # "form" => { "username" => "bar" },
- # })
- # ```
- def request(verb : String, uri : String, *,
- headers : (Hash(String, _) | NamedTuple)? = nil,
- params : (Hash(String, _) | NamedTuple)? = nil,
- form : (Hash(String, _) | NamedTuple)? = nil,
- json : (Hash(String, _) | NamedTuple)? = nil,
- raw : String? = nil,
- tls : OpenSSL::SSL::Context::Client? = nil) : Halite::Response
- request(verb, uri, options_with(headers, params, form, json, raw, tls))
- end
-
- # Make an HTTP request with the given verb and options
- #
- # > This method will be executed with oneshot request.
- #
- # ```
- # Halite.request("get", "http://httpbin.org/stream/3", headers: {"user-agent" => "halite"}) do |response|
- # puts response.status_code
- # while line = response.body_io.gets
- # puts line
- # end
- # end
- # ```
- def request(verb : String, uri : String, *,
- headers : (Hash(String, _) | NamedTuple)? = nil,
- params : (Hash(String, _) | NamedTuple)? = nil,
- form : (Hash(String, _) | NamedTuple)? = nil,
- json : (Hash(String, _) | NamedTuple)? = nil,
- raw : String? = nil,
- tls : OpenSSL::SSL::Context::Client? = nil,
- &block : Halite::Response ->)
- request(verb, uri, options_with(headers, params, form, json, raw, tls), &block)
- end
-
- # Make an HTTP request with the given verb and options
- #
- # > This method will be executed with oneshot request.
- #
- # ```
- # Halite.request("get", "http://httpbin.org/get", Halite::Options.new(
- # "headers" = { "user_agent" => "halite" },
- # "params" => { "nickname" => "foo" },
- # "form" => { "username" => "bar" },
- # )
- # ```
- def request(verb : String, uri : String, options : Halite::Options? = nil) : Halite::Response
- branch(options).request(verb, uri)
- end
-
- # Make an HTTP request with the given verb and options
- #
- # > This method will be executed with oneshot request.
- #
- # ```
- # Halite.request("get", "http://httpbin.org/stream/3") do |response|
- # puts response.status_code
- # while line = response.body_io.gets
- # puts line
- # end
- # end
- # ```
- def request(verb : String, uri : String, options : Halite::Options? = nil, &block : Halite::Response ->)
- branch(options).request(verb, uri, &block)
- end
-
- private def branch(options : Halite::Options? = nil) : Halite::Client
- options ||= default_options
- Halite::Client.new(options)
- end
-
- # Use with new instance of Halite::Client to load unique options
- #
- # Note: append options in Halite::Client#initialize and revoke at #finalize
- DEFAULT_OPTIONS = {} of UInt64 => Halite::Options
-
- private def default_options
- {% if @type.superclass %}
- DEFAULT_OPTIONS[object_id]
- {% else %}
- Halite::Options.new
- {% end %}
- end
-
- private def options_with(headers : (Hash(String, _) | NamedTuple)? = nil,
- params : (Hash(String, _) | NamedTuple)? = nil,
- form : (Hash(String, _) | NamedTuple)? = nil,
- json : (Hash(String, _) | NamedTuple)? = nil,
- raw : String? = nil,
- tls : OpenSSL::SSL::Context::Client? = nil)
- options = Halite::Options.new(headers: headers, params: params, form: form, json: json, raw: raw, tls: tls)
- default_options.merge!(options)
- end
- end
-end
diff --git a/lib/octokit/lib/halite/src/halite/client.cr b/lib/octokit/lib/halite/src/halite/client.cr
deleted file mode 100644
index aa588cd..0000000
--- a/lib/octokit/lib/halite/src/halite/client.cr
+++ /dev/null
@@ -1,304 +0,0 @@
-require "./request"
-require "./response"
-require "./redirector"
-
-require "http/client"
-require "json"
-
-module Halite
- # Clients make requests and receive responses
- #
- # Support all `Chainable` methods.
- #
- # ### Simple setup
- #
- # ```
- # client = Halite::Client.new(headers: {
- # "private-token" => "bdf39d82661358f80b31b67e6f89fee4"
- # })
- #
- # client.auth(private_token: "bdf39d82661358f80b31b67e6f89fee4").
- # .get("http://httpbin.org/get", params: {
- # name: "icyleaf"
- # })
- # ```
- #
- # ### Setup with block
- #
- # ```
- # client = Halite::Client.new do
- # basic_auth "name", "foo"
- # headers content_type: "application/jsong"
- # read_timeout 3.minutes
- # logging true
- # end
- # ```
- class Client
- include Chainable
-
- # Instance a new client
- #
- # ```
- # Halite::Client.new(headers: {"private-token" => "bdf39d82661358f80b31b67e6f89fee4"})
- # ```
- def self.new(*,
- endpoint : (String | URI)? = nil,
- headers : (Hash(String, _) | NamedTuple)? = nil,
- cookies : (Hash(String, _) | NamedTuple)? = nil,
- params : (Hash(String, _) | NamedTuple)? = nil,
- form : (Hash(String, _) | NamedTuple)? = nil,
- json : (Hash(String, _) | NamedTuple)? = nil,
- raw : String? = nil,
- timeout = Timeout.new,
- follow = Follow.new,
- tls : OpenSSL::SSL::Context::Client? = nil)
- new(Options.new(
- endpoint: endpoint,
- headers: headers,
- cookies: cookies,
- params: params,
- form: form,
- json: json,
- raw: raw,
- tls: tls,
- timeout: timeout,
- follow: follow
- ))
- end
-
- property options
-
- # Instance a new client with block
- #
- # ```
- # client = Halite::Client.new do
- # basic_auth "name", "foo"
- # logging true
- # end
- # ```
- def self.new(&block)
- instance = new
- yield_instance = with instance yield
- if yield_instance
- yield_instance.options.merge!(yield_instance.oneshot_options)
- yield_instance.oneshot_options.clear!
- instance = yield_instance
- end
-
- instance
- end
-
- # Instance a new client
- #
- # ```
- # options = Halite::Options.new(headers: {
- # "private-token" => "bdf39d82661358f80b31b67e6f89fee4",
- # })
- #
- # client = Halite::Client.new(options)
- # ```
- def initialize(@options = Halite::Options.new)
- @history = [] of Response
-
- DEFAULT_OPTIONS[object_id] = Halite::Options.new
- end
-
- def finalize
- DEFAULT_OPTIONS.delete(object_id)
- end
-
- # Make an HTTP request
- def request(verb : String, uri : String, options : Halite::Options? = nil) : Halite::Response
- opts = options ? @options.merge(options.not_nil!) : @options
- request = build_request(verb, uri, opts)
- response = perform_chain(request, opts) do
- perform(request, opts)
- end
-
- return response if opts.follow.hops.zero?
-
- Redirector.new(request, response, opts).perform do |req|
- perform(req, opts)
- end
- end
-
- # Make an HTTP request
- def request(verb : String, uri : String, options : Halite::Options? = nil, &block : Halite::Response ->)
- opts = options ? @options.merge(options.not_nil!) : @options
- request = build_request(verb, uri, opts)
- perform(request, opts, &block)
- end
-
- # Find interceptor and return `Response` else perform HTTP request.
- private def perform_chain(request : Halite::Request, options : Halite::Options, &block : -> Response)
- chain = Feature::Chain.new(request, nil, options, &block)
- options.features.each do |_, feature|
- current_chain = feature.intercept(chain)
- if current_chain.result == Feature::Chain::Result::Next
- chain = current_chain
- elsif current_chain.result == Feature::Chain::Result::Return && (response = current_chain.response)
- return handle_response(response, options)
- end
- end
-
- # Make sure return if has response with each interceptor
- if response = chain.response
- return handle_response(response, options)
- end
-
- # Perform original HTTP request if not found any response in interceptors
- block.call
- end
-
- # Perform a single (no follow) HTTP request
- private def perform(request : Halite::Request, options : Halite::Options) : Halite::Response
- raise RequestError.new("SSL context given for HTTP URI = #{request.uri}") if request.scheme == "http" && options.tls
-
- conn = make_connection(request, options)
- conn_response = conn.exec(request.verb, request.full_path, request.headers, request.body)
- handle_response(request, conn_response, options)
- rescue ex : IO::TimeoutError
- raise TimeoutError.new(ex.message)
- rescue ex : Socket::Error
- raise ConnectionError.new(ex.message)
- end
-
- # Perform a single (no follow) streaming HTTP request and redirect automatically
- private def perform(request : Halite::Request, options : Halite::Options, &block : Halite::Response ->)
- raise RequestError.new("SSL context given for HTTP URI = #{request.uri}") if request.scheme == "http" && options.tls
-
- conn = make_connection(request, options)
- conn.exec(request.verb, request.full_path, request.headers, request.body) do |conn_response|
- response = handle_response(request, conn_response, options)
- redirector = Redirector.new(request, response, options)
- if redirector.avaiable?
- redirector.each_redirect do |req|
- perform(req, options, &block)
- end
- else
- block.call(response)
- end
-
- return response
- end
- end
-
- # Prepare a HTTP request
- private def build_request(verb : String, uri : String, options : Halite::Options) : Halite::Request
- uri = make_request_uri(uri, options)
- body_data = make_request_body(options)
- headers = make_request_headers(options, body_data.content_type)
- request = Request.new(verb, uri, headers, body_data.body)
-
- # reset options during onshot request, see `default_options` method at the bottom of file.
- default_options.clear!
-
- options.features.reduce(request) do |req, (_, feature)|
- feature.request(req)
- end
- end
-
- # Merges query params if needed
- private def make_request_uri(url : String, options : Halite::Options) : URI
- uri = resolve_uri(url, options)
- if params = options.params
- query = HTTP::Params.encode(params)
- uri.query = [uri.query, query].compact.join('&') unless query.empty?
- end
-
- uri
- end
-
- # Merges request headers
- private def make_request_headers(options : Halite::Options, content_type : String?) : HTTP::Headers
- headers = options.headers
- if (value = content_type) && !value.empty? && !headers.has_key?("Content-Type")
- headers.add("Content-Type", value)
- end
-
- # Cookie shards
- options.cookies.add_request_headers(headers)
- end
-
- # Create the request body object to send
- private def make_request_body(options : Halite::Options) : Halite::Request::Data
- if (form = options.form) && !form.empty?
- FormData.create(form)
- elsif (hash = options.json) && !hash.empty?
- body = JSON.build do |builder|
- hash.to_json(builder)
- end
-
- Halite::Request::Data.new(body, "application/json")
- elsif (raw = options.raw) && !raw.empty?
- Halite::Request::Data.new(raw, "text/plain")
- else
- Halite::Request::Data.new("")
- end
- end
-
- # Create the http connection
- private def make_connection(request, options)
- conn = HTTP::Client.new(request.domain, options.tls)
- conn.connect_timeout = options.timeout.connect.not_nil! if options.timeout.connect
- conn.read_timeout = options.timeout.read.not_nil! if options.timeout.read
- conn.write_timeout = options.timeout.write.not_nil! if options.timeout.write
- conn
- end
-
- # Convert HTTP::Client::Response to response and handles response (see below)
- private def handle_response(request, conn_response : HTTP::Client::Response, options) : Halite::Response
- response = Response.new(uri: request.uri, conn: conn_response, history: @history)
- handle_response(response, options)
- end
-
- # Handles response by reduce the response of feature, add history and update options
- private def handle_response(response, options) : Halite::Response
- response = options.features.reduce(response) do |res, (_, feature)|
- feature.response(res)
- end
-
- # Append history of response if enable follow
- @history << response unless options.follow.hops.zero?
- store_cookies_from_response(response)
- end
-
- # Store cookies for sessions use from response
- private def store_cookies_from_response(response : Halite::Response) : Halite::Response
- return response unless response.headers
-
- @options.with_cookies(HTTP::Cookies.from_server_headers(response.headers))
- response
- end
-
- # Use in instance/session mode, it will replace same method in `Halite::Chainable`.
- private def branch(options : Halite::Options? = nil) : Halite::Client
- oneshot_options.merge!(options)
- self
- end
-
- private def resolve_uri(url : String, options : Halite::Options) : URI
- return URI.parse(url) unless endpoint = options.endpoint
- return endpoint if url.empty?
-
- endpoint.path += '/' unless endpoint.path.ends_with?('/')
- endpoint.resolve(url)
- end
-
- # :nodoc:
- @oneshot_options : Halite::Options?
-
- # :nodoc:
- #
- # Store options on each request, then it will reset after finish response.
- #
- # > It will called in this class method, so it mark be public but not recommend to users.
- #
- # It make sure never store any gived headers, cookies, query, form, raw and tls
- # during each request in instance/session mode.
- def oneshot_options
- @oneshot_options ||= Halite::Options.new
- @oneshot_options.not_nil!
- end
- end
-end
diff --git a/lib/octokit/lib/halite/src/halite/error.cr b/lib/octokit/lib/halite/src/halite/error.cr
deleted file mode 100644
index 3e489c6..0000000
--- a/lib/octokit/lib/halite/src/halite/error.cr
+++ /dev/null
@@ -1,87 +0,0 @@
-module Halite
- module Exception
- # Generic error
- class Error < ::Exception; end
-
- # Generic Connection error
- class ConnectionError < Error; end
-
- # Generic Request error
- class RequestError < Error; end
-
- # Generic Response error
- class ResponseError < Error; end
-
- # Generic Feature error
- class FeatureError < Error; end
-
- # The method given was not understood
- class UnsupportedMethodError < RequestError; end
-
- # The scheme given was not understood
- class UnsupportedSchemeError < RequestError; end
-
- # The head method can not streaming without empty response
- class UnsupportedStreamMethodError < RequestError; end
-
- # Requested to do something when we're in the wrong state
- class StateError < RequestError; end
-
- # Generic Timeout error
- class TimeoutError < RequestError; end
-
- # The feature given was not understood
- class UnRegisterFeatureError < FeatureError; end
-
- # The format given was not understood
- class UnRegisterLoggerFormatError < FeatureError; end
-
- # Notifies that we reached max allowed redirect hops
- class TooManyRedirectsError < ResponseError; end
-
- # Notifies that following redirects got into an endless loop
- class EndlessRedirectError < TooManyRedirectsError; end
-
- # The MIME type(adapter) given was not understood
- class UnRegisterMimeTypeError < ResponseError; end
-
- # Generic API error
- class APIError < ResponseError
- getter uri
- getter status_code
- getter status_message : String? = nil
-
- def initialize(@message : String? = nil, @status_code : Int32? = nil, @uri : URI? = nil)
- @status_message = build_status_message
- if status_code = @status_code
- @message ||= "#{status_code} #{@status_message}"
- end
-
- super(@message)
- end
-
- private def build_status_message : String
- String::Builder.build do |io|
- if status_code = @status_code
- io << "#{HTTP::Status.new(status_code).description.to_s.downcase} error"
- else
- io << "#{@message || "unknown"} error"
- end
-
- io << " with url: #{@uri}" if uri = @uri
- end.to_s
- end
- end
-
- # 4XX client error
- class ClientError < APIError; end
-
- # 5XX server error
- class ServerError < APIError; end
- end
-
- {% for cls in Exception.constants %}
- # :nodoc:
- alias {{ cls.id }} = Exception::{{ cls.id }}
- {% end %}
-end
diff --git a/lib/octokit/lib/halite/src/halite/ext/file_to_json.cr b/lib/octokit/lib/halite/src/halite/ext/file_to_json.cr
deleted file mode 100644
index 7e1e54a..0000000
--- a/lib/octokit/lib/halite/src/halite/ext/file_to_json.cr
+++ /dev/null
@@ -1,6 +0,0 @@
-# :nodoc:
-class File
- def to_json(json : JSON::Builder)
- json.string(to_s)
- end
-end
diff --git a/lib/octokit/lib/halite/src/halite/ext/http_headers_encode.cr b/lib/octokit/lib/halite/src/halite/ext/http_headers_encode.cr
deleted file mode 100644
index fdccd74..0000000
--- a/lib/octokit/lib/halite/src/halite/ext/http_headers_encode.cr
+++ /dev/null
@@ -1,57 +0,0 @@
-module HTTP
- # This is **extension** apply in Halite.
- struct Headers
- # Returns the given key value pairs as HTTP Headers
- #
- # Every parameter added is directly written to an IO, where keys are properly escaped.
- #
- # ```
- # HTTP::Headers.encode({
- # content_type: "application/json",
- # })
- # # => "HTTP::Headers{"Content-Type" => "application/json"}"
- #
- # HTTP::Headers.encode({
- # "conTENT-type": "application/json",
- # })
- # # => "HTTP::Headers{"Content-Type" => "application/json"}"
- # ```
- def self.encode(data : Hash(String, _) | NamedTuple) : HTTP::Headers
- ::HTTP::Headers.new.tap do |builder|
- data = data.is_a?(NamedTuple) ? data.to_h : data
- data.each do |key, value|
- key = key.to_s.gsub("_", "-").split("-").map { |v| v.capitalize }.join("-")
- # skip invalid value of content length
- next if key == "Content-Length" && !(value =~ /^\d+$/)
-
- builder.add key, value.is_a?(Array(String)) ? value : value.to_s
- end
- end
- end
-
- # Same as `#encode`
- def self.encode(**data)
- encode(data)
- end
-
- # Similar as `Hahs#to_h` but return `String` if it has one value of the key.
- #
- # ```
- # headers = HTTP::Headers{"Accepts" => ["application/json", "text/html"], "Content-Type" => ["text/html"]}
- # headers["Accepts"] # => ["application/json", "text/html"]
- # headers["Content-Type"] # => "text/html"
- # ```
- def to_flat_h
- @hash.each_with_object({} of String => String | Array(String)) do |(key, values), obj|
- obj[key.name] = case values
- when String
- values.as(String)
- when Array
- values.size == 1 ? values[0].as(String) : values.as(Array(String))
- else
- raise Halite::Error.new("Not support type `#{values.class} with value: #{values}")
- end
- end
- end
- end
-end
diff --git a/lib/octokit/lib/halite/src/halite/ext/http_params_encode.cr b/lib/octokit/lib/halite/src/halite/ext/http_params_encode.cr
deleted file mode 100644
index 5dcde8c..0000000
--- a/lib/octokit/lib/halite/src/halite/ext/http_params_encode.cr
+++ /dev/null
@@ -1,79 +0,0 @@
-module HTTP
- # This is **extension** apply in Halite.
- struct Params
- # Returns the given key value pairs as a url-encoded query.
- #
- # Every parameter added is directly written to an IO, where keys and values are properly escaped.
- #
- # ```
- # HTTP::Params.encode({
- # "name" => "Lizeth Gusikowski",
- # "skill" => ["ruby", "crystal"],
- # "company" => {
- # "name" => "Keeling Inc",
- # },
- # "avatar" => File.open("avatar_big.png"),
- # })
- # # => "name=Lizeth+Gusikowski&skill=ruby&skill=crystal&company=%7B%22name%22+%3D%3E+%22Keeling+Inc%22%7D&avatar=avatar_big.png"
- # ```
- def self.encode(hash : Hash) : String
- ::HTTP::Params.build do |form|
- hash.each do |key, value|
- key = key.to_s
- case value
- when Array
- value.each do |item|
- form.add("#{key}", item.to_s)
- end
- when File
- form.add(key, value.as(File).path)
- when Hash
- value.each do |hkey, hvalue|
- form.add("#{key}[#{hkey}]", hvalue.to_s)
- end
- else
- form.add(key, value.to_s)
- end
- end
- end
- end
-
- # Returns the given key value pairs as a url-encoded query.
- #
- # Every parameter added is directly written to an IO, where keys and values are properly escaped.
- #
- # ```
- # HTTP::Params.encode({
- # name: "Lizeth Gusikowski",
- # skill: ["ruby", "crystal"],
- # company: {
- # name: "Keeling Inc",
- # },
- # avatar: File.open("avatar_big.png"
- # })
- # # => "name=Lizeth+Gusikowski&skill=ruby&skill=crystal&company=%7B%22name%22+%3D%3E+%22Keeling+Inc%22%7D&avatar=avatar_big.png"
- # ```
- def self.encode(named_tuple : NamedTuple) : String
- encode(named_tuple.to_h)
- end
-
- # Returns the given key value pairs as a url-encoded query.
- #
- # Every parameter added is directly written to an IO, where keys and values are properly escaped.
- #
- # ```
- # HTTP::Params.encode(
- # name: "Lizeth Gusikowski",
- # skill: ["ruby", "crystal"],
- # company: {
- # name: "Keeling Inc",
- # },
- # avatar: File.open("avatar_big.png"
- # )
- # # => "name=Lizeth+Gusikowski&skill=ruby&skill=crystal&company=%7B%22name%22+%3D%3E+%22Keeling+Inc%22%7D&avatar=avatar_big.png"
- # ```
- def self.encode(**named_tuple) : String
- encode(named_tuple)
- end
- end
-end
diff --git a/lib/octokit/lib/halite/src/halite/feature.cr b/lib/octokit/lib/halite/src/halite/feature.cr
deleted file mode 100644
index fcfc629..0000000
--- a/lib/octokit/lib/halite/src/halite/feature.cr
+++ /dev/null
@@ -1,71 +0,0 @@
-module Halite
- abstract class Feature
- def initialize(**options)
- end
-
- # Cooks with request
- def request(request : Halite::Request) : Halite::Request
- request
- end
-
- # Cooking with response
- def response(response : Halite::Response) : Halite::Response
- response
- end
-
- # Intercept and cooking request and response
- def intercept(chain : Halite::Feature::Chain) : Halite::Feature::Chain
- chain
- end
-
- # Feature chain
- #
- # Chain has two result:
- #
- # next: perform and run next interceptor
- # return: perform and return
- class Chain
- enum Result
- Next
- Return
- end
-
- property request
- getter response
- getter result
-
- @performed_response : Halite::Response?
-
- def initialize(@request : Halite::Request, @response : Halite::Response?, @options : Halite::Options, &block : -> Halite::Response)
- @result = Result::Next
- @performed_response = nil
- @perform_request_block = block
- end
-
- def next(response)
- @result = Result::Next
- @response = response
-
- self
- end
-
- def return(response)
- @result = Result::Return
- @response = response
-
- self
- end
-
- def performed?
- !@performed_response.nil?
- end
-
- def perform
- @performed_response ||= @perform_request_block.call
- @performed_response.not_nil!
- end
- end
- end
-end
-
-require "./features/*"
diff --git a/lib/octokit/lib/halite/src/halite/features/cache.cr b/lib/octokit/lib/halite/src/halite/features/cache.cr
deleted file mode 100644
index 703732b..0000000
--- a/lib/octokit/lib/halite/src/halite/features/cache.cr
+++ /dev/null
@@ -1,184 +0,0 @@
-require "json"
-require "digest"
-require "file_utils"
-
-module Halite
- # Cache feature use for caching HTTP response to local storage to speed up in developing stage.
- #
- # It has the following options:
- #
- # - `file`: Load cache from file. it conflict with `path` and `expires`.
- # - `path`: The path of cache, default is "/tmp/halite/cache/"
- # - `expires`: The expires time of cache, default is never expires.
- # - `debug`: The debug mode of cache, default is `true`
- #
- # With debug mode, cached response it always included some headers information:
- #
- # - `X-Halite-Cached-From`: Cache source (cache or file)
- # - `X-Halite-Cached-Key`: Cache key with verb, uri and body (return with cache, not `file` passed)
- # - `X-Halite-Cached-At`: Cache created time
- # - `X-Halite-Cached-Expires-At`: Cache expired time (return with cache, not `file` passed)
- #
- # ```
- # Halite.use("cache").get "http://httpbin.org/anything" # request a HTTP
- # r = Halite.use("cache").get "http://httpbin.org/anything" # request from local storage
- # r.headers # => {..., "X-Halite-Cached-At" => "2018-08-30 10:41:14 UTC", "X-Halite-Cached-By" => "Halite", "X-Halite-Cached-Expires-At" => "2018-08-30 10:41:19 UTC", "X-Halite-Cached-Key" => "2bb155e6c8c47627da3d91834eb4249a"}}
- # ```
- class Cache < Feature
- DEFAULT_PATH = "/tmp/halite/cache/"
-
- getter file : String?
- getter path : String
- getter expires : Time::Span?
- getter debug : Bool
-
- # return a new Cache instance
- #
- # Accepts argument:
- #
- # - **debug**: `Bool`
- # - **path**: `String`
- # - **expires**: `(Int32 | Time::Span)?`
- def initialize(**options)
- @debug = options.fetch(:debug, true).as(Bool)
- if file = options[:file]?
- @file = file
- @path = DEFAULT_PATH
- @expires = nil
- else
- @file = nil
- @path = options.fetch(:path, DEFAULT_PATH).as(String)
- @expires = case expires = options[:expires]?
- when Time::Span
- expires.as(Time::Span)
- when Int32
- Time::Span.new(seconds: expires.as(Int32), nanoseconds: 0)
- when Nil
- nil
- else
- raise "Only accept Int32 and Time::Span type."
- end
- end
- end
-
- def intercept(chain)
- response = cache(chain) do
- chain.perform
- end
-
- chain.return(response)
- end
-
- private def cache(chain, &block : -> Halite::Response)
- if response = find_cache(chain.request)
- return response
- end
-
- response = yield
- write_cache(chain.request, response)
- response
- end
-
- private def find_cache(request : Halite::Request) : Halite::Response?
- if file = @file
- build_response(request, file)
- elsif response = build_response(request)
- response
- end
- end
-
- private def find_file(file) : Halite::Response
- raise Error.new("Not find cache file: #{file}") if File.file?(file)
- build_response(file)
- end
-
- private def build_response(request : Halite::Request, file : String? = nil) : Halite::Response?
- status_code = 200
- headers = HTTP::Headers.new
- cache_from = "file"
-
- unless file
- # Cache in path
- key = generate_cache_key(request)
- path = File.join(@path, key)
-
- return unless Dir.exists?(path)
-
- cache_from = "cache"
- cache_file = File.join(path, "#{key}.cache")
- if File.file?(cache_file) && !cache_expired?(cache_file)
- file = cache_file
-
- if metadata = find_metadata(path)
- status_code = metadata["status_code"].as_i
- metadata["headers"].as_h.each do |name, value|
- headers[name] = value.as_s
- end
- end
-
- if @debug
- headers["X-Halite-Cached-Key"] = key
- headers["X-Halite-Cached-Expires-At"] = @expires ? (cache_created_time(file) + @expires.not_nil!).to_s : "None"
- end
- end
- end
-
- return unless file
-
- if @debug
- headers["X-Halite-Cached-From"] = cache_from
- headers["X-Halite-Cached-At"] = cache_created_time(file).to_s
- end
-
- body = File.read_lines(file).join("\n")
- Response.new(request.uri, status_code, body, headers)
- end
-
- private def find_metadata(path)
- file = File.join(path, "metadata.json")
- if File.exists?(file)
- JSON.parse(File.open(file)).as_h
- end
- end
-
- private def cache_expired?(file)
- return false unless expires = @expires
- file_modified_time = cache_created_time(file)
- Time.utc >= (file_modified_time + expires)
- end
-
- private def cache_created_time(file)
- File.info(file).modification_time
- end
-
- private def generate_cache_key(request) : String
- Digest::MD5.hexdigest("#{request.verb}-#{request.uri}-#{request.body}")
- end
-
- private def write_cache(request, response)
- key = generate_cache_key(request)
- path = File.join(@path, key)
- FileUtils.mkdir_p(path) unless Dir.exists?(path)
-
- write_metadata(path, response)
- write_body(path, key, response)
- end
-
- private def write_metadata(path, response)
- File.open(File.join(path, "metadata.json"), "w") do |f|
- f.puts({
- "status_code" => response.status_code,
- "headers" => response.headers.to_flat_h,
- }.to_json)
- end
- end
-
- private def write_body(path, key, response)
- File.open(File.join(path, "#{key}.cache"), "w") do |f|
- f.puts response.body
- end
- end
-
- Halite.register_feature "cache", self
- end
-end
diff --git a/lib/octokit/lib/halite/src/halite/features/logging.cr b/lib/octokit/lib/halite/src/halite/features/logging.cr
deleted file mode 100644
index d450086..0000000
--- a/lib/octokit/lib/halite/src/halite/features/logging.cr
+++ /dev/null
@@ -1,120 +0,0 @@
-require "log"
-require "colorize"
-require "file_utils"
-
-Log.setup do |c|
- backend = Log::IOBackend.new(formatter: Halite::Logging::ShortFormat)
- c.bind("halite", :info, backend)
-end
-
-module Halite
- # Logging feature
- class Logging < Feature
- DEFAULT_LOGGER = Logging::Common.new
-
- getter writer : Logging::Abstract
-
- # return a new Cache instance
- #
- # Accepts argument:
- #
- # - **logging**: `Logging::Abstract`
- def initialize(**options)
- @writer = (logging = options[:logging]?) ? logging.as(Logging::Abstract) : DEFAULT_LOGGER
- end
-
- def request(request)
- @writer.request(request)
- request
- end
-
- def response(response)
- @writer.response(response)
- response
- end
-
- # Logging format Abstract
- abstract class Abstract
- setter logger : Log
- getter skip_request_body : Bool
- getter skip_response_body : Bool
- getter skip_benchmark : Bool
- getter colorize : Bool
-
- @request_time : Time?
-
- def initialize(*, for : String = "halite",
- @skip_request_body = false, @skip_response_body = false,
- @skip_benchmark = false, @colorize = true)
- @logger = Log.for(for)
- Colorize.enabled = @colorize
- end
-
- abstract def request(request)
- abstract def response(response)
-
- protected def human_time(elapsed : Time::Span)
- elapsed = elapsed.to_f
- case Math.log10(elapsed)
- when 0..Float64::MAX
- digits = elapsed
- suffix = "s"
- when -3..0
- digits = elapsed * 1000
- suffix = "ms"
- when -6..-3
- digits = elapsed * 1_000_000
- suffix = "ยตs"
- else
- digits = elapsed * 1_000_000_000
- suffix = "ns"
- end
-
- "#{digits.round(2).to_s}#{suffix}"
- end
- end
-
- @@formats = {} of String => Abstract.class
-
- # Logging format register
- module Register
- def register(name : String, format : Abstract.class)
- @@formats[name] = format
- end
-
- def [](name : String)
- @@formats[name]
- end
-
- def []?(name : String)
- @@formats[name]?
- end
-
- def availables
- @@formats.keys
- end
- end
-
- # Similar to `Log::ShortFormat`
- #
- # **NOTE**: It invalid by calling `Log.setup` or `Log.setup_from_env` outside of Halite.
- #
- # Copy from https://github.com/crystal-lang/crystal/blob/3c48f311f/src/log/format.cr#L197
- struct ShortFormat < Log::StaticFormatter
- def run
- "#{timestamp} - #{source(before: " ", after: ": ")}#{message}" \
- "#{data(before: " -- ")}#{context(before: " -- ")}#{exception}"
- end
-
- def timestamp
- Helper.to_rfc3339(@entry.timestamp, @io)
- end
- end
-
- extend Register
-
- Halite.register_feature "logging", self
- end
-end
-
-require "./logging/*"
diff --git a/lib/octokit/lib/halite/src/halite/features/logging/common.cr b/lib/octokit/lib/halite/src/halite/features/logging/common.cr
deleted file mode 100644
index 892f520..0000000
--- a/lib/octokit/lib/halite/src/halite/features/logging/common.cr
+++ /dev/null
@@ -1,112 +0,0 @@
-class Halite::Logging
- # Common logging format
- #
- # Instance variables to check `Halite::Logging::Abstract`
- #
- # ```
- # Halite.use("logging", logging: Halite::Logging::Common.new(skip_request_body: true))
- # .get("http://httpbin.org/get")
- #
- # # Or
- # Halite.logging(format: "common", skip_request_body: true)
- # .get("http://httpbin.org/get")
- #
- # # => 2018-08-31 16:56:12 +08:00 | request | GET | http://httpbin.org/get
- # # => 2018-08-31 16:56:13 +08:00 | response | 200 | http://httpbin.org/get | 1.08s | application/json
- # ```
- class Common < Abstract
- def request(request)
- message = String.build do |io|
- io << "> | request | " << colorful_method(request.verb)
- io << "| " << request.uri
- unless request.body.empty? || @skip_request_body
- io << "\n" << request.body
- end
- end
-
- @logger.info { message }
- @request_time = Time.utc unless @skip_benchmark
- end
-
- def response(response)
- message = String.build do |io|
- content_type = response.content_type || "Unknown MIME"
- io << "< | response | " << colorful_status_code(response.status_code)
- io << "| " << response.uri
- if !@skip_benchmark && (request_time = @request_time)
- elapsed = Time.utc - request_time
- io << " | " << human_time(elapsed)
- end
-
- io << " | " << content_type
- unless response.body.empty? || binary_type?(content_type) || @skip_response_body
- io << "\n" << response.body
- end
- end
-
- @logger.info { message }
- end
-
- protected def colorful_method(method, is_request = true)
- fore, back = case method.upcase
- when "GET"
- [:white, :blue]
- when "POST"
- [:white, :cyan]
- when "PUT"
- [:white, :yellow]
- when "DELETE"
- [:white, :red]
- when "PATCH"
- [:white, :green]
- when "HEAD"
- [:white, :magenta]
- else
- [:dark_gray, :white]
- end
-
- colorful((" %-7s" % method), fore, back)
- end
-
- protected def colorful_status_code(status_code : Int32)
- fore, back = case status_code
- when 300..399
- [:dark_gray, :white]
- when 400..499
- [:white, :yellow]
- when 500..999
- [:white, :red]
- else
- [:white, :green]
- end
-
- colorful((" %-7s" % status_code), fore, back)
- end
-
- protected def colorful(message, fore, back)
- Colorize.enabled = !!(@colorize && (backend = @logger.backend.as?(Log::IOBackend)) && backend.io.tty?)
-
- message.colorize.fore(fore).back(back)
- end
-
- # return `true` if is binary types with MIME type
- #
- # MIME types list: https://developer.mozilla.org/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Complete_list_of_MIME_types
- private def binary_type?(content_type)
- binary_types = %w(image audio video)
- application_types = %w(pdf octet-stream ogg 3gpp ebook archive rar zip tar 7z word powerpoint excel flash font)
-
- binary_types.each do |name|
- return true if content_type.starts_with?(name)
- end
-
- application_types.each do |name|
- return true if content_type.starts_with?("application") && content_type.includes?(name)
- end
-
- false
- end
-
- Logging.register "common", self
- end
-end
diff --git a/lib/octokit/lib/halite/src/halite/features/logging/json.cr b/lib/octokit/lib/halite/src/halite/features/logging/json.cr
deleted file mode 100644
index da980bc..0000000
--- a/lib/octokit/lib/halite/src/halite/features/logging/json.cr
+++ /dev/null
@@ -1,106 +0,0 @@
-require "json"
-
-class Halite::Logging
- # JSON logging format
- #
- # Instance variables to check `Halite::Logging::Abstract`.
- #
- # In JSON format, if you set skip some key, it will return `false`.
- #
- # ```
- # Halite.use("logging", logging: Halite::Logging::JSON.new(skip_request_body: true))
- # .get("http://httpbin.org/get")
- #
- # # Or
- # Halite.logging(format: "json", skip_request_body: true)
- # .get("http://httpbin.org/get")
- # ```
- #
- # Log will look like:
- #
- # ```
- # {
- # "created_at": "2018-08-31T16:53:57+08:00:00",
- # "entry": {
- # "request": {
- # "body": "",
- # "headers": {...},
- # "method": "GET",
- # "url": "http://httpbin.org/anything",
- # "timestamp": "2018-08-31T16:53:59+08:00:00",
- # },
- # "response": {
- # "body": false,
- # "header": {...},
- # "status_code": 200,
- # "http_version": "HTTP/1.1",
- # "timestamp": "2018-08-31T16:53:59+08:00:00",
- # },
- # },
- # }
- # ```
- class JSON < Abstract
- @request : Request? = nil
- @response : Response? = nil
-
- def request(request)
- @request_time = Time.utc
- @request = Request.new(request, @skip_request_body)
- end
-
- def response(response)
- @response = Response.new(response, @skip_response_body)
- @logger.info { raw }
- end
-
- private def raw
- elapsed : String? = nil
- if !@skip_benchmark && (request_time = @request_time)
- elapsed = human_time(Time.utc - request_time)
- end
-
- {
- "created_at" => Helper.to_rfc3339(@request_time.not_nil!),
- "elapsed" => elapsed,
- "entry" => {
- "request" => @request.not_nil!.to_h,
- "response" => @response.not_nil!.to_h,
- },
- }.to_pretty_json
- end
-
- # :nodoc:
- private struct Request
- def initialize(@request : Halite::Request, @skip_body = false)
- end
-
- def to_h
- {
- "body" => @skip_body ? false : @request.body,
- "headers" => @request.headers.to_flat_h,
- "method" => @request.verb,
- "url" => @request.uri.to_s,
- "timestamp" => Helper.to_rfc3339(Time.utc),
- }
- end
- end
-
- # :nodoc:
- private struct Response
- def initialize(@response : Halite::Response, @skip_body = false)
- end
-
- def to_h
- {
- "body" => @skip_body ? false : @response.body,
- "header" => @response.headers.to_flat_h,
- "status_code" => @response.status_code,
- "http_version" => @response.version,
- "timestamp" => Helper.to_rfc3339(Time.utc),
- }
- end
- end
-
- Logging.register "json", self
- end
-end
diff --git a/lib/octokit/lib/halite/src/halite/form_data.cr b/lib/octokit/lib/halite/src/halite/form_data.cr
deleted file mode 100644
index 707d53b..0000000
--- a/lib/octokit/lib/halite/src/halite/form_data.cr
+++ /dev/null
@@ -1,68 +0,0 @@
-require "http/formdata"
-require "mime/multipart"
-
-module Halite
- # Utility-belt to build form data request bodies.
- #
- # Provides support for `application/x-www-form-urlencoded` and
- # `multipart/form-data` types.
- #
- # ```
- # form = FormData.create({
- # "name" => "Lizeth Gusikowski",
- # "skill" => ["ruby", "crystal"],
- # "avatar" => File.open("avatar.png"), # => "image binary data"
- # })
- #
- # form.body # => "----------------------------_ytTht-0D5oif0cAGXSPjPSN\r\nContent-Disposition: form-data; name=\"name\"\r\n\r\nLizeth Gusikowski\r\n----------------------------_ytTht-0D5oif0cAGXSPjPSN\r\nContent-Disposition: form-data; name=\"skill\"\r\n\r\nruby\r\n----------------------------_ytTht-0D5oif0cAGXSPjPSN\r\nContent-Disposition: form-data; name=\"skill\"\r\n\r\ncrystal\r\n----------------------------_ytTht-0D5oif0cAGXSPjPSN\r\nContent-Disposition: form-data; name=\"avatar\"; filename=\"avatar.png\"\r\n\r\nimage binary data\n\r\n----------------------------_ytTht-0D5oif0cAGXSPjPSN--"
- # form.headers # => HTTP::Headers{"Content-Type" => "multipart/form-data; boundary=\"--------------------------SS0a9QKeM_6fcj2CE5D4d0LQ\""}
- # ```
- module FormData
- # FormData factory. Automatically selects best type depending on given `data` Hash
- def self.create(data : Hash(String, Halite::Options::Type) = {} of String => Halite::Options::Type) : Halite::Request::Data
- if multipart?(data)
- io = IO::Memory.new
- builder = HTTP::FormData::Builder.new(io)
- data.each do |k, v|
- case v
- when File
- builder.file(k, v.as(IO), HTTP::FormData::FileMetadata.new(filename: File.basename(v.path)))
- when Array
- v.each do |e|
- case e
- when File
- builder.file(k, e.as(IO), HTTP::FormData::FileMetadata.new(filename: File.basename(e.path)))
- else
- builder.field(k, e.to_s)
- end
- end
- else
- builder.field(k, v.to_s)
- end
- end
- builder.finish
-
- Halite::Request::Data.new(io.to_s, builder.content_type)
- else
- body = HTTP::Params.encode(data)
- Halite::Request::Data.new(body, "application/x-www-form-urlencoded")
- end
- end
-
- # Tells whenever data contains multipart data or not.
- private def self.multipart?(data : Hash(String, Halite::Options::Type)) : Bool
- data.any? do |_, v|
- case v
- when File
- next true
- when Array
- v.any? do |vv|
- next true if vv.is_a?(File)
- end
- else
- false
- end
- end
- end
- end
-end
diff --git a/lib/octokit/lib/halite/src/halite/header_link.cr b/lib/octokit/lib/halite/src/halite/header_link.cr
deleted file mode 100644
index 25b6bbf..0000000
--- a/lib/octokit/lib/halite/src/halite/header_link.cr
+++ /dev/null
@@ -1,59 +0,0 @@
-module Halite
- # HeaderLink
- #
- # ref: [https://tools.ietf.org/html/rfc5988](https://tools.ietf.org/html/rfc5988)
- struct HeaderLink
- # Header link parser
- def self.parse(raw : String, uri : URI? = nil) : Hash(String, Halite::HeaderLink)
- links = {} of String => HeaderLink
- raw.split(/,\s*).each do |rel|
- head_link = parse_link(rel, uri)
- links[head_link.rel] = head_link
- end
- links
- end
-
- private def self.parse_link(raw, uri)
- params = {} of String => String
- if raw.includes?(";")
- target, attrs = raw.split(";", 2)
- rel = target = target.gsub(/[<> '\"]/, "").strip
- unless attrs.strip.empty?
- attrs.split(";").each do |attr|
- next if attr.strip.empty?
- key, value = attr.split("=")
- key = key.gsub(/['\"]/, "").strip
- next if params.has_key?(key)
-
- value = value.gsub(/['\"]/, "").strip
- params[key] = value
- end
-
- if name = params.delete("rel")
- rel = name
- if target == "/"
- target = rel
- elsif target.starts_with?("/") && (uri_local = uri)
- full_target = uri_local.dup
- full_target.path = target
- target = full_target.to_s
- end
- end
- end
- else
- rel = target = raw.gsub(/[<> '\"]/, "").strip
- end
-
- new(rel, target, params)
- end
-
- getter rel, target, params
-
- def initialize(@rel : String, @target : String, @params : Hash(String, String))
- end
-
- def to_s(io)
- io << target
- end
- end
-end
diff --git a/lib/octokit/lib/halite/src/halite/mime_type.cr b/lib/octokit/lib/halite/src/halite/mime_type.cr
deleted file mode 100644
index ca871e6..0000000
--- a/lib/octokit/lib/halite/src/halite/mime_type.cr
+++ /dev/null
@@ -1,33 +0,0 @@
-module Halite
- module MimeType
- @@adapters = {} of String => MimeType::Adapter
- @@aliases = {} of String => String
-
- def self.register(adapter : MimeType::Adapter, name : String, *shortcuts)
- @@adapters[name] = adapter
- shortcuts.each do |shortcut|
- next unless shortcut.is_a?(String)
- @@aliases[shortcut] = name
- end unless shortcuts.empty?
- end
-
- def self.[](name : String)
- @@adapters[normalize name]
- end
-
- def self.[]?(name : String)
- @@adapters[normalize name]?
- end
-
- private def self.normalize(name : String)
- @@aliases.fetch name, name
- end
-
- abstract class Adapter
- abstract def encode(obj)
- abstract def decode(string)
- end
- end
-end
-
-require "./mime_types/*"
diff --git a/lib/octokit/lib/halite/src/halite/mime_types/json.cr b/lib/octokit/lib/halite/src/halite/mime_types/json.cr
deleted file mode 100644
index 6519190..0000000
--- a/lib/octokit/lib/halite/src/halite/mime_types/json.cr
+++ /dev/null
@@ -1,15 +0,0 @@
-require "json"
-
-module Halite::MimeType
- class JSON < Adapter
- def encode(obj)
- obj.to_json
- end
-
- def decode(str)
- ::JSON.parse str
- end
- end
-end
-
-Halite::MimeType.register Halite::MimeType::JSON.new, "application/json", "json"
diff --git a/lib/octokit/lib/halite/src/halite/options.cr b/lib/octokit/lib/halite/src/halite/options.cr
deleted file mode 100644
index b70f12d..0000000
--- a/lib/octokit/lib/halite/src/halite/options.cr
+++ /dev/null
@@ -1,495 +0,0 @@
-require "openssl"
-require "./options/*"
-
-module Halite
- # Options class
- #
- # ### Init with splats options
- #
- # ```
- # o = Options.new(
- # headers: {
- # user_agent: "foobar"
- # }
- # }
- # o.headers.class # => HTTP::Headers
- # o.cookies.class # => HTTP::Cookies
- # ```
- #
- # ### Set/Get timeout
- #
- # Set it with `connect_timeout`/`read_timeout`/`write_timeout` keys,
- # but get it call `Timeout` class.
- #
- # ```
- # o = Options.new(connect_timeout: 30, read_timeout: 30)
- # o.timeout.connect # => 30.0
- # o.timeout.read # => 30.0
- # o.timeout.write # => nil
- # ```
- #
- # ### Set/Get follow
- #
- # Set it with `follow`/`follow_strict` keys, but get it call `Follow` class.
- #
- # ```
- # o = Options.new(follow: 3, follow_strict: false)
- # o.follow.hops # => 3
- # o.follow.strict # => false
- # ```
- class Options
- def self.new(endpoint : (String | URI)? = nil,
- headers : (Hash(String, _) | NamedTuple)? = nil,
- cookies : (Hash(String, _) | NamedTuple)? = nil,
- params : (Hash(String, _) | NamedTuple)? = nil,
- form : (Hash(String, _) | NamedTuple)? = nil,
- json : (Hash(String, _) | NamedTuple)? = nil,
- raw : String? = nil,
- connect_timeout : (Int32 | Float64 | Time::Span)? = nil,
- read_timeout : (Int32 | Float64 | Time::Span)? = nil,
- write_timeout : (Int32 | Float64 | Time::Span)? = nil,
- follow : Int32? = nil,
- follow_strict : Bool? = nil,
- tls : OpenSSL::SSL::Context::Client? = nil,
- features = {} of String => Feature)
- new(
- endpoint: endpoint,
- headers: headers,
- cookies: cookies,
- params: params,
- form: form,
- json: json,
- raw: raw,
- timeout: Timeout.new(connect: connect_timeout, read: read_timeout, write: write_timeout),
- follow: Follow.new(hops: follow, strict: follow_strict),
- tls: tls,
- features: features
- )
- end
-
- # Types of options in a Hash
- alias Type = Nil | Symbol | String | Int32 | Int64 | Float64 | Bool | File | Array(Type) | Hash(String, Type)
-
- property endpoint : URI?
- property headers : HTTP::Headers
- property cookies : HTTP::Cookies
- property timeout : Timeout
- property follow : Follow
- property tls : OpenSSL::SSL::Context::Client?
-
- property params : Hash(String, Type)
- property form : Hash(String, Type)
- property json : Hash(String, Type)
- property raw : String?
-
- property features : Hash(String, Feature)
-
- def initialize(*,
- endpoint : (String | URI)? = nil,
- headers : (Hash(String, _) | NamedTuple)? = nil,
- cookies : (Hash(String, _) | NamedTuple)? = nil,
- params : (Hash(String, _) | NamedTuple)? = nil,
- form : (Hash(String, _) | NamedTuple)? = nil,
- json : (Hash(String, _) | NamedTuple)? = nil,
- @raw : String? = nil,
- @timeout = Timeout.new,
- @follow = Follow.new,
- @tls : OpenSSL::SSL::Context::Client? = nil,
- @features = {} of String => Feature)
- @endpoint = parse_endpoint(endpoint)
- @headers = parse_headers(headers)
- @cookies = parse_cookies(cookies)
- @params = parse_params(params)
- @form = parse_form(form)
- @json = parse_json(json)
- end
-
- def initialize(*,
- @endpoint : URI?,
- @headers : HTTP::Headers,
- @cookies : HTTP::Cookies,
- @params : Hash(String, Type),
- @form : Hash(String, Type),
- @json : Hash(String, Type),
- @raw : String? = nil,
- @timeout = Timeout.new,
- @follow = Follow.new,
- @tls : OpenSSL::SSL::Context::Client? = nil,
- @features = {} of String => Feature)
- end
-
- def with_endpoint(endpoint : String | URI)
- self.endpoint = endpoint
- self
- end
-
- # Alias `with_headers` method.
- def with_headers(**with_headers) : Halite::Options
- with_headers(with_headers)
- end
-
- # Returns `Options` self with given headers combined.
- def with_headers(headers : Hash(String, _) | NamedTuple) : Halite::Options
- @headers.merge!(parse_headers(headers))
- self
- end
-
- # Alias `with_cookies` method.
- def with_cookies(**cookies) : Halite::Options
- with_cookies(cookies)
- end
-
- # Returns `Options` self with given cookies combined.
- def with_cookies(cookies : Hash(String, _) | NamedTuple) : Halite::Options
- cookies.each do |key, value|
- @cookies[key.to_s] = value.to_s
- end
-
- self
- end
-
- # Returns `Options` self with given cookies combined.
- def with_cookies(cookies : HTTP::Cookies) : Halite::Options
- cookies.each do |cookie|
- with_cookies(cookie)
- end
-
- self
- end
-
- # Returns `Options` self with given cookies combined.
- def with_cookies(cookie : HTTP::Cookie) : Halite::Options
- cookie_header = HTTP::Headers{"Cookie" => cookie.to_cookie_header}
- @headers.merge!(cookie_header)
- @cookies.fill_from_client_headers(@headers)
- self
- end
-
- # Returns `Options` self with given max hops of redirect times.
- #
- # ```
- # # Automatically following redirects
- # options.with_follow
- # # A maximum of 3 subsequent redirects
- # options.with_follow(3)
- # # Set subsequent redirects
- # options.with_follow(3)
- # ```
- def with_follow(follow = Follow::MAX_HOPS, strict = Follow::STRICT) : Halite::Options
- @follow.hops = follow
- @follow.strict = strict
- self
- end
-
- # Returns `Options` self with given connect, read timeout.
- def with_timeout(connect : (Int32 | Float64 | Time::Span)? = nil,
- read : (Int32 | Float64 | Time::Span)? = nil,
- write : (Int32 | Float64 | Time::Span)? = nil) : Halite::Options
- @timeout.connect = connect.to_f if connect
- @timeout.read = read.to_f if read
- @timeout.write = write.to_f if write
-
- self
- end
-
- # Returns `Options` self with the name of features.
- def with_features(*features)
- features.each do |feature|
- with_features(feature, NamedTuple.new)
- end
- self
- end
-
- # Returns `Options` self with feature name and options.
- def with_features(feature_name : String, **opts)
- with_features(feature_name, opts)
- end
-
- # Returns `Options` self with feature name and options.
- def with_features(name : String, opts : NamedTuple)
- raise UnRegisterFeatureError.new("Not available feature: #{name}") unless klass = Halite.feature?(name)
- @features[name] = klass.new(**opts)
- self
- end
-
- # Returns `Options` self with feature name and feature.
- def with_features(name : String, feature : Feature)
- @features[name] = feature
- self
- end
-
- # Returns `Options` iitself with given format and the options of format.
- def with_logging(format : String, **opts)
- raise UnRegisterLoggerFormatError.new("Not available logging format: #{format}") unless format_cls = Logging[format]?
- with_logging(format_cls.new(**opts))
- end
-
- # Returns `Options` self with given logging, depend on `with_features`.
- def with_logging(logging : Halite::Logging::Abstract)
- with_features("logging", logging: logging)
- self
- end
-
- # Set endpoint of request
- def endpoint=(endpoint : String)
- @endpoint = URI.parse(endpoint)
- end
-
- # Set headers of request
- def headers=(headers : (Hash(String, _) | NamedTuple))
- @headers = parse_headers(headers)
- end
-
- # Alias `Timeout.connect`
- def connect_timeout
- @timeout.connect
- end
-
- # Alias `Timeout.connect=`
- def connect_timeout=(timeout : Int32 | Float64 | Time::Span)
- @timeout.connect = timeout
- end
-
- # Alias `Timeout.read`
- def read_timeout
- @timeout.read
- end
-
- # Alias `Timeout.read=`
- def read_timeout=(timeout : Int32 | Float64 | Time::Span)
- @timeout.read = timeout
- end
-
- # Alias `Timeout.write`
- def write_timeout
- @timeout.write
- end
-
- # Alias `Timeout.write=`
- def write_timeout=(timeout : Int32 | Float64 | Time::Span)
- @timeout.write = timeout
- end
-
- # Alias `Follow.hops=`
- def follow=(hops : Int32)
- @follow.hops = hops
- end
-
- # Alias `Follow.strict`
- def follow_strict
- @follow.strict
- end
-
- # Alias `Follow.strict=`
- def follow_strict=(strict : Bool)
- @follow.strict = strict
- end
-
- # Get logging status
- def logging : Bool
- !@features.values.select { |v| v.is_a?(Halite::Logging) }.empty?
- end
-
- # Quick enable logging
- #
- # By defaults, use `Logging::Common` as logging output.
- def logging=(enable : Bool)
- if enable
- with_features("logging") unless logging
- else
- @features.delete("logging")
- end
- end
-
- # Merge with other `Options` and return new `Halite::Options`
- def merge(other : Halite::Options) : Halite::Options
- options = Halite::Options.new
- options.merge!(dup)
- options.merge!(other)
- options
- end
-
- # Merge with other `Options` and return self
- def merge!(other : Halite::Options) : Halite::Options
- @endpoint = other.endpoint if other.endpoint
-
- @headers.merge!(other.headers)
-
- other.cookies.each do |cookie|
- @cookies << cookie
- end if other.cookies != @cookies
-
- if other.timeout.connect || other.timeout.read || other.timeout.write
- @timeout = other.timeout
- end
-
- if other.follow.updated?
- @follow = other.follow
- end
-
- @features.merge!(other.features) unless other.features.empty?
- @params.merge!(other.params) if other.params
- @form.merge!(other.form) if other.form
- @json.merge!(other.json) if other.json
- @raw = other.raw if other.raw
- @tls = other.tls if other.tls
-
- self
- end
-
- # Reset options
- def clear! : Halite::Options
- @endpoint = nil
- @headers = HTTP::Headers.new
- @cookies = HTTP::Cookies.new
- @params = {} of String => Type
- @form = {} of String => Type
- @json = {} of String => Type
- @raw = nil
- @timeout = Timeout.new
- @follow = Follow.new
- @features = {} of String => Feature
- @tls = nil
-
- self
- end
-
- # Produces a shallow copy of objโthe instance variables of obj are copied,
- # but not the objects they reference. dup copies the tainted state of obj.
- def dup
- Halite::Options.new(
- endpoint: @endpoint,
- headers: @headers.dup,
- cookies: @cookies,
- params: @params,
- form: @form,
- json: @json,
- raw: @raw,
- timeout: @timeout,
- follow: @follow,
- features: @features,
- tls: @tls
- )
- end
-
- # Returns this collection as a plain Hash.
- def to_h
- {
- "endpoint" => @endpoint,
- "headers" => @headers.to_h,
- "cookies" => @cookies.to_h,
- "params" => @params ? @params.to_h : nil,
- "form" => @form ? @form.to_h : nil,
- "json" => @json ? @json.to_h : nil,
- "raw" => @raw,
- "connect_timeout" => @timeout.connect,
- "read_timeout" => @timeout.read,
- "follow" => @follow.hops,
- "follow_strict" => @follow.strict,
- }
- end
-
- private def parse_endpoint(endpoint : (String | URI)?) : URI?
- case endpoint
- when String
- URI.parse(endpoint)
- when URI
- endpoint.as(URI)
- else
- nil
- end
- end
-
- private def parse_headers(raw : (Hash(String, _) | NamedTuple | HTTP::Headers)?) : HTTP::Headers
- case raw
- when Hash, NamedTuple
- HTTP::Headers.encode(raw)
- when HTTP::Headers
- raw.as(HTTP::Headers)
- else
- HTTP::Headers.new
- end
- end
-
- private def parse_cookies(raw : (Hash(String, _) | NamedTuple | HTTP::Cookies)?) : HTTP::Cookies
- cookies = HTTP::Cookies.from_client_headers(@headers)
- if objects = raw
- objects.each do |key, value|
- cookies[key] = case value
- when HTTP::Cookie
- value
- else
- value.to_s
- end
- end
- end
- cookies
- end
-
- private def parse_cookies(headers : HTTP::Headers) : HTTP::Cookies
- cookies = HTTP::Cookies.from_client_headers(headers)
- end
-
- {% for attr in %w(params form json) %}
- private def parse_{{ attr.id }}(raw : (Hash(String, _) | NamedTuple)?) : Hash(String, Options::Type)
- new_{{ attr.id }} = {} of String => Type
- return new_{{ attr.id }} unless {{ attr.id }} = raw
-
- if {{ attr.id }}.responds_to?(:each)
- {{ attr.id }}.each do |key, value|
- new_{{ attr.id }}[key.to_s] = case value
- when Array
- cast_hash(value.as(Array))
- when Hash
- cast_hash(value.as(Hash))
- when NamedTuple
- cast_hash(value.as(NamedTuple))
- when Type
- value
- else
- value.as(Type)
- end
- end
- end
-
- new_{{ attr.id }}
- end
- {% end %}
-
- private def cast_hash(raw : Array) : Options::Type
- raw.each_with_object([] of Type) do |value, obj|
- obj << case value
- when Array
- cast_hash(value.as(Array))
- when Hash
- cast_hash(value.as(Hash))
- when NamedTuple
- cast_hash(value.as(NamedTuple))
- else
- value.as(Type)
- end
- end.as(Type)
- end
-
- private def cast_hash(raw : Hash) : Options::Type
- raw.each_with_object({} of String => Type) do |(key, value), obj|
- if key.responds_to?(:to_s)
- obj[key.to_s] = case value
- when Array
- cast_hash(value.as(Array))
- when Hash
- cast_hash(value.as(Hash))
- when NamedTuple
- cast_hash(value.as(NamedTuple))
- else
- value.as(Type)
- end
- end
- end.as(Type)
- end
-
- private def cast_hash(raw : NamedTuple) : Options::Type
- cast_hash(raw.to_h)
- end
- end
-end
diff --git a/lib/octokit/lib/halite/src/halite/options/follow.cr b/lib/octokit/lib/halite/src/halite/options/follow.cr
deleted file mode 100644
index 9ff8264..0000000
--- a/lib/octokit/lib/halite/src/halite/options/follow.cr
+++ /dev/null
@@ -1,33 +0,0 @@
-module Halite
- class Options
- struct Follow
- # No follow by default
- DEFAULT_HOPS = 0
-
- # A maximum of 5 subsequent redirects
- MAX_HOPS = 5
-
- # Redirector hops policy
- STRICT = true
-
- property hops : Int32
- property strict : Bool
-
- def initialize(hops : Int32? = nil, strict : Bool? = nil)
- @hops = hops || DEFAULT_HOPS
- @strict = strict.nil? ? STRICT : strict
- end
-
- def strict?
- @strict == true
- end
-
- def updated?
- @hops != DEFAULT_HOPS || @strict != STRICT
- end
- end
- end
-
- # :nodoc:
- alias Follow = Options::Follow
-end
diff --git a/lib/octokit/lib/halite/src/halite/options/timeout.cr b/lib/octokit/lib/halite/src/halite/options/timeout.cr
deleted file mode 100644
index 9c3b043..0000000
--- a/lib/octokit/lib/halite/src/halite/options/timeout.cr
+++ /dev/null
@@ -1,46 +0,0 @@
-module Halite
- class Options
- # Timeout struct
- struct Timeout
- getter connect : Float64?
- getter read : Float64?
- getter write : Float64?
-
- def initialize(connect : (Int32 | Float64 | Time::Span)? = nil,
- read : (Int32 | Float64 | Time::Span)? = nil,
- write : (Int32 | Float64 | Time::Span)? = nil)
- @connect = timeout_value(connect)
- @read = timeout_value(read)
- @write = timeout_value(write)
- end
-
- def connect=(connect : (Int32 | Float64 | Time::Span)?)
- @connect = timeout_value(connect)
- end
-
- def read=(read : (Int32 | Float64 | Time::Span)?)
- @read = timeout_value(read)
- end
-
- def write=(write : (Int32 | Float64 | Time::Span)?)
- @write = timeout_value(write)
- end
-
- private def timeout_value(value : (Int32 | Float64 | Time::Span)? = nil) : Float64?
- case value
- when Int32
- value.as(Int32).to_f
- when Float64
- value.as(Float64)
- when Time::Span
- value.as(Time::Span).total_seconds.to_f
- else
- nil
- end
- end
- end
- end
-
- # :nodoc:
- alias Timeout = Options::Timeout
-end
diff --git a/lib/octokit/lib/halite/src/halite/rate_limit.cr b/lib/octokit/lib/halite/src/halite/rate_limit.cr
deleted file mode 100644
index 1f05e37..0000000
--- a/lib/octokit/lib/halite/src/halite/rate_limit.cr
+++ /dev/null
@@ -1,30 +0,0 @@
-module Halite
- # Limit Rate
- #
- # ref: [https://tools.ietf.org/id/draft-polli-ratelimit-headers-00.html](https://tools.ietf.org/id/draft-polli-ratelimit-headers-00.html)
- #
- # ```
- # > X-RateLimit-Limit: 5000
- # > X-RateLimit-Remaining: 4987
- # > X-RateLimit-Reset: 1350085394
- # ```
- struct RateLimit
- RATELIMIT_LIMIT = "X-RateLimit-Limit"
- RATELIMIT_REMAINING = "X-RateLimit-Remaining"
- RATELIMIT_RESET = "X-RateLimit-Reset"
-
- def self.parse(headers : HTTP::Headers)
- limit = headers[RATELIMIT_LIMIT]?.try &.to_i
- remaining = headers[RATELIMIT_REMAINING]?.try &.to_i
- reset = headers[RATELIMIT_RESET]?.try &.to_i
- return if !limit && !remaining && !reset
-
- new(limit, remaining, reset)
- end
-
- getter limit, remaining, reset
-
- def initialize(@limit : Int32?, @remaining : Int32?, @reset : Int32?)
- end
- end
-end
diff --git a/lib/octokit/lib/halite/src/halite/redirector.cr b/lib/octokit/lib/halite/src/halite/redirector.cr
deleted file mode 100644
index d639fe3..0000000
--- a/lib/octokit/lib/halite/src/halite/redirector.cr
+++ /dev/null
@@ -1,84 +0,0 @@
-module Halite
- class Redirector
- # HTTP status codes which indicate redirects
- REDIRECT_CODES = [300, 301, 302, 303, 307, 308]
-
- # Codes which which should raise StateError in strict mode if original
- # request was any of {UNSAFE_VERBS}
- STRICT_SENSITIVE_CODES = [300, 301, 302]
-
- # Insecure http verbs, which should trigger StateError in strict mode
- # upon {STRICT_SENSITIVE_CODES}
- UNSAFE_VERBS = %w(PUT DELETE POST)
-
- # Verbs which will remain unchanged upon See Other response.
- SEE_OTHER_ALLOWED_VERBS = %w(GET HEAD)
-
- def self.new(request : Halite::Request, response : Halite::Response, options : Halite::Options)
- new(request, response, options.follow.hops, options.follow.strict)
- end
-
- getter strict : Bool
- getter max_hops : Int32
-
- # Instance a new Redirector
- def initialize(@request : Halite::Request, @response : Halite::Response, @max_hops = 5, @strict = true)
- @visited = [] of String
- end
-
- # Follows redirects until non-redirect response found
- def perform(&block : Halite::Request -> Halite::Response) : Halite::Response
- if avaiable?
- each_redirect do |request|
- block.call(request)
- end
- end
-
- @response
- end
-
- # Loop each redirect request with block call
- def each_redirect(&block : Halite::Request -> Halite::Response)
- while avaiable?
- @visited << "#{@request.verb} #{@request.uri}"
-
- raise TooManyRedirectsError.new if too_many_hops?
- raise EndlessRedirectError.new if endless_loop?
-
- @request = redirect_to(@response.headers["Location"]?)
- @response = block.call(@request)
- end
- end
-
- # Return `true` if it should redirect, else `false`
- def avaiable?
- REDIRECT_CODES.includes?(@response.status_code)
- end
-
- # Redirect policy for follow
- private def redirect_to(uri : String?)
- raise StateError.new("No found `Location` in headers") unless uri
-
- verb = @request.verb
- code = @response.status_code
-
- if UNSAFE_VERBS.includes?(verb) && STRICT_SENSITIVE_CODES.includes?(code)
- raise StateError.new("Can not follow #{code} redirect") if @strict
- verb = "GET"
- end
-
- verb = "GET" if !SEE_OTHER_ALLOWED_VERBS.includes?(verb) && code == 303
- @request.redirect(uri, verb)
- end
-
- # Check if we reached max amount of redirect hops
- private def too_many_hops? : Bool
- 1 <= @max_hops && @max_hops < @visited.size
- end
-
- # Check if we got into an endless loop
- def endless_loop?
- 2 <= @visited.count(@visited.last)
- end
- end
-end
diff --git a/lib/octokit/lib/halite/src/halite/request.cr b/lib/octokit/lib/halite/src/halite/request.cr
deleted file mode 100644
index 637b536..0000000
--- a/lib/octokit/lib/halite/src/halite/request.cr
+++ /dev/null
@@ -1,92 +0,0 @@
-module Halite
- class Request
- # Allowed methods
- #
- # See more: [https://github.com/crystal-lang/crystal/blob/863f301cfe9e9757a6bf1a494ab7bf49bfc07a06/src/http/client.cr#L329](https://github.com/crystal-lang/crystal/blob/863f301cfe9e9757a6bf1a494ab7bf49bfc07a06/src/http/client.cr#L329)
- METHODS = %w(GET PUT POST DELETE HEAD PATCH OPTIONS)
-
- # Allowed schemes
- SCHEMES = %w(http https)
-
- # Request user-agent by default
- USER_AGENT = "Halite/#{Halite::VERSION}"
-
- # The verb name of request
- getter verb : String
-
- # The uri of request
- getter uri : URI
-
- # The scheme name of request
- getter scheme : String
-
- # The headers of request
- getter headers : HTTP::Headers
-
- # The payload of request
- getter body : String
-
- def initialize(verb : String, @uri : URI, @headers : HTTP::Headers = HTTP::Headers.new, @body : String = "")
- @verb = verb.upcase
-
- raise UnsupportedMethodError.new("Unknown method: #{@verb}") unless METHODS.includes?(@verb)
- raise UnsupportedSchemeError.new("Missing scheme: #{@uri}") unless @uri.scheme
-
- @scheme = @uri.scheme.not_nil!
-
- raise UnsupportedSchemeError.new("Unknown scheme: #{@scheme}") unless SCHEMES.includes?(@scheme)
-
- @headers["User-Agent"] ||= USER_AGENT
- @headers["Connection"] ||= "close"
- end
-
- # Returns new Request with updated uri
- def redirect(uri : String, verb = @verb)
- headers = @headers.dup
- headers.delete("Host")
-
- Request.new(verb, redirect_uri(domain, uri), headers, body)
- end
-
- # @return `URI` with the scheme, user, password, port and host combined
- def domain
- URI.new(@uri.scheme, @uri.host, @uri.port, "", nil, @uri.user, @uri.password, nil)
- end
-
- # @return `String` with the path, query and fragment combined
- def full_path
- String.build do |str|
- {% if Crystal::VERSION < "0.36.0" %}
- str << @uri.full_path
- {% else %}
- str << @uri.request_target
- {% end %}
- if @uri.fragment
- str << "#" << @uri.fragment
- end
- end
- end
-
- private def redirect_uri(source : URI, uri : String) : URI
- return source if uri == '/'
-
- new_uri = URI.parse(uri)
- # return a new uri with source and relative path
- unless new_uri.scheme && new_uri.host
- new_uri = source.dup.tap do |u|
- u.path = (uri[0] == '/') ? uri : "/#{uri}"
- end
- end
-
- new_uri
- end
-
- # Request data of body
- struct Data
- getter body, content_type
-
- def initialize(@body : String, @content_type : String? = nil)
- end
- end
- end
-end
diff --git a/lib/octokit/lib/halite/src/halite/response.cr b/lib/octokit/lib/halite/src/halite/response.cr
deleted file mode 100644
index 4048d01..0000000
--- a/lib/octokit/lib/halite/src/halite/response.cr
+++ /dev/null
@@ -1,123 +0,0 @@
-module Halite
- class Response
- def self.new(uri : URI, status_code : Int32, body : String? = nil, headers = HTTP::Headers.new,
- status_message = nil, body_io : IO? = nil, version = "HTTP/1.1", history = [] of Halite::Response)
- conn = HTTP::Client::Response.new(status_code, body, headers, status_message, version, body_io)
- new(uri, conn, history)
- end
-
- getter uri
- getter conn
- getter history : Array(Response)
-
- def initialize(@uri : URI, @conn : HTTP::Client::Response, @history = [] of Halite::Response)
- end
-
- delegate version, to: @conn
- delegate status_code, to: @conn
- delegate status_message, to: @conn
- delegate content_type, to: @conn
- delegate success?, to: @conn
-
- delegate headers, to: @conn
- delegate charset, to: @conn
-
- delegate body, to: @conn
- delegate body_io, to: @conn
-
- # Content Length
- def content_length : Int64?
- if value = @conn.headers["Content-Length"]?
- value.to_i64
- end
- end
-
- # Return a `HTTP::Cookies` of parsed cookie headers or else nil.
- def cookies : HTTP::Cookies?
- cookies = @conn.cookies ? @conn.cookies : HTTP::Cookies.from_server_headers(@conn.headers)
-
- # Try to fix empty domain
- cookies.map do |cookie|
- cookie.domain = @uri.host unless cookie.domain
- cookie
- end
-
- cookies
- end
-
- # Return a list of parsed link headers proxies or else nil.
- def links : Hash(String, Halite::HeaderLink)?
- return unless raw = headers["Link"]?
-
- HeaderLink.parse(raw, uri)
- end
-
- def rate_limit : Halite::RateLimit?
- RateLimit.parse(headers)
- end
-
- # Raise `Halite::ClientError`/`Halite::ServerError` if one occurred.
- #
- # - `4XX` raise an `Halite::ClientError` exception
- # - `5XX` raise an `Halite::ServerError` exception
- # - return `nil` with other status code
- #
- # ```
- # Halite.get("https://httpbin.org/status/404").raise_for_status
- # # => Unhandled exception: 404 not found error with url: https://httpbin.org/status/404 (Halite::ClientError)
- #
- # Halite.get("https://httpbin.org/status/500", params: {"foo" => "bar"}).raise_for_status
- # # => Unhandled exception: 500 internal server error error with url: https://httpbin.org/status/500?foo=bar (Halite::ServerError)
- #
- # Halite.get("https://httpbin.org/status/301").raise_for_status
- # # => nil
- # ```
- def raise_for_status
- if status_code >= 400 && status_code < 500
- raise Halite::ClientError.new(status_code: status_code, uri: uri)
- elsif status_code >= 500 && status_code < 600
- raise Halite::ServerError.new(status_code: status_code, uri: uri)
- end
- end
-
- # Parse response body with corresponding MIME type adapter.
- def parse(name : String? = nil)
- name ||= content_type
- raise Halite::Error.new("Missing media type") unless name
- raise Halite::UnRegisterMimeTypeError.new("unregister MIME type adapter: #{name}") unless MimeType[name]?
- MimeType[name].decode to_s
- end
-
- # Return filename if it exists, else `Nil`.
- def filename : String?
- headers["Content-Disposition"]?.try do |value|
- value.split("filename=")[1]
- end
- end
-
- # Return raw of response
- def to_raw
- io = IO::Memory.new
- @conn.to_io(io)
- io
- end
-
- # Return status_code, headers and body in a array
- def to_a
- [@conn.status_code, @conn.headers, to_s]
- end
-
- # Return String eagerly consume the entire body as a string
- def to_s
- @conn.body? ? @conn.body : @conn.body_io.to_s
- end
-
- def inspect
- "#<#{self.class} #{version} #{status_code} #{status_message} #{headers.to_flat_h}>"
- end
-
- def to_s(io)
- io << to_s
- end
- end
-end
diff --git a/lib/octokit/lib/json_mapping/.editorconfig b/lib/octokit/lib/json_mapping/.editorconfig
deleted file mode 100644
index 163eb75..0000000
--- a/lib/octokit/lib/json_mapping/.editorconfig
+++ /dev/null
@@ -1,9 +0,0 @@
-root = true
-
-[*.cr]
-charset = utf-8
-end_of_line = lf
-insert_final_newline = true
-indent_style = space
-indent_size = 2
-trim_trailing_whitespace = true
diff --git a/lib/octokit/lib/json_mapping/.gitignore b/lib/octokit/lib/json_mapping/.gitignore
deleted file mode 100644
index 0bbd4a9..0000000
--- a/lib/octokit/lib/json_mapping/.gitignore
+++ /dev/null
@@ -1,9 +0,0 @@
-/docs/
-/lib/
-/bin/
-/.shards/
-*.dwarf
-
-# Libraries don't need dependency lock
-# Dependencies will be locked in applications that use them
-/shard.lock
diff --git a/lib/octokit/lib/json_mapping/.travis.yml b/lib/octokit/lib/json_mapping/.travis.yml
deleted file mode 100644
index 227f158..0000000
--- a/lib/octokit/lib/json_mapping/.travis.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-language: crystal
-
-script:
- - crystal spec
- - crystal tool format --check
diff --git a/lib/octokit/lib/json_mapping/LICENSE b/lib/octokit/lib/json_mapping/LICENSE
deleted file mode 100644
index edcccc5..0000000
--- a/lib/octokit/lib/json_mapping/LICENSE
+++ /dev/null
@@ -1,21 +0,0 @@
-The MIT License (MIT)
-
-Copyright (c) 2020 Manas Technology Solutions
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
diff --git a/lib/octokit/lib/json_mapping/README.md b/lib/octokit/lib/json_mapping/README.md
deleted file mode 100644
index abef140..0000000
--- a/lib/octokit/lib/json_mapping/README.md
+++ /dev/null
@@ -1,56 +0,0 @@
-# json_mapping
-
-Provides the legacy `JSON.mapping` macro method.
-
-This shard is provided as-is and considered deprecated. It won't receive feature enhancements.
-
-Please consider using [`JSON::Serializable`](https://crystal-lang.org/api/latest/JSON/Serializable.html) instead, the successor included in Crystal's standard library.
-
-## Installation
-
-1. Add the dependency to your `shard.yml`:
-
-```yaml
-dependencies:
- json_mapping:
- github: crystal-lang/json_mapping.cr
-```
-
-2. Run `shards install`
-
-## Usage
-
-```crystal
-require "json_mapping"
-
-class Location
- JSON.mapping(
- lat: Float64,
- lng: Float64,
- )
-end
-
-class House
- JSON.mapping(
- address: String,
- location: {type: Location, nilable: true},
- )
-end
-
-house = House.from_json(%({"address": "Crystal Road 1234", "location": {"lat": 12.3, "lng": 34.5}}))
-house.address # => "Crystal Road 1234"
-house.location # => #
-house.to_json # => %({"address":"Crystal Road 1234","location":{"lat":12.3,"lng":34.5}})
-
-houses = Array(House).from_json(%([{"address": "Crystal Road 1234", "location": {"lat": 12.3, "lng": 34.5}}]))
-houses.size # => 1
-houses.to_json # => %([{"address":"Crystal Road 1234","location":{"lat":12.3,"lng":34.5}}])
-```
-
-## Contributing
-
-1. Fork it ()
-2. Create your feature branch (`git checkout -b my-new-feature`)
-3. Commit your changes (`git commit -am 'Add some feature'`)
-4. Push to the branch (`git push origin my-new-feature`)
-5. Create a new Pull Request
diff --git a/lib/octokit/lib/json_mapping/lib b/lib/octokit/lib/json_mapping/lib
deleted file mode 120000
index a96aa0e..0000000
--- a/lib/octokit/lib/json_mapping/lib
+++ /dev/null
@@ -1 +0,0 @@
-..
\ No newline at end of file
diff --git a/lib/octokit/lib/json_mapping/shard.yml b/lib/octokit/lib/json_mapping/shard.yml
deleted file mode 100644
index c42be08..0000000
--- a/lib/octokit/lib/json_mapping/shard.yml
+++ /dev/null
@@ -1,9 +0,0 @@
-name: json_mapping
-version: 0.1.1
-
-authors:
- - Brian J. Cardiff
-
-crystal: ">= 0.34.0, < 2.0.0"
-
-license: MIT
diff --git a/lib/octokit/lib/json_mapping/src/json_mapping.cr b/lib/octokit/lib/json_mapping/src/json_mapping.cr
deleted file mode 100644
index b7fee06..0000000
--- a/lib/octokit/lib/json_mapping/src/json_mapping.cr
+++ /dev/null
@@ -1,259 +0,0 @@
-require "json"
-
-module JSON
- module Mapping
- VERSION = "0.1.1"
- end
-
- # The `JSON.mapping` macro defines how an object is mapped to JSON.
- #
- # ### Example
- #
- # ```
- # require "json_mapping"
- #
- # class Location
- # JSON.mapping(
- # lat: Float64,
- # lng: Float64,
- # )
- # end
- #
- # class House
- # JSON.mapping(
- # address: String,
- # location: {type: Location, nilable: true},
- # )
- # end
- #
- # house = House.from_json(%({"address": "Crystal Road 1234", "location": {"lat": 12.3, "lng": 34.5}}))
- # house.address # => "Crystal Road 1234"
- # house.location # => #
- # house.to_json # => %({"address":"Crystal Road 1234","location":{"lat":12.3,"lng":34.5}})
- #
- # houses = Array(House).from_json(%([{"address": "Crystal Road 1234", "location": {"lat": 12.3, "lng": 34.5}}]))
- # houses.size # => 1
- # houses.to_json # => %([{"address":"Crystal Road 1234","location":{"lat":12.3,"lng":34.5}}])
- # ```
- #
- # ### Usage
- #
- # `JSON.mapping` must receive a series of named arguments, or a named tuple literal, or a hash literal,
- # whose keys will define Crystal properties.
- #
- # The value of each key can be a type. Primitive types (numbers, string, boolean and nil)
- # are supported, as well as custom objects which use `JSON.mapping` or define a `new` method
- # that accepts a `JSON::PullParser` and returns an object from it. Union types are supported,
- # if multiple types in the union can be mapped from the JSON, it is undefined which one will be chosen.
- #
- # The value can also be another hash literal with the following options:
- # * **type**: (required) the type described above (you can use `JSON::Any` too)
- # * **key**: the property name in the JSON document (as opposed to the property name in the Crystal code)
- # * **nilable**: if `true`, the property can be `Nil`. Passing `T?` as a type has the same effect.
- # * **default**: value to use if the property is missing in the JSON document, or if it's `null` and `nilable` was not set to `true`. If the default value creates a new instance of an object (for example `[1, 2, 3]` or `SomeObject.new`), a different instance will be used each time a JSON document is parsed.
- # * **emit_null**: if `true`, emits a `null` value for nilable properties (by default nulls are not emitted)
- # * **converter**: specify an alternate type for parsing and generation. The converter must define `from_json(JSON::PullParser)` and `to_json(value, JSON::Builder)` as class methods. Examples of converters are `Time::Format` and `Time::EpochConverter` for `Time`.
- # * **root**: assume the value is inside a JSON object with a given key (see `Object.from_json(string_or_io, root)`)
- # * **setter**: if `true`, will generate a setter for the variable, `true` by default
- # * **getter**: if `true`, will generate a getter for the variable, `true` by default
- # * **presence**: if `true`, a `{{key}}_present?` method will be generated when the key was present (even if it has a `null` value), `false` by default
- #
- # This macro by default defines getters and setters for each variable (this can be overrided with *setter* and *getter*).
- # The mapping doesn't define a constructor accepting these variables as arguments, but you can provide an overload.
- #
- # The macro basically defines a constructor accepting a `JSON::PullParser` that reads from
- # it and initializes this type's instance variables. It also defines a `to_json(JSON::Builder)` method
- # by invoking `to_json(JSON::Builder)` on each of the properties (unless a converter is specified, in
- # which case `to_json(value, JSON::Builder)` is invoked).
- #
- # This macro also declares instance variables of the types given in the mapping.
- #
- # If *strict* is `true`, unknown properties in the JSON
- # document will raise a parse exception. The default is `false`, so unknown properties
- # are silently ignored.
- macro mapping(_properties_, strict = false)
- {% for key, value in _properties_ %}
- {% _properties_[key] = {type: value} unless value.is_a?(HashLiteral) || value.is_a?(NamedTupleLiteral) %}
- {% end %}
-
- {% for key, value in _properties_ %}
- {% _properties_[key][:key_id] = key.id.gsub(/\?$/, "") %}
- {% end %}
-
- {% for key, value in _properties_ %}
- @{{value[:key_id]}} : {{value[:type]}}{{ (value[:nilable] ? "?" : "").id }}
-
- {% if value[:setter] == nil ? true : value[:setter] %}
- def {{value[:key_id]}}=(_{{value[:key_id]}} : {{value[:type]}}{{ (value[:nilable] ? "?" : "").id }})
- @{{value[:key_id]}} = _{{value[:key_id]}}
- end
- {% end %}
-
- {% if value[:getter] == nil ? true : value[:getter] %}
- def {{key.id}} : {{value[:type]}}{{ (value[:nilable] ? "?" : "").id }}
- @{{value[:key_id]}}
- end
- {% end %}
-
- {% if value[:presence] %}
- @{{value[:key_id]}}_present : Bool = false
-
- def {{value[:key_id]}}_present?
- @{{value[:key_id]}}_present
- end
- {% end %}
- {% end %}
-
- def initialize(%pull : ::JSON::PullParser)
- {% for key, value in _properties_ %}
- %var{key.id} = nil
- %found{key.id} = false
- {% end %}
-
- %location = %pull.location
- begin
- %pull.read_begin_object
- rescue exc : ::JSON::ParseException
- raise ::JSON::MappingError.new(exc.message, self.class.to_s, nil, *%location, exc)
- end
- until %pull.kind.end_object?
- %key_location = %pull.location
- key = %pull.read_object_key
- case key
- {% for key, value in _properties_ %}
- when {{value[:key] || value[:key_id].stringify}}
- %found{key.id} = true
- begin
- %var{key.id} =
- {% if value[:nilable] || value[:default] != nil %} %pull.read_null_or { {% end %}
-
- {% if value[:root] %}
- %pull.on_key!({{value[:root]}}) do
- {% end %}
-
- {% if value[:converter] %}
- {{value[:converter]}}.from_json(%pull)
- {% elsif value[:type].is_a?(Path) || value[:type].is_a?(Generic) %}
- {{value[:type]}}.new(%pull)
- {% else %}
- ::Union({{value[:type]}}).new(%pull)
- {% end %}
-
- {% if value[:root] %}
- end
- {% end %}
-
- {% if value[:nilable] || value[:default] != nil %} } {% end %}
- rescue exc : ::JSON::ParseException
- raise ::JSON::MappingError.new(exc.message, self.class.to_s, {{value[:key] || value[:key_id].stringify}}, *%key_location, exc)
- end
- {% end %}
- else
- {% if strict %}
- raise ::JSON::MappingError.new("Unknown JSON attribute: #{key}", self.class.to_s, nil, *%key_location, nil)
- {% else %}
- %pull.skip
- {% end %}
- end
- end
- %pull.read_next
-
- {% for key, value in _properties_ %}
- {% unless value[:nilable] || value[:default] != nil %}
- if %var{key.id}.nil? && !%found{key.id} && !::Union({{value[:type]}}).nilable?
- raise ::JSON::MappingError.new("Missing JSON attribute: {{(value[:key] || value[:key_id]).id}}", self.class.to_s, nil, *%location, nil)
- end
- {% end %}
-
- {% if value[:nilable] %}
- {% if value[:default] != nil %}
- @{{value[:key_id]}} = %found{key.id} ? %var{key.id} : {{value[:default]}}
- {% else %}
- @{{value[:key_id]}} = %var{key.id}
- {% end %}
- {% elsif value[:default] != nil %}
- @{{value[:key_id]}} = %var{key.id}.nil? ? {{value[:default]}} : %var{key.id}
- {% else %}
- @{{value[:key_id]}} = (%var{key.id}).as({{value[:type]}})
- {% end %}
-
- {% if value[:presence] %}
- @{{value[:key_id]}}_present = %found{key.id}
- {% end %}
- {% end %}
- end
-
- def to_json(json : ::JSON::Builder)
- json.object do
- {% for key, value in _properties_ %}
- _{{value[:key_id]}} = @{{value[:key_id]}}
-
- {% unless value[:emit_null] %}
- unless _{{value[:key_id]}}.nil?
- {% end %}
-
- json.field({{value[:key] || value[:key_id].stringify}}) do
- {% if value[:root] %}
- {% if value[:emit_null] %}
- if _{{value[:key_id]}}.nil?
- nil.to_json(json)
- else
- {% end %}
-
- json.object do
- json.field({{value[:root]}}) do
- {% end %}
-
- {% if value[:converter] %}
- if _{{value[:key_id]}}
- {{ value[:converter] }}.to_json(_{{value[:key_id]}}, json)
- else
- nil.to_json(json)
- end
- {% else %}
- _{{value[:key_id]}}.to_json(json)
- {% end %}
-
- {% if value[:root] %}
- {% if value[:emit_null] %}
- end
- {% end %}
- end
- end
- {% end %}
- end
-
- {% unless value[:emit_null] %}
- end
- {% end %}
- {% end %}
- end
- end
- end
-
- # This is a convenience method to allow invoking `JSON.mapping`
- # with named arguments instead of with a hash/named-tuple literal.
- macro mapping(**_properties_)
- ::JSON.mapping({{_properties_}})
- end
-
- class MappingError < ParseException
- getter klass : String
- getter attribute : String?
-
- def initialize(message : String?, @klass : String, @attribute : String?, line_number : Int32, column_number : Int32, cause)
- message = String.build do |io|
- io << message
- io << "\n parsing "
- io << klass
- if attribute = @attribute
- io << '#' << attribute
- end
- end
- super(message, line_number, column_number, cause)
- if cause
- @line_number, @column_number = cause.location
- end
- end
- end
-end
diff --git a/lib/octokit/lib/webmock/.gitignore b/lib/octokit/lib/webmock/.gitignore
deleted file mode 100644
index 0d6aead..0000000
--- a/lib/octokit/lib/webmock/.gitignore
+++ /dev/null
@@ -1,3 +0,0 @@
-.deps/
-.crystal/
-.deps.lock
diff --git a/lib/octokit/lib/webmock/.travis.yml b/lib/octokit/lib/webmock/.travis.yml
deleted file mode 100644
index 31f20e1..0000000
--- a/lib/octokit/lib/webmock/.travis.yml
+++ /dev/null
@@ -1,7 +0,0 @@
-language: crystal
-crystal:
- - latest
- - nightly
-script:
- - crystal spec
- - crystal tool format --check
diff --git a/lib/octokit/lib/webmock/LICENSE b/lib/octokit/lib/webmock/LICENSE
deleted file mode 100644
index 434acd7..0000000
--- a/lib/octokit/lib/webmock/LICENSE
+++ /dev/null
@@ -1,21 +0,0 @@
-The MIT License (MIT)
-
-Copyright (c) 2015 Manas Technology Solutions
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
diff --git a/lib/octokit/lib/webmock/README.md b/lib/octokit/lib/webmock/README.md
deleted file mode 100644
index 287c1ce..0000000
--- a/lib/octokit/lib/webmock/README.md
+++ /dev/null
@@ -1,135 +0,0 @@
-# webmock.cr
-
-[![Build Status](https://travis-ci.org/manastech/webmock.cr.svg?branch=master)](https://travis-ci.org/manastech/webmock.cr)
-
-Library for stubbing `HTTP::Client` requests in [Crystal](http://crystal-lang.org/).
-
-Inspired by [webmock ruby gem](https://github.com/bblimke/webmock).
-
-## Installation
-
-Add it to `shards.yml`:
-
-```yaml
-development_dependencies:
- webmock:
- github: manastech/webmock.cr
- branch: master
-```
-
-## Usage
-
-```crystal
-require "webmock"
-```
-
-By requiring `webmock` unregistered `HTTP::Client` requests will raise an exception.
-If you still want to execute real requests, do this:
-
-```crystal
-WebMock.allow_net_connect = true
-```
-
-### Stub request based on uri only and with the default response
-
-```crystal
-WebMock.stub(:any, "www.example.com")
-
-response = HTTP::Client.get("http://www.example.com")
-response.body #=> ""
-response.status_code #=> 200
-```
-
-### Stub requests based on method, uri, body, headers and custom response
-
-```crystal
-WebMock.stub(:post, "www.example.com/foo").
- with(body: "abc", headers: {"Content-Type" => "text/plain"}).
- to_return(status: 500, body: "oops", headers: {"X-Error" => "true"})
-
-response = HTTP::Client.post("http://www.example.com/foo",
- body: "abc",
- headers: HTTP::Headers{"Content-Type" => "text/plain"})
-response.status_code #=> 500
-response.body #=> "oops"
-response.headers["X-Error"] #=> "true"
-
-# Executing the same request gives the same response
-response = HTTP::Client.post("http://www.example.com/foo",
- body: "abc",
- headers: HTTP::Headers{"Content-Type" => "text/plain"})
-response.body #=> "oops"
-```
-
-### Stub requests based on query string
-
-```crystal
-WebMock.stub(:get, "www.example.com").
- with(query: {"page" => "1", "count" => "10"})
-
-response = HTTP::Client.get("http://www.example.com?count=10&page=1")
-response.status_code #=> 200
-```
-
-### Stub requests and provide a block for the response
-
-Your block will be called and passed the `HTTP::Request`, allowing you to construct a response dynamically based upon the request.
-
-```crystal
-WebMock.stub(:post, "www.example.com/foo").to_return do |request|
- headers = HTTP::Headers.new.merge!({ "Content-length" => request.body.to_s.length })
- HTTP::Client::Response.new(418, body: request.body.to_s.reverse, headers: headers)
-end
-
-response = HTTP::Client.post("http://www.example.com/foo",
- body: "abc",
- headers: HTTP::Headers{"Content-Type" => "text/plain"})
-response.status_code #=> 418
-response.body #=> "cba"
-response.headers["Content-length"] #=> "3"
-
-response = HTTP::Client.post("http://www.example.com/foo",
- body: "olleh",
- headers: HTTP::Headers{"Content-Type" => "text/plain"})
-response.status_code #=> 418
-response.body #=> "hello"
-response.headers["Content-length"] #=> "5"
-```
-
-### Resetting
-
-```crystal
-WebMock.reset
-```
-
-This clears all stubs and sets `allow_net_connect` to `false`.
-
-To execute this automatically before each spec, you can do:
-
-```crystal
-Spec.before_each &->WebMock.reset
-```
-
-Or, for individual specs you can use `WebMock.wrap` and a block to make sure `WebMock` is reset at the end of a spec:
-
-```crystal
-WebMock.wrap do
- WebMock.stub(:get, "www.example.com").to_return(body: "Example")
-
- HTTP::Client.get("http://www.example.com").body #=> "Example"
-end
-
-HTTP::Client.get("http://www.example.com") # Raises WebMock::NetConnectNotAllowedError
-```
-
-## Todo
-
-Bring more features found in the [webmock ruby gem](https://github.com/bblimke/webmock).
-
-## Contributing
-
-1. Fork it ( https://github.com/manastech/webmock.cr/fork )
-2. Create your feature branch (git checkout -b my-new-feature)
-3. Commit your changes (git commit -am 'Add some feature')
-4. Push to the branch (git push origin my-new-feature)
-5. Create a new Pull Request
diff --git a/lib/octokit/lib/webmock/lib b/lib/octokit/lib/webmock/lib
deleted file mode 120000
index a96aa0e..0000000
--- a/lib/octokit/lib/webmock/lib
+++ /dev/null
@@ -1 +0,0 @@
-..
\ No newline at end of file
diff --git a/lib/octokit/lib/webmock/shard.yml b/lib/octokit/lib/webmock/shard.yml
deleted file mode 100644
index 462b940..0000000
--- a/lib/octokit/lib/webmock/shard.yml
+++ /dev/null
@@ -1,8 +0,0 @@
-name: webmock
-version: 0.14.0
-
-crystal: ">= 0.36.0, < 2.0.0"
-
-authors:
- - Ary Borenszweig
-
diff --git a/lib/octokit/lib/webmock/src/webmock.cr b/lib/octokit/lib/webmock/src/webmock.cr
deleted file mode 100644
index ce5210d..0000000
--- a/lib/octokit/lib/webmock/src/webmock.cr
+++ /dev/null
@@ -1,48 +0,0 @@
-require "./**"
-
-module WebMock
- extend self
-
- @@allow_net_connect = false
- @@registry = StubRegistry.new
- @@callbacks = CallbackRegistry.new
-
- def wrap
- yield
- ensure
- reset
- end
-
- def stub(method, uri)
- @@registry.stub(method, uri)
- end
-
- def reset
- @@registry.reset
- @@allow_net_connect = false
- end
-
- def allow_net_connect=(@@allow_net_connect)
- end
-
- def allows_net_connect?
- @@allow_net_connect
- end
-
- def find_stub(request : HTTP::Request)
- @@registry.find_stub(request)
- end
-
- def callbacks
- @@callbacks
- end
-
- # :nodoc:
- def self.body(request : HTTP::Request)
- body = request.body.try(&.gets_to_end)
- if body
- request.body = IO::Memory.new(body)
- end
- body
- end
-end
diff --git a/lib/octokit/lib/webmock/src/webmock/callback_registry.cr b/lib/octokit/lib/webmock/src/webmock/callback_registry.cr
deleted file mode 100644
index bf0a41e..0000000
--- a/lib/octokit/lib/webmock/src/webmock/callback_registry.cr
+++ /dev/null
@@ -1,26 +0,0 @@
-class WebMock::CallbackRegistry
- getter callbacks
-
- def initialize
- @callbacks = Hash(Symbol, (HTTP::Request, HTTP::Client::Response -> Nil)).new
- end
-
- def reset
- @callbacks.clear
- end
-
- def add
- with self yield
- self
- end
-
- def after_live_request(&block : (HTTP::Request, HTTP::Client::Response) ->)
- @callbacks[:after_live_request] = block
- end
-
- def call(name, *args)
- if !@callbacks.empty?
- @callbacks[name].try &.call(*args)
- end
- end
-end
diff --git a/lib/octokit/lib/webmock/src/webmock/core_ext.cr b/lib/octokit/lib/webmock/src/webmock/core_ext.cr
deleted file mode 100644
index 11436ba..0000000
--- a/lib/octokit/lib/webmock/src/webmock/core_ext.cr
+++ /dev/null
@@ -1,45 +0,0 @@
-require "http/client"
-
-class HTTP::Request
- property scheme : String = "http"
-
- def full_uri
- "#{scheme}://#{headers["Host"]?}#{resource}"
- end
-end
-
-class HTTP::Client
- private def exec_internal(request : HTTP::Request)
- exec_internal(request, &.itself).tap do |response|
- response.consume_body_io
- response.headers.delete("Transfer-encoding")
- response.headers["Content-length"] = response.body.bytesize.to_s
- end
- end
-
- private def exec_internal(request : HTTP::Request, &block : Response -> T) : T forall T
- request.scheme = "https" if tls?
- request.headers["Host"] = host_header unless request.headers.has_key?("Host")
- run_before_request_callbacks(request)
-
- stub = WebMock.find_stub(request)
- return yield(stub.exec(request)) if stub
- raise WebMock::NetConnectNotAllowedError.new(request) unless WebMock.allows_net_connect?
-
- request.headers["User-agent"] ||= "Crystal"
- request.to_io(io)
- io.flush
-
- result = nil
-
- HTTP::Client::Response.from_io(io, request.ignore_body?) do |response|
- result = yield(response)
- close unless response.keep_alive?
- WebMock.callbacks.call(:after_live_request, request, response)
- end
-
- raise "Unexpected end of response" unless result.is_a?(T)
-
- result
- end
-end
diff --git a/lib/octokit/lib/webmock/src/webmock/net_connect_not_allowed_error.cr b/lib/octokit/lib/webmock/src/webmock/net_connect_not_allowed_error.cr
deleted file mode 100644
index 2036dab..0000000
--- a/lib/octokit/lib/webmock/src/webmock/net_connect_not_allowed_error.cr
+++ /dev/null
@@ -1,82 +0,0 @@
-class WebMock::NetConnectNotAllowedError < Exception
- def initialize(request : HTTP::Request)
- super(help_message(request))
- end
-
- private def help_message(request)
- String.build do |io|
- io << "Real HTTP connections are disabled. "
- io << "Unregistered request: "
- signature(request, io)
- io << "\n\n"
- io << "You can stub this request with the following snippet:"
- io << "\n\n"
- stubbing_instructions(request, io)
- io << "\n\n"
- end
- end
-
- private def signature(request, io)
- io << request.method << " "
- request_uri_to_s request, io
- if request.body
- io << " with body "
- WebMock.body(request).inspect(io)
- end
- io << " with headers "
- headers_to_s request.headers, io
- end
-
- private def stubbing_instructions(request, io)
- # For the instructions we remove these two headers because they are automatically
- # included in HTTP::Client requests
- headers = request.headers.dup
- headers.delete("Content-Length")
- headers.delete("Connection")
- headers.delete("Host")
-
- io << "WebMock.stub(:" << request.method.downcase << ", "
- io << '"'
- request_uri_to_s request, io
- io << %[").]
- io.puts
-
- if request.body && !headers.empty?
- io << " with("
-
- if request.body
- io << "body: "
- WebMock.body(request).inspect(io)
- io << ", " unless headers.empty?
- end
-
- unless headers.empty?
- io << "headers: "
- headers_to_s headers, io
- end
- io << ")."
- io.puts
- end
-
- io << %[ to_return(body: "")]
- end
-
- private def request_uri_to_s(request, io)
- io << request.scheme
- io << "://"
- io << request.headers["Host"]
- io << request.path
- io << "?#{request.query}" if request.query
- end
-
- private def headers_to_s(headers, io)
- io << "{"
- headers.each_with_index do |(key, values), index|
- io << ", " if index > 0
- key.inspect(io)
- io << " => "
- values.join(", ").inspect(io)
- end
- io << "}"
- end
-end
diff --git a/lib/octokit/lib/webmock/src/webmock/stub.cr b/lib/octokit/lib/webmock/src/webmock/stub.cr
deleted file mode 100644
index acdd3d7..0000000
--- a/lib/octokit/lib/webmock/src/webmock/stub.cr
+++ /dev/null
@@ -1,135 +0,0 @@
-class WebMock::Stub
- @method : String
- @uri : URI | Regex
- @expected_headers : HTTP::Headers?
- @calls = 0
- @body_io : IO?
-
- def initialize(method : Symbol | String, uri : String | Regex)
- @method = method.to_s.upcase
- @uri = uri.is_a?(String) ? parse_uri(uri) : uri
-
- # For to_return
- @status = 200
- @body = ""
- @headers = HTTP::Headers{"Content-length" => "0", "Connection" => "close"}
-
- @block = Proc(HTTP::Request, HTTP::Client::Response).new do |_request|
- HTTP::Client::Response.new(@status, body: @body, headers: @headers, body_io: @body_io)
- end
- end
-
- def with(query : Hash(String, String)? = nil, body : String? = nil, headers = nil)
- @expected_query = query
- @expected_body = body
- @expected_headers = HTTP::Headers.new.merge!(headers) if headers
- self
- end
-
- def to_return(body : String? = "", status = 200, headers = nil)
- @body = body
- @body_io = nil
- @status = status
- @headers.delete("Transfer-encoding")
- @headers["Content-length"] = body.size.to_s
- @headers.merge!(headers) if headers
- self
- end
-
- def to_return(body_io : IO, status = 200, headers = nil)
- @body = nil
- @body_io = body_io
- @status = status
- @headers.delete("Content-length")
- @headers["Transfer-encoding"] = "chunked"
- @headers.merge!(headers) if headers
- self
- end
-
- def to_return(&block : HTTP::Request -> HTTP::Client::Response)
- @block = block
- self
- end
-
- def matches?(request)
- matches_method?(request) &&
- matches_uri?(request) &&
- matches_body?(request) &&
- matches_headers?(request)
- end
-
- def matches_uri?(request)
- case uri = @uri
- when URI
- matches_scheme?(request, uri) &&
- matches_host?(request, uri) &&
- matches_path?(request, uri)
- when Regex
- uri =~ request.full_uri
- end
- end
-
- def matches_method?(request)
- return true if @method == "ANY"
-
- @method == request.method
- end
-
- def matches_scheme?(request, uri)
- uri.scheme == request.scheme
- end
-
- def matches_host?(request, uri)
- host_uri = parse_uri(request.headers["Host"])
- host_uri.host == uri.host && host_uri.port == uri.port
- end
-
- def matches_path?(request, uri)
- uri_path = uri.path.presence || "/"
- uri_query = uri.query
-
- request_uri = parse_uri(request.resource)
- request_path = request_uri.path.presence || "/"
- request_query = request_uri.query
-
- request_query = HTTP::Params.parse(request_query || "")
- uri_query = HTTP::Params.parse(uri_query || "")
-
- @expected_query.try &.each do |key, value|
- uri_query.add(key.to_s, value.to_s)
- end
- request_path == uri_path && request_query == uri_query
- end
-
- def matches_body?(request)
- @expected_body ? @expected_body == WebMock.body(request) : true
- end
-
- def matches_headers?(request)
- expected_headers = @expected_headers
- return true unless expected_headers
-
- expected_headers.each do |key, _|
- request_value = request.headers[key]?
- expected_value = expected_headers[key]?
- return false unless request_value.to_s == expected_value.to_s
- end
-
- true
- end
-
- def exec(request)
- @calls += 1
- @block.call(request)
- end
-
- def calls
- @calls
- end
-
- private def parse_uri(uri_string)
- uri = URI.parse(uri_string)
- uri = URI.parse("http://#{uri_string}") unless uri.host
- uri
- end
-end
diff --git a/lib/octokit/lib/webmock/src/webmock/stub_registry.cr b/lib/octokit/lib/webmock/src/webmock/stub_registry.cr
deleted file mode 100644
index 789660c..0000000
--- a/lib/octokit/lib/webmock/src/webmock/stub_registry.cr
+++ /dev/null
@@ -1,19 +0,0 @@
-struct WebMock::StubRegistry
- def initialize
- @stubs = [] of Stub
- end
-
- def stub(method, uri)
- stub = Stub.new(method, uri)
- @stubs << stub
- stub
- end
-
- def reset
- @stubs.clear
- end
-
- def find_stub(request)
- @stubs.find &.matches?(request)
- end
-end
diff --git a/lib/octokit/script/acceptance b/lib/octokit/script/acceptance
deleted file mode 100755
index 35dc63c..0000000
--- a/lib/octokit/script/acceptance
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/bin/bash
-
-# COLORS
-OFF='\033[0m'
-RED='\033[0;31m'
-GREEN='\033[0;32m'
-BLUE='\033[0;34m'
-PURPLE='\033[0;35m'
-
-# set the working directory to the root of the project
-DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && cd .. && pwd )"
-
-crystal run spec/acceptance/acceptance.cr
diff --git a/lib/octokit/script/all b/lib/octokit/script/all
deleted file mode 100755
index 42ed4b8..0000000
--- a/lib/octokit/script/all
+++ /dev/null
@@ -1,23 +0,0 @@
-#!/bin/bash
-
-# COLORS
-OFF='\033[0m'
-RED='\033[0;31m'
-GREEN='\033[0;32m'
-BLUE='\033[0;34m'
-PURPLE='\033[0;35m'
-
-# runs all formatting scripts and tests at once
-
-# set the working directory to the root of the project
-DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && cd .. && pwd )"
-
-set -e
-
-script/format
-echo ""
-
-script/lint --fix
-echo ""
-
-script/test
diff --git a/lib/octokit/script/bootstrap b/lib/octokit/script/bootstrap
deleted file mode 100755
index 996ce87..0000000
--- a/lib/octokit/script/bootstrap
+++ /dev/null
@@ -1,70 +0,0 @@
-#!/bin/bash
-
-set -e
-
-# COLORS
-OFF='\033[0m'
-RED='\033[0;31m'
-GREEN='\033[0;32m'
-BLUE='\033[0;34m'
-PURPLE='\033[0;35m'
-YELLOW='\033[0;33m'
-
-# set the working directory to the root of the project
-DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && cd .. && pwd )"
-
-# check to ensure both crystal and shards are installed
-if ! [ -x "$(command -v crystal)" ]; then
- echo -e "โ ${RED}Error${OFF}: crystal is not installed"
- echo "Please install crystal via crenv -> https://github.com/crenv/crenv"
- exit 1
-fi
-
-if ! [ -x "$(command -v shards)" ]; then
- echo -e "โ ${RED}Error${OFF}: shards is not installed"
- echo "Please install crystal (comes with shards) via crenv -> https://github.com/crenv/crenv"
- exit 1
-fi
-
-compatability_warning=""
-
-# Get OS info
-if [[ "$OSTYPE" == "linux-gnu"* ]]; then
- os="linux"
-elif [[ "$OSTYPE" == "darwin"* ]]; then
- os="mac"
-
- # if CRYSTAL_OPTS is not set to `--link-flags=-Wl,-ld_classic` then print a warning
- if [[ -z "$CRYSTAL_OPTS" || "$CRYSTAL_OPTS" != "--link-flags=-Wl,-ld_classic" ]]; then
- compatability_warning="โ ๏ธ ${YELLOW}Warning${OFF}: crystal may have issues on macOS due to -> https://github.com/crystal-lang/crystal/issues/13846. If you have issues, please consider exporting the following env vars in your terminal -> https://github.com/GrantBirki/dotfiles/blob/d57db3e4167aa5ae7766c5e544f38ead111f040c/dotfiles/.bashrc#L199"
- fi
-
-elif [[ "$OSTYPE" == "cygwin" ]]; then
- os="cygwin"
- compatability_warning="โ ๏ธ ${YELLOW}Warning${OFF}: cygwin is not officially supported. Please use WSL2 or a Linux VM"
-elif [[ "$OSTYPE" == "msys" ]]; then
- os="msys"
- compatability_warning="โ ๏ธ ${YELLOW}Warning${OFF}: msys is not officially supported. Please use WSL2 or a Linux VM"
-elif [[ "$OSTYPE" == "win32" ]]; then
- os="win"
- compatability_warning="โ ๏ธ ${YELLOW}Warning${OFF}: Windows is not officially supported. Please use WSL2 or a Linux VM"
-elif [[ "$OSTYPE" == "freebsd"* ]]; then
- os="freebsd"
- compatability_warning="โ ๏ธ ${YELLOW}Warning${OFF}: FreeBSD is not officially supported. It may work but it is not tested. Please consider using a debian based Linux distro"
-else
- os="unknown"
- compatability_warning="โ ๏ธ ${YELLOW}Warning${OFF}: Your OS is not officially supported. It may work but it is not tested. Please consider using a debian based Linux distro"
-fi
-
-# print the warning if it isn't an empty string and SUPPRESS_BOOTSTRAP_WARNINGS is not true
-if [[ ! -z "$compatability_warning" && "$SUPPRESS_BOOTSTRAP_WARNINGS" != "true" ]]; then
- echo -e "$compatability_warning"
- echo ""
- echo -e "You can set ${PURPLE}SUPPRESS_BOOTSTRAP_WARNINGS=true${OFF} in your environment to suppress this warning"
-fi
-
-script/preinstall
-
-SHARDS_CACHE_PATH="$DIR/.cache/shards" shards install --frozen $@
-
-script/postinstall
diff --git a/lib/octokit/script/format b/lib/octokit/script/format
deleted file mode 100755
index f662157..0000000
--- a/lib/octokit/script/format
+++ /dev/null
@@ -1,19 +0,0 @@
-#!/bin/bash
-
-set -e
-
-# COLORS
-OFF='\033[0m'
-RED='\033[0;31m'
-GREEN='\033[0;32m'
-BLUE='\033[0;34m'
-PURPLE='\033[0;35m'
-
-# set the working directory to the root of the project
-DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && cd .. && pwd )"
-
-echo -e "๐งน ${BLUE}formatting ${PURPLE}crystal${BLUE} files...${OFF}"
-
-crystal tool format $@
-
-echo -e "โ
${GREEN}formatting complete!${OFF}"
diff --git a/lib/octokit/script/lint b/lib/octokit/script/lint
deleted file mode 100755
index 415c08f..0000000
--- a/lib/octokit/script/lint
+++ /dev/null
@@ -1,19 +0,0 @@
-#!/bin/bash
-
-set -e
-
-# COLORS
-OFF='\033[0m'
-RED='\033[0;31m'
-GREEN='\033[0;32m'
-BLUE='\033[0;34m'
-PURPLE='\033[0;35m'
-
-# set the working directory to the root of the project
-DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && cd .. && pwd )"
-
-echo -e "๐๏ธ ${BLUE}linting ${PURPLE}crystal${BLUE} files..."
-
-"$DIR/bin/ameba" $@
-
-echo -e "โ
${GREEN}linting complete!${OFF}"
diff --git a/lib/octokit/script/postinstall b/lib/octokit/script/postinstall
deleted file mode 100755
index d807d89..0000000
--- a/lib/octokit/script/postinstall
+++ /dev/null
@@ -1,29 +0,0 @@
-#!/bin/bash
-
-# set the working directory to the root of the project
-DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && cd .. && pwd )"
-
-mkdir -p "$DIR/bin"
-
-# ensure the ameba binary is built and available in the bin directory
-AMEBA_UP_TO_DATE=false
-# first, check the version of the ameba binary in the lock file
-AMEBA_VERSION=$(shards list | grep ameba | awk '{print $3}' | tr -d '()')
-
-# if the bin/ameba binary exists, check if it is the correct version
-if [ -f "$DIR/bin/ameba" ]; then
- CURRENT_VERSION=$("$DIR/bin/ameba" --version)
- if [ "$AMEBA_VERSION" = "$CURRENT_VERSION" ]; then
- AMEBA_UP_TO_DATE=true
- else
- echo "ameba binary is not up to date"
- echo "ameba version (./bin/ameba): $CURRENT_VERSION"
- echo "ameba version (shards list): $AMEBA_VERSION"
- AMEBA_UP_TO_DATE=false
- fi
-fi
-
-if [ "$AMEBA_UP_TO_DATE" = false ]; then
- echo "building ameba binary"
- cd "$DIR/lib/ameba" && shards build && cp bin/ameba "$DIR/bin/ameba" && cd "$DIR"
-fi
diff --git a/lib/octokit/script/preinstall b/lib/octokit/script/preinstall
deleted file mode 100755
index 46f59c0..0000000
--- a/lib/octokit/script/preinstall
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/bin/bash
-
-set -e
-
-# set the working directory to the root of the project
-DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && cd .. && pwd )"
-
-mkdir -p "$DIR/bin"
diff --git a/lib/octokit/script/release b/lib/octokit/script/release
deleted file mode 100755
index edeccab..0000000
--- a/lib/octokit/script/release
+++ /dev/null
@@ -1,31 +0,0 @@
-#!/bin/bash
-
-# Usage:
-# script/release
-
-# COLORS
-OFF='\033[0m'
-RED='\033[0;31m'
-GREEN='\033[0;32m'
-BLUE='\033[0;34m'
-
-latest_tag=$(git describe --tags $(git rev-list --tags --max-count=1))
-echo -e "The latest release tag is: ${BLUE}${latest_tag}${OFF}"
-read -p 'New Release Tag (vX.X.X format): ' new_tag
-
-tag_regex='^v[0-9]+\.[0-9]+\.[0-9]+$'
-echo "$new_tag" | grep -E "$tag_regex"
-
-if [[ $? -ne 0 ]]; then
- echo -e "${RED}ERROR${OFF} - Tag: $new_tag is not valid. Please use vX.X.X format."
- exit 1
-fi
-
-git tag -a $new_tag -m "$new_tag Release"
-
-echo -e "${GREEN}OK${OFF} - Tagged: $new_tag"
-
-git push --tags
-
-echo -e "${GREEN}OK${OFF} - Tags pushed to remote!"
-echo -e "${GREEN}DONE${OFF}"
diff --git a/lib/octokit/script/server b/lib/octokit/script/server
deleted file mode 100755
index aee5d39..0000000
--- a/lib/octokit/script/server
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/bin/bash
-
-set -e
-
-# set the working directory to the root of the project
-DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && cd .. && pwd )"
-
-SHARDS_CACHE_PATH="$DIR/.cache/shards" shards run --release --debug --error-trace
diff --git a/lib/octokit/script/test b/lib/octokit/script/test
deleted file mode 100755
index a9b4385..0000000
--- a/lib/octokit/script/test
+++ /dev/null
@@ -1,19 +0,0 @@
-#!/bin/bash
-
-set -e
-
-# COLORS
-OFF='\033[0m'
-RED='\033[0;31m'
-GREEN='\033[0;32m'
-BLUE='\033[0;34m'
-PURPLE='\033[0;35m'
-
-# set the working directory to the root of the project
-DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && cd .. && pwd )"
-
-echo -e "๐งช ${BLUE}running unit tests...${OFF}"
-
-crystal spec
-
-echo -e "โ
${GREEN}tests complete!${OFF}"
diff --git a/lib/octokit/script/update b/lib/octokit/script/update
deleted file mode 100755
index f344f86..0000000
--- a/lib/octokit/script/update
+++ /dev/null
@@ -1,23 +0,0 @@
-#!/bin/bash
-
-set -e
-
-# COLORS
-OFF='\033[0m'
-RED='\033[0;31m'
-GREEN='\033[0;32m'
-BLUE='\033[0;34m'
-PURPLE='\033[0;35m'
-
-# set the working directory to the root of the project
-DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && cd .. && pwd )"
-
-echo -e "๐ฆ ${BLUE}Running ${PURPLE}shards update${BLUE} to update all dependencies${OFF}"
-
-script/preinstall
-
-SHARDS_CACHE_PATH="$DIR/.cache/shards" shards update --skip-postinstall --skip-executables $@
-
-script/postinstall
-
-echo -e "โ
${GREEN}All dependencies have been updated!${OFF}"
diff --git a/lib/octokit/shard.lock b/lib/octokit/shard.lock
deleted file mode 100644
index f84400f..0000000
--- a/lib/octokit/shard.lock
+++ /dev/null
@@ -1,18 +0,0 @@
-version: 2.0
-shards:
- ameba:
- git: https://github.com/crystal-ameba/ameba.git
- version: 1.6.1
-
- halite:
- git: https://github.com/icyleaf/halite.git
- version: 0.12.0
-
- json_mapping:
- git: https://github.com/crystal-lang/json_mapping.cr.git
- version: 0.1.1
-
- webmock:
- git: https://github.com/manastech/webmock.cr.git
- version: 0.14.0
-
diff --git a/lib/octokit/shard.yml b/lib/octokit/shard.yml
deleted file mode 100644
index d5cae59..0000000
--- a/lib/octokit/shard.yml
+++ /dev/null
@@ -1,25 +0,0 @@
-name: octokit
-version: 0.3.0
-
-authors:
- - Grant Birkinbine
- - Chris Watson
-
-crystal: ">= 1.13.1"
-
-license: MIT
-
-dependencies:
- json_mapping:
- github: crystal-lang/json_mapping.cr
- version: 0.1.1
- halite:
- github: icyleaf/halite
- version: 0.12.0
-development_dependencies:
- webmock:
- github: manastech/webmock.cr
- version: 0.14.0
- ameba:
- github: crystal-ameba/ameba
- version: ~> 1.6.1
diff --git a/lib/octokit/src/octokit.cr b/lib/octokit/src/octokit.cr
deleted file mode 100644
index bbf868f..0000000
--- a/lib/octokit/src/octokit.cr
+++ /dev/null
@@ -1,47 +0,0 @@
-require "./octokit/core_ext/*"
-require "./octokit/macros"
-require "./octokit/helpers"
-require "./octokit/default"
-require "./octokit/client"
-require "./octokit/enterprise_admin_client"
-require "./octokit/enterprise_management_console_client"
-
-# Crystal toolkit for the GitHub API.
-#
-# **Note:** All examples contained herein assume that `@client` is an instantiated
-# `Octokit::Client` with a valid user configured.
-module Octokit
- # @@enterprise_admin_client : Octokit::EnterpriseAdminClient? = nil
-
- # @@enterprise_management_console_client : Octokit::EnterpriseManagementConsoleClient? = nil
-
- # API client based on configuration options in `Configurable`
- def self.client(
- login = nil,
- password = nil,
- *,
- access_token = nil,
- bearer_token = nil,
- client_id = nil,
- client_secret = nil
- )
- Octokit::Client.new(
- login,
- password,
- access_token,
- bearer_token,
- client_id,
- client_secret
- )
- end
-
- # EnterpriseAdminClient client based on configuration options in `Configurable`
- def self.enterprise_admin_client
- raise "not implemented!"
- end
-
- # EnterpriseManagementConsoleClient client based on configuration options in `Configurable`
- def self.enterprise_management_console_client
- raise "not implemented!"
- end
-end
diff --git a/lib/octokit/src/octokit/arguments.cr b/lib/octokit/src/octokit/arguments.cr
deleted file mode 100644
index e69de29..0000000
diff --git a/lib/octokit/src/octokit/authentication.cr b/lib/octokit/src/octokit/authentication.cr
deleted file mode 100644
index 873e036..0000000
--- a/lib/octokit/src/octokit/authentication.cr
+++ /dev/null
@@ -1,74 +0,0 @@
-module Octokit
- # Authentication methods for `Octokit::Client`
- module Authentication
- # Indicates if the client was supplied Basic Auth
- # username and password
- #
- # **See Also:**
- # - [https://developer.github.com/v3/#authentication](https://developer.github.com/v3/#authentication)
- def basic_authenticated?
- !!(@login && @password)
- end
-
- # Indicates if the client was supplied an OAuth
- # access token
- #
- # **See Also:**
- # - [https://developer.github.com/v3/#authentication](https://developer.github.com/v3/#authentication)
- def token_authenticated?
- !!@access_token
- end
-
- # Indicates if the client was supplied a bearer token
- #
- # **See Also:**
- # - [https://developer.github.com/early-access/integrations/authentication/#as-an-integration](https://developer.github.com/early-access/integrations/authentication/#as-an-integration)
- def bearer_authenticated?
- !!@bearer_token
- end
-
- # Indicates if the client was supplied an OAuth
- # access token or Basic Auth username and password
- #
- # **See Also:**
- # - [https://developer.github.com/v3/#authentication](https://developer.github.com/v3/#authentication)
- def user_authenticated?
- basic_authenticated? || token_authenticated?
- end
-
- # Indicates if the client has OAuth Application
- # client_id and secret credentials to make anonymous
- # requests at a higher rate limit
- #
- # **See Also:**
- # - [https://developer.github.com/v3/#unauthenticated-rate-limited-requests](https://developer.github.com/v3/#unauthenticated-rate-limited-requests)
- def application_authenticated?
- !!application_authentication
- end
-
- private def application_authentication
- if @client_id && @client_secret
- {"client_id" => @client_id, "client_secret" => @client_secret}
- end
- end
-
- # def login_from_netrc
- # return unless netrc?
-
- # require 'netrc'
- # info = Netrc.read netrc_file
- # netrc_host = URI.parse(api_endpoint).host
- # creds = info[netrc_host]
- # if creds.nil?
- # # creds will be nil if there is no netrc for this end point
- # octokit_warn "Error loading credentials from netrc file for #{api_endpoint}"
- # else
- # creds = creds.to_a
- # self.login = creds.shift
- # self.password = creds.shift
- # end
- # rescue LoadError
- # octokit_warn "Please install netrc gem for .netrc support"
- # end
- end
-end
diff --git a/lib/octokit/src/octokit/client.cr b/lib/octokit/src/octokit/client.cr
deleted file mode 100644
index ce68c14..0000000
--- a/lib/octokit/src/octokit/client.cr
+++ /dev/null
@@ -1,244 +0,0 @@
-require "./models/*"
-require "./connection"
-require "./warnable"
-require "./arguments"
-require "./configurable"
-require "./authentication"
-require "./rate_limit"
-require "./preview"
-require "./client/apps"
-require "./client/authorizations"
-require "./client/checks"
-require "./client/commits"
-require "./client/commit_comments"
-require "./client/community_profile"
-require "./client/contents"
-require "./client/downloads"
-require "./client/deployments"
-require "./client/emojis"
-require "./client/events"
-require "./client/feeds"
-require "./client/gists"
-require "./client/gitignore"
-require "./client/hooks"
-require "./client/issues"
-require "./client/labels"
-require "./client/legacy_search"
-require "./client/licenses"
-require "./client/meta"
-require "./client/markdown"
-require "./client/marketplace"
-require "./client/milestones"
-require "./client/notifications"
-require "./client/objects"
-require "./client/organizations"
-require "./client/pages"
-require "./client/projects"
-require "./client/pub_sub_hubbub"
-require "./client/pull_requests"
-require "./client/rate_limit"
-require "./client/reactions"
-require "./client/refs"
-require "./client/releases"
-require "./client/repositories"
-require "./client/repository_invitations"
-require "./client/reviews"
-require "./client/say"
-require "./client/search"
-require "./client/service_status"
-require "./client/source_import"
-require "./client/stats"
-require "./client/statuses"
-require "./client/traffic"
-require "./client/users"
-
-module Octokit
- # User client for interacting with the GitHub API.
- #
- # The `Client` class is your main entrypoint into the GitHub user API. If
- # you want to access the enterprise admin or enterprise management APIs,
- # see `EnterpriseAdminClient` and `EnterpriseManagementClient`
- # respectively.
- #
- # **Configuration:**
- # Configuration options for `Client` are stored in `Configurable` and include:
- # - access_token : `String`
- # - auto_paginate : `Bool`
- # - bearer_token : `String`
- # - client_id : `String`
- # - client_secret : `String`
- # - default_media_type : `String`
- # - connection_options : `Halite::Options`
- # - middleware : `Array(Halite::Feature)`
- # - per_page : `Int32`
- # - proxy : `String`
- # - ssl_verify_mode : `Int32`
- # - user_agent : `String`
- #
- # The following items are setters only:
- # - api_endpoint : `String`
- # - login : `String`
- # - password : `String`
- # - web_endpoint : `String`
- #
- # Defaults for these are stored in `Default`. Most can be set using
- # environment variables.
- #
- # **Examples:**
- #
- # With standard auth:
- # ```
- # @client = Octokit::Client.new("monalisa", "PASSWORD")
- # ```
- #
- # With access token:
- # ```
- # @client = Octokit::Client.new("monalisa", access_token: "ACCESS_TOKEN")
- # ```
- #
- # With bearer token:
- # ```
- # @client = Octokit::Client.new("monalisa", bearer_token: "BEARER_TOKEN")
- # ```
- class Client
- include Octokit::Authentication
- include Octokit::Configurable
- include Octokit::Connection
- include Octokit::Preview
- include Octokit::Warnable
- include Octokit::Client::Authorizations
- include Octokit::Client::Issues
- include Octokit::Client::Markdown
- include Octokit::Client::PubSubHubbub
- include Octokit::Client::PullRequests
- include Octokit::Client::Users
- include Octokit::Client::RateLimit
- include Octokit::Client::Repositories
- include Octokit::Client::Organizations
- include Octokit::Client::Releases
- include Octokit::Client::Search
- include Octokit::Client::Statuses
- include Octokit::Client::Say
- include Octokit::Client::Deployments
-
- CONVENIENCE_HEADERS = Set{"accept", "content_type"}
-
- # Create a new Client instance.
- #
- # **Example:**
- # ```
- # cli = Octokit::Client.new("monalisa", "MY_PASSWORD")
- # pp cli.user # Show information about the logged in user
- # ```
- def initialize(
- @login : String? = nil,
- @password : String? = nil,
- @access_token : String? = nil,
- @bearer_token : String? = nil,
- @client_id : String? = nil,
- @client_secret : String? = nil
- )
- end
-
- # Create a new Client instance yielding a block.
- #
- # **Example:**
- # ```
- # Octokit::Client.new("monalisa", "MY_PASSWORD") do |cli|
- # pp cli.user # Show information about the logged in user
- # end
- # ```
- def initialize(
- @login : String? = nil,
- @password : String? = nil,
- @access_token : String? = nil,
- @bearer_token : String? = nil,
- @client_id : String? = nil,
- @client_secret : String? = nil,
- &
- )
- yield self
- end
-
- # Text representation of the client, masking tokens and passwords
- def inspect
- inspected = super
-
- # mask password
- inspected = inspected.gsub @password.to_s, "*******" if @password
- # inspected = inspected.gsub @management_console_password, "*******" if @management_console_password
- inspected = inspected.gsub @bearer_token.to_s, "********" if @bearer_token
-
- # Only show last 4 of token, secret
- inspected = inspected.gsub @access_token.to_s, "#{"*"*36}#{@access_token.to_s[36..-1]}" if @access_token
- inspected = inspected.gsub @client_secret.to_s, "#{"*"*36}#{@client_secret.to_s[36..-1]}" if @client_secret
-
- inspected
- end
-
- def as_app(key = @client_id, secret = @client_secret, &)
- if !key || !secret
- raise Error::ApplicationCredentialsRequired.new("client_id and client_secret required")
- end
-
- app_client = self.dup
- app_client.client_id = app_client.client_secret = nil
- app_client.login = key
- app_client.password = secret
-
- yield app_client
- end
-
- # Set username for authentication
- def login=(value : String)
- reset_agent
- @login = value
- end
-
- # Set password for authentication
- def password=(value : String)
- reset_agent
- @password = value
- end
-
- # Set OAuth access token for authentication
- def access_token=(value : String)
- reset_agent
- @access_token = value
- end
-
- # Set Bearer Token for authentication
- def bearer_token=(value : String)
- reset_agent
- @bearer_token = value
- end
-
- # Set OAuth app client_id
- def client_id=(value : String)
- reset_agent
- @client_id = value
- end
-
- # Set OAuth app client_secret
- def client_secret=(value : String)
- reset_agent
- @client_secret = value
- end
-
- def ensure_basic_authenticated!
- unless !!@login && !!@password
- raise "Client not Basic authenticated"
- end
- end
-
- def ensure_token_authenticated!
- unless !!@access_token
- raise "Client not Token authenticated"
- end
- end
-
- def client_without_redirects(options = {} of String => String)
- raise "unimplemented method"
- end
- end
-end
diff --git a/lib/octokit/src/octokit/client/apps.cr b/lib/octokit/src/octokit/client/apps.cr
deleted file mode 100644
index e69de29..0000000
diff --git a/lib/octokit/src/octokit/client/authorizations.cr b/lib/octokit/src/octokit/client/authorizations.cr
deleted file mode 100644
index fbddef4..0000000
--- a/lib/octokit/src/octokit/client/authorizations.cr
+++ /dev/null
@@ -1,237 +0,0 @@
-require "../models/authorizations"
-
-module Octokit
- class Client
- # Methods for the Authorizations API
- #
- # **See Api:**
- # - [https://developer.github.com/v3/oauth_authorizations/#oauth-authorizations-api](https://developer.github.com/v3/oauth_authorizations/#oauth-authorizations-api)
- module Authorizations
- # :nodoc:
- alias Authorization = Models::Authorization
-
- # List the authenticated user's authorizations.
- #
- # API for users to manage their own tokens.
- # You can only access your own tokens, and only through
- # Basic Authentication.
- #
- # **See Also:**
- # - [https://developer.github.com/v3/oauth_authorizations/#list-your-authorizations](https://developer.github.com/v3/oauth_authorizations/#list-your-authorizations)
- #
- # **Example:**
- # ```
- # @client = Octokit.client("monalisa", "PASSWORD")
- # @client.authorizations
- # ```
- def authorizations(**options) : Connection::Paginator(Authorization)
- paginate Authorization, "authorizations", options: {json: options}
- end
-
- # Get a single authorization for the authenticated user.
- #
- # You can only access your own tokens, and only through
- # Basic Authentication.
- #
- # **See Also:**
- # - [https://developer.github.com/v3/oauth_authorizations/#get-a-single-authorization](https://developer.github.com/v3/oauth_authorizations/#get-a-single-authorization)
- #
- # **Example:**
- # ```
- # @client = Octokit.client("monalisa", "PASSWORD")
- # @client.authorization(999999)
- # ```
- def authorizations(number : Int32) : Authorization
- res = get "authorizations/#{number}"
- Authorization.from_json(res)
- end
-
- # Create an authorization for the authenticated user.
- #
- # You can only access your own tokens, and only through
- # Basic Authentication.
- #
- # **See Also:**
- # - [https://developer.github.com/v3/oauth/#scopes](https://developer.github.com/v3/oauth/#scopes)
- # - [https://developer.github.com/v3/oauth_authorizations/#create-a-new-authorization](https://developer.github.com/v3/oauth_authorizations/#create-a-new-authorization)
- # - [https://developer.github.com/v3/oauth_authorizations/#get-or-create-an-authorization-for-a-specific-app](https://developer.github.com/v3/oauth_authorizations/#get-or-create-an-authorization-for-a-specific-app)
- #
- # **Example:**
- # ```
- # @client = Octokit.client("monalisa", "PASSWORD")
- # @client.create_authorization(idempotent: true, client_id: "xxxx", client_secret: "yyyy", scopes: ["user"])
- # ```
- def create_authorization(
- *,
- client_id = nil,
- client_secret = nil,
- scopes = [] of String,
- note = nil,
- note_url = nil,
- idempotent = nil,
- fingerprint = nil
- ) : Authorization
- # Techincally we can omit scopes as GitHub has a default, however the
- # API will reject us if we send a POST request with an empty body.
- if idempotent
- raise ArgumentError.new("Client ID and Secret required for idempotent authorizations") unless client_id && client_secret
-
- # Don't include the client_id in the body or
- # this will result in a 422.
- json = {
- client_secret: client_secret,
- scopes: scopes,
- note: note,
- note_url: note_url,
- }
-
- if fingerprint
- res = put "authorizations/clients/#{client_id}/#{fingerprint}", {json: json}
- else
- res = put "authorizations/clients/#{client_id}", {json: json}
- end
- else
- json = {
- client_secret: client_secret,
- scopes: scopes,
- note: note,
- note_url: note_url,
- }
-
- res = post "authorizations", {json: json}
- end
-
- Authorization.from_json(res)
- end
-
- # Update an authorization for the authenticated user.
- #
- # You can only access your own tokens, and only through
- # Basic Authentication.
- #
- # **See Also:**
- # - [https://developer.github.com/v3/oauth_authorizations/#update-an-existing-authorization](https://developer.github.com/v3/oauth_authorizations/#update-an-existing-authorization)
- # - [https://developer.github.com/v3/oauth/#scopes](https://developer.github.com/v3/oauth/#scopes)
- #
- # **Example:**
- # ```
- # @client = Octokit.client("monalisa", "PASSWORD")
- # @client.update_authorization(999999, add_scopes: ["gist", "repo"], note: "Why not Zoidberg possibly?")
- # ```
- def update_authorization(number : Int32, **options) : Authorization
- json = options.merge({number: number})
- res = patch "authorizations/#{number}", {json: json}
- Authorization.from_json(res)
- end
-
- # Delete an authorization for the authenticated user.
- #
- # You can only access your own tokens, and only through
- # Basic Authentication.
- #
- # **See Also:**
- # - [https://developer.github.com/v3/oauth_authorizations/#delete-an-authorization](https://developer.github.com/v3/oauth_authorizations/#delete-an-authorization)
- #
- # **Example:**
- # ```
- # @client = Octokit.client("monalisa", "PASSWORD")
- # @client.delete_authorization(999999)
- # ```
- def delete_authorization(number : Int32) : Bool
- boolean_from_response :delete, "authorizations/#{number}"
- end
-
- # Check scopes for a token.
- #
- # **See Also:**
- # - [https://developer.github.com/v3/oauth/#scopes](https://developer.github.com/v3/oauth/#scopes)
- def scopes(token = @access_token, headers = nil) : Array(String)
- raise ArgumentError.new("Access token required") if token.nil?
-
- auth = {"Authorization": "token #{token}"}
- headers = headers ? headers.merge(auth) : auth
-
- get "user", {headers: headers}
- last_response = @last_response.not_nil!
- last_response.headers["X-OAuth-Scopes"]
- .to_s
- .split(',')
- .map(&.strip)
- .sort!
- end
-
- # Check if a token is valid.
- #
- # **See Also:**
- # - [https://developer.github.com/v3/oauth_authorizations/#check-an-authorization](https://developer.github.com/v3/oauth_authorizations/#check-an-authorization)
- #
- # **Example:**
- # ```
- # @client = Octokit.client(client_id: "abcdefg12345", client_secret: "secret")
- # @client.check_application_authorization("deadbeef1234567890deadbeef987654321")
- # ```
- def check_application_authorization(token, key = client_id) : Authorization
- as_app(key, secret) do |app_client|
- app_client.get "applications/#{client_id}/tokens/#{token}"
- end
- end
-
- # Reset a token.
- #
- # **See Also:**
- # - [https://developer.github.com/v3/oauth_authorizations/#reset-an-authorization](https://developer.github.com/v3/oauth_authorizations/#reset-an-authorization)
- #
- # **Example:**
- # ```
- # @client = Octokit.client(client_id: "abcdefg12345", client_secret: "secret")
- # @client.reset_application_authorization("deadbeef1234567890deadbeef987654321")
- # ```
- def reset_application_authorization(token, key = client_id) : Authorization
- as_app(key, secret) do |app_client|
- app_client.post "applications/#{client_id}/tokens/#{token}"
- end
- end
-
- # Revoke a token.
- #
- # **See Also:**
- # - [https://developer.github.com/v3/oauth_authorizations/#revoke-an-authorization-for-an-application](https://developer.github.com/v3/oauth_authorizations/#revoke-an-authorization-for-an-application)
- #
- # **Example:**
- # ```
- # @client = Octokit.client(client_id: "abcdefg12345", client_secret: "secret")
- # @client.revoke_application_authorization("deadbeef1234567890deadbeef987654321")
- # ```
- def revoke_application_authorization(token, key = client_id) : Authorization
- as_app(key, secret) do |app_client|
- app_client.delete "applications/#{client_id}/tokens/#{token}"
- app_client.last_response.status_code == 204
- end
- rescue Octokit::NotFound
- false
- end
-
- alias_method :revoke_application_authorization, :delete_application_authorization
-
- # Get the URL to authorize a user for an application via the web flow.
- #
- # **See Also:**
- # - [https://developer.github.com/v3/oauth/#web-application-flow](https://developer.github.com/v3/oauth/#web-application-flow)
- #
- # **Example:**
- # ```
- # @client.authorize_url("xxxx")
- # ```
- def authorize_url(app_id = client_id, **options) : String
- String.build do |authorize_url|
- authorize_url << (options[:endpoint]? || web_endpoint)
- authorize_url << "login/oauth/authorize?client_id=#{app_id}"
-
- options.to_h.each do |key, value|
- authorize_url << "{key}=#{URI.escape(value)}"
- end
- end
- end
- end
- end
-end
diff --git a/lib/octokit/src/octokit/client/checks.cr b/lib/octokit/src/octokit/client/checks.cr
deleted file mode 100644
index e69de29..0000000
diff --git a/lib/octokit/src/octokit/client/commit_comments.cr b/lib/octokit/src/octokit/client/commit_comments.cr
deleted file mode 100644
index e69de29..0000000
diff --git a/lib/octokit/src/octokit/client/commits.cr b/lib/octokit/src/octokit/client/commits.cr
deleted file mode 100644
index e69de29..0000000
diff --git a/lib/octokit/src/octokit/client/community_profile.cr b/lib/octokit/src/octokit/client/community_profile.cr
deleted file mode 100644
index e69de29..0000000
diff --git a/lib/octokit/src/octokit/client/contents.cr b/lib/octokit/src/octokit/client/contents.cr
deleted file mode 100644
index e69de29..0000000
diff --git a/lib/octokit/src/octokit/client/deployments.cr b/lib/octokit/src/octokit/client/deployments.cr
deleted file mode 100644
index 336a414..0000000
--- a/lib/octokit/src/octokit/client/deployments.cr
+++ /dev/null
@@ -1,230 +0,0 @@
-require "uri"
-require "../models/repos"
-require "../models/repo_deployments"
-
-module Octokit
- class Client
- # Methods for the Deployments API
- #
- # All "repo" params are constructed in the format of `/`
- #
- # **See Also:**
- # - [https://developer.github.com/v3/repos/commits/deployments/](https://developer.github.com/v3/repos/commits/deployments/)
-
- module Deployments
- # :nodoc:
- alias Repository = Models::Repository
-
- # :nodoc:
- VALID_STATES = %w[error failure inactive in_progress queued pending success]
-
- # Fetch a single deployment for a repository
- #
- # **See Also:**
- # - [https://developer.github.com/v3/repos/deployments/#get-a-single-deployment](https://developer.github.com/v3/repos/deployments/#get-a-single-deployment)
- #
- # **Examples:**
- #
- # Fetch a single deployment for a repository
- #
- # ```
- # Octokit.deployment("monsalisa/app", 123456)
- # ```
- def deployment(repo : String, deployment_id : Int64, **options)
- get("#{Repository.path(repo)}/deployments/#{deployment_id}", options)
- end
-
- # List deployments for a repository
- #
- # **See Also:**
- # - [https://developer.github.com/v3/repos/deployments/#list-deployments](https://developer.github.com/v3/repos/deployments/#list-deployments)
- #
- # **Examples:**
- # List deployments for a repository
- #
- # ```
- # Octokit.deployments("monalisa/app")
- # ```
- #
- # Filter deployments by environment:
- # ```
- # Octokit.deployments("monalisa/app", {"environment" => "production"})
- # ```
- # An alias method exists for `deployments` called `list_deployments` which can be used interchangeably
- def deployments(repo : String, params : Hash(String, String) = {} of String => String, **options)
- query_string = params.map { |k, v| "#{URI.encode_path(k)}=#{URI.encode_path(v)}" }.join("&")
- url = "#{Repository.path(repo)}/deployments"
- url += "?#{query_string}" unless query_string.empty?
- get(url, options)
- end
-
- # Alias for `deployments`
- def list_deployments(repo : String, params : Hash(String, String) = {} of String => String, **options)
- deployments(repo, params, **options)
- end
-
- # Create a deployment for a ref
- # The ref parameter can be any named branch, tag, or SHA
- #
- # **See Also:**
- # - [https://developer.github.com/v3/repos/deployments/#create-a-deployment](https://developer.github.com/v3/repos/deployments/#create-a-deployment)
- #
- # **Examples:**
- # Create a deployment for a ref
- #
- # ```
- # Octokit.create_deployment("monalisa/app", "main")
- # ```
- #
- # ```
- # Octokit.create_deployment("monalisa/app", "main", description: "Deploying main branch!")
- # ```
- def create_deployment(
- repo : String, # in org/repo format (required)
- ref : String, # The ref to deploy. This can be a branch, tag, or SHA. (required)
- task : String = "deploy",
- auto_merge : Bool = true,
- required_contexts : Array(String)? = nil,
- payload : Hash(String, String) = {} of String => String,
- environment : String = "production",
- description : String = "",
- transient_environment : Bool = false,
- production_environment : Bool = true,
- **options
- )
- options = options.merge({
- json: {
- ref: ref,
- task: task,
- auto_merge: auto_merge,
- required_contexts: required_contexts,
- payload: payload,
- environment: environment,
- description: description,
- transient_environment: transient_environment,
- production_environment: production_environment,
- },
- })
-
- post("#{Repository.path(repo)}/deployments", options)
- end
-
- # Delete a Deployment
- #
- # If the repository only has one deployment, you can delete the deployment regardless of its status. If the repository has more than one deployment, you can only delete inactive deployments. This ensures that repositories with multiple deployments will always have an active deployment.
- #
- # To set a deployment as inactive, you must:
- #
- # Create a new deployment that is active so that the system has a record of the current state, then delete the previously active deployment.
- # Mark the active deployment as inactive by adding any non-successful deployment status.
- #
- # **See Also:**
- # - [https://developer.github.com/v3/repos/deployments/#delete-a-deployment](https://developer.github.com/v3/repos/deployments/#delete-a-deployment)
- # **Examples:**
- #
- # ```
- # Octokit.delete_deployment("monalisa/app", 123456)
- # ```
- def delete_deployment(repo : String, deployment_id : Int64, **options)
- delete("#{Repository.path(repo)}/deployments/#{deployment_id}", options)
- end
-
- # Get a deployment status
- #
- # **See Also:**
- # - [https://developer.github.com/v3/repos/deployments/#get-a-deployment-status](https://developer.github.com/v3/repos/deployments/#get-a-deployment-status)
- #
- # **Examples:**
- #
- # ```
- # Octokit.deployment_status("monalisa/app", 1234567890, 1234567890)
- # ```
- def deployment_status(repo : String, deployment_id : Int64, status_id : Int64, **options)
- get("#{Repository.path(repo)}/deployments/#{deployment_id}/statuses/#{status_id}", options)
- end
-
- # List all statuses for a Deployment
- #
- # **See Also:**
- # - [https://developer.github.com/v3/repos/deployments/#list-deployment-statuses](https://developer.github.com/v3/repos/deployments/#list-deployment-statuses)
- #
- # **Examples:**
- #
- # ```
- # Octokit.deployment_statuses("monalisa/app", 1234567890)
- # ```
- #
- # You should use a paginated octokit instance to fetch all statuses:
- #
- # ```
- # client = Octokit.client
- # client.auto_paginate = true
- # client.per_page = 100
- #
- # data = client.deployment_statuses("monalisa/app", 1234567890)
- # puts data.records.to_pretty_json
- # ```
- #
- # Returns an array of deployment statuses
- def deployment_statuses(repo : String, deployment_id : Int64, **options) : Paginator(Octokit::Models::DeploymentStatus)
- paginate(
- Octokit::Models::DeploymentStatus,
- "#{Repository.path(repo)}/deployments/#{deployment_id}" + "/statuses",
- start_page: options[:page]?,
- per_page: options[:per_page]?
- )
- end
-
- # alias for `deployment_statuses`
- def list_deployment_statuses(repo : String, deployment_id : Int64, **options) : Paginator(Octokit::Models::DeploymentStatus)
- deployment_statuses(repo, deployment_id, **options)
- end
-
- # Create a deployment status for a Deployment
- #
- # :param repo [String]: The repository to create a deployment status for in org/repo format (required)
- # :param deployment_id [Integer]: The deployment id (required)
- # :param state: can be one of the following: error, failure, inactive, in_progress, queued, pending, success
- # :param options [String]: :target_url The target URL to associate with this status. Default: ""
- # :param options [String]: :description A short description of the status. Maximum length of 140 characters. Default: ""
- # :return: A deployment status
- #
- # **See Also:**
- # - [https://developer.github.com/v3/repos/deployments/#create-a-deployment-status](https://developer.github.com/v3/repos/deployments/#create-a-deployment-status)
- #
- # **Examples:**
- #
- # ```
- # Octokit.create_deployment_status("monalisa/app", 1234567890, "success")
- # ```
- def create_deployment_status(
- repo : String, # in org/repo format (required)
- deployment_id : Int64, # The deployment id (required)
- state : String, # The state of the status (required)
- target_url : String = "",
- log_url : String = "",
- description : String = "",
- environment : String? = nil,
- environment_url : String = "",
- auto_inactive : Bool = true,
- **options
- )
- raise "ArgumentError: state must be one of error, failure, inactive, in_progress, queued, pending, success" unless VALID_STATES.includes?(state)
-
- options = options.merge({
- json: {
- state: state.downcase,
- target_url: target_url,
- log_url: log_url,
- description: description,
- environment: environment,
- environment_url: environment_url,
- auto_inactive: auto_inactive,
- },
- })
-
- post("#{Repository.path(repo)}/deployments/#{deployment_id}" + "/statuses", options)
- end
- end
- end
-end
diff --git a/lib/octokit/src/octokit/client/downloads.cr b/lib/octokit/src/octokit/client/downloads.cr
deleted file mode 100644
index e69de29..0000000
diff --git a/lib/octokit/src/octokit/client/emojis.cr b/lib/octokit/src/octokit/client/emojis.cr
deleted file mode 100644
index e69de29..0000000
diff --git a/lib/octokit/src/octokit/client/events.cr b/lib/octokit/src/octokit/client/events.cr
deleted file mode 100644
index e69de29..0000000
diff --git a/lib/octokit/src/octokit/client/feeds.cr b/lib/octokit/src/octokit/client/feeds.cr
deleted file mode 100644
index e69de29..0000000
diff --git a/lib/octokit/src/octokit/client/gists.cr b/lib/octokit/src/octokit/client/gists.cr
deleted file mode 100644
index e69de29..0000000
diff --git a/lib/octokit/src/octokit/client/gitignore.cr b/lib/octokit/src/octokit/client/gitignore.cr
deleted file mode 100644
index e69de29..0000000
diff --git a/lib/octokit/src/octokit/client/hooks.cr b/lib/octokit/src/octokit/client/hooks.cr
deleted file mode 100644
index e69de29..0000000
diff --git a/lib/octokit/src/octokit/client/issues.cr b/lib/octokit/src/octokit/client/issues.cr
deleted file mode 100644
index 9bf06b8..0000000
--- a/lib/octokit/src/octokit/client/issues.cr
+++ /dev/null
@@ -1,414 +0,0 @@
-require "../models/repos"
-require "../models/orgs"
-require "../models/issues"
-require "../models/users"
-
-module Octokit
- class Client
- # Methods for the Issues API
- #
- # **See Also:**
- # - [https://developer.github.com/v3/issues/](https://developer.github.com/v3/issues/)
- module Issues
- # :nodoc:
- alias Repository = Models::Repository
-
- # :nodoc:
- alias Organization = Models::Organization
-
- # :nodoc:
- alias Issue = Models::Issue
-
- # :nodoc:
- alias User = Models::User
-
- # Valid filters for Issues
- FILTERS = ["all", "assigned", "created", "mentioned", "subscribed"]
-
- # Valid states for Issues
- STATES = ["all", "open", "closed"]
-
- # Valid sort for Issues
- SORTS = ["created", "updated", "comments"]
-
- # Valid directions in which to sort Issues
- DIRECTIONS = ["asc", "desc"]
-
- # List issues for the authenticated user or repository
- #
- # **See Also:**
- # - [https://developer.github.com/v3/issues/#list-issues-for-a-repository](https://developer.github.com/v3/issues/#list-issues-for-a-repository)
- # - [https://developer.github.com/v3/issues/#list-issues](https://developer.github.com/v3/issues/#list-issues)
- #
- # **Example:**
- #
- # List issues for a repository
- # ```
- # Octokit.client.list_issues("watzon/cadmium")
- # ```
- #
- # List issues for the authenticated user across repositories
- # ```
- # @client = Octokit::Client.new(login: "foo", password: "bar")
- # @client.list_issues
- # ```
- def list_issues(repo = nil, **options)
- validate_options(options)
- path = repo ? "#{Repository.path(repo)}/issues" : "issues"
- paginate Issue, path, options: {json: options}
- end
-
- # List all user issues across owned and member repositories for the
- # authenticated user.
- #
- # **See Also:**
- # - [https://developer.github.com/v3/issues/#list-issues](https://developer.github.com/v3/issues/#list-issues)
- #
- # **Example:**
- #
- # List issues for the authenticated user across owned and member repositories.
- # ```
- # @client = Octokit::Client.new(login: "foo", password: "bar")
- # @client.user_issues
- # ```
- def user_issues(**options)
- validate_options(options)
- paginate Issue, "user/issues", options: {json: options}
- end
-
- # List all user issues for a given organization for the authenticated user.
- #
- # **See Also:**
- # - [https://developer.github.com/v3/issues/#list-issues](https://developer.github.com/v3/issues/#list-issues)
- #
- # **Example:**
- #
- # List all issues for a given organization for the authenticated user
- # ```
- # @client = Octokit::Client.new(login: "foo", password: "bar")
- # @client.org_issues
- # ```
- def org_issues(org, **options)
- validate_options(options)
- paginate Issue, "#{Organization.path(org)}/issues", options: {json: options}
- end
-
- # Create an issue for a repository.
- #
- # **See Also:**
- # - [https://developer.github.com/v3/issues/#create-an-issue](https://developer.github.com/v3/issues/#create-an-issue)
- #
- # **Example:**
- #
- # Create a new Issues for a repository
- # ```
- # @client = Octokit::Client.new(login: "foo", password: "bar")
- # @client.create_issue("watzon/cadmium", "Not enough awesome", "You heard me.")
- # ```
- def create_issue(repo, title, body, **options)
- params = {title: title, body: body, labels: [] of String}.merge(options)
- res = post "#{Repository.path(repo)}/issues", {json: params}
- Issue.from_json(res)
- end
-
- alias_method :create_issue, :open_issue
-
- # Get a single issue from a repository
- #
- # **See Also:**
- # - [https://developer.github.com/v3/issues/#get-a-single-issue](https://developer.github.com/v3/issues/#get-a-single-issue)
- #
- # **Example:**
- #
- # Get issue #4 from watzon/cadmium
- # ```
- # Octokit.client.issue("watzon/cadmium", 4)
- # ```
- def issue(repo, number : Int32)
- res = get "#{Repository.path(repo)}/issues/#{number}"
- Issue.from_json(res)
- end
-
- # Close an issue
- #
- # **See Also:**
- # - [https://developer.github.com/v3/issues/#edit-an-issue](https://developer.github.com/v3/issues/#edit-an-issue)
- #
- # **Example:**
- #
- # Close issue #4 from watzon/cadmium
- # ```
- # @client.close_issue("watzon/cadmium", 4)
- # ```
- def close_issue(repo, number : Int32, **options)
- res = patch "#{Repository.path(repo)}/issues/#{number}", {json: options.merge({state: closed})}
- Issue.from_json(res)
- end
-
- # Repoen an issue
- #
- # **See Also:**
- # - [https://developer.github.com/v3/issues/#edit-an-issue](https://developer.github.com/v3/issues/#edit-an-issue)
- #
- # **Example:**
- #
- # Repoen issue #4 from watzon/cadmium
- # ```
- # @client.reopen_issue("watzon/cadmium", 4)
- # ```
- def reopen_issue(repo, number : Int32, **options)
- res = patch "#{Repository.path(repo)}/issues/#{number}", {json: options.merge({state: open})}
- Issue.from_json(res)
- end
-
- # Lock an issue's conversation, limiting it to collaborators
- #
- # **See Also:**
- # - [https://developer.github.com/v3/issues/#edit-an-issue](https://developer.github.com/v3/issues/#edit-an-issue)
- #
- # **Example:**
- #
- # Lock issue #4 from watzon/cadmium
- # ```
- # @client.lock_issue("watzon/cadmium", 4)
- # ```
- def lock_issue(repo, number : Int32, **options)
- boolean_from_response :put, "#{Repository.path(repo)}/issues/#{number}/lock", {json: options}
- end
-
- # Unlock an issue's conversation, opening it to all viewers
- #
- # **See Also:**
- # - [https://developer.github.com/v3/issues/#edit-an-issue](https://developer.github.com/v3/issues/#edit-an-issue)
- #
- # **Example:**
- #
- # Lock issue #4 from watzon/cadmium
- # ```
- # @client.unlock_issue("watzon/cadmium", 4)
- # ```
- def unlock_issue(repo, number : Int32, **options)
- boolean_from_response :delete, "#{Repository.path(repo)}/issues/#{number}/lock", {json: options}
- end
-
- # Update an issue
- #
- # **See Also:**
- # - [https://developer.github.com/v3/issues/#edit-an-issue](https://developer.github.com/v3/issues/#edit-an-issue)
- #
- # **Examples:**
- #
- # Change the title of issue #4
- # ```
- # @client.update_issue("watzon/cadmium", 4, title: "New title")
- # ```
- #
- # Change only the assignee of issue #4
- # ```
- # @client.update_issue("watzon/cadmium", 4, assignee: "monalisa")
- # ```
- def update_issue(repo, number : Int32, **options)
- res = patch "#{Repository.path(repo)}/issues/#{number}", {json: options}
- Issue.from_json(res)
- end
-
- # Get all comments attached to issues for the repository.
- #
- # By default, Issue Comments are ordered by ascending ID.
- #
- # **See Also:**
- # - [https://developer.github.com/v3/issues/comments/#list-comments-in-a-repository](https://developer.github.com/v3/issues/comments/#list-comments-in-a-repository)
- #
- # **Examples:**
- #
- # Get the comments for issues in the cadmium repository
- # ```
- # @client.issues_comments("watzon/cadmium")
- # ```
- #
- # Get issues comments, sort by updated descending since a time
- # ```
- # @client.issues_comments("watzon/cadmium", sort: :desc, direction: :asc, since: "2010-05-04T23:45:02Z")
- # ```
- def issues_comments(repo, number : Int32, **options)
- validate_options(options)
- options.merge({since: options[:since].to_rfc3339}) if options[:since].is_a?(Time)
- res = patch "#{Repository.path(repo)}/issues/#{number}", {json: options}
- Issue.from_json(res)
- end
-
- # Get all comments attached to an issue.
- #
- # **See Also:**
- # - [https://developer.github.com/v3/issues/comments/#list-comments-on-an-issue](https://developer.github.com/v3/issues/comments/#list-comments-on-an-issue)
- #
- # **Examples:**
- #
- # Get the comments for issue #4 from watzon/cadmium
- # ```
- # Octokit.client.issue_comments("watzon/cadmium", 4)
- # ```
- def issue_comments(repo, number : Int32)
- headers = api_media_type(:reactions)
- paginate Models::IssueComment, "#{Repository.path(repo)}/issues/#{number}/comments", options: {headers: headers}
- end
-
- # Get a single comment attached to an issue.
- #
- # **See Also:**
- # - [https://developer.github.com/v3/issues/comments/#get-a-single-comment](https://developer.github.com/v3/issues/comments/#get-a-single-comment)
- #
- # **Examples:**
- #
- # Get comment #495536069 from an issue on watzon/cadmium
- # ```
- # Octokit.client.issue_comment("watzon/cadmium", 495536069)
- # ```
- def issue_comment(repo, number : Int32)
- headers = api_media_type(:reactions)
- res = get "#{Repository.path(repo)}/issues/comments/#{number}", {headers: headers}
- Models::IssueComment.from_json(res)
- end
-
- # Get a single comment attached to an issue.
- #
- # **See Also:**
- # - [https://developer.github.com/v3/issues/comments/#create-a-comment](https://developer.github.com/v3/issues/comments/#create-a-comment)
- #
- # **Examples:**
- #
- # Add a comment to issue #4 on watzon/cadmium
- # ```
- # Octokit.client.add_comment("watzon/cadmium", 4, "Plenty of awesome")
- # ```
- def add_comment(repo, number : Int32, comment : String)
- res = post "#{Repository.path(repo)}/issues/#{number}/comments", {json: {body: comment}}
- Models::IssueComment.from_json(res)
- end
-
- # Update a single comment on an issue.
- #
- # **See Also:**
- # - [https://developer.github.com/v3/issues/comments/#edit-a-comment](https://developer.github.com/v3/issues/comments/#edit-a-comment)
- #
- # **Examples:**
- #
- # Update comment #495536069
- # ```
- # Octokit.client.update_comment("watzon/cadmium", 495536069, "Plenty of awesome!")
- # ```
- def update_comment(repo, number : Int32, comment : String)
- res = patch "#{Repository.path(repo)}/issues/comments/#{number}", {json: {body: comment}}
- Models::IssueComment.from_json(res)
- end
-
- # Delete a single comment.
- #
- # **See Also:**
- # - [https://developer.github.com/v3/issues/comments/#delete-a-comment](https://developer.github.com/v3/issues/comments/#delete-a-comment)
- #
- # **Examples:**
- #
- # Delete comment #495536069
- # ```
- # Octokit.client.delete_comment("watzon/cadmium", 495536069)
- # ```
- def delete_comment(repo, number : Int32)
- boolean_from_response :delete, "#{Repository.path(repo)}/issues/comments/#{number}"
- end
-
- # Get the timeline for an issue.
- #
- # **See Also:**
- # - [https://developer.github.com/v3/issues/timeline/](https://developer.github.com/v3/issues/timeline/)
- #
- # **Examples:**
- #
- # Get timeline for issue #4 on watzon/cadmium
- # ```
- # Octokit.client.issue_timeline("watzon/cadmium", 4)
- # ```
- def issue_timeline(repo, number : Int32)
- headers = api_media_type(:issue_timelines)
- paginate Models::Timeline, "#{Repository.path(repo)}/issues/comments/#{number}", options: {headers: headers}
- end
-
- # List the available assignees for issues in a repository.
- #
- # **See Also:**
- # - [https://developer.github.com/v3/issues/assignees/#list-assignees](https://developer.github.com/v3/issues/assignees/#list-assignees)
- #
- # **Examples:**
- #
- # Get avaialble assignees on repository watzon/cadmium
- # ```
- # Octokit.client.list_assignees("watzon/cadmium")
- # ```
- def list_assignees(repo)
- paginate User, "#{Repository.path(repo)}/assignees"
- end
-
- # Add assignees to an issue.
- #
- # **See Also:**
- # - [https://developer.github.com/v3/issues/assignees/#add-assignees-to-an-issue](https://developer.github.com/v3/issues/assignees/#add-assignees-to-an-issue)
- #
- # **Examples:**
- #
- # Add assignees "monalisa" and "asterite" to issue #4 on watzon/cadmium
- # ```
- # Octokit.client.add_assignees("watzon/cadmium", 4, ["monalisa", "asterite"])
- # ```
- def add_assignees(repo, number : Int32, assignees : Array(String | User))
- assignees = assignees.map { |a| a.is_a?(User) ? a.login : a }
- res = post "#{Repository.path(repo)}/issues/#{number}/assignees", {json: {assignees: assignees}}
- Issue.from_json(res)
- end
-
- # Remove assignees from an issue.
- #
- # **See Also:**
- # - [https://developer.github.com/v3/issues/assignees/#remove-assignees-from-an-issue](https://developer.github.com/v3/issues/assignees/#remove-assignees-from-an-issue)
- #
- # **Examples:**
- #
- # Remove assignee "asterite" from issue #4 on watzon/cadmium
- # ```
- # Octokit.client.remove_assignees("watzon/cadmium", 4, ["asterite"])
- # ```
- def remove_assignees(repo, number : Int32, assignees : Array(String | User))
- assignees = assignees.map { |a| a.is_a?(User) ? a.login : a }
- res = post "#{Repository.path(repo)}/issues/#{number}/assignees", {json: {assignees: assignees}}
- Issue.from_json(res)
- end
-
- # Validate options for filtering issues and log a warning if an incorrect
- # filter is used.
- protected def validate_options(options)
- if filter = options[:filter]?
- unless FILTERS.includes?(filter.to_s)
- octokit_warn "'#{filter}' is not a valid Issue filter. Valid values are: #{FILTERS}"
- end
- end
-
- if state = options[:state]?
- unless STATES.includes?(state.to_s)
- octokit_warn "'#{state}' is not a valid Issue state. Valid values are: #{STATES}"
- end
- end
-
- if sort = options[:sort]?
- unless SORTS.includes?(sort.to_s)
- octokit_warn "'#{sort}' is not a valid Issue sort. Valid values are: #{SORTS}"
- end
- end
-
- if direction = options[:direction]?
- unless DIRECTIONS.includes(direction.to_s)
- octokit_warn "'#{direction}' is not a valid Issue sort direction. Valid values are: #{DIRECTIONS}"
- end
- end
- end
- end
- end
-end
diff --git a/lib/octokit/src/octokit/client/labels.cr b/lib/octokit/src/octokit/client/labels.cr
deleted file mode 100644
index e69de29..0000000
diff --git a/lib/octokit/src/octokit/client/legacy_search.cr b/lib/octokit/src/octokit/client/legacy_search.cr
deleted file mode 100644
index e69de29..0000000
diff --git a/lib/octokit/src/octokit/client/licenses.cr b/lib/octokit/src/octokit/client/licenses.cr
deleted file mode 100644
index e69de29..0000000
diff --git a/lib/octokit/src/octokit/client/markdown.cr b/lib/octokit/src/octokit/client/markdown.cr
deleted file mode 100644
index 3ce0c1f..0000000
--- a/lib/octokit/src/octokit/client/markdown.cr
+++ /dev/null
@@ -1,17 +0,0 @@
-module Octokit
- class Client
- module Markdown
- # Render an arbitrary Markdown document
- #
- # Example:
- # ```
- # Octokit.markdown("Fixed in #111", mode: :gfm, context: "watzon/cadmium")
- # ```
- def markdown(text, mode = :markdown, context = nil)
- headers = {accept: "application/vnd.github.raw"}
- json = {text: text, mode: mode.to_s, context: context}
- post "markdown", {json: json, headers: headers}
- end
- end
- end
-end
diff --git a/lib/octokit/src/octokit/client/marketplace.cr b/lib/octokit/src/octokit/client/marketplace.cr
deleted file mode 100644
index e69de29..0000000
diff --git a/lib/octokit/src/octokit/client/meta.cr b/lib/octokit/src/octokit/client/meta.cr
deleted file mode 100644
index e69de29..0000000
diff --git a/lib/octokit/src/octokit/client/milestones.cr b/lib/octokit/src/octokit/client/milestones.cr
deleted file mode 100644
index e69de29..0000000
diff --git a/lib/octokit/src/octokit/client/notifications.cr b/lib/octokit/src/octokit/client/notifications.cr
deleted file mode 100644
index e69de29..0000000
diff --git a/lib/octokit/src/octokit/client/objects.cr b/lib/octokit/src/octokit/client/objects.cr
deleted file mode 100644
index e69de29..0000000
diff --git a/lib/octokit/src/octokit/client/organizations.cr b/lib/octokit/src/octokit/client/organizations.cr
deleted file mode 100644
index 85b5465..0000000
--- a/lib/octokit/src/octokit/client/organizations.cr
+++ /dev/null
@@ -1,55 +0,0 @@
-require "../models/orgs"
-require "../models/users"
-
-module Octokit
- class Client
- # Methods for the Organizations API
- #
- # **See Also:**
- # - [https://developer.github.com/v3/orgs/](https://developer.github.com/v3/orgs/)
- module Organizations
- # :nodoc:
- alias Organization = Models::Organization
- alias OrganizationListItem = Models::OrganizationListItem
- alias User = Models::User
-
- # List all GitHub organizations
- #
- # This provides a list of every organization, in the order that they were created
- # on GitHub.
- #
- # **See Also:**
- # - [https://developer.github.com/v3/orgs/#list-organizations](https://developer.github.com/v3/orgs/#list-organizations)
- def organizations
- # paginate Organization, "organizations", **options
- res = paginate "organizations"
- OrganizationListItem.from_json(res)
- end
-
- # Get a single organization
- #
- # **See Also:**
- # - [https://developer.github.com/v3/orgs#get-an-organization](https://developer.github.com/v3/orgs#get-an-organization)
- def organization(organization)
- res = get Organization.path(organization)
- Organization.from_json(res)
- end
-
- # List organizations for authenticated user
- #
- # **See Also:**
- # - [https://developer.github.com/v3/orgs#list-organizations-for-the-authenticated-user](https://developer.github.com/v3/orgs#list-organizations-for-the-authenticated-user)
- def organizations_for_authenticated_user
- paginate OrganizationListItem, "user/orgs"
- end
-
- # List organizations for a user
- #
- # **See Also:**
- # - [https://developer.github.com/v3/orgs#list-organizations-for-a-user](https://developer.github.com/v3/orgs#list-organizations-for-a-user)
- def organizations_for_user(user)
- paginate OrganizationListItem, "#{User.path user}/orgs"
- end
- end
- end
-end
diff --git a/lib/octokit/src/octokit/client/pages.cr b/lib/octokit/src/octokit/client/pages.cr
deleted file mode 100644
index e69de29..0000000
diff --git a/lib/octokit/src/octokit/client/projects.cr b/lib/octokit/src/octokit/client/projects.cr
deleted file mode 100644
index e69de29..0000000
diff --git a/lib/octokit/src/octokit/client/pub_sub_hubbub.cr b/lib/octokit/src/octokit/client/pub_sub_hubbub.cr
deleted file mode 100644
index ec5cd45..0000000
--- a/lib/octokit/src/octokit/client/pub_sub_hubbub.cr
+++ /dev/null
@@ -1,116 +0,0 @@
-require "http/params"
-
-module Octokit
- class Client
- # Methods for the PubSubHubbub API
- #
- # **Note:** The pubsub api requires clients to be OAuth authenticated.
- #
- # **See Also:**
- # - [https://developer.github.com/v3/repos/hooks/#pubsubhubbub](https://developer.github.com/v3/repos/hooks/#pubsubhubbub)
- module PubSubHubbub
- # Subscribe to a pubsub topic
- #
- # **See Also:**
- # - [https://developer.github.com/v3/repos/hooks/#subscribing](https://developer.github.com/v3/repos/hooks/#subscribing)
- #
- # **Example:**
- #
- # Subscribe to push events from one of your repositories, having an email sent when fired.
- # ```
- # @client = Octokit.client.(oauth_token: "token")
- # @client.subscribe("https://github.com/watzon/cadmium/events/push", "github://Email?address=chris@watzon.me")
- # ```
- def subscribe(topic, callback, secret = nil)
- options = {
- "hub.callback": callback,
- "hub.mode": "subscribe",
- "hub.topic": topic,
- }
-
- options = options.merge({"hub.secret": secret}) unless secret.nil?
- pub_sub_hubbub_request(options)
- end
-
- # Unsubscribe from a pubsub topic
- #
- # **See Also:**
- # - [https://developer.github.com/v3/repos/hooks/#subscribing](https://developer.github.com/v3/repos/hooks/#subscribing)
- #
- # **Example:**
- #
- # Unsubscribe to push events from one of your repositories, no longer having an email sent when fired
- # ```
- # @client = Octokit.client(oauth_token: "token")
- # @client.unsubscribe("https://github.com/watzon/cadmium/events/push", "github://Email?address=chris@watzon.me")
- # ```
- def unsubscribe(topic, callback)
- options = {
- "hub.callback": callback,
- "hub.mode": "unsubscribe",
- "hub.topic": topic,
- }
-
- pub_sub_hubbub_request(options)
- end
-
- # Subscribe to a repository through pubsub.
- #
- # **Note:** A list of services is available @
- # [https://github.com/github/github-services/tree/master/docs](https://github.com/github/github-services/tree/master/docs).
- #
- # **See Also:**
- # - [https://developer.github.com/v3/repos/hooks/#subscribing](https://developer.github.com/v3/repos/hooks/#subscribing)
- #
- # **Example:**
- #
- # Subscribe to push events to one of your repositories to Travis-CI
- # ```
- # @client = Octokit.client.(oauth_token: "token")
- # @client.subscribe_service_hook("watzon/cadmium", "Travis", { :token => "test", :domain => "domain", :user => "user" })
- # ```
- def subscribe_service_hook(
- repo,
- service_name,
- service_arguments = {} of String => String,
- secret = nil
- )
- topic = "#{File.join(Octokit.web_endpoint, Repository.new(repo))}/events/push"
- callback = "github://#{service_name}?#{HTTP::Params.encode(service_arguments)}"
- subscribe(topic, callback, secret)
- end
-
- # Unsubscribe from a repository through pubsub.
- #
- # **Note:** A list of services is available @
- # [https://github.com/github/github-services/tree/master/docs](https://github.com/github/github-services/tree/master/docs).
- #
- # **See Also:**
- # - [https://developer.github.com/v3/repos/hooks/#subscribing](https://developer.github.com/v3/repos/hooks/#subscribing)
- #
- # **Example:**
- #
- # Subscribe to push events to one of your repositories to Travis-CI
- # ```
- # @client = Octokit.client.(oauth_token: "token")
- # @client.unsubscribe_service_hook("watzon/cadmium", "Travis")
- # ```
- def unsubscribe_service_hook(
- repo,
- service_name
- )
- topic = "#{File.join(Octokit.web_endpoint, Repository.new(repo))}/events/push"
- callback = "github://#{service_name}"
- unsubscribe(topic, callback)
- end
-
- # Send the pubsub requests as form-urlencoded data and ensure that
- # they are token authenticated before doing so.
- protected def pub_sub_hubbub_request(options)
- ensure_token_authenticated!
- headers = {"Content-Type": "application/x-www-form-urlencoded"}
- boolean_from_response :post, "hub", {headers: headers, form_data: options}
- end
- end
- end
-end
diff --git a/lib/octokit/src/octokit/client/pull_requests.cr b/lib/octokit/src/octokit/client/pull_requests.cr
deleted file mode 100644
index 039f00a..0000000
--- a/lib/octokit/src/octokit/client/pull_requests.cr
+++ /dev/null
@@ -1,411 +0,0 @@
-require "uri"
-require "../models/repos"
-require "../models/pulls"
-require "../models/commits"
-require "../models/pull_comments"
-require "../models/repo_commits"
-
-module Octokit
- class Client
- # Methods for the Pull Requests API
- #
- # All "repo" params are constructed in the format of `/`
- #
- # **See Also:**
- # - [https://docs.github.com/en/rest/pulls/pulls?apiVersion=2022-11-28](https://docs.github.com/en/rest/pulls/pulls?apiVersion=2022-11-28)
-
- module PullRequests
- # :nodoc:
- alias Repository = Models::Repository
- # :nodoc:
- alias PullRequest = Octokit::Models::PullRequest
- # :nodoc:
- alias Commit = Octokit::Models::Commit
- # :nodoc:
- alias PullRequestComment = Octokit::Models::PullRequestComment
- # :nodoc:
- alias CommitFile = Octokit::Models::CommitFile
-
- # Valid filters for PullRequests
- FILTERS = ["all", "assigned", "created", "mentioned", "subscribed"]
-
- # Valid states for PullRequests
- STATES = ["all", "open", "closed"]
-
- # Valid sort for PullRequests
- SORTS = ["created", "updated", "comments"]
-
- # Valid directions in which to sort PullRequests
- DIRECTIONS = ["asc", "desc"]
-
- # The default options for listing pull requests
- DEFAULTS = {
- state: "open",
- sort: "created",
- direction: "desc",
- }
-
- # List pull requests for a repository
- #
- # **See Also:**
- # - [https://developer.github.com/v3/pulls/#list-pull-requests](https://developer.github.com/v3/pulls/#list-pull-requests)
- #
- # **Examples:**
- #
- # ```
- # Octokit.pull_requests("crystal-lang/crystal")
- # Octokit.pull_requests("crystal-lang/crystal", state: "closed")
- # ```
- def pull_requests(repo : String, **options) : Paginator(PullRequest)
- validate_options(options)
- paginate(
- PullRequest,
- "#{Repository.path(repo)}/pulls",
- options: {params: DEFAULTS.merge(options)}
- )
- end
-
- alias_method :pull_requests, :pulls
-
- # Create a pull request
- #
- # **See Also:**
- # - [https://developer.github.com/v3/pulls/#create-a-pull-request](https://developer.github.com/v3/pulls/#create-a-pull-request)
- #
- # **Examples:**
- #
- # ```
- # Octokit.create_pull_request("crystal-lang/crystal", "master", "new-branch", "Title", "Body")
- # ```
- def create_pull_request(repo : String, base : String, head : String, title : String, body : String, **options)
- options = {base: base, head: head, title: title, body: body}.merge(options)
- post "#{Repository.path repo}/pulls", {json: options}
- end
-
- # Create a pull request for an issue
- #
- # **See Also:**
- # - [https://developer.github.com/v3/pulls/#create-a-pull-request](https://developer.github.com/v3/pulls/#create-a-pull-request)
- #
- # **Examples:**
- #
- # ```
- # Octokit.create_pull_request_for_issue("crystal-lang/crystal", "master", "new-branch", 123)
- # ```
- def create_pull_request_for_issue(repo : String, base : String, head : String, issue : Int32, **options)
- options = {base: base, head: head, issue: issue}.merge(options)
- post "#{Repository.path repo}/pulls", {json: options}
- end
-
- # Update a pull request
- #
- # **See Also:**
- # - [https://developer.github.com/v3/pulls/#update-a-pull-request](https://developer.github.com/v3/pulls/#update-a-pull-request)
- #
- # **Examples:**
- #
- # ```
- # Octokit.update_pull_request("crystal-lang/crystal", 123, title: "New Title", body: "New Body")
- # ```
- def update_pull_request(repo : String, number : Int64, **options)
- patch "#{Repository.path repo}/pulls/#{number}", {json: options}
- end
-
- # Close a pull request
- #
- # **See Also:**
- # - [https://developer.github.com/v3/pulls/#update-a-pull-request](https://developer.github.com/v3/pulls/#update-a-pull-request)
- #
- # **Examples:**
- #
- # ```
- # Octokit.close_pull_request("crystal-lang/crystal", 123)
- # ```
- def close_pull_request(repo : String, number : Int64, **options)
- options = {state: "closed"}.merge(options)
- patch "#{Repository.path repo}/pulls/#{number}", {json: options}
- end
-
- # List commits on a pull request
- #
- # **See Also:**
- # - [https://developer.github.com/v3/pulls/#list-commits-on-a-pull-request](https://developer.github.com/v3/pulls/#list-commits-on-a-pull-request)
- #
- # **Examples:**
- #
- # ```
- # Octokit.pull_request_commits("crystal-lang/crystal", 123)
- # ```
- def pull_request_commits(repo : String, number : Int64, **options) : Paginator(Commit)
- paginate(
- Commit,
- "#{Repository.path(repo)}/pulls/#{number}/commits",
- options: {params: options}
- )
- end
-
- alias_method :pull_request_commits, :pull_commits
-
- # List review comments on a pull request
- #
- # This method applies to pull request review comments. Pull request review comments are NOT the same as standard comments left on PRs - those are issue comments.
- #
- # **See Also:**
- # - [https://developer.github.com/v3/pulls/comments/#list-comments-on-a-pull-request](https://developer.github.com/v3/pulls/comments/#list-comments-on-a-pull-request)
- #
- # **Examples:**
- #
- # ```
- # Octokit.pull_requests_comments("crystal-lang/crystal", 123)
- # ```
- def pull_requests_comments(repo : String, number : Int64, **options) : Paginator(PullRequestComment)
- paginate(
- PullRequestComment,
- "#{Repository.path(repo)}/pulls/#{number}/comments",
- options: {params: options}
- )
- end
-
- alias_method :pull_requests_comments, :reviews_comments
-
- # List comments on a pull request
- #
- # This method applies to pull request review comments. Pull request review comments are NOT the same as standard comments left on PRs - those are issue comments.
- #
- # **See Also:**
- # - [https://developer.github.com/v3/pulls/comments/#list-comments-on-a-pull-request](https://developer.github.com/v3/pulls/comments/#list-comments-on-a-pull-request)
- #
- # **Examples:**
- #
- # ```
- # Octokit.pull_request_comments("crystal-lang/crystal", 123)
- # ```
- def pull_request_comments(repo : String, number : Int64, **options) : Paginator(PullRequestComment)
- paginate(
- PullRequestComment,
- "#{Repository.path(repo)}/pulls/#{number}/comments",
- options: {params: options}
- )
- end
-
- alias_method :pull_request_comments, :pull_comments
- alias_method :pull_request_comments, :review_comments
-
- # Get a single comment on a pull request
- #
- # This method applies to pull request review comments. Pull request review comments are NOT the same as standard comments left on PRs - those are issue comments.
- #
- # **See Also:**
- # - [https://developer.github.com/v3/pulls/comments/#get-a-single-comment](https://developer.github.com/v3/pulls/comments/#get-a-single-comment)
- #
- # **Examples:**
- #
- # ```
- # Octokit.pull_request_comment("crystal-lang/crystal", 456)
- # ```
- def pull_request_comment(repo : String, comment_id : Int64, **options)
- get "#{Repository.path(repo)}/pulls/comments/#{comment_id}", {params: options}
- end
-
- alias_method :pull_request_comment, :pull_comment
- alias_method :pull_request_comment, :review_comment
-
- # Create a comment on a pull request
- #
- # This method applies to pull request review comments. Pull request review comments are NOT the same as standard comments left on PRs - those are issue comments.
- #
- # **See Also:**
- # - [https://developer.github.com/v3/pulls/comments/#create-a-comment](https://developer.github.com/v3/pulls/comments/#create-a-comment)
- #
- # - repo (String) โ A GitHub repository
- # - number (Integer) โ Pull request number
- # - body (String) โ Comment content
- # - commit_id (String) โ Sha of the commit to comment on
- # - path (String) โ Relative path of the file to comment on
- # - line (Integer) โ Line number in the diff to comment on
- # - side (String) โ Side of the diff that the comment applies to (LEFT or RIGHT)
- # - start_line (Integer) โ Start line for multi-line comments
- # - start_side (String) โ Start side for multi-line comments (LEFT or RIGHT)
- # - in_reply_to (Integer) โ ID of the review comment to reply to
- # - subject_type (String) โ Level at which the comment is targeted (line or file)
- #
- # **Examples:**
- #
- # ```
- # Octokit.create_pull_request_comment("crystal-lang/crystal", 123, "Comment body", "commit_id", "path/to/file.txt", 1, side: "RIGHT")
- # ```
- def create_pull_request_comment(
- repo : String,
- number : Int64,
- body : String,
- commit_id : String,
- path : String,
- line : Int32,
- **options
- )
- options = {
- body: body,
- commit_id: commit_id,
- path: path,
- line: line,
- }.merge(options)
- post "#{Repository.path repo}/pulls/#{number}/comments", {json: options}
- end
-
- alias_method :create_pull_request_comment, :create_pull_comment
- alias_method :create_pull_request_comment, :create_review_comment
-
- # Create a reply to a comment on a pull request
- #
- # **See Also:**
- # - [https://developer.github.com/v3/pulls/comments/#create-a-reply-to-a-comment](https://developer.github.com/v3/pulls/comments/#create-a-reply-to-a-comment)
- #
- # **Examples:**
- #
- # ```
- # Octokit.create_pull_request_comment_reply("crystal-lang/crystal", 123, "Comment body", 456)
- # ```
- def create_pull_request_comment_reply(repo : String, number : Int64, body : String, in_reply_to : Int64, **options)
- options = {body: body, in_reply_to: in_reply_to}.merge(options)
- post "#{Repository.path repo}/pulls/#{number}/comments", {json: options}
- end
-
- alias_method :create_pull_request_comment_reply, :create_pull_reply
- alias_method :create_pull_request_comment_reply, :create_review_reply
-
- # Update a comment on a pull request
- #
- # **See Also:**
- # - [https://developer.github.com/v3/pulls/comments/#update-a-comment](https://developer.github.com/v3/pulls/comments/#update-a-comment)
- #
- # **Examples:**
- #
- # ```
- # Octokit.update_pull_request_comment("crystal-lang/crystal", 456, "New comment body")
- # ```
- def update_pull_request_comment(repo : String, comment_id : Int64, body : String, **options)
- options = {body: body}.merge(options)
- patch "#{Repository.path repo}/pulls/comments/#{comment_id}", {json: options}
- end
-
- alias_method :update_pull_request_comment, :update_pull_comment
- alias_method :update_pull_request_comment, :update_review_comment
-
- # Delete a comment on a pull request
- #
- # **See Also:**
- # - [https://developer.github.com/v3/pulls/comments/#delete-a-comment](https://developer.github.com/v3/pulls/comments/#delete-a-comment)
- #
- # **Examples:**
- #
- # ```
- # Octokit.delete_pull_request_comment("crystal-lang/crystal", 456)
- # ```
- def delete_pull_request_comment(repo : String, comment_id : Int64, **options)
- delete "#{Repository.path repo}/pulls/comments/#{comment_id}", {params: options}
- end
-
- alias_method :delete_pull_request_comment, :delete_pull_comment
- alias_method :delete_pull_request_comment, :delete_review_comment
-
- # List files on a pull request
- #
- # **See Also:**
- # - [https://developer.github.com/v3/pulls/#list-pull-requests-files](https://developer.github.com/v3/pulls/#list-pull-requests-files)
- #
- # **Examples:**
- #
- # ```
- # Octokit.pull_request_files("crystal-lang/crystal", 123)
- # ```
- def pull_request_files(repo : String, number : Int64, **options) : Paginator(CommitFile)
- paginate(
- CommitFile,
- "#{Repository.path(repo)}/pulls/#{number}/files",
- options: {params: options}
- )
- end
-
- alias_method :pull_request_files, :pull_files
-
- # Update a pull request branch
- #
- # **See Also:**
- # - [https://developer.github.com/v3/pulls/#update-a-pull-request-branch](https://developer.github.com/v3/pulls/#update-a-pull-request-branch)
- #
- # **Examples:**
- # ```
- # Octokit.update_pull_request_branch("crystal-lang/crystal", 123)
- # ```
- def update_pull_request_branch(repo : String, number : Int64, **options) : Bool
- boolean_from_response(
- :put,
- "#{Repository.path(repo)}/pulls/#{number}/update-branch"
- )
- end
-
- # Merge a pull request
- #
- # **See Also:**
- # - [https://developer.github.com/v3/pulls/#merge-a-pull-request](https://developer.github.com/v3/pulls/#merge-a-pull-request)
- #
- # **Examples:**
- #
- # ```
- # Octokit.merge_pull_request("crystal-lang/crystal", 123, "Commit message")
- # ```
- def merge_pull_request(repo : String, number : Int64, commit_message : String, **options)
- options = {commit_message: commit_message}.merge(options)
- put "#{Repository.path repo}/pulls/#{number}/merge", {json: options}
- end
-
- # Check if a pull request has been merged
- #
- # **See Also:**
- # - [https://developer.github.com/v3/pulls/#get-if-a-pull-request-has-been-merged](https://developer.github.com/v3/pulls/#get-if-a-pull-request-has-been-merged)
- #
- # **Examples:**
- #
- # ```
- # Octokit.pull_merged?("crystal-lang/crystal", 123)
- # ```
- def pull_merged?(repo : String, number : Int64, **options) : Bool
- boolean_from_response(
- :get,
- "#{Repository.path(repo)}/pulls/#{number}/merge",
- options: {params: options}
- )
- end
-
- alias_method :pull_merged?, :pull_request_merged?
-
- # Validate options for filtering issues and log a warning if an incorrect
- # filter is used.
- protected def validate_options(options)
- if filter = options[:filter]?
- unless FILTERS.includes?(filter.to_s)
- octokit_warn "'#{filter}' is not a valid Issue filter. Valid values are: #{FILTERS}"
- end
- end
-
- if state = options[:state]?
- unless STATES.includes?(state.to_s)
- octokit_warn "'#{state}' is not a valid Issue state. Valid values are: #{STATES}"
- end
- end
-
- if sort = options[:sort]?
- unless SORTS.includes?(sort.to_s)
- octokit_warn "'#{sort}' is not a valid Issue sort. Valid values are: #{SORTS}"
- end
- end
-
- if direction = options[:direction]?
- unless DIRECTIONS.includes(direction.to_s)
- octokit_warn "'#{direction}' is not a valid Issue sort direction. Valid values are: #{DIRECTIONS}"
- end
- end
- end
- end
- end
-end
diff --git a/lib/octokit/src/octokit/client/rate_limit.cr b/lib/octokit/src/octokit/client/rate_limit.cr
deleted file mode 100644
index 860deed..0000000
--- a/lib/octokit/src/octokit/client/rate_limit.cr
+++ /dev/null
@@ -1,35 +0,0 @@
-require "../connection"
-
-module Octokit
- class Client
- # Methods for API rate limiting info
- #
- # **See Also:**
- # - [https://developer.github.com/v3/#rate-limiting](https://developer.github.com/v3/#rate-limiting)
- module RateLimit
- # Get rate limit info from last response if available
- # or make a new request to fetch rate limit
- #
- # **See Also:**
- # - [https://developer.github.com/v3/rate_limit/#rate-limit](https://developer.github.com/v3/rate_limit/#rate-limit)
- def rate_limit
- return rate_limit! if @last_response.nil?
-
- Octokit::RateLimit.from_response(@last_response)
- end
-
- alias_method :rate_limit, :ratelimit
-
- # Refresh rate limit info by making a new request
- #
- # **See Also:**
- # - [https://developer.github.com/v3/rate_limit/#rate-limit](https://developer.github.com/v3/rate_limit/#rate-limit)
- def rate_limit!
- get "rate_limit"
- Octokit::RateLimit.from_response(@last_response)
- end
-
- alias_method :rate_limit!, :ratelimit!
- end
- end
-end
diff --git a/lib/octokit/src/octokit/client/reactions.cr b/lib/octokit/src/octokit/client/reactions.cr
deleted file mode 100644
index e69de29..0000000
diff --git a/lib/octokit/src/octokit/client/refs.cr b/lib/octokit/src/octokit/client/refs.cr
deleted file mode 100644
index e69de29..0000000
diff --git a/lib/octokit/src/octokit/client/releases.cr b/lib/octokit/src/octokit/client/releases.cr
deleted file mode 100644
index 2898783..0000000
--- a/lib/octokit/src/octokit/client/releases.cr
+++ /dev/null
@@ -1,142 +0,0 @@
-require "mime"
-
-module Octokit
- class Client
- # Methods for the Releases API
- #
- # **See Also:**
- # - [https://developer.github.com/v3/repos/releases/](https://developer.github.com/v3/repos/releases/)
- module Releases
- # :nodoc:
- alias Repository = Models::Repository
-
- # :nodoc:
- alias RepositoryRelease = Models::RepositoryRelease
-
- # :nodoc:
- alias ReleaseAsset = Models::ReleaseAsset
-
- # List releases for a repository.
- #
- # **See Also:**
- # - [https://developer.github.com/v3/repos/releases/#list-releases-for-a-repository](https://developer.github.com/v3/repos/releases/#list-releases-for-a-repository)
- def releases(path, **options)
- paginate RepositoryRelease, "#{Repository.path(path)}/releases", **options
- end
-
- # Create a release
- #
- # **See Also:**
- # - [ https://developer.github.com/v3/repos/releases/#create-a-release]( https://developer.github.com/v3/repos/releases/#create-a-release)
- def create_release(repo, tag_name, **options)
- options = options.merge({tag_name: tag_name})
- res = post "#{Repository.path(path)}/releases", {json: options}
- RepositoryRelease.from_json(res)
- end
-
- # Get a release
- #
- # **See Also:**
- # - [ https://developer.github.com/v3/repos/releases/#create-a-release]( https://developer.github.com/v3/repos/releases/#create-a-release)
- def release(repo, id)
- res = get "#{Repository.path(repo)}/releases/#{id}"
- RepositoryRelease.from_json(res)
- end
-
- # Update a release
- #
- # **See Also:**
- # - [ https://developer.github.com/v3/repos/releases/#edit-a-release]( https://developer.github.com/v3/repos/releases/#edit-a-release)
- def update_release(repo, id, **options)
- res = patch "#{Repository.path(path)}/releases/#{id}", {json: options}
- RepositoryRelease.from_json(res)
- end
-
- # Delete a release
- #
- # **See Also:**
- # - [ https://developer.github.com/v3/repos/releases/#delete-a-release]( https://developer.github.com/v3/repos/releases/#delete-a-release)
- def delete_release(repo, id, **options)
- boolean_from_response :delete, "#{Repository.path(path)}/releases/#{id}"
- end
-
- # List release assets
- #
- # **See Also:**
- # - [ https://developer.github.com/v3/repos/releases/#list-assets-for-a-release]( https://developer.github.com/v3/repos/releases/#list-assets-for-a-release)
- def release_assets(repo, id, **options)
- paginate RepositoryRelease, "#{Repository.path(repo)}/releases/#{id}/assets", **options
- end
-
- # Upload a release asset
- #
- # TODO: Get this to work
- #
- # **See Also:**
- # - [ https://developer.github.com/v3/repos/releases/#upload-a-release-asset]( https://developer.github.com/v3/repos/releases/#upload-a-release-asset)
- def upload_asset(repo, id, path_or_file, **options)
- file = path_or_file.is_a?(File) ? path_or_file : File.new(path_or_file, "rb")
- filename = File.basename(file.path)
- content_type = options[:content_type]? || MIME.from_filename(filename)
- raise Octokit::Error::MissingContentType.new if content_type.nil?
- unless name = options[:name]?
- name = filename
- end
-
- upload_url = release(repo, id).upload_url.split('/')[0..-2].join('/')
- upload_uri = URI.parse(upload_url)
- upload_uri.query = HTTP::Params.encode({name: name})
-
- headers = {"content-type": content_type, "content-length": file.size}
- options = Halite::Options.new(headers: headers, raw: file.gets_to_end)
-
- response = request :post, upload_uri.to_s, options
- ReleaseAsset.from_json(response)
- end
-
- # Get a single release asset
- #
- # **See Also:**
- # - [ https://developer.github.com/v3/repos/releases/#get-a-single-release-asset]( https://developer.github.com/v3/repos/releases/#get-a-single-release-asset)
- def release_asset(repo, id)
- res = get "#{Repository.path(repo)}/releases/assets/#{id}"
- ReleaseAsset.from_json(res)
- end
-
- # Update a release asset
- #
- # **See Also:**
- # - [ https://developer.github.com/v3/repos/releases/#edit-a-release-asset]( https://developer.github.com/v3/repos/releases/#edit-a-release-asset)
- def update_release_asset(repo, id, **options)
- res = patch "#{Repository.path(repo)}/releases/assets/#{id}", {json: options}
- ReleaseAsset.from_json(res)
- end
-
- # Delete a release asset
- #
- # **See Also:**
- # - [ https://developer.github.com/v3/repos/releases/#delete-a-release-asset]( https://developer.github.com/v3/repos/releases/#delete-a-release-asset)
- def delete_release_asset(repo, id)
- boolean_from_response :delete, "#{Repository.path(repo)}/releases/assets/#{id}"
- end
-
- # Get the releases for a given tag
- #
- # **See Also:**
- # - [ https://developer.github.com/v3/repos/releases/#get-a-release-by-tag-name]( https://developer.github.com/v3/repos/releases/#get-a-release-by-tag-name)
- def release_for_tag(repo, tag_name)
- res = get "#{Repository.path(repo)}/releases/tags/#{tag_name}"
- RepositoryRelease.from_json(res)
- end
-
- # Get the latest release
- #
- # **See Also:**
- # - [ https://developer.github.com/v3/repos/releases/#get-the-latest-release]( https://developer.github.com/v3/repos/releases/#get-the-latest-release)
- def latest_release(repo)
- res = get "#{Repository.path(repo)}/releases/latest"
- RepositoryRelease.from_json(res)
- end
- end
- end
-end
diff --git a/lib/octokit/src/octokit/client/repositories.cr b/lib/octokit/src/octokit/client/repositories.cr
deleted file mode 100644
index b8dd34f..0000000
--- a/lib/octokit/src/octokit/client/repositories.cr
+++ /dev/null
@@ -1,697 +0,0 @@
-module Octokit
- class Client
- # Methods for the Repositories API
- #
- # **See Also:**
- # - [https://developer.github.com/v3/repos/](https://developer.github.com/v3/repos/)
- module Repositories
- # :nodoc:
- alias Repository = Models::Repository
-
- # Check if a repository exists.
- #
- # **See Also:**
- # - [https://developer.github.com/v3/repos/#get](https://developer.github.com/v3/repos/#get)
- def repository?(repo)
- !!repository(repo)
- rescue Octokit::Error::InvalidRepository
- false
- rescue Octokit::Error::NotFound
- false
- end
-
- # Get a single repository
- #
- # **Aliases:** `repo`
- #
- # **See Also:**
- # - [https://developer.github.com/v3/repos/#get](https://developer.github.com/v3/repos/#get)
- # - [https://developer.github.com/v3/licenses/#get-a-repositorys-license](https://developer.github.com/v3/licenses/#get-a-repositorys-license)
- def repository(path)
- res = get Repository.path(path)
- Repository.from_json(res)
- end
-
- alias_method :repository, :repo
-
- # Edit a repository.
- #
- # **Example:**
- # ```
- # @client.edit_repository("watzon/cadmium", has_wiki: true)
- # ```
- #
- # Available edit options are stored in `Octokit::Models::CreateRepoRequest`
- #
- # **Aliases:** `edit`, `update`, `update`
- #
- # **See Also:**
- # - [https://developer.github.com/v3/repos/#edit](https://developer.github.com/v3/repos/#edit)
- def edit_repository(repo : String | Repository, **options)
- name = Repository.get_name(repo)
- options = {name: name}.merge(options)
- res = post "repos/#{repo}", {json: options}
- Repository.from_json(res)
- end
-
- alias_method :edit_repository, :edit
- alias_method :edit_repository, :update_repository
- alias_method :edit_repository, :update
-
- # List user repositories.
- #
- # If user is not supplied, repositories for the current
- # authenticated user are returned.
- #
- # **Aliases:** `list_repositories`, `list_repos`, `repos`
- #
- # **Note:** If the user provided is a GitHub organization, only the
- # organization's public repositories will be listed. For retrieving
- # organization repositories the `Organizations#organization_repositories`
- # method should be used instead.
- #
- # **See Also:**
- # - [https://developer.github.com/v3/repos/#list-your-repositories](https://developer.github.com/v3/repos/#list-your-repositories)
- # - [https://developer.github.com/v3/repos/#list-user-repositories](https://developer.github.com/v3/repos/#list-user-repositories)
- def repositories(user = nil, **options)
- paginate Repository, "#{User.path user}/repos", **options
- end
-
- alias_method :edit_repository, :list_repositories
- alias_method :edit_repository, :list_repos
- alias_method :edit_repository, :repos
-
- # List all repositories.
- #
- # This provides a dump of every public repository on Github, in the order
- # that they were created.
- #
- # **See Also:**
- # - [https://developer.github.com/v3/repos/#list-all-public-repositories](https://developer.github.com/v3/repos/#list-all-public-repositories)
- def all_repositories(**options)
- paginate Repository, "repositories", **options
- end
-
- # Star a repository.
- #
- # **See Also:**
- # - [https://developer.github.com/v3/activity/starring/#star-a-repository](https://developer.github.com/v3/activity/starring/#star-a-repository)
- def star(repo)
- boolean_from_response :put, "user/starred/#{Repository.get_full_name(repo)}"
- end
-
- # Unstar a repository.
- #
- # **See Also:**
- # - [https://developer.github.com/v3/activity/starring/#unstar-a-repository](https://developer.github.com/v3/activity/starring/#unstar-a-repository)
- def unstar(repo)
- boolean_from_response :delete, "user/starred/#{Repository.get_full_name(repo)}"
- end
-
- # Watch a repository.
- #
- # **See Also:**
- # - [https://developer.github.com/v3/activity/watching/#watch-a-repository-legacy](https://developer.github.com/v3/activity/watching/#watch-a-repository-legacy)
- def watch(repo)
- boolean_from_response :put, "user/watched/#{Repository.get_full_name(repo)}"
- end
-
- # Unwatch a repository.
- #
- # **See Also:**
- # - [https://developer.github.com/v3/activity/watching/#stop-watching-a-repository-legacy](https://developer.github.com/v3/activity/watching/#stop-watching-a-repository-legacy)
- def unwatch(repo)
- boolean_from_response :put, "user/watched/#{Repository.get_full_name(repo)}"
- end
-
- # Fork a repository.
- #
- # **See Also:**
- # - [https://developer.github.com/v3/repos/forks/#create-a-fork](https://developer.github.com/v3/repos/forks/#create-a-fork)
- def fork(repo)
- post "#{Repository.path(repo)}/forks"
- end
-
- # Create a repository for a user or organization.
- #
- # **Aliases:** `create`, `create_repo`
- #
- # **See Also:**
- # - [https://developer.github.com/v3/repos/#create](https://developer.github.com/v3/repos/#create)
- def create_repository(repo, organization = nil, **options)
- name = Repository.get_name(repo)
- options = {name: name}.merge(options)
-
- if organization.nil?
- res = post "user/repos", {json: options}
- else
- res = post "#{Octokit::Models::Organization.path(organization)}/repos", {json: options}
- end
-
- Repository.from_json(res)
- end
-
- alias_method :create_repository, :create_repo
- alias_method :create_repository, :create
-
- # Delete a repository.
- #
- # **Aliases:** `delete_repo`
- #
- # **Note:** If OAuth is used, 'delete_repo' scope is required.
- #
- # **See Also:**
- # - [https://developer.github.com/v3/repos/#delete-a-repository](https://developer.github.com/v3/repos/#delete-a-repository)
- def delete_repository(repo)
- boolean_from_response :delete, Repository.path(repo)
- end
-
- # Transfer a repository.
- #
- # Transfer a repository owned by your organization.
- #
- # **Aliases:** `transfer_repo`
- #
- # **See Also:**
- # - [https://developer.github.com/v3/repos/#transfer-a-repository](https://developer.github.com/v3/repos/#transfer-a-repository)
- def transfer_repository(repo, new_owner, team_ids : Array(Int32))
- options = {new_owner: new_owner, team_ids: team_ids}
- res = post "#{Repository.path(repo)}/transfer", {json: options}
- Repository.from_json(res)
- end
-
- alias_method :transfer_repository, :transfer_repo
-
- # Hide a public repository.
- #
- # This is a convenience method that uses `#update_repository`
- def set_private(repo)
- update_repository repo, {private: true}
- end
-
- # Unhide a private repository.
- #
- # This is a convenience method that uses `#update_repository`
- def set_public(repo)
- update_repository repo, {private: false}
- end
-
- # Get deploy keys on a repo.
- #
- # Requires authenticated client.
- #
- # **Aliases:**
- # - [https://developer.github.com/v3/repos/keys/#list-deploy-keys](https://developer.github.com/v3/repos/keys/#list-deploy-keys)
- #
- # **Example:**
- # ```
- # @client.deploy_keys("watzon/cadmium")
- # ```
- def deploy_keys(repo)
- paginate Repository, "#{Repository.path(repo)}/keys"
- end
-
- alias_method :deploy_keys, :list_deploy_keys
-
- # Get a single deploy key for a repo.
- #
- # **See Also:**
- # - [https://developer.github.com/v3/repos/keys/#get-a-deploy-key](https://developer.github.com/v3/repos/keys/#get-a-deploy-key)
- #
- # **Example:**
- # ```
- # @client.deploy_key("watzon/cadmium", 7729435)
- # ```
- def deploy_key(repo, id)
- res = get "#{Repository.path(repo)}/keys/#{id}"
- RepositoryDeployKey.from_json(res)
- end
-
- # Add deploy key to a repo.
- #
- # Requires authenticated client.
- #
- # **See Also:**
- # - [https://developer.github.com/v3/repos/keys/#add-a-new-deploy-key](https://developer.github.com/v3/repos/keys/#add-a-new-deploy-key)
- #
- # **Example:**
- # ```
- # @client.deploy_key("watzon/cadmium", "Staging server", "ssh-rsa AAA...")
- # ```
- def add_deploy_key(repo, title, key, read_only = false)
- options = {title: title, key: key, read_only: read_only}
- res = post "#{Repository.path(repo)}/keys", {json: options}
- RepositoryDeployKey.from_json(res)
- end
-
- # Remove a deploy key from a repo.
- #
- # **Note:** Requires authenticated client.
- #
- # **See Also:**
- # - [https://developer.github.com/v3/repos/keys/#remove-a-deploy-key](https://developer.github.com/v3/repos/keys/#remove-a-deploy-key)
- #
- # **Example:**
- # ```
- # @client.remove_deploy_key("watzon/cadmium", 7729435)
- # ```
- def remove_deploy_key(repo, id)
- boolean_from_response :delete, "#{Repository.path(repo)}/keys/#{id}"
- end
-
- # List collaborators.
- #
- # **Aliases:** `collabs`
- #
- # **Note:** Requires authenticated client for private repos.
- #
- # **See Also:**
- # - [https://developer.github.com/v3/repos/collaborators/#list-collaborators](https://developer.github.com/v3/repos/collaborators/#list-collaborators)
- #
- # **Examples:**
- #
- # With unauthenticated client
- # ```
- # Octokit.client.collaborators("watzon/cadmium")
- # ```
- #
- # With authenticated client
- # ```
- # @client.collaborators("watzon/cadmium")
- # ```
- def collaborators(repo, affiliation = :all)
- options = {affiliation: affiliation.to_s}
- paginate User, "#{Repository.path(repo)}/collaborators", options: {json: options}
- end
-
- alias_method :collaborators, :collabs
-
- # Add collaborator to a repo.
- #
- # This can be used to update the permissions of an existing collaborator.
- #
- # **Aliases:** `add_collab`
- #
- # **Note:** Requires authenticated client.
- #
- # **See Also:**
- # - [https://developer.github.com/v3/repos/collaborators/#add-user-as-a-collaborator](https://developer.github.com/v3/repos/collaborators/#add-user-as-a-collaborator)
- #
- # **Examples:**
- #
- # Add a new collaborator
- # ```
- # @client.add_collaborator("watzon/cadmium", "asterite")
- # ```
- #
- # Update permissions for a collaborator
- # ```
- # @client.add_collaborator("watzon/cadmium", "asterite", permisson: "admin")
- # ```
- def add_collaborator(repo, collaborator, **options)
- boolean_from_response :put, "#{Repository.path(repo)}/collaborators/#{collaborator}", {json: options}
- end
-
- alias_method :add_collaborator, :add_collab
-
- # Remove collaborator from a repo.
- #
- # **Aliases:** `remove_collab`
- #
- # **Note:** Requires authenticated client.
- #
- # **See Also:**
- # - [https://developer.github.com/v3/repos/collaborators/#remove-user-as-a-collaborator](https://developer.github.com/v3/repos/collaborators/#remove-user-as-a-collaborator)
- #
- # **Example:**
- # ```
- # @client.remove_collaborator("watzon/cadmium", "asterite")
- # ```
- def remove_collaborator(repo, collaborator)
- boolean_from_response :delete, "#{Repository.path(repo)}/collaborators/#{collaborator}"
- end
-
- alias_method :remove_collaborator, :remove_collab
-
- # Check if a user is a collaborator for a repo
- #
- # **Note:** Requires authenticated client.
- #
- # **See Also:**
- # - [https://developer.github.com/v3/repos/collaborators/#check-if-a-user-is-a-collaborator](https://developer.github.com/v3/repos/collaborators/#check-if-a-user-is-a-collaborator)
- #
- # **Example:**
- # ```
- # @client.collaborator?("watzon/cadmium", "asterite")
- # ```
- def collaborator?(repo, collaborator)
- boolean_from_response :get, "#{Repository.path(repo)}/collaborators/#{collaborator}"
- end
-
- # Get a user's permission level for a repo.
- #
- # **Note:** Requires authenticated client.
- #
- # **See Also:**
- # - [https://developer.github.com/v3/repos/collaborators/#review-a-users-permission-level](https://developer.github.com/v3/repos/collaborators/#review-a-users-permission-level)
- #
- # **Example:**
- # ```
- # @client.permission_level("watzon/cadmium", "asterite")
- # ```
- def permission_level(repo, collaborator)
- res = get "#{Repository.path(repo)}/collaborators/#{collaborator}/permission"
- Models::RepositoryPermissionLevel.from_json(res)
- end
-
- # List teams for a repo.
- #
- # **Aliases:** `repo_teams`, `teams`
- #
- # **Note:** Requires authenticated client that is an owner or collaborator of the repo.
- #
- # **See Also:**
- # - [https://developer.github.com/v3/repos/#list-teams](https://developer.github.com/v3/repos/#list-teams)
- #
- # **Example:**
- # ```
- # @client.repository_teams("watzon/cadmium")
- # ```
- def repository_teams(repo)
- paginate Team, "#{Repository.path(repo)}/teams"
- end
-
- alias_method :repository_teams, :repo_teams
- alias_method :repository_teams, :teams
-
- # List all topics for a repository.
- #
- # **Note:** Requires authenticated client that is an owner or collaborator of the repo.
- #
- # **See Also:**
- # - [https://developer.github.com/v3/repos/#list-all-topics-for-a-repository](https://developer.github.com/v3/repos/#list-all-topics-for-a-repository)
- #
- # **Example:**
- # ```
- # @client.topics("watzon/cadmium")
- # ```
- def topics(repo)
- headers = api_media_type(:topics)
- paginate Models::RepositoryTopics, "#{Repository.path(repo)}/topics", options: {headers: headers}
- end
-
- # Replace all topics for a repository.
- #
- # **Note:** Requires authenticated client.
- #
- # **See Also:**
- # - [https://developer.github.com/v3/repos/#replace-all-topics-for-a-repository](https://developer.github.com/v3/repos/#replace-all-topics-for-a-repository)
- #
- # **Examples:**
- #
- # Replace all topics
- # ```
- # @client.replace_all_topics("watzon/cadmium", ["element", "nlp", "crystal", "awesome"])
- # ```
- #
- # Clear all topics
- # ```
- # @client.replace_all_topics("watzon/cadmium", nil)
- # ```
- def replace_all_topics(repo, names)
- json = {names: names || [] of String}
- options = {headers: api_media_type(:topics), json: json}
- res = put "#{Repository.path(repo)}/topics", options: options
- Models::RepositoryTopics.from_json(res)
- end
-
- # List contributors to a repo.
- #
- # **Aliases:** `contribs`
- #
- # **Note:** Requires authenticated client for private repos.
- #
- # **See Also:**
- # - [https://developer.github.com/v3/repos/#list-contributors](https://developer.github.com/v3/repos/#list-contributors)
- #
- # **Examples:**
- # ```
- # Octokit.client.contributors("watzon/cadmium", true)
- # @client.contribs("watzon/cadmium")
- # ```
- def contributors(repo, anon = false)
- paginate User, "#{Repository.path(repo)}/contributors", options: {json: {anon: anon}}
- end
-
- alias_method :contributors, :contribs
-
- # List stargazers of a repo.
- #
- # **Note:** Requires authenticated client for private repos.
- #
- # **See Also:**
- # - [https://developer.github.com/v3/activity/starring/#list-stargazers](https://developer.github.com/v3/activity/starring/#list-stargazers)
- #
- # **Examples:**
- # ```
- # Octokit.client.stargazers("watzon/cadmium")
- # @client.stargazers("watzon/cadmium")
- # ```
- def stargazers(repo)
- paginate User, "#{Repository.path(repo)}/stargazers"
- end
-
- # List forks
- #
- # **Aliases:** `network`
- #
- # **Note:** Requires authenticated client for private repos.
- #
- # **See Also:**
- # - [https://developer.github.com/v3/repos/forks/#list-forks](https://developer.github.com/v3/repos/forks/#list-forks)
- #
- # **Examples:**
- # ```
- # Octokit.client.forks("watzon/cadmium")
- # @client.forks("watzon/cadmium", sort: "oldest")
- # ```
- def forks(repo, sort = "newest")
- paginate Repository, "#{Repository.path(repo)}/forks", options: {json: {sort: sort}}
- end
-
- alias_method :forks, :network
-
- # List programming languages in the repo.
- #
- # **Note:** Requires authenticated client for private repos.
- #
- # **See Also:**
- # - [https://developer.github.com/v3/repos/#list-languages](https://developer.github.com/v3/repos/#list-languages)
- #
- # **Examples:**
- # ```
- # Octokit.client.languages("watzon/cadmium")
- # @client.languages("watzon/cadmium", sort: "oldest")
- # ```
- def languages(repo)
- paginate Hash(String, Int32), "#{Repository.path(repo)}/languages"
- end
-
- # List tags
- #
- # **Note:** Requires authenticated client for private repos.
- #
- # **See Also:**
- # - [https://developer.github.com/v3/repos/#list-tags](https://developer.github.com/v3/repos/#list-tags)
- #
- # **Examples:**
- # ```
- # Octokit.client.tags("watzon/cadmium")
- # @client.tags("watzon/cadmium")
- # ```
- def tags(repo)
- paginate RepositoryTag, "#{Repository.path(repo)}/tags"
- end
-
- # List branches
- #
- # **Note:** Requires authenticated client for private repos.
- #
- # **See Also:**
- # - [https://developer.github.com/v3/repos/branches/#list-branches](https://developer.github.com/v3/repos/branches/#list-branches)
- #
- # **Examples:**
- # ```
- # Octokit.client.branches("watzon/cadmium")
- # @client.branches("watzon/cadmium")
- # ```
- def branches(repo, get_protected = false)
- paginate Models::Branch, "#{Repository.path(repo)}/branches", options: {json: {protected: get_protected}}
- end
-
- # Get a single branch from a repository.
- #
- # **Aliases:** `get_branch`
- #
- # **See Also:**
- # - [https://developer.github.com/v3/repos/branches/#get-branch](https://developer.github.com/v3/repos/branches/#get-branch)
- #
- # **Example:**
- # ```
- # Octokit.client.branch("watzon/cadmium", "master")
- # ```
- def branch(repo, branch)
- res = get "#{Repository.path(repo)}/branches/#{branch}"
- Models::Branch.from_json(res)
- end
-
- alias_method :branch, :get_branch
-
- # Lock a single branch from a repository.
- #
- # **Note:** Requires authenticated client
- #
- # **See Also:**
- # - [https://developer.github.com/v3/repos/branches/#get-branch](https://developer.github.com/v3/repos/branches/#get-branch)
- #
- # **Example:**
- # ```
- # @client.protect_branch("watzon/cadmium", "master")
- # ```
- def protect_branch(repo, branch, **options)
- headers = api_media_type(:branch_protection)
- options = options.merge({
- restrictions: nil,
- required_status_checks: nil,
- })
- opts = {headers: headers, json: options}
- res = put "#{Repository.path(repo)}/branches/#{branch}/protection", opts
- Models::BranchProtectionSummary.from_json(res)
- end
-
- # Get branch protection summary.
- #
- # **Note:** Requires authenticated client
- #
- # **See Also:**
- # - [https://developer.github.com/v3/repos/branches/#get-branch-protection](https://developer.github.com/v3/repos/branches/#get-branch-protection)
- #
- # **Example:**
- # ```
- # @client.branch_protection("watzon/cadmium", "master")
- # ```
- def branch_protection(repo, branch)
- headers = api_media_type(:branch_protection)
- begin
- res = get "#{Repository.path(repo)}/branches/#{branch}/protection", {headers: headers}
- Models::BranchProtectionSummary.from_json(res.body)
- rescue Octokit::BranchNotProtected
- nil
- end
- end
-
- # Unlock a single branch from a repository.
- #
- # **Note:** Requires authenticated client
- #
- # **See Also:**
- # - [https://developer.github.com/v3/repos/#enabling-and-disabling-branch-protection](https://developer.github.com/v3/repos/#enabling-and-disabling-branch-protection)
- #
- # **Example:**
- # ```
- # @client.unprotect_branch("watzon/cadmium", "master")
- # ```
- def unprotect_branch(repo, branch)
- headers = api_media_type(:branch_protection)
- boolean_from_response :delete, "#{Repository.path(repo)}/branches/#{branch}/protection", {headers: headers}
- end
-
- # List users available for assigning issues.
- #
- # **Aliases:** `repo_assignees`
- #
- # **Note:** Requires authenticated client for private repos.
- #
- # **See Also:**
- # - [https://developer.github.com/v3/issues/assignees/#list-assignees](https://developer.github.com/v3/issues/assignees/#list-assignees)
- #
- # **Examples:**
- # ```
- # Octokit.client.repository_assignees("watzon/cadmium")
- # @client.repository_assignees("watzon/cadmium")
- # ```
- def repository_assignees(repo)
- paginate User, "#{Repository.path(repo)}/assignees"
- end
-
- alias_method :repository_assignees, :repo_assignees
-
- # Check to see if a particular user is an assignee for a repository.
- #
- # **See Also:**
- # - [https://developer.github.com/v3/issues/assignees/#check-assignee](https://developer.github.com/v3/issues/assignees/#check-assignee)
- #
- # **Example:**
- # ```
- # Octokit.client.repository_assignees("watzon/cadmium")
- # ```
- def check_assignee(repo, assignee)
- boolean_from_response :get, "#{Repository.path(repo)}/assignees/#{assignee}"
- end
-
- # List watchers subscribing to notifications for a repo.
- #
- # **See Also:**
- # - [https://developer.github.com/v3/activity/watching/#list-watchers](https://developer.github.com/v3/activity/watching/#list-watchers)
- #
- # **Example:**
- # ```
- # @client.subscribers("watzon/cadmium")
- # ```
- def subscribers(repo)
- paginate User, "#{Repository.path(repo)}/subscribers"
- end
-
- # Get a repository subscription.
- #
- # **See Also:**
- # - [https://developer.github.com/v3/activity/watching/#get-a-repository-subscription](https://developer.github.com/v3/activity/watching/#get-a-repository-subscription)
- #
- # **Example:**
- # ```
- # @client.subscription("watzon/cadmium")
- # ```
- def subscription(repo)
- res = get "#{Repository.path(repo)}/subscription"
- Models::Subscription.from_json(res.body)
- end
-
- # Update a repository subscription.
- #
- # **See Also:**
- # - [https://developer.github.com/v3/activity/watching/#set-a-repository-subscription](https://developer.github.com/v3/activity/watching/#set-a-repository-subscription)
- #
- # **Example:**
- # ```
- # @client.update_subscription("watzon/cadmium", subscribed: true)
- # ```
- def update_subscription(repo, **options)
- res = put "#{Repository.path(repo)}/subscription", {json: options}
- Models::Subscription.from_json(res.body)
- end
-
- # Delete a repository subscription.
- #
- # **See Also:**
- # - [https://developer.github.com/v3/activity/watching/#delete-a-repository-subscription](https://developer.github.com/v3/activity/watching/#delete-a-repository-subscription)
- #
- # **Example:**
- # ```
- # @client.delete_subscription("watzon/cadmium")
- # ```
- def delete_subscription(repo, **options)
- boolean_from_response :delete, "#{Repository.path(repo)}/subscription", {json: options}
- end
- end
- end
-end
diff --git a/lib/octokit/src/octokit/client/repository_invitations.cr b/lib/octokit/src/octokit/client/repository_invitations.cr
deleted file mode 100644
index e69de29..0000000
diff --git a/lib/octokit/src/octokit/client/reviews.cr b/lib/octokit/src/octokit/client/reviews.cr
deleted file mode 100644
index e69de29..0000000
diff --git a/lib/octokit/src/octokit/client/say.cr b/lib/octokit/src/octokit/client/say.cr
deleted file mode 100644
index b1722b8..0000000
--- a/lib/octokit/src/octokit/client/say.cr
+++ /dev/null
@@ -1,14 +0,0 @@
-module Octokit
- class Client
- # Methods for the unpublished Octocat API
- module Say
- # Return a nifty ASCII Octocat with GitHub wisdom
- # or your own
- def say(text = nil)
- get "octocat", {params: {s: text}}
- end
-
- alias_method :say, :octocat
- end
- end
-end
diff --git a/lib/octokit/src/octokit/client/search.cr b/lib/octokit/src/octokit/client/search.cr
deleted file mode 100644
index 6650013..0000000
--- a/lib/octokit/src/octokit/client/search.cr
+++ /dev/null
@@ -1,76 +0,0 @@
-module Octokit
- class Client
- # Methods for the Search API
- #
- # Valid options for all search methods are as follows:
- # - `sort` - sort field
- # - `order` - sort order (`:asc` or `:dsc`)
- # - `page` - the page to return
- # - `per_page` - number of items per page
- #
- # **See Also:**
- # - [https://developer.github.com/v3/search/](https://developer.github.com/v3/search/)
- module Search
- # Search code
- #
- # **See Also:**
- # - [https://developer.github.com/v3/search/#search-code](https://developer.github.com/v3/search/#search-code)
- def search_code(query, **options) : Paginator(Models::CodeSearchResult)
- search Models::CodeSearchResult, "search/code", query, options
- end
-
- # Search commits
- #
- # **See Also:**
- # - [https://developer.github.com/v3/search/#search-commits](https://developer.github.com/v3/search/#search-commits)
- def search_commits(query, **options) : Paginator(Models::CommitsSearchResult)
- options = ensure_api_media_type(:commit_search, options)
- search Models::CommitsSearchResult, "search/commits", query, options
- end
-
- # Search issues
- #
- # **See Also:**
- # - [https://developer.github.com/v3/search/#search-issues](https://developer.github.com/v3/search/#search-issues)
- def search_issues(query, **options) : Paginator(Models::IssuesSearchResult)
- search Models::IssuesSearchResult, "search/issues", query, options
- end
-
- # Search repositories
- #
- # **Aliases:** `search_repos`
- #
- # **See Also:**
- # - [https://developer.github.com/v3/search/#search-repositories](https://developer.github.com/v3/search/#search-repositories)
- def search_repositories(query, **options) : Paginator(Models::RepositoriesSearchResult)
- search Models::RepositoriesSearchResult, "search/repositories", query, options
- end
-
- alias_method :search_repositories, :search_repos
-
- # Search users
- #
- # **See Also:**
- # - [https://developer.github.com/v3/search/#search-users](https://developer.github.com/v3/search/#search-users)
- def search_users(query, **options) : Paginator(Models::UsersSearchResult)
- search Models::UsersSearchResult, "search/users", query, options
- end
-
- private def search(klass, path, query, options)
- paginate(
- klass,
- path,
- start_page: options[:page]?,
- per_page: options[:per_page]?,
- options: {
- params: {
- q: query,
- sort: options[:sort]?,
- order: options[:order]?,
- },
- }
- )
- end
- end
- end
-end
diff --git a/lib/octokit/src/octokit/client/service_status.cr b/lib/octokit/src/octokit/client/service_status.cr
deleted file mode 100644
index e69de29..0000000
diff --git a/lib/octokit/src/octokit/client/source_import.cr b/lib/octokit/src/octokit/client/source_import.cr
deleted file mode 100644
index e69de29..0000000
diff --git a/lib/octokit/src/octokit/client/stats.cr b/lib/octokit/src/octokit/client/stats.cr
deleted file mode 100644
index e69de29..0000000
diff --git a/lib/octokit/src/octokit/client/statuses.cr b/lib/octokit/src/octokit/client/statuses.cr
deleted file mode 100644
index db1412f..0000000
--- a/lib/octokit/src/octokit/client/statuses.cr
+++ /dev/null
@@ -1,48 +0,0 @@
-require "../models/repo_statuses"
-
-module Octokit
- class Client
- # Methods for the Commit Statuses API
- #
- # **See Also:**
- # - [https://developer.github.com/v3/repos/statuses/](https://developer.github.com/v3/repos/statuses/)
- module Statuses
- # :nodoc:
- alias RepoStatus = Models::RepoStatus
-
- # :nodoc:
- alias CombinedStatus = Models::CombinedStatus
-
- # List all statuses for a given commit.
- #
- # **See All:**
- # - [https://developer.github.com/v3/repos/statuses/#list-statuses-for-a-specific-ref](https://developer.github.com/v3/repos/statuses/#list-statuses-for-a-specific-ref)
- def statuses(repo, sha)
- paginate RepoStatus, "#{Repository.path(repo)}/statuses/#{sha}"
- end
-
- alias_method :statuses, :list_statuses
-
- # Get the combined status for a ref.
- #
- # **See All:**
- # - [https://developer.github.com/v3/repos/statuses/#get-the-combined-status-for-a-specific-ref](https://developer.github.com/v3/repos/statuses/#get-the-combined-status-for-a-specific-ref)
- def combined_status(repo, ref)
- res = get "#{Repository.path(repo)}/commits/#{ref}/status"
- CombinedStatus.from_json(res)
- end
-
- alias_method :combined_status, :status
-
- # Create a status for a commit.
- #
- # **See All:**
- # - [https://developer.github.com/v3/repos/statuses/#create-a-status](https://developer.github.com/v3/repos/statuses/#create-a-status)
- def create_status(repo, sha, state, **options)
- options = options.merge(state: state)
- res = post "#{Repository.path(repo)}/commits/#{ref}/status", {json: options}
- RepoStatus.from_json(res)
- end
- end
- end
-end
diff --git a/lib/octokit/src/octokit/client/traffic.cr b/lib/octokit/src/octokit/client/traffic.cr
deleted file mode 100644
index e69de29..0000000
diff --git a/lib/octokit/src/octokit/client/users.cr b/lib/octokit/src/octokit/client/users.cr
deleted file mode 100644
index cdd4d57..0000000
--- a/lib/octokit/src/octokit/client/users.cr
+++ /dev/null
@@ -1,362 +0,0 @@
-module Octokit
- class Client
- # Methods for the Users API
- #
- # **See Also:**
- # - [https://developer.github.com/v3/users/](https://developer.github.com/v3/users/)
- module Users
- # :nodoc:
- alias User = Models::User
-
- # List all GitHub users
- #
- # This provides a list of every user, in the order that they signed up
- # for GitHub.
- #
- # **See Also:**
- # - [https://developer.github.com/v3/users/#get-all-users](https://developer.github.com/v3/users/#get-all-users)
- def all_users
- res = paginate "users"
- User.from_json(res)
- end
-
- # Get a single user
- #
- # **See Also:**
- # - [https://developer.github.com/v3/users/#get-a-single-user](https://developer.github.com/v3/users/#get-a-single-user)
- # - [https://developer.github.com/v3/users/#get-the-authenticated-user](https://developer.github.com/v3/users/#get-the-authenticated-user)
- def user(user = nil)
- res = get User.path(user)
- User.from_json(res)
- end
-
- # Retrieve access token
- #
- # **Example:**
- # ```
- # Octokit.client.exchange_code_for_token("aaaa", "xxxx", "yyyy", {accept: "application/json"})
- # ```
- #
- # **See Also:**
- # - [https://developer.github.com/v3/oauth/#web-application-flow](https://developer.github.com/v3/oauth/#web-application-flow)
- def exchange_code_for_token(code, app_id = client_id, app_secret = client_secret)
- options = {
- code: code,
- client_id: app_id,
- client_secret: app_secret,
- headers: {
- content_type: "application/json",
- accept: "application/json",
- },
- }
-
- res = post "#{web_endpoint}/login/oauth/access_token", options
- Models::AccessToken.from_json(res)
- end
-
- # Validate user username and password
- def validate_credentials(options = nil)
- !self.class.new(options).user.nil?
- rescue Octokit::Error::Unauthorized
- false
- end
-
- # Update the authenticated user
- #
- # **Example:**
- # ```
- # Octokit.client.update_user(name: "Chris Watson", email: "cawatson1993@gmail.com", company: "Manas Tech", location: "Buenos Aires", hireable: false)
- # ```
- #
- # **See Also:**
- # - [https://developer.github.com/v3/users/#update-the-authenticated-user](https://developer.github.com/v3/users/#update-the-authenticated-user)
- def update_user(**options)
- res = patch "user", {json: options}
- User.from_json(res)
- end
-
- # Get a user's followers
- #
- # **Example:**
- # ```
- # Octokit.client.followers("monalisa")
- # ```
- #
- # **See Also:**
- # - [https://developer.github.com/v3/users/followers/#list-followers-of-a-user](https://developer.github.com/v3/users/followers/#list-followers-of-a-user)
- def followers(user, **options)
- res = paginate User, "#{User.path(user)}/followers", **options
- Array(Models::Follower).from_json(res)
- end
-
- # Get a list of users the user is following
- #
- # **Example:**
- # ```
- # Octokit.client.following("monalisa")
- # ```
- #
- # **See Also:**
- # - [https://developer.github.com/v3/users/followers/#list-users-followed-by-another-user](https://developer.github.com/v3/users/followers/#list-users-followed-by-another-user)
- def following(user, **options)
- res = paginate User, "#{User.path(user)}/following", **options
- Array(Models::Follower).from_json(res)
- end
-
- # Check if you is following a user. Alternatively check if a given user
- # is following a target user.
- #
- # **Examples:**
- # ```
- # @client.follows?("asterite")
- # @client.follows?("asterite", "waj")
- # ```
- #
- # **Note:** Requires an authenticated user.
- #
- # **See Also:**
- # - [https://developer.github.com/v3/users/followers/#check-if-you-are-following-a-user](https://developer.github.com/v3/users/followers/#check-if-you-are-following-a-user)
- # - [https://developer.github.com/v3/users/followers/#check-if-one-user-follows-another](https://developer.github.com/v3/users/followers/#check-if-one-user-follows-another)
- def follows?(user, target = nil)
- if !target
- target = user
- user = nil
- end
-
- boolean_from_response :get, "#{User.path(user)}/following/#{target}"
- end
-
- # Follow a user.
- #
- # **Example:**
- # ```
- # @client.follow("monalisa")
- # ```
- #
- # **Note:** Requires an authenticated user.
- #
- # **See Also:**
- # - [https://developer.github.com/v3/users/followers/#follow-a-user](https://developer.github.com/v3/users/followers/#follow-a-user)
- def follow(user)
- boolean_from_response :put, "user/following/#{user}"
- end
-
- # Unfollow a user.
- #
- # **Example:**
- # ```
- # @client.unfollow("monalisa")
- # ```
- #
- # **Note:** Requires an authenticated user.
- #
- # **See Also:**
- # - [https://developer.github.com/v3/users/followers/#unfollow-a-user](https://developer.github.com/v3/users/followers/#unfollow-a-user)
- def unfollow(user)
- boolean_from_response :delete, "user/following/#{user}"
- end
-
- # Get a list of repos starred by a user.
- #
- # **Example:**
- # ```
- # Octokit.client.starred("monalisa")
- # ```
- #
- # **See Also:**
- # - [https://developer.github.com/v3/activity/starring/#list-repositories-being-starred](https://developer.github.com/v3/activity/starring/#list-repositories-being-starred)
- def starred(user = login, **options)
- paginate User, user_path(user, "starred"), **options
- end
-
- # Check if you are starring a repo.
- #
- # **Example:**
- # ```
- # @client.starred?("watzon/octokit")
- # ```
- #
- # **Note:** Requires an authenticated client.
- #
- # **See Also:**
- # - [https://developer.github.com/v3/activity/starring/#check-if-you-are-starring-a-repository](https://developer.github.com/v3/activity/starring/#check-if-you-are-starring-a-repository)
- def starred?(repo)
- boolean_from_response :get, "user/starred/#{repo}"
- end
-
- # Get a public key.
- #
- # **Examples:**
- # ```
- # @client.key(1)
- #
- # # Retrieve public key contents
- # public_key = @client.key(1)
- # public_key.key
- # # => Error
- #
- # public_key[:key]
- # # => "ssh-rsa AAA..."
- # ```
- #
- # **Note:** when using dot notation to retrieve the values, ruby will return
- # the hash key for the public keys value instead of the actual value, use
- # symbol or key string to retrieve the value. See example.
- #
- # **Note:** Requires an authenticated client.
- #
- # **See Also:**
- # - [https://developer.github.com/v3/users/keys/#get-a-single-public-key](https://developer.github.com/v3/users/keys/#get-a-single-public-key)
- def key(key_id)
- get "user/keys/#{key_id}"
- end
-
- # Get a list of public keys for a user.
- #
- # **Examples:**
- # ```
- # @client.keys
- # @client.keys("monalisa")
- # ```
- # **Note:** Requires an authenticated client.
- #
- # **See Also:**
- # - [https://developer.github.com/v3/users/keys/#list-your-public-keys](https://developer.github.com/v3/users/keys/#list-your-public-keys)
- # - [https://developer.github.com/v3/users/keys/#list-public-keys-for-a-user](https://developer.github.com/v3/users/keys/#list-public-keys-for-a-user)
- def keys(user = nil)
- paginate User, "#{User.path user}/keys", **options
- end
-
- # Add public key to user account.
- #
- # **Example:**
- # ```
- # @client.add_key("Personal projects key", "ssh-rsa AAA...")
- # ```
- #
- # **Note:** Requires authenticated client.
- #
- # **See Also:**
- # - [https://developer.github.com/v3/users/keys/#create-a-public-key](https://developer.github.com/v3/users/keys/#create-a-public-key)
- def add_key(title, key)
- options = {title: title, key: key}
- post "user/keys", {json: options}
- end
-
- # Delete a public key.
- #
- # **Example:**
- # ```
- # @client.remove_key(1)
- # ```
- #
- # **Note:** Requires an authenticated client.
- #
- # **See Also:**
- # - [https://developer.github.com/v3/users/keys/#delete-a-public-key](https://developer.github.com/v3/users/keys/#delete-a-public-key)
- def remove_key(id)
- boolean_from_response :delete, "user/keys/#{id}"
- end
-
- # List email addresses for a user.
- #
- # **Example:**
- # ```
- # @client.emails
- # ```
- #
- # **Note:** Requires an authenticated client.
- #
- # **See Also:**
- # - [https://developer.github.com/v3/users/emails/#list-email-addresses-for-a-user](https://developer.github.com/v3/users/emails/#list-email-addresses-for-a-user)
- def emails(**options)
- paginate User, "user/emails", **options
- end
-
- # List public email addresses for a user.
- #
- # **Example:**
- # ```
- # @client.public_emails
- # ```
- #
- # **Note:** Requires an authenticated client.
- #
- # **See Also:**
- # - [https://developer.github.com/v3/users/emails/#list-public-email-addresses-for-a-user](https://developer.github.com/v3/users/emails/#list-public-email-addresses-for-a-user)
- def public_emails(**options)
- paginate User, "user/public_emails", **options
- end
-
- # Add email address to user.
- #
- # **Example:**
- # ```
- # @client.add_email("new_email@user.com")
- # ```
- #
- # **Note:** Requires authenticated client.
- #
- # **See Also:**
- # - [https://developer.github.com/v3/users/emails/#add-email-addresses](https://developer.github.com/v3/users/emails/#add-email-addresses)
- def add_email(email)
- email = [email] unless email.is_a?(Array)
- post "user/emails", email
- end
-
- # Remove email from user.
- #
- # **Example:**
- # ```
- # @client.remove_email("old_email@user.com")
- # ```
- #
- # **Note:** Requires authenticated client.
- #
- # **See Also:**
- # - [https://developer.github.com/v3/users/emails/#delete-email-addresses](https://developer.github.com/v3/users/emails/#delete-email-addresses)
- def remove_email(email)
- email = [email] unless email.is_a?(Array)
- boolean_from_response :delete, "user/emails", email
- end
-
- # Toggle the visibility of the users primary email addresses.
- #
- # **Example:**
- # ```
- # @client.toggle_email_visibility([{email: "email@user.com", visibility: "private"}])
- # ```
- #
- # **Note:** Requires authenticated client.
- #
- # **See Also:**
- # - [https://developer.github.com/v3/users/emails/#toggle-primary-email-visibility](https://developer.github.com/v3/users/emails/#toggle-primary-email-visibility)
- def toggle_email_visibility(options)
- res = patch "user/email/visibility", {json: options}
- Array(Models::UserEmail).from_json(res)
- end
-
- # List repositories being watched by a user.
- #
- # **Example:**
- # ```
- # @client.subscriptions("monalisa")
- # ```
- #
- # **See Also:**
- # - [https://developer.github.com/v3/activity/watching/#list-repositories-being-watched](https://developer.github.com/v3/activity/watching/#list-repositories-being-watched)
- def subscriptions(user = login, **options)
- paginate User, user_path(user, "subscriptions"), **options
- end
-
- # Convenience method for constructing a user specific path, if the user is logged in
- private def user_path(user, path)
- if user == login && user_authenticated?
- "user/#{path}"
- else
- "#{User.path user}/#{path}"
- end
- end
- end
- end
-end
diff --git a/lib/octokit/src/octokit/configurable.cr b/lib/octokit/src/octokit/configurable.cr
deleted file mode 100644
index ec0f320..0000000
--- a/lib/octokit/src/octokit/configurable.cr
+++ /dev/null
@@ -1,319 +0,0 @@
-require "log"
-require "./default"
-
-module Octokit
- # Provides configuration options for `Client`.
- module Configurable
- # :nodoc:
- KEYS = [
- "access_token",
- "api_endpoint",
- "auto_paginate",
- "bearer_token",
- "client_id",
- "client_secret",
- "connection_options",
- "default_media_type",
- "login",
- "management_console_endpoint",
- "management_console_password",
- "middleware",
- "per_page",
- "password",
- "proxy",
- "ssl_verify_mode",
- "user_agent",
- "web_endpoint",
- "logger",
- ]
-
- @access_token : String? = nil
-
- # Get access token for authentication.
- def access_token
- @access_token
- end
-
- # Set access token for authentication.
- def access_token=(token)
- @access_token = token
- end
-
- @auto_paginate : Bool = Default.auto_paginate
-
- # Do we want to auto paginate.
- def auto_paginate
- @auto_paginate
- end
-
- # Set if we want to auto paginate.
- def auto_paginate=(val)
- @auto_paginate = val
- end
-
- @bearer_token : String? = nil
-
- # Get the bearer token.
- def bearer_token
- @bearer_token
- end
-
- # Set the bearer token.
- def bearer_token=(token)
- @bearer_token = token
- end
-
- @client_id : String? = nil
-
- # Get the Client ID.
- def client_id
- @client_id
- end
-
- # Set the Client ID.
- def client_id=(val)
- @client_id = val
- end
-
- @client_secret : String? = nil
-
- # Get the Client Secret.
- def client_secret
- @client_secret
- end
-
- # Set the Client secret.
- def client_secret=(val)
- @client_secret = val
- end
-
- # The default type to use for accept headers.
- @default_media_type : String = Default.default_media_type
-
- # Get the default media type for headers.
- def default_media_type
- @default_media_type
- end
-
- # Set the default media type for headers.
- def default_media_type=(val)
- @default_media_type = val
- end
-
- # `Halite::Options` to be used for all connections.
- @connection_options : Halite::Options = Default.connection_options
-
- # Get the default connection options passed to Halite.
- def connection_options
- @connection_options
- end
-
- # Set the default connection options passed to Halite.
- def connection_options=(val)
- @connection_options = val
- end
-
- # Array of `Halite::Feature` to be used as middleware for requests.
- @middleware : Array(Halite::Feature) = Default.middleware
-
- # Get the middleware stack for Halite.
- def middleware
- @middleware
- end
-
- # Set the middleware stack for Halite.
- def middleware=(val)
- @middleware = val
- end
-
- # Add middleware to the middleware stack.
- def add_middleware(middleware : Halite::Feature)
- @middleware << middleware
- end
-
- @per_page : Int32?
-
- # Get the maximum results returned per page for paginated endpoints.
- def per_page
- @per_page
- end
-
- # Set the maximum results returned per page for paginated endpoints.
- def per_page=(val)
- @per_page = val
- end
-
- # Logger. Must be compatible with Crystal logger.
- @logger : Log = Default.logger
-
- # Get the configured logger instance.
- def logger
- @logger
- end
-
- # Set a configured logger instance.
- def logger=(val)
- @logger = val
- end
-
- @proxy : String? = nil
-
- # Get the proxy to use when connecting.
- # **Note:** Crystal's `HTTP::Client` and by extension `Halite` do not yet
- # support proxy's. Therefore this option does nothing for now.
- def proxy
- @proxy
- end
-
- # Set the proxy to use when connecting.
- # **Note:** Crystal's `HTTP::Client` and by extension `Halite` do not yet
- # support proxy's. Therefore this option does nothing for now.
- def proxy=(val)
- @proxy = val
- end
-
- @ssl_verify_mode : Int32 = Default.ssl_verify_mode
-
- # Get the `OpenSSL` verify mode to use for SSL connections.
- # 0 is OpenSSL::SSL::NONE
- # 1 is OpenSSL::SSL::PEER
- def ssl_verify_mode
- @ssl_verify_mode
- end
-
- # Set the `OpenSSL` verify mode to use for SSL connections.
- # 0 is OpenSSL::SSL::NONE
- # 1 is OpenSSL::SSL::PEER
- def ssl_verify_mode=(mode)
- @ssl_verify_mode = mode
- end
-
- @user_agent : String = Default.user_agent
-
- # Get the User Agent header to be passed to all requests.
- def user_agent
- @user_agent
- end
-
- # Set the User Agent header to be passed to all requests.
- def user_agent=(val)
- @user_agent = val
- end
-
- @web_endpoint : String = Default.web_endpoint
-
- # Get the web endpoint.
- def web_endpoint
- @web_endpoint
- end
-
- # Set the web endpoint.
- def web_endpoint=(val)
- @web_endpoint = val
- end
-
- @api_endpoint : String = Default.api_endpoint
-
- # Get the api endpoint.
- def api_endpoint
- @api_endpoint
- end
-
- # Set the api endpoint.
- def api_endpoint=(val)
- @api_endpoint = val
- end
-
- @password : String? = nil
-
- # Set the user password.
- def password=(val)
- @password = val
- end
-
- @login : String? = nil
-
- # Set the user login.
- def login=(val)
- @login = val
- end
-
- @management_console_endpoint : String? = nil
-
- # Set the management console endpoint.
- def management_console_endpoint=(val)
- @management_console_endpoint = val
- end
-
- # Get the management console endpoint.
- def management_console_endpoint
- @management_console_endpoint
- end
-
- @management_console_password : String? = nil
-
- # Set the management console password.
- def management_console_endpoint=(val)
- @management_console_endpoint = val
- end
-
- # Yield a block allowing configuration of options.
- #
- # **Example:**
- # ```
- # @client.configure do
- # auto_paginate = true
- # end
- # ```
- def configure(&)
- yield
- end
-
- def reset!
- do_reset!
- end
-
- # Resets the configuration options to their defaults definied in `Default`.
- private macro do_reset!
- {% begin %}
- {% for key in KEYS %}
- @{{ key.id }} = Octokit::Default.options[{{ key.id.stringify }}]
- {% end %}
- {% end %}
- end
-
- # API endpoint for `Client`.
- def api_endpoint
- File.join(@api_endpoint, "")
- end
-
- # API endpoint for `EnterpriseManagementConsoleClient`
- def management_console_endpoint
- return if @management_console_endpoint.nil?
- File.join(@management_console_endpoint.not_nil!, "")
- end
-
- # Base URL for generated web URLs
- def web_endpoint
- File.join(@web_endpoint, "")
- end
-
- # The username of the authenticated user
- def login
- @login ||= begin
- user.login if token_authenticated?
- rescue e : Exception
- end
- end
-
- private macro options
- {% begin %}
- [
- {% for key in KEYS %}
- [{{key.id.stringify}}, @{{key.id}}],
- {% end %}
- ].to_h
- {% end %}
- end
- end
-end
diff --git a/lib/octokit/src/octokit/connection.cr b/lib/octokit/src/octokit/connection.cr
deleted file mode 100644
index e9aed41..0000000
--- a/lib/octokit/src/octokit/connection.cr
+++ /dev/null
@@ -1,365 +0,0 @@
-require "base64"
-require "halite"
-require "./authentication"
-require "./macros"
-
-module Octokit
- module Connection
- include Octokit::Authentication
-
- getter last_response : Halite::Response? = nil
-
- @agent : Halite::Client? = nil
-
- protected getter last_response
-
- # Header keys that can be passed in options hash to {#get},{#head}
- CONVENIENCE_HEADERS = Set{"accept", "content_type"}
-
- # Successful status codes from PUT/POST/PATCH requests
- SUCCESSFUL_STATUSES = [201, 202, 204]
-
- # Make a HTTP GET request
- def get(url, options = nil)
- request "get", url, make_options(options)
- end
-
- # Make a HTTP POST request
- def post(url, options = nil)
- request "post", url, make_options(options)
- end
-
- # Make a HTTP PUT request
- def put(url, options = nil)
- request "put", url, make_options(options)
- end
-
- # Make a HTTP PATCH request
- def patch(url, options = nil)
- request "patch", url, make_options(options)
- end
-
- # Make a HTTP DELETE request
- def delete(url, options = nil)
- request "delete", url, make_options(options)
- end
-
- # Make a HTTP HEAD request
- def head(url, options = nil)
- request "head", url, make_options(options)
- end
-
- # Make one or more HTTP GET requests, optionally fetching
- # the next page of results from URL in Link response header based
- # on value in `#auto_paginate`.
- def paginate(
- klass : T.class,
- url : String,
- *,
- start_page = nil,
- per_page = nil,
- auto_paginate = @auto_paginate,
- options = nil
- ) : Paginator(T) forall T
- options = make_options(options)
- Paginator(T).new(self, url, start_page, per_page, auto_paginate, options)
- end
-
- # ditto
- def paginate(
- klass : T.class,
- url : String,
- *,
- start_page = nil,
- per_page = nil,
- auto_paginate = @auto_paginate,
- options = nil,
- &
- )
- paginator = Paginator(T).new(self, url, start_page, per_page, auto_paginate, options)
- while paginator.next?
- data = fetch_next
- yield(data, paginator)
- end
- paginator
- end
-
- # Hypermedia agent for the GitHub API
- def agent
- @agent ||= Halite::Client.new do
- if basic_authenticated?
- basic_auth(@login.to_s, @password.to_s)
- elsif token_authenticated?
- auth("Token #{@access_token.to_s}")
- elsif bearer_authenticated?
- auth("Bearer #{@access_token.to_s}")
- end
- user_agent(@user_agent)
- accept(Default::MEDIA_TYPE)
- end
- end
-
- # Fetch the root resource for the API
- def root
- get "/"
- end
-
- # Response for last HTTP request
- def last_response
- @last_response
- end
-
- protected def endpoint
- api_endpoint
- end
-
- protected def reset_agent
- @agent = nil
- end
-
- protected def request(method : Symbol | String, path : String, options = nil)
- path = File.join(endpoint, path) unless path.nil? || path.starts_with?("http")
- options = options ? @connection_options.merge(options) : @connection_options
- @last_response = response = agent.request(verb: method.to_s, uri: path, options: options)
- handle_error(response)
- response.body
- end
-
- protected def request(method : Symbol | String, path : String, options = nil, &)
- path = File.join(endpoint, path) unless path.nil? || path.starts_with?("http")
- options = options ? @connection_options.merge(options) : @connection_options
- @last_response = response = agent.request(verb: method, uri: path, options: options)
- handle_error(response)
- yield response
- response.body
- end
-
- # Executes the request, checking if it was successful
- protected def boolean_from_response(method : Symbol, path : String, options : NamedTuple | Nil = nil) : Bool
- request(method, path, make_options(options))
- @last_response.not_nil!.status_code.in?(SUCCESSFUL_STATUSES)
- rescue Error::NotFound
- false
- end
-
- protected def handle_error(response)
- if (300..599).includes?(response.status_code)
- error = Error.from_response(response)
- raise error if error
- end
- end
-
- protected def make_options(options) : Halite::Options?
- return if options.nil?
- options.is_a?(Halite::Options) ? options : Halite::Options.new(**options)
- end
-
- # Returned for all paginated responses, such as with
- # `Client::Repositories#repositories`. Allows you
- # to fetch the next page, the last page, or
- # fetch all pages in a response.
- #
- # **Examples:**
- # ```
- # pages = @client.repositories
- # pp pages
- # # => #
- # ```
- class Paginator(T)
- getter last_response : Halite::Response? = nil
-
- # Get all collected records. This is updated every time
- # a `fetch_*` method is called.
- getter records : Array(T) = [] of T
-
- # Get the current page.
- getter current_page : Int32
-
- # Get the number of pages remaining.
- #
- # **Note:** This is only not nil after a page has been fetched.
- getter remaining : Int32? = nil
-
- # Get the number of total pages for this query.
- #
- # **Note:** This is only not nil after a page has been fetched.
- getter total_pages : Int32? = nil
-
- # Create a new instance of `Connection::Paginator`
- def initialize(
- @client : Octokit::Client,
- @url : String,
- current_page : Int32? = nil,
- @per_page : Int32? = nil,
- auto_paginate : Bool? = nil,
- options : Halite::Options? = nil
- )
- @auto_paginate = auto_paginate.nil? ? @client.auto_paginate : auto_paginate
-
- # Don't allow the @current_page variable to be less than 1.
- @current_page = current_page.nil? || current_page < 0 ? 0 : current_page
-
- @options = options.nil? ? Halite::Options.new : options.not_nil!
-
- # If auto-pagination is turned on we go ahead and fetch
- # everything at initialization.
- fetch_all if @auto_paginate
- end
-
- # Get the record at a specific index.
- def [](index)
- @records[index]
- end
-
- # Get the record at a specific index, returning `nil` if
- # the index contains no record.
- def []?(index)
- @records[index]?
- end
-
- # Fetch all pages.
- #
- # **Example:**
- # ```
- # @client.repositories.fetch_all # => Array(Repository)
- # ```
- #
- # **Note:** This is automatically called if `Configurable#auto_paginate`
- # is set to true.
- def fetch_all : Array(T)
- # TODO: Add rate limiting support
- while next? # && !@client.rate_limit.remaining.nil? && @client.rate_limit.remaining.not_nil! > 0
- fetch_next
- end
- records
- end
-
- alias_method :fetch_all, :all
-
- # Fetch a specific page.
- #
- # **Example:**
- # ```
- # pages = @client.repositories
- # pages.fetch_page(4) # => Array(Repository)
- # ```
- def fetch_page(page : Int32) : Array(T)?
- @current_page = page
- @options.params = @options.params.merge({"page" => page.as(Halite::Options::Type)})
-
- if @per_page
- @options.params = @options.params.merge({"per_page" => @per_page.as(Halite::Options::Type)})
- end
-
- begin
- data = @client.request(:get, @url, @options)
- set_total_pages!
- models = Array(T).from_json(data)
- @records.concat(models)
- models
- rescue Octokit::Error::NotFound
- @total_pages = 0
- [] of T
- end
- end
-
- # Fetch the next page.
- #
- # **Example:**
- # ```
- # pages = @client.repositories
- # pages.fetch_next # => Array(Repository)
- # ```
- def fetch_next : Array(T)?
- return unless next?
- @current_page += 1
- fetch_page(@current_page)
- end
-
- alias_method :fetch_next, :next
-
- # Check if there is a next page.
- #
- # **Example:**
- # ```
- # pages = @client.repositories
- # pages.fetch_next
- # pages.next? # => Bool
- # ```
- def next? : Bool
- if total_pages = @total_pages
- return true if @current_page < total_pages && total_pages != 0
- false
- else
- true
- end
- end
-
- # Fetch the previous page.
- #
- # **Example:**
- # ```
- # pages = @client.repositories
- # pages.fetch_next
- # pages.fetch_previous # => Array(Repository)
- # ```
- #
- # **Note:** This is really only useful if you want to fetch
- # records backwards for some reason. Included just in case.
- def fetch_previous : Array(T)?
- return unless previous?
- @current_page -= 1
- fetch_page(@current_page)
- end
-
- alias_method :fetch_previous, :previous
-
- # Check if there is a previous page.
- #
- # **Example:**
- # ```
- # pages = @client.repositories
- # pages.fetch_next
- # pages.previous? # => Bool
- # ```
- def previous? : Bool
- @current_page > 0
- end
-
- # Checks if the current page is the last page.
- #
- # **Example:**
- # ```
- # pages = @client.repositories
- # pages.fetch_all
- # pages.last? # => Bool
- # ```
- def last? : Bool
- @current_page == @total_pages
- end
-
- # Checks if the paginator is empty.
- def empty? : Bool
- @records.empty?
- end
-
- # Utility method to set the `@total_pages` variable.
- private def set_total_pages!
- return @total_pages = 0 if @client.last_response.nil?
- if links = @client.last_response.try(&.links)
- unless links["last"]?
- @total_pages = 1
- return
- end
- if target = links["last"].target
- if match = target.match(/page=([0-9]+)/)
- @total_pages = match[1].to_i
- end
- end
- else
- @total_pages = 1
- end
- end
- end
- end
-end
diff --git a/lib/octokit/src/octokit/core_ext/time.cr b/lib/octokit/src/octokit/core_ext/time.cr
deleted file mode 100644
index 40e0e46..0000000
--- a/lib/octokit/src/octokit/core_ext/time.cr
+++ /dev/null
@@ -1,11 +0,0 @@
-struct Time
- module ISO8601Converter
- def self.to_json(value : Time, json : JSON::Builder)
- json.string(value.to_rfc3339)
- end
-
- def self.from_json(value : JSON::PullParser) : Time
- Time.parse_iso8601(value.read_string)
- end
- end
-end
diff --git a/lib/octokit/src/octokit/default.cr b/lib/octokit/src/octokit/default.cr
deleted file mode 100644
index b18b80d..0000000
--- a/lib/octokit/src/octokit/default.cr
+++ /dev/null
@@ -1,144 +0,0 @@
-require "halite"
-require "./middleware/follow_redirects"
-require "./response/raise_error"
-require "./response/feed_parser"
-require "./version"
-
-module Octokit
- # Default configuration options for `Client`
- module Default
- extend self
-
- # Default API endpoint
- API_ENDPOINT = "https://api.github.com"
-
- # Default User Agent header string
- USER_AGENT = "Octokit Crystal #{Octokit::VERSION}"
-
- # Default media type
- MEDIA_TYPE = "application/vnd.github.v3+json"
-
- # Default WEB endpoint
- WEB_ENDPOINT = "https://github.com"
-
- # Default Halite middleware stack
- MIDDLEWARE = [] of Halite::Feature
-
- # :nodoc:
- macro options
- {% begin %}
- {
- {% for key in Octokit::Configurable::KEYS %}
- {{ key.id }}: Default.{{ key.id }},
- {% end %}
- }
- {% end %}
- end
-
- # Default access token from ENV
- def access_token : String?
- ENV["OCTOKIT_ACCESS_TOKEN"]?
- end
-
- # Default API endpoint from ENV
- def api_endpoint
- ENV["OCTOKIT_API_ENDPOINT"]? || API_ENDPOINT
- end
-
- # Default pagination preference from ENV
- def auto_paginate
- !!ENV["OCTOKIT_AUTO_PAGINATE"]? || false
- end
-
- # Default bearer token from ENV
- def bearer_token
- ENV["OCTOKIT_BEARER_TOKEN"]?
- end
-
- # Default OAuth app key from ENV
- def client_id
- ENV["OCTOKIT_CLIENT_ID"]?
- end
-
- # Default OAuth app secret from ENV
- def client_secret
- ENV["OCTOKIT_SECRET"]?
- end
-
- # Default management console password from ENV
- def management_console_password
- ENV["OCTOKIT_ENTERPRISE_MANAGEMENT_CONSOLE_PASSWORD"]?
- end
-
- # Default management console endpoint from ENV
- def management_console_endpoint
- ENV["OCTOKIT_ENTERPRISE_MANAGEMENT_CONSOLE_ENDPOINT"]?
- end
-
- # Default options for `Halite::Options`
- def connection_options : Halite::Options
- Halite::Options.new(
- headers: {
- accept: default_media_type,
- user_agent: user_agent,
- })
- end
-
- # Default media type from ENV or `MEDIA_TYPE`
- def default_media_type
- ENV["OCTOKIT_DEFAULT_MEDIA_TYPE"]? || MEDIA_TYPE
- end
-
- # Default GitHub username for Basic Auth from ENV
- def login : String?
- ENV["OCTOKIT_LOGIN"]?
- end
-
- # Middleware stack for `Halite::Client`
- def middleware
- MIDDLEWARE
- end
-
- # Default GitHub password for Basic Auth from ENV
- def password : String?
- ENV["OCTOKIT_PASSWORD"]?
- end
-
- # Default pagination page size from ENV
- def per_page : Int32?
- page_size = ENV["OCTOKIT_PER_PAGE"]?
- page_size.to_i if page_size
- end
-
- # Default proxy server URI for Halite::Client from ENV
- # NOTE: Won't work until proxies are implemented by Halite
- def proxy
- ENV["OCTOKIT_PROXY"]?
- end
-
- # Default SSL verify mode from ENV
- def ssl_verify_mode : Int32
- # 0 is OpenSSL::SSL::NONE
- # 1 is OpenSSL::SSL::PEER
- # the standard default for SSL is PEER which requires a server certificate check on the client
- ENV.fetch("OCTOKIT_SSL_VERIFY_MODE", "1").to_i
- end
-
- # Default User-Agent header string from ENV or `USER_AGENT`
- def user_agent : String
- ENV["OCTOKIT_USER_AGENT"]? || USER_AGENT
- end
-
- # Default web endpoint from ENV or `WEB_ENDPOINT`
- def web_endpoint : String
- ENV["OCTOKIT_WEB_ENDPOINT"]? || WEB_ENDPOINT
- end
-
- # Default logger
- def logger
- log_level = ENV["OCTOKIT_LOG_LEVEL"]?.to_s.upcase || "INFO".to_s.upcase
- Log.setup(log_level)
- ::Log.for(self)
- end
- end
-end
diff --git a/lib/octokit/src/octokit/enterprise_admin_client.cr b/lib/octokit/src/octokit/enterprise_admin_client.cr
deleted file mode 100644
index e69de29..0000000
diff --git a/lib/octokit/src/octokit/enterprise_admin_client/admin_stats.cr b/lib/octokit/src/octokit/enterprise_admin_client/admin_stats.cr
deleted file mode 100644
index e69de29..0000000
diff --git a/lib/octokit/src/octokit/enterprise_admin_client/license.cr b/lib/octokit/src/octokit/enterprise_admin_client/license.cr
deleted file mode 100644
index e69de29..0000000
diff --git a/lib/octokit/src/octokit/enterprise_admin_client/orgs.cr b/lib/octokit/src/octokit/enterprise_admin_client/orgs.cr
deleted file mode 100644
index e69de29..0000000
diff --git a/lib/octokit/src/octokit/enterprise_admin_client/search_indexing.cr b/lib/octokit/src/octokit/enterprise_admin_client/search_indexing.cr
deleted file mode 100644
index e69de29..0000000
diff --git a/lib/octokit/src/octokit/enterprise_admin_client/users.cr b/lib/octokit/src/octokit/enterprise_admin_client/users.cr
deleted file mode 100644
index e69de29..0000000
diff --git a/lib/octokit/src/octokit/enterprise_management_console_client.cr b/lib/octokit/src/octokit/enterprise_management_console_client.cr
deleted file mode 100644
index e69de29..0000000
diff --git a/lib/octokit/src/octokit/enterprise_management_console_client/management_console.cr b/lib/octokit/src/octokit/enterprise_management_console_client/management_console.cr
deleted file mode 100644
index e69de29..0000000
diff --git a/lib/octokit/src/octokit/error.cr b/lib/octokit/src/octokit/error.cr
deleted file mode 100644
index 28f9484..0000000
--- a/lib/octokit/src/octokit/error.cr
+++ /dev/null
@@ -1,304 +0,0 @@
-require "json"
-require "xml"
-
-module Octokit
- class Error < Exception
- @response : Halite::Response?
-
- @data : JSON::Any? = nil
-
- # Returns the appropriate Octokit::Error subclass based
- # on status and response message
- def self.from_response(response : Halite::Response)
- status = response.status_code
- body = response.body
- headers = response.headers
-
- if klass = case status
- when 400 then Error::BadRequest
- when 401 then error_for_401(headers)
- when 403 then error_for_403(body)
- when 404 then error_for_404(body)
- when 405 then Error::MethodNotAllowed
- when 406 then Error::NotAcceptable
- when 409 then Error::Conflict
- when 415 then Error::UnsupportedMediaType
- when 422 then Error::UnprocessableEntity
- when 451 then Error::UnavailableForLegalReasons
- when 400..499 then Error::ClientError
- when 500 then Error::InternalServerError
- when 501 then Error::NotImplemented
- when 502 then Error::BadGateway
- when 503 then Error::ServiceUnavailable
- when 500..599 then Error::ServerError
- end
- klass.new(response)
- end
- end
-
- def initialize(response : Halite::Response? = nil)
- @response = response
- super(build_error_message)
- end
-
- # Documentation URL returned by the API for some errors
- #
- # @return [String]
- def documentation_url
- data["documentation_url"] if data.is_a? Hash
- end
-
- # Returns most appropriate error for 401 HTTP status code
- # @private
- def self.error_for_401(headers)
- if Error::OneTimePasswordRequired.required_header(headers)
- Error::OneTimePasswordRequired
- else
- Error::Unauthorized
- end
- end
-
- # Returns most appropriate error for 403 HTTP status code
- # @private
- def self.error_for_403(body)
- if body =~ /rate limit exceeded/i
- Error::TooManyRequests
- elsif body =~ /login attempts exceeded/i
- Error::TooManyLoginAttempts
- elsif body =~ /returns blobs up to [0-9]+ MB/i
- Error::TooLargeContent
- elsif body =~ /abuse/i
- Error::AbuseDetected
- elsif body =~ /repository access blocked/i
- Error::RepositoryUnavailable
- elsif body =~ /email address must be verified/i
- Error::UnverifiedEmail
- elsif body =~ /account was suspended/i
- Error::AccountSuspended
- elsif body =~ /billing issue/i
- Error::BillingIssue
- else
- Error::Forbidden
- end
- end
-
- # Return most appropriate error for 404 HTTP status code
- # @private
- def self.error_for_404(body)
- if body =~ /Branch not protected/i
- Error::BranchNotProtected
- else
- Error::NotFound
- end
- end
-
- # Array of validation errors
- # @return [Array] Error info
- def errors
- if data && data.is_a?(Hash)
- data["errors"]? || [] of Hash(String, String)
- else
- [] of Hash(String, String)
- end
- end
-
- # Status code returned by the GitHub server.
- #
- # @return [Integer]
- def response_status
- @response.not_nil!.status_code
- end
-
- # Headers returned by the GitHub server.
- #
- # @return [Hash]
- def response_headers
- @response.not_nil!.headers
- end
-
- # Body returned by the GitHub server.
- #
- # @return [String]
- def response_body
- @response.not_nil!.body
- end
-
- private def data
- @data ||= JSON.parse(@response.not_nil!.body)
- rescue JSON::ParseException
- # TODO: Clean this up
- xml = XML.parse(@response.not_nil!.body)
- title = xml.xpath_node("//title")
- @data ||= JSON.parse("{\"message\": \"#{title.not_nil!.content}\"}")
- end
-
- private def response_message
- case data
- when .as_h?
- data.as_h["message"]
- when .as_s?
- data.as_s
- end
- end
-
- private def response_error
- "Error: #{data["error"]}" if data.as_h? && data["error"]?
- end
-
- private def response_error_summary
- return nil unless data["errors"]? && data["errors"].as_a?
- return nil unless data["errors"].as_a.empty?
-
- String.build do |summary|
- summary << "\nError summary:\n"
- data["errors"].as_a.each do |error|
- if error.is_a?(Hash)
- summary << error.map { |k, v| " #{k}: #{v}" }.join('\n')
- elsif error.is_a?(String)
- summary << " #{error}"
- end
- end
- end
- end
-
- private def build_error_message
- String.build do |message|
- message << redact_url(@response.not_nil!.uri.to_s) + ": "
- message << "#{@response.not_nil!.status_code} - "
- message << "#{response_message}" unless response_message.nil?
- message << "#{response_error}" unless response_error.nil?
- message << "#{response_error_summary}" unless response_error_summary.nil?
- message << " // See: #{documentation_url}" unless documentation_url.nil?
- end
- end
-
- private def redact_url(url_string)
- %w[client_secret access_token].each do |token|
- url_string = url_string.gsub(/#{token}=\S+/, "#{token}=(redacted)") if url_string.includes? token
- end
- url_string
- end
- end
-
- class Error::ArgumentError < Error; end
-
- # Raised on errors in the 400-499 range
- class Error::ClientError < Error; end
-
- # Raised when GitHub returns a 400 HTTP status code
- class Error::BadRequest < Error::ClientError; end
-
- # Raised when GitHub returns a 401 HTTP status code
- class Error::Unauthorized < Error::ClientError; end
-
- # Raised when GitHub returns a 401 HTTP status code
- # and headers include "X-GitHub-OTP"
- class Error::OneTimePasswordRequired < Error::ClientError
- # @private
- OTP_DELIVERY_PATTERN = /required; (\w+)/i
-
- # @private
- def self.required_header(headers)
- OTP_DELIVERY_PATTERN.match headers["X-GitHub-OTP"]?.to_s
- end
-
- # Delivery method for the user's OTP
- #
- # @return [String]
- def password_delivery
- @password_delivery ||= delivery_method_from_header
- end
-
- private def delivery_method_from_header
- if match = self.class.Error
- ::required_header(@response.not_nil!.headers)
- match[1]
- end
- end
- end
-
- # Raised when GitHub returns a 403 HTTP status code
- class Error::Forbidden < Error::ClientError; end
-
- # Raised when GitHub returns a 403 HTTP status code
- # and body matches 'rate limit exceeded'
- class Error::TooManyRequests < Error::Forbidden; end
-
- # Raised when GitHub returns a 403 HTTP status code
- # and body matches 'login attempts exceeded'
- class Error::TooManyLoginAttempts < Error::Forbidden; end
-
- # Raised when GitHub returns a 403 HTTP status code
- # and body matches 'returns blobs up to [0-9]+ MB'
- class Error::TooLargeContent < Error::Forbidden; end
-
- # Raised when GitHub returns a 403 HTTP status code
- # and body matches 'abuse'
- class Error::AbuseDetected < Error::Forbidden; end
-
- # Raised when GitHub returns a 403 HTTP status code
- # and body matches 'repository access blocked'
- class Error::RepositoryUnavailable < Error::Forbidden; end
-
- # Raised when GitHub returns a 403 HTTP status code
- # and body matches 'email address must be verified'
- class Error::UnverifiedEmail < Error::Forbidden; end
-
- # Raised when GitHub returns a 403 HTTP status code
- # and body matches 'account was suspended'
- class Error::AccountSuspended < Error::Forbidden; end
-
- # Raised when GitHub returns a 403 HTTP status code
- # and body matches 'billing issue'
- class Error::BillingIssue < Error::Forbidden; end
-
- # Raised when GitHub returns a 404 HTTP status code
- class Error::NotFound < Error::ClientError; end
-
- # Raised when GitHub returns a 404 HTTP status code
- # and body matches 'Branch not protected'
- class Error::BranchNotProtected < Error::ClientError; end
-
- # Raised when GitHub returns a 405 HTTP status code
- class Error::MethodNotAllowed < Error::ClientError; end
-
- # Raised when GitHub returns a 406 HTTP status code
- class Error::NotAcceptable < Error::ClientError; end
-
- # Raised when GitHub returns a 409 HTTP status code
- class Error::Conflict < Error::ClientError; end
-
- # Raised when GitHub returns a 414 HTTP status code
- class Error::UnsupportedMediaType < Error::ClientError; end
-
- # Raised when GitHub returns a 422 HTTP status code
- class Error::UnprocessableEntity < Error::ClientError; end
-
- # Raised when GitHub returns a 451 HTTP status code
- class Error::UnavailableForLegalReasons < Error::ClientError; end
-
- # Raised on errors in the 500-599 range
- class Error::ServerError < Error; end
-
- # Raised when GitHub returns a 500 HTTP status code
- class Error::InternalServerError < Error::ServerError; end
-
- # Raised when GitHub returns a 501 HTTP status code
- class Error::NotImplemented < Error::ServerError; end
-
- # Raised when GitHub returns a 502 HTTP status code
- class Error::BadGateway < Error::ServerError; end
-
- # Raised when GitHub returns a 503 HTTP status code
- class Error::ServiceUnavailable < Error::ServerError; end
-
- # Raised when client fails to provide valid Content-Type
- class Error::MissingContentType < Error::ArgumentError; end
-
- # Raised when a method requires an application client_id
- # and secret but none is provided
- class Error::ApplicationCredentialsRequired < Exception; end
-
- # Raised when a repository is created with an invalid format
- class Error::InvalidRepository < Error::ArgumentError; end
-end
diff --git a/lib/octokit/src/octokit/helpers.cr b/lib/octokit/src/octokit/helpers.cr
deleted file mode 100644
index 1e7cc51..0000000
--- a/lib/octokit/src/octokit/helpers.cr
+++ /dev/null
@@ -1,50 +0,0 @@
-require "json_mapping"
-
-module Octokit
- # writes basic initializer from properti maps used by JSON.mapping
- # if a `mustbe` field is present for the value, the initializer will set the
- # instance variable to the given value
- macro initializer_for(properties)
- {% for key, value in properties %}
- {% properties[key] = {type: value} unless value.is_a?(NamedTupleLiteral) %}
- {% end %}
-
-
- {% for key, value in properties %}
- {% if value[:mustbe] || value[:mustbe] == false %}
- @{{key.id}} : {{value[:type]}}
- {% end %}
- {% end %}
- def initialize(
- {% for key, value in properties %}
- {% if !value[:nilable] && !value[:mustbe] && value[:mustbe] != false %}
- @{{key.id}} : {{ (value[:nilable] ? "#{value[:type]}? = nil, " : "#{value[:type]},").id }}
- {% end %}
- {% end %}
- {% for key, value in properties %}
- {% if value[:nilable] && !value[:mustbe] && value[:mustbe] != false %}
- @{{key.id}} : {{ (value[:nilable] ? "#{value[:type]}? = nil, " : "#{value[:type]},").id }}
- {% end %}
- {% end %}
- )
- {% for key, value in properties %}
- {% if value[:mustbe] || value[:mustbe] == false %}
- @{{key.id}} = {{value[:mustbe]}}
- {% end %}
- {% end %}
- end
- end
-
- macro initializer_for(**properties)
- Octokit.initializer_for({{properties}})
- end
-
- macro rest_model(fields)
- JSON.mapping({{fields}})
- Octokit.initializer_for({{fields}})
- end
-
- macro rest_model(**fields)
- Octokit.rest_model({{fields}})
- end
-end
diff --git a/lib/octokit/src/octokit/macros.cr b/lib/octokit/src/octokit/macros.cr
deleted file mode 100644
index e4b55b1..0000000
--- a/lib/octokit/src/octokit/macros.cr
+++ /dev/null
@@ -1,36 +0,0 @@
-# Duplicate a method under a different name.
-#
-# Yes, I know that aliasing methods is considered "bad practice"
-# in Crystal, but as I am trying to replicate the Octokit Ruby
-# API as closely as possible (minus a few improvements) I
-# figured I could make an exception here.
-macro alias_method(from, to, nodoc = true)
- {% for method in @type.methods %}
- {% if method.class_name == "Def" %}
- {% if method.name.id.symbolize == from.id.symbolize %}
- {% if nodoc %}# :nodoc: {% end %}
- def {{ to.id }}(
- {% for arg, i in method.args %}
- {% if method.splat_index == i %}
- *,
- {% else %}
- {{arg.name}}{% if arg.internal_name != arg.name %} {{ arg.internal_name }}{% end %}{% if arg.restriction %} : {{ arg.restriction }}{% end %},
- {% end %}
- {% end %}
- {% if method.double_splat %}
- **{{ method.double_splat }},
- {% end %}
- {% if method.accepts_block? %}
- {% if method.block_arg %}
- {{ method.block_arg }}
- {% else %}
- &block
- {% end %}
- {% end %}
- )
- {{ method.body }}
- end
- {% end %}
- {% end %}
- {% end %}
-end
diff --git a/lib/octokit/src/octokit/middleware/follow_redirects.cr b/lib/octokit/src/octokit/middleware/follow_redirects.cr
deleted file mode 100644
index e69de29..0000000
diff --git a/lib/octokit/src/octokit/models/activity.cr b/lib/octokit/src/octokit/models/activity.cr
deleted file mode 100644
index 73c84d6..0000000
--- a/lib/octokit/src/octokit/models/activity.cr
+++ /dev/null
@@ -1,47 +0,0 @@
-require "../helpers"
-
-module Octokit
- module Models
- struct Activity
- Octokit.rest_model(
- timeline_url: String,
- user_url: String,
- current_user_public_url: String,
- current_user_url: String,
- current_user_actor_url: String,
- current_user_organization_url: String,
- current_user_organization_urls: Array(String)
- )
-
- struct FeedLink
- Octokit.rest_model(
- href: String,
- type: String
- )
- end
-
- struct Links
- Octokit.rest_model(
- timeline: FeedLink,
- user: FeedLink,
- current_user_public: FeedLink,
- current_user: FeedLink,
- current_user_actor: FeedLink,
- current_user_organization: FeedLink,
- current_user_organizations: FeedLink
- )
- end
-
- struct Subscription
- Octokit.rest_model(
- subscribed: Bool,
- ignored: Bool,
- reason: String?,
- created_at: {type: Time?, converter: Time::ISO8601Converter},
- url: String,
- repository_url: String?
- )
- end
- end
- end
-end
diff --git a/lib/octokit/src/octokit/models/activity_notifications.cr b/lib/octokit/src/octokit/models/activity_notifications.cr
deleted file mode 100644
index e90a0c7..0000000
--- a/lib/octokit/src/octokit/models/activity_notifications.cr
+++ /dev/null
@@ -1,42 +0,0 @@
-require "../models/repos"
-
-module Octokit
- module Models
- struct ActivityNotifications
- Octokit.rest_model(
- id: String,
- repository: Repository,
- subject: NotificationSubject,
-
- # Reason idntifies the event that triggered the notification.
- #
- # GitHub API docs: https://developer.github.com/v3/activity/notifications/#notification-reasons
- reason: String,
-
- unread: Bool,
- updated_at: {type: Time, converter: Time::ISO8601Converter}, # TODO: Create converter for 2014-11-07T22:01:45Z
- last_read_at: String,
- url: String
- )
-
- struct NotificationSubject
- Octokit.rest_model(
- title: String,
- url: String,
- latest_comment_url: String,
- type: String
- )
- end
-
- struct NotificationListOptions
- Octokit.rest_model({
- all: Bool,
- participating: Bool,
- since: String,
- before: String,
- # }.merge(ListOptions::FIELDS))
- })
- end
- end
- end
-end
diff --git a/lib/octokit/src/octokit/models/activity_star.cr b/lib/octokit/src/octokit/models/activity_star.cr
deleted file mode 100644
index f38bf0e..0000000
--- a/lib/octokit/src/octokit/models/activity_star.cr
+++ /dev/null
@@ -1,17 +0,0 @@
-module Octokit
- module Models
- struct ActivityStar
- Octokit.rest_model(
- starred_at: String,
- repository: Repository
- )
- end
-
- struct Stargazer
- Octokit.rest_model(
- starred_at: String,
- user: User
- )
- end
- end
-end
diff --git a/lib/octokit/src/octokit/models/activity_watching.cr b/lib/octokit/src/octokit/models/activity_watching.cr
deleted file mode 100644
index e7f77cb..0000000
--- a/lib/octokit/src/octokit/models/activity_watching.cr
+++ /dev/null
@@ -1,19 +0,0 @@
-module Octokit
- module Models
- struct ActivityWatching
- Octokit.rest_model(
- subscriptions: Bool,
- ignored: Bool,
- reason: String,
- created_at: {type: Time, converter: Time::ISO8601Converter},
- url: String,
-
- # Only populated for repository subscriptions
- repository_url: String?,
-
- # Only populated for thread subscriptions
- thread_url: String?
- )
- end
- end
-end
diff --git a/lib/octokit/src/octokit/models/admin.cr b/lib/octokit/src/octokit/models/admin.cr
deleted file mode 100644
index 15b5b09..0000000
--- a/lib/octokit/src/octokit/models/admin.cr
+++ /dev/null
@@ -1,42 +0,0 @@
-module Octokit
- module Models
- struct TeamLDAPMapping
- Octokit.rest_model(
- id: Int64,
- ldap_dn: String,
- url: String,
- name: String,
- slug: String,
- description: String,
- privacy: String,
- permission: String,
-
- members_url: String,
- repositories_url: String
- )
- end
-
- struct UserLDAPMapping
- Octokit.rest_model(
- id: Int64,
- ldap_dn: String,
- login: String,
- avatar_url: String,
- gravatar_id: String,
- type: String,
- site_admin: String,
-
- url: String,
- events_url: String,
- following_url: String,
- followers_url: String,
- gists_url: String,
- organizations_url: String,
- received_events_url: String,
- repos_url: String,
- starred_url: String,
- subscriptions_url: String
- )
- end
- end
-end
diff --git a/lib/octokit/src/octokit/models/admin_stats.cr b/lib/octokit/src/octokit/models/admin_stats.cr
deleted file mode 100644
index 598a3ee..0000000
--- a/lib/octokit/src/octokit/models/admin_stats.cr
+++ /dev/null
@@ -1,102 +0,0 @@
-module Octokit
- module Models
- struct AdminStats
- Octokit.rest_model(
- issues: IssueStats,
- hooks: HookStats,
- milestones: MilestoneStats,
- orgs: OrgStats,
- comments: CommentStats,
- pages: PageStats,
- users: UserStats,
- gists: GistStats,
- pulls: PullStats,
- repos: RepoStats,
- )
- end
-
- struct IssueStats
- Octokit.rest_model(
- total_issues: Int32,
- open_issues: Int32,
- closed_issues: Int32,
- )
- end
-
- struct HookStats
- Octokit.rest_model(
- total_hooks: Int32,
- active_hooks: Int32,
- inactive_hooks: Int32,
- )
- end
-
- struct MilestoneStats
- Octokit.rest_model(
- total_milestones: Int32,
- open_milestones: Int32,
- closed_milestones: Int32
- )
- end
-
- struct OrgStats
- Octokit.rest_model(
- total_orgs: Int32,
- disabled_orgs: Int32,
- total_teams: Int32,
- total_team_members: Int32
- )
- end
-
- struct CommentStats
- Octokit.rest_model(
- total_commit_comments: Int32,
- total_gist_comments: Int32,
- total_issue_comments: Int32,
- total_pull_request_comments: Int32
- )
- end
-
- struct PageStats
- Octokit.rest_model(
- total_pages: Int32
- )
- end
-
- struct UserStats
- Octokit.rest_model(
- total_users: Int32,
- admin_users: Int32,
- suspended_users: Int32
- )
- end
-
- struct GistStats
- Octokit.rest_model(
- total_gists: Int32,
- private_gists: Int32,
- public_gists: Int32
- )
- end
-
- struct PullStats
- Octokit.rest_model(
- total_pulls: Int32,
- merged_pulls: Int32,
- mergable_pulls: Int32,
- unmergable_pulls: Int32
- )
- end
-
- struct RepoStats
- Octokit.rest_model(
- total_repos: Int32,
- root_repos: Int32,
- fork_repos: Int32,
- org_repos: Int32,
- total_pushes: Int32,
- total_wikis: Int32
- )
- end
- end
-end
diff --git a/lib/octokit/src/octokit/models/apps.cr b/lib/octokit/src/octokit/models/apps.cr
deleted file mode 100644
index 23161fe..0000000
--- a/lib/octokit/src/octokit/models/apps.cr
+++ /dev/null
@@ -1,60 +0,0 @@
-module Octokit
- module Models
- struct App
- Octokit.rest_model(
- id: Int64,
- node_id: String,
- owner: User,
- name: String,
- description: String,
- external_url: String,
- html_url: String,
- created_at: {type: Time, converter: Time::ISO8601Converter},
- updated_at: String
- )
- end
-
- struct InstallationToken
- Octokit.rest_model(
- token: String,
- expires_at: String
- )
- end
-
- struct InstallationPermissions
- Octokit.rest_model(
- metadata: String,
- contents: String,
- issues: String,
- single_file: String
- )
- end
-
- struct Installation
- Octokit.rest_model(
- id: Int64,
- app_id: Int64,
- target_id: Int64,
- account: User,
- access_tokens_url: String,
- repositories_url: String,
- html_url: String,
- target_type: String,
- single_file_name: String,
- repository_selection: String,
- events: Array(String),
- permissions: InstallationPermissions,
- created_at: {type: Time, converter: Time::ISO8601Converter},
- updated_at: String
- )
- end
-
- struct Attachment
- Octokit.rest_model(
- id: Int64,
- title: String,
- body: String
- )
- end
- end
-end
diff --git a/lib/octokit/src/octokit/models/apps_marketplace.cr b/lib/octokit/src/octokit/models/apps_marketplace.cr
deleted file mode 100644
index f77e959..0000000
--- a/lib/octokit/src/octokit/models/apps_marketplace.cr
+++ /dev/null
@@ -1,65 +0,0 @@
-module Octokit
- module Models
- struct MarketplacePlan
- Octokit.rest_model(
- url: String,
- accounts_url: String,
- id: Int64,
- name: String,
- description: String,
- monthly_price_in_cents: Int32,
- yearly_price_in_cents: Int32,
-
- # The pricing model for this listing. Can be one of "flat-rate", "per-unit", or "free"
- # TODO: Make an Enum eventually
- price_model: String,
-
- unit_name: String,
- bullets: Array(String),
-
- # State can be one of "draft" or "published"
- state: String,
-
- has_free_trial: Bool
- )
- end
-
- class MarketplacePurchase
- # Created as a class to prevent recursive struct
- Octokit.rest_model(
- # Billing cycle can be one of "yearly", "monthly", or `nil`.
- billing_cycle: String?,
-
- next_billing_date: String?,
- unit_count: Int32,
- plan: MarketplacePlan,
- account: MarketplacePlanAccount,
- on_free_trial: Bool,
- free_trial_ends_on: String?
- )
- end
-
- struct MarketplacePendingChange
- Octokit.rest_model(
- effective_date: String,
- unit_count: Int32,
- id: Int64,
- plan: MarketplacePlan
- )
- end
-
- struct MarketplacePlanAccount
- Octokit.rest_model(
- url: String,
- type: String,
- id: Int64,
- node_id: String,
- login: String,
- email: String,
- organization_billing_email: String,
- marketplace_purchase: MarketplacePurchase,
- marketplace_pending_change: MarketplacePendingChange
- )
- end
- end
-end
diff --git a/lib/octokit/src/octokit/models/authorizations.cr b/lib/octokit/src/octokit/models/authorizations.cr
deleted file mode 100644
index 53c8c55..0000000
--- a/lib/octokit/src/octokit/models/authorizations.cr
+++ /dev/null
@@ -1,64 +0,0 @@
-require "../core_ext/time"
-require "../helpers"
-
-module Octokit
- module Models
- struct Authorization
- Octokit.rest_model(
- id: Int64,
- url: String,
- scopes: Array(String),
- token: String,
- token_has_eight: String,
- hashed_token: String,
- app: AuthorizationApp,
- note: String,
- note_url: String,
- updated_at: {type: Time, converter: Time::ISO8601Converter},
- created_at: {type: Time, converter: Time::ISO8601Converter},
- fingerprint: String
- )
- end
-
- struct AuthorizationApp
- Octokit.rest_model(
- url: String,
- name: String,
- client_id: String
- )
- end
-
- struct Grant
- Octokit.rest_model(
- id: Int64,
- url: String,
- app: AuthorizationApp,
- created_at: {type: Time, converter: Time::ISO8601Converter},
- updated_at: {type: Time, converter: Time::ISO8601Converter},
- scopes: Array(String)
- )
- end
-
- struct AuthorizationRequest
- Octokit.rest_model(
- scopes: Array(String),
- note: String,
- note_url: String,
- client_id: String,
- client_secret: String,
- fingerprint: String
- )
- end
-
- struct AuthorizationUpdateRequest
- Octokit.rest_model(
- scopes: Array(String),
- add_scopes: Array(String),
- remove_scopes: Array(String),
- note: String,
- note_url: String,
- fingerprint: String
- )
- end
- end
-end
diff --git a/lib/octokit/src/octokit/models/checks.cr b/lib/octokit/src/octokit/models/checks.cr
deleted file mode 100644
index 04eab1b..0000000
--- a/lib/octokit/src/octokit/models/checks.cr
+++ /dev/null
@@ -1,72 +0,0 @@
-module Octokit
- module Models
- struct CheckRun
- Octokit.rest_model(
- id: Int64,
- node_id: String,
- head_sha: String,
- external_id: String,
- url: String,
- html_url: String,
- details_url: String,
- conclusion: String,
- started_at: String,
- completed_at: String,
- output: CheckRunOutput,
- name: String,
- check_suite: CheckSuite,
- app: App,
- pull_requests: Array(PullRequest)
- )
- end
-
- struct CheckRunOutput
- Octokit.rest_model(
- title: String,
- summary: String,
- text: String,
- annotations_count: Int32,
- annotations: Array(CheckRunAnnotation),
- images: Array(CheckRunImage)
- )
- end
-
- struct CheckRunAnnotation
- Octokit.rest_model(
- path: String,
- blob_href: String,
- start_line: Int32,
- end_line: Int32,
- annotation_level: String,
- message: String,
- title: String,
- raw_deals: String
- )
- end
-
- struct CheckRunImage
- Octokit.rest_model(
- alt: String,
- image_url: String,
- caption: String
- )
- end
-
- struct CheckSuite
- Octokit.rest_model(
- id: Int64,
- node_id: String,
- head_branch: String,
- head_sha: String,
- url: String,
- before_sha: String,
- after_sha: String,
- status: String,
- conclusion: String,
- app: App,
- repository: Repository,
- pull_requests: Array(PullRequest)
- )
- end
- end
-end
diff --git a/lib/octokit/src/octokit/models/commits.cr b/lib/octokit/src/octokit/models/commits.cr
deleted file mode 100644
index 743752e..0000000
--- a/lib/octokit/src/octokit/models/commits.cr
+++ /dev/null
@@ -1,38 +0,0 @@
-module Octokit
- module Models
- struct SignatureVerification
- Octokit.rest_model(
- verified: Bool,
- reason: String,
- signature: String,
- payload: String
- )
- end
-
- struct Commit
- Octokit.rest_model(
- sha: String,
- author: CommitAuthor?,
- committer: CommitAuthor?,
- message: String?,
- tree: Tree?,
- parents: Array(Commit)?,
- stats: CommitStats?,
- html_url: String,
- url: String,
- verification: SignatureVerification?,
- node_id: String?
- )
- end
-
- struct CommitAuthor
- Octokit.rest_model(
- date: String?,
- name: String?,
- email: String?,
-
- login: String
- )
- end
- end
-end
diff --git a/lib/octokit/src/octokit/models/event.cr b/lib/octokit/src/octokit/models/event.cr
deleted file mode 100644
index bb6c17b..0000000
--- a/lib/octokit/src/octokit/models/event.cr
+++ /dev/null
@@ -1,17 +0,0 @@
-module Octokit
- module Models
- struct Event
- Octokit.rest_model(
- type: String,
- public: Bool,
- # TODO: Parse the payload
- raw_payload: {key: "payload", type: String},
- repo: Repository,
- actor: User,
- org: Organization,
- created_at: {type: Time, converter: Time::ISO8601Converter},
- id: String
- )
- end
- end
-end
diff --git a/lib/octokit/src/octokit/models/event_types.cr b/lib/octokit/src/octokit/models/event_types.cr
deleted file mode 100644
index 6920eeb..0000000
--- a/lib/octokit/src/octokit/models/event_types.cr
+++ /dev/null
@@ -1,681 +0,0 @@
-module Octokit
- module Models
- struct RequestedAction
- Octokit.rest_model(
- identifier: String
- )
- end
-
- struct CheckRunEvent
- Octokit.rest_model(
- check_run: CheckRun,
-
- # The action performed. Possible values are: "created", "updated", "rerequested", or "requested_action".
- action: String,
-
- # The following fields are only published by Webhook events.
- repo: {key: "repository", type: Repository?},
- org: {key: "organization", type: Organization?},
- sender: User?,
- installation: Installation?,
-
- # The action requested by the user. Populated when the `action` is "requested_action".
- requested_action: RequestedAction?
- )
- end
-
- struct CheckSuiteEvent
- Octokit.rest_model(
- check_suite: CheckSuite,
-
- # The action performed. Possible values are: "completed", "requested" or "rerequested".
- action: String,
-
- # The following fields are only populated by Webhook events.
- repo: {key: "repository", type: Repository?},
- org: {key: "organization", type: Organization?},
- sender: User?,
- installation: Installation?
- )
- end
-
- struct CommitCommentEvent
- Octokit.rest_model(
- comment: RepositoryComment,
-
- # The following fields are only populated by Webhook events.
- action: String?,
- repo: {key: "repository", type: Repository?},
- sender: User?,
- installation: Installation?
- )
- end
-
- struct CreateEvent
- Octokit.rest_model(
- ref: String,
-
- # `ref_type` is the object that was created. Possible values are: "repository", "branch", "tag".
- ref_type: String,
-
- master_branch: String,
- description: String,
-
- # The following fields are only populated by Webhook events.
- pusher_type: String?,
- repo: {key: "repository", type: Repository?},
- sender: User?,
- installation: Installation?
- )
- end
-
- struct DeleteEvent
- Octokit.rest_model(
- ref: String,
-
- # `ref_type` is the object that was deleted. Possible values are: "branch:, "tag".
- ref_type: String,
-
- # The following fields are only populated by Webhook events.
- pusher_type: String?,
- repo: {key: "repository", type: Repository?},
- sender: User?,
- installation: Installation?
- )
- end
-
- struct DeployKeyEvent
- Octokit.rest_model(
- # `action` is the action that was performed. Possible values are: "created" or "deleted".
- action: String,
-
- # The deploy key resource.
- key: Key
- )
- end
-
- struct DeploymentEvent
- Octokit.rest_model(
- deployment: Deployment,
- deployment_status: DeploymentStatus,
- repo: {key: "repository", type: Repository},
-
- # The following fields are only populated by Webhook events.
- sender: User?,
- installation: Installation?
- )
- end
-
- struct DeploymentStatusEvent
- Octokit.rest_model(
- deployment: Deployment,
- deployment_status: DeploymentStatus,
- repo: {key: "repository", type: Repository},
-
- # The following fields are only populated by Webhook events.
- sender: User?,
- installation: Installation?
- )
- end
-
- struct ForkEvent
- Octokit.rest_model(
- # The forkee is the created repository.
- forkee: Repository,
-
- # The following fields are only populated by Webhook events.
- repo: {key: "repository", type: Repository?},
- sender: User?,
- installation: Installation?
- )
- end
-
- struct GitHubAppAuthorizationEvent
- Octokit.rest_model(
- # The action performed. Possible value is: "revoked".
- action: String,
-
- # The following fields are only populated by Webhook events.
- sender: User?
- )
- end
-
- struct Page
- Octokit.rest_model(
- page_name: String,
- title: String,
- summary: String,
- action: String,
- sha: String,
- html_url: String
- )
- end
-
- struct GollumEvent
- Octokit.rest_model(
- pages: Array(Page),
-
- # The following fields are only populated by Webhook events.
- repo: {key: "repository", type: Repository?},
- sender: User?,
- installation: Installation?
- )
- end
-
- struct EditChange
- Octokit.rest_model(
- title: NamedTuple(from: String),
- body: NamedTuple(body: String)
- )
- end
-
- struct ProjectChange
- Octokit.rest_model(
- title: NamedTuple(from: String),
- body: NamedTuple(body: String)
- )
- end
-
- struct ProjectCardChange
- Octokit.rest_model(
- note: NamedTuple(from: String)
- )
- end
-
- struct ProjectColumnChange
- Octokit.rest_model(
- note: NamedTuple(from: String)
- )
- end
-
- struct TeamChange
- Octokit.rest_model(
- description: NamedTuple(from: String),
- name: NamedTuple(from: String),
- privacy: NamedTuple(from: String),
- repository: NamedTuple(permissions: TeamChange::From)
- )
-
- struct From
- Octokit.rest_model(
- admin: Bool,
- pull: Bool,
- push: Bool
- )
- end
- end
-
- struct InstallationEvent
- Octokit.rest_model(
- # The action that was performed. Can be either "created" or "deleted".
- action: String,
-
- repositories: Array(Repository),
- sender: User,
- installation: Installation
- )
- end
-
- struct InstallationRepositoriesEvent
- Octokit.rest_model(
- # The action that was performed. Can be either "added" or "removed".
- action: String,
-
- repositories_added: Array(String),
- repositories_removed: Array(String),
- repository_selection: String,
- sender: User,
- installation: Installation
- )
- end
-
- struct IssueCommentEvent
- Octokit.rest_model(
- # The action that was performed on the comment. Can be either "created", "edited" or "deleted".
- action: String,
- issue: Issue,
- comment: IssueComment,
-
- # The following fields are only populated by Webhook events.
- changes: EditChange?,
- repo: {key: "repository", type: Repository?},
- sender: User?,
- installation: Installation?
- )
- end
-
- struct IssuesEvent
- Octokit.rest_model(
- # Action is the action that was performed. Possible values are: "opened",
- # "edited", "deleted", "transferred", "pinned", "unpinned", "closed", "reopened",
- # "assigned", "unassigned", "labeled", "unlabeled", "locked", "unlocked",
- # "milestoned", or "demilestoned".
- action: String,
-
- issue: Issue,
- assignee: User,
- label: Label,
-
- # The following fields are only populated by Webhook events.
- changes: EditChange?,
- repo: Repository?,
- sender: User?,
- installation: Installation?
- )
- end
-
- struct LabelEvent
- Octokit.rest_model(
- # Action that was performed. Possible values are: "created", "edited" or "deleted".
- action: String,
- label: Label,
-
- # The following fields are only populated by Webhook events.
- changes: EditChange?,
- repo: {key: "repository", type: Repository?},
- org: {key: "organization", type: Organization?},
- installation: Installation?
- )
- end
-
- struct MarketplacePurchaseEvent
- Octokit.rest_model(
- # Action is the action that was performed. Possible values are:
- # "purchased", "cancelled", "pending_change", "pending_change_cancelled", "changed".
- action: String,
-
- # The following fields are only populated by Webhook events.
- effective_date: String?,
- marketplace_purchase: MarketplacePurchase?,
- previous_marketplace_purchase: MarketplacePurchase?,
- sender: User?,
- installation: Installation?
- )
- end
-
- struct MemberEvent
- Octokit.rest_model(
- # `action` that was performed. Possible value is: "added".
- action: String,
- member: User,
-
- # The following fields are only populated by Webhook events.
- repo: {key: "repository", type: Repository?},
- sender: User?,
- installation: Installation?
- )
- end
-
- struct MembershipEvent
- Octokit.rest_model(
- action: String,
-
- scope: String,
- member: String,
- team: String,
-
- org: {key: "organization", type: Organization?},
- sender: User,
- installation: Installation?
- )
- end
-
- struct MetaEvent
- Octokit.rest_model(
- action: String,
-
- hook_id: Int64,
-
- hook: Hook
- )
- end
-
- struct MilestoneEvent
- Octokit.rest_model(
- action: String,
- milestone: Milestone,
-
- changes: EditChange?,
- repo: {key: "repository", type: Repository?},
- sender: User?,
- org: {key: "organization", type: Organization?},
- installation: Installation?
- )
- end
-
- struct OrganizationEvent
- Octokit.rest_model(
- action: String,
-
- invitation: Invitation?,
-
- membership: Membership?,
-
- organization: Organization?,
- sender: User?,
- installation: Installation?
- )
- end
-
- struct OrgBlockEvent
- Octokit.rest_model(
- action: String,
- blocked_user: User,
- organization: Organization,
- sender: User,
-
- installation: Installation?
- )
- end
-
- struct PageBuildEvent
- Octokit.rest_model(
- build: PagesBuild,
-
- id: Int64?,
- repo: {key: "repository", type: Repository?},
- sender: User?,
- installation: Installation?
- )
- end
-
- struct PingEvent
- Octokit.rest_model(
- zen: String,
- hook_id: Int64,
- hook: Hook,
- installation: Installation
- )
- end
-
- struct ProjectEvent
- Octokit.rest_model(
- action: String,
- changes: ProjectChange,
- project: Project,
-
- repo: {key: "repository", type: Repository?},
- org: {key: "organization", type: Organization?},
- sender: User?,
- installation: Installation?
- )
- end
-
- struct ProjectCardEvent
- Octokit.rest_model(
- action: String,
- changes: ProjectCardChange,
- after_id: Int64,
- project_card: ProjectCard,
-
- repo: {key: "repository", type: Repository?},
- org: {key: "organization", type: Organization?},
- sender: User?,
- installation: Installation?
- )
- end
-
- struct ProjectColumnEvent
- Octokit.rest_model(
- action: String,
- changes: ProjectColumnChange,
- after_id: Int64,
- project_column: ProjectColumn,
-
- repo: {key: "repository", type: Repository?},
- org: {key: "organization", type: Organization?},
- sender: User?,
- installation: Installation?
- )
- end
-
- struct PublicEvent
- Octokit.rest_model(
- repo: {key: "repository", type: Repository?},
- sender: User,
- installation: Installation
- )
- end
-
- struct PullRequestEvent
- Octokit.rest_model(
- action: String,
- assignee: User,
- number: Int32,
- pull_request: PullRequest,
-
- changes: EditChange?,
-
- requested_reviewer: User?,
- repo: {key: "repository", type: Repository?},
- sender: User?,
- installation: Installation?,
- label: Label?,
-
- organization: Organization?
- )
- end
-
- struct PullRequestReviewEvent
- Octokit.rest_model(
- action: String,
- review: PullRequestReview,
- pull_request: PullRequest,
-
- repo: {key: "repository", type: Repository?},
- sender: User?,
- installation: Installation?,
-
- organization: Organization?
- )
- end
-
- struct PullRequestReviewCommentEvent
- Octokit.rest_model(
- action: String,
- pull_request: PullRequest,
- comment: PullRequestComment,
-
- changes: EditChange?,
- repo: {key: "repository", type: Repository?},
- sender: User?,
- installation: Installation?
- )
- end
-
- struct PushEvent
- Octokit.rest_model(
- push_id: Int64,
- head: String,
- ref: String,
- size: Int32,
- commits: Array(PushEventCommit),
- before: String,
- distinct_size: Int32,
-
- after: String?,
- created: Bool?,
- deleted: Bool?,
- forced: Bool?,
- base_ref: String?,
- compare: String?,
- repo: {key: "repository", type: PushEventRepository?},
- head_commit: PushEventCommit?,
- pusher: User?,
- sender: User?,
- installation: Installation?
- )
- end
-
- struct PushEventCommit
- Octokit.rest_model(
- message: String,
- author: CommitAuthor,
- url: String,
- distinct: Bool,
-
- sha: String?,
-
- id: String?,
- tree_id: String?,
- timestamp: String?,
- committer: CommitAuthor?,
- added: Array(String)?,
- removed: Array(String)?,
- modified: Array(String)?
- )
- end
-
- struct PushEventRepository
- Octokit.rest_model(
- id: Int64,
- node_id: String,
- name: String,
- full_name: String,
- owner: User,
- private: Bool,
- description: String,
- fork: Bool,
- created_at: {type: Time, converter: Time::ISO8601Converter},
- pushed_at: String,
- updated_at: {type: Time, converter: Time::ISO8601Converter},
- homepage: String,
- size: Int32,
- stargazers_count: Int32,
- watchers_count: Int32,
- language: String,
- has_issues: Bool,
- has_downloads: Bool,
- has_wiki: Bool,
- has_pages: Bool,
- forks_count: Int32,
- open_issues_count: Int32,
- default_branch: String,
- master_branch: String,
- organization: String,
- url: String,
- archive_url: String,
- html_url: String,
- statuses_url: String,
- git_url: String,
- ssh_url: String,
- clone_url: String,
- svn_url: String
- )
- end
-
- struct PushEventRepoOwner
- Octokit.rest_model(
- name: String,
- email: String
- )
- end
-
- struct ReleaseEvent
- Octokit.rest_model(
- action: String,
- release: RepositoryRelease,
-
- repo: {key: "repository", type: Repository?},
- sender: User?,
- installation: Installation?
- )
- end
-
- struct RepositoryEvent
- Octokit.rest_model(
- action: String,
- repo: {key: "repository", type: Repository},
-
- org: {key: "organization", type: Organization?},
- sender: User?,
- installation: Installation?
- )
- end
-
- struct RepositoryVulnerabilityAlertEvent
- Octokit.rest_model(
- action: String,
-
- alert: RepositoryVulnerabilityAlertEvent::Alert
- )
-
- struct Alert
- Octokit.rest_model(
- id: Int64,
- affected_range: String,
- affected_package_name: String,
- external_reference: String,
- external_identifier: String,
- fixed_id: String,
- dismisser: User,
- dismiss_reason: String,
- dismissed_at: String
- )
- end
- end
-
- struct StarEvent
- Octokit.rest_model(
- action: String,
-
- starred_at: String?
- )
- end
-
- struct StatusEvent
- Octokit.rest_model(
- sha: String,
-
- state: String,
- description: String,
- target_url: String,
- branches: Array(Branch),
-
- id: Int64?,
- name: String?,
- context: String?,
- commit: RepositoryCommit?,
- created_at: {type: Time?, converter: Time::ISO8601Converter},
- updated_at: {type: Time?, converter: Time::ISO8601Converter},
- repo: {key: "repository", type: Repository?},
- sender: User?,
- installation: Installation?
- )
- end
-
- struct TeamEvent
- Octokit.rest_model(
- action: String,
- team: Team,
- changes: TeamChange,
- repo: {key: "repository", type: Repository},
-
- org: {key: "organization", type: Organization?},
- sender: User?,
- installation: Installation?
- )
- end
-
- struct TeamAddEvent
- Octokit.rest_model(
- team: Team,
- repo: {key: "repository", type: Repository},
-
- org: {key: "organization", type: Organization?},
- sender: User?,
- installation: Installation?
- )
- end
-
- struct WatchEvent
- Octokit.rest_model(
- action: String,
-
- repo: {key: "repository", type: Repository?},
- sender: User?,
- installation: Installation?
- )
- end
- end
-end
diff --git a/lib/octokit/src/octokit/models/gists.cr b/lib/octokit/src/octokit/models/gists.cr
deleted file mode 100644
index 1b3fdb0..0000000
--- a/lib/octokit/src/octokit/models/gists.cr
+++ /dev/null
@@ -1,49 +0,0 @@
-module Octokit
- module Models
- struct Gists
- Octokit.rest_model(
- id: String,
- description: String,
- public: Bool,
- owner: User,
- files: Hash(String, GistFile),
- comments: Int32,
- html_url: String,
- git_pull_url: String,
- git_push_url: String,
- created_at: {type: Time, converter: Time::ISO8601Converter},
- updated_at: {type: Time, converter: Time::ISO8601Converter},
- node_id: String
- )
- end
-
- struct GistFile
- Octokit.rest_model(
- size: Int32,
- filename: String,
- language: String,
- type: String,
- raw_url: String,
- content: String
- )
- end
-
- struct GistFork
- Octokit.rest_model(
- url: String,
- user: User,
- id: String,
- created_at: {type: Time, converter: Time::ISO8601Converter},
- updated_at: {type: Time, converter: Time::ISO8601Converter},
- node_id: String
- )
- end
-
- struct GistListOptions
- Octokit.rest_model({
- since: String,
- # }.merge(ListOptions::FIELDS))
- })
- end
- end
-end
diff --git a/lib/octokit/src/octokit/models/git_blobs.cr b/lib/octokit/src/octokit/models/git_blobs.cr
deleted file mode 100644
index bd1d511..0000000
--- a/lib/octokit/src/octokit/models/git_blobs.cr
+++ /dev/null
@@ -1,14 +0,0 @@
-module Octokit
- module Models
- struct Blob
- Octokit.rest_model(
- content: String,
- encoding: String,
- sha: String,
- size: Int32,
- url: String,
- node_id: String
- )
- end
- end
-end
diff --git a/lib/octokit/src/octokit/models/git_refs.cr b/lib/octokit/src/octokit/models/git_refs.cr
deleted file mode 100644
index d7323e5..0000000
--- a/lib/octokit/src/octokit/models/git_refs.cr
+++ /dev/null
@@ -1,34 +0,0 @@
-module Octokit
- module Models
- struct Reference
- Octokit.rest_model(
- ref: String,
- url: String,
- object: GitObject,
- node_id: String
- )
- end
-
- struct GitObject
- Octokit.rest_model(
- type: String,
- sha: String,
- url: String
- )
- end
-
- struct CreateRefRequest
- Octokit.rest_model(
- ref: String,
- sha: String
- )
- end
-
- struct UpdateRefRequest
- Octokit.rest_model(
- sha: String,
- force: Bool
- )
- end
- end
-end
diff --git a/lib/octokit/src/octokit/models/git_tags.cr b/lib/octokit/src/octokit/models/git_tags.cr
deleted file mode 100644
index b22e4a2..0000000
--- a/lib/octokit/src/octokit/models/git_tags.cr
+++ /dev/null
@@ -1,26 +0,0 @@
-module Octokit
- module Models
- struct Tag
- Octokit.rest_model(
- tag: String,
- sha: String,
- url: String,
- message: String,
- tagger: CommitAuthor,
- object: GitObject,
- verification: SignatureVerification,
- node_id: String
- )
- end
-
- struct CreateTagRequest
- Octokit.rest_model(
- tag: String,
- message: String,
- object: String,
- type: String,
- tagger: CommitAuthor
- )
- end
- end
-end
diff --git a/lib/octokit/src/octokit/models/git_trees.cr b/lib/octokit/src/octokit/models/git_trees.cr
deleted file mode 100644
index 782d22e..0000000
--- a/lib/octokit/src/octokit/models/git_trees.cr
+++ /dev/null
@@ -1,24 +0,0 @@
-module Octokit
- module Models
- struct Tree
- Octokit.rest_model(
- sha: String,
- entries: Array(TreeEntry),
-
- truncated: Bool
- )
- end
-
- struct TreeEntry
- Octokit.rest_model(
- sha: String,
- path: String,
- mode: String,
- type: String,
- size: Int32,
- content: String,
- url: String
- )
- end
- end
-end
diff --git a/lib/octokit/src/octokit/models/github.cr b/lib/octokit/src/octokit/models/github.cr
deleted file mode 100644
index 5e5320c..0000000
--- a/lib/octokit/src/octokit/models/github.cr
+++ /dev/null
@@ -1,27 +0,0 @@
-module Octokit
- module Models
- struct ListOptions
- Octokit.rest_model(
- page: Int32,
-
- per_page: Int32?
- )
- end
-
- struct UploadOptions
- Octokit.rest_model(
- name: String,
- label: String,
- media_type: String
- )
- end
-
- alias RawType = UInt8
-
- struct RawOptions
- Octokit.rest_model(
- type: RawType
- )
- end
- end
-end
diff --git a/lib/octokit/src/octokit/models/gitignore.cr b/lib/octokit/src/octokit/models/gitignore.cr
deleted file mode 100644
index 0b681a2..0000000
--- a/lib/octokit/src/octokit/models/gitignore.cr
+++ /dev/null
@@ -1,10 +0,0 @@
-module Octokit
- module Models
- struct Gitignore
- Octokit.rest_model(
- name: String,
- source: String
- )
- end
- end
-end
diff --git a/lib/octokit/src/octokit/models/interactions.cr b/lib/octokit/src/octokit/models/interactions.cr
deleted file mode 100644
index 56dda2b..0000000
--- a/lib/octokit/src/octokit/models/interactions.cr
+++ /dev/null
@@ -1,13 +0,0 @@
-module Octokit
- module Models
- struct InteractionsRestriction
- Octokit.rest_model(
- limit: String,
-
- origin: String,
-
- expires_at: String
- )
- end
- end
-end
diff --git a/lib/octokit/src/octokit/models/issue_comments.cr b/lib/octokit/src/octokit/models/issue_comments.cr
deleted file mode 100644
index 532cdac..0000000
--- a/lib/octokit/src/octokit/models/issue_comments.cr
+++ /dev/null
@@ -1,20 +0,0 @@
-module Octokit
- module Models
- struct IssueComment
- Octokit.rest_model(
- id: Int64,
- node_id: String,
- body: String,
- user: User,
- reactions: Reactions,
- created_at: {type: Time, converter: Time::ISO8601Converter},
- updated_at: {type: Time, converter: Time::ISO8601Converter},
-
- author_associations: String?,
- url: String,
- html_url: String,
- issue_url: String
- )
- end
- end
-end
diff --git a/lib/octokit/src/octokit/models/issue_events.cr b/lib/octokit/src/octokit/models/issue_events.cr
deleted file mode 100644
index 777775f..0000000
--- a/lib/octokit/src/octokit/models/issue_events.cr
+++ /dev/null
@@ -1,43 +0,0 @@
-module Octokit
- module Models
- struct IssueEvent
- Octokit.rest_model(
- id: Int64,
- url: String,
-
- actor: User,
-
- event: String,
-
- created_at: {type: Time, converter: Time::ISO8601Converter},
- issue: Issue,
-
- assignee: User?,
- assigner: User?,
- commit_id: String?,
- milestone: Milestone?,
- label: Label?,
- rename: Rename?,
- lock_reason: String?,
- project_card: ProjectCard?,
- dismissed_review: DismissedReview?
- )
- end
-
- struct DismissedReview
- Octokit.rest_model(
- state: String,
- review_id: Int64,
- dismissal_message: String,
- dismissal_commit_id: String
- )
- end
-
- struct Rename
- Octokit.rest_model(
- from: String,
- to: String
- )
- end
- end
-end
diff --git a/lib/octokit/src/octokit/models/issue_labels.cr b/lib/octokit/src/octokit/models/issue_labels.cr
deleted file mode 100644
index 10c88e1..0000000
--- a/lib/octokit/src/octokit/models/issue_labels.cr
+++ /dev/null
@@ -1,15 +0,0 @@
-module Octokit
- module Models
- struct Label
- Octokit.rest_model(
- id: Int64,
- url: String,
- name: String,
- color: String,
- description: String?,
- default: Bool,
- node_id: String
- )
- end
- end
-end
diff --git a/lib/octokit/src/octokit/models/issue_milestones.cr b/lib/octokit/src/octokit/models/issue_milestones.cr
deleted file mode 100644
index bca9946..0000000
--- a/lib/octokit/src/octokit/models/issue_milestones.cr
+++ /dev/null
@@ -1,24 +0,0 @@
-module Octokit
- module Models
- struct Milestone
- Octokit.rest_model(
- url: String,
- html_url: String,
- labels_url: String,
- id: Int64,
- number: Int32,
- state: String,
- title: String,
- description: String?,
- creator: User,
- open_issues: Int32,
- closed_issues: Int32,
- created_at: {type: Time, converter: Time::ISO8601Converter},
- updated_at: {type: Time, converter: Time::ISO8601Converter},
- closed_at: String?,
- due_on: String?,
- node_id: String
- )
- end
- end
-end
diff --git a/lib/octokit/src/octokit/models/issue_timeline.cr b/lib/octokit/src/octokit/models/issue_timeline.cr
deleted file mode 100644
index 207b974..0000000
--- a/lib/octokit/src/octokit/models/issue_timeline.cr
+++ /dev/null
@@ -1,40 +0,0 @@
-module Octokit
- module Models
- struct Timeline
- Octokit.rest_model(
- id: Int64,
- url: String,
- commit_url: String,
-
- actor: User,
-
- event: String,
-
- commit_id: String,
-
- created_at: {type: Time, converter: Time::ISO8601Converter},
-
- label: Label?,
-
- assignee: User?,
-
- milestone: User?,
-
- source: Source?,
-
- rename: Rename?,
- project_card: ProjectCard?
- )
- end
-
- struct Source
- Octokit.rest_model(
- id: Int64,
- url: String,
- actor: User,
- type: String,
- issue: Issue
- )
- end
- end
-end
diff --git a/lib/octokit/src/octokit/models/issues.cr b/lib/octokit/src/octokit/models/issues.cr
deleted file mode 100644
index 0d78069..0000000
--- a/lib/octokit/src/octokit/models/issues.cr
+++ /dev/null
@@ -1,76 +0,0 @@
-module Octokit
- module Models
- struct Issue
- Octokit.rest_model(
- id: Int64,
- number: Int32,
- state: String,
- locked: Bool,
- title: String,
- body: String?,
- user: User,
- labels: Array(Label)?,
- assignee: User?,
- comments: Int32,
- closed_at: String?,
- created_at: {type: Time, converter: Time::ISO8601Converter},
- updated_at: {type: Time?, converter: Time::ISO8601Converter},
- closed_by: User?,
- url: String,
- html_url: String,
- comments_url: String,
- events_url: String,
- labels_url: String,
- repository_url: String,
- milestone: Milestone?,
- pull_request_links: PullRequestLinks?,
- repository: Repository?,
- reactions: Reactions?,
- assignees: Array(User),
- node_id: String,
-
- text_matches: Array(TextMatch)?,
-
- active_lock_reason: String?
- )
- end
-
- struct IssueRequest
- Octokit.rest_model(
- title: String,
- body: String,
- labels: Array(String),
- assignee: String,
- state: String,
- milestone: Int32,
- assignees: Array(String)
- )
- end
-
- struct IssueListOptions
- Octokit.rest_model({
- filter: String,
-
- state: String,
-
- labels: Array(String),
-
- sort: String,
-
- direction: String,
-
- since: String,
- # }.merge(ListOptions::FIELDS))
- })
- end
-
- struct PullRequestLinks
- Octokit.rest_model(
- url: String,
- html_url: String,
- diff_url: String,
- patch_url: String
- )
- end
- end
-end
diff --git a/lib/octokit/src/octokit/models/licenses.cr b/lib/octokit/src/octokit/models/licenses.cr
deleted file mode 100644
index 5addb9c..0000000
--- a/lib/octokit/src/octokit/models/licenses.cr
+++ /dev/null
@@ -1,39 +0,0 @@
-module Octokit
- module Models
- struct RepositoryLicense
- Octokit.rest_model(
- name: String,
- path: String,
-
- sha: String,
- size: Int32,
- url: String,
- html_url: String,
- git_url: String,
- download_url: String,
- type: String,
- content: String,
- encoding: String,
- license: License
- )
- end
-
- struct License
- Octokit.rest_model(
- key: String,
- name: String,
- url: String?,
-
- spdx_id: String,
- html_url: String?,
- featured: Bool?,
- description: String?,
- implementation: String?,
- permissions: Array(String)?,
- conditions: Array(String)?,
- limitations: Array(String)?,
- body: String?
- )
- end
- end
-end
diff --git a/lib/octokit/src/octokit/models/migration_source_import.cr b/lib/octokit/src/octokit/models/migration_source_import.cr
deleted file mode 100644
index 6392d3b..0000000
--- a/lib/octokit/src/octokit/models/migration_source_import.cr
+++ /dev/null
@@ -1,62 +0,0 @@
-module Octokit
- module Models
- struct Import
- Octokit.rest_model(
- vcs_url: String,
-
- vcs: String,
-
- vcs_username: String?,
- vcs_password: String?,
-
- tfvc_project: String?,
-
- use_lfs: String,
-
- has_large_files: Bool,
-
- large_file_size: Int32,
-
- large_files_count: Int32,
-
- status: String,
- commit_count: Int32,
- status_text: String,
- authors_count: Int32,
- percent: Int32,
- push_percent: Int32,
- url: String,
- html_url: String,
- authors_url: String,
- repository_url: String,
- message: String,
- failed_step: String,
-
- human_name: String?,
-
- project_choices: Array(Import)
- )
- end
-
- struct SourceImportAuthor
- Octokit.rest_model(
- id: Int64,
- remote_id: String,
- remote_name: String,
- email: String,
- name: String,
- url: String,
- import_url: String
- )
- end
-
- struct LargeFile
- Octokit.rest_model(
- ref_name: String,
- path: String,
- oid: String,
- size: Int32
- )
- end
- end
-end
diff --git a/lib/octokit/src/octokit/models/migration_user.cr b/lib/octokit/src/octokit/models/migration_user.cr
deleted file mode 100644
index 1a9ec4f..0000000
--- a/lib/octokit/src/octokit/models/migration_user.cr
+++ /dev/null
@@ -1,37 +0,0 @@
-module Octokit
- module Models
- struct UserMigration
- Octokit.rest_model(
- id: Int64,
- guid: String,
-
- state: String,
-
- lock_repositories: Bool,
-
- exclude_attachments: Bool,
- url: String,
- created_at: {type: Time, converter: Time::ISO8601Converter},
- updated_at: {type: Time, converter: Time::ISO8601Converter},
- repositories: Array(Repository)
- )
- end
-
- struct UserMigrationOptions
- Octokit.rest_model(
- lock_repositories: Bool?,
- exclude_attachments: Bool?
- )
- end
-
- struct StartUserMigration
- Octokit.rest_model(
- repositories: Array(String)?,
-
- lock_repositories: Bool?,
-
- exclude_attachments: Bool?
- )
- end
- end
-end
diff --git a/lib/octokit/src/octokit/models/migrations.cr b/lib/octokit/src/octokit/models/migrations.cr
deleted file mode 100644
index 8096948..0000000
--- a/lib/octokit/src/octokit/models/migrations.cr
+++ /dev/null
@@ -1,37 +0,0 @@
-module Octokit
- module Models
- struct Migration
- Octokit.rest_model(
- id: Int64,
- guid: String,
-
- state: String,
-
- lock_repositories: Bool,
-
- exclude_attachments: Bool,
- url: String,
- created_at: {type: Time, converter: Time::ISO8601Converter},
- updated_at: {type: Time, converter: Time::ISO8601Converter},
- repositories: Array(Repository)
- )
- end
-
- struct MigrationOptions
- Octokit.rest_model(
- lock_repositories: Bool,
- exclude_attachments: Bool
- )
- end
-
- struct StartMigration
- Octokit.rest_model(
- repositories: Array(String),
-
- lock_repositories: Bool?,
-
- exclude_attachments: Bool?
- )
- end
- end
-end
diff --git a/lib/octokit/src/octokit/models/misc.cr b/lib/octokit/src/octokit/models/misc.cr
deleted file mode 100644
index d803f7a..0000000
--- a/lib/octokit/src/octokit/models/misc.cr
+++ /dev/null
@@ -1,42 +0,0 @@
-module Octokit
- module Models
- struct MarkdownOptions
- Octokit.rest_model(
- mode: String?,
-
- context: String?
- )
- end
-
- struct MarkdownRequest
- Octokit.rest_model(
- text: String?,
- mode: String?,
- context: String?
- )
- end
-
- struct CodeOfConduct
- Octokit.rest_model(
- name: String,
- key: String,
- url: String,
- body: String
- )
- end
-
- struct APIMeta
- Octokit.rest_model(
- hooks: Array(String),
-
- git: Array(String),
-
- verifiable_password_authentication: Bool,
-
- pages: Array(String),
-
- importer: Array(String)
- )
- end
- end
-end
diff --git a/lib/octokit/src/octokit/models/oauth.cr b/lib/octokit/src/octokit/models/oauth.cr
deleted file mode 100644
index 9189f07..0000000
--- a/lib/octokit/src/octokit/models/oauth.cr
+++ /dev/null
@@ -1,13 +0,0 @@
-module Octokit
- module Models
- struct AccessToken
- Octokit.rest_model(
- access_token: String,
- token_type: String,
-
- # Can be received with a modified accept header
- scope: String?
- )
- end
- end
-end
diff --git a/lib/octokit/src/octokit/models/org_members.cr b/lib/octokit/src/octokit/models/org_members.cr
deleted file mode 100644
index 7e42db9..0000000
--- a/lib/octokit/src/octokit/models/org_members.cr
+++ /dev/null
@@ -1,48 +0,0 @@
-module Octokit
- module Models
- struct Membership
- Octokit.rest_model(
- url: String,
-
- state: String,
-
- role: String,
-
- organization_url: String,
-
- organization: Organization,
-
- user: User
- )
- end
-
- struct ListMembershipOptions
- Octokit.rest_model({
- public_only: Bool,
-
- filter: String,
-
- role: String,
- # }.merge(ListOptions::FIELDS))
- })
- end
-
- struct ListOrgMembershipOptions
- Octokit.rest_model({
- state: String,
- # }.merge(ListOptions::FIELDS))
- })
- end
-
- struct CreateOrgInvitationOptions
- Octokit.rest_model(
- invitee_id: Int64,
-
- email: String,
-
- role: String,
- team_id: Int64
- )
- end
- end
-end
diff --git a/lib/octokit/src/octokit/models/org_outside_collaborators.cr b/lib/octokit/src/octokit/models/org_outside_collaborators.cr
deleted file mode 100644
index 528f250..0000000
--- a/lib/octokit/src/octokit/models/org_outside_collaborators.cr
+++ /dev/null
@@ -1,10 +0,0 @@
-module Octokit
- module Models
- struct ListOutsideCollaboratorsOptions
- Octokit.rest_model({
- filter: String,
- # }.merge(ListOptions::FIELDS))
- })
- end
- end
-end
diff --git a/lib/octokit/src/octokit/models/orgs.cr b/lib/octokit/src/octokit/models/orgs.cr
deleted file mode 100644
index 59f66bf..0000000
--- a/lib/octokit/src/octokit/models/orgs.cr
+++ /dev/null
@@ -1,92 +0,0 @@
-require "../core_ext/time"
-require "../helpers"
-
-module Octokit
- module Models
- struct Organization
- def path
- Organization.path(self)
- end
-
- def self.path(org)
- "orgs/#{org}"
- end
-
- Octokit.rest_model(
- login: String,
- id: Int64,
- node_id: String,
- avatar_url: String,
- html_url: String,
- name: String,
- company: String,
- blog: String,
- location: String,
- email: String,
- description: String,
- public_repos: Int32,
- public_gists: Int32,
- followers: Int32,
- following: Int32,
- created_at: {type: Time, converter: Time::ISO8601Converter},
- updated_at: {type: Time, converter: Time::ISO8601Converter},
- total_private_repos: Int32,
- owned_private_repos: Int32,
- private_gists: Int32,
- disk_usage: Int32,
- collaborators: Int32,
- billing_email: String,
- type: String,
- plan: Plan,
- two_factor_requirement_enabled: Bool,
-
- default_repo_permission: String,
-
- default_repo_settings: String,
-
- members_can_create_repos: Bool,
-
- url: String,
- events_url: String,
- hooks_url: String,
- issues_url: String,
- members_url: String,
- public_members_url: String,
- repos_url: String
- )
- end
-
- struct OrganizationListItem
- Octokit.rest_model(
- login: String,
- id: Int32,
- node_id: String,
- url: String,
- repos_url: String,
- events_url: String,
- hooks_url: String,
- issues_url: String,
- members_url: String,
- public_members_url: String,
- avatar_url: String,
- description: String | Nil
- )
- end
-
- struct Plan
- Octokit.rest_model(
- name: String,
- space: Int32,
- collaborators: Int32,
- private_repos: Int32
- )
- end
-
- struct OrganizationsListOptions
- Octokit.rest_model({
- since: Int64,
- # }.merge(ListOptions::FIELDS))
- })
- end
- end
-end
diff --git a/lib/octokit/src/octokit/models/projects.cr b/lib/octokit/src/octokit/models/projects.cr
deleted file mode 100644
index 6e77bdb..0000000
--- a/lib/octokit/src/octokit/models/projects.cr
+++ /dev/null
@@ -1,128 +0,0 @@
-module Octokit
- module Models
- struct Project
- Octokit.rest_model(
- id: Int64,
- url: String,
- html_url: String,
- columns_url: String,
- name: String,
- body: String,
- number: Int32,
- state: String,
- created_at: {type: Time, converter: Time::ISO8601Converter},
- updated_at: {type: Time, converter: Time::ISO8601Converter},
- node_id: String,
-
- creator: User
- )
- end
-
- struct ProjectOptions
- Octokit.rest_model(
- name: String,
-
- body: String,
-
- state: String,
-
- organization_permission: String,
-
- public: Bool
- )
- end
-
- struct ProjectColumn
- Octokit.rest_model(
- id: Int64,
- name: String,
- url: String,
- projects_url: String,
- cards_url: String,
- created_at: {type: Time, converter: Time::ISO8601Converter},
- updated_at: {type: Time, converter: Time::ISO8601Converter},
- node_id: String
- )
- end
-
- struct ProjectColumnOptions
- Octokit.rest_model(
- name: String
- )
- end
-
- struct ProjectColumnMoveOptions
- Octokit.rest_model(
- position: String
- )
- end
-
- struct ProjectCard
- Octokit.rest_model(
- url: String,
- columns_url: String,
- content_url: String,
- id: Int64,
- note: String,
- creator: User,
- created_at: {type: Time, converter: Time::ISO8601Converter},
- updated_at: {type: Time, converter: Time::ISO8601Converter},
- node_id: String,
- archived: Bool,
-
- column_id: Int64?,
-
- project_id: Int64?,
- project_url: String?,
- column_name: String?,
- previous_column_name: String?
- )
- end
-
- struct ProjectCardListOptions
- Octokit.rest_model({
- archived_state: String,
- # }.merge(ListOptions::FIELDS))
- })
- end
-
- struct ProjectCardOptions
- Octokit.rest_model(
- note: String,
-
- content_id: Int64,
-
- content_type: String,
-
- archived: Bool
- )
- end
-
- struct ProjectCardMoveOptions
- Octokit.rest_model(
- position: String,
- column_id: Int64
- )
- end
-
- struct ProjectCollaboratorOptions
- Octokit.rest_model(
- permission: String
- )
- end
-
- struct ListCollaboratorOptions
- Octokit.rest_model({
- affiliation: String,
- # }.merge(ListOptions::FIELDS))
- })
- end
-
- struct ProjectPermissionLevel
- Octokit.rest_model(
- permission: String,
- user: User
- )
- end
- end
-end
diff --git a/lib/octokit/src/octokit/models/pull_comments.cr b/lib/octokit/src/octokit/models/pull_comments.cr
deleted file mode 100644
index b71615c..0000000
--- a/lib/octokit/src/octokit/models/pull_comments.cr
+++ /dev/null
@@ -1,39 +0,0 @@
-module Octokit
- module Models
- struct PullRequestComment
- Octokit.rest_model(
- id: Int64,
- node_id: String,
- in_reply_to: Int64?,
- body: String,
- path: String,
- diff_hunk: String,
- pull_request_review_id: Int64,
- position: Int32,
- original_position: Int32,
- commit_id: String,
- original_commit_id: String,
- user: User,
- reactions: Reactions,
- created_at: {type: Time, converter: Time::ISO8601Converter},
- updated_at: {type: Time, converter: Time::ISO8601Converter},
-
- author_association: String,
- url: String,
- html_url: String,
- pull_request_url: String
- )
- end
-
- struct PullRequestListCommentOptions
- Octokit.rest_model({
- sort: String,
-
- direction: String,
-
- since: String,
- # }.merge(ListOptions::FIELDS))
- })
- end
- end
-end
diff --git a/lib/octokit/src/octokit/models/pull_reviewers.cr b/lib/octokit/src/octokit/models/pull_reviewers.cr
deleted file mode 100644
index 9448ad8..0000000
--- a/lib/octokit/src/octokit/models/pull_reviewers.cr
+++ /dev/null
@@ -1,18 +0,0 @@
-module Octokit
- module Models
- struct ReviewersRequest
- Octokit.rest_model(
- node_id: String,
- reviewers: Array(String),
- team_reviewers: Array(String)
- )
- end
-
- struct Reviewers
- Octokit.rest_model(
- users: User,
- teams: Team
- )
- end
- end
-end
diff --git a/lib/octokit/src/octokit/models/pull_reviews.cr b/lib/octokit/src/octokit/models/pull_reviews.cr
deleted file mode 100644
index 736e903..0000000
--- a/lib/octokit/src/octokit/models/pull_reviews.cr
+++ /dev/null
@@ -1,41 +0,0 @@
-module Octokit
- module Models
- struct PullRequestReview
- Octokit.rest_model(
- id: Int64,
- node_id: String,
- user: User,
- body: String,
- submitted_at: String,
- commit_id: String,
- html_url: String,
- pull_request_url: String,
- state: String
- )
- end
-
- struct DraftReviewComment
- Octokit.rest_model(
- path: String,
- position: Int32,
- body: String
- )
- end
-
- struct PullRequestReviewRequest
- Octokit.rest_model(
- node_id: String,
- commit_id: String,
- body: String,
- event: String,
- comments: Array(DraftReviewComment)
- )
- end
-
- struct PullRequestReviewDismissalRequest
- Octokit.rest_model(
- message: String
- )
- end
- end
-end
diff --git a/lib/octokit/src/octokit/models/pulls.cr b/lib/octokit/src/octokit/models/pulls.cr
deleted file mode 100644
index 0e69831..0000000
--- a/lib/octokit/src/octokit/models/pulls.cr
+++ /dev/null
@@ -1,146 +0,0 @@
-require "../core_ext/time"
-require "./issue_labels"
-
-module Octokit
- module Models
- struct PullRequest
- Octokit.rest_model(
- id: Int64,
- number: Int32,
- state: String,
- title: String,
- body: String?,
- created_at: {type: Time, converter: Time::ISO8601Converter},
- updated_at: {type: Time, converter: Time::ISO8601Converter},
- closed_at: String?,
- merged_at: String?,
- labels: Array(Label)?,
- user: User,
- draft: Bool,
- merged: Bool?,
- mergeable: Bool?,
- mergeable_state: String?,
- merged_by: String?,
- merge_commit_sha: String,
- comments: Int32?,
- commits: Int32?,
- additions: Int32?,
- deletions: Int32?,
- changed_files: Int32?,
- url: String,
- html_url: String,
- issue_url: String,
- statuses_url: String,
- diff_url: String,
- patch_url: String,
- commits_url: String,
- comments_url: String,
- review_comment_url: String,
- review_comments: Int32?,
- assignee: User?,
- assignees: Array(User)?,
- milestone: Milestone?,
- maintainer_can_modify: Bool?,
- author_association: String,
- node_id: String,
- requested_reviewers: Array(User),
-
- requested_teams: Array(Team),
-
- links: PRLinks?,
- head: PullRequestBranch,
- base: PullRequestBranch,
-
- active_lock_reason: String?
- )
- end
-
- struct PRLink
- Octokit.rest_model(
- href: String
- )
- end
-
- struct PRLinks
- Octokit.rest_model(
- this: {key: "self", type: PRLink},
- html: PRLink,
- issue: PRLink,
- comments: PRLink,
- review_comments: PRLink,
- review_comment: PRLink,
- commits: PRLink,
- statuses: PRLink
- )
- end
-
- struct PullRequestBranch
- Octokit.rest_model(
- label: String,
- ref: String,
- sha: String,
- repo: Repository?,
- user: User
- )
- end
-
- struct PullRequestListOptions
- Octokit.rest_model({
- state: String,
- head: String,
- base: String,
- sort: String,
- direction: String,
- # }.merge(ListOptions::FIELDS))
- })
- end
-
- struct NewPullRequest
- Octokit.rest_model(
- title: String,
- head: String,
- base: String,
- body: String,
- issue: Int32,
- maintainer_can_modify: Bool,
- draft: Bool
- )
- end
-
- struct PullRequestUpdate
- Octokit.rest_model(
- title: String,
- body: String,
- state: String,
- base: String,
- maintainer_can_modify: Bool
- )
- end
-
- struct PullRequestMergeResult
- Octokit.rest_model(
- sha: String,
- merged: Bool,
- message: String
- )
- end
-
- struct PullRequestOptions
- Octokit.rest_model(
- commit_title: String,
- sha: String,
-
- merge_method: String
- )
- end
-
- struct PullRequestMergeRequest
- Octokit.rest_model(
- commit_message: String,
- commit_title: String,
- merge_method: String,
- sha: String
- )
- end
- end
-end
diff --git a/lib/octokit/src/octokit/models/reactions.cr b/lib/octokit/src/octokit/models/reactions.cr
deleted file mode 100644
index eb9539a..0000000
--- a/lib/octokit/src/octokit/models/reactions.cr
+++ /dev/null
@@ -1,26 +0,0 @@
-module Octokit
- module Models
- struct Reaction
- Octokit.rest_model(
- id: Int64,
- user: User,
- node_id: String,
-
- content: String
- )
- end
-
- struct Reactions
- Octokit.rest_model(
- total_count: Int32,
- plus_one: {type: Int32, key: "+1"},
- minus_one: {type: Int32, key: "-1"},
- laugh: Int32,
- confused: Int32,
- heart: Int32,
- hooray: Int32,
- url: String
- )
- end
- end
-end
diff --git a/lib/octokit/src/octokit/models/repo_branches.cr b/lib/octokit/src/octokit/models/repo_branches.cr
deleted file mode 100644
index efd9131..0000000
--- a/lib/octokit/src/octokit/models/repo_branches.cr
+++ /dev/null
@@ -1,38 +0,0 @@
-module Octokit
- module Models
- struct Branch
- Octokit.rest_model(
- name: String,
- commit: BranchCommit,
- protected: Bool,
- protection: BranchProtection,
- protection_url: String
- )
- end
-
- struct BranchCommit
- Octokit.rest_model(
- sha: String,
- url: String
- )
- end
-
- struct BranchProtection
- Octokit.rest_model(
- enabled: Bool,
- required_status_checks: BranchProtectionRequiredStatusChecks
- )
- end
-
- struct BranchProtectionRequiredStatusChecks
- Octokit.rest_model(
- enforcement_level: String,
- contexts: Array(String)
- )
- end
-
- struct BranchProtectionSummary
- # Octokit.rest_model # TODO
- end
- end
-end
diff --git a/lib/octokit/src/octokit/models/repo_collaborators.cr b/lib/octokit/src/octokit/models/repo_collaborators.cr
deleted file mode 100644
index a45fc0b..0000000
--- a/lib/octokit/src/octokit/models/repo_collaborators.cr
+++ /dev/null
@@ -1,23 +0,0 @@
-module Octokit
- module Models
- struct ListCollaboratorOptions
- Octokit.rest_model({
- affiliation: String,
- # }.merge(ListOptions::FIELDS))
- })
- end
-
- struct RepositoryPermissionLevel
- Octokit.rest_model(
- permission: String,
- user: User
- )
- end
-
- struct RepositoryAddCollaboratorOptions
- Octokit.rest_model(
- permission: String
- )
- end
- end
-end
diff --git a/lib/octokit/src/octokit/models/repo_comments.cr b/lib/octokit/src/octokit/models/repo_comments.cr
deleted file mode 100644
index 6c85eaa..0000000
--- a/lib/octokit/src/octokit/models/repo_comments.cr
+++ /dev/null
@@ -1,21 +0,0 @@
-module Octokit
- module Models
- struct RepositoryComment
- Octokit.rest_model(
- html_url: String,
- url: String,
- id: Int64,
- commit_id: String,
- user: User,
- reactions: Reactions,
- created_at: {type: Time, converter: Time::ISO8601Converter},
- updated_at: {type: Time, converter: Time::ISO8601Converter},
-
- body: String,
-
- path: String,
- position: Int32
- )
- end
- end
-end
diff --git a/lib/octokit/src/octokit/models/repo_commits.cr b/lib/octokit/src/octokit/models/repo_commits.cr
deleted file mode 100644
index b771999..0000000
--- a/lib/octokit/src/octokit/models/repo_commits.cr
+++ /dev/null
@@ -1,81 +0,0 @@
-module Octokit
- module Models
- struct RepositoryCommit
- Octokit.rest_model(
- node_id: String,
- sha: String,
- commit: Commit,
- author: User,
- committer: User,
- parents: Array(Commit),
- html_url: String,
- url: String,
- comments_url: String,
-
- stats: CommitStats,
- files: Array(CommitFile)
- )
- end
-
- struct CommitStats
- Octokit.rest_model(
- additions: Int32,
- deletions: Int32,
- total: Int32
- )
- end
-
- struct CommitFile
- Octokit.rest_model(
- sha: String,
- filename: String,
- additions: Int32,
- deletions: Int32,
- changes: Int32,
- status: String,
- patch: String?,
- blob_url: String,
- raw_url: String,
- contents_url: String,
- previous_filename: String?
- )
- end
-
- struct CommitsComparison
- Octokit.rest_model(
- base_commit: RepositoryCommit,
- merge_base_commit: RepositoryCommit,
-
- status: String,
- ahead_by: Int32,
- behind_by: Int32,
- total_commits: Int32,
-
- commits: Array(RepositoryCommit),
-
- files: Array(CommitFile),
-
- html_url: String,
- permalink: String,
- diff_url: String,
- patch_url: String,
- url: String
- )
- end
-
- struct CommitListOptions
- Octokit.rest_model({
- sha: String,
-
- path: String,
-
- author: String,
-
- since: String,
-
- until: String,
- # }.merge(ListOptions::FIELDS))
- })
- end
- end
-end
diff --git a/lib/octokit/src/octokit/models/repo_community_health.cr b/lib/octokit/src/octokit/models/repo_community_health.cr
deleted file mode 100644
index 4bbec0a..0000000
--- a/lib/octokit/src/octokit/models/repo_community_health.cr
+++ /dev/null
@@ -1,31 +0,0 @@
-module Octokit
- module Models
- struct Metric
- Octokit.rest_model(
- name: String,
- key: String,
- url: String,
- html_url: String
- )
- end
-
- struct CommunityHealthFiles
- Octokit.rest_model(
- code_of_conduct: Metric,
- contributing: Metric,
- issue_template: Metric,
- pull_request_template: Metric,
- license: Metric,
- readme: Metric
- )
- end
-
- struct CommunityHealthMetrics
- Octokit.rest_model(
- health_percentage: Int32,
- files: CommunityHealthFiles,
- updated_at: String
- )
- end
- end
-end
diff --git a/lib/octokit/src/octokit/models/repo_contents.cr b/lib/octokit/src/octokit/models/repo_contents.cr
deleted file mode 100644
index 04aa9a7..0000000
--- a/lib/octokit/src/octokit/models/repo_contents.cr
+++ /dev/null
@@ -1,46 +0,0 @@
-module Octokit
- module Models
- struct RepositoryContent
- Octokit.rest_model(
- type: String,
-
- target: String,
- encoding: String,
- size: String,
- name: String,
- path: String,
-
- content: String,
- sha: String,
- url: String,
- git_url: String,
- html_url: String,
- download_url: String
- )
- end
-
- struct RepositoryContentResponse
- Octokit.rest_model(
- content: RepositoryContent,
- commit: Commit
- )
- end
-
- struct RepositoryContentFileOptions
- Octokit.rest_model(
- message: String,
- content: Array(UInt8),
- sha: String,
- branch: String,
- author: CommitAuthor,
- commiter: CommitAuthor
- )
- end
-
- struct RepositoryContentGetOptions
- Octokit.rest_model(
- ref: String
- )
- end
- end
-end
diff --git a/lib/octokit/src/octokit/models/repo_deployments.cr b/lib/octokit/src/octokit/models/repo_deployments.cr
deleted file mode 100644
index 3d48301..0000000
--- a/lib/octokit/src/octokit/models/repo_deployments.cr
+++ /dev/null
@@ -1,78 +0,0 @@
-require "./users"
-
-module Octokit
- module Models
- struct Deployment
- Octokit.rest_model(
- url: String,
- id: Int64,
- sha: String,
- ref: String,
- task: String,
- payload: String,
- environment: String,
- description: String,
- creator: User,
- created_at: {type: Time, converter: Time::ISO8601Converter},
- updated_at: {type: Time, converter: Time::ISO8601Converter},
- statuses_url: String,
- repository_url: String,
- node_id: String
- )
- end
-
- struct DeploymentRequest
- Octokit.rest_model(
- ref: String,
- task: String,
- auto_merge: Bool,
- required_contexts: Array(String),
- payload: String,
- environment: String,
- description: String,
- transient_environment: Bool,
- production_environment: Bool
- )
- end
-
- struct DeploymentsListOptions
- Octokit.rest_model({
- sha: String,
-
- ref: String,
-
- task: String,
-
- environment: String,
- # }.merge(ListOptions::FIELDS))
- })
- end
-
- struct DeploymentStatus
- Octokit.rest_model(
- id: Int64,
-
- state: String,
- creator: User,
- description: String,
- target_url: String,
- created_at: {type: Time, converter: Time::ISO8601Converter},
- updated_at: {type: Time, converter: Time::ISO8601Converter},
- deployment_url: String,
- repository_url: String,
- node_id: String
- )
- end
-
- struct DeploymentStatusRequest
- Octokit.rest_model(
- state: String,
- log_url: String,
- description: String,
- environment: String,
- environment_url: String,
- auto_inactive: Bool
- )
- end
- end
-end
diff --git a/lib/octokit/src/octokit/models/repo_forks.cr b/lib/octokit/src/octokit/models/repo_forks.cr
deleted file mode 100644
index 154de33..0000000
--- a/lib/octokit/src/octokit/models/repo_forks.cr
+++ /dev/null
@@ -1,18 +0,0 @@
-require "../helpers"
-
-module Octokit
- module Models
- struct RepositoryListForksOptions
- Octokit.rest_model({
- sort: String,
- # }.merge(ListOptions::FIELDS))
- })
- end
-
- struct RepositoryCreateForkOptions
- Octokit.rest_model(
- organization: String
- )
- end
- end
-end
diff --git a/lib/octokit/src/octokit/models/repo_hooks.cr b/lib/octokit/src/octokit/models/repo_hooks.cr
deleted file mode 100644
index 36b0347..0000000
--- a/lib/octokit/src/octokit/models/repo_hooks.cr
+++ /dev/null
@@ -1,64 +0,0 @@
-module Octokit
- module Models
- struct WebHookPayload
- Octokit.rest_model(
- after: String,
- before: String,
- commits: Array(String),
- compare: String,
- created: Bool,
- deleted: Bool,
- forced: Bool,
- head_commit: WebHookCommit,
- pusher: User,
- ref: String,
- repo: Repository,
- sender: User
- )
- end
-
- struct WebHookCommit
- Octokit.rest_model(
- added: Array(String),
- author: WebHookAuthor,
- committer: WebHookAuthor,
- distinct: Bool,
- id: String,
- message: Array(String),
- modified: Array(String),
- removed: Array(String),
- timestamp: String
- )
- end
-
- struct WebHookAuthor
- Octokit.rest_model(
- email: String,
- name: String,
- username: String
- )
- end
-
- struct Hook
- Octokit.rest_model(
- created_at: {type: Time, converter: Time::ISO8601Converter},
- updated_at: {type: Time, converter: Time::ISO8601Converter},
- url: String,
- id: Int64,
-
- config: Hash(String, String),
- events: Array(String),
- active: Bool
- )
- end
-
- struct CreateHookRequest
- Octokit.rest_model(
- name: String?,
- config: Hash(String, String)?,
- events: Array(String)?,
- active: Bool?
- )
- end
- end
-end
diff --git a/lib/octokit/src/octokit/models/repo_invitations.cr b/lib/octokit/src/octokit/models/repo_invitations.cr
deleted file mode 100644
index 74d2f5e..0000000
--- a/lib/octokit/src/octokit/models/repo_invitations.cr
+++ /dev/null
@@ -1,17 +0,0 @@
-module Octokit
- module Models
- struct RepositoryInvitation
- Octokit.rest_model(
- id: Int64,
- repo: Repository,
- invitee: User,
- inviter: User,
-
- permissions: String,
- created_at: {type: Time, converter: Time::ISO8601Converter},
- url: String,
- html_url: String
- )
- end
- end
-end
diff --git a/lib/octokit/src/octokit/models/repo_merging.cr b/lib/octokit/src/octokit/models/repo_merging.cr
deleted file mode 100644
index 7059daf..0000000
--- a/lib/octokit/src/octokit/models/repo_merging.cr
+++ /dev/null
@@ -1,13 +0,0 @@
-require "../helpers"
-
-module Octokit
- module Models
- struct RepositoryMergeRequest
- Octokit.rest_model(
- base: String,
- head: String,
- commit_message: String
- )
- end
- end
-end
diff --git a/lib/octokit/src/octokit/models/repo_pages.cr b/lib/octokit/src/octokit/models/repo_pages.cr
deleted file mode 100644
index 3891e5f..0000000
--- a/lib/octokit/src/octokit/models/repo_pages.cr
+++ /dev/null
@@ -1,40 +0,0 @@
-module Octokit
- module Models
- struct Pages
- Octokit.rest_model(
- url: String,
- status: String,
- cname: String,
- custom_404: String,
- html_url: String,
- source: PagesSource
- )
- end
-
- struct PagesSource
- Octokit.rest_model(
- branch: String,
- path: String
- )
- end
-
- struct PagesError
- Octokit.rest_model(
- message: String
- )
- end
-
- struct PagesBuild
- Octokit.rest_model(
- url: String,
- status: String,
- error: PagesError,
- pusher: User,
- commit: String,
- duration: Int32,
- created_at: {type: Time, converter: Time::ISO8601Converter},
- updated_at: String
- )
- end
- end
-end
diff --git a/lib/octokit/src/octokit/models/repo_prereceive_hooks.cr b/lib/octokit/src/octokit/models/repo_prereceive_hooks.cr
deleted file mode 100644
index f14818c..0000000
--- a/lib/octokit/src/octokit/models/repo_prereceive_hooks.cr
+++ /dev/null
@@ -1,14 +0,0 @@
-require "../helpers"
-
-module Octokit
- module Models
- struct PreReceiveHook
- Octokit.rest_model(
- id: Int64,
- name: String,
- enforcement: String,
- config_url: String
- )
- end
- end
-end
diff --git a/lib/octokit/src/octokit/models/repo_projects.cr b/lib/octokit/src/octokit/models/repo_projects.cr
deleted file mode 100644
index 57060b3..0000000
--- a/lib/octokit/src/octokit/models/repo_projects.cr
+++ /dev/null
@@ -1,12 +0,0 @@
-require "../helpers"
-
-module Octokit
- module Models
- struct ProjctListOptions
- Octokit.rest_model({
- state: String,
- # }.merge(ListOptions::FIELDS))
- })
- end
- end
-end
diff --git a/lib/octokit/src/octokit/models/repo_releases.cr b/lib/octokit/src/octokit/models/repo_releases.cr
deleted file mode 100644
index b5a77f7..0000000
--- a/lib/octokit/src/octokit/models/repo_releases.cr
+++ /dev/null
@@ -1,56 +0,0 @@
-module Octokit
- module Models
- struct RepositoryRelease
- Octokit.rest_model(
- tag_name: String,
- target_commitish: String,
- name: String,
- body: String,
- draft: Bool,
- prerelease: Bool,
-
- id: Int64?,
- created_at: {type: Time?, converter: Time::ISO8601Converter},
- published_at: String?,
- url: String?,
- html_url: String?,
- assets_url: String?,
- assets: Array(ReleaseAsset)?,
- upload_url: String,
- zipball_url: String?,
- tarball_url: String?,
- author: User?,
- node_id: String?
- )
- end
-
- struct ReleaseAsset
- Octokit.rest_model(
- id: Int32,
- url: String,
- name: String,
- label: String?,
- state: String,
- content_type: String,
- size: Int32,
- download_count: Int32,
- created_at: {type: Time, converter: Time::ISO8601Converter},
- updated_at: {type: Time, converter: Time::ISO8601Converter},
- browser_download_url: String,
- uploader: User,
- node_id: String
- )
- end
-
- struct RepositoryReleaseRequest
- Octokit.rest_model(
- tag_name: String,
- target_commit_hash: String,
- name: String,
- body: String,
- draft: Bool,
- prerelease: Bool
- )
- end
- end
-end
diff --git a/lib/octokit/src/octokit/models/repo_stats.cr b/lib/octokit/src/octokit/models/repo_stats.cr
deleted file mode 100644
index 2dabe96..0000000
--- a/lib/octokit/src/octokit/models/repo_stats.cr
+++ /dev/null
@@ -1,36 +0,0 @@
-module Octokit
- module Models
- struct ContributorStats
- Octokit.rest_model(
- author: Contributor,
- total: Int32,
- weeks: Array(WeeklyStats)
- )
- end
-
- struct WeeklyStats
- Octokit.rest_model(
- week: String,
- additions: Int32,
- deletions: Int32,
- commits: Int32
- )
- end
-
- struct WeeklyCommitActivity
- Octokit.rest_model(
- days: Array(Int32),
- total: Int32,
- week: String
- )
- end
-
- struct PunchCard
- Octokit.rest_model(
- day: Int32,
- hour: Int32,
- commits: Int32
- )
- end
- end
-end
diff --git a/lib/octokit/src/octokit/models/repo_statuses.cr b/lib/octokit/src/octokit/models/repo_statuses.cr
deleted file mode 100644
index 1c61160..0000000
--- a/lib/octokit/src/octokit/models/repo_statuses.cr
+++ /dev/null
@@ -1,36 +0,0 @@
-require "../core_ext/time"
-require "./users"
-
-module Octokit
- module Models
- alias Users = Octokit::Models::User
-
- struct RepoStatus
- Octokit.rest_model(
- url: String,
- avatar_id: String?,
- id: Int32,
- node_id: String,
- state: String,
- description: String,
- target_url: String?,
- context: String,
- created_at: {type: Time, converter: Time::ISO8601Converter},
- updated_at: {type: Time, converter: Time::ISO8601Converter},
- creator: User?
- )
- end
-
- struct CombinedStatus
- Octokit.rest_model(
- state: String,
- statuses: Array(RepoStatus),
- sha: String,
- total_count: Int32,
- repository: Repository,
- commit_url: String,
- url: String
- )
- end
- end
-end
diff --git a/lib/octokit/src/octokit/models/repo_traffic.cr b/lib/octokit/src/octokit/models/repo_traffic.cr
deleted file mode 100644
index a48fa22..0000000
--- a/lib/octokit/src/octokit/models/repo_traffic.cr
+++ /dev/null
@@ -1,52 +0,0 @@
-require "../helpers"
-
-module Octokit
- module Models
- struct TrafficReferrer
- Octokit.rest_model(
- referrer: String,
- count: Int32,
- uniques: Int32
- )
- end
-
- struct TrafficPath
- Octokit.rest_model(
- path: String,
- title: String,
- count: Int32,
- uniques: Int32
- )
- end
-
- struct TrafficData
- Octokit.rest_model(
- timestamp: String,
- count: Int32,
- uniques: Int32
- )
- end
-
- struct TrafficViews
- Octokit.rest_model(
- views: Array(TrafficData),
- count: Int32,
- uniques: Int32
- )
- end
-
- struct TrafficClones
- Octokit.rest_model(
- clones: Array(TrafficData),
- count: Int32,
- uniques: Int32
- )
- end
-
- struct TrafficBreakdownOptions
- Octokit.rest_model(
- per: String
- )
- end
- end
-end
diff --git a/lib/octokit/src/octokit/models/repos.cr b/lib/octokit/src/octokit/models/repos.cr
deleted file mode 100644
index 7e6afcd..0000000
--- a/lib/octokit/src/octokit/models/repos.cr
+++ /dev/null
@@ -1,345 +0,0 @@
-require "../models/misc"
-
-module Octokit
- module Models
- class Repository
- # Created as a class to prevent recursive struct
-
- def slug
- Repository.slug(full_name)
- end
-
- def self.slug(repo)
- owner, name = repo.split('/')
- "#{owner}/#{name}"
- end
-
- def to_s(io)
- io << slug
- end
-
- def self.get_name(repo)
- repo.is_a?(String) ? name.split('/').last : repo.name
- end
-
- def self.get_full_name(repo)
- name = repo.is_a?(String) ? repo : repo.full_name
- parts = name.split('/')
- raise "The full name of a Repository must be in the format `user/repo`" unless parts.size > 1
- parts.join('/')
- end
-
- def self.path(repo)
- case repo
- when Number
- "repositories/#{repo}"
- when String
- "repos/#{Repository.slug(repo)}"
- else
- raise "repo must be a number or string"
- end
- end
-
- Octokit.rest_model(
- id: Int64,
- node_id: String,
- owner: RepositoryOwner,
- name: String,
- full_name: String,
- description: String?,
- homepage: String?,
- code_of_conduct: CodeOfConduct?,
- default_branch: String?,
- master_branch: String?,
- created_at: {type: Time?, converter: Time::ISO8601Converter},
- pushed_at: {type: Time?, converter: Time::ISO8601Converter},
- updated_at: {type: Time?, converter: Time::ISO8601Converter},
- html_url: String,
- clone_url: String?,
- git_url: String?,
- mirror_url: String?,
- ssh_url: String?,
- svn_url: String?,
- language: String?,
- fork: Bool,
- forks_count: {type: Int32, default: 0},
- network_count: {type: Int32, default: 0},
- open_issues_count: {type: Int32, default: 0},
- stargazers_count: {type: Int32, default: 0},
- subscribers_count: {type: Int32, default: 0},
- watchers_count: {type: Int32, default: 0},
- size: {type: Int32, default: 0},
- auto_init: Bool?,
- parent: Repository?,
- source: Repository?,
- organization: Organization?,
- permissions: Hash(String, Bool)?,
- allow_rebase_merge: Bool?,
- allow_squash_merge: Bool?,
- allow_merge_commit: Bool?,
- topics: Array(String)?,
- archived: Bool?,
- disabled: Bool?,
-
- license: License?,
-
- private: Bool,
- has_issues: Bool?,
- has_wiki: Bool?,
- has_pages: Bool?,
- has_projects: Bool?,
- has_downloads: Bool?,
- license_template: String?,
- gitignore_template: String?,
-
- team_id: Int64?,
-
- url: String,
- archive_url: String,
- assignees_url: String,
- blobs_url: String,
- branches_url: String,
- collaborators_url: String,
- comments_url: String,
- commits_url: String,
- compare_url: String,
- contents_url: String,
- contributors_url: String,
- deployments_url: String,
- downloads_url: String,
- events_url: String,
- forks_url: String,
- git_commits_url: String,
- git_refs_url: String,
- git_tags_url: String,
- hooks_url: String,
- issue_comment_url: String?,
- issue_events_url: String,
- issues_url: String,
- keys_url: String,
- labels_url: String,
- languages_url: String,
- merges_url: String,
- milestones_url: String,
- notifications_url: String,
- pulls_url: String,
- releases_url: String,
- stargazers_url: String,
- statuses_url: String,
- subscribers_url: String,
- subscription_url: String,
- tags_url: String,
- trees_url: String,
- teams_url: String,
-
- text_matches: Array(TextMatch)?
- )
- end
-
- struct RepositoryOwner
- Octokit.rest_model(
- login: String,
- id: Int64,
- node_id: String,
- avatar_url: String,
- gravatar_id: String,
- url: String,
- html_url: String,
- followers_url: String,
- following_url: String,
- gists_url: String,
- starred_url: String,
- subscriptions_url: String,
- organizations_url: String,
- repos_url: String,
- events_url: String,
- received_events_url: String,
- type: String,
- site_admin: Bool
- )
- end
-
- struct RepositoryDeployKey
- Octokit.rest_model(
- id: Int32,
- key: String,
- url: String,
- title: String,
- verified: Bool,
- created_at: {type: Time, converter: Time::ISO8601Converter},
- read_only: Bool
- )
- end
-
- struct RepositoryTag
- Octokit.rest_model(
- name: String,
- commit_sha: {type: String, root: "commit", key: "sha"},
- commit_url: {type: String, root: "commit", key: "url"},
- zipball_url: String,
- tarball_url: String
- )
- end
-
- struct RepositoryListByOrgOptions
- Octokit.rest_model({
- type: String,
- # }.merge(ListOptions::FIELDS))
- })
- end
-
- struct RepositoryListAllOptions
- Octokit.rest_model(
- since: Int64
- )
- end
-
- struct CreateRepoRequest
- Octokit.rest_model(
- name: String?,
- description: String?,
- homepage: String?,
-
- private: Bool?,
- has_issues: Bool?,
- has_projects: Bool?,
- has_wiki: Bool?,
- default_branch: String?,
-
- team_id: Int64?,
-
- auto_init: Bool?,
- gitignore_template: String?,
- license_template: String?,
- allow_squash_merge: Bool?,
- allow_merge_commit: Bool?,
- allow_rebase_merge: Bool?
- )
- end
-
- struct Contributor
- Octokit.rest_model(
- login: String,
- id: Int64,
- avatar_url: String,
- gravatar_id: String,
- url: String,
- html_url: String,
- followers_url: String,
- following_url: String,
- gists_url: String,
- starred_url: String,
- subscriptions_url: String,
- organizations_url: String,
- repos_url: String,
- events_url: String,
- received_events_url: String,
- type: String,
- site_admin: Bool,
- contributions: Int32
- )
- end
-
- struct ListContributorsOptions
- Octokit.rest_model({
- anon: String,
- # }.merge(ListOptions::FIELDS))
- })
- end
-
- struct RepositoryTopics
- Octokit.rest_model(
- names: Array(String)
- )
- end
-
- struct RequiredStatusChecks
- Octokit.rest_model(
- static: Bool,
-
- contexts: Array(String)
- )
- end
-
- struct RequiredStatusChecksRequest
- Octokit.rest_model(
- strict: Bool,
- contexts: Array(String)
- )
- end
-
- struct PullRequestReviewsEnforcement
- Octokit.rest_model(
- dismissal_restrictions: DismissalRestrictions,
- dismiss_stale_reviews: Bool,
- require_code_owner_reviews: Bool,
- required_approving_review_count: Int32
- )
- end
-
- struct PullRequestReviewsEnforcementRequest
- Octokit.rest_model(
- dismissal_restrictions_request: DismissalRestrictionsRequest,
-
- dismiss_stale_reviews: Bool,
-
- require_code_owner_reviews: Bool,
-
- required_approving_review_count: Int32
- )
- end
-
- struct PullRequestReviewsEnforcementUpdate
- Octokit.rest_model(
- dismissal_restrictions_request: DismissalRestrictionsRequest,
-
- dismiss_stale_reviews: Bool,
-
- require_code_owner_reviews: Bool,
-
- required_approving_review_count: Int32
- )
- end
-
- struct AdminEnforcement
- Octokit.rest_model(
- url: String,
- enabled: Bool
- )
- end
-
- struct DismissalRestrictions
- Octokit.rest_model(
- users: Array(User),
- teams: Array(Team)
- )
- end
-
- struct DismissalRestrictionsRequest
- Octokit.rest_model(
- users: Array(User)?,
- teams: Array(Team)?
- )
- end
-
- struct SignaturesProtectedBranch
- Octokit.rest_model(
- url: String,
- enabled: Bool
- )
- end
-
- struct RepositoryTopics
- Octokit.rest_model(
- names: Array(String)
- )
- end
-
- struct TransferRequest
- Octokit.rest_model(
- new_owner: String,
- team_id: Array(Int64)
- )
- end
- end
-end
diff --git a/lib/octokit/src/octokit/models/search.cr b/lib/octokit/src/octokit/models/search.cr
deleted file mode 100644
index 1f8cdaa..0000000
--- a/lib/octokit/src/octokit/models/search.cr
+++ /dev/null
@@ -1,107 +0,0 @@
-module Octokit
- module Models
- struct SearchOptions
- Octokit.rest_model({
- sort: String,
- order: String,
- text_match: Bool,
- # }.merge(ListOptions::FIELDS))
- })
- end
-
- struct SearchParameters
- Octokit.rest_model(
- query: String,
- repository_id: Int64
- )
- end
-
- struct RepositoriesSearchResult
- Octokit.rest_model(
- total_count: Int32,
- incomplete_results: Bool,
- items: Array(Repository)
- )
- end
-
- struct CommitsSearchResult
- Octokit.rest_model(
- sha: String,
- commit: Commit,
- author: User,
- committer: User,
- parents: Array(Commit),
- html_url: String,
- url: String,
- comments_url: String,
-
- repository: Repository,
- score: Float64
- )
- end
-
- struct IssuesSearchResult
- Octokit.rest_model(
- total: Int32,
- incomplete_results: Bool,
- issues: Array(Issue)
- )
- end
-
- struct UserSearchResult
- Octokit.rest_model(
- total: Int32,
- incomplete_results: Bool,
- users: Array(User)
- )
- end
-
- struct Match
- Octokit.rest_model(
- text: String,
- indices: Array(Int32)
- )
- end
-
- struct TextMatch
- Octokit.rest_model(
- object_url: String,
- object_type: String,
- property: String,
- fragment: String,
- matches: Array(Match)
- )
- end
-
- struct CodeSearchResult
- Octokit.rest_model(
- total: Int32,
- incomplete_results: Bool,
- code_results: Array(CodeResult)
- )
- end
-
- struct CodeResult
- Octokit.rest_model(
- name: String,
- path: String,
- sha: String,
- html_url: String,
- repository: Repository,
- text_matches: Array(TextMatch)
- )
- end
-
- struct LabelResult
- Octokit.rest_model(
- id: Int64,
- url: String,
- name: String,
- color: String,
- default: Bool,
- description: String,
- score: Float64
- )
- end
- end
-end
diff --git a/lib/octokit/src/octokit/models/team_discussion_comments.cr b/lib/octokit/src/octokit/models/team_discussion_comments.cr
deleted file mode 100644
index c36c625..0000000
--- a/lib/octokit/src/octokit/models/team_discussion_comments.cr
+++ /dev/null
@@ -1,27 +0,0 @@
-module Octokit
- module Models
- struct DiscussionComment
- Octokit.rest_model(
- author: User,
- body: String,
- body_html: String,
- body_version: String,
- created_at: {type: Time, converter: Time::ISO8601Converter},
- last_edited_at: String,
- discussion_url: String,
- html_url: String,
- node_id: String,
- number: Int32,
- updated_at: {type: Time, converter: Time::ISO8601Converter},
- url: String,
- reactions: Reactions
- )
- end
-
- struct DiscussionCommentListOptions
- Octokit.rest_model(
- direction: String
- )
- end
- end
-end
diff --git a/lib/octokit/src/octokit/models/team_discussions.cr b/lib/octokit/src/octokit/models/team_discussions.cr
deleted file mode 100644
index 1e64f1b..0000000
--- a/lib/octokit/src/octokit/models/team_discussions.cr
+++ /dev/null
@@ -1,32 +0,0 @@
-module Octokit
- module Models
- struct TeamDiscussion
- Octokit.rest_model(
- author: User,
- body: String,
- body_html: String,
- body_version: String,
- comments_count: Int32,
- comments_url: String,
- created_at: {type: Time, converter: Time::ISO8601Converter},
- last_edited_at: String,
- html_url: String,
- node_id: String,
- number: Int32,
- pinned: Bool,
- private: Bool,
- team_url: String,
- title: String,
- updated_at: {type: Time, converter: Time::ISO8601Converter},
- url: String,
- reactions: Reactions
- )
- end
-
- struct DiscussionListOptions
- Octokit.rest_model(
- direction: String
- )
- end
- end
-end
diff --git a/lib/octokit/src/octokit/models/team_members.cr b/lib/octokit/src/octokit/models/team_members.cr
deleted file mode 100644
index 5dd54f9..0000000
--- a/lib/octokit/src/octokit/models/team_members.cr
+++ /dev/null
@@ -1,16 +0,0 @@
-module Octokit
- module Models
- struct TeamListTeamMembersOptions
- Octokit.rest_model({
- role: String,
- # }.merge(ListOptions::FIELDS))
- })
- end
-
- struct TeamAddTeamMembershipOptions
- Octokit.rest_model(
- role: String
- )
- end
- end
-end
diff --git a/lib/octokit/src/octokit/models/teams.cr b/lib/octokit/src/octokit/models/teams.cr
deleted file mode 100644
index 48bcdf9..0000000
--- a/lib/octokit/src/octokit/models/teams.cr
+++ /dev/null
@@ -1,71 +0,0 @@
-module Octokit
- module Models
- class Team
- # Created as a class to prevent recursive struct
- Octokit.rest_model(
- id: Int64,
- node_id: String,
- name: String,
- description: String,
- url: String,
- slug: String,
-
- permission: String,
-
- privacy: String,
-
- members_count: Int32,
- repos_count: Int32,
- organization: Organization,
- members_url: String,
- repositories_url: String,
- parent: Team,
-
- ldap_dn: String?
- )
- end
-
- struct Invitation
- Octokit.rest_model(
- id: Int64,
- node_id: String,
- login: String,
- email: String,
-
- role: String,
- created_at: {type: Time, converter: Time::ISO8601Converter},
- inviter: User,
- team_count: Int32,
- invitation_team_url: String
- )
- end
-
- struct NewTeam
- Octokit.rest_model(
- name: String,
- description: String,
- maintainers: Array(String),
- repo_names: Array(String),
- parent_team_id: Int64,
-
- permission: String,
-
- privacy: String,
-
- ldap_dn: String?
- )
- end
-
- struct TeamAddTeamRepoOptions
- Octokit.rest_model(
- permission: String
- )
- end
-
- struct TeamProjectOptions
- Octokit.rest_model(
- permission: String
- )
- end
- end
-end
diff --git a/lib/octokit/src/octokit/models/user_administration.cr b/lib/octokit/src/octokit/models/user_administration.cr
deleted file mode 100644
index e8a3d83..0000000
--- a/lib/octokit/src/octokit/models/user_administration.cr
+++ /dev/null
@@ -1,11 +0,0 @@
-require "../helpers"
-
-module Octokit
- module Models
- struct UserSuspendOptions
- Octokit.rest_model(
- reason: String
- )
- end
- end
-end
diff --git a/lib/octokit/src/octokit/models/user_emails.cr b/lib/octokit/src/octokit/models/user_emails.cr
deleted file mode 100644
index 909322e..0000000
--- a/lib/octokit/src/octokit/models/user_emails.cr
+++ /dev/null
@@ -1,14 +0,0 @@
-require "../helpers"
-
-module Octokit
- module Models
- struct UserEmail
- Octokit.rest_model(
- email: String,
- primary: Bool,
- verified: Bool,
- visibility: String?
- )
- end
- end
-end
diff --git a/lib/octokit/src/octokit/models/user_gpg_keys.cr b/lib/octokit/src/octokit/models/user_gpg_keys.cr
deleted file mode 100644
index 02c0bed..0000000
--- a/lib/octokit/src/octokit/models/user_gpg_keys.cr
+++ /dev/null
@@ -1,30 +0,0 @@
-require "../helpers"
-require "../core_ext/time"
-
-module Octokit
- module Models
- struct GPGKey
- Octokit.rest_model(
- id: Int64,
- primary_key_id: Int64,
- key_id: String,
- public_key: String,
- emails: Array(GPGEmail),
- subkeys: Array(GPGKey),
- can_sign: Bool,
- can_encrypt_coms: Bool,
- can_encrypt_storage: Bool,
- can_certify: Bool,
- created_at: {type: Time, converter: Time::ISO8601Converter},
- expires_at: String
- )
- end
-
- struct GPGEmail
- Octokit.rest_model(
- email: String,
- verified: Bool
- )
- end
- end
-end
diff --git a/lib/octokit/src/octokit/models/user_keys.cr b/lib/octokit/src/octokit/models/user_keys.cr
deleted file mode 100644
index 84570a4..0000000
--- a/lib/octokit/src/octokit/models/user_keys.cr
+++ /dev/null
@@ -1,15 +0,0 @@
-require "../helpers"
-
-module Octokit
- module Models
- struct Key
- Octokit.rest_model(
- id: Int64,
- key: String,
- url: String,
- title: String,
- read_only: Bool
- )
- end
- end
-end
diff --git a/lib/octokit/src/octokit/models/users.cr b/lib/octokit/src/octokit/models/users.cr
deleted file mode 100644
index 7f2cfe1..0000000
--- a/lib/octokit/src/octokit/models/users.cr
+++ /dev/null
@@ -1,115 +0,0 @@
-require "../core_ext/time"
-
-module Octokit
- module Models
- struct User
- # Get the api path for a user
- def self.path(user)
- case user
- when String
- "users/#{user}"
- when Int
- "user/#{user}"
- else
- "user"
- end
- end
-
- Octokit.rest_model(
- login: String,
- id: Int64,
- node_id: String,
- avatar_url: String,
- url: String,
- html_url: String,
- gravatar_id: String,
- name: String?,
- company: String?,
- blog: String?,
- location: String?,
- email: String?,
- hireable: Bool?,
- bio: String?,
- public_repos: Int32?,
- public_gists: Int32?,
- followers: Int32?,
- following: Int32?,
- created_at: {type: Time?, converter: Time::ISO8601Converter},
- updated_at: {type: Time?, converter: Time::ISO8601Converter},
- suspended_at: String?,
- type: String,
- site_admin: Bool,
- total_private_repos: Int32?,
- owned_private_repos: Int32?,
- private_gists: Int32?,
- disk_usage: Int32?,
- collaborators: Int32?,
- two_factor_authentication: Bool?,
- plan: Plan?,
-
- followers_url: String,
- gists_url: String,
- organizations_url: String,
- received_events_url: String,
- repos_url: String,
- events_url: String,
- starred_url: String,
- subscriptions_url: String,
-
- text_matches: Array(TextMatch)?,
-
- permissions: Hash(String, Bool)?
- )
- end
-
- struct Follower
- Octokit.rest_model(
- login: String,
- id: Int64,
- node_id: String,
- avatar_url: String,
- gravatar_id: String,
- url: String,
- html_url: String,
- followers_url: String,
- following_url: String,
- gists_url: String,
- starred_url: String,
- subscriptions_url: String,
- organizations_url: String,
- repos_url: String,
- events_url: String,
- received_events_url: String,
- type: String,
- site_admin: Bool
- )
- end
-
- struct HovercardOptions
- Octokit.rest_model(
- subject_type: String,
- subject_id: String
- )
- end
-
- struct Hovercard
- Octokit.rest_model(
- contexts: Array(UserContext)
- )
- end
-
- struct UserContext
- Octokit.rest_model(
- message: String,
- octicon: String
- )
- end
-
- struct UserListOptions
- Octokit.rest_model({
- since: Int64,
- # }.merge(ListOptions::FIELDS))
- })
- end
- end
-end
diff --git a/lib/octokit/src/octokit/preview.cr b/lib/octokit/src/octokit/preview.cr
deleted file mode 100644
index c4a35f6..0000000
--- a/lib/octokit/src/octokit/preview.cr
+++ /dev/null
@@ -1,34 +0,0 @@
-module Octokit
- # Default setup options for preview features
- module Preview
- PREVIEW_TYPES = {
- "branch_protection" => "application/vnd.github.loki-preview+json",
- "checks" => "application/vnd.github.antiope-preview+json",
- "commit_search" => "application/vnd.github.cloak-preview+json",
- "migrations" => "application/vnd.github.wyandotte-preview+json",
- "licenses" => "application/vnd.github.drax-preview+json",
- "source_imports" => "application/vnd.github.barred-rock-preview",
- "reactions" => "application/vnd.github.squirrel-girl-preview",
- "transfer_repository" => "application/vnd.github.nightshade-preview+json",
- "issue_timelines" => "application/vnd.github.mockingbird-preview+json",
- "nested_teams" => "application/vnd.github.hellcat-preview+json",
- "pages" => "application/vnd.github.mister-fantastic-preview+json",
- "projects" => "application/vnd.github.inertia-preview+json",
- "traffic" => "application/vnd.github.spiderman-preview",
- "integrations" => "application/vnd.github.machine-man-preview+json",
- "topics" => "application/vnd.github.mercy-preview+json",
- "community_profile" => "application/vnd.github.black-panther-preview+json",
- "strict_validation" => "application/vnd.github.speedy-preview+json",
- "drafts" => "application/vnd.github.shadow-cat-preview",
- }
-
- def api_media_type(type)
- warn_preview(type)
- {accept: PREVIEW_TYPES[type.to_s]}
- end
-
- def warn_preview(type)
- octokit_warn "WARNING: The preview version of the #{type.to_s.capitalize} API is not yet suitable for production use. You can avoid this message by supplying an appropriate media type in the 'Accept' request header."
- end
- end
-end
diff --git a/lib/octokit/src/octokit/rate_limit.cr b/lib/octokit/src/octokit/rate_limit.cr
deleted file mode 100644
index 02ffaa0..0000000
--- a/lib/octokit/src/octokit/rate_limit.cr
+++ /dev/null
@@ -1,43 +0,0 @@
-module Octokit
- # Class for API Rate Limit info
- #
- # **See Also:**
- # - [https://developer.github.com/v3/#rate-limiting](https://developer.github.com/v3/#rate-limiting)
- struct RateLimit
- property limit : Int32? = nil
-
- property remaining : Int32? = nil
-
- property resets_at : Time? = nil
-
- property resets_in : Int64? = nil
-
- def initialize(
- @limit : Int32? = nil,
- @remaining : Int32? = nil,
- @resets_at : Time? = nil,
- @resets_in : Int32? = nil
- )
- end
-
- # Get rate limit info from HTTP response
- def self.from_response(response)
- info = new
- if response && !response.headers.nil?
- limit = (response.headers["X-RateLimit-Limit"] || 1).to_i
- remaining = (response.headers["X-RateLimit-Remaining"] || 1).to_i
- resets_at = Time.unix(
- response.headers["X-RateLimit-Reset"]? ? response.headers["X-RateLimit-Reset"].to_i64 : Time.utc.to_unix
- )
- resets_in = [(resets_at - Time.utc).to_i, 0_i64].max
-
- info.limit = limit
- info.remaining = remaining
- info.resets_at = resets_at
- info.resets_in = resets_in
- end
-
- info
- end
- end
-end
diff --git a/lib/octokit/src/octokit/response/feed_parser.cr b/lib/octokit/src/octokit/response/feed_parser.cr
deleted file mode 100644
index e69de29..0000000
diff --git a/lib/octokit/src/octokit/response/raise_error.cr b/lib/octokit/src/octokit/response/raise_error.cr
deleted file mode 100644
index cf904eb..0000000
--- a/lib/octokit/src/octokit/response/raise_error.cr
+++ /dev/null
@@ -1,7 +0,0 @@
-require "halite"
-require "../error"
-
-module Octokit
- class Response < Halite::Feature
- end
-end
diff --git a/lib/octokit/src/octokit/version.cr b/lib/octokit/src/octokit/version.cr
deleted file mode 100644
index db2becd..0000000
--- a/lib/octokit/src/octokit/version.cr
+++ /dev/null
@@ -1,3 +0,0 @@
-module Octokit
- VERSION = "0.3.0"
-end
diff --git a/lib/octokit/src/octokit/warnable.cr b/lib/octokit/src/octokit/warnable.cr
deleted file mode 100644
index db829c9..0000000
--- a/lib/octokit/src/octokit/warnable.cr
+++ /dev/null
@@ -1,12 +0,0 @@
-module Octokit
- # Allows warnings to be suppressed via environment variable.
- module Warnable
- # Wrapper around Logger.warn to print warnings unless
- # OCTOKIT_SILENT is set to true.
- def octokit_warn(message)
- unless !!ENV["OCTOKIT_SILENT"]?
- @logger.warn { message }
- end
- end
- end
-end
diff --git a/lib/retriable/.editorconfig b/lib/retriable/.editorconfig
deleted file mode 100644
index 8f0c87a..0000000
--- a/lib/retriable/.editorconfig
+++ /dev/null
@@ -1,7 +0,0 @@
-[*.cr]
-charset = utf-8
-end_of_line = lf
-insert_final_newline = true
-indent_style = space
-indent_size = 2
-trim_trailing_whitespace = true
diff --git a/lib/retriable/.gitignore b/lib/retriable/.gitignore
deleted file mode 100644
index e3bc6ea..0000000
--- a/lib/retriable/.gitignore
+++ /dev/null
@@ -1,8 +0,0 @@
-/docs/
-/lib/
-/bin/
-/.shards/
-
-# Libraries don't need dependency lock
-# Dependencies will be locked in application that uses them
-/shard.lock
diff --git a/lib/retriable/LICENSE b/lib/retriable/LICENSE
deleted file mode 100644
index 87633a7..0000000
--- a/lib/retriable/LICENSE
+++ /dev/null
@@ -1,21 +0,0 @@
-The MIT License (MIT)
-
-Copyright (c) 2018 Sijawusz Pur Rahnama
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
diff --git a/lib/retriable/README.md b/lib/retriable/README.md
deleted file mode 100644
index 6a54a93..0000000
--- a/lib/retriable/README.md
+++ /dev/null
@@ -1,238 +0,0 @@
-# retriable.cr [![CI](https://github.com/Sija/retriable.cr/actions/workflows/ci.yml/badge.svg)](https://github.com/Sija/retriable.cr/actions/workflows/ci.yml) [![Releases](https://img.shields.io/github/release/Sija/retriable.cr.svg)](https://github.com/Sija/retriable.cr/releases) [![License](https://img.shields.io/github/license/Sija/retriable.cr.svg)](https://github.com/Sija/retriable.cr/blob/master/LICENSE)
-
-Retriable is a simple DSL to retry failed code blocks with randomized [exponential backoff](https://en.wikipedia.org/wiki/Exponential_backoff) time intervals. This is especially useful when interacting external APIs, remote services, or file system calls.
-
-## Installation
-
-Add this to your application's `shard.yml`:
-
-```yaml
-dependencies:
- retriable:
- github: Sija/retriable.cr
-```
-
-## Usage
-
-Code in a `Retriable.retry` block will be retried if either an exception is
-raised or `next retry` is called.
-
-```crystal
-require "retriable"
-
-class Api
- # Use it in methods that interact with unreliable services
- def get
- Retriable.retry do
- # code here...
- end
- end
-end
-```
-
-### Defaults
-
-By default, `Retriable` will:
-
-* rescue any exception inherited from `Exception`
-* use randomized exponential backoff to calculate each succeeding try interval.
-
-The default interval table with 10 tries looks like this (in seconds, rounded to the nearest millisecond):
-
-| Retry # | Min | Average | Max |
-| -------- | -------- | -------- | -------- |
-| 1 | `0.25` | `0.5` | `0.75` |
-| 2 | `0.375` | `0.75` | `1.125` |
-| 3 | `0.563` | `1.125` | `1.688` |
-| 4 | `0.844` | `1.688` | `2.531` |
-| 5 | `1.266` | `2.531` | `3.797` |
-| 6 | `1.898` | `3.797` | `5.695` |
-| 7 | `2.848` | `5.695` | `8.543` |
-| 8 | `4.271` | `8.543` | `12.814` |
-| 9 | `6.407` | `12.814` | `19.222` |
-| 10 | **stop** | **stop** | **stop** |
-
-### Options
-
-Here are the available options, in some vague order of relevance to most common use patterns:
-
-| Option | Default | Definition |
-| ----------------------- | ----------------- | ----------------------------- |
-| **`max_attempts`** | `nil` | Number of attempts to make at running your code block (includes initial attempt). |
-| **`except`** | `nil` | Type of exceptions to NOT retry. [Read more](#configuring-which-options-to-retry-with-onexcept). |
-| **`on`** | `nil` | Type of exceptions to retry. [Read more](#configuring-which-options-to-retry-with-onexcept). |
-| **`on_retry`** | `nil` | `Proc` to call after each try is rescued. [Read more](#callbacks). |
-| **`base_interval`** | `0.5.seconds` | The initial interval between tries. |
-| **`max_elapsed_time`** | `15.minutes` | The maximum amount of total time that code is allowed to keep being retried. |
-| **`max_interval`** | `1.minute` | The maximum interval that any individual retry can reach. |
-| **`multiplier`** | `1.5` | Each successive interval grows by this factor. A multiplier of 1.5 means the next interval will be 1.5x the current interval. |
-| **`rand_factor`** | `0.5` | The percentage to randomize the next retry interval time. The next interval calculation is `randomized_interval = retry_interval * (random value in range [1 - randomization_factor, 1 + randomization_factor])` |
-| **`intervals`** | `nil` | Skip generated intervals and provide your own `Enumerable` of intervals in seconds. [Read more](#customizing-intervals). |
-| **`backoff`** | `true` | Whether backoff strategy should be used. |
-| **`random`** | `Random::DEFAULT` | Object inheriting from `Random`, which provides an interface for random values generation, using a pseudo random number generator (PRNG). |
-
-#### Configuring which options to retry with :on/:except
-
-**`:on`** / **`:except`** Can take the form:
-
-- An `Exception` class (retry every exception of this type, including subclasses)
-- An `Enumerable` of `Exception` classes (retry any exception of one of these types, including subclasses)
-- A single `Proc` (retries exceptions ONLY if return is _truthy_)
-- A `Hash` where the keys are `Exception` classes and the values are one of:
- - `nil` (retry every exception of the key's type, including subclasses)
- - A single `Proc` (retries exceptions ONLY for non `nil` returns)
- - A single `Regex` pattern (retries exceptions ONLY if their `message` matches the pattern)
- - An `Enumerable` of patterns (retries exceptions ONLY if their `message` matches at least one of the patterns)
-
-### Configuration
-
-You can change the global defaults with a `#configure` block:
-
-```crystal
-Retriable.configure do |settings|
- settings.max_attempts = 5
- settings.max_elapsed_time = 1.hour
-end
-```
-
-### Example usage
-
-This example will only retry on a `IO::Timeout`, retry 3 times and sleep for a full second before each try.
-
-```crystal
-Retriable.retry(on: IO::Timeout, times: 3, base_interval: 1.second) do
- # code here...
-end
-```
-
-You can also specify multiple errors to retry on by passing an `Enumerable` of exceptions.
-
-```crystal
-Retriable.retry(on: {IO::Timeout, Errno::ECONNRESET}) do
- # code here...
-end
-```
-
-You can also use a `Hash` to specify that you only want to retry exceptions with certain messages (see [the documentation above](#configuring-which-options-to-retry-with-on)). This example will retry all `ActiveRecord::RecordNotUnique` exceptions, `ActiveRecord::RecordInvalid` exceptions where the message matches either `/Parent must exist/` or `/Username has already been taken/`, or `Mysql2::Error` exceptions where the message matches `/Duplicate entry/`.
-
-```crystal
-Retriable.retry(on: {
- ActiveRecord::RecordNotUnique => nil,
- ActiveRecord::RecordInvalid => [/Parent must exist/, /Username has already been taken/],
- ActiveRecord::RecordNotFound => ->(ex : Exception, attempt : Int32, elapsed : Time::Span, interval : Time::Span) {
- {User, Post}.includes?(ex.model.class)
- },
- Mysql2::Error => /Duplicate entry/,
-}) do
- # code here...
-end
-```
-
-### Customizing intervals
-
-You can also bypass the built-in interval generation and provide your own `Enumerable` of intervals. Supplying your own intervals overrides the `max_attempts`, `base_interval`, `max_interval`, `rand_factor`, and `multiplier` parameters.
-
-```crystal
-Retriable.retry(intervals: {0.5, 1.0, 2.0, 2.5}) do
- # code here...
-end
-```
-
-This example makes 5 total attempts. If the first attempt fails, the 2nd attempt occurs 0.5 seconds later.
-
-### Turning off exponential backoff
-
-Exponential backoff is enabled by default. If you want to simply retry code every second, 5 times maximum, you can do this:
-
-```crystal
-Retriable.retry(times: 5, base_interval: 1.second, multiplier: 1.0, rand_factor: 0.0) do
- # code here...
-end
-```
-
-This works by starting at a 1 second `base_interval`. Setting the `multiplier` to 1.0 means each subsequent try will increase 1x, which is still `1.0` seconds, and then a `rand_factor` of 0.0 means that there's no randomization of that interval. (By default, it would randomize 0.5 seconds, which would mean normally the intervals would randomize between 0.75 and 1.25 seconds, but in this case `rand_factor` is basically being disabled.)
-
-Same thing can be done by passing `backoff: false` option.
-
-```crystal
-Retriable.retry(times: 5, backoff: false) do
- # code here...
-end
-```
-
-Another way to accomplish this would be to create an array with a fixed interval. In this example, `Array.new(5, 1.second)` creates an array with 5 elements, all with the value of 1 second as `Time::Span` instances. The code block will retry up to 5 times, and wait 1 second between each attempt.
-
-```crystal
-# Array.new(5, 1.second) # => [00:00:01, 00:00:01, 00:00:01, 00:00:01, 00:00:01]
-
-Retriable.retry(intervals: Array.new(5, 1.second)) do
- # code here...
-end
-```
-
-If you don't want exponential backoff but you still want some randomization between intervals, this code will run every 1 seconds with a randomization factor of 0.2, which means each interval will be a random value between 0.8 and 1.2 (1 second +/- 0.2):
-
-```crystal
-Retriable.retry(base_interval: 1.second, multiplier: 1.0, rand_factor: 0.2) do
- # code here...
-end
-```
-
-### Callbacks
-
-`#retry` also provides a callback called `:on_retry` that will run after an exception is rescued. This callback provides the `exception` that was raised in the current try, the `try_number`, the `elapsed_time` for all tries so far, and the time (as a `Time::Span`) of the `next_interval`.
-
-```crystal
-do_this_on_each_retry = ->(ex : Exception, attempt : Int32, elapsed_time : Time::Span, next_interval : Time::Span) do
- log "#{ex.class}: '#{ex.message}' - #{attempt} attempt in #{elapsed_time} seconds and #{next_interval} seconds until the next try."
-end
-
-Retriable.retry(on_retry: do_this_on_each_retry) do
- # code here...
-end
-```
-
-### Ensure/Else
-
-What if I want to execute a code block at the end, whether or not an exception was rescued ([ensure](https://crystal-lang.org/docs/syntax_and_semantics/exception_handling.html#ensure))? Or what if I want to execute a code block if no exception is raised ([else](https://crystal-lang.org/docs/syntax_and_semantics/exception_handling.html#else))? Instead of providing more callbacks, I recommend you just wrap retriable in a begin/retry/else/ensure block:
-
-```crystal
-begin
- Retriable.retry do
- # some code
- end
-rescue ex
- # run this if retriable ends up re-rasing the exception
-else
- # run this if retriable doesn't raise any exceptions
-ensure
- # run this no matter what, exception or no exception
-end
-```
-
-## Kernel extension
-
-If you want to call `Retriable.retry` without the `Retriable` module prefix and you don't mind extending `Kernel`,
-there is a kernel extension available for this.
-
-In your crystal program:
-
-```crystal
-require "retriable/core_ext/kernel"
-```
-
-and then you can call `#retry` in any context like this:
-
-```crystal
-retry do
- # code here...
-end
-```
-
-## Contributors
-
-- [@Sija](https://github.com/Sija) Sijawusz Pur Rahnama - creator, maintainer
-
-## Thanks
-
-Thanks to all of the contributors for their awesome work on [Retriable](https://github.com/kamui/retriable) gem, from which this shard was ported.
diff --git a/lib/retriable/lib b/lib/retriable/lib
deleted file mode 120000
index a96aa0e..0000000
--- a/lib/retriable/lib
+++ /dev/null
@@ -1 +0,0 @@
-..
\ No newline at end of file
diff --git a/lib/retriable/shard.yml b/lib/retriable/shard.yml
deleted file mode 100644
index 5018db6..0000000
--- a/lib/retriable/shard.yml
+++ /dev/null
@@ -1,14 +0,0 @@
-name: retriable
-version: 0.2.5
-
-authors:
- - Sijawusz Pur Rahnama
-
-development_dependencies:
- ameba:
- github: crystal-ameba/ameba
- version: ~> 1.5.0
-
-crystal: ~> 1.9
-
-license: MIT
diff --git a/lib/retriable/src/retriable.cr b/lib/retriable/src/retriable.cr
deleted file mode 100644
index 617d1c1..0000000
--- a/lib/retriable/src/retriable.cr
+++ /dev/null
@@ -1,157 +0,0 @@
-require "./retriable/*"
-
-# ```
-# # include it scoped to the Retriable module
-# require "retriable"
-#
-# Retriable.retry do
-# # ...
-# end
-#
-# # or include it into top level namespace
-# require "retriable/core_ext/kernel"
-#
-# retry do
-# # ...
-# end
-# ```
-module Retriable
- extend self
-
- private abstract class Retry
- end
-
- class_getter settings : Settings { Settings.new }
-
- def configure(&) : Nil
- yield settings
- end
-
- def retry
- Retry
- end
-
- # ameba:disable Metrics/CyclomaticComplexity
- def retry(on = nil, **opts, &)
- base_interval = opts[:base_interval]? || settings.base_interval
- max_interval = opts[:max_interval]? || settings.max_interval
- rand_factor = opts[:rand_factor]? || settings.rand_factor
- random = opts[:random]? || settings.random
- multiplier = opts[:multiplier]? || settings.multiplier
- max_elapsed_time = opts[:max_elapsed_time]? || settings.max_elapsed_time
- intervals = opts[:intervals]? || settings.intervals
- max_attempts = opts[:times]? || opts[:max_attempts]? || settings.max_attempts
- sleep_disabled = opts[:sleep_disabled]? || settings.sleep_disabled?
- except = opts[:except]? || settings.except
- on = on || opts[:only]? || settings.on
- on_retry = opts[:on_retry]? || settings.on_retry
- backoff = opts[:backoff]? || settings.backoff?
-
- if backoff == false
- base_interval = 0.seconds
- multiplier = 1.0
- rand_factor = 0.0
- end
-
- backoff = ExponentialBackoff.new(
- base_interval: base_interval,
- multiplier: multiplier,
- max_interval: max_interval,
- rand_factor: rand_factor,
- random: random
- )
-
- case intervals
- when Enumerable(Time::Span)
- # ignore
- when Enumerable
- intervals = intervals.map(&.seconds)
- end
-
- case intervals
- in Enumerable(Time::Span)
- intervals_size = intervals.size + 1
- intervals = intervals.each
- if max_attempts && !settings.max_attempts
- if max_attempts > intervals_size
- intervals = intervals.chain(backoff.intervals.skip(intervals_size))
- else
- max_attempts = intervals_size
- end
- else
- max_attempts = intervals_size
- end
- in Nil
- intervals = backoff.intervals
- end
-
- initial_intervals = intervals.dup
-
- start_time = Time.monotonic
- attempt = 0
- loop do
- attempt += 1
- begin
- return_value = yield attempt
- return return_value unless return_value == Retry
- rescue ex
- elapsed_time = Time.monotonic - start_time
-
- case interval = intervals.next
- when Iterator::Stop
- intervals = initial_intervals.dup
- interval = intervals.first
- end
-
- raise ex if on && should_raise?(on, ex, attempt, elapsed_time, interval)
- raise ex if except && !should_raise?(except, ex, attempt, elapsed_time, interval)
-
- raise ex if max_attempts && (attempt >= max_attempts)
- raise ex if (elapsed_time + interval) > max_elapsed_time
-
- on_retry.try &.call(ex, attempt, elapsed_time, interval)
-
- sleep interval unless sleep_disabled || interval.zero?
- end
- end
- end
-
- protected def should_raise?(on : Exception.class | Proc | Enumerable, ex, *proc_args)
- !matches_exception?(on, ex, *proc_args)
- end
-
- protected def matches_exception?(on : Nil | Exception.class | Regex | Proc | Enumerable, ex, *proc_args)
- case on
- in Nil
- true
- in Exception.class
- on >= ex.class
- in Regex
- on =~ ex.message
- in Proc
- on.call(ex, *proc_args)
- in Hash
- on.any? do |klass, value|
- next unless klass >= ex.class
- case value
- when Nil, Regex, Proc
- matches_exception?(value, ex, *proc_args)
- when Enumerable
- value.any? do |matcher|
- case matcher
- when Regex, Proc
- matches_exception?(matcher, ex, *proc_args)
- end
- end
- end
- end
- in Enumerable
- on.any? do |matcher|
- case matcher
- when Exception.class, Proc
- matches_exception?(matcher, ex, *proc_args)
- end
- end
- end
- end
-end
diff --git a/lib/retriable/src/retriable/core_ext/kernel.cr b/lib/retriable/src/retriable/core_ext/kernel.cr
deleted file mode 100644
index 0e98a3b..0000000
--- a/lib/retriable/src/retriable/core_ext/kernel.cr
+++ /dev/null
@@ -1,9 +0,0 @@
-require "../../retriable"
-
-module Retriable
- module KernelExtension
- delegate :retry, to: Retriable
- end
-end
-
-include Retriable::KernelExtension
diff --git a/lib/retriable/src/retriable/exponential_backoff.cr b/lib/retriable/src/retriable/exponential_backoff.cr
deleted file mode 100644
index d3e224a..0000000
--- a/lib/retriable/src/retriable/exponential_backoff.cr
+++ /dev/null
@@ -1,34 +0,0 @@
-module Retriable
- struct ExponentialBackoff
- property base_interval : Time::Span
- property max_interval : Time::Span
- property rand_factor : Float64
- property multiplier : Float64
- property random : Random { Random::DEFAULT }
-
- def initialize(@base_interval, @max_interval, @rand_factor, @multiplier, @random = nil)
- end
-
- def randomize?
- !@rand_factor.zero?
- end
-
- def intervals : Iterator(Time::Span)
- should_randomize = randomize?
- (0..Int32::MAX).each.map do |iteration|
- interval = @multiplier**iteration
- interval = randomize(interval) if should_randomize
- {@base_interval * interval, @max_interval}.min
- rescue OverflowError
- @max_interval
- end
- end
-
- protected def randomize(interval) : Float64
- delta = interval * @rand_factor
- min = interval - delta
- max = interval + delta
- random.rand(min.to_f..max.to_f)
- end
- end
-end
diff --git a/lib/retriable/src/retriable/settings.cr b/lib/retriable/src/retriable/settings.cr
deleted file mode 100644
index 1d8fd7f..0000000
--- a/lib/retriable/src/retriable/settings.cr
+++ /dev/null
@@ -1,21 +0,0 @@
-module Retriable
- class Settings
- property max_attempts : Int32?
- property except : Exception.class | Array(Exception.class)?
- property on : Exception.class | Array(Exception.class)?
- property on_retry : Proc(Exception, Int32, Time::Span, Time::Span, Nil)?
- property base_interval : Time::Span = 0.5.seconds
- property max_elapsed_time : Time::Span = 15.minutes
- property max_interval : Time::Span = 1.minute
- property multiplier : Float64 = 1.5
- property? sleep_disabled : Bool = false
- property rand_factor : Float64 = 0.5
- property random : Random = Random::DEFAULT
- property intervals : Array(Time::Span)?
- property? backoff : Bool = true
-
- def on_retry(&block : (Exception, Int32, Time::Span, Time::Span) -> _)
- self.on_retry = block
- end
- end
-end
diff --git a/lib/retriable/src/retriable/version.cr b/lib/retriable/src/retriable/version.cr
deleted file mode 100644
index 38279f9..0000000
--- a/lib/retriable/src/retriable/version.cr
+++ /dev/null
@@ -1,3 +0,0 @@
-module Retriable
- VERSION = {{ `shards version "#{__DIR__}"`.chomp.stringify }}
-end
diff --git a/lib/spectator/.editorconfig b/lib/spectator/.editorconfig
deleted file mode 100644
index 163eb75..0000000
--- a/lib/spectator/.editorconfig
+++ /dev/null
@@ -1,9 +0,0 @@
-root = true
-
-[*.cr]
-charset = utf-8
-end_of_line = lf
-insert_final_newline = true
-indent_style = space
-indent_size = 2
-trim_trailing_whitespace = true
diff --git a/lib/spectator/.gitignore b/lib/spectator/.gitignore
deleted file mode 100644
index f76b510..0000000
--- a/lib/spectator/.gitignore
+++ /dev/null
@@ -1,14 +0,0 @@
-/docs/
-/lib/
-/bin/
-/.shards/
-*.dwarf
-
-# Libraries don't need dependency lock
-# Dependencies will be locked in application that uses them
-/shard.lock
-
-# Ignore JUnit output
-output.xml
-
-/test.cr
diff --git a/lib/spectator/.gitlab-ci.yml b/lib/spectator/.gitlab-ci.yml
deleted file mode 100644
index d627d27..0000000
--- a/lib/spectator/.gitlab-ci.yml
+++ /dev/null
@@ -1,89 +0,0 @@
-# Official language image. Look for the different tagged releases at:
-# https://hub.docker.com/r/crystallang/crystal/
-image: "crystallang/crystal:latest"
-
-# Cache shards in between builds
-cache:
- paths:
- - lib
- - bin
-
-before_script:
- - crystal -v # Print out Crystal version for debugging
-
-spec:
- script:
- - crystal spec --error-on-warnings --junit_output=. spec/matchers/ spec/spectator/*.cr
- artifacts:
- when: always
- paths:
- - output.xml
- reports:
- junit: output.xml
-
-spec docs:
- extends: spec
- script:
- - crystal spec --error-on-warnings --junit_output=. spec/docs/
-
-spec features:
- extends: spec
- script:
- - crystal spec --error-on-warnings --junit_output=. spec/features/
-
-spec regression:
- extends: spec
- script:
- - crystal spec --error-on-warnings --junit_output=. spec/issues/
-
-spec rspec:
- extends: spec
- script:
- - crystal spec --error-on-warnings --junit_output=. spec/rspec/
-
-spec dsl:
- extends: spec
- script:
- - crystal spec --error-on-warnings --junit_output=. spec/spectator/dsl/
-
-spec mocks:
- extends: spec
- script:
- - crystal spec --error-on-warnings --junit_output=. spec/spectator/mocks/
-
-format:
- script:
- - shards
- - crystal tool format --check
-
-style:
- script:
- - shards
- - bin/ameba
-
-nightly:
- image: "crystallang/crystal:nightly"
- allow_failure: true
- script:
- - shards --ignore-crystal-version
- - crystal spec --error-on-warnings --junit_output=. --tag smoke spec/spectator/dsl/
- - crystal tool format --check
- artifacts:
- when: always
- paths:
- - output.xml
- reports:
- junit: output.xml
-
-pages:
- stage: deploy
- dependencies:
- - spec
- script:
- - crystal docs
- - mv docs/ public/
- artifacts:
- paths:
- - public
- only:
- - master
diff --git a/lib/spectator/.guardian.yml b/lib/spectator/.guardian.yml
deleted file mode 100644
index f283d96..0000000
--- a/lib/spectator/.guardian.yml
+++ /dev/null
@@ -1,11 +0,0 @@
-files: ./src/**/*.cr
-run: time crystal spec --error-trace
----
-files: ./src/**/*.cr
-run: bin/ameba %file%
----
-files: ./spec/**/*.cr
-run: time crystal spec --error-trace %file%
----
-files: ./shard.yml
-run: shards
diff --git a/lib/spectator/ARCHITECTURE.md b/lib/spectator/ARCHITECTURE.md
deleted file mode 100644
index 90bcaba..0000000
--- a/lib/spectator/ARCHITECTURE.md
+++ /dev/null
@@ -1,273 +0,0 @@
-# Architecture and Design of Spectator
-
-This document explains the structure and design decisions behind Spectator.
-It is broken up into the logical components of Spectator:
-
-- [Terms](#terms)
-- [DSL](#dsl) - Domain Specific Language. Macros and methods that build a spec.
-- [Matchers](#matchers)
-- [Examples and groups](#examples-and-groups)
-- [Runner and harness](#runner-and-harness)
- - [Hooks](#hooks)
-- [Mocks and doubles](#mocks-and-doubles)
- - [Stubs](#stubs)
- - [Doubles](#doubles)
-- [Formatting](#formatting)
-
-## Terms
-
-The following are terms and concepts frequently used in the project.
-They are listed in alphabetical order,
-but you may find it useful to jump around when learning what they mean.
-
-**Assertion**
-
-An *assertion* is a fundamental piece of a test.
-It checks that a condition is satisfied.
-If that condition isn't met, then an exception is raised.
-
-**Builder**
-
-A *builder* is a type that incrementally constructs a complex object.
-Builders are primarily used to create *specs* and *example groups*.
-See: https://sourcemaking.com/design_patterns/builder
-
-**Config**
-
-Short for *configuration*, a *config* stores information about how to run the *spec*.
-The configuration includes parsed command-line options, settings from `.spectator` and `Spectator.configure`.
-
-**Context**
-
-A *context* is the scope or "environment" a test runs in.
-It is a part of an *example group* that provides methods, memoized values, and more to an example block.
-From a technical standpoint, it is typically an instance of the class defined by an `example_group` block.
-It can thought of as a closure.
-
-**Double**
-
-Stand-in for another type.
-*Doubles* can be passed to methods under test instead of a real object.
-They can be configured to respond to methods with *stubs*.
-*Doubles* also track calls made to them.
-An important note: a *double* is _not_ the same type (nor does it inherit) the replaced type.
-
-**DSL**
-
-*DSL* stands for **D**omain **S**pecific **L**anguage.
-It is the human-like language that comprises a *spec*.
-Keywords in the *DSL*, such as `describe`, `it`, and `expect`, are macros or methods.
-Those macros and methods make calls to Spectator to describe the structure of a *spec*.
-They are combined in such a way that makes it easy to read.
-
-**Example**
-
-An *example* is essentially a *test* and metadata.
-Spectator makes a distinction between *test* and *example*.
-An *example* can have a description, *group*, *context*, *result*, and *tags*.
-That is to say: an *example* is the *test* and information for execution.
-An *example* is a type of *node*.
-
-In the *DSL*, an *example* is created with `example` and `it` blocks and their variants.
-
-**Example Group**
-
-An *example group* (or *group* for short), is a collection of *examples*.
-*Groups* can be nested in other *groups*, but can only have one parent.
-*Groups* can have *hooks*.
-*Groups* have extra properties like a name and metadata.
-A *group* is a type of *node*.
-
-In the *DSL*, an *example group* is created with `example_group`, `describe`, and `context` blocks and their variants.
-
-**Expectation**
-
-An *expectation* captures a value or behavior and whether it satisfies a condition.
-*Expectations* contain *match data*.
-They are bubbled up from the *harness* to the runner.
-*Expectations* can be thought of as wrappers for *assertions*.
-
-In the *DSL*, an *expectation* is the code: `expect(THIS).to eq(THAT)`
-An *expectation target* is just the `expect(THIS)` portion.
-
-**Formatter**
-
-A *formatter* takes *results* and reports them to the user in a specific format.
-Examples of *formatters* are XML, HTML, JSON, dots, and documentation.
-The runner will call methods on the *formatter*.
-The methods called depend on the type of *result* and the state of the runner.
-For instance, `#example_started` is called before a an example runs,
-and `#dump_summary` is called at the end when all *results* are available.
-
-**Harness**
-
-A *harness* is used to safely wrap *test* code.
-It captures *expectations* and creates a *result* based on the outcome.
-
-**Filter**
-
-A *filter* selects *nodes* to be included in a running *spec*.
-There are multiple types of *filters*.
-
-**Hook**
-
-A *hook* is a piece of code to execute at a key time.
-For instance, before a *test* starts, or after everything in a *group* completes.
-*Hooks* can be run in the same *context* as a *test*.
-These are known as "example hooks."
-*Hooks* that don't run in a *context*, and instead run independent of *examples*, are called "example group hooks."
-*Hooks* are attached to *groups*.
-
-**Label**
-
-A *label* is a string from the *spec* that identifies a expression.
-*Labels* are captured to improve the readability of *results* and *match data*.
-
-In the following code, the labels are: `does something useful`, `the_answer`, and `42`.
-
-```crystal
-it "does something useful" do
- expect(the_answer).to eq(42)
-end
-```
-
-**Matcher**
-
-A *matcher* defines an expected value or behavior.
-*Matchers* are given an "actual" value from a test and produce *match data*.
-The *match data* contains information regarding whether the value or behavior was expected (satisfies a condition).
-They behave similarly to an instance of a `Regex`.
-
-In the following code, the `eq(42)` portion returns an instance of a *matcher* expecting the value 42.
-
-```crystal
-expect(the_answer).to eq(42)
-```
-
-**Match Data**
-
-*Match data* is produced by *matchers*.
-It contains information regarding whether an *expectation* is satisfied and values from the match.
-The values are key-value pairs identifying things such as "expected value" and "actual value."
-*Match data* is similar in concept to `Regex::MatchData`.
-
-**Mock**
-
-A *mock* is a type that can have its original functionality "swapped out" for a *stub*.
-This allows complex types to be "mocked" so that other types can be unit tested.
-*Mocks* can have any number of *stubs* defined.
-They are similar to *doubles*, but use a real type.
-
-**Node**
-
-A *node* refers to any component in a *spec*.
-*Nodes* are typically *examples* and *example groups*.
-A *node* can have metadata associated with it, such as a *label*, location, and *tags*.
-
-**Procsy**
-
-A *procsy* is a glorified `Proc`.
-It is used to wrap an underlying proc in some way.
-Typically used to wrap an *example* when passed to a *hook*.
-
-**Profile**
-
-A *profile* includes timing information for *examples*.
-It tracks how long each *example* took and sorts them.
-
-**Report**
-
-A *report* is a collection of *results* generated by running *examples*.
-It provides easy access to various metrics and types of *results*.
-
-**Result**
-
-A *result* summarizes the outcome of running an *example*.
-A *result* can be passing, failing, or pending.
-*Results* contain timing information, *expectations* processed in the *example*, and an error for failing *results*.
-
-**Spec**
-
-A *spec* is a collection of *examples*.
-Conceptually, a *spec* defines the behavior of a system.
-A *spec* consists of a single, root *example group* that provides a tree structure of *examples*.
-A *spec* also contains some *config* describing how to run it.
-
-**Stub**
-
-A *stub* is a method in a *double* or *mock* that replaces the original functionality.
-*Stubs* can be attached to a single instance or all instances of a type.
-
-**Tag**
-
-A *tag* is an identifier with optional value.
-*Tags* can be used to group and filter *examples* and *example groups*.
-Some *tags* have special meaning, like `skip` indicating an *example* or *group* should be skipped.
-
-**Test**
-
-The word "test" is overused, especially when using a testing framework.
-We make an effort to avoid using the word "test" for everything.
-However, *test* has a technical meaning in Spectator.
-It refers to the code (block) executed in an *example*.
-
-```crystal
-it "does a thing" do
- # Test code starts here. Everything inside this `it` block is considered a test.
- expect(the_answer).to eq(42)
- # Test code ends here.
-end
-```
-
-## DSL
-
-The DSL is made up of methods and macros.
-What look like keywords (`describe`, `it`, `expect`, `eq`, etc.) are just macros and methods provided by the DSL.
-Those macros and methods are defined in multiple modules in the `Spectator::DSL` namespace.
-They are logically grouped by their functionality.
-
-Each module is included (as a mix-in) to the base Spectator context that all tests use.
-The `SpectatorTestContext` class includes all of the DSL modules.
-
-The DSL methods and macros should be kept simple.
-Their functionality should be off-loaded to internal Spectator "APIs."
-For instance, when the DSL creates an example,
-it defines a method for the test code and calls another method to register it.
-While Crystal macros are powerful, excessive use of them makes maintenance harder and compilation slower.
-Additionally, by keeping logic out of the DSL, testing of internals becomes less dependent on the DSL.
-
-*TODO:* Builders...
-
-*TODO:* Tricks...
-
-## Matchers
-
-*TODO:* Base types
-
-## Examples and groups
-
-*TODO*
-
-## Runner and harness
-
-*TODO*
-
-### Hooks
-
-*TODO*
-
-## Mocks and doubles
-
-*TODO*
-
-### Stubs
-
-*TODO*
-
-### Doubles
-
-*TODO*
-
-## Formatting
-
-*TODO*
diff --git a/lib/spectator/CHANGELOG.md b/lib/spectator/CHANGELOG.md
deleted file mode 100644
index 278c53c..0000000
--- a/lib/spectator/CHANGELOG.md
+++ /dev/null
@@ -1,530 +0,0 @@
-# Changelog
-All notable changes to this project will be documented in this file.
-
-The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
-and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
-
-## [0.12.0] - 2024-02-03
-### Added
-- Added ability to use matchers for case equality. [#55](https://github.com/icy-arctic-fox/spectator/issues/55)
-- Added support for nested case equality when checking arguments with Array, Tuple, Hash, and NamedTuple.
-
-### Fixed
-- Fixed some issues with the `be_within` matcher when used with expected and union types.
-
-## [0.11.7] - 2023-10-16
-### Fixed
-- Fix memoized value (`let`) with a union type causing segfault. [#81](https://gitlab.com/arctic-fox/spectator/-/issues/81)
-
-## [0.11.6] - 2023-01-26
-### Added
-- Added ability to cast types using the return value from expect/should statements with a type matcher.
-- Added support for string interpolation in context names/labels.
-
-### Fixed
-- Fix invalid syntax (unterminated call) when recording calls to stubs with an un-named splat. [#51](https://github.com/icy-arctic-fox/spectator/issues/51)
-- Fix malformed method signature when using named splat with keyword arguments in mocked type. [#49](https://github.com/icy-arctic-fox/spectator/issues/49)
-
-### Changed
-- Expectations using 'should' syntax report file and line where the 'should' keyword is instead of the test start.
-- Add non-captured block argument in preparation for Crystal 1.8.0.
-
-## [0.11.5] - 2022-12-18
-### Added
-- Added support for mock modules and types that include mocked modules.
-
-### Fixed
-- Fix macro logic to support free variables, 'self', and variants on stubbed methods. [#48](https://github.com/icy-arctic-fox/spectator/issues/48)
-- Fix method stubs used on methods that capture blocks.
-- Fix type name resolution for when using custom types in a mocked typed.
-- Prevent comparing range arguments with non-compatible types in stubs. [#48](https://github.com/icy-arctic-fox/spectator/issues/48)
-
-### Changed
-- Simplify string representation of mock-related types.
-- Remove unnecessary redefinitions of methods when adding stub functionality to a type.
-- Allow metadata to be stored as nil to reduce overhead when tracking nodes without tags.
-- Use normal equality (==) instead of case-equality (===) with proc arguments in stubs.
-- Change stub value cast logic to avoid compiler bug. [#80](https://gitlab.com/arctic-fox/spectator/-/issues/80)
-
-## [0.11.4] - 2022-11-27
-### Added
-- Add support for using named (keyword) arguments in place of positional arguments in stubs. [#47](https://github.com/icy-arctic-fox/spectator/issues/47)
-- Add `before`, `after`, and `around` as aliases for `before_each`, `after_each`, and `around_each` respectively.
-
-### Fixed
-- Clear stubs defined with `expect().to receive()` syntax after test finishes to prevent leakage between tests.
-- Ensure stubs defined with `allow().to receive()` syntax are cleared after test finishes when used inside a test (another leakage).
-- Fix crash caused when logging is enabled after running an example that attempts to exit.
-
-### Removed
-- Removed support for stubbing undefined (untyped) methods in lazy doubles. Avoids possible segfault.
-
-## [0.11.3] - 2022-09-03
-### Fixed
-- Display error block (failure message and stack trace) when using `fail`. [#78](https://gitlab.com/arctic-fox/spectator/-/issues/78)
-- Defining a custom matcher outside of the `Spectator` namespace no longer produces a compilation error. [#46](https://github.com/icy-arctic-fox/spectator/issues/46)
-
-## [0.11.2] - 2022-08-07
-### Fixed
-- `expect_raises` with block and no arguments produces compilation error. [#77](https://gitlab.com/arctic-fox/spectator/-/issues/77)
-
-### Changed
-- `-e` (`--example`) CLI option performs a partial match instead of exact match. [#71](https://gitlab.com/arctic-fox/spectator/-/issues/71) [#45](https://github.com/icy-arctic-fox/spectator/issues/45)
-
-## [0.11.1] - 2022-07-18
-### Fixed
-- Workaround nilable type issue with memoized value. [#76](https://gitlab.com/arctic-fox/spectator/-/issues/76)
-
-## [0.11.0] - 2022-07-14
-### Changed
-- Overhauled mock and double system. [#63](https://gitlab.com/arctic-fox/spectator/-/issues/63)
-- Testing if `exit` is called no longer is done with stubs and catching the `Spectator::SystemExit` exception should be caught. [#29](https://github.com/icy-arctic-fox/spectator/issues/29)
-- Adjust evaluation order of `change` matcher expressions.
-
-### Removed
-- Removed support for stubbing top-level methods (such as `exit`).
-
-## [0.10.6] - 2022-07-07
-### Fixed
-- Fixed compiler warnings generated by positional arguments with different names.
-
-### Changed
-- Forward example procsy `to_s` to underlying example. [#70](https://gitlab.com/arctic-fox/spectator/-/issues/70)
-
-## [0.10.5] - 2022-01-27
-### Fixed
-- Fixed usage of `sample` with single block argument. [#41](https://github.com/icy-arctic-fox/spectator/issues/41#issuecomment-1022525702)
-
-## [0.10.4] - 2022-01-11
-### Added
-- Support string interpolation for example name/description. [#41](https://github.com/icy-arctic-fox/spectator/issues/41)
-- Support multiple block arguments in `sample` block (`Hash#each`). [#41](https://github.com/icy-arctic-fox/spectator/issues/41#issuecomment-1010192486)
-
-### Changed
-- Source line reported by failure list changed to line containing `expect` instead of example start line.
-- Better compiler error when using string interpolation in group name/description. [#41](https://github.com/icy-arctic-fox/spectator/issues/41)
-
-## [0.10.3] - 2021-10-13
-### Fixed
-- Fixed runtime error with `expect` outside of test block - now gives compilation error.
-
-### Added
-- Description of a `provided` example can be set by using `it` as an argument. [#69](https://gitlab.com/arctic-fox/spectator/-/issues/69)
-
-## [0.10.2] - 2021-10-22
-### Fixed
-- Fix usage of `be ===` and `be =~` [#34](https://github.com/icy-arctic-fox/spectator/issues/34)
-- Better handling of the `be(nil)` when used with value types. [#37](https://github.com/icy-arctic-fox/spectator/issues/37)
-- Fix missing arguments for stubbed top-level methods (`system`, `exit`, etc.). [#36](https://github.com/icy-arctic-fox/spectator/issues/36)
-- Fix outdated naming when using `expect_any_instance_of`.
-- Fix adding stubs to class methods on mocked types.
-
-### Changed
-- Elegantly handle missing/undefined methods with `have_attributes` matcher.
-
-## [0.10.1] - 2021-09-16
-### Fixed
-- Fix `Spectator.configure` block calls to `filter_run_excluding` and `filter_run_including`. [#61](https://gitlab.com/arctic-fox/spectator/-/issues/61)
-- Fix shard version constant creation when lib is in a directory with spaces in the path. [#33](https://gitlab.com/arctic-fox/spectator/-/merge_requests/33) Thanks @toddsundsted !
-- Re-add pre- and post-condition hooks. [#62](https://gitlab.com/arctic-fox/spectator/-/issues/62)
-
-## [0.10.0] - 2021-08-19
-### Fixed
-- Fix resolution of types with the same name in nested scopes. [#31](https://github.com/icy-arctic-fox/spectator/issues/31)
-- `around_each` hooks wrap `before_all` and `after_all` hooks. [#12](https://github.com/icy-arctic-fox/spectator/issues/12)
-- Hook execution order has been tweaked to match RSpec.
-
-### Added
-- `before_each`, `after_each`, and `around_each` hooks are yielded the current example as a block argument.
-- The `let` and `subject` blocks are yielded the current example as a block argument.
-- Add internal logging that uses Crystal's `Log` utility. Provide the `LOG_LEVEL` environment variable to enable.
-- Support dynamic creation of examples.
-- Capture and log information for hooks.
-- Tags can be added to examples and example groups.
-- Add matcher to check compiled type of values.
-- Examples can be skipped by using a `:pending` tag. A reason method can be specified: `pending: "Some excuse"`
-- Examples without a test block are marked as pending. [#37](https://gitlab.com/arctic-fox/spectator/-/issues/37)
-- Examples can be skipped during execution by using `skip` or `pending` in the example block. [#17](https://gitlab.com/arctic-fox/spectator/-/issues/17)
-- Sample blocks can be temporarily skipped by using `xsample` or `xrandom_sample`.
-- Add `before_suite` and `after_suite` hooks. [#21](https://gitlab.com/arctic-fox/spectator/-/issues/21)
-- Support defining hooks in `Spectator.configure` block. [#21](https://gitlab.com/arctic-fox/spectator/-/issues/21)
-- Examples with failures or skipped during execution will report the location of that result. [#57](https://gitlab.com/arctic-fox/spectator/-/issues/57)
-- Support custom messages for failed expectations. [#28](https://gitlab.com/arctic-fox/spectator/-/issues/28)
-- Allow named arguments and assignments for `provided` (`given`) block.
-- Add `aggregate_failures` to capture and report multiple failed expectations. [#24](https://gitlab.com/arctic-fox/spectator/-/issues/24)
-- Supports matching groups. [#25](https://gitlab.com/arctic-fox/spectator/-/issues/25) [#24](https://github.com/icy-arctic-fox/spectator/issues/24)
-- Add `filter_run_including`, `filter_run_excluding`, and `filter_run_when_matching` to config block.
-- By default, only run tests when any are marked with `focus: true`.
-- Add "f-prefix" blocks for examples and groups (`fit`, `fdescribe`, etc.) as a short-hand for specifying `focus: true`.
-- Add HTML formatter. Operates the same as the JUnit formatter. Specify `--html_output=DIR` to use. [#22](https://gitlab.com/arctic-fox/spectator/-/issues/22) [#3](https://github.com/icy-arctic-fox/spectator/issues/3)
-
-### Changed
-- `given` (now `provided`) blocks changed to produce a single example. `it` can no longer be nested in a `provided` block.
-- The "should" syntax no longer reports the source as inside Spectator.
-- Short-hand "should" syntax must be included by using `require "spectator/should"` - `it { should eq("foo") }`
-- Better error messages and detection when DSL methods are used when they shouldn't (i.e. `describe` inside `it`).
-- Prevent usage of reserved keywords in DSL (such as `initialize`).
-- The count argument for `sample` and `random_sample` groups must be named (use `count: 5` instead of just `5`).
-- Helper methods used as arguments for `sample` and `random_sample` must be class methods.
-- Simplify and reduce instanced types and generics. Should speed up compilation times.
-- Overhaul example creation and handling.
-- Overhaul storage of test values.
-- Overhaul reporting and formatting. Cleaner output for failures and pending tests.
-- Cleanup and simplify DSL implementation.
-- Other minor internal improvements and cleanup.
-
-### Deprecated
-- `pending` blocks will behave differently in v0.11.0. They will mimic RSpec in that they _compile and run_ the block expecting it to fail. Use a `skip` (or `xit`) block instead to prevent compiling the example.
-- `given` has been renamed to `provided`. The `given` keyword may be reused later for memoization.
-
-### Removed
-- Removed one-liner `it`-syntax without braces (block).
-
-## [0.9.40] - 2021-07-10
-### Fixed
-- Fix stubbing of class methods.
-- Fix handling of `no_args` in some cases.
-
-### Changed
-- Better handling and stubbing of `Process.exit`.
-
-## [0.9.39] - 2021-07-02
-### Fixed
-- Fix `expect().to receive()` syntax not implicitly stubbing the method.
-- Avoid calling `NoReturn` methods from stubs. [#29](https://github.com/icy-arctic-fox/spectator/issues/29)
-
-### Added
-- Added support for `with(no_args)` for method stubs. [#28](https://github.com/icy-arctic-fox/spectator/issues/28)
-- Allow creation of doubles without definition block. [#30](https://github.com/icy-arctic-fox/spectator/issues/30)
-
-## [0.9.38] - 2021-05-27
-### Fixed
-- Fix `Channel::ClosedError` when using default Crystal Logger. [#27](https://github.com/icy-arctic-fox/spectator/issues/27)
-
-## [0.9.37] - 2021-05-19
-### Added
-- Added support for `be ===` and `be =~`. [#26](https://github.com/icy-arctic-fox/spectator/issues/26)
-
-## [0.9.36] - 2021-04-22
-### Fixed
-- Remove old workaround that prevented compilation on Windows. [#58](https://gitlab.com/arctic-fox/spectator/-/issues/58)
-
-## [0.9.35] - 2021-04-18
-### Fixed
-- Allow types stored in variables or returned by methods in `be_a` (and variants), not just type literals. [#25](https://github.com/icy-arctic-fox/spectator/issues/25)
-
-## [0.9.34] - 2021-03-31
-### Changed
-- Allow filtering examples by using any line in the example block. [#19](https://github.com/icy-arctic-fox/spectator/issues/19) Thanks @matthewmcgarvey !
-
-## [0.9.33] - 2021-03-22
-### Changed
-- Target Crystal 1.0
-
-## [0.9.32] - 2021-02-03
-### Fixed
-- Fix source reference with brace-less example syntax. [#20](https://github.com/icy-arctic-fox/spectator/issues/20)
-
-## [0.9.31] - 2021-01-08
-### Fixed
-- Fix misaligned line numbers when referencing examples and groups.
-
-## [0.9.30] - 2020-12-23
-### Fixed
-- Fix issue caused by additions from 0.9.29.
-
-### Changed
-- Improve the `contain`, `contain_elements`, `have`, and `have_elements` to show missing items in output.
-
-## [0.9.29] - 2020-12-23
-### Added
-- Add variants `contain_elements` and `have_elements`, which behave like `contain` and `have` matchers except that they take an array (or any enumerable type) instead of a parameter list or splat.
-
-## [0.9.28] - 2020-11-07
-### Added
-- Add `return_type` option to method stubs.
-
-## [0.9.27] - 2020-10-01
-### Added
-- Add syntax for stubbing operator-style methods, such as `[]`.
-
-## [0.9.26] - 2020-09-27
-### Fixed
-- Fix issue with yielding in stubbed mocks.
-
-## [0.9.25] - 2020-09-26
-### Fixed
-- Fix issue with splatting values for failed match data. This prevented the use of "description" and "failure_message" in some matches like `respond_to`.
-
-## [0.9.24] - 2020-09-17
-### Changed
-- Allow some forms of string interpolation in group and example descriptions.
-
-## [0.9.23] - 2020-08-30
-### Fixed
-- Allow the use of `object_id` and other possibly conflicting method names via `let`. [#53](https://gitlab.com/arctic-fox/spectator/-/issues/53)
-
-## [0.9.22] - 2020-08-11
-### Changed
-- Handle splat in macro for matcher DSL. [#8](https://github.com/icy-arctic-fox/spectator/issues/8)
-
-## [0.9.21] - 2020-07-27
-### Added
-- Display random seed when using `-r` or `--seed` options. [#7](https://github.com/icy-arctic-fox/spectator/issues/7)
-
-## [0.9.20] - 2020-05-29
-### Fixed
-- Fix bug when using multiple short-hand block expects in one test.
-
-## [0.9.19] - 2020-05-28
-### Fixed
-- Fix issue with `match_array` and `contain_exactly` matchers not working with immutable collections.
-
-## [0.9.18] - 2020-04-26
-### Fixed
-- Fix `describe_class.new` when using a generic type.
-
-## [0.9.17] - 2020-04-23
-### Fixed
-- Fix issue when using deferred syntax with `receive` matcher. [#48](https://gitlab.com/arctic-fox/spectator/-/issues/48)
-
-## [0.9.16] - 2020-04-06
-### Fixed
-- Silence warnings from Crystal 0.34
-
-## [0.9.15] - 2020-04-03
-### Fixed
-- Fix issues with `match_array().in_any_order` and `contain_exactly().in_any_order`. [#47](https://gitlab.com/arctic-fox/spectator/-/issues/47)
-
-### Changed
-- Improve usability when actual value does not respond to methods needed to verify it.
-For instance, `expect(nil).to contain_exactly(:foo)` would not compile.
-This has been changed so that it compiles and raises an error at runtime with a useful message.
-
-## [0.9.14] - 2020-04-01
-### Fixed
-- Fix using nil with `be` matcher. [#45](https://gitlab.com/arctic-fox/spectator/-/issues/45)
-
-## [0.9.13] - 2020-03-28
-### Fixed
-- Fix arguments not found in default stubs for mocks. [#44](https://gitlab.com/arctic-fox/spectator/-/issues/44)
-
-## [0.9.12] - 2020-03-20
-### Fixed
-- Fix issue when mocking modules. Thanks @watzon !
-
-## [0.9.11] - 2020-03-04
-### Fixed
-- Fix issue when describing constants. [#40](https://gitlab.com/arctic-fox/spectator/-/issues/40) [#41](https://gitlab.com/arctic-fox/spectator/-/issues/41)
-
-## [0.9.10] - 2020-03-03
-### Changed
-- Smarter behavior when omitting the block argument to the `around_each` hook.
-
-## [0.9.9] - 2020-02-22
-### Fixed
-- Fix implicit subject when used with a module. [#6](https://github.com/icy-arctic-fox/spectator/issues/6)
-
-## [0.9.8] - 2020-02-21
-### Fixed
-- Fix `be_between` matcher. Thanks @davidepaolotua / @jinn999 !
-
-## [0.9.7] - 2020-02-16
-### Fixed
-- Fix memoization of subject when using a type name for the context.
-- Fix some cases when mocking a class method.
-
-## [0.9.6] - 2020-02-10
-### Added
-- Add short-hand "should" syntax - `it { should eq("foo") }`
-- The `be` matcher can be used on value types.
-- Add more tests cases from RSpec docs.
-
-### Fixed
-- Fix an issue with stubbed class methods on mocked types. Sometimes `previous_def` was used when `super` should have been used instead.
-- Fix deferred expectations not running after all hooks.
-
-## [0.9.5] - 2020-01-19
-### Changed
-- Described type is now considered an explicit subject.
-
-## [0.9.4] - 2020-01-19
-### Added
-- Add more test cases from RSpec docs.
-- Add `it_fails` utility to test expected failures.
-
-### Fixed
-- Fix negated case for `respond_to` matcher.
-
-## [0.9.3] - 2020-01-17
-### Fixed
-- Fix implicit subject overwriting explicit subject. [#25](https://gitlab.com/arctic-fox/spectator/-/merge_requests/25)
-
-## [0.9.2] - 2020-01-14
-### Added
-- Add tests from RSpec docs.
-- Add `with_message` modifier for `raise_error` matcher.
-- Support omitted description on `it` and `specify` blocks. Use matcher description by default.
-
-### Fixed
-- Fix `let!` not inferring return type. [#4](https://github.com/icy-arctic-fox/spectator/issues/4)
-
-### Changed
-- Modified some matchers to behave more closely to their RSpec counterparts.
-
-## [0.9.1] - 2019-12-13
-### Fixed
-- Fix default stub with type.
-- Fix verifying double on self argument type.
-- Pass stub instead of stub name to mock registry.
-
-### Removed
-- Remove unnecessary type from stub class hierarchy.
-
-## [0.9.0] - 2019-12-08
-### Added
-- Implement initial mocks and doubles (stubbing) support. [#16](https://gitlab.com/arctic-fox/spectator/-/merge_requests/16) [#6](https://gitlab.com/arctic-fox/spectator/-/issues/6)
-- Deferred expectations (`to_eventually` and `to_never`).
-
-### Changed
-- Test cases no longer define an entire class, but rather a method in a class belonging to the group.
-
-## [0.8.3] - 2019-09-23
-### Fixed
-- Fix and address warnings with Crystal 0.31.0.
-
-## [0.8.2] - 2019-08-21
-### Fixed
-- Workaround for Crystal compiler bug [#7060](https://github.com/crystal-lang/crystal/issues/7060). [#1](https://github.com/icy-arctic-fox/spectator/issues/1)
-
-## [0.8.1] - 2019-08-17
-### Fixed
-- Fix nested `sample_value` blocks giving cryptic error. [#20](https://gitlab.com/arctic-fox/spectator/-/issues/20)
-
-## [0.8.0] - 2019-08-12
-### Added
-- Add "any order" modifier for `contains_exactly` and `match_array`.
-- Add `change` matcher and its variations.
-- Add `all` matcher.
-- Variation of `let` syntax that takes an assignment.
-
-### Changed
-- Rewrote matcher class structure.
-- Improved tracking of actual and expected values and their labels.
-- Matcher values are only produced when the match fails, instead of always.
-
-### Fixed
-- Fix malformed code generated by macros not working in latest Crystal version.
-
-## [0.7.2] - 2019-06-01
-### Fixed
-- Reference types used in `subject` and `let` were recreated between hooks and the test block. [#11](https://gitlab.com/arctic-fox/spectator/-/issues/11)
-
-## [0.7.1] - 2019-05-21
-### Fixed
-- Fixed an issue where named subjects could crash the compiler.
-
-## [0.7.0] - 2019-05-16
-### Added
-- Added `be_between` matcher.
-
-### Changed
-- The `be_within` matcher behaves like RSpec's.
-
-## [0.6.0] - 2019-05-08
-### Changed
-- Introduced reference matcher and changed `be` matcher to use it instead of the case matcher.
-
-### Removed
-- Removed regex matcher, the case matcher is used instead.
-
-## [0.5.3] - 2019-05-08
-### Fixed
-- Updated the `expect_raises` matcher to accept an optional second argument to mimic `raise_error`. [#4](https://gitlab.com/arctic-fox/spectator/-/issues/4)
-
-## [0.5.2] - 2019-04-22
-### Fixed
-- Fix `after_all` hooks not running with fail-fast enabled. [#2](https://gitlab.com/arctic-fox/spectator/-/issues/2)
-
-## [0.5.1] - 2019-04-18
-### Added
-- Note in README regarding repository mirror.
-
-### Fixed
-- Change protection on expectation partial to work with Crystal 0.28 and "should" syntax.
-- Change references to `Time.now` to `Time.utc` in docs.
-
-## [0.5.0] - 2019-04-07
-First version ready for public use.
-
-
-[Unreleased]: https://gitlab.com/arctic-fox/spectator/-/compare/v0.12.0...master
-[0.12.0]: https://gitlab.com/arctic-fox/spectator/-/compare/v0.11.7...v0.12.0
-[0.11.7]: https://gitlab.com/arctic-fox/spectator/-/compare/v0.11.6...v0.11.7
-[0.11.6]: https://gitlab.com/arctic-fox/spectator/-/compare/v0.11.5...v0.11.6
-[0.11.5]: https://gitlab.com/arctic-fox/spectator/-/compare/v0.11.4...v0.11.5
-[0.11.4]: https://gitlab.com/arctic-fox/spectator/-/compare/v0.11.3...v0.11.4
-[0.11.3]: https://gitlab.com/arctic-fox/spectator/-/compare/v0.11.2...v0.11.3
-[0.11.2]: https://gitlab.com/arctic-fox/spectator/-/compare/v0.11.1...v0.11.2
-[0.11.1]: https://gitlab.com/arctic-fox/spectator/-/compare/v0.11.0...v0.11.1
-[0.11.0]: https://gitlab.com/arctic-fox/spectator/-/compare/v0.10.6...v0.11.0
-[0.10.6]: https://gitlab.com/arctic-fox/spectator/-/compare/v0.10.5...v0.10.6
-[0.10.5]: https://gitlab.com/arctic-fox/spectator/-/compare/v0.10.4...v0.10.5
-[0.10.4]: https://gitlab.com/arctic-fox/spectator/-/compare/v0.10.3...v0.10.4
-[0.10.3]: https://gitlab.com/arctic-fox/spectator/-/compare/v0.10.2...v0.10.3
-[0.10.2]: https://gitlab.com/arctic-fox/spectator/-/compare/v0.10.1...v0.10.2
-[0.10.1]: https://gitlab.com/arctic-fox/spectator/-/compare/v0.10.0...v0.10.1
-[0.10.0]: https://gitlab.com/arctic-fox/spectator/-/compare/v0.9.40...v0.10.0
-[0.9.40]: https://gitlab.com/arctic-fox/spectator/-/compare/v0.9.39...v0.9.40
-[0.9.39]: https://gitlab.com/arctic-fox/spectator/-/compare/v0.9.38...v0.9.39
-[0.9.38]: https://gitlab.com/arctic-fox/spectator/-/compare/v0.9.37...v0.9.38
-[0.9.37]: https://gitlab.com/arctic-fox/spectator/-/compare/v0.9.36...v0.9.37
-[0.9.36]: https://gitlab.com/arctic-fox/spectator/-/compare/v0.9.35...v0.9.36
-[0.9.35]: https://gitlab.com/arctic-fox/spectator/-/compare/v0.9.34...v0.9.35
-[0.9.34]: https://gitlab.com/arctic-fox/spectator/-/compare/v0.9.33...v0.9.34
-[0.9.33]: https://gitlab.com/arctic-fox/spectator/-/compare/v0.9.32...v0.9.33
-[0.9.32]: https://gitlab.com/arctic-fox/spectator/-/compare/v0.9.31...v0.9.32
-[0.9.31]: https://gitlab.com/arctic-fox/spectator/-/compare/v0.9.30...v0.9.31
-[0.9.30]: https://gitlab.com/arctic-fox/spectator/-/compare/v0.9.29...v0.9.30
-[0.9.29]: https://gitlab.com/arctic-fox/spectator/-/compare/v0.9.28...v0.9.29
-[0.9.28]: https://gitlab.com/arctic-fox/spectator/-/compare/v0.9.27...v0.9.28
-[0.9.27]: https://gitlab.com/arctic-fox/spectator/-/compare/v0.9.26...v0.9.27
-[0.9.26]: https://gitlab.com/arctic-fox/spectator/-/compare/v0.9.25...v0.9.26
-[0.9.25]: https://gitlab.com/arctic-fox/spectator/-/compare/v0.9.24...v0.9.25
-[0.9.24]: https://gitlab.com/arctic-fox/spectator/-/compare/v0.9.23...v0.9.24
-[0.9.23]: https://gitlab.com/arctic-fox/spectator/-/compare/v0.9.22...v0.9.23
-[0.9.22]: https://gitlab.com/arctic-fox/spectator/-/compare/v0.9.21...v0.9.22
-[0.9.21]: https://gitlab.com/arctic-fox/spectator/-/compare/v0.9.20...v0.9.21
-[0.9.20]: https://gitlab.com/arctic-fox/spectator/-/compare/v0.9.19...v0.9.20
-[0.9.19]: https://gitlab.com/arctic-fox/spectator/-/compare/v0.9.18...v0.9.19
-[0.9.18]: https://gitlab.com/arctic-fox/spectator/-/compare/v0.9.17...v0.9.18
-[0.9.17]: https://gitlab.com/arctic-fox/spectator/-/compare/v0.9.16...v0.9.17
-[0.9.16]: https://gitlab.com/arctic-fox/spectator/-/compare/v0.9.15...v0.9.16
-[0.9.15]: https://gitlab.com/arctic-fox/spectator/-/compare/v0.9.14...v0.9.15
-[0.9.14]: https://gitlab.com/arctic-fox/spectator/-/compare/v0.9.13...v0.9.14
-[0.9.13]: https://gitlab.com/arctic-fox/spectator/-/compare/v0.9.12...v0.9.13
-[0.9.12]: https://gitlab.com/arctic-fox/spectator/-/compare/v0.9.11...v0.9.12
-[0.9.11]: https://gitlab.com/arctic-fox/spectator/-/compare/v0.9.10...v0.9.11
-[0.9.10]: https://gitlab.com/arctic-fox/spectator/-/compare/v0.9.9...v0.9.10
-[0.9.9]: https://gitlab.com/arctic-fox/spectator/-/compare/v0.9.8...v0.9.9
-[0.9.8]: https://gitlab.com/arctic-fox/spectator/-/compare/v0.9.7...v0.9.8
-[0.9.7]: https://gitlab.com/arctic-fox/spectator/-/compare/v0.9.6...v0.9.7
-[0.9.6]: https://gitlab.com/arctic-fox/spectator/-/compare/v0.9.5...v0.9.6
-[0.9.5]: https://gitlab.com/arctic-fox/spectator/-/compare/v0.9.4...v0.9.5
-[0.9.4]: https://gitlab.com/arctic-fox/spectator/-/compare/v0.9.3...v0.9.4
-[0.9.3]: https://gitlab.com/arctic-fox/spectator/-/compare/v0.9.2...v0.9.3
-[0.9.2]: https://gitlab.com/arctic-fox/spectator/-/compare/v0.9.1...v0.9.2
-[0.9.1]: https://gitlab.com/arctic-fox/spectator/-/compare/v0.9.0...v0.9.1
-[0.9.0]: https://gitlab.com/arctic-fox/spectator/-/compare/v0.8.3...v0.9.0
-[0.8.3]: https://gitlab.com/arctic-fox/spectator/-/compare/v0.8.2...v0.8.3
-[0.8.2]: https://gitlab.com/arctic-fox/spectator/-/compare/v0.8.1...v0.8.2
-[0.8.1]: https://gitlab.com/arctic-fox/spectator/-/compare/v0.8.0...v0.8.1
-[0.8.0]: https://gitlab.com/arctic-fox/spectator/-/compare/v0.7.2...v0.8.0
-[0.7.2]: https://gitlab.com/arctic-fox/spectator/-/compare/v0.7.1...v0.7.2
-[0.7.1]: https://gitlab.com/arctic-fox/spectator/-/compare/v0.7.0...v0.7.1
-[0.7.0]: https://gitlab.com/arctic-fox/spectator/-/compare/v0.6.0...v0.7.0
-[0.6.0]: https://gitlab.com/arctic-fox/spectator/-/compare/v0.5.2...v0.6.0
-[0.5.3]: https://gitlab.com/arctic-fox/spectator/-/compare/v0.5.2...v0.5.3
-[0.5.2]: https://gitlab.com/arctic-fox/spectator/-/compare/v0.5.1...v0.5.2
-[0.5.1]: https://gitlab.com/arctic-fox/spectator/-/compare/v0.5.0...v0.5.1
-[0.5.0]: https://gitlab.com/arctic-fox/spectator/-/releases/v0.5.0
diff --git a/lib/spectator/CONTRIBUTING.md b/lib/spectator/CONTRIBUTING.md
deleted file mode 100644
index 0dbf778..0000000
--- a/lib/spectator/CONTRIBUTING.md
+++ /dev/null
@@ -1,204 +0,0 @@
-# Contributing to Spectator
-
-Welcome to Spectator! We're glad you're here!
-
-Spectator strives to be an easy-to-use, batteries included testing framework for Crystal shards and applications.
-The goal of Spectator is to:
-
-- Provide an easy-to-understand syntax for tests. Reading and writing tests should feel natural.
-- Lower the bar to entry. Simplify non-trivial use cases make testing easier.
-- Remove boilerplate. Reduce the amount of code necessary to get the job done. Provide common utilities.
-
-Spectator is heavily inspired by [RSpec](https://rspec.info/).
-It tries to maintain compatibility with RSpec, but this isn't always possible.
-Some language differences between [Ruby and Crystal](https://www.crystalforrubyists.com/) prohibit this.
-Spectator also maintains feature parity with Crystal's [Spec](https://crystal-lang.org/reference/guides/testing.html).
-
-**Table of Contents**
-
-- [Useful links](#useful-links)
-- [Repository hosting](#repository-hosting)
-- [How can I contribute?](#how-can-i-contribute)
- - [Upcoming](#upcoming)
- - [How to submit changes](#how-to-submit-changes)
- - [How to report a bug](#how-to-report-a-bug)
- - [How to request an enhancement](#how-to-request-an-enhancement)
- - [Where can I get help?](#where-can-i-get-help)
-- [Development](#development)
- - [Testing](#testing)
- - [Style guide and conventions](#style-guide-and-conventions)
- - [Branching](#branching)
-
-## Useful links
-
-Here are some useful links for Spectator:
-
-- [README](README.md)
-- [Change log](CHANGELOG.md)
-- [Architecture](ARCHITECTURE.md)
-- Wiki [GitLab](https://gitlab.com/arctic-fox/spectator/-/wikis/home) | [GitHub](https://github.com/icy-arctic-fox/spectator/wiki)
- - Big List of Matchers [GitLab](https://gitlab.com/arctic-fox/spectator/-/wikis/Big-List-of-Matchers) | [GitHub](https://github.com/icy-arctic-fox/spectator/wiki/Big-List-of-Matchers)
-- [Documentation (Crystal docs)](https://arctic-fox.gitlab.io/spectator)
-- Issue tracker [GitLab](https://gitlab.com/arctic-fox/spectator/-/issues) | [GitHub](https://github.com/icy-arctic-fox/spectator/issues)
-- [Builds](https://gitlab.com/arctic-fox/spectator/-/pipelines)
-- [Crystal Macros](https://crystal-lang.org/reference/syntax_and_semantics/macros/index.html)
- - [API](https://crystal-lang.org/api/latest/Crystal/Macros.html)
-
-## Repository hosting
-
-Spectator is available on [GitHub](https://github.com/icy-arctic-fox/spectator) and [GitLab](https://gitlab.com/arctic-fox/spectator).
-The primary housing for Spectator is [GitLab](https://gitlab.com/arctic-fox/spectator).
-This is a preference of the primary developer ([arctic-fox](https://gitlab.com/arctic-fox)).
-That doesn't mean GitLab is the only place to contribute!
-The repository and wiki are mirrored and maintainers will ensure contributions get into the project.
-Issues, pull requests, and other contributions are accepted on both.
-Use whichever you prefer!
-
-## How can I contribute?
-
-You can contribute in a variety of ways.
-One of the easiest ways to contribute is to use Spectator!
-Provide us feedback and report and bugs or issues you find.
-Being a testing framework, Spectator should be rock solid.
-
-If you want to contribute to the codebase, take a look at the open issues.
-[GitLab](https://gitlab.com/arctic-fox/spectator/-/issues) | [GitHub](https://github.com/icy-arctic-fox/spectator/issues)
-Any issue not assigned can be picked up.
-Even if one is already assigned, you may still be able to help out, just ask!
-
-If there isn't an issue for something you want to add or change, please create one first.
-That way, we can discuss it before possibly wasting time on a misunderstanding.
-Check out the [upcoming](#upcoming) section for a list of upcoming changes.
-Anyone submitting code to Spectator will get a call-out in the [change log](CHANGELOG.md).
-
-You can also help by writing tests or documentation for the wiki.
-
-### Upcoming
-
-These are the projects that Spectator maintainers are looking to tackle next.
-These issues are quite substantial, but assistance would be greatly appreciated!
-
-- [Overhaul of the mock and stubbing system](https://gitlab.com/arctic-fox/spectator/-/issues/63)
-- [Errors masked in DSL by `method_missing` (predicate matcher)](https://gitlab.com/arctic-fox/spectator/-/issues/64)
-- [Custom matcher DSL](https://gitlab.com/arctic-fox/spectator/-/issues/65)
-- [Compiler optimizations](https://gitlab.com/arctic-fox/spectator/-/issues/66)
-- More tests!
-
-### How to submit changes
-
-Submit your changes as a pull request (either GitLab or GitHub).
-Please keep change requests focused on a single feature or bug.
-Larger pull requests may be broken up into logical pieces.
-This helps reviewers digest the changes.
-
-Describe the purpose of the change, what it addresses.
-Provide links to related issues, bugs the changes fix, or external resources (i.e. RSpec docs).
-Note any significant items or breaking changes.
-Include a snippet of code demonstrating the code, if applicable.
-
-Please include tests for new code and bug fixes.
-Some parts of Spectator are harder to test than others.
-Check out the [testing](#testing) section for more information.
-
-### How to report a bug
-
-Be sure you can reproduce the issue.
-Try to reduce the amount of code and complexity needed to reproduce the issue.
-Check of outstanding issues, it might already be reported.
-
-Open an issue (either [GitLab](https://gitlab.com/arctic-fox/spectator/-/issues/new) or [GitHub](https://github.com/icy-arctic-fox/spectator/issues/new)).
-Provide information on what you're trying to do.
-Include source code that reproduces the issue.
-Add any specific details or specifics about your usage and environment.
-For instance: using Windows, compiling with specific flags, dependencies on other shards, custom helper code, etc.
-
-Maintainers generally won't close an issue until they're certain it is resolved.
-We may ask that you verify the fix on your end before closing the issue.
-
-### How to request an enhancement
-
-Check for existing feature requests, someone might already have the same idea.
-Create a new issue (either [GitLab](https://gitlab.com/arctic-fox/spectator/-/issues/new) or [GitHub](https://github.com/icy-arctic-fox/spectator/issues/new)).
-Explain what you're trying to do or would like improved.
-Include reasoning - why do you want this feature, what would it help with?
-Provide code snippets if it helps illustrate the idea.
-
-## Where can I get help?
-
-First checkout the [README](README.md) and wiki ([GitLab](https://gitlab.com/arctic-fox/spectator/-/wikis/home) | [GitHub](https://github.com/icy-arctic-fox/spectator/wiki)).
-These two locations are official sources of information for the project.
-
-Look for existing issues before creating a new one.
-We use issues for bugs, features, and general help/support.
-You might find something that addresses your issue or points you in the right direction.
-Adding a :+1: to the original issue is appreciated!
-
-If you can't find anything already out there, submit an issue.
-Explain what you're trying to do and maybe an explanation of why.
-Sometimes we might discover a better solution for what you're attempting to do.
-Provide code snippets, command-line, and examples if possible.
-
-## Development
-
-Spectator is cross-platform and should work on any OS that [Crystal supports](https://crystal-lang.org/install/).
-Development on Spectator is possible with a default Crystal installation (with Shards).
-
-To get started:
-
-1. Fork the repository [GitLab](https://gitlab.com/arctic-fox/spectator/fork/new) | [GitHub](https://github.com/icy-arctic-fox/spectator/fork)
-2. Clone the forked git repository.
-3. Run `shards` in the repository to pull developer dependencies.
-4. Verify everything works by running `crystal spec`.
-
-At this point, dive into the code or check out the [architecture](ARCHITECTURE.md).
-
-### Testing
-
-Spectator uses itself for testing.
-Please try to write tests for any new features that are added.
-Bugs should have tests created for them to combat regression.
-
-The `spec/` directory contains all tests.
-The feature tests are grouped into sub directories based on their type, they are:
-
-- `docs/` - Example snippets from Spectator's documentation.
-- `features/` - Tests for Spectator's DSL and headline features.
-- `issues/` - Tests for reported bugs.
-- `matchers/` - Exhaustive testing of matchers.
-- `rspec/` - Examples from RSpec's documentation modified slightly to work with Spectator. See: https://relishapp.com/rspec/
-- `spectator/` - Unit tests for Spectator internals.
-
-The `helpers/` directory contains utilities to aid tests.
-
-### Style guide and conventions
-
-General Crystal styling should be used.
-To ensure everything is formatted correctly, run `crystal tool format` prior to committing.
-
-Additionally, [Ameba](https://crystal-ameba.github.io/) is used to encourage best coding practices.
-To run Ameba, run `bin/ameba` in the root of the repository.
-This requires that shards have been installed.
-
-Formatting checks and Ameba will be run as part of the CI pipeline.
-Both are required to pass before a pull request will be accepted and merged.
-Exceptions can be made for some Ameba issues.
-Adding `#ameba:disable` to a line will [disable Ameba](https://crystal-ameba.github.io/ameba/#inline-disabling) for a particular issue.
-However, please prefer to fix the issue instead of ignoring them.
-
-Please attempt to document every class and public method.
-Documentation isn't required on private methods and trivial code.
-Please add comments explaining algorithms and complex code.
-DSL methods and macros should be heavily documented.
-This helps developers using Spectator.
-
-HTML documentation is automatically generated (by `crystal docs`) and published to [GitLab pages](https://arctic-fox.gitlab.io/spectator).
-
-### Branching
-
-The `master` branch contains the latest stable code.
-Branches are used for features, fixes, and release preparation.
-
-A new minor release is made whenever there is enough functionality to warrant one or some time has passed since the last one and there's pending fixes.
-A new major release occurs when there are substantial changes to Spectator.
-Known breaking changes are always in a major release.
-Tags are made for each release.
diff --git a/lib/spectator/LICENSE b/lib/spectator/LICENSE
deleted file mode 100644
index e4174f9..0000000
--- a/lib/spectator/LICENSE
+++ /dev/null
@@ -1,21 +0,0 @@
-The MIT License (MIT)
-
-Copyright (c) 2018 Michael Miller
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
diff --git a/lib/spectator/README.md b/lib/spectator/README.md
deleted file mode 100644
index 323b4ca..0000000
--- a/lib/spectator/README.md
+++ /dev/null
@@ -1,427 +0,0 @@
-Spectator
-=========
-
-Spectator is a fully-featured spec-based test framework for Crystal.
-It mimics features from [RSpec](http://rspec.info/).
-Developers coming from Ruby and RSpec will feel right at home.
-Spectator provides additional functionality to make testing easier and more fluent.
-
-**Goal:**
-
-Spectator is designed to:
-
-- Reduce complexity of test code.
-- Remove boilerplate from tests.
-- Lower the difficulty of writing non-trivial tests.
-- Provide an elegant syntax that is easy to read and understand.
-- Provide common utilities that the end-user would otherwise need to write.
-
-Installation
-------------
-
-Add this to your application's `shard.yml`:
-
-```yaml
-development_dependencies:
- spectator:
- gitlab: arctic-fox/spectator
- version: ~> 0.11.0
-```
-
-Usage
------
-
-If it doesn't exist already, create a `spec/spec_helper.cr` file.
-In it, place the following:
-
-```crystal
-require "../src/*"
-require "spectator"
-```
-
-This will include Spectator and the source code for your shard.
-Now you can start writing your specs.
-The syntax is the same as what you would expect from modern RSpec.
-The "expect" syntax is recommended and the default, however the "should" syntax is also available.
-Your specs must be wrapped in a `Spectator.describe` block.
-All other blocks inside the top-level block may use `describe` and `context` without the `Spectator.` prefix.
-
-Here's a minimal spec to demonstrate:
-
-```crystal
-require "./spec_helper"
-
-Spectator.describe String do
- subject { "foo" }
-
- describe "#==" do
- context "with the same value" do
- let(value) { subject.dup }
-
- it "is true" do
- is_expected.to eq(value)
- end
- end
-
- context "with a different value" do
- let(value) { "bar" }
-
- it "is false" do
- is_expected.to_not eq(value)
- end
- end
- end
-end
-```
-
-If you find yourself trying to shoehorn in functionality
-or unsure how to write a test, please create an [issue](https://gitlab.com/arctic-fox/spectator/issues/new) for it.
-The goal is to make it as easy as possible to write specs and keep your code clean.
-We may come up with a solution or even introduce a feature to support your needs.
-
-**NOTE:** Due to the way this shard uses macros,
-you may find that some code you would expect to work, or works in other spec libraries, creates syntax errors.
-If you run into this, please create an issue so that we may try to resolve it.
-
-Features
---------
-
-Spectator has all of the basic functionality for BDD.
-For full documentation on what it can do, please visit the [wiki](https://gitlab.com/arctic-fox/spectator/wikis/home).
-
-### Contexts
-
-The DSL supports arbitrarily nested contexts.
-Contexts can have values defined for multiple tests (`let` and `subject`).
-Additionally, hooks can be used to ensure any initialization or cleanup is done (`before`, `after`, and `around`).
-Pre- and post-conditions can be used to ensure code contracts are kept.
-
-```crystal
-# Initialize the database before running the tests in this context.
-before_all { Database.init }
-
-# Teardown the database and cleanup after tests in the is context finish.
-after_all { Database.cleanup }
-
-# Before each test, add some rows to the database.
-let(row_count) { 5 }
-before_each do
- row_count.times { Database.insert_row }
-end
-
-# Remove the rows after the test to get a clean slate.
-after_each { Database.clear }
-
-describe "#row_count" do
- it "returns the number of rows" do
- expect(Database.row_count).to eq(row_count)
- end
-end
-```
-
-Spectator has different types of contexts to reduce boilerplate.
-One is the `sample` context.
-This context type repeats all tests (and contexts within) for a set of values.
-For instance, some feature should behave the same for different input.
-However, some inputs might cause problems, but should behave the same.
-An example is various strings (empty strings, quoted strings, strings with non-ASCII, etc),
-and numbers (positive, negative, zero, NaN, infinity).
-
-```crystal
-# List of integers to test against.
-def various_integers
- [-7, -1, 0, 1, 42]
-end
-
-# Repeat nested tests for every value in `#various_integers`.
-sample various_integers do |int|
- # Example that checks if a fictitious method `#format` converts to strings.
- it "formats correctly" do
- expect(format(int)).to eq(int.to_s)
- end
-end
-```
-
-Another context type is `provided`.
-This context drastically reduces the amount of code needed in some scenarios.
-It can be used where one (or more inputs) changes the output of multiple methods.
-The `provided` context gives a concise syntax for this use case.
-
-```crystal
-subject(user) { User.new(age) }
-
-# Each expression in the `provided` block is its own test.
-provided age = 10 do
- expect(user.can_drive?).to be_false
- expect(user.can_vote?).to be_false
-end
-
-provided age = 16 do
- expect(user.can_drive?).to be_true
- expect(user.can_vote?).to be_false
-end
-
-provided age = 18 do
- expect(user.can_drive?).to be_true
- expect(user.can_vote?).to be_true
-end
-```
-
-### Assertions
-
-Spectator supports two formats for assertions (expectations).
-The preferred format is the "expect syntax".
-This takes the form:
-
-```crystal
-expect(THIS).to eq(THAT)
-```
-
-The other format, "should syntax" is used by Crystal's default Spec.
-
-```
-THIS.should eq(THAT)
-```
-
-The first format doesn't monkey-patch the `Object` type.
-And as a bonus, it captures the expression or variable passed to `expect()`.
-For instance, compare these two tests:
-
-```crystal
-foo = "Hello world"
-foo.size.should eq(12) # Wrong on purpose!
-```
-
-Produces this error output:
-
-```text
-Failure: 11 does not equal 12
-
- expected: 11
- actual: 12
-```
-
-Which is reasonable, but where did 11 come from?
-Alternatively, with the "expect syntax":
-
-```crystal
-foo = "Hello world"
-expect(foo.size).to eq(12) # Wrong on purpose!
-```
-
-Produces this error output:
-
-```text
-Failure: foo.size does not equal 12
-
- expected: 12
- actual: 11
-```
-
-This makes it clearer what was being tested and failed.
-
-### Matchers
-
-Spectator has a variety of matchers for assertions.
-These are named in such a way to help tests read as plain English.
-Matchers can be used on any value or block.
-
-There are typical matchers for testing equality: `eq` and `ne`.
-And matchers for comparison: `<`, `<=`, `>`, `>=`, `be_within`.
-There are matchers for checking contents of collections:
-`contain`, `have`, `start_with`, `end_with`, `be_empty`, `have_key`, and more.
-See the [wiki](https://gitlab.com/arctic-fox/spectator/wikis/Matchers) for a full list of matchers.
-
-### Running
-
-Spectator supports multiple options for running tests.
-"Fail fast" aborts on the first test failure.
-"Fail blank" fails if there are no tests.
-Tests can be filtered by their location and name.
-Additionally, tests can be randomized.
-Spectator can be configured with command-line arguments,
-a configure block in a `spec_helper.cr` file, and `.spectator` configuration file.
-
-```crystal
-Spectator.configure do |config|
- config.fail_blank # Fail on no tests.
- config.randomize # Randomize test order.
- config.profile # Display slowest tests.
-end
-```
-
-### Mocks and Doubles
-
-Spectator supports an extensive mocking feature set via two types - mocks and doubles.
-Mocks are used to override behavior in existing types.
-Doubles are objects that stand-in when there are no type restrictions.
-Stubs can be defined on both which control how methods behave.
-
-```crystal
-abstract class Interface
- abstract def invoke(thing) : String
-end
-
-# Type being tested.
-class Driver
- def do_something(interface : Interface, thing)
- interface.invoke(thing)
- end
-end
-
-Spectator.describe Driver do
- # Define a mock for Interface.
- mock Interface
-
- # Define a double that the interface will use.
- double(:my_double, foo: 42)
-
- it "does a thing" do
- # Create an instance of the mock interface.
- interface = mock(Interface)
- # Indicate that `#invoke` should return "test" when called.
- allow(interface).to receive(:invoke).and_return("test")
-
- # Create an instance of the double.
- dbl = double(:my_double)
- # Call the mock method.
- subject.do_something(interface, dbl)
- # Verify everything went okay.
- expect(interface).to have_received(:invoke).with(dbl)
- end
-end
-```
-
-For details on mocks and doubles, see the [wiki](https://gitlab.com/arctic-fox/spectator/-/wikis/Mocks-and-Doubles).
-
-### Output
-
-Spectator matches Crystal's default Spec output with some minor changes.
-JUnit and TAP are also supported output formats.
-There are also highly detailed JSON and HTML outputs.
-
-Development
------------
-
-This shard is still in active development.
-New features are being added and existing functionality improved.
-Spectator is well-tested, but may have some yet-to-be-found bugs.
-
-### Feature Progress
-
-In no particular order, features that have been implemented and are planned.
-Items not marked as completed may have partial implementations.
-
-- [ ] DSL
- - [X] `describe` and `context` blocks
- - [X] Contextual values with `let`, `let!`, `subject`, `described_class`
- - [X] Test multiple and generated values - `sample`, `random_sample`
- - [X] Concise syntax - `provided` (was the now deprecated `given`)
- - [X] Before and after hooks - `before_each`, `before_all`, `after_each`, `after_all`, `around_each`
- - [X] Pre- and post-conditions - `pre_condition`, `post_condition`
- - [ ] Other hooks - `on_success`, `on_failure`, `on_error`
- - [X] One-liner syntax
- - [X] Should syntax - `should`, `should_not`
- - [X] Helper methods and modules
- - [ ] Aliasing - custom example group types with preset attributes
- - [X] Pending tests - `pending`
- - [ ] Shared examples - `behaves_like`, `include_examples`
- - [X] Deferred expectations - `to_eventually`, `to_never`
-- [ ] Matchers
- - [X] Equality matchers - `eq`, `ne`, `be ==`, `be !=`
- - [X] Comparison matchers - `be <`, `be <=`, `be >`, `be >=`, `be_within[.of]`, `be_close`
- - [X] Type matchers - `be_a`, `respond_to`
- - [ ] Collection matchers
- - [X] `contain`
- - [X] `have`
- - [X] `contain_exactly`
- - [X] `contain_exactly.in_any_order`
- - [X] `match_array`
- - [X] `match_array.in_any_order`
- - [X] `start_with`
- - [X] `end_with`
- - [X] `be_empty`
- - [X] `have_key`
- - [X] `have_value`
- - [X] `all`
- - [ ] `all_satisfy`
- - [X] Truthy matchers - `be`, `be_true`, `be_truthy`, `be_false`, `be_falsey`, `be_nil`
- - [X] Error matchers - `raise_error`
- - [ ] Yield matchers - `yield_control[.times]`, `yield_with_args[.times]`, `yield_with_no_args[.times]`, `yield_successive_args`
- - [ ] Output matchers - `output[.to_stdout|.to_stderr]`
- - [X] Predicate matchers - `be_x`, `have_x`
- - [ ] Misc. matchers
- - [X] `match`
- - [ ] `satisfy`
- - [X] `change[.by|.from[.to]|.to|.by_at_least|.by_at_most]`
- - [X] `have_attributes`
- - [ ] Compound - `and`, `or`
-- [ ] Mocks and Doubles
- - [X] Mocks (Stub real types) - `mock TYPE { }`
- - [X] Doubles (Stand-ins for real types) - `double NAME { }`
- - [X] Method stubs - `allow().to receive()`, `allow().to receive().and_return()`
- - [X] Spies - `expect().to have_received()`
- - [X] Message expectations - `expect().to have_received().at_least()`
- - [X] Argument expectations - `expect().to have_received().with()`
- - [ ] Message ordering - `expect().to have_received().ordered`
- - [X] Null doubles
-- [X] Runner
- - [X] Fail fast
- - [X] Test filtering - by name, context, and tags
- - [X] Fail on no tests
- - [X] Randomize test order
- - [X] Dry run - for validation and checking formatted output
- - [X] Config block in `spec_helper.cr`
- - [X] Config file - `.spectator`
-- [X] Reporter and formatting
- - [X] RSpec/Crystal Spec default
- - [X] JSON
- - [X] JUnit
- - [X] TAP
- - [X] HTML
-
-### How it Works (in a nutshell)
-
-This shard makes extensive use of the Crystal macro system to build classes and modules.
-Each `describe` and `context` block creates a new class that inherits its parent.
-The `it` block creates an method.
-An instance of the group class is created to run the test.
-Each group class includes all test values and hooks.
-
-Contributing
-------------
-
-1. Fork it (GitHub or GitLab )
-2. Create your feature branch (`git checkout -b my-new-feature`)
-3. Commit your changes (`git commit -am 'Add some feature'`)
-4. Push to the branch (`git push origin my-new-feature`)
-5. Create a new Pull/Merge Request
-
-Please make sure to run `crystal tool format` before submitting.
-The CI build checks for properly formatted code.
-[Ameba](https://crystal-ameba.github.io/) is run to check for code style.
-
-Documentation is automatically generated and published to GitLab pages.
-It can be found here: https://arctic-fox.gitlab.io/spectator
-
-This project's home is (and primarily developed) on [GitLab](https://gitlab.com/arctic-fox/spectator).
-A mirror is maintained to [GitHub](https://github.com/icy-arctic-fox/spectator).
-Issues, pull requests (merge requests), and discussion are welcome on both.
-Maintainers will ensure your contributions make it in.
-
-For more information, see: [CONTRIBUTING.md](CONTRIBUTING.md)
-
-### Testing
-
-Tests must be written for any new functionality.
-
-The `spec/` directory contains feature tests as well as unit tests.
-These demonstrate small bits of functionality.
-The feature tests are grouped into sub directories based on their type, they are:
-
-- docs/ - Example snippets from Spectator's documentation.
-- rspec/ - Examples from RSpec's documentation modified slightly to work with Spectator.
- See: https://relishapp.com/rspec/
- Additional sub directories in this directory represent the modules/projects of RSpec.
-
-The other directories are for unit testing various parts of Spectator.
diff --git a/lib/spectator/lib b/lib/spectator/lib
deleted file mode 120000
index a96aa0e..0000000
--- a/lib/spectator/lib
+++ /dev/null
@@ -1 +0,0 @@
-..
\ No newline at end of file
diff --git a/lib/spectator/shard.yml b/lib/spectator/shard.yml
deleted file mode 100644
index 559754f..0000000
--- a/lib/spectator/shard.yml
+++ /dev/null
@@ -1,16 +0,0 @@
-name: spectator
-version: 0.12.0
-description: |
- Feature-rich testing framework for Crystal inspired by RSpec.
-
-authors:
- - Michael Miller
-
-crystal: 1.6.0
-
-license: MIT
-
-development_dependencies:
- ameba:
- github: crystal-ameba/ameba
- version: ~> 1.2.0
diff --git a/lib/spectator/src/spectator.cr b/lib/spectator/src/spectator.cr
deleted file mode 100644
index a05a7e2..0000000
--- a/lib/spectator/src/spectator.cr
+++ /dev/null
@@ -1,120 +0,0 @@
-require "colorize"
-require "log"
-require "./spectator/includes"
-
-# Module that contains all functionality related to Spectator.
-module Spectator
- extend self
- include DSL::Top
-
- # Current version of the Spectator library.
- VERSION = {{ `shards version "#{__DIR__}"`.stringify.chomp }}
-
- # Logger for Spectator internals.
- ::Log.setup_from_env
- Log = ::Log.for(self)
-
- # Flag indicating whether Spectator should automatically run tests.
- # This should be left alone (set to true) in typical usage.
- # There are times when Spectator shouldn't run tests.
- # One of those is testing Spectator.
- class_property? autorun = true
-
- # All tests are ran just before the executable exits.
- # Tests will be skipped, however, if `#autorun?` is set to false.
- # There are a couple of reasons for this.
- #
- # First is that we want a clean interface for the end-user.
- # They shouldn't need to call a "run" method.
- # That adds the burden on the developer to ensure the tests are run after they are created.
- # And that gets complicated when there are multiple files that could run in any order.
- #
- # Second is to allow all of the tests and framework to be constructed.
- # We know that all of the instances and DSL builders have finished
- # after the main part of the executable has run.
- #
- # By doing this, we provide a clean interface and safely run after everything is constructed.
- # The downside, if something bad happens, like an exception is raised,
- # Crystal doesn't display much information about what happened.
- # That issue is handled by putting a begin/rescue block to show a custom error message.
- at_exit do
- # Run only if `#autorun?` is true.
- # Return 1 on failure.
- exit(1) if autorun? && !run
- end
-
- @@config_builder = Config::Builder.new
- @@config : Config?
-
- # Provides a means to configure how Spectator will run and report tests.
- # A `ConfigBuilder` is yielded to allow changing the configuration.
- # NOTE: The configuration set here can be overridden
- # with a `.spectator` file and command-line arguments.
- def configure(& : Config::Builder -> _) : Nil
- yield @@config_builder
- end
-
- # Random number generator for the test suite.
- # All randomly generated values should be pulled from this.
- # This provides re-producible results even though random values are used.
- # The seed for this random generator is controlled by `ConfigBuilder.seed=`.
- def random
- config.random
- end
-
- # Builds the tests and runs the framework.
- private def run
- # Silence default logger.
- ::Log.setup_from_env(default_level: :none)
-
- # Build the spec and run it.
- spec = DSL::Builder.build
- spec.run
- rescue ex
- # Re-enable logger for fatal error.
- ::Log.setup_from_env
-
- # Catch all unhandled exceptions here.
- # Examples are already wrapped, so any exceptions they throw are caught.
- # But if an exception occurs outside an example,
- # it's likely the fault of the test framework (Spectator).
- # So we display a helpful error that could be reported and return non-zero.
- Log.fatal(exception: ex) { "Spectator encountered an unexpected error" }
- false
- end
-
- # Global configuration used by Spectator for running tests.
- class_getter(config) { build_config }
-
- # Builds the configuration.
- private def build_config
- # Build up the configuration from various sources.
- # The sources that take priority are later in the list.
- apply_config_file
- apply_command_line_args
-
- @@config_builder.build
- end
-
- # Path to the Spectator configuration file.
- # The contents of this file should contain command-line arguments.
- # Those arguments are automatically applied when Spectator starts.
- # Arguments should be placed with one per line.
- CONFIG_FILE_PATH = ".spectator"
-
- # Loads configuration arguments from a file.
- # The file is expected to be new-line delimited,
- # one argument per line.
- # The arguments are identical to those
- # that would be passed on the command-line.
- private def apply_config_file(file_path = CONFIG_FILE_PATH) : Nil
- return unless File.exists?(file_path)
- args = File.read(file_path).lines
- Config::CLIArgumentsApplicator.new(args).apply(@@config_builder)
- end
-
- # Applies configuration options from the command-line arguments
- private def apply_command_line_args : Nil
- Config::CLIArgumentsApplicator.new.apply(@@config_builder)
- end
-end
diff --git a/lib/spectator/src/spectator/abstract_expression.cr b/lib/spectator/src/spectator/abstract_expression.cr
deleted file mode 100644
index 6ab4cbf..0000000
--- a/lib/spectator/src/spectator/abstract_expression.cr
+++ /dev/null
@@ -1,53 +0,0 @@
-require "./label"
-
-module Spectator
- # Represents an expression from a test.
- # This is typically captured by an `expect` macro.
- # It consists of a label and the value of the expression.
- # The label should be a string recognizable by the user,
- # or nil if one isn't available.
- #
- # This base class is provided so that all generic sub-classes can be stored as this one type.
- # The value of the expression can be retrieved by down-casting to the expected type with `#cast`.
- #
- # NOTE: This is intentionally a class and not a struct.
- # If it were a struct, changes made to the value held by an instance may not be kept when passing it around.
- # See commit ca564619ad2ae45f832a058d514298c868fdf699.
- abstract class AbstractExpression
- # User recognizable string for the expression.
- # This can be something like a variable name or a snippet of Crystal code.
- getter label : Label
-
- # Creates the expression.
- # The *label* is usually the Crystal code evaluating to the `#raw_value`.
- # It can be nil if it isn't available.
- def initialize(@label : Label)
- end
-
- # Retrieves the evaluated value of the expression.
- abstract def raw_value
-
- # Attempts to cast `#raw_value` to the type *T* and return it.
- def cast(type : T.class) : T forall T
- raw_value.as(T)
- end
-
- # Produces a string representation of the expression.
- # This consists of the label (if one is available) and the value.
- def to_s(io : IO) : Nil
- if (label = @label)
- io << label << ": "
- end
- raw_value.to_s(io)
- end
-
- # Produces a detailed string representation of the expression.
- # This consists of the label (if one is available) and the value.
- def inspect(io : IO) : Nil
- if (label = @label)
- io << label << ": "
- end
- raw_value.inspect(io)
- end
- end
-end
diff --git a/lib/spectator/src/spectator/anything.cr b/lib/spectator/src/spectator/anything.cr
deleted file mode 100644
index aa25e3c..0000000
--- a/lib/spectator/src/spectator/anything.cr
+++ /dev/null
@@ -1,25 +0,0 @@
-module Spectator
- # Type dedicated to matching everything.
- # This is intended to be used as a value to compare against when the value doesn't matter.
- # Can be used like so:
- # ```
- # anything = Spectator::Anything.new
- # expect("foo").to match(anything)
- # ```
- struct Anything
- # Always returns true.
- def ===(other)
- true
- end
-
- # Displays "anything".
- def to_s(io : IO) : Nil
- io << "anything"
- end
-
- # Displays "".
- def inspect(io : IO) : Nil
- io << ""
- end
- end
-end
diff --git a/lib/spectator/src/spectator/block.cr b/lib/spectator/src/spectator/block.cr
deleted file mode 100644
index 3e861ff..0000000
--- a/lib/spectator/src/spectator/block.cr
+++ /dev/null
@@ -1,34 +0,0 @@
-require "./expression"
-require "./label"
-
-module Spectator
- # Represents a block from a test.
- # This is typically captured by an `expect` macro.
- # It consists of a label and parameter-less block.
- # The label should be a string recognizable by the user,
- # or nil if one isn't available.
- class Block(T) < Expression(T)
- # Creates the block expression from a proc.
- # The *proc* will be called to evaluate the value of the expression.
- # The *label* is usually the Crystal code for the *proc*.
- # It can be nil if it isn't available.
- def initialize(@block : -> T, label : Label = nil)
- super(label)
- end
-
- # Creates the block expression by capturing a block as a proc.
- # The block will be called to evaluate the value of the expression.
- # The *label* is usually the Crystal code for the *block*.
- # It can be nil if it isn't available.
- def initialize(label : Label = nil, &@block : -> T)
- super(label)
- end
-
- # Evaluates the block and returns the value from it.
- # This method _does not_ cache the resulting value like `#value` does.
- # Successive calls to this method may return different values.
- def value : T
- @block.call
- end
- end
-end
diff --git a/lib/spectator/src/spectator/composite_node_filter.cr b/lib/spectator/src/spectator/composite_node_filter.cr
deleted file mode 100644
index 1450bcc..0000000
--- a/lib/spectator/src/spectator/composite_node_filter.cr
+++ /dev/null
@@ -1,15 +0,0 @@
-require "./node_filter"
-
-module Spectator
- # Filter that combines multiple other filters.
- class CompositeNodeFilter < NodeFilter
- # Creates the example filter.
- def initialize(@filters : Array(NodeFilter))
- end
-
- # Checks whether the node satisfies the filter.
- def includes?(node) : Bool
- @filters.any?(&.includes?(node))
- end
- end
-end
diff --git a/lib/spectator/src/spectator/config.cr b/lib/spectator/src/spectator/config.cr
deleted file mode 100644
index 66e6501..0000000
--- a/lib/spectator/src/spectator/config.cr
+++ /dev/null
@@ -1,120 +0,0 @@
-require "./config/*"
-require "./node_filter"
-require "./example_group"
-require "./filtered_example_iterator"
-require "./formatting/formatter"
-require "./node_iterator"
-require "./run_flags"
-
-module Spectator
- # Provides customization and describes specifics for how Spectator will run and report tests.
- class Config
- # Primary formatter all events will be sent to.
- getter formatter : Formatting::Formatter
-
- # Flags indicating how the spec should run.
- getter run_flags : RunFlags
-
- # Seed used for random number generation.
- getter random_seed : UInt64
-
- # Filter used to select which examples to run.
- getter node_filter : NodeFilter
-
- # Filter used to select which examples to _not_ run.
- getter node_reject : NodeFilter
-
- # Tags to filter on if they're present in a spec.
- protected getter match_filters : Metadata
-
- # List of hooks to run before all examples in the test suite.
- protected getter before_suite_hooks : Deque(ExampleGroupHook)
-
- # List of hooks to run before each top-level example group.
- protected getter before_all_hooks : Deque(ExampleGroupHook)
-
- # List of hooks to run before every example.
- protected getter before_each_hooks : Deque(ExampleHook)
-
- # List of hooks to run after all examples in the test suite.
- protected getter after_suite_hooks : Deque(ExampleGroupHook)
-
- # List of hooks to run after each top-level example group.
- protected getter after_all_hooks : Deque(ExampleGroupHook)
-
- # List of hooks to run after every example.
- protected getter after_each_hooks : Deque(ExampleHook)
-
- # List of hooks to run around every example.
- protected getter around_each_hooks : Deque(ExampleProcsyHook)
-
- # Creates a new configuration.
- # Properties are pulled from *source*.
- # Typically, *source* is a `Config::Builder`.
- def initialize(source)
- @formatter = source.formatter
- @run_flags = source.run_flags
- @random_seed = source.random_seed
- @node_filter = source.node_filter
- @node_reject = source.node_reject
- @match_filters = source.match_filters
-
- @before_suite_hooks = source.before_suite_hooks
- @before_all_hooks = source.before_all_hooks
- @before_each_hooks = source.before_each_hooks
- @after_suite_hooks = source.after_suite_hooks
- @after_all_hooks = source.after_all_hooks
- @after_each_hooks = source.after_each_hooks
- @around_each_hooks = source.around_each_hooks
- end
-
- # Produces the default configuration.
- def self.default : self
- Builder.new.build
- end
-
- # Shuffles the items in an array using the configured random settings.
- # If `#randomize?` is true, the *items* are shuffled and returned as a new array.
- # Otherwise, the items are left alone and returned as-is.
- # The array of *items* is never modified.
- def shuffle(items)
- return items unless run_flags.randomize?
-
- items.shuffle(random)
- end
-
- # Shuffles the items in an array using the configured random settings.
- # If `#randomize?` is true, the *items* are shuffled and returned.
- # Otherwise, the items are left alone and returned as-is.
- # The array of *items* is modified, the items are shuffled in-place.
- def shuffle!(items)
- return items unless run_flags.randomize?
-
- items.shuffle!(random)
- end
-
- # Creates an iterator configured to select the filtered examples.
- def iterator(group : ExampleGroup)
- match_filter = match_filter(group)
- iterator = FilteredExampleIterator.new(group, @node_filter)
- iterator = iterator.select(match_filter) if match_filter
- iterator.reject(@node_reject)
- end
-
- # Creates a node filter if any conditionally matching filters apply to an example group.
- private def match_filter(group : ExampleGroup) : NodeFilter?
- iterator = NodeIterator.new(group)
- filters = @match_filters.compact_map do |key, value|
- filter = TagNodeFilter.new(key.to_s, value)
- filter.as(NodeFilter) if iterator.rewind.any?(filter)
- end
- CompositeNodeFilter.new(filters) unless filters.empty?
- end
-
- # Retrieves the configured random number generator.
- # This will produce the same generator with the same seed every time.
- def random
- Random.new(random_seed)
- end
- end
-end
diff --git a/lib/spectator/src/spectator/config/builder.cr b/lib/spectator/src/spectator/config/builder.cr
deleted file mode 100644
index c7bdfa7..0000000
--- a/lib/spectator/src/spectator/config/builder.cr
+++ /dev/null
@@ -1,317 +0,0 @@
-require "../composite_node_filter"
-require "../node_filter"
-require "../formatting"
-require "../metadata"
-require "../null_node_filter"
-require "../run_flags"
-require "../tag_node_filter"
-
-module Spectator
- class Config
- # Mutable configuration used to produce a final configuration.
- # Use the setters in this class to incrementally build a configuration.
- # Then call `#build` to create the final configuration.
- class Builder
- # Seed used for random number generation.
- property random_seed : UInt64 = Random.rand(100000_u64)
-
- # Toggles indicating how the test spec should execute.
- property run_flags = RunFlags::None
-
- protected getter match_filters : Metadata = {:focus => nil.as(String?)}
-
- @primary_formatter : Formatting::Formatter?
- @additional_formatters = [] of Formatting::Formatter
- @filters = [] of NodeFilter
- @rejects = [] of NodeFilter
-
- # List of hooks to run before all examples in the test suite.
- protected getter before_suite_hooks = Deque(ExampleGroupHook).new
-
- # List of hooks to run before each top-level example group.
- protected getter before_all_hooks = Deque(ExampleGroupHook).new
-
- # List of hooks to run before every example.
- protected getter before_each_hooks = Deque(ExampleHook).new
-
- # List of hooks to run after all examples in the test suite.
- protected getter after_suite_hooks = Deque(ExampleGroupHook).new
-
- # List of hooks to run after each top-level example group.
- protected getter after_all_hooks = Deque(ExampleGroupHook).new
-
- # List of hooks to run after every example.
- protected getter after_each_hooks = Deque(ExampleHook).new
-
- # List of hooks to run around every example.
- protected getter around_each_hooks = Deque(ExampleProcsyHook).new
-
- # Attaches a hook to be invoked before all examples in the test suite.
- def add_before_suite_hook(hook)
- @before_suite_hooks.push(hook)
- end
-
- # Defines a block of code to execute before all examples in the test suite.
- def before_suite(&block)
- hook = ExampleGroupHook.new(&block)
- add_before_suite_hook(hook)
- end
-
- # Attaches a hook to be invoked before each top-level example group.
- def add_before_all_hook(hook)
- @before_all_hooks.push(hook)
- end
-
- # Defines a block of code to execute before each top-level example group.
- def before_all(&block)
- hook = ExampleGroupHook.new(&block)
- add_before_all_hook(hook)
- end
-
- # Attaches a hook to be invoked before every example.
- # The current example is provided as a block argument.
- def add_before_each_hook(hook)
- @before_each_hooks.push(hook)
- end
-
- # Defines a block of code to execute before every.
- # The current example is provided as a block argument.
- def before_each(&block : Example -> _)
- hook = ExampleHook.new(&block)
- add_before_each_hook(hook)
- end
-
- # Attaches a hook to be invoked after all examples in the test suite.
- def add_after_suite_hook(hook)
- @after_suite_hooks.unshift(hook)
- end
-
- # Defines a block of code to execute after all examples in the test suite.
- def after_suite(&block)
- hook = ExampleGroupHook.new(&block)
- add_after_suite_hook(hook)
- end
-
- # Attaches a hook to be invoked after each top-level example group.
- def add_after_all_hook(hook)
- @after_all_hooks.unshift(hook)
- end
-
- # Defines a block of code to execute after each top-level example group.
- def after_all(&block)
- hook = ExampleGroupHook.new(&block)
- add_after_all_hook(hook)
- end
-
- # Attaches a hook to be invoked after every example.
- # The current example is provided as a block argument.
- def add_after_each_hook(hook)
- @after_each_hooks.unshift(hook)
- end
-
- # Defines a block of code to execute after every example.
- # The current example is provided as a block argument.
- def after_each(&block : Example -> _)
- hook = ExampleHook.new(&block)
- add_after_each_hook(hook)
- end
-
- # Attaches a hook to be invoked around every example.
- # The current example in procsy form is provided as a block argument.
- def add_around_each_hook(hook)
- @around_each_hooks.push(hook)
- end
-
- # Defines a block of code to execute around every example.
- # The current example in procsy form is provided as a block argument.
- def around_each(&block : Example::Procsy -> _)
- hook = ExampleProcsyHook.new(label: "around_each", &block)
- add_around_each_hook(hook)
- end
-
- # Creates a configuration.
- def build : Config
- Config.new(self)
- end
-
- # Sets the primary formatter to use for reporting test progress and results.
- def formatter=(formatter : Formatting::Formatter)
- @primary_formatter = formatter
- end
-
- # Adds an extra formatter to use for reporting test progress and results.
- def add_formatter(formatter : Formatting::Formatter)
- @additional_formatters << formatter
- end
-
- # Retrieves the formatters to use.
- # If one wasn't specified by the user,
- # then `#default_formatter` is returned.
- private def formatters
- @additional_formatters + [(@primary_formatter || default_formatter)]
- end
-
- # The formatter that should be used if one wasn't provided.
- private def default_formatter
- Formatting::ProgressFormatter.new
- end
-
- # A single formatter that will satisfy the configured output.
- # If one formatter was configured, then it is returned.
- # Otherwise, a `Formatting::BroadcastFormatter` is returned.
- protected def formatter
- case (formatters = self.formatters)
- when .one? then formatters.first
- else Formatting::BroadcastFormatter.new(formatters)
- end
- end
-
- # Enables fail-fast mode.
- def fail_fast
- @run_flags |= RunFlags::FailFast
- end
-
- # Sets the fail-fast flag.
- def fail_fast=(flag)
- if flag
- @run_flags |= RunFlags::FailFast
- else
- @run_flags &= ~RunFlags::FailFast
- end
- end
-
- # Indicates whether fail-fast mode is enabled.
- protected def fail_fast?
- @run_flags.fail_fast?
- end
-
- # Enables fail-blank mode (fail on no tests).
- def fail_blank
- @run_flags |= RunFlags::FailBlank
- end
-
- # Enables or disables fail-blank mode.
- def fail_blank=(flag)
- if flag
- @run_flags |= RunFlags::FailBlank
- else
- @run_flags &= ~RunFlags::FailBlank
- end
- end
-
- # Indicates whether fail-fast mode is enabled.
- # That is, it is a failure if there are no tests.
- protected def fail_blank?
- @run_flags.fail_blank?
- end
-
- # Enables dry-run mode.
- def dry_run
- @run_flags |= RunFlags::DryRun
- end
-
- # Enables or disables dry-run mode.
- def dry_run=(flag)
- if flag
- @run_flags |= RunFlags::DryRun
- else
- @run_flags &= ~RunFlags::DryRun
- end
- end
-
- # Indicates whether dry-run mode is enabled.
- # In this mode, no tests are run, but output acts like they were.
- protected def dry_run?
- @run_flags.dry_run?
- end
-
- # Randomizes test execution order.
- def randomize
- @run_flags |= RunFlags::Randomize
- end
-
- # Enables or disables running tests in a random order.
- def randomize=(flag)
- if flag
- @run_flags |= RunFlags::Randomize
- else
- @run_flags &= ~RunFlags::Randomize
- end
- end
-
- # Indicates whether tests are run in a random order.
- protected def randomize?
- @run_flags.randomize?
- end
-
- # Displays profiling information
- def profile
- @run_flags |= RunFlags::Profile
- end
-
- # Enables or disables displaying profiling information.
- def profile=(flag)
- if flag
- @run_flags |= RunFlags::Profile
- else
- @run_flags &= ~RunFlags::Profile
- end
- end
-
- # Indicates whether profiling information should be displayed.
- protected def profile?
- @run_flags.profile?
- end
-
- # Adds a filter to determine which examples can run.
- def add_node_filter(filter : NodeFilter)
- @filters << filter
- end
-
- # Specifies one or more tags to constrain running examples to.
- def filter_run_including(*tags : Symbol, **values)
- tags.each { |tag| @filters << TagNodeFilter.new(tag.to_s) }
- values.each { |tag, value| @filters << TagNodeFilter.new(tag.to_s, value.to_s) }
- end
-
- # Adds a filter to prevent examples from running.
- def add_node_reject(filter : NodeFilter)
- @rejects << filter
- end
-
- # Specifies one or more tags to exclude from running examples.
- def filter_run_excluding(*tags : Symbol, **values)
- tags.each { |tag| @rejects << TagNodeFilter.new(tag.to_s) }
- values.each { |tag, value| @rejects << TagNodeFilter.new(tag.to_s, value.to_s) }
- end
-
- # Specifies one or more tags to filter on only if they're present in the spec.
- def filter_run_when_matching(*tags : Symbol, **values)
- tags.each { |tag| @match_filters[tag] = nil }
- values.each { |tag, value| @match_filters[tag] = value.to_s }
- end
-
- # Retrieves a filter that determines which examples can run.
- # If no filters were added with `#add_node_filter`,
- # then the returned filter will allow all examples to be run.
- protected def node_filter
- case (filters = @filters)
- when .empty? then NullNodeFilter.new
- when .one? then filters.first
- else CompositeNodeFilter.new(filters)
- end
- end
-
- # Retrieves a filter that prevents examples from running.
- # If no filters were added with `#add_node_reject`,
- # then the returned filter will allow all examples to be run.
- protected def node_reject
- case (filters = @rejects)
- when .empty? then NullNodeFilter.new(false)
- when .one? then filters.first
- else CompositeNodeFilter.new(filters)
- end
- end
- end
- end
-end
diff --git a/lib/spectator/src/spectator/config/cli_arguments_applicator.cr b/lib/spectator/src/spectator/config/cli_arguments_applicator.cr
deleted file mode 100644
index 15c9f94..0000000
--- a/lib/spectator/src/spectator/config/cli_arguments_applicator.cr
+++ /dev/null
@@ -1,240 +0,0 @@
-require "colorize"
-require "option_parser"
-require "../formatting"
-require "../line_node_filter"
-require "../location"
-require "../location_node_filter"
-require "../name_node_filter"
-require "../tag_node_filter"
-
-module Spectator
- class Config
- # Applies command-line arguments to a configuration.
- class CLIArgumentsApplicator
- # Logger for this class.
- Log = Spectator::Log.for("config")
-
- # Creates the configuration source.
- # By default, the command-line arguments (ARGV) are used.
- # But custom arguments can be passed in.
- def initialize(@args : Array(String) = ARGV)
- end
-
- # Applies the specified configuration to a builder.
- # Calling this method from multiple sources builds up the final configuration.
- def apply(builder) : Nil
- OptionParser.parse(@args) do |parser|
- control_parser_options(parser, builder)
- filter_parser_options(parser, builder)
- output_parser_options(parser, builder)
- end
- end
-
- # Adds options to the parser for controlling the test execution.
- private def control_parser_options(parser, builder)
- fail_fast_option(parser, builder)
- fail_blank_option(parser, builder)
- dry_run_option(parser, builder)
- random_option(parser, builder)
- seed_option(parser, builder)
- order_option(parser, builder)
- end
-
- # Adds the fail-fast option to the parser.
- private def fail_fast_option(parser, builder)
- parser.on("-f", "--fail-fast", "Stop testing on first failure") do
- Log.debug { "Enabling fail-fast (-f)" }
- builder.fail_fast
- end
- end
-
- # Adds the fail-blank option to the parser.
- private def fail_blank_option(parser, builder)
- parser.on("-b", "--fail-blank", "Fail if there are no examples") do
- Log.debug { "Enabling fail-blank (-b)" }
- builder.fail_blank
- end
- end
-
- # Adds the dry-run option to the parser.
- private def dry_run_option(parser, builder)
- parser.on("-d", "--dry-run", "Don't run any tests, output what would have run") do
- Log.debug { "Enabling dry-run (-d)" }
- builder.dry_run
- end
- end
-
- # Adds the randomize examples option to the parser.
- private def random_option(parser, builder)
- parser.on("-r", "--rand", "Randomize the execution order of tests") do
- Log.debug { "Randomizing test order (-r)" }
- builder.randomize
- end
- end
-
- # Adds the random seed option to the parser.
- private def seed_option(parser, builder)
- parser.on("--seed INTEGER", "Set the seed for the random number generator (implies -r)") do |seed|
- Log.debug { "Randomizing test order and setting RNG seed to #{seed}" }
- builder.randomize
- builder.random_seed = seed.to_u64
- end
- end
-
- # Adds the example order option to the parser.
- private def order_option(parser, builder)
- parser.on("--order ORDER", "Set the test execution order. ORDER should be one of: defined, rand, or rand:SEED") do |method|
- case method.downcase
- when "defined"
- Log.debug { "Disabling randomized tests (--order defined)" }
- builder.randomize = false
- when /^rand/
- builder.randomize
- parts = method.split(':', 2)
- if (seed = parts[1]?)
- Log.debug { "Randomizing test order and setting RNG seed to #{seed} (--order rand:#{seed})" }
- builder.random_seed = seed.to_u64
- else
- Log.debug { "Randomizing test order (--order rand)" }
- end
- end
- end
- end
-
- # Adds options to the parser for filtering examples.
- private def filter_parser_options(parser, builder)
- example_option(parser, builder)
- line_option(parser, builder)
- location_option(parser, builder)
- tag_option(parser, builder)
- end
-
- # Adds the example filter option to the parser.
- private def example_option(parser, builder)
- parser.on("-e", "--example STRING", "Run examples whose full nested names include STRING") do |pattern|
- Log.debug { "Filtering for examples containing '#{pattern}' (-e '#{pattern}')" }
- filter = NameNodeFilter.new(pattern)
- builder.add_node_filter(filter)
- end
- end
-
- # Adds the line filter option to the parser.
- private def line_option(parser, builder)
- parser.on("-l", "--line LINE", "Run examples whose line matches LINE") do |line|
- Log.debug { "Filtering for examples on line #{line} (-l #{line})" }
- filter = LineNodeFilter.new(line.to_i)
- builder.add_node_filter(filter)
- end
- end
-
- # Adds the location filter option to the parser.
- private def location_option(parser, builder)
- parser.on("--location FILE:LINE", "Run the example at line 'LINE' in the file 'FILE', multiple allowed") do |location|
- Log.debug { "Filtering for examples at #{location} (--location '#{location}')" }
- location = Location.parse(location)
- filter = LocationNodeFilter.new(location)
- builder.add_node_filter(filter)
- end
- end
-
- # Adds the tag filter option to the parser.
- private def tag_option(parser, builder)
- parser.on("--tag TAG[:VALUE]", "Run examples with the specified TAG, or exclude examples by adding ~ before the TAG.") do |tag|
- negated = tag.starts_with?('~')
- tag = tag.lchop('~')
- Log.debug { "Filtering for example with tag #{tag}" }
- parts = tag.split(':', 2, remove_empty: true)
- if parts.size > 1
- tag = parts.first
- value = parts.last
- end
-
- filter = TagNodeFilter.new(tag, value)
- if negated
- builder.add_node_reject(filter)
- else
- builder.add_node_filter(filter)
- end
- end
- end
-
- # Adds options to the parser for changing output.
- private def output_parser_options(parser, builder)
- verbose_option(parser, builder)
- help_option(parser, builder)
- profile_option(parser, builder)
- json_option(parser, builder)
- tap_option(parser, builder)
- junit_option(parser, builder)
- html_option(parser, builder)
- no_color_option(parser, builder)
- end
-
- # Adds the verbose output option to the parser.
- private def verbose_option(parser, builder)
- parser.on("-v", "--verbose", "Verbose output using document formatter") do
- Log.debug { "Setting output format to document (-v)" }
- builder.formatter = Formatting::DocumentFormatter.new
- end
- end
-
- # Adds the help output option to the parser.
- private def help_option(parser, builder)
- parser.on("-h", "--help", "Show this help") do
- puts parser
- exit
- end
- end
-
- # Adds the profile output option to the parser.
- private def profile_option(parser, builder)
- parser.on("-p", "--profile", "Display the 10 slowest specs") do
- Log.debug { "Enabling timing information (-p)" }
- builder.profile
- end
- end
-
- # Adds the JSON output option to the parser.
- private def json_option(parser, builder)
- parser.on("--json", "Generate JSON output") do
- Log.debug { "Setting output format to JSON (--json)" }
- builder.formatter = Formatting::JSONFormatter.new
- end
- end
-
- # Adds the TAP output option to the parser.
- private def tap_option(parser, builder)
- parser.on("--tap", "Generate TAP output (Test Anything Protocol)") do
- Log.debug { "Setting output format to TAP (--tap)" }
- builder.formatter = Formatting::TAPFormatter.new
- end
- end
-
- # Adds the JUnit output option to the parser.
- private def junit_option(parser, builder)
- parser.on("--junit_output OUTPUT_DIR", "Generate JUnit XML output") do |output_dir|
- Log.debug { "Setting output format to JUnit XML (--junit_output '#{output_dir}')" }
- formatter = Formatting::JUnitFormatter.new(output_dir)
- builder.add_formatter(formatter)
- end
- end
-
- # Adds the HTML output option to the parser.
- private def html_option(parser, builder)
- parser.on("--html_output OUTPUT_DIR", "Generate HTML output") do |output_dir|
- Log.debug { "Setting output format to HTML (--html_output '#{output_dir}')" }
- formatter = Formatting::HTMLFormatter.new(output_dir)
- builder.add_formatter(formatter)
- end
- end
-
- # Adds the "no color" output option to the parser.
- private def no_color_option(parser, builder)
- parser.on("--no-color", "Disable colored output") do
- Log.debug { "Disabling color output (--no-color)" }
- Colorize.enabled = false
- end
- end
- end
- end
-end
diff --git a/lib/spectator/src/spectator/context.cr b/lib/spectator/src/spectator/context.cr
deleted file mode 100644
index 15b9335..0000000
--- a/lib/spectator/src/spectator/context.cr
+++ /dev/null
@@ -1,37 +0,0 @@
-# Base class that all test cases run in.
-# This type is used to store all test case contexts as a single type.
-# The instance must be downcast to the correct type before calling a context method.
-# This type is intentionally outside the `Spectator` module.
-# The reason for this is to prevent name collision when using the DSL to define a spec.
-abstract class SpectatorContext
- # Evaluates the contents of a block within the scope of the context.
- def eval(&)
- with self yield
- end
-
- # Produces a dummy string to represent the context as a string.
- # This prevents the default behavior, which normally stringifies instance variables.
- # Due to the sheer amount of types Spectator can create
- # and that the Crystal compiler instantiates a `#to_s` and/or `#inspect` for each of those types,
- # an explosion in method instances can be created.
- # The compile time is drastically reduced by using a dummy string instead.
- def to_s(io : IO) : Nil
- io << "Context"
- end
-
- # :ditto:
- def inspect(io : IO) : Nil
- io << "Context<" << self.class << '>'
- end
-end
-
-module Spectator
- # Base class that all test cases run in.
- # This type is used to store all test case contexts as a single type.
- # The instance must be downcast to the correct type before calling a context method.
- #
- # Nested contexts, such as those defined by `context` and `describe` in the DSL, can define their own methods.
- # The intent is that a proc will downcast to the correct type and call one of those methods.
- # This is how methods that contain test cases, hooks, and other context-specific code blocks get invoked.
- alias Context = ::SpectatorContext
-end
diff --git a/lib/spectator/src/spectator/context_delegate.cr b/lib/spectator/src/spectator/context_delegate.cr
deleted file mode 100644
index ac927b9..0000000
--- a/lib/spectator/src/spectator/context_delegate.cr
+++ /dev/null
@@ -1,27 +0,0 @@
-require "./context"
-require "./context_method"
-require "./null_context"
-
-module Spectator
- # Stores a test context and a method to call within it.
- struct ContextDelegate
- # Creates the delegate.
- # The *context* is the instance of the test context.
- # The *method* is proc that downcasts *context* and calls a method on it.
- def initialize(@context : Context, @method : ContextMethod)
- end
-
- # Creates a delegate with a null context.
- # The context will be ignored and the block will be executed in its original scope.
- def self.null(&block : -> _)
- context = NullContext.new
- method = ContextMethod.new { block.call }
- new(context, method)
- end
-
- # Invokes a method in the test context.
- def call
- @method.call(@context)
- end
- end
-end
diff --git a/lib/spectator/src/spectator/context_method.cr b/lib/spectator/src/spectator/context_method.cr
deleted file mode 100644
index 30cce6d..0000000
--- a/lib/spectator/src/spectator/context_method.cr
+++ /dev/null
@@ -1,10 +0,0 @@
-require "./context"
-
-module Spectator
- # Encapsulates a method in a test context.
- # This could be used to invoke a test case or hook method.
- # The context is passed as an argument.
- # The proc should downcast the context instance to the desired type
- # and call a method on that context.
- alias ContextMethod = Context ->
-end
diff --git a/lib/spectator/src/spectator/dsl.cr b/lib/spectator/src/spectator/dsl.cr
deleted file mode 100644
index a7d89fb..0000000
--- a/lib/spectator/src/spectator/dsl.cr
+++ /dev/null
@@ -1,11 +0,0 @@
-require "./dsl/*"
-
-module Spectator
- # Namespace containing methods representing the spec domain specific language.
- #
- # Note: Documentation inside macros is kept to a minimum to reduce generated code.
- # This also helps keep error traces small.
- # Documentation only useful for debugging is included in generated code.
- module DSL
- end
-end
diff --git a/lib/spectator/src/spectator/dsl/builder.cr b/lib/spectator/src/spectator/dsl/builder.cr
deleted file mode 100644
index ed1c6a4..0000000
--- a/lib/spectator/src/spectator/dsl/builder.cr
+++ /dev/null
@@ -1,120 +0,0 @@
-require "../example_group_hook"
-require "../example_hook"
-require "../example_procsy_hook"
-require "../spec_builder"
-
-module Spectator::DSL
- # Incrementally builds up a test spec from the DSL.
- # This is intended to be used only by the Spectator DSL.
- module Builder
- extend self
-
- # Underlying spec builder.
- private class_getter(builder) { SpecBuilder.new(Spectator.config) }
-
- # Defines a new example group and pushes it onto the group stack.
- # Examples and groups defined after calling this method will be nested under the new group.
- # The group will be finished and popped off the stack when `#end_example` is called.
- #
- # See `Spec::Builder#start_group` for usage details.
- def start_group(*args)
- builder.start_group(*args)
- end
-
- # Defines a new iterative example group and pushes it onto the group stack.
- # Examples and groups defined after calling this method will be nested under the new group.
- # The group will be finished and popped off the stack when `#end_example` is called.
- #
- # See `Spec::Builder#start_iterative_group` for usage details.
- def start_iterative_group(*args)
- builder.start_iterative_group(*args)
- end
-
- # Completes a previously defined example group and pops it off the group stack.
- # Be sure to call `#start_group` and `#end_group` symmetrically.
- #
- # See `Spec::Builder#end_group` for usage details.
- def end_group(*args)
- builder.end_group(*args)
- end
-
- # Defines a new example.
- # The example is added to the group currently on the top of the stack.
- #
- # See `Spec::Builder#add_example` for usage details.
- def add_example(*args, &block : Example ->)
- builder.add_example(*args, &block)
- end
-
- # Defines a new pending example.
- # The example is added to the group currently on the top of the stack.
- #
- # See `Spec::Builder#add_pending_example` for usage details.
- def add_pending_example(*args)
- builder.add_pending_example(*args)
- end
-
- # Defines a block of code to execute before any and all examples in the test suite.
- def before_suite(location = nil, label = "before_suite", &block)
- hook = ExampleGroupHook.new(location: location, label: label, &block)
- builder.before_suite(hook)
- end
-
- # Defines a block of code to execute before any and all examples in the current group.
- def before_all(location = nil, label = "before_all", &block)
- hook = ExampleGroupHook.new(location: location, label: label, &block)
- builder.before_all(hook)
- end
-
- # Defines a block of code to execute before every example in the current group
- def before_each(location = nil, label = "before_each", &block : Example -> _)
- hook = ExampleHook.new(location: location, label: label, &block)
- builder.before_each(hook)
- end
-
- # Defines a block of code to execute after any and all examples in the test suite.
- def after_suite(location = nil, label = "after_suite", &block)
- hook = ExampleGroupHook.new(location: location, label: label, &block)
- builder.after_suite(hook)
- end
-
- # Defines a block of code to execute after any and all examples in the current group.
- def after_all(location = nil, label = "after_all", &block)
- hook = ExampleGroupHook.new(location: location, label: label, &block)
- builder.after_all(hook)
- end
-
- # Defines a block of code to execute after every example in the current group.
- def after_each(location = nil, label = "after_each", &block : Example ->)
- hook = ExampleHook.new(location: location, label: label, &block)
- builder.after_each(hook)
- end
-
- # Defines a block of code to execute around every example in the current group.
- def around_each(location = nil, label = "around_each", &block : Example::Procsy ->)
- hook = ExampleProcsyHook.new(location: location, label: label, &block)
- builder.around_each(hook)
- end
-
- # Defines a block of code to execute before every example in the current group
- def pre_condition(location = nil, label = "pre_condition", &block : Example -> _)
- hook = ExampleHook.new(location: location, label: label, &block)
- builder.pre_condition(hook)
- end
-
- # Defines a block of code to execute after every example in the current group.
- def post_condition(location = nil, label = "post_condition", &block : Example ->)
- hook = ExampleHook.new(location: location, label: label, &block)
- builder.post_condition(hook)
- end
-
- # Constructs the test spec.
- # Returns the spec instance.
- #
- # Raises an error if there were not symmetrical calls to `#start_group` and `#end_group`.
- # This would indicate a logical error somewhere in Spectator or an extension of it.
- def build : Spec
- builder.build
- end
- end
-end
diff --git a/lib/spectator/src/spectator/dsl/concise.cr b/lib/spectator/src/spectator/dsl/concise.cr
deleted file mode 100644
index bb65a42..0000000
--- a/lib/spectator/src/spectator/dsl/concise.cr
+++ /dev/null
@@ -1,56 +0,0 @@
-require "./examples"
-require "./groups"
-require "./memoize"
-
-module Spectator::DSL
- # DSL methods and macros for shorter syntax.
- module Concise
- # Defines an example and input values in a shorter syntax.
- # The only arguments given to this macro are one or more assignments.
- # The names in the assignments will be available in the example code.
- #
- # If the code block is omitted, then the example is skipped (marked as not implemented).
- #
- # Tags and metadata cannot be used with this macro.
- #
- # ```
- # provided x = 42, y: 123 do
- # expect(x).to eq(42)
- # expect(y).to eq(123)
- # end
- # ```
- macro provided(*assignments, it description = nil, **kwargs, &block)
- {% raise "Cannot use 'provided' inside of a test block" if @def %}
-
- class Given%given < {{@type.id}}
- {% for assignment in assignments %}
- let({{assignment.target}}) { {{assignment.value}} }
- {% end %}
- {% for name, value in kwargs %}
- let({{name}}) { {{value}} }
- {% end %}
-
- {% if block %}
- {% if description %}
- example {{description}} {{block}}
- {% else %}
- example {{block}}
- {% end %}
- {% else %}
- {% if description %}
- example {{description}} {{block}}
- {% else %}
- example {{assignments.splat.stringify}}
- {% end %}
- {% end %}
- end
- end
-
- # :ditto:
- @[Deprecated("Use `provided` instead.")]
- macro given(*assignments, **kwargs, &block)
- {% raise "Cannot use 'given' inside of a test block" if @def %}
- provided({{assignments.splat(",")}} {{kwargs.double_splat}}) {{block}}
- end
- end
-end
diff --git a/lib/spectator/src/spectator/dsl/examples.cr b/lib/spectator/src/spectator/dsl/examples.cr
deleted file mode 100644
index 703f2d3..0000000
--- a/lib/spectator/src/spectator/dsl/examples.cr
+++ /dev/null
@@ -1,153 +0,0 @@
-require "../context"
-require "../location"
-require "./builder"
-require "./metadata"
-
-module Spectator::DSL
- # DSL methods for defining examples and test code.
- module Examples
- include Metadata
-
- # Defines a macro to generate code for an example.
- # The *name* is the name given to the macro.
- #
- # In addition, another macro is defined that marks the example as pending.
- # The pending macro is prefixed with 'x'.
- # For instance, `define_example :it` defines `it` and `xit`.
- #
- # Default tags can be provided with *tags* and *metadata*.
- # The tags are merged with parent groups.
- # Any items with falsey values from *metadata* remove the corresponding tag.
- macro define_example(name, *tags, **metadata)
- # Defines an example.
- #
- # If a block is given, it is treated as the code to test.
- # The block is provided the current example instance as an argument.
- #
- # The first argument names the example (test).
- # Typically, this specifies what is being tested.
- # It has no effect on the test and is purely used for output.
- # If omitted, a name is generated from the first assertion in the test.
- #
- # The example will be marked as pending if the block is omitted.
- # A block or name must be provided.
- #
- # Tags can be specified by adding symbols (keywords) after the first argument.
- # Key-value pairs can also be specified.
- # Any falsey items will remove a previously defined tag.
- macro {{name.id}}(what = nil, *tags, **metadata, &block)
- \{% raise "Cannot use '{{name.id}}' inside of a test block" if @def %}
- \{% raise "A description or block must be provided. Cannot use '{{name.id}}' alone." unless what || block %}
-
- _spectator_metadata(%metadata, :metadata, {{tags.splat(",")}} {{metadata.double_splat}})
- _spectator_metadata(\%metadata, %metadata, \{{tags.splat(",")}} \{{metadata.double_splat}})
-
- \{% if block %}
- \{% raise "Block argument count '{{name.id}}' must be 0..1" if block.args.size > 1 %}
-
- private def \%test(\{{block.args.splat}}) : Nil
- \{{block.body}}
- end
-
- ::Spectator::DSL::Builder.add_example(
- _spectator_example_name(\{{what}}),
- ::Spectator::Location.new(\{{block.filename}}, \{{block.line_number}}, \{{block.end_line_number}}),
- -> { new.as(::Spectator::Context) },
- \%metadata
- ) do |example|
- example.with_context(\{{@type.name}}) do
- \{% if block.args.empty? %}
- \%test
- \{% else %}
- \%test(example)
- \{% end %}
- end
- end
-
- \{% else %}
- ::Spectator::DSL::Builder.add_pending_example(
- _spectator_example_name(\{{what}}),
- ::Spectator::Location.new(\{{what.filename}}, \{{what.line_number}}),
- \%metadata,
- "Not yet implemented"
- )
- \{% end %}
- end
-
- define_pending_example :x{{name.id}}, skip: "Temporarily skipped with x{{name.id}}"
- end
-
- # Defines a macro to generate code for a pending example.
- # The *name* is the name given to the macro.
- #
- # The block for the example's content is discarded at compilation time.
- # This prevents issues with undefined methods, signature differences, etc.
- #
- # Default tags can be provided with *tags* and *metadata*.
- # The tags are merged with parent groups.
- # Any items with falsey values from *metadata* remove the corresponding tag.
- macro define_pending_example(name, *tags, **metadata)
- # Defines a pending example.
- #
- # If a block is given, it is treated as the code to test.
- # The block is provided the current example instance as an argument.
- #
- # The first argument names the example (test).
- # Typically, this specifies what is being tested.
- # It has no effect on the test and is purely used for output.
- # If omitted, a name is generated from the first assertion in the test.
- #
- # Tags can be specified by adding symbols (keywords) after the first argument.
- # Key-value pairs can also be specified.
- # Any falsey items will remove a previously defined tag.
- macro {{name.id}}(what = nil, *tags, **metadata, &block)
- \{% raise "Cannot use '{{name.id}}' inside of a test block" if @def %}
- \{% raise "A description or block must be provided. Cannot use '{{name.id}}' alone." unless what || block %}
- \{% raise "Block argument count '{{name.id}}' must be 0..1" if block && block.args.size > 1 %}
-
- _spectator_metadata(%metadata, :metadata, {{tags.splat(",")}} {{metadata.double_splat}})
- _spectator_metadata(\%metadata, %metadata, \{{tags.splat(",")}} \{{metadata.double_splat}})
-
- ::Spectator::DSL::Builder.add_pending_example(
- _spectator_example_name(\{{what}}),
- ::Spectator::Location.new(\{{(what || block).filename}}, \{{(what || block).line_number}}, \{{(what || block).end_line_number}}),
- \%metadata,
- \{% if !block %}"Not yet implemented"\{% end %}
- )
- end
- end
-
- # Inserts the correct representation of a example's name.
- # If *what* is a string, then it is dropped in as-is.
- # For anything else, it is stringified.
- # This is intended to be used to convert a description from the spec DSL to `Node#name`.
- private macro _spectator_example_name(what)
- {% if what.is_a?(StringLiteral) || what.is_a?(NilLiteral) %}
- {{what}}
- {% elsif what.is_a?(StringInterpolation) %}
- ->(example : ::Spectator::Example) do
- example.with_context(\{{@type.name}}) { {{what}} }
- end
- {% else %}
- {{what.stringify}}
- {% end %}
- end
-
- define_example :example
-
- define_example :it
-
- define_example :specify
-
- define_example :fexample, focus: true
-
- define_example :fit, focus: true
-
- define_example :fspecify, focus: true
-
- @[Deprecated("Behavior of pending blocks will change in Spectator v0.11.0. Use `skip` instead.")]
- define_pending_example :pending
-
- define_pending_example :skip
- end
-end
diff --git a/lib/spectator/src/spectator/dsl/expectations.cr b/lib/spectator/src/spectator/dsl/expectations.cr
deleted file mode 100644
index dba2e9b..0000000
--- a/lib/spectator/src/spectator/dsl/expectations.cr
+++ /dev/null
@@ -1,191 +0,0 @@
-require "../block"
-require "../example_pending"
-require "../expectation"
-require "../expectation_failed"
-require "../location"
-require "../pending_result"
-require "../value"
-
-module Spectator::DSL
- # Methods and macros for asserting that conditions are met.
- module Expectations
- # Immediately fail the current test.
- # A reason can be specified with *message*.
- def fail(message = "Example failed", *, _file = __FILE__, _line = __LINE__)
- raise ExampleFailed.new(Location.new(_file, _line), message)
- end
-
- # Mark the current test as pending and immediately abort.
- # A reason can be specified with *message*.
- def pending(message = PendingResult::DEFAULT_REASON, *, _file = __FILE__, _line = __LINE__)
- raise ExamplePending.new(Location.new(_file, _line), message)
- end
-
- # Mark the current test as skipped and immediately abort.
- # A reason can be specified with *message*.
- def skip(message = PendingResult::DEFAULT_REASON, *, _file = __FILE__, _line = __LINE__)
- raise ExamplePending.new(Location.new(_file, _line), message)
- end
-
- # Starts an expectation.
- # This should be followed up with `Assertion::Target#to` or `Assertion::Target#to_not`.
- # The value passed in will be checked to see if it satisfies the conditions of the specified matcher.
- #
- # This macro should be used like so:
- # ```
- # expect(actual).to eq(expected)
- # ```
- #
- # Where the actual value is returned by the system under test,
- # and the expected value is what the actual value should be to satisfy the condition.
- macro expect(actual)
- {% raise "Cannot use 'expect' outside of a test block" unless @def %}
-
- %actual = begin
- {{actual}}
- end
-
- %expression = ::Spectator::Value.new(%actual, {{actual.stringify}})
- %location = ::Spectator::Location.new({{actual.filename}}, {{actual.line_number}})
- ::Spectator::Expectation::Target.new(%expression, %location)
- end
-
- # Starts an expectation.
- # This should be followed up with `Assertion::Target#to` or `Assertion::Target#not_to`.
- # The value passed in will be checked to see if it satisfies the conditions of the specified matcher.
- #
- # This macro should be used like so:
- # ```
- # expect { raise "foo" }.to raise_error
- # ```
- #
- # The block of code is passed along for validation to the matchers.
- #
- # The short, one argument syntax used for passing methods to blocks can be used.
- # So instead of doing this:
- # ```
- # expect(subject.size).to eq(5)
- # ```
- #
- # The following syntax can be used instead:
- # ```
- # expect(&.size).to eq(5)
- # ```
- #
- # The method passed will always be evaluated on the subject.
- #
- # TECHNICAL NOTE:
- # This macro uses an ugly hack to detect the short-hand syntax.
- #
- # The Crystal compiler will translate:
- # ```
- # &.foo
- # ```
- #
- # effectively to:
- # ```
- # { |__arg0| __arg0.foo }
- # ```
- macro expect(&block)
- {% raise "Cannot use 'expect' outside of a test block" unless @def %}
-
- {% if block.args.size == 1 && block.args[0] =~ /^__arg\d+$/ && block.body.is_a?(Call) && block.body.id =~ /^__arg\d+\./ %}
- {% method_name = block.body.id.split('.')[1..-1].join('.') %}
- %block = ::Spectator::Block.new({{"#" + method_name}}) do
- subject.{{method_name.id}}
- end
- {% elsif block.args.empty? %}
- %block = ::Spectator::Block.new({{"`" + block.body.stringify + "`"}}) {{block}}
- {% else %}
- {% raise "Unexpected block arguments in 'expect' call" %}
- {% end %}
-
- %location = ::Spectator::Location.new({{block.filename}}, {{block.line_number}})
- ::Spectator::Expectation::Target.new(%block, %location)
- end
-
- # Short-hand for expecting something of the subject.
- #
- # These two are functionally equivalent:
- # ```
- # expect(subject).to eq("foo")
- # is_expected.to eq("foo")
- # ```
- macro is_expected
- {% raise "Cannot use 'is_expected' outside of a test block" unless @def %}
-
- expect(subject)
- end
-
- # Short-hand form of `#is_expected` that can be used for one-liner syntax.
- #
- # For instance:
- # ```
- # it "is 42" do
- # expect(subject).to eq(42)
- # end
- # ```
- #
- # Can be shortened to:
- # ```
- # it { is(42) }
- # ```
- #
- # These three are functionally equivalent:
- # ```
- # expect(subject).to eq("foo")
- # is_expected.to eq("foo")
- # is("foo")
- # ```
- #
- # See also: `#is_not`
- macro is(expected)
- {% raise "Cannot use 'is' outside of a test block" unless @def %}
-
- expect(subject).to(eq({{expected}}))
- end
-
- # Short-hand, negated form of `#is_expected` that can be used for one-liner syntax.
- #
- # For instance:
- # ```
- # it "is not 42" do
- # expect(subject).to_not eq(42)
- # end
- # ```
- #
- # Can be shortened to:
- # ```
- # it { is_not(42) }
- # ```
- #
- # These three are functionally equivalent:
- # ```
- # expect(subject).not_to eq("foo")
- # is_expected.not_to eq("foo")
- # is_not("foo")
- # ```
- #
- # See also: `#is`
- macro is_not(expected)
- {% raise "Cannot use 'is_not' outside of a test block" unless @def %}
-
- expect(subject).not_to(eq({{expected}}))
- end
-
- # Captures multiple possible failures.
- # Aborts after the block completes if there were any failed expectations in the block.
- #
- # ```
- # aggregate_failures do
- # expect(true).to be_false
- # expect(false).to be_true
- # end
- # ```
- def aggregate_failures(label = nil, &)
- ::Spectator::Harness.current.aggregate_failures(label) do
- yield
- end
- end
- end
-end
diff --git a/lib/spectator/src/spectator/dsl/groups.cr b/lib/spectator/src/spectator/dsl/groups.cr
deleted file mode 100644
index da06906..0000000
--- a/lib/spectator/src/spectator/dsl/groups.cr
+++ /dev/null
@@ -1,245 +0,0 @@
-require "../location"
-require "./builder"
-require "./memoize"
-require "./metadata"
-
-module Spectator::DSL
- # DSL methods and macros for creating example groups.
- # This module should be included as a mix-in.
- module Groups
- include Metadata
-
- # Defines a macro to generate code for an example group.
- # The *name* is the name given to the macro.
- #
- # Default tags can be provided with *tags* and *metadata*.
- # The tags are merged with parent groups.
- # Any items with falsey values from *metadata* remove the corresponding tag.
- macro define_example_group(name, *tags, **metadata)
- # Defines a new example group.
- # The *what* argument is a name or description of the group.
- #
- # The first argument names the example (test).
- # Typically, this specifies what is being tested.
- # This argument is also used as the subject.
- # When it is a type name, it becomes an explicit, which overrides any previous subjects.
- # Otherwise it becomes an implicit subject, which doesn't override explicitly defined subjects.
- #
- # Tags can be specified by adding symbols (keywords) after the first argument.
- # Key-value pairs can also be specified.
- # Any falsey items will remove a previously defined tag.
- #
- # TODO: Handle string interpolation in example and group names.
- macro {{name.id}}(what, *tags, **metadata, &block)
- \{% raise "Cannot use '{{name.id}}' inside of a test block" if @def %}
-
- class Group\%group < \{{@type.id}}
- _spectator_group_subject(\{{what}})
-
- _spectator_metadata(:metadata, :super, {{tags.splat(", ")}} {{metadata.double_splat}})
- _spectator_metadata(:metadata, :previous_def, \{{tags.splat(", ")}} \{{metadata.double_splat}})
-
- ::Spectator::DSL::Builder.start_group(
- _spectator_group_name(\{{what}}),
- ::Spectator::Location.new(\{{block.filename}}, \{{block.line_number}}, \{{block.end_line_number}}),
- metadata
- )
-
- \{{block.body if block}}
-
- ::Spectator::DSL::Builder.end_group
- end
- end
- end
-
- # Defines a macro to generate code for an iterative example group.
- # The *name* is the name given to the macro.
- #
- # Default tags can be provided with *tags* and *metadata*.
- # The tags are merged with parent groups.
- # Any items with falsey values from *metadata* remove the corresponding tag.
- #
- # If provided, a block can be used to modify collection that will be iterated.
- # It takes a single argument - the original collection from the user.
- # The modified collection should be returned.
- #
- # TODO: Handle string interpolation in example and group names.
- macro define_iterative_group(name, *tags, **metadata, &block)
- macro {{name.id}}(collection, *tags, count = nil, **metadata, &block)
- \{% raise "Cannot use 'sample' inside of a test block" if @def %}
-
- class Group\%group < \{{@type.id}}
- _spectator_metadata(:metadata, :super, {{tags.splat(", ")}} {{metadata.double_splat}})
- _spectator_metadata(:metadata, :previous_def, \{{tags.splat(", ")}} \{{metadata.double_splat}})
-
- def self.\%collection
- \{{collection}}
- end
-
- {% if block %}
- def self.%mutate({{block.args.splat}})
- {{block.body}}
- end
-
- def self.\%collection
- %mutate(previous_def)
- end
- {% end %}
-
- \{% if count %}
- def self.\%collection
- previous_def.first(\{{count}})
- end
- \{% end %}
-
- ::Spectator::DSL::Builder.start_iterative_group(
- \%collection,
- \{{collection.stringify}},
- [\{{block.args.empty? ? "".id : block.args.map(&.stringify).splat}}] of String,
- ::Spectator::Location.new(\{{block.filename}}, \{{block.line_number}}, \{{block.end_line_number}}),
- metadata
- )
-
- \{% if block %}
- \{% if block.args.size > 1 %}
- \{% for arg, i in block.args %}
- let(\{{arg}}) do |example|
- example.group.as(::Spectator::ExampleGroupIteration(typeof(Group\%group.\%collection.first))).item[\{{i}}]
- end
- \{% end %}
- \{% else %}
- let(\{{block.args[0]}}) do |example|
- example.group.as(::Spectator::ExampleGroupIteration(typeof(Group\%group.\%collection.first))).item
- end
- \{% end %}
-
- \{{block.body}}
- \{% end %}
-
- ::Spectator::DSL::Builder.end_group
- end
- end
- end
-
- # Inserts the correct representation of a group's name.
- # If *what* appears to be a type name, it will be symbolized.
- # If it's a string, then it is dropped in as-is.
- # For anything else, it is stringified.
- # This is intended to be used to convert a description from the spec DSL to `Node#name`.
- private macro _spectator_group_name(what)
- {% if (what.is_a?(Generic) ||
- what.is_a?(Path) ||
- what.is_a?(TypeNode) ||
- what.is_a?(Union)) &&
- what.resolve?.is_a?(TypeNode) %}
- {{what.symbolize}}
- {% elsif what.is_a?(StringLiteral) ||
- what.is_a?(NilLiteral) %}
- {{what}}
- {% elsif what.is_a?(StringInterpolation) %}
- {{@type.name}}.new.eval do
- {{what}}
- rescue e
- ""
- end
- {% else %}
- {{what.stringify}}
- {% end %}
- end
-
- # Defines the implicit subject for the test context.
- # If *what* is a type, then the `described_class` method will be defined.
- # Additionally, the implicit subject is set to an instance of *what* if it's not a module.
- #
- # There is no common macro type that has the `#resolve?` method.
- # Also, `#responds_to?` can't be used in macros.
- # So the large if statement in this macro is used to look for type signatures.
- private macro _spectator_group_subject(what)
- {% if (what.is_a?(Generic) ||
- what.is_a?(Path) ||
- what.is_a?(TypeNode) ||
- what.is_a?(Union)) &&
- (described_type = what.resolve?).is_a?(TypeNode) %}
- private macro described_class
- {{what}}
- end
-
- subject do
- {% if described_type.class? || described_type.struct? %}
- described_class.new
- {% else %}
- described_class
- {% end %}
- end
- {% else %}
- private def _spectator_implicit_subject
- {{what}}
- end
- {% end %}
- end
-
- define_example_group :example_group
-
- define_example_group :describe
-
- define_example_group :context
-
- define_example_group :xexample_group, skip: "Temporarily skipped with xexample_group"
-
- define_example_group :xdescribe, skip: "Temporarily skipped with xdescribe"
-
- define_example_group :xcontext, skip: "Temporarily skipped with xcontext"
-
- define_example_group :fexample_group, focus: true
-
- define_example_group :fdescribe, focus: true
-
- define_example_group :fcontext, focus: true
-
- # Defines a new iterative example group.
- # This type of group duplicates its contents for each element in *collection*.
- #
- # The first argument is the collection of elements to iterate over.
- #
- # Tags can be specified by adding symbols (keywords) after the first argument.
- # Key-value pairs can also be specified.
- # Any falsey items will remove a previously defined tag.
- #
- # The number of items iterated can be restricted by specifying a *count* argument.
- # The first *count* items will be used if specified, otherwise all items will be used.
- define_iterative_group :sample
-
- # :ditto:
- define_iterative_group :xsample, skip: "Temporarily skipped with xsample"
-
- # :ditto:
- define_iterative_group :fsample, focus: true
-
- # Defines a new iterative example group.
- # This type of group duplicates its contents for each element in *collection*.
- # This is the same as `#sample` except that the items are shuffled.
- # The items are selected with a RNG based on the seed.
- #
- # The first argument is the collection of elements to iterate over.
- #
- # Tags can be specified by adding symbols (keywords) after the first argument.
- # Key-value pairs can also be specified.
- # Any falsey items will remove a previously defined tag.
- #
- # The number of items iterated can be restricted by specifying a *count* argument.
- # The first *count* items will be used if specified, otherwise all items will be used.
- define_iterative_group :random_sample do |collection|
- collection.to_a.shuffle(::Spectator.random)
- end
-
- # :ditto:
- define_iterative_group :xrandom_sample, skip: "Temporarily skipped with xrandom_sample" do |collection|
- collection.to_a.shuffle(::Spectator.random)
- end
-
- # :ditto:
- define_iterative_group :frandom_sample, focus: true do |collection|
- collection.to_a.shuffle(::Spectator.random)
- end
- end
-end
diff --git a/lib/spectator/src/spectator/dsl/hooks.cr b/lib/spectator/src/spectator/dsl/hooks.cr
deleted file mode 100644
index 6672e59..0000000
--- a/lib/spectator/src/spectator/dsl/hooks.cr
+++ /dev/null
@@ -1,167 +0,0 @@
-require "../location"
-require "./builder"
-
-module Spectator::DSL
- # DSL methods for adding custom logic to key times of the spec execution.
- module Hooks
- # Defines a macro to create an example group hook.
- # The *type* indicates when the hook runs and must be a method on `Spectator::DSL::Builder`.
- # A custom *name* can be used for the hook method.
- # If not provided, *type* will be used instead.
- # Additionally, a block can be provided.
- # The block can perform any operations necessary and yield to invoke the end-user hook.
- macro define_example_group_hook(type, name = nil, &block)
- macro {{(name ||= type).id}}(&block)
- \{% raise "Missing block for '{{name.id}}' hook" unless block %}
- \{% raise "Cannot use '{{name.id}}' inside of a test block" if @def %}
-
- private def self.\%hook : Nil
- \{{block.body}}
- end
-
- {% if block %}
- private def self.%wrapper : Nil
- {{block.body}}
- end
- {% end %}
-
- ::Spectator::DSL::Builder.{{type.id}}(
- ::Spectator::Location.new(\{{block.filename}}, \{{block.line_number}}, \{{block.end_line_number}})
- ) do
- {% if block %}
- %wrapper do |*args|
- \{% if block.args.empty? %}
- \%hook
- \{% else %}
- \%hook(*args)
- \{% end %}
- end
- {% else %}
- \%hook
- {% end %}
- end
- end
- end
-
- # Defines a macro to create an example hook.
- # The *type* indicates when the hook runs and must be a method on `Spectator::DSL::Builder`.
- # A custom *name* can be used for the hook method.
- # If not provided, *type* will be used instead.
- # Additionally, a block can be provided that takes the current example as an argument.
- # The block can perform any operations necessary and yield to invoke the end-user hook.
- macro define_example_hook(type, name = nil, &block)
- macro {{(name ||= type).id}}(&block)
- \{% raise "Missing block for '{{name.id}}' hook" unless block %}
- \{% raise "Block argument count '{{name.id}}' hook must be 0..1" if block.args.size > 1 %}
- \{% raise "Cannot use '{{name.id}}' inside of a test block" if @def %}
-
- private def \%hook(\{{block.args.splat}}) : Nil
- \{{block.body}}
- end
-
- {% if block %}
- private def %wrapper({{block.args.splat}}) : Nil
- {{block.body}}
- end
- {% end %}
-
- ::Spectator::DSL::Builder.{{type.id}}(
- ::Spectator::Location.new(\{{block.filename}}, \{{block.line_number}})
- ) do |example|
- example.with_context(\{{@type.name}}) do
- {% if block %}
- {% if block.args.empty? %}
- %wrapper do |*args|
- \{% if block.args.empty? %}
- \%hook
- \{% else %}
- \%hook(*args)
- \{% end %}
- end
- {% else %}
- %wrapper(example) do |*args|
- \{% if block.args.empty? %}
- \%hook
- \{% else %}
- \%hook(*args)
- \{% end %}
- end
- {% end %}
- {% else %}
- \{% if block.args.empty? %}
- \%hook
- \{% else %}
- \%hook(example)
- \{% end %}
- {% end %}
- end
- end
- end
- end
-
- # Defines a block of code that will be invoked once before any examples in the suite.
- # The block will not run in the context of the current running example.
- # This means that values defined by `let` and `subject` are not available.
- define_example_group_hook :before_suite
-
- # Defines a block of code that will be invoked once after all examples in the suite.
- # The block will not run in the context of the current running example.
- # This means that values defined by `let` and `subject` are not available.
- define_example_group_hook :after_suite
-
- # Defines a block of code that will be invoked once before any examples in the group.
- # The block will not run in the context of the current running example.
- # This means that values defined by `let` and `subject` are not available.
- define_example_group_hook :before_all
-
- # Defines a block of code that will be invoked once after all examples in the group.
- # The block will not run in the context of the current running example.
- # This means that values defined by `let` and `subject` are not available.
- define_example_group_hook :after_all
-
- # Defines a block of code that will be invoked before every example in the group.
- # The block will be run in the context of the current running example.
- # This means that values defined by `let` and `subject` are available.
- define_example_hook :before_each
-
- # :ditto:
- macro before(&block)
- before_each {{block}}
- end
-
- # Defines a block of code that will be invoked after every example in the group.
- # The block will be run in the context of the current running example.
- # This means that values defined by `let` and `subject` are available.
- define_example_hook :after_each
-
- # :ditto:
- macro after(&block)
- after_each {{block}}
- end
-
- # Defines a block of code that will be invoked around every example in the group.
- # The block will be run in the context of the current running example.
- # This means that values defined by `let` and `subject` are available.
- #
- # The block will execute before the example.
- # An `Example::Procsy` is passed to the block.
- # The `Example::Procsy#run` method should be called to ensure the example runs.
- # More code can run afterwards (in the block).
- define_example_hook :around_each
-
- # :ditto:
- macro around(&block)
- around_each {{block}}
- end
-
- # Defines a block of code that will be invoked before every example in the group.
- # The block will be run in the context of the current running example.
- # This means that values defined by `let` and `subject` are available.
- define_example_hook :pre_condition
-
- # Defines a block of code that will be invoked after every example in the group.
- # The block will be run in the context of the current running example.
- # This means that values defined by `let` and `subject` are available.
- define_example_hook :post_condition
- end
-end
diff --git a/lib/spectator/src/spectator/dsl/matchers.cr b/lib/spectator/src/spectator/dsl/matchers.cr
deleted file mode 100644
index 95e6c5d..0000000
--- a/lib/spectator/src/spectator/dsl/matchers.cr
+++ /dev/null
@@ -1,879 +0,0 @@
-require "../block"
-require "../matchers"
-require "../value"
-
-module Spectator::DSL
- module Matchers
- # Indicates that some value should equal another.
- # The == operator is used for this check.
- # The value passed to this method is the expected value.
- #
- # Example:
- # ```
- # expect(1 + 2).to eq(3)
- # ```
- macro eq(expected)
- %value = ::Spectator::Value.new({{expected}}, {{expected.stringify}})
- ::Spectator::Matchers::EqualityMatcher.new(%value)
- end
-
- # Indicates that some value should not equal another.
- # The != operator is used for this check.
- # The value passed to this method is the unexpected value.
- #
- # Example:
- # ```
- # expect(1 + 2).to ne(5)
- # ```
- macro ne(expected)
- %value = ::Spectator::Value.new({{expected}}, {{expected.stringify}})
- ::Spectator::Matchers::InequalityMatcher.new(%value)
- end
-
- # Indicates that some value when compared to another satisfies an operator.
- # An operator can follow, such as: <, <=, >, or >=.
- # See `Spectator::Matchers::TruthyMatcher` for a full list of operators.
- #
- # Examples:
- # ```
- # expect(1 + 1).to be > 1
- # expect(5).to be >= 3
- # ```
- #
- # Additionally, a value can just "be" truthy by omitting an operator.
- # ```
- # expect("foo").to be
- # # is the same as:
- # expect("foo").to be_truthy
- # ```
- macro be
- ::Spectator::Matchers::TruthyMatcher.new
- end
-
- # Indicates that some object should be the same as another.
- # This checks if two references are the same.
- # The `Reference#same?` method is used for this check.
- #
- # Examples:
- # ```
- # obj = "foobar"
- # expect(obj).to be(obj)
- # expect(obj.dup).to_not be(obj)
- # ```
- macro be(expected)
- %value = ::Spectator::Value.new({{expected}}, {{expected.stringify}})
- ::Spectator::Matchers::ReferenceMatcher.new(%value)
- end
-
- # Indicates that some value should be of a specified type.
- # The `Object#is_a?` method is used for this check.
- # A type name or type union should be used for *expected*.
- #
- # Examples:
- # ```
- # expect("foo").to be_a(String)
- #
- # x = Random.rand(2) == 0 ? "foobar" : 5
- # expect(x).to be_a(Int32 | String)
- # ```
- macro be_a(expected)
- ::Spectator::Matchers::TypeMatcher.create({{expected}})
- end
-
- # Indicates that some value should be of a specified type.
- # The `Object#is_a?` method is used for this check.
- # A type name or type union should be used for *expected*.
- # This method is identical to `#be_a`,
- # and exists just to improve grammar.
- #
- # Examples:
- # ```
- # expect(123).to be_an(Int32)
- # ```
- macro be_an(expected)
- be_a({{expected}})
- end
-
- # Indicates that some value should be of a specified type.
- # The `Object#is_a?` method is used for this check.
- # A type name or type union should be used for *expected*.
- # This method is identical to `#be_a`,
- # and exists just to improve grammar.
- #
- # Examples:
- # ```
- # expect(123).to be_kind_of(Int)
- # ```
- macro be_kind_of(expected)
- be_a({{expected}})
- end
-
- # Indicates that some value should be of a specified type.
- # The `Object#is_a?` method is used for this check.
- # A type name or type union should be used for *expected*.
- # This method is identical to `#be_a`,
- # and exists just to improve grammar.
- #
- # Examples:
- # ```
- # expect(123).to be_a_kind_of(Int)
- # ```
- macro be_a_kind_of(expected)
- be_a({{expected}})
- end
-
- # Indicates that some value should be of a specified type.
- # The value's runtime type is checked.
- # A type name or type union should be used for *expected*.
- #
- # Examples:
- # ```
- # expect(123).to be_instance_of(Int32)
- # ```
- macro be_instance_of(expected)
- ::Spectator::Matchers::InstanceMatcher({{expected}}).new
- end
-
- # Indicates that some value should be of a specified type.
- # The value's runtime type is checked.
- # A type name or type union should be used for *expected*.
- # This method is identical to `#be_an_instance_of`,
- # and exists just to improve grammar.
- #
- # Examples:
- # ```
- # expect(123).to be_an_instance_of(Int32)
- # ```
- macro be_an_instance_of(expected)
- be_instance_of({{expected}})
- end
-
- # Indicates that some value should be of a specified type at compile time.
- # The value's compile time type is checked.
- # This can test is a variable or value returned by a method is inferred to the expected type.
- #
- # Examples:
- # ```
- # value = 42 || "foobar"
- # expect(value).to compile_as(Int32 | String)
- # ```
- macro compile_as(expected)
- ::Spectator::Matchers::CompiledTypeMatcher({{expected}}).new
- end
-
- # Indicates that some value should respond to a method call.
- # One or more method names can be provided.
- #
- # Examples:
- # ```
- # expect("foobar").to respond_to(:downcase)
- # expect(%i[a b c]).to respond_to(:size, :first)
- # ```
- macro respond_to(*expected)
- ::Spectator::Matchers::RespondMatcher({% begin %}NamedTuple(
- {% for method in expected %}
- {{method.id.stringify}}: Nil,
- {% end %}
- ){% end %}).new
- end
-
- # Indicates that some value should be less than another.
- # The < operator is used for this check.
- # The value passed to this method is the value expected to be larger.
- #
- # Example:
- # ```
- # expect(3 - 1).to be_lt(3)
- # ```
- macro be_lt(expected)
- %value = ::Spectator::Value.new({{expected}}, {{expected.stringify}})
- ::Spectator::Matchers::LessThanMatcher.new(%value)
- end
-
- # Indicates that some value should be less than or equal to another.
- # The <= operator is used for this check.
- # The value passed to this method is the value expected to be larger or equal.
- #
- # Example:
- # ```
- # expect(3 - 1).to be_le(3)
- # ```
- macro be_le(expected)
- %value = ::Spectator::Value.new({{expected}}, {{expected.stringify}})
- ::Spectator::Matchers::LessThanEqualMatcher.new(%value)
- end
-
- # Indicates that some value should be greater than another.
- # The > operator is used for this check.
- # The value passed to this method is the value expected to be smaller.
- #
- # Example:
- # ```
- # expect(3 + 1).to be_gt(3)
- # ```
- macro be_gt(expected)
- %value = ::Spectator::Value.new({{expected}}, {{expected.stringify}})
- ::Spectator::Matchers::GreaterThanMatcher.new(%value)
- end
-
- # Indicates that some value should be greater than or equal to another.
- # The >= operator is used for this check.
- # The value passed to this method is the value expected to be smaller or equal.
- #
- # Example:
- # ```
- # expect(3 + 1).to be_ge(3)
- # ```
- macro be_ge(expected)
- %value = ::Spectator::Value.new({{expected}}, {{expected.stringify}})
- ::Spectator::Matchers::GreaterThanEqualMatcher.new(%value)
- end
-
- # Indicates that some value should match another.
- # The === (case equality) operator is used for this check.
- # Typically a regular expression is used.
- # This has identical behavior as a "when" condition in a case block.
- #
- # Examples:
- # ```
- # expect("foo").to match(/foo|bar/)
- # expect("BAR").to match(/foo|bar/i)
- # expect(1 + 2).to match(3)
- # expect(5).to match(Int32) # Using `#be_a` instead is recommended here.
- # expect({:foo, 5}).to match({Symbol, Int32})
- # ```
- macro match(expected)
- %value = ::Spectator::Value.new({{expected}}, {{expected.stringify}})
- ::Spectator::Matchers::CaseMatcher.new(%value)
- end
-
- # Indicates that some value should be true.
- #
- # Examples:
- # ```
- # expect(nil.nil?).to be_true
- # expect(%i[a b c].any?).to be_true
- # ```
- macro be_true
- eq(true)
- end
-
- # Indicates that some value should be false.
- #
- # Examples:
- # ```
- # expect("foo".nil?).to be_false
- # expect(%i[a b c].empty?).to be_false
- # ```
- macro be_false
- eq(false)
- end
-
- # Indicates that some value should be truthy.
- # This means that the value is not false and not nil.
- #
- # Examples:
- # ```
- # expect(123).to be_truthy
- # expect(true).to be_truthy
- # ```
- macro be_truthy
- ::Spectator::Matchers::TruthyMatcher.new
- end
-
- # Indicates that some value should be falsey.
- # This means that the value is either false or nil.
- #
- # Examples:
- # ```
- # expect(false).to be_falsey
- # expect(nil).to be_falsey
- # ```
- macro be_falsey
- ::Spectator::Matchers::TruthyMatcher.new(false)
- end
-
- # Indicates that some value should be contained within another.
- # This checker can be used in one of two ways.
- #
- # The first: the *expected* argument can be anything
- # that implements the `includes?` method.
- # This is typically a `Range`, but can also be `Enumerable`.
- #
- # Examples:
- # ```
- # expect(:foo).to be_within(%i[foo bar baz])
- # expect(7).to be_within(1..10)
- # ```
- #
- # The other way is to use this is with the "of" keyword.
- # This creates a lower and upper bound
- # centered around the value of the *expected* argument.
- # This usage is helpful for comparisons on floating-point numbers.
- #
- # Examples:
- # ```
- # expect(50.0).to be_within(0.01).of(50.0)
- # expect(speed).to be_within(5).of(speed_limit)
- # ```
- #
- # NOTE: The of suffix must be used
- # if the *expected* argument does not implement an `includes?` method.
- #
- # Additionally, for this second usage,
- # an "inclusive" or "exclusive" suffix can be added.
- # These modify the upper-bound on the range being checked against.
- # By default, the range is inclusive.
- #
- # Examples:
- # ```
- # expect(days).to be_within(1).of(30).inclusive # 29, 30, or 31
- # expect(100).to be_within(2).of(99).exclusive # 97, 98, 99, or 100 (not 101)
- # ```
- #
- # NOTE: Do not attempt to mix the two use cases.
- # It likely won't work and will result in a compilation error.
- macro be_within(expected)
- %value = ::Spectator::Value.new({{expected}}, {{expected.stringify}})
- ::Spectator::Matchers::CollectionMatcher.new(%value)
- end
-
- # Indicates that some value should be between a lower and upper-bound.
- #
- # Example:
- # ```
- # expect(7).to be_between(1, 10)
- # ```
- #
- # Additionally, an "inclusive" or "exclusive" suffix can be added.
- # These modify the upper-bound on the range being checked against.
- # By default, the range is inclusive.
- #
- # Examples:
- # ```
- # expect(days).to be_between(28, 31).inclusive # 28, 29, 30, or 31
- # expect(100).to be_between(97, 101).exclusive # 97, 98, 99, or 100 (not 101)
- # ```
- macro be_between(min, max)
- %range = Range.new({{min}}, {{max}})
- %label = [{{min.stringify}}, {{max.stringify}}].join(" to ")
- %value = ::Spectator::Value.new(%range, %label)
- ::Spectator::Matchers::RangeMatcher.new(%value)
- end
-
- # Indicates that some value should be within a delta of an expected value.
- #
- # Example:
- # ```
- # expect(pi).to be_close(3.14159265359, 0.0000001)
- # ```
- #
- # This is functionally equivalent to:
- # ```
- # be_within(expected).of(delta)
- # ```
- macro be_close(expected, delta)
- be_within({{delta}}).of({{expected}})
- end
-
- # Indicates that some value should or should not be nil.
- #
- # Examples:
- # ```
- # expect(error).to be_nil
- # expect(input).to_not be_nil
- # ```
- macro be_nil
- ::Spectator::Matchers::NilMatcher.new
- end
-
- # Indicates that some collection should be empty.
- #
- # Example:
- # ```
- # expect([]).to be_empty
- # ```
- macro be_empty
- ::Spectator::Matchers::EmptyMatcher.new
- end
-
- # Indicates that some value or set should start with another value.
- # This is typically used on a `String` or `Array` (any `Enumerable` works).
- # The *expected* argument can be a `String`, `Char`, or `Regex`
- # when the actual type (being compared against) is a `String`.
- # For `Enumerable` types, only the first item is inspected.
- # It is compared with the === operator,
- # so that values, types, regular expressions, and others can be tested.
- #
- # Examples:
- # ```
- # expect("foobar").to start_with("foo")
- # expect("foobar").to start_with('f')
- # expect("FOOBAR").to start_with(/foo/i)
- #
- # expect(%i[a b c]).to start_with(:a)
- # expect(%i[a b c]).to start_with(Symbol)
- # expect(%w[foo bar]).to start_with(/foo/)
- # ```
- macro start_with(expected)
- %value = ::Spectator::Value.new({{expected}}, {{expected.stringify}})
- ::Spectator::Matchers::StartWithMatcher.new(%value)
- end
-
- # Indicates that some value or set should end with another value.
- # This is typically used on a `String` or `Array` (any `Indexable` works).
- # The *expected* argument can be a `String`, `Char`, or `Regex`
- # when the actual type (being compared against) is a `String`.
- # For `Indexable` types, only the last item is inspected.
- # It is compared with the === operator,
- # so that values, types, regular expressions, and others can be tested.
- #
- # Examples:
- # ```
- # expect("foobar").to end_with("bar")
- # expect("foobar").to end_with('r')
- # expect("FOOBAR").to end_with(/bar/i)
- #
- # expect(%i[a b c]).to end_with(:c)
- # expect(%i[a b c]).to end_with(Symbol)
- # expect(%w[foo bar]).to end_with(/bar/)
- # ```
- macro end_with(expected)
- %value = ::Spectator::Value.new({{expected}}, {{expected.stringify}})
- ::Spectator::Matchers::EndWithMatcher.new(%value)
- end
-
- # Indicates that some value or set should contain another value.
- # This is typically used on a `String` or `Array` (any `Enumerable` works).
- # The *expected* argument can be a `String` or `Char`
- # when the actual type (being compared against) is a `String`.
- # For `Enumerable` types, items are compared using the underlying implementation.
- # In both cases, the `includes?` method is used.
- #
- # Examples:
- # ```
- # expect("foobar").to contain("foo")
- # expect("foobar").to contain('o')
- # expect(%i[a b c]).to contain(:b)
- # ```
- #
- # Additionally, multiple arguments can be specified.
- # ```
- # expect("foobarbaz").to contain("foo", "bar")
- # expect(%i[a b c]).to contain(:a, :b)
- # ```
- macro contain(*expected)
- {% if expected.id.starts_with?("{*") %}
- %value = ::Spectator::Value.new({{expected.id[2...-1]}}, {{expected.splat.stringify}})
- ::Spectator::Matchers::ContainMatcher.new(%value)
- {% else %}
- %value = ::Spectator::Value.new({{expected}}, {{expected.splat.stringify}})
- ::Spectator::Matchers::ContainMatcher.new(%value)
- {% end %}
- end
-
- # Indicates that some value or set should contain specific items.
- # This is typically used on a `String` or `Array` (any `Enumerable` works).
- # The *expected* argument can be a `String` or `Char`
- # when the actual type (being compared against) is a `String`.
- # For `Enumerable` types, items are compared using the underlying implementation.
- # In both cases, the `includes?` method is used.
- #
- # This is identical to `#contain`, but accepts an array (or enumerable type) instead of multiple arguments.
- #
- # Examples:
- # ```
- # expect("foobar").to contain_elements(["foo", "bar"])
- # expect("foobar").to contain_elements(['a', 'b'])
- # expect(%i[a b c]).to contain_elements(%i[a b])
- # ```
- macro contain_elements(expected)
- %value = ::Spectator::Value.new({{expected}}, {{expected.stringify}})
- ::Spectator::Matchers::ContainMatcher.new(%value)
- end
-
- # Indicates that some range (or collection) should contain another value.
- # This is typically used on a `Range` (although any `Enumerable` works).
- # The `includes?` method is used.
- #
- # Examples:
- # ```
- # expect(1..10).to contain(5)
- # expect((1..)).to contain(100)
- # expect(..100).to contain(50)
- # ```
- #
- # Additionally, multiple arguments can be specified.
- # ```
- # expect(1..10).to contain(2, 3)
- # expect(..100).to contain(0, 50)
- # ```
- macro cover(*expected)
- {% if expected.id.starts_with?("{*") %}
- %value = ::Spectator::Value.new({{expected.id[2...-1]}}, {{expected.splat.stringify}})
- ::Spectator::Matchers::ContainMatcher.new(%value)
- {% else %}
- %value = ::Spectator::Value.new({{expected}}, {{expected.splat.stringify}})
- ::Spectator::Matchers::ContainMatcher.new(%value)
- {% end %}
- end
-
- # Indicates that some value or set should contain another value.
- # This is similar to `#contain`, but uses a different method for matching.
- # Typically a `String` or `Array` (any `Enumerable` works) is checked against.
- # The *expected* argument can be a `String` or `Char`
- # when the actual type (being compared against) is a `String`.
- # The `includes?` method is used for this case.
- # For `Enumerable` types, each item is inspected until one matches.
- # The === operator is used for this case, which allows for equality, type, regex, and other matches.
- #
- # Examples:
- # ```
- # expect("foobar").to have("foo")
- # expect("foobar").to have('o')
- #
- # expect(%i[a b c]).to have(:b)
- # expect(%w[FOO BAR BAZ]).to have(/bar/i)
- # expect([1, 2, 3, :a, :b, :c]).to have(Int32)
- # ```
- #
- # Additionally, multiple arguments can be specified.
- # ```
- # expect("foobarbaz").to have("foo", "bar")
- # expect(%i[a b c]).to have(:a, :b)
- # expect(%w[FOO BAR BAZ]).to have(/foo/i, String)
- # ```
- macro have(*expected)
- {% if expected.id.starts_with?("{*") %}
- %value = ::Spectator::Value.new({{expected.id[2...-1]}}, {{expected.splat.stringify}})
- ::Spectator::Matchers::HaveMatcher.new(%value)
- {% else %}
- %value = ::Spectator::Value.new({{expected}}, {{expected.splat.stringify}})
- ::Spectator::Matchers::HaveMatcher.new(%value)
- {% end %}
- end
-
- # Indicates that some value or set should contain specific items.
- # This is similar to `#contain_elements`, but uses a different method for matching.
- # Typically a `String` or `Array` (any `Enumerable` works) is checked against.
- # The *expected* argument can be a `String` or `Char`
- # when the actual type (being compared against) is a `String`.
- # The `includes?` method is used for this case.
- # For `Enumerable` types, each item is inspected until one matches.
- # The === operator is used for this case, which allows for equality, type, regex, and other matches.
- #
- # Examples:
- # ```
- # expect("foobar").to have_elements(["foo", "bar"])
- # expect("foobar").to have_elements(['a', 'b'])
- #
- # expect(%i[a b c]).to have_elements(%i[b c])
- # expect(%w[FOO BAR BAZ]).to have_elements([/FOO/, /bar/i])
- # expect([1, 2, 3, :a, :b, :c]).to have_elements([Int32, Symbol])
- # ```
- macro have_elements(expected)
- %value = ::Spectator::Value.new({{expected}}, {{expected.stringify}})
- ::Spectator::Matchers::HaveMatcher.new(%value)
- end
-
- # Indicates that some set, such as a `Hash`, has a given key.
- # The `has_key?` method is used for this check.
- #
- # Examples:
- # ```
- # expect({foo: "bar"}).to have_key(:foo)
- # expect({"lucky" => 7}).to have_key("lucky")
- # ```
- macro have_key(expected)
- %value = ::Spectator::Value.new({{expected}}, {{expected.stringify}})
- ::Spectator::Matchers::HaveKeyMatcher.new(%value)
- end
-
- # :ditto:
- macro has_key(expected)
- have_key({{expected}})
- end
-
- # Indicates that some set, such as a `Hash`, has a given value.
- # The `has_value?` method is used for this check.
- #
- # Examples:
- # ```
- # expect({foo: "bar"}).to have_value("bar")
- # expect({"lucky" => 7}).to have_value(7)
- # ```
- macro have_value(expected)
- %value = ::Spectator::Value.new({{expected}}, {{expected.stringify}})
- ::Spectator::Matchers::HaveValueMatcher.new(%value)
- end
-
- # :ditto:
- macro has_value(expected)
- have_value({{expected}})
- end
-
- # Indicates that some set should contain some values in any order.
- #
- # Example:
- # ```
- # expect([1, 2, 3]).to contain_exactly(3, 2, 1)
- # ```
- macro contain_exactly(*expected)
- {% if expected.id.starts_with?("{*") %}
- %value = ::Spectator::Value.new(({{expected.id[2...-1]}}).to_a, {{expected.stringify}})
- ::Spectator::Matchers::ArrayMatcher.new(%value)
- {% else %}
- %value = ::Spectator::Value.new(({{expected}}).to_a, {{expected.stringify}})
- ::Spectator::Matchers::ArrayMatcher.new(%value)
- {% end %}
- end
-
- # Indicates that some set should contain the same values in any order as another set.
- # This is the same as `#contain_exactly`, but takes an array as an argument.
- #
- # Example:
- # ```
- # expect([1, 2, 3]).to match_array([3, 2, 1])
- # ```
- macro match_array(expected)
- %value = ::Spectator::Value.new(({{expected}}).to_a, {{expected.stringify}})
- ::Spectator::Matchers::ArrayMatcher.new(%value)
- end
-
- # Indicates that some set should have a specified size.
- #
- # Example:
- # ```
- # expect([1, 2, 3]).to have_size(3)
- # ```
- macro have_size(expected)
- %value = ::Spectator::Value.new({{expected}}, {{expected.stringify}})
- ::Spectator::Matchers::SizeMatcher.new(%value)
- end
-
- # Indicates that some set should have the same size (number of elements) as another set.
- #
- # Example:
- # ```
- # expect([1, 2, 3]).to have_size_of(%i[x y z])
- # ```
- macro have_size_of(expected)
- %value = ::Spectator::Value.new({{expected}}, {{expected.stringify}})
- ::Spectator::Matchers::SizeOfMatcher.new(%value)
- end
-
- # Indicates that some value should have a set of attributes matching some conditions.
- # A list of named arguments are expected.
- # The names correspond to the attributes in the instance to check.
- # The values are conditions to check with the === operator against the attribute's value.
- #
- # Examples:
- # ```
- # expect("foobar").to have_attributes(size: 6, upcase: "FOOBAR")
- # expect(%i[a b c]).to have_attributes(size: 1..5, first: Symbol)
- # ```
- macro have_attributes(**expected)
- {% if expected.id.starts_with?("{**") %}
- %value = ::Spectator::Value.new({{expected.id[3...-1]}}, {{expected.double_splat.stringify}})
- ::Spectator::Matchers::AttributesMatcher.new(%value)
- {% else %}
- %value = ::Spectator::Value.new({{expected}}, {{expected.double_splat.stringify}})
- ::Spectator::Matchers::AttributesMatcher.new(%value)
- {% end %}
- end
-
- # Verifies that all elements of a collection satisfy some matcher.
- # The collection should implement `Enumerable`.
- #
- # Examples:
- # ```
- # array = [1, 2, 3, 4]
- # expect(array).to all(be_even) # Fails.
- # expect(array).to all(be_lt(5)) # Passes.
- # ```
- macro all(matcher)
- ::Spectator::Matchers::AllMatcher.new({{matcher}})
- end
-
- # Indicates that some expression's value should change after taking an action.
- #
- # Examples:
- # ```
- # i = 0
- # expect { i += 1 }.to change { i }
- # expect { i += 0 }.to_not change { i }
- # ```
- #
- # ```
- # i = 0
- # expect { i += 5 }.to change { i }.from(0).to(5)
- # ```
- #
- # ```
- # i = 0
- # expect { i += 5 }.to change { i }.to(5)
- # ```
- #
- # ```
- # i = 0
- # expect { i += 5 }.to change { i }.from(0)
- # ```
- #
- # ```
- # i = 0
- # expect { i += 42 }.to change { i }.by(42)
- # ```
- #
- # The block short-hand syntax can be used here.
- # It will reference the current subject.
- #
- # ```
- # expect { subject << :foo }.to change(&.size).by(1)
- # ```
- macro change(&expression)
- {% if expression.args.size == 1 && expression.args[0] =~ /^__arg\d+$/ && expression.body.is_a?(Call) && expression.body.id =~ /^__arg\d+\./ %}
- {% method_name = expression.body.id.split('.')[1..-1].join('.') %}
- %block = ::Spectator::Block.new({{"#" + method_name}}) do
- subject.{{method_name.id}}
- end
- {% elsif expression.args.empty? %}
- %block = ::Spectator::Block.new({{"`" + expression.body.stringify + "`"}}) {{expression}}
- {% else %}
- {% raise "Unexpected block arguments in 'expect' call" %}
- {% end %}
-
- ::Spectator::Matchers::ChangeMatcher.new(%block)
- end
-
- # Indicates that some block should raise an error.
- #
- # Examples:
- # ```
- # expect { raise "foobar" }.to raise_error
- # ```
- macro raise_error
- ::Spectator::Matchers::ExceptionMatcher(Exception, Nil).new
- end
-
- # Indicates that some block should raise an error with a given message or type.
- # The *type_or_message* parameter should be an exception type
- # or a string or regex to match the exception's message against.
- #
- # Examples:
- # ```
- # hash = {"foo" => "bar"}
- # expect { hash["baz"] }.to raise_error(KeyError)
- # expect { hash["baz"] }.to raise_error(/baz/)
- # expect { raise "foobar" }.to raise_error("foobar")
- # ```
- macro raise_error(type_or_message)
- ::Spectator::Matchers::ExceptionMatcher.create({{type_or_message}}, {{type_or_message.stringify}})
- end
-
- # Indicates that some block should raise an error with a given message and type.
- # The *type* is the exception type expected to be raised.
- # The *message* is a string or regex to match to exception message against.
- #
- # Examples:
- # ```
- # hash = {"foo" => "bar"}
- # expect { hash["baz"] }.to raise_error(KeyError, /baz/)
- # expect { raise ArgumentError.new("foobar") }.to raise_error(ArgumentError, "foobar")
- # ```
- macro raise_error(type, message)
- ::Spectator::Matchers::ExceptionMatcher.create({{type}}, {{message}}, {{message.stringify}})
- end
-
- # Indicates that some block should raise an error.
- #
- # Examples:
- # ```
- # expect_raises { raise "foobar" }
- # ```
- macro expect_raises(&block)
- expect {{block}}.to raise_error
- end
-
- # Indicates that some block should raise an error with a given type.
- # The *type* parameter should be an exception type.
- #
- # Examples:
- # ```
- # hash = {"foo" => "bar"}
- # expect_raises(KeyError) { hash["baz"] }.to raise_error(KeyError)
- # ```
- macro expect_raises(type, &block)
- expect {{block}}.to raise_error({{type}})
- end
-
- # Indicates that some block should raise an error with a given message and type.
- # The *type* is the exception type expected to be raised.
- # The *message* is a string or regex to match to exception message against.
- # This method is included for compatibility with Crystal's default spec.
- #
- # Examples:
- # ```
- # hash = {"foo" => "bar"}
- # expect_raises(KeyError, /baz/) { hash["baz"] }
- # expect_raises(ArgumentError, "foobar") { raise ArgumentError.new("foobar") }
- # ```
- macro expect_raises(type, message, &block)
- expect {{block}}.to raise_error({{type}}, {{message}})
- end
-
- # Indicates that a mock or double (stubbable type) should receive a message (have a method called).
- # The *method* is the name of the method expected to be called.
- #
- # ```
- # expect(dbl).to have_received(:foo)
- # ```
- macro have_received(method)
- %value = ::Spectator::Value.new(({{method.id.symbolize}}), {{method.id.stringify}})
- ::Spectator::Matchers::ReceiveMatcher.new(%value)
- end
-
- # Used to create predicate matchers.
- # Any missing method that starts with 'be_' or 'have_' will be handled.
- # All other method names will be ignored and raise a compile-time error.
- #
- # This can be used to simply check a predicate method that ends in '?'.
- # For instance:
- # ```
- # expect("foobar").to be_ascii_only
- # # Is equivalent to:
- # expect("foobar".ascii_only?).to be_true
- #
- # expect("foobar").to_not have_back_references
- # # Is equivalent to:
- # expect("foobar".has_back_references?).to_not be_true
- # ```
- macro method_missing(call)
- {% if call.name.starts_with?("be_") %}
- # Remove `be_` prefix.
- {% method_name = call.name[3..-1] %}
- {% matcher = "PredicateMatcher" %}
- {% elsif call.name.starts_with?("have_") %}
- # Remove `have_` prefix.
- {% method_name = call.name[5..-1] %}
- {% matcher = "HavePredicateMatcher" %}
- {% else %}
- {% raise "Undefined local variable or method '#{call}'" %}
- {% end %}
-
- descriptor = { {{method_name}}: ::Tuple.new({{call.args.splat}}) }
- label = ::String::Builder.new({{method_name.stringify}})
- {% unless call.args.empty? %}
- label << '('
- {% for arg, index in call.args %}
- label << {{arg}}
- {% if index < call.args.size - 1 %}
- label << ", "
- {% end %}
- {% end %}
- label << ')'
- {% end %}
- value = ::Spectator::Value.new(descriptor, label.to_s)
- ::Spectator::Matchers::{{matcher.id}}.new(value)
- end
- end
-end
diff --git a/lib/spectator/src/spectator/dsl/memoize.cr b/lib/spectator/src/spectator/dsl/memoize.cr
deleted file mode 100644
index 788a610..0000000
--- a/lib/spectator/src/spectator/dsl/memoize.cr
+++ /dev/null
@@ -1,108 +0,0 @@
-require "../lazy_wrapper"
-require "./reserved"
-
-module Spectator::DSL
- # DSL methods for defining test values (subjects).
- # These values are stored and reused throughout the test.
- module Memoize
- # Defines a memoized getter.
- # The *name* is the name of the getter method.
- # The block is evaluated only on the first time the getter is used
- # and the return value is saved for subsequent calls.
- macro let(name, &block)
- {% raise "Missing block for 'let'" unless block %}
- {% raise "Expected zero or one arguments for 'let', but got #{block.args.size}" if block.args.size > 1 %}
- {% raise "Cannot use 'let' inside of an example block" if @def %}
- {% raise "Cannot use '#{name.id}' for 'let'" if name.id.starts_with?("_spectator") || ::Spectator::DSL::RESERVED_KEYWORDS.includes?(name.id.symbolize) %}
-
- @%value = ::Spectator::LazyWrapper.new
-
- private def {{name.id}}
- {% if block.args.size > 0 %}
- {{block.args.first}} = ::Spectator::Example.current
- {% end %}
- @%value.get do
- {{block.body}}
- end
- end
- end
-
- # Defines a memoized getter.
- # The *name* is the name of the getter method.
- # The block is evaluated once before the example runs
- # and the return value is saved.
- macro let!(name, &block)
- {% raise "Missing block for 'let!'" unless block %}
- {% raise "Expected zero or one arguments for 'let!', but got #{block.args.size}" if block.args.size > 1 %}
- {% raise "Cannot use 'let!' inside of an example block" if @def %}
- {% raise "Cannot use '#{name.id}' for 'let!'" if name.id.starts_with?("_spectator") || ::Spectator::DSL::RESERVED_KEYWORDS.includes?(name.id.symbolize) %}
-
- let({{name}}) {{block}}
- before_each { {{name.id}} }
- end
-
- # Explicitly defines the subject of the tests.
- # Creates a memoized getter for the subject.
- # The block is evaluated only the first time the subject is referenced
- # and the return value is saved for subsequent calls.
- macro subject(&block)
- {% raise "Missing block for 'subject'" unless block %}
- {% raise "Expected zero or one arguments for 'let!', but got #{block.args.size}" if block.args.size > 1 %}
- {% raise "Cannot use 'subject' inside of an example block" if @def %}
-
- let(subject) {{block}}
- end
-
- # Explicitly defines the subject of the tests.
- # Creates a memoized getter for the subject.
- # The subject can be referenced by using `subject` or *name*.
- # The block is evaluated only the first time the subject is referenced
- # and the return value is saved for subsequent calls.
- macro subject(name, &block)
- {% raise "Missing block for 'subject'" unless block %}
- {% raise "Expected zero or one arguments for 'subject', but got #{block.args.size}" if block.args.size > 1 %}
- {% raise "Cannot use 'subject' inside of an example block" if @def %}
- {% raise "Cannot use '#{name.id}' for 'subject'" if name.id.starts_with?("_spectator") || ::Spectator::DSL::RESERVED_KEYWORDS.includes?(name.id.symbolize) %}
-
- let({{name.id}}) {{block}}
-
- {% if name.id != :subject.id %}
- private def subject
- {{name.id}}
- end
- {% end %}
- end
-
- # Explicitly defines the subject of the tests.
- # Creates a memoized getter for the subject.
- # The block is evaluated once before the example runs
- # and the return value is saved for subsequent calls.
- macro subject!(&block)
- {% raise "Missing block for 'subject'" unless block %}
- {% raise "Expected zero or one arguments for 'subject!', but got #{block.args.size}" if block.args.size > 1 %}
- {% raise "Cannot use 'subject!' inside of an example block" if @def %}
-
- let!(subject) {{block}}
- end
-
- # Explicitly defines the subject of the tests.
- # Creates a memoized getter for the subject.
- # The subject can be referenced by using `subject` or *name*.
- # The block is evaluated once before the example runs
- # and the return value is saved for subsequent calls.
- macro subject!(name, &block)
- {% raise "Missing block for 'subject'" unless block %}
- {% raise "Expected zero or one arguments for 'subject!', but got #{block.args.size}" if block.args.size > 1 %}
- {% raise "Cannot use 'subject!' inside of an example block" if @def %}
- {% raise "Cannot use '#{name.id}' for 'subject!'" if name.id.starts_with?("_spectator") || ::Spectator::DSL::RESERVED_KEYWORDS.includes?(name.id.symbolize) %}
-
- let!({{name.id}}) {{block}}
-
- {% if name.id != :subject.id %}
- private def subject
- {{name.id}}
- end
- {% end %}
- end
- end
-end
diff --git a/lib/spectator/src/spectator/dsl/metadata.cr b/lib/spectator/src/spectator/dsl/metadata.cr
deleted file mode 100644
index 04092b9..0000000
--- a/lib/spectator/src/spectator/dsl/metadata.cr
+++ /dev/null
@@ -1,29 +0,0 @@
-module Spectator::DSL
- module Metadata
- # Defines a class method named *name* that combines metadata
- # returned by *source* with *tags* and *metadata*.
- # Any falsey items from *metadata* are removed.
- private macro _spectator_metadata(name, source, *tags, **metadata)
- private def self.{{name.id}}
- %metadata = {{source.id}}.dup
- {% unless tags.empty? && metadata.empty? %}
- %metadata ||= ::Spectator::Metadata.new
- {% end %}
- {% for k in tags %}
- %metadata[{{k.id.symbolize}}] = nil
- {% end %}
- {% for k, v in metadata %}
- %cond = begin
- {{v}}
- end
- if %cond
- %metadata[{{k.id.symbolize}}] = %cond.to_s
- else
- %metadata.delete({{k.id.symbolize}})
- end
- {% end %}
- %metadata
- end
- end
- end
-end
diff --git a/lib/spectator/src/spectator/dsl/mocks.cr b/lib/spectator/src/spectator/dsl/mocks.cr
deleted file mode 100644
index 18fe1fa..0000000
--- a/lib/spectator/src/spectator/dsl/mocks.cr
+++ /dev/null
@@ -1,507 +0,0 @@
-require "../mocks"
-
-module Spectator::DSL
- # Methods and macros for mocks and doubles.
- module Mocks
- # All defined double and mock types.
- # Each tuple consists of the double name or mocked type,
- # defined context (example group), and double type name relative to its context.
- TYPES = [] of {Symbol, Symbol, Symbol}
-
- # Defines a new double type.
- #
- # This must be called from outside of a method (where classes can be defined).
- # The *name* is the identifier used to reference the double, like when instantiating it.
- # Simple stubbed methods returning a value can be defined by *value_methods*.
- # More complex methods and stubs can be defined in a block passed to this macro.
- #
- # ```
- # def_double(:dbl, foo: 42, bar: "baz") do
- # stub abstract def deferred : String
- # end
- # ```
- private macro def_double(name, **value_methods, &block)
- {% # Construct a unique type name for the double by using the number of defined doubles.
- index = ::Spectator::DSL::Mocks::TYPES.size
- double_type_name = "Double#{index}".id
- null_double_type_name = "NullDouble#{index}".id
-
- # Store information about how the double is defined and its context.
- # This is important for constructing an instance of the double later.
- ::Spectator::DSL::Mocks::TYPES << {name.id.symbolize, @type.name(generic_args: false).symbolize, double_type_name.symbolize} %}
-
- # Define the plain double type.
- ::Spectator::Double.define({{double_type_name}}, {{name}}, {{**value_methods}}) do
- # Returns a new double that responds to undefined methods with itself.
- # See: `NullDouble`
- def as_null_object
- {{null_double_type_name}}.new(@stubs)
- end
-
- {{block.body if block}}
- end
-
- {% begin %}
- # Define a matching null double type.
- ::Spectator::NullDouble.define({{null_double_type_name}}, {{name}}, {{**value_methods}}) {{block}}
- {% end %}
- end
-
- # Instantiates a double.
- #
- # The *name* is an optional identifier for the double.
- # If *name* was previously used to define a double (with `#def_double`),
- # then this macro returns a new instance of that previously defined double type.
- # Otherwise, a `LazyDouble` is created and returned.
- #
- # Initial stubbed values for methods can be provided with *value_methods*.
- #
- # ```
- # def_double(:dbl, foo: 42)
- #
- # specify do
- # dbl = new_double(:dbl, foo: 7)
- # expect(dbl.foo).to eq(7)
- # lazy = new_double(:lazy, foo: 123)
- # expect(lazy.foo).to eq(123)
- # end
- # ```
- private macro new_double(name = nil, **value_methods)
- {% # Find tuples with the same name.
- found_tuples = ::Spectator::DSL::Mocks::TYPES.select { |tuple| tuple[0] == name.id.symbolize }
-
- # Split the current context's type namespace into parts.
- type_parts = @type.name(generic_args: false).split("::")
-
- # Find tuples in the same context or a parent of where the double was defined.
- # This is done by comparing each part of their namespaces.
- found_tuples = found_tuples.select do |tuple|
- # Split the namespace of the context the double was defined in.
- context_parts = tuple[1].id.split("::")
-
- # Compare namespace parts between the context the double was defined in and this context.
- # This logic below is effectively comparing array elements, but with methods supported by macros.
- matches = context_parts.map_with_index { |part, i| part == type_parts[i] }
- matches.all? { |b| b }
- end
-
- # Sort the results by the number of namespace parts.
- # The last result will be the double type defined closest to the current context's type.
- found_tuples = found_tuples.sort_by do |tuple|
- tuple[1].id.split("::").size
- end
- found_tuple = found_tuples.last %}
-
- begin
- %double = {% if found_tuple %}
- {{found_tuple[2].id}}.new({{**value_methods}})
- {% else %}
- ::Spectator::LazyDouble.new({{name}}, {{**value_methods}})
- {% end %}
- ::Spectator::Harness.current?.try(&.cleanup { %double._spectator_reset })
- %double
- end
- end
-
- # Instantiates a class double.
- #
- # The *name* is an optional identifier for the double.
- # If *name* was previously used to define a double (with `#def_double`),
- # then this macro returns a previously defined double class.
- # Otherwise, `LazyDouble` is created and returned.
- #
- # Initial stubbed values for methods can be provided with *value_methods*.
- #
- # ```
- # def_double(:dbl) do
- # stub def self.foo
- # 42
- # end
- # end
- #
- # specify do
- # dbl = class_double(:dbl)
- # expect(dbl.foo).to eq(42)
- # allow(dbl).to receive(:foo).and_return(123)
- # expect(dbl.foo).to eq(123)
- # end
- # ```
- private macro class_double(name = nil, **value_methods)
- {% # Find tuples with the same name.
- found_tuples = ::Spectator::DSL::Mocks::TYPES.select { |tuple| tuple[0] == name.id.symbolize }
-
- # Split the current context's type namespace into parts.
- type_parts = @type.name(generic_args: false).split("::")
-
- # Find tuples in the same context or a parent of where the double was defined.
- # This is done by comparing each part of their namespaces.
- found_tuples = found_tuples.select do |tuple|
- # Split the namespace of the context the double was defined in.
- context_parts = tuple[1].id.split("::")
-
- # Compare namespace parts between the context the double was defined in and this context.
- # This logic below is effectively comparing array elements, but with methods supported by macros.
- matches = context_parts.map_with_index { |part, i| part == type_parts[i] }
- matches.all? { |b| b }
- end
-
- # Sort the results by the number of namespace parts.
- # The last result will be the double type defined closest to the current context's type.
- found_tuples = found_tuples.sort_by do |tuple|
- tuple[1].id.split("::").size
- end
- found_tuple = found_tuples.last %}
-
- begin
- %double = {% if found_tuple %}
- {{found_tuple[2].id}}
- {% else %}
- ::Spectator::LazyDouble
- {% end %}
- {% for key, value in value_methods %}
- %stub{key} = ::Spectator::ValueStub.new({{key.id.symbolize}}, {{value}})
- %double._spectator_define_stub(%stub{key})
- {% end %}
- ::Spectator::Harness.current?.try(&.cleanup { %double._spectator_reset })
- %double
- end
- end
-
- # Defines or instantiates a double.
- #
- # When used inside of a method, instantiates a new double.
- # See `#new_double`.
- #
- # When used outside of a method, defines a new double.
- # See `#def_double`.
- macro double(name, **value_methods, &block)
- {% begin %}
- {% if @def %}new_double{% else %}def_double{% end %}({{name}}, {{**value_methods}}) {{block}}
- {% end %}
- end
-
- # Instantiates a new double with predefined responses.
- #
- # This constructs a `LazyDouble`.
- #
- # ```
- # dbl = double(foo: 42)
- # expect(dbl.foo).to eq(42)
- # ```
- macro double(**value_methods)
- ::Spectator::LazyDouble.new({{**value_methods}})
- end
-
- # Defines a new mock type.
- #
- # This must be called from outside of a method (where classes can be defined).
- # *type* is the type being mocked.
- # The *name* is an optional identifier used in debug output.
- # Simple stubbed methods returning a value can be defined by *value_methods*.
- # More complex methods and stubs can be defined in a block passed to this macro.
- #
- # ```
- # abstract class MyClass
- # def foo
- # 42
- # end
- #
- # def bar
- # Time.utc
- # end
- # end
- #
- # def_mock(MyClass, foo: 5) do
- # stub def bar
- # Time.utc(2022, 7, 10)
- # end
- # end
- # ```
- private macro def_mock(type, name = nil, **value_methods, &block)
- {% resolved = type.resolve
- # Construct a unique type name for the mock by using the number of defined types.
- index = ::Spectator::DSL::Mocks::TYPES.size
- # The type is nested under the original so that any type names from the original can be resolved.
- mock_type_name = "Mock#{index}".id
-
- # Store information about how the mock is defined and its context.
- # This is important for constructing an instance of the mock later.
- ::Spectator::DSL::Mocks::TYPES << {type.id.symbolize, @type.name(generic_args: false).symbolize, "::#{resolved.name}::#{mock_type_name}".id.symbolize}
-
- base = if resolved.class?
- :class
- elsif resolved.struct?
- :struct
- else
- :module
- end %}
-
- {% begin %}
- {{base.id}} ::{{resolved.name}}
- ::Spectator::Mock.define_subtype({{base}}, {{type.id}}, {{mock_type_name}}, {{name}}, {{**value_methods}}) {{block}}
- end
- {% end %}
- end
-
- # Instantiates a mock.
- #
- # *type* is the type being mocked.
- #
- # Initial stubbed values for methods can be provided with *value_methods*.
- #
- # ```
- # abstract class MyClass
- # def foo
- # 42
- # end
- #
- # def bar
- # Time.utc
- # end
- # end
- #
- # def_mock(MyClass, foo: 5) do
- # stub def bar
- # Time.utc(2022, 7, 10)
- # end
- # end
- #
- # specify do
- # dbl = new_mock(MyClass, foo: 7)
- # expect(dbl.foo).to eq(7)
- # expect(dbl.bar).to eq(Time.utc(2022, 7, 10))
- # end
- # ```
- private macro new_mock(type, **value_methods)
- {% # Find tuples with the same name.
- found_tuples = ::Spectator::DSL::Mocks::TYPES.select { |tuple| tuple[0] == type.id.symbolize }
-
- # Split the current context's type namespace into parts.
- type_parts = @type.name(generic_args: false).split("::")
-
- # Find tuples in the same context or a parent of where the mock was defined.
- # This is done by comparing each part of their namespaces.
- found_tuples = found_tuples.select do |tuple|
- # Split the namespace of the context the double was defined in.
- context_parts = tuple[1].id.split("::")
-
- # Compare namespace parts between the context the double was defined in and this context.
- # This logic below is effectively comparing array elements, but with methods supported by macros.
- matches = context_parts.map_with_index { |part, i| part == type_parts[i] }
- matches.all? { |b| b }
- end
-
- # Sort the results by the number of namespace parts.
- # The last result will be the double type defined closest to the current context's type.
- found_tuples = found_tuples.sort_by do |tuple|
- tuple[1].id.split("::").size
- end
- found_tuple = found_tuples.last %}
-
- {% if found_tuple %}
- {{found_tuple[2].id}}.new.tap do |%mock|
- {% for key, value in value_methods %}
- %stub{key} = ::Spectator::ValueStub.new({{key.id.symbolize}}, {{value}})
- %mock._spectator_define_stub(%stub{key})
- {% end %}
- ::Spectator::Harness.current?.try(&.cleanup { %mock._spectator_reset })
- end
- {% else %}
- {% raise "Type `#{type.id}` must be previously mocked before attempting to instantiate." %}
- {% end %}
- end
-
- # Defines or instantiates a mock.
- #
- # When used inside of a method, instantiates a new mock.
- # See `#new_mock`.
- #
- # When used outside of a method, defines a new mock.
- # See `#def_mock`.
- macro mock(type, **value_methods, &block)
- {% raise "First argument of `mock` must be a type name, not #{type}" unless type.is_a?(Path) || type.is_a?(Generic) || type.is_a?(Union) || type.is_a?(Metaclass) || type.is_a?(TypeNode) %}
- {% begin %}
- {% if @def %}new_mock{% else %}def_mock{% end %}({{type}}, {{**value_methods}}) {{block}}
- {% end %}
- end
-
- # Instantiates a class mock.
- #
- # *type* is the type being mocked.
- #
- # Initial stubbed values for methods can be provided with *value_methods*.
- #
- # ```
- # class MyClass
- # def self.foo
- # 42
- # end
- # end
- #
- # def_mock(MyClass)
- #
- # specify do
- # mock = class_mock(MyClass, foo: 5)
- # expect(dbl.foo).to eq(5)
- # allow(dbl).to receive(:foo).and_return(123)
- # expect(dbl.foo).to eq(123)
- # end
- # ```
- private macro class_mock(type, **value_methods)
- {% # Find tuples with the same name.
- found_tuples = ::Spectator::DSL::Mocks::TYPES.select { |tuple| tuple[0] == type.id.symbolize }
-
- # Split the current context's type namespace into parts.
- type_parts = @type.name(generic_args: false).split("::")
-
- # Find tuples in the same context or a parent of where the mock was defined.
- # This is done by comparing each part of their namespaces.
- found_tuples = found_tuples.select do |tuple|
- # Split the namespace of the context the double was defined in.
- context_parts = tuple[1].id.split("::")
-
- # Compare namespace parts between the context the double was defined in and this context.
- # This logic below is effectively comparing array elements, but with methods supported by macros.
- matches = context_parts.map_with_index { |part, i| part == type_parts[i] }
- matches.all? { |b| b }
- end
-
- # Sort the results by the number of namespace parts.
- # The last result will be the double type defined closest to the current context's type.
- found_tuples = found_tuples.sort_by do |tuple|
- tuple[1].id.split("::").size
- end
- found_tuple = found_tuples.last %}
-
- {% if found_tuple %}
- begin
- %mock = {{found_tuple[2].id}}
- {% for key, value in value_methods %}
- %stub{key} = ::Spectator::ValueStub.new({{key.id.symbolize}}, {{value}})
- %mock._spectator_define_stub(%stub{key})
- {% end %}
- ::Spectator::Harness.current?.try(&.cleanup { %mock._spectator_reset })
- %mock
- end
- {% else %}
- {% raise "Type `#{type.id}` must be previously mocked before attempting to instantiate." %}
- {% end %}
- end
-
- # Injects mock (stub) functionality into an existing type.
- #
- # Warning: Using this will modify the type being tested.
- # This may result in different behavior between test and non-test code.
- #
- # This must be used instead of `def_mock` if a concrete struct is tested.
- # The `mock` method is not necessary to create a type with an injected mock.
- # The type can be used as it would normally instead.
- # However, stub information may leak between examples.
- #
- # The *type* is the name of the type to inject mock functionality into.
- # Initial stubbed values for methods can be provided with *value_methods*.
- #
- # ```
- # struct MyStruct
- # def foo
- # 42
- # end
- # end
- #
- # inject_mock(MyStruct, foo: 5)
- #
- # specify do
- # inst = MyStruct.new
- # expect(inst.foo).to eq(5)
- # allow(inst).to receive(:foo).and_return(123)
- # expect(inst.foo).to eq(123)
- # end
- # ```
- macro inject_mock(type, **value_methods, &block)
- {% resolved = type.resolve
- base = if resolved.class?
- :class
- elsif resolved.struct?
- :struct
- else
- :module
- end
-
- # Store information about how the mock is defined and its context.
- # This isn't required, but new_mock() should still find this type.
- ::Spectator::DSL::Mocks::TYPES << {type.id.symbolize, @type.name(generic_args: false).symbolize, resolved.name.symbolize} %}
-
- ::Spectator::Mock.inject({{base}}, {{resolved.name}}, {{**value_methods}}) {{block}}
- end
-
- # Targets a stubbable object (such as a mock or double) for operations.
- #
- # The *stubbable* must be a `Stubbable` or `StubbedType`.
- # This method is expected to be followed up with `.to receive()`.
- #
- # ```
- # dbl = dbl(:foobar)
- # allow(dbl).to receive(:foo).and_return(42)
- # ```
- def allow(stubbable : Stubbable | StubbedType)
- ::Spectator::Allow.new(stubbable)
- end
-
- # Helper method producing a compilation error when attempting to stub a non-stubbable object.
- #
- # Triggered in cases like this:
- # ```
- # allow(42).to receive(:to_s).and_return("123")
- # ```
- def allow(stubbable)
- {% raise "Target of `allow()` must be stubbable (mock or double)." %}
- end
-
- # Begins the creation of a stub.
- #
- # The *method* is the name of the method being stubbed.
- # It should not define any parameters, it should be just the method name as a literal symbol or string.
- #
- # Alone, this method returns a `NullStub`, which allows a stubbable object to return nil from a method.
- # This macro is typically followed up with a method like `and_return` to change the stub's behavior.
- #
- # ```
- # dbl = dbl(:foobar)
- # allow(dbl).to receive(:foo)
- # expect(dbl.foo).to be_nil
- #
- # allow(dbl).to receive(:foo).and_return(42)
- # expect(dbl.foo).to eq(42)
- # ```
- #
- # A block can be provided to be run every time the stub is invoked.
- # The value returned by the block is returned by the stubbed method.
- #
- # ```
- # dbl = dbl(:foobar)
- # allow(dbl).to receive(:foo) { 42 }
- # expect(dbl.foo).to eq(42)
- # ```
- macro receive(method, *, _file = __FILE__, _line = __LINE__, &block)
- {% if block %}
- %proc = ->(%args : ::Spectator::AbstractArguments) {
- {% if !block.args.empty? %}{{*block.args}} = %args {% end %}
- {{block.body}}
- }
- ::Spectator::ProcStub.new({{method.id.symbolize}}, %proc, location: ::Spectator::Location.new({{_file}}, {{_line}}))
- {% else %}
- ::Spectator::NullStub.new({{method.id.symbolize}}, location: ::Spectator::Location.new({{_file}}, {{_line}}))
- {% end %}
- end
-
- # Returns empty arguments.
- def no_args
- ::Spectator::Arguments.none
- end
-
- # Indicates any arguments can be used (no constraint).
- def any_args
- ::Spectator::Arguments.any
- end
- end
-end
diff --git a/lib/spectator/src/spectator/dsl/reserved.cr b/lib/spectator/src/spectator/dsl/reserved.cr
deleted file mode 100644
index 63e0026..0000000
--- a/lib/spectator/src/spectator/dsl/reserved.cr
+++ /dev/null
@@ -1,7 +0,0 @@
-module Spectator
- module DSL
- # Keywords that cannot be used in specs using the DSL.
- # These are either problematic or reserved for internal use.
- RESERVED_KEYWORDS = %i[initialize finalize class allocate]
- end
-end
diff --git a/lib/spectator/src/spectator/dsl/top.cr b/lib/spectator/src/spectator/dsl/top.cr
deleted file mode 100644
index e70dd8f..0000000
--- a/lib/spectator/src/spectator/dsl/top.cr
+++ /dev/null
@@ -1,32 +0,0 @@
-require "./groups"
-
-module Spectator::DSL
- module Top
- {% for method in %i[example_group describe context] %}
- # Top-level describe method.
- # All specs in a file must be wrapped in this call.
- # This takes an argument and a block.
- # The argument is what your spec is describing.
- # It can be any Crystal expression,
- # but is typically a class name or feature string.
- # The block should contain all of the examples for what is being described.
- #
- # Example:
- # ```
- # Spectator.describe Foo do
- # # Your examples for `Foo` go here.
- # end
- # ```
- #
- # Tags can be specified by adding symbols (keywords) after the first argument.
- # Key-value pairs can also be specified.
- #
- # NOTE: Inside the block, the `Spectator` prefix _should not_ be used.
- macro {{method.id}}(description, *tags, **metadata, &block)
- class ::SpectatorTestContext
- {{method.id}}(\{{description}}, \{{tags.splat(", ")}} \{{metadata.double_splat}}) \{{block}}
- end
- end
- {% end %}
- end
-end
diff --git a/lib/spectator/src/spectator/error_result.cr b/lib/spectator/src/spectator/error_result.cr
deleted file mode 100644
index f58da20..0000000
--- a/lib/spectator/src/spectator/error_result.cr
+++ /dev/null
@@ -1,28 +0,0 @@
-require "./fail_result"
-
-module Spectator
- # Outcome that indicates running an example generated an error.
- # This occurs when an unexpected exception was raised while running an example.
- # This is different from a "failed" result in that the error was not from a failed assertion.
- class ErrorResult < FailResult
- # Calls the `error` method on *visitor*.
- def accept(visitor)
- visitor.error(self)
- end
-
- # Calls the `error` method on *visitor*.
- def accept(visitor, &)
- visitor.error(yield self)
- end
-
- # One-word description of the result.
- def to_s(io : IO) : Nil
- io << "error"
- end
-
- # String used for the JSON status field.
- private def json_status
- "error"
- end
- end
-end
diff --git a/lib/spectator/src/spectator/example.cr b/lib/spectator/src/spectator/example.cr
deleted file mode 100644
index e18676c..0000000
--- a/lib/spectator/src/spectator/example.cr
+++ /dev/null
@@ -1,297 +0,0 @@
-require "./example_context_delegate"
-require "./example_group"
-require "./harness"
-require "./location"
-require "./node"
-require "./pending_result"
-require "./result"
-require "./metadata"
-
-module Spectator
- # Standard example that runs a test case.
- class Example < Node
- # Currently running example.
- class_getter! current : Example
-
- # Group the node belongs to.
- getter! group : ExampleGroup
-
- # Assigns the node to the specified *group*.
- # This is an internal method and should only be called from `ExampleGroup`.
- # `ExampleGroup` manages the association of nodes to groups.
- protected setter group : ExampleGroup?
-
- # Indicates whether the example already ran.
- getter? finished : Bool = false
-
- # Result of the last time the example ran.
- # Is pending if the example hasn't run.
- getter result : Result = PendingResult.new("Example not run")
-
- @name_proc : Proc(Example, String)?
-
- # Creates the example.
- # An instance to run the test code in is given by *context*.
- # The *entrypoint* defines the test code (typically inside *context*).
- # The *name* describes the purpose of the example.
- # The *location* tracks where the example exists in source code.
- # The example will be assigned to *group* if it is provided.
- # A set of *metadata* can be used for filtering and modifying example behavior.
- # Note: The metadata will not be merged with the parent metadata.
- def initialize(@context : Context, @entrypoint : self ->,
- name : String? = nil, location : Location? = nil,
- @group : ExampleGroup? = nil, metadata = nil)
- super(name, location, metadata)
-
- # Ensure group is linked.
- group << self if group
- end
-
- # Creates the example.
- # An instance to run the test code in is given by *context*.
- # The *entrypoint* defines the test code (typically inside *context*).
- # The *name* describes the purpose of the example.
- # It can be a proc to be evaluated in the context of the example.
- # The *location* tracks where the example exists in source code.
- # The example will be assigned to *group* if it is provided.
- # A set of *metadata* can be used for filtering and modifying example behavior.
- # Note: The metadata will not be merged with the parent metadata.
- def initialize(@context : Context, @entrypoint : self ->,
- @name_proc : Example -> String, location : Location? = nil,
- @group : ExampleGroup? = nil, metadata = nil)
- super(nil, location, metadata)
-
- # Ensure group is linked.
- group << self if group
- end
-
- # Creates a dynamic example.
- # A block provided to this method will be called as-if it were the test code for the example.
- # The block will be given this example instance as an argument.
- # The *name* describes the purpose of the example.
- # It can be a `Symbol` to describe a type.
- # The *location* tracks where the example exists in source code.
- # The example will be assigned to *group* if it is provided.
- # A set of *metadata* can be used for filtering and modifying example behavior.
- # Note: The metadata will not be merged with the parent metadata.
- def initialize(name : String? = nil, location : Location? = nil,
- @group : ExampleGroup? = nil, metadata = nil, &block : self ->)
- super(name, location, metadata)
-
- @context = NullContext.new
- @entrypoint = block
-
- # Ensure group is linked.
- group << self if group
- end
-
- # Creates a pending example.
- # The *name* describes the purpose of the example.
- # It can be a `Symbol` to describe a type.
- # The *location* tracks where the example exists in source code.
- # The example will be assigned to *group* if it is provided.
- # A set of *metadata* can be used for filtering and modifying example behavior.
- # Note: The metadata will not be merged with the parent metadata.
- def self.pending(name : String? = nil, location : Location? = nil,
- group : ExampleGroup? = nil, metadata = nil, reason = nil)
- # Add pending tag and reason if they don't exist.
- tags = {:pending => nil, :reason => reason}
- metadata = metadata ? metadata.merge(tags) { |_, v, _| v } : tags
- new(name, location, group, metadata) { nil }
- end
-
- # Executes the test case.
- # Returns the result of the execution.
- # The result will also be stored in `#result`.
- def run : Result
- Log.debug { "Running example: #{self}" }
- Log.warn { "Example already ran: #{self}" } if @finished
-
- if pending?
- Log.debug { "Skipping example #{self} - marked pending" }
- @finished = true
- return @result = PendingResult.new(pending_reason)
- end
-
- previous_example = @@current
- @@current = self
-
- begin
- @result = Harness.run do
- if proc = @name_proc
- self.name = proc.call(self)
- end
-
- @group.try(&.call_before_all)
- if (parent = @group)
- parent.call_around_each(procsy).call
- else
- run_internal
- end
- if (parent = @group)
- parent.call_after_all if parent.finished?
- end
- end
- ensure
- @@current = previous_example
- @finished = true
- end
- end
-
- private def run_internal
- if group = @group
- group.call_before_each(self)
- group.call_pre_condition(self)
- end
- Log.trace { "Running example code for: #{self}" }
- @entrypoint.call(self)
- @finished = true
- Log.trace { "Finished running example code for: #{self}" }
- if group = @group
- group.call_post_condition(self)
- group.call_after_each(self)
- end
- end
-
- # Executes code within the example's test context.
- # This is an advanced method intended for internal usage only.
- #
- # The *klass* defines the type of the test context.
- # This is typically only known by the code constructing the example.
- # An error will be raised if *klass* doesn't match the test context's type.
- # The block given to this method will be executed within the test context.
- #
- # The context casted to an instance of *klass* is provided as a block argument.
- #
- # TODO: Benchmark compiler performance using this method versus client-side casting in a proc.
- protected def with_context(klass, &)
- context = klass.cast(@context)
- with context yield
- end
-
- # Casts the example's test context to a specific type.
- # This is an advanced method intended for internal usage only.
- #
- # The *klass* defines the type of the test context.
- # This is typically only known by the code constructing the example.
- # An error will be raised if *klass* doesn't match the test context's type.
- #
- # The context casted to an instance of *klass* is returned.
- #
- # TODO: Benchmark compiler performance using this method versus client-side casting in a proc.
- protected def cast_context(klass)
- klass.cast(@context)
- end
-
- # Yields this example and all parent groups.
- def ascend(&)
- node = self
- while node
- yield node
- node = node.group?
- end
- end
-
- # Constructs the full name or description of the example.
- # This prepends names of groups this example is part of.
- def to_s(io : IO) : Nil
- name = @name
-
- # Prefix with group's full name if the node belongs to a group.
- if (parent = @group)
- parent.to_s(io)
-
- # Add padding between the node names
- # only if the names don't appear to be symbolic.
- # Skip blank group names (like the root group).
- io << ' ' unless !parent.name? || # ameba:disable Style/NegatedConditionsInUnless
- (parent.name?.is_a?(Symbol) && name.is_a?(String) &&
- (name.starts_with?('#') || name.starts_with?('.')))
- end
-
- super
- end
-
- # Exposes information about the example useful for debugging.
- def inspect(io : IO) : Nil
- super
- io << " - " << result
- end
-
- # Creates the JSON representation of the example,
- # which is just its name.
- def to_json(json : JSON::Builder)
- json.object do
- json.field("description", name? || "")
- json.field("full_description", to_s)
- if location = location?
- json.field("file_path", location.path)
- json.field("line_number", location.line)
- end
- @result.to_json(json) if @finished
- end
- end
-
- # Creates a procsy from this example that runs the example.
- def procsy
- Procsy.new(self) { run_internal }
- end
-
- # Creates a procsy from this example and the provided block.
- def procsy(&block : ->)
- Procsy.new(self, &block)
- end
-
- # Wraps an example to behave like a `Proc`.
- # This is typically used for an *around_each* hook.
- # Invoking `#call` or `#run` will run the example.
- struct Procsy
- # Underlying example that will run.
- getter example : Example
-
- # Creates the example proxy.
- # The *example* should be run eventually.
- # The *proc* defines the block of code to run when `#call` or `#run` is invoked.
- def initialize(@example : Example, &@proc : ->)
- end
-
- # Invokes the proc.
- def call : Nil
- @proc.call
- end
-
- # Invokes the proc.
- def run : Nil
- @proc.call
- end
-
- # Creates a new procsy for a block and the example from this instance.
- def wrap(&block : ->) : self
- self.class.new(@example, &block)
- end
-
- # Executes code within the example's test context.
- # This is an advanced method intended for internal usage only.
- #
- # The *klass* defines the type of the test context.
- # This is typically only known by the code constructing the example.
- # An error will be raised if *klass* doesn't match the test context's type.
- # The block given to this method will be executed within the test context.
- #
- # TODO: Benchmark compiler performance using this method versus client-side casting in a proc.
- protected def with_context(klass, &)
- context = @example.cast_context(klass)
- with context yield
- end
-
- # Allow instance to behave like an example.
- forward_missing_to @example
-
- # Constructs the full name or description of the example.
- # This prepends names of groups this example is part of.
- def to_s(io : IO) : Nil
- @example.to_s(io)
- end
- end
- end
-end
diff --git a/lib/spectator/src/spectator/example_builder.cr b/lib/spectator/src/spectator/example_builder.cr
deleted file mode 100644
index 23398d2..0000000
--- a/lib/spectator/src/spectator/example_builder.cr
+++ /dev/null
@@ -1,38 +0,0 @@
-require "./context"
-require "./example"
-require "./location"
-require "./metadata"
-require "./node_builder"
-
-module Spectator
- # Constructs examples.
- # Call `#build` to produce an `Example`.
- class ExampleBuilder < NodeBuilder
- @name : Proc(Example, String) | String?
-
- # Creates the builder.
- # A proc provided by *context_builder* is used to create a unique `Context` for each example produced by `#build`.
- # The *entrypoint* indicates the proc used to invoke the test code in the example.
- # The *name*, *location*, and *metadata* will be applied to the `Example` produced by `#build`.
- def initialize(@context_builder : -> Context, @entrypoint : Example ->,
- @name : String? = nil, @location : Location? = nil, @metadata : Metadata? = nil)
- end
-
- # Creates the builder.
- # A proc provided by *context_builder* is used to create a unique `Context` for each example produced by `#build`.
- # The *entrypoint* indicates the proc used to invoke the test code in the example.
- # The *name* is an interpolated string that runs in the context of the example.
- # *location*, and *metadata* will be applied to the `Example` produced by `#build`.
- def initialize(@context_builder : -> Context, @entrypoint : Example ->,
- @name : Example -> String, @location : Location? = nil, @metadata : Metadata? = nil)
- end
-
- # Constructs an example with previously defined attributes and context.
- # The *parent* is an already constructed example group to nest the new example under.
- # It can be nil if the new example won't have a parent.
- def build(parent = nil)
- context = @context_builder.call
- Example.new(context, @entrypoint, @name, @location, parent, @metadata)
- end
- end
-end
diff --git a/lib/spectator/src/spectator/example_context_delegate.cr b/lib/spectator/src/spectator/example_context_delegate.cr
deleted file mode 100644
index 0b61f57..0000000
--- a/lib/spectator/src/spectator/example_context_delegate.cr
+++ /dev/null
@@ -1,33 +0,0 @@
-require "./context"
-require "./example_context_method"
-require "./null_context"
-
-module Spectator
- # Stores a test context and a method to call within it.
- # This is a variant of `ContextDelegate` that accepts the current running example.
- struct ExampleContextDelegate
- # Retrieves the underlying context.
- protected getter context : Context
-
- # Creates the delegate.
- # The *context* is the instance of the test context.
- # The *method* is proc that downcasts *context* and calls a method on it.
- def initialize(@context : Context, @method : ExampleContextMethod)
- end
-
- # Creates a delegate with a null context.
- # The context will be ignored and the block will be executed in its original scope.
- # The example instance will be provided as an argument to the block.
- def self.null(&block : Example -> _)
- context = NullContext.new
- method = ExampleContextMethod.new { |example| block.call(example) }
- new(context, method)
- end
-
- # Invokes a method in the test context.
- # The *example* is the current running example.
- def call(example : Example)
- @method.call(example, @context)
- end
- end
-end
diff --git a/lib/spectator/src/spectator/example_context_method.cr b/lib/spectator/src/spectator/example_context_method.cr
deleted file mode 100644
index c14d254..0000000
--- a/lib/spectator/src/spectator/example_context_method.cr
+++ /dev/null
@@ -1,10 +0,0 @@
-require "./context"
-
-module Spectator
- # Encapsulates a method in a test context.
- # This could be used to invoke a test case or hook method.
- # The context is passed as an argument.
- # The proc should downcast the context instance to the desired type and call a method on that context.
- # The current example is also passed as an argument.
- alias ExampleContextMethod = Example, Context ->
-end
diff --git a/lib/spectator/src/spectator/example_failed.cr b/lib/spectator/src/spectator/example_failed.cr
deleted file mode 100644
index 2170604..0000000
--- a/lib/spectator/src/spectator/example_failed.cr
+++ /dev/null
@@ -1,14 +0,0 @@
-require "./location"
-
-module Spectator
- # Exception that indicates an example failed.
- # When raised within a test, the test should abort.
- class ExampleFailed < Exception
- getter! location : Location
-
- # Creates the exception.
- def initialize(@location : Location?, message : String? = nil, cause : Exception? = nil)
- super(message, cause)
- end
- end
-end
diff --git a/lib/spectator/src/spectator/example_group.cr b/lib/spectator/src/spectator/example_group.cr
deleted file mode 100644
index 55a3233..0000000
--- a/lib/spectator/src/spectator/example_group.cr
+++ /dev/null
@@ -1,151 +0,0 @@
-require "./example_procsy_hook"
-require "./hooks"
-require "./node"
-
-module Spectator
- # Collection of examples and sub-groups.
- class ExampleGroup < Node
- include Hooks
- include Indexable(Node)
-
- @nodes = [] of Node
-
- # Parent group this group belongs to.
- getter! group : ExampleGroup
-
- # Assigns this group to the specified *group*.
- # This is an internal method and should only be called from `ExampleGroup`.
- # `ExampleGroup` manages the association of nodes to groups.
- protected setter group : ExampleGroup?
-
- define_hook before_all : ExampleGroupHook do
- Log.trace { "Processing before_all hooks for: #{self}" }
-
- @group.try &.call_before_all
- before_all_hooks.each &.call_once
- end
-
- define_hook after_all : ExampleGroupHook, :prepend do
- Log.trace { "Processing after_all hooks for: #{self}" }
-
- after_all_hooks.each &.call_once if finished?
- if group = @group
- group.call_after_all if group.finished?
- end
- end
-
- define_hook before_each : ExampleHook do |example|
- Log.trace { "Processing before_each hooks for: #{self}" }
-
- @group.try &.call_before_each(example)
- before_each_hooks.each &.call(example)
- end
-
- define_hook after_each : ExampleHook, :prepend do |example|
- Log.trace { "Processing after_each hooks for: #{self}" }
-
- after_each_hooks.each &.call(example)
- @group.try &.call_after_each(example)
- end
-
- define_hook around_each : ExampleProcsyHook do |procsy|
- Log.trace { "Processing around_each hooks for: #{self}" }
-
- around_each_hooks.reverse_each { |hook| procsy = hook.wrap(procsy) }
- if group = @group
- procsy = group.call_around_each(procsy)
- end
- procsy
- end
-
- define_hook pre_condition : ExampleHook do |example|
- Log.trace { "Processing pre_condition hooks for: #{self}" }
-
- @group.try &.call_pre_condition(example)
- pre_condition_hooks.each &.call(example)
- end
-
- define_hook post_condition : ExampleHook, :prepend do |example|
- Log.trace { "Processing post_condition hooks for: #{self}" }
-
- post_condition_hooks.each &.call(example)
- @group.try &.call_post_condition(example)
- end
-
- # Creates the example group.
- # The *name* describes the purpose of the group.
- # It can be a `Symbol` to describe a type.
- # The *location* tracks where the group exists in source code.
- # This group will be assigned to the parent *group* if it is provided.
- # A set of *metadata* can be used for filtering and modifying example behavior.
- def initialize(@name : Label = nil, @location : Location? = nil,
- @group : ExampleGroup? = nil, @metadata : Metadata? = nil)
- # Ensure group is linked.
- group << self if group
- end
-
- delegate size, unsafe_fetch, to: @nodes
-
- # Yields this group and all parent groups.
- def ascend(&)
- group = self
- while group
- yield group
- group = group.group?
- end
- end
-
- # Removes the specified *node* from the group.
- # The node will be unassigned from this group.
- def delete(node : Node)
- # Only remove from the group if it is associated with this group.
- return unless node.group == self
-
- node.group = nil
- @nodes.delete(node)
- end
-
- # Checks if all examples and sub-groups have finished.
- def finished? : Bool
- @nodes.all?(&.finished?)
- end
-
- # Constructs the full name or description of the example group.
- # This prepends names of groups this group is part of.
- def to_s(io : IO, *, nested = false) : Nil
- unless parent = @group
- # Display special string when called directly.
- io << "" unless nested
- return
- end
-
- # Prefix with group's full name if the node belongs to a group.
- parent.to_s(io, nested: true)
- name = @name
-
- # Add padding between the node names
- # only if the names don't appear to be symbolic.
- # Skip blank group names (like the root group).
- io << ' ' unless !parent.name? || # ameba:disable Style/NegatedConditionsInUnless
- (parent.name?.is_a?(Symbol) && name.is_a?(String) &&
- (name.starts_with?('#') || name.starts_with?('.')))
-
- super(io)
- end
-
- # Adds the specified *node* to the group.
- # Assigns the node to this group.
- # If the node already belongs to a group,
- # it will be removed from the previous group before adding it to this group.
- def <<(node : Node)
- # Remove from existing group if the node is part of one.
- if (previous = node.group?)
- previous.delete(node)
- end
-
- # Add the node to this group and associate with it.
- @nodes << node
- node.group = self
- end
- end
-end
diff --git a/lib/spectator/src/spectator/example_group_builder.cr b/lib/spectator/src/spectator/example_group_builder.cr
deleted file mode 100644
index 207cb6e..0000000
--- a/lib/spectator/src/spectator/example_group_builder.cr
+++ /dev/null
@@ -1,62 +0,0 @@
-require "./example_group"
-require "./example_group_hook"
-require "./example_hook"
-require "./example_procsy_hook"
-require "./hooks"
-require "./label"
-require "./location"
-require "./metadata"
-require "./node_builder"
-
-module Spectator
- # Progressively constructs an example group.
- # Hooks and builders for child nodes can be added over time to this builder.
- # When done, call `#build` to produce an `ExampleGroup`.
- class ExampleGroupBuilder < NodeBuilder
- include Hooks
-
- define_hook before_all : ExampleGroupHook
- define_hook after_all : ExampleGroupHook, :prepend
- define_hook before_each : ExampleHook
- define_hook after_each : ExampleHook, :prepend
- define_hook pre_condition : ExampleHook
- define_hook post_condition : ExampleHook, :prepend
- define_hook around_each : ExampleProcsyHook
-
- @children = [] of NodeBuilder
-
- # Creates the builder.
- # Initially, the builder will have no children and no hooks.
- # The *name*, *location*, and *metadata* will be applied to the `ExampleGroup` produced by `#build`.
- def initialize(@name : Label = nil, @location : Location? = nil, @metadata : Metadata? = nil)
- end
-
- # Constructs an example group with previously defined attributes, children, and hooks.
- # The *parent* is an already constructed example group to nest the new example group under.
- # It can be nil if the new example group won't have a parent.
- def build(parent = nil)
- ExampleGroup.new(@name, @location, parent, @metadata).tap do |group|
- apply_hooks(group)
- @children.each(&.build(group))
- end
- end
-
- # Adds a child builder to the group.
- # The *builder* will have `NodeBuilder#build` called on it from within `#build`.
- # The new example group will be passed to it.
- def <<(builder)
- @children << builder
- end
-
- # Adds all previously configured hooks to an example group.
- private def apply_hooks(group)
- before_all_hooks.each { |hook| group.before_all(hook) }
- before_each_hooks.each { |hook| group.before_each(hook) }
- after_all_hooks.reverse_each { |hook| group.after_all(hook) }
- after_each_hooks.reverse_each { |hook| group.after_each(hook) }
- around_each_hooks.each { |hook| group.around_each(hook) }
- pre_condition_hooks.each { |hook| group.pre_condition(hook) }
- post_condition_hooks.reverse_each { |hook| group.post_condition(hook) }
- end
- end
-end
diff --git a/lib/spectator/src/spectator/example_group_hook.cr b/lib/spectator/src/spectator/example_group_hook.cr
deleted file mode 100644
index aee357f..0000000
--- a/lib/spectator/src/spectator/example_group_hook.cr
+++ /dev/null
@@ -1,57 +0,0 @@
-require "./label"
-require "./location"
-
-module Spectator
- # Information about a hook tied to an example group and a proc to invoke it.
- class ExampleGroupHook
- # Location of the hook in source code.
- getter! location : Location
-
- # User-defined description of the hook.
- getter! label : Label
-
- @proc : ->
- @called = Atomic::Flag.new
-
- # Creates the hook with a proc.
- # The *proc* will be called when the hook is invoked.
- # A *location* and *label* can be provided for debugging.
- def initialize(@proc : (->), *, @location : Location? = nil, @label : Label = nil)
- end
-
- # Creates the hook with a block.
- # The block will be executed when the hook is invoked.
- # A *location* and *label* can be provided for debugging.
- def initialize(*, @location : Location? = nil, @label : Label = nil, &block : -> _)
- @proc = block
- end
-
- # Invokes the hook.
- def call : Nil
- @called.test_and_set
- @proc.call
- end
-
- # Invokes the hook if it hasn't already been invoked.
- # Returns true if the hook was invoked (first time being called).
- def call_once : Bool
- first = @called.test_and_set
- @proc.call if first
- first
- end
-
- # Produces the string representation of the hook.
- # Includes the location and label if they're not nil.
- def to_s(io : IO) : Nil
- io << "example group hook"
-
- if (label = @label)
- io << ' ' << label
- end
-
- if (location = @location)
- io << " @ " << location
- end
- end
- end
-end
diff --git a/lib/spectator/src/spectator/example_group_iteration.cr b/lib/spectator/src/spectator/example_group_iteration.cr
deleted file mode 100644
index 0d20a29..0000000
--- a/lib/spectator/src/spectator/example_group_iteration.cr
+++ /dev/null
@@ -1,25 +0,0 @@
-require "./example_group"
-require "./label"
-require "./location"
-require "./metadata"
-
-module Spectator
- # Collection of examples and sub-groups for a single iteration of an iterative example group.
- class ExampleGroupIteration(T) < ExampleGroup
- # Item for this iteration of the example groups.
- getter item : T
-
- # Creates the example group iteration.
- # The element for the current iteration is provided by *item*.
- # The *name* describes the purpose of the group.
- # It can be a `Symbol` to describe a type.
- # This is typically a stringified form of *item*.
- # The *location* tracks where the group exists in source code.
- # This group will be assigned to the parent *group* if it is provided.
- # A set of *metadata* can be used for filtering and modifying example behavior.
- def initialize(@item : T, name : Label = nil, location : Location? = nil,
- group : ExampleGroup? = nil, metadata : Metadata? = nil)
- super(name, location, group, metadata)
- end
- end
-end
diff --git a/lib/spectator/src/spectator/example_hook.cr b/lib/spectator/src/spectator/example_hook.cr
deleted file mode 100644
index 6bc77a0..0000000
--- a/lib/spectator/src/spectator/example_hook.cr
+++ /dev/null
@@ -1,52 +0,0 @@
-require "./label"
-require "./location"
-
-module Spectator
- # Information about a hook tied to an example and a proc to invoke it.
- class ExampleHook
- # Method signature for example hooks.
- alias Proc = Example ->
-
- # Location of the hook in source code.
- getter! location : Location
-
- # User-defined description of the hook.
- getter! label : Label
-
- @proc : Proc
-
- # Creates the hook with a proc.
- # The *proc* will be called when the hook is invoked.
- # A *location* and *label* can be provided for debugging.
- def initialize(@proc : Proc, *, @location : Location? = nil, @label : Label = nil)
- end
-
- # Creates the hook with a block.
- # The block must take a single argument - the current example.
- # The block will be executed when the hook is invoked.
- # A *location* and *label* can be provided for debugging.
- def initialize(*, @location : Location? = nil, @label : Label = nil, &block : Proc)
- @proc = block
- end
-
- # Invokes the hook.
- # The *example* refers to the current example.
- def call(example : Example) : Nil
- @proc.call(example)
- end
-
- # Produces the string representation of the hook.
- # Includes the location and label if they're not nil.
- def to_s(io : IO) : Nil
- io << "example hook"
-
- if (label = @label)
- io << ' ' << label
- end
-
- if (location = @location)
- io << " @ " << location
- end
- end
- end
-end
diff --git a/lib/spectator/src/spectator/example_iterator.cr b/lib/spectator/src/spectator/example_iterator.cr
deleted file mode 100644
index 3a4ba30..0000000
--- a/lib/spectator/src/spectator/example_iterator.cr
+++ /dev/null
@@ -1,52 +0,0 @@
-require "./example"
-require "./node"
-
-module Spectator
- # Iterates through all examples in a group and its nested groups.
- # Nodes are iterated in pre-order.
- class ExampleIterator
- include Iterator(Example)
-
- # A stack is used to track where in the tree this iterator is.
- @stack = Deque(Node).new(1)
-
- # Creates a new iterator.
- # The *group* is the example group to iterate through.
- def initialize(@group : Node)
- @stack.push(@group)
- end
-
- # Retrieves the next `Example`.
- # If there are none left, then `Iterator::Stop` is returned.
- def next
- # Keep going until either:
- # a. an example is found.
- # b. the stack is empty.
- until @stack.empty?
- # Retrieve the next node.
- # This could be an `Example` or a group.
- node = @stack.pop
-
- # If the node is a group, add its direct children to the queue
- # in reverse order so that the tree is traversed in pre-order.
- if node.is_a?(Indexable(Node))
- node.reverse_each { |child| @stack.push(child) }
- end
-
- # Return the node if it's an example.
- # Otherwise, advance and check the next one.
- return node if node.is_a?(Example)
- end
-
- # Nothing left to iterate.
- stop
- end
-
- # Restart the iterator at the beginning.
- def rewind
- @stack.clear
- @stack.push(@group)
- self
- end
- end
-end
diff --git a/lib/spectator/src/spectator/example_pending.cr b/lib/spectator/src/spectator/example_pending.cr
deleted file mode 100644
index 16c0709..0000000
--- a/lib/spectator/src/spectator/example_pending.cr
+++ /dev/null
@@ -1,14 +0,0 @@
-module Spectator
- # Exception that indicates an example is pending and should be skipped.
- # When raised within a test, the test should abort.
- class ExamplePending < Exception
- # Location of where the example was aborted.
- getter location : Location?
-
- # Creates the exception.
- # Specify *location* to where the example was aborted.
- def initialize(@location : Location? = nil, message : String? = nil, cause : Exception? = nil)
- super(message, cause)
- end
- end
-end
diff --git a/lib/spectator/src/spectator/example_procsy_hook.cr b/lib/spectator/src/spectator/example_procsy_hook.cr
deleted file mode 100644
index 16bc970..0000000
--- a/lib/spectator/src/spectator/example_procsy_hook.cr
+++ /dev/null
@@ -1,54 +0,0 @@
-require "./label"
-require "./location"
-
-module Spectator
- # Information about a hook tied to an example and a proc to invoke it.
- class ExampleProcsyHook
- # Location of the hook in source code.
- getter! location : Location
-
- # User-defined description of the hook.
- getter! label : Label
-
- @proc : Example::Procsy ->
-
- # Creates the hook with a proc.
- # The *proc* will be called when the hook is invoked.
- # A *location* and *label* can be provided for debugging.
- def initialize(@proc : (Example::Procsy ->), *, @location : Location? = nil, @label : Label = nil)
- end
-
- # Creates the hook with a block.
- # The block must take a single argument - the current example wrapped in a procsy.
- # The block will be executed when the hook is invoked.
- # A *location* and *label* can be provided for debugging.
- def initialize(*, @location : Location? = nil, @label : Label = nil, &block : Example::Procsy -> _)
- @proc = block
- end
-
- # Invokes the hook.
- # The *example* refers to the current example.
- def call(procsy : Example::Procsy) : Nil
- @proc.call(procsy)
- end
-
- # Creates an example procsy that invokes this hook.
- def wrap(procsy : Example::Procsy) : Example::Procsy
- procsy.wrap { call(procsy) }
- end
-
- # Produces the string representation of the hook.
- # Includes the location and label if they're not nil.
- def to_s(io : IO) : Nil
- io << "example hook"
-
- if (label = @label)
- io << ' ' << label
- end
-
- if (location = @location)
- io << " @ " << location
- end
- end
- end
-end
diff --git a/lib/spectator/src/spectator/expectation.cr b/lib/spectator/src/spectator/expectation.cr
deleted file mode 100644
index 79d8473..0000000
--- a/lib/spectator/src/spectator/expectation.cr
+++ /dev/null
@@ -1,281 +0,0 @@
-require "json"
-require "./expression"
-require "./location"
-
-module Spectator
- # Result of evaluating a matcher on a target.
- # Contains information about the match,
- # such as whether it was successful and a description of the operation.
- struct Expectation
- # Location of the expectation in source code.
- # This can be nil if the location can't be captured,
- # for instance using the *should* syntax or dynamically created expectations.
- getter! location : Location
-
- # Indicates whether the expectation was met.
- def satisfied?
- @match_data.matched?
- end
-
- # Indicates whether the expectation was not met.
- def failed?
- !satisfied?
- end
-
- # If nil, then the match was successful.
- def failure_message?
- return unless match_data = @match_data.as?(Matchers::FailedMatchData)
-
- case message = @message
- when String then message
- when Proc(String) then @message = message.call # Cache result of call.
- else match_data.failure_message
- end
- end
-
- # Description of why the match failed.
- def failure_message
- failure_message?.not_nil!
- end
-
- # Additional information about the match, useful for debug.
- # If nil, then the match was successful.
- def values?
- @match_data.as?(Matchers::FailedMatchData).try(&.values)
- end
-
- # Additional information about the match, useful for debug.
- def values
- values?.not_nil!
- end
-
- def description
- @match_data.description
- end
-
- # Creates the expectation.
- # The *match_data* comes from the result of calling `Matcher#match`.
- # The *location* is the location of the expectation in source code, if available.
- # A custom *message* can be used in case of a failure.
- def initialize(@match_data : Matchers::MatchData, @location : Location? = nil,
- @message : String? | Proc(String) = nil)
- end
-
- # Creates the JSON representation of the expectation.
- def to_json(json : JSON::Builder)
- json.object do
- if location = @location
- json.field("file_path", location.path)
- json.field("line_number", location.line)
- end
- json.field("satisfied", satisfied?)
- if (failed = @match_data.as?(Matchers::FailedMatchData))
- failed_to_json(failed, json)
- end
- end
- end
-
- # Adds failure information to a JSON structure.
- private def failed_to_json(failed : Matchers::FailedMatchData, json : JSON::Builder)
- json.field("failure", failed.failure_message)
- json.field("values") do
- json.object do
- failed.values.each do |pair|
- json.field(pair.first, pair.last)
- end
- end
- end
- end
-
- # Stores part of an expectation.
- # This covers the actual value (or block) being inspected and its location.
- # This is the type returned by an `expect` block in the DSL.
- # It is not intended to be used directly, but instead by chaining methods.
- # Typically `#to` and `#not_to` are used.
- struct Target(T)
- # Creates the expectation target.
- # The *expression* is the actual value being tested and its label.
- # The *location* is the location of where this expectation was defined.
- def initialize(@expression : Expression(T), @location : Location)
- end
-
- # Asserts that a method is called some point before the example completes.
- @[AlwaysInline]
- def to(stub : Stub, message = nil) : Nil
- {% raise "The syntax `expect(...).to receive(...)` requires the expression passed to `expect` be stubbable (a mock or double)" unless T < ::Spectator::Stubbable || T < ::Spectator::StubbedType %}
-
- to_eventually(stub, message)
- end
-
- # Asserts that some criteria defined by the matcher is satisfied.
- # Allows a custom message to be used.
- def to(matcher, message = nil) : Nil
- match_data = matcher.match(@expression)
- report(match_data, message)
- end
-
- # Asserts that some criteria defined by the matcher is satisfied.
- # Allows a custom message to be used.
- # Returns the expected value cast as the expected type, if the matcher is satisfied.
- def to(matcher : Matchers::TypeMatcher(U), message = nil) forall U
- match_data = matcher.match(@expression)
- value = @expression.value
- if report(match_data, message)
- return value if value.is_a?(U)
-
- raise "Spectator bug: expected value should have cast to #{U}"
- else
- raise TypeCastError.new("#{@expression.label} is expected to be a #{U}, but was actually #{value.class}")
- end
- end
-
- # Asserts that a method is not called before the example completes.
- @[AlwaysInline]
- def to_not(stub : Stub, message = nil) : Nil
- {% raise "The syntax `expect(...).to_not receive(...)` requires the expression passed to `expect` be stubbable (a mock or double)" unless T < ::Spectator::Stubbable || T < ::Spectator::StubbedType %}
-
- to_never(stub, message)
- end
-
- # :ditto:
- @[AlwaysInline]
- def not_to(stub : Stub, message = nil) : Nil
- to_not(stub, message)
- end
-
- # Asserts that some criteria defined by the matcher is not satisfied.
- # This is effectively the opposite of `#to`.
- # Allows a custom message to be used.
- def to_not(matcher, message = nil) : Nil
- match_data = matcher.negated_match(@expression)
- report(match_data, message)
- end
-
- # Asserts that some criteria defined by the matcher is not satisfied.
- # Allows a custom message to be used.
- # Returns the expected value cast without the unexpected type, if the matcher is satisfied.
- def to_not(matcher : Matchers::TypeMatcher(U), message = nil) forall U
- match_data = matcher.negated_match(@expression)
- value = @expression.value
- if report(match_data, message)
- return value unless value.is_a?(U)
-
- raise "Spectator bug: expected value should not be #{U}"
- else
- raise TypeCastError.new("#{@expression.label} is not expected to be a #{U}, but was actually #{value.class}")
- end
- end
-
- # Asserts that some criteria defined by the matcher is not satisfied.
- # Allows a custom message to be used.
- # Returns the expected value cast as a non-nillable type, if the matcher is satisfied.
- def to_not(matcher : Matchers::NilMatcher, message = nil)
- match_data = matcher.negated_match(@expression)
- if report(match_data, message)
- value = @expression.value
- return value unless value.nil?
-
- raise "Spectator bug: expected value should not be nil"
- else
- raise NilAssertionError.new("#{@expression.label} is not expected to be nil.")
- end
- end
-
- # :ditto:
- @[AlwaysInline]
- def not_to(matcher, message = nil) : Nil
- to_not(matcher, message)
- end
-
- # Asserts that a method is called some point before the example completes.
- def to_eventually(stub : Stub, message = nil) : Nil
- {% raise "The syntax `expect(...).to_eventually receive(...)` requires the expression passed to `expect` be stubbable (a mock or double)" unless T < ::Spectator::Stubbable || T < ::Spectator::StubbedType %}
-
- stubbable = @expression.value
- unless stubbable._spectator_stub_for_method?(stub.method)
- # Add stub without an argument constraint.
- # Avoids confusing logic like this:
- # ```
- # expect(dbl).to receive(:foo).with(:bar)
- # dbl.foo(:baz)
- # ```
- # Notice that `#foo` is called, but with different arguments.
- # Normally this would raise an error, but that should be prevented.
- unconstrained_stub = stub.with(Arguments.any)
- stubbable._spectator_define_stub(unconstrained_stub)
- end
-
- # Apply the stub that is expected to be called.
- stubbable._spectator_define_stub(stub)
-
- # Check if the stub was invoked after the test completes.
- matcher = Matchers::ReceiveMatcher.new(stub)
- Harness.current.defer { to(matcher, message) }
-
- # Prevent leaking stubs between tests.
- Harness.current.cleanup { stubbable._spectator_remove_stub(stub) }
- end
-
- # Asserts that some criteria defined by the matcher is eventually satisfied.
- # The expectation is checked after the example finishes and all hooks have run.
- # Allows a custom message to be used.
- def to_eventually(matcher, message = nil) : Nil
- Harness.current.defer { to(matcher, message) }
- end
-
- # Asserts that a method is not called before the example completes.
- def to_never(stub : Stub, message = nil) : Nil
- {% raise "The syntax `expect(...).to_never receive(...)` requires the expression passed to `expect` be stubbable (a mock or double)" unless T < ::Spectator::Stubbable || T < ::Spectator::StubbedType %}
-
- stubbable = @expression.value
- unless stubbable._spectator_stub_for_method?(stub.method)
- # Add stub without an argument constraint.
- # Avoids confusing logic like this:
- # ```
- # expect(dbl).to receive(:foo).with(:bar)
- # dbl.foo(:baz)
- # ```
- # Notice that `#foo` is called, but with different arguments.
- # Normally this would raise an error, but that should be prevented.
- unconstrained_stub = stub.with(Arguments.any)
- stubbable._spectator_define_stub(unconstrained_stub)
- end
-
- # Apply the stub that could be called in case it is.
- stubbable._spectator_define_stub(stub)
-
- # Check if the stub was invoked after the test completes.
- matcher = Matchers::ReceiveMatcher.new(stub)
- Harness.current.defer { to_not(matcher, message) }
-
- # Prevent leaking stubs between tests.
- Harness.current.cleanup { stubbable._spectator_remove_stub(stub) }
- end
-
- # :ditto:
- @[AlwaysInline]
- def never_to(stub : Stub, message = nil) : Nil
- to_never(stub, message)
- end
-
- # Asserts that some criteria defined by the matcher is never satisfied.
- # The expectation is checked after the example finishes and all hooks have run.
- # Allows a custom message to be used.
- def to_never(matcher, message = nil) : Nil
- Harness.current.defer { to_not(matcher, message) }
- end
-
- # :ditto:
- @[AlwaysInline]
- def never_to(matcher, message = nil) : Nil
- to_never(matcher, message)
- end
-
- # Reports an expectation to the current harness.
- private def report(match_data : Matchers::MatchData, message : String? | Proc(String) = nil)
- expectation = Expectation.new(match_data, @location, message)
- Harness.current.report(expectation)
- end
- end
- end
-end
diff --git a/lib/spectator/src/spectator/expectation_failed.cr b/lib/spectator/src/spectator/expectation_failed.cr
deleted file mode 100644
index 2fe3941..0000000
--- a/lib/spectator/src/spectator/expectation_failed.cr
+++ /dev/null
@@ -1,16 +0,0 @@
-require "./example_failed"
-require "./expectation"
-
-module Spectator
- # Exception that indicates an expectation from a test failed.
- # When raised within a test, the test should abort.
- class ExpectationFailed < ExampleFailed
- # Expectation that failed.
- getter expectation : Expectation
-
- # Creates the exception.
- def initialize(@expectation : Expectation, message : String? = nil, cause : Exception? = nil)
- super(expectation.location?, message, cause)
- end
- end
-end
diff --git a/lib/spectator/src/spectator/expression.cr b/lib/spectator/src/spectator/expression.cr
deleted file mode 100644
index 0937b8e..0000000
--- a/lib/spectator/src/spectator/expression.cr
+++ /dev/null
@@ -1,18 +0,0 @@
-require "./abstract_expression"
-
-module Spectator
- # Represents an expression from a test.
- # This is typically captured by an `expect` macro.
- # It consists of a label and a typed expression.
- # The label should be a string recognizable by the user,
- # or nil if one isn't available.
- abstract class Expression(T) < AbstractExpression
- # Retrieves the underlying value of the expression.
- abstract def value : T
-
- # Retrieves the evaluated value of the expression.
- def raw_value
- value
- end
- end
-end
diff --git a/lib/spectator/src/spectator/fail_result.cr b/lib/spectator/src/spectator/fail_result.cr
deleted file mode 100644
index 082a0d2..0000000
--- a/lib/spectator/src/spectator/fail_result.cr
+++ /dev/null
@@ -1,81 +0,0 @@
-require "json"
-require "./example_failed"
-require "./location"
-require "./result"
-
-module Spectator
- # Outcome that indicates an example failed.
- # This typically means an assertion did not pass.
- class FailResult < Result
- # Error that occurred while running the example.
- # This describes the primary reason for the failure.
- getter error : Exception
-
- # Creates a failure result.
- # The *elapsed* argument is the length of time it took to run the example.
- # The *error* is the exception raised that caused the failure.
- def initialize(elapsed, @error, expectations = [] of Expectation)
- super(elapsed, expectations)
- end
-
- # Calls the `failure` method on *visitor*.
- def accept(visitor)
- visitor.fail(self)
- end
-
- # Calls the `failure` method on *visitor*.
- def accept(visitor, &)
- visitor.fail(yield self)
- end
-
- # Indicates whether the example passed.
- def pass? : Bool
- false
- end
-
- # Indicates whether the example failed.
- def fail? : Bool
- true
- end
-
- # Attempts to retrieve the location where the example failed.
- # This only works if the location of the failed expectation was reported.
- # If available, returns a `Location`, otherwise `nil`.
- def location? : Location?
- return unless error = @error.as?(ExampleFailed)
-
- error.location?
- end
-
- # Attempts to retrieve the location where the example failed.
- # This only works if the location of the failed expectation was reported.
- # If available, returns a `Location`, otherwise raises `NilAssertionError`.
- def location : Location
- location? || raise(NilAssertionError.new("Source location of failure unavailable"))
- end
-
- # One-word description of the result.
- def to_s(io : IO) : Nil
- io << "fail"
- end
-
- # Creates a JSON object from the result information.
- def to_json(json : JSON::Builder)
- super
- json.field("status", json_status)
- json.field("exception") do
- json.object do
- json.field("class", @error.class.name)
- json.field("message", @error.message)
- json.field("backtrace", @error.backtrace)
- end
- end
- end
-
- # String used for the JSON status field.
- # Necessary for the error result to override the status, but nothing else from `#to_json`.
- private def json_status
- "failed"
- end
- end
-end
diff --git a/lib/spectator/src/spectator/filtered_example_iterator.cr b/lib/spectator/src/spectator/filtered_example_iterator.cr
deleted file mode 100644
index 3286f3b..0000000
--- a/lib/spectator/src/spectator/filtered_example_iterator.cr
+++ /dev/null
@@ -1,85 +0,0 @@
-require "./example"
-require "./node"
-require "./node_filter"
-require "./node_iterator"
-
-module Spectator
- # Iterates through selected nodes in a group and its nested groups.
- # Nodes are iterated in pre-order.
- class FilteredExampleIterator
- include Iterator(Example)
-
- # A stack is used to track where in the tree this iterator is.
- @stack = Deque(Node).new(1)
-
- # A queue stores forced examples that have been matched by the a parent group.
- @queue = Deque(Example).new
-
- # Creates a new iterator.
- # The *group* is the example group to iterate through.
- # The *filter* selects which examples (and groups) to iterate through.
- def initialize(@group : Node, @filter : NodeFilter)
- @stack.push(@group)
- end
-
- # Retrieves the next selected `Example`.
- # If there are none left, then `Iterator::Stop` is returned.
- def next
- # Return items from the queue first before continuing to the stack.
- return @queue.shift unless @queue.empty?
-
- # Keep going until either:
- # a. a suitable example is found.
- # b. the stack is empty.
- until @stack.empty?
- # Retrieve the next node.
- node = @stack.pop
-
- # If the node is a group, conditionally traverse it.
- if node.is_a?(Indexable(Node))
- # To traverse, a child node or the group itself must match the filter.
- return node if node = next_group_match(node)
- elsif node.is_a?(Example) && @filter.includes?(node)
- return node
- end
- end
-
- # Nothing left to iterate.
- stop
- end
-
- # Restart the iterator at the beginning.
- def rewind
- @stack.clear
- @stack.push(@group)
- @queue.clear
- self
- end
-
- # Attempts to find the next matching example in a group.
- # If any child in the group matches, then traversal on the stack (down the tree) continues.
- # However, if no children match, but the group itself does, then all examples in the group match.
- # In the latter scenario, the examples are added to the queue, and the next item from the queue returned.
- # Stack iteration should continue if nil is returned.
- private def next_group_match(group : Indexable(Node)) : Example?
- # Look for any children that match.
- iterator = NodeIterator.new(group)
-
- # Check if any children match.
- # Skip first node because its the group being checked.
- if iterator.skip(1).any?(@filter)
- # Add the group's direct children to the queue
- # in reverse order so that the tree is traversed in pre-order.
- group.reverse_each { |node| @stack.push(node) }
-
- # Check if the group matches, but no children match.
- elsif @filter.includes?(group)
- # Add examples from the group to the queue.
- # Return the next example from the queue.
- iterator.rewind.select(Example).each { |node| @queue.push(node) }
- @queue.shift unless @queue.empty?
- # If the queue is empty (group has no examples), go to next loop iteration of the stack.
- end
- end
- end
-end
diff --git a/lib/spectator/src/spectator/formatting.cr b/lib/spectator/src/spectator/formatting.cr
deleted file mode 100644
index b5373d2..0000000
--- a/lib/spectator/src/spectator/formatting.cr
+++ /dev/null
@@ -1,7 +0,0 @@
-require "./formatting/*"
-
-module Spectator
- # Reports test results to the end-user in various formats.
- module Formatting
- end
-end
diff --git a/lib/spectator/src/spectator/formatting/broadcast_formatter.cr b/lib/spectator/src/spectator/formatting/broadcast_formatter.cr
deleted file mode 100644
index 76ac814..0000000
--- a/lib/spectator/src/spectator/formatting/broadcast_formatter.cr
+++ /dev/null
@@ -1,87 +0,0 @@
-require "./formatter"
-
-module Spectator::Formatting
- # Reports events to multiple other formatters.
- # Events received by this formatter will be sent to others.
- class BroadcastFormatter < Formatter
- # Creates the broadcast formatter.
- # Takes a collection of formatters to pass events along to.
- def initialize(@formatters : Enumerable(Formatter))
- end
-
- # Forwards the event to other formatters.
- def start(notification)
- @formatters.each(&.start(notification))
- end
-
- # :ditto:
- def example_started(notification)
- @formatters.each(&.example_started(notification))
- end
-
- # :ditto:
- def example_finished(notification)
- @formatters.each(&.example_finished(notification))
- end
-
- # :ditto:
- def example_passed(notification)
- @formatters.each(&.example_passed(notification))
- end
-
- # :ditto:
- def example_pending(notification)
- @formatters.each(&.example_pending(notification))
- end
-
- # :ditto:
- def example_failed(notification)
- @formatters.each(&.example_failed(notification))
- end
-
- # :ditto:
- def example_error(notification)
- @formatters.each(&.example_error(notification))
- end
-
- # :ditto:
- def message(notification)
- @formatters.each(&.message(notification))
- end
-
- # :ditto:
- def stop
- @formatters.each(&.stop)
- end
-
- # :ditto:
- def start_dump
- @formatters.each(&.start_dump)
- end
-
- # :ditto:
- def dump_pending(notification)
- @formatters.each(&.dump_pending(notification))
- end
-
- # :ditto:
- def dump_failures(notification)
- @formatters.each(&.dump_failures(notification))
- end
-
- # :ditto:
- def dump_summary(notification)
- @formatters.each(&.dump_summary(notification))
- end
-
- # :ditto:
- def dump_profile(notification)
- @formatters.each(&.dump_profile(notification))
- end
-
- # :ditto:
- def close
- @formatters.each(&.close)
- end
- end
-end
diff --git a/lib/spectator/src/spectator/formatting/components.cr b/lib/spectator/src/spectator/formatting/components.cr
deleted file mode 100644
index 9d888f3..0000000
--- a/lib/spectator/src/spectator/formatting/components.cr
+++ /dev/null
@@ -1,8 +0,0 @@
-require "./components/**"
-
-module Spectator::Formatting
- # Namespace for snippets of text displayed in console output.
- # These types are typically constructed and have `#to_s` called.
- module Components
- end
-end
diff --git a/lib/spectator/src/spectator/formatting/components/block.cr b/lib/spectator/src/spectator/formatting/components/block.cr
deleted file mode 100644
index 22411a7..0000000
--- a/lib/spectator/src/spectator/formatting/components/block.cr
+++ /dev/null
@@ -1,32 +0,0 @@
-module Spectator::Formatting::Components
- # Base type for handling indented output.
- # Indents are tracked and automatically printed.
- # Use `#indent` to increase the indent for the duration of a block.
- # Use `#line` to produce a line with an indentation prefixing it.
- abstract struct Block
- # Default indent amount.
- private INDENT = 2
-
- # Creates the block.
- # A default *indent* size can be specified.
- def initialize(*, @indent : Int32 = INDENT)
- end
-
- # Increases the indent by the a specific *amount* for the duration of the block.
- private def indent(amount = INDENT, &)
- @indent += amount
- yield
- @indent -= amount
- end
-
- # Produces a line of output with an indent before it.
- # The contents of the line should be generated by a block provided to this method.
- # Ensure that _only_ one line is produced by the block,
- # otherwise the indent will be lost.
- private def line(io, &)
- @indent.times { io << ' ' }
- yield
- io.puts
- end
- end
-end
diff --git a/lib/spectator/src/spectator/formatting/components/comment.cr b/lib/spectator/src/spectator/formatting/components/comment.cr
deleted file mode 100644
index 30f4293..0000000
--- a/lib/spectator/src/spectator/formatting/components/comment.cr
+++ /dev/null
@@ -1,23 +0,0 @@
-require "colorize"
-
-module Spectator::Formatting::Components
- # Object that can be stringified pre-pended with a comment mark (#).
- struct Comment(T)
- # Default color for a comment.
- private COLOR = :cyan
-
- # Creates a comment with the specified content.
- def initialize(@content : T)
- end
-
- # Creates a colored comment.
- def self.colorize(content)
- new(content).colorize(COLOR)
- end
-
- # Writes the comment to the output.
- def to_s(io : IO) : Nil
- io << "# " << @content
- end
- end
-end
diff --git a/lib/spectator/src/spectator/formatting/components/error_result_block.cr b/lib/spectator/src/spectator/formatting/components/error_result_block.cr
deleted file mode 100644
index a24784a..0000000
--- a/lib/spectator/src/spectator/formatting/components/error_result_block.cr
+++ /dev/null
@@ -1,83 +0,0 @@
-require "colorize"
-require "../../example"
-require "../../error_result"
-require "./result_block"
-
-module Spectator::Formatting::Components
- # Displays information about an error result.
- struct ErrorResultBlock < ResultBlock
- # Creates the component.
- def initialize(example : Example, index : Int32, @error : Exception, subindex = 0)
- super(example, index, subindex)
- end
-
- # Content displayed on the second line of the block after the label.
- private def subtitle
- @error.message.try(&.each_line.first)
- end
-
- # Prefix for the second line of the block.
- private def subtitle_label
- case @error
- when ExampleFailed then "Failure: "
- else "Error: "
- end.colorize(:red)
- end
-
- # Display error information.
- private def content(io)
- # Fetch the error and message.
- lines = @error.message.try(&.lines)
-
- # Write the error and message if available.
- case
- when lines.nil? then write_error_class(io)
- when lines.size == 1 then write_error_message(io, lines.first)
- when lines.size > 1 then write_multiline_error_message(io, lines)
- else write_error_class(io)
- end
-
- # Display the backtrace if it's available.
- if backtrace = @error.backtrace?
- indent { write_backtrace(io, backtrace) }
- end
-
- io.puts
- end
-
- # Display just the error type.
- private def write_error_class(io)
- line(io) do
- io << @error.class.colorize(:red)
- end
- end
-
- # Display the error type and first line of the message.
- private def write_error_message(io, message)
- line(io) do
- io << "#{@error.class}: ".colorize(:red)
- io << message
- end
- end
-
- # Display the error type and its multi-line message.
- private def write_multiline_error_message(io, lines)
- # Use the normal formatting for the first line.
- write_error_message(io, lines.first)
-
- # Display additional lines after the first.
- lines.skip(1).each do |entry|
- line(io) { io << entry }
- end
- end
-
- # Writes the backtrace entries to the output.
- private def write_backtrace(io, backtrace)
- backtrace.each do |entry|
- # Dim entries that are outside the shard.
- entry = entry.colorize.dim unless entry.starts_with?(/(src|spec)\//)
- line(io) { io << entry }
- end
- end
- end
-end
diff --git a/lib/spectator/src/spectator/formatting/components/example_command.cr b/lib/spectator/src/spectator/formatting/components/example_command.cr
deleted file mode 100644
index b1246db..0000000
--- a/lib/spectator/src/spectator/formatting/components/example_command.cr
+++ /dev/null
@@ -1,26 +0,0 @@
-require "../../example"
-require "./comment"
-
-module Spectator::Formatting::Components
- # Provides syntax for running a specific example from the command-line.
- struct ExampleCommand
- # Creates the component with the specified example.
- def initialize(@example : Example)
- end
-
- # Produces output for running the previously specified example.
- def to_s(io : IO) : Nil
- io << "crystal spec "
-
- # Use location for argument if it's available, since it's simpler.
- # Otherwise, use the example name filter argument.
- if location = @example.location?
- io << location
- else
- io << "-e " << @example
- end
-
- io << ' ' << Comment.colorize(@example.to_s)
- end
- end
-end
diff --git a/lib/spectator/src/spectator/formatting/components/fail_result_block.cr b/lib/spectator/src/spectator/formatting/components/fail_result_block.cr
deleted file mode 100644
index e93a94d..0000000
--- a/lib/spectator/src/spectator/formatting/components/fail_result_block.cr
+++ /dev/null
@@ -1,66 +0,0 @@
-require "colorize"
-require "../../example"
-require "../../expectation"
-require "../../fail_result"
-require "./result_block"
-
-module Spectator::Formatting::Components
- # Displays information about a fail result.
- struct FailResultBlock < ResultBlock
- @longest_key : Int32
-
- # Creates the component.
- def initialize(example : Example, index : Int32, @expectation : Expectation, subindex = 0)
- super(example, index, subindex)
- @longest_key = expectation.values.max_of { |(key, _value)| key.to_s.size }
- end
-
- # Content displayed on the second line of the block after the label.
- private def subtitle
- @expectation.failure_message
- end
-
- # Prefix for the second line of the block.
- private def subtitle_label
- "Failure: ".colorize(:red)
- end
-
- # Display expectation match data.
- private def content(io)
- indent do
- @expectation.values.each do |(key, value)|
- value_line(io, key, value)
- end
- end
-
- io.puts
- end
-
- # Display a single line for a match data value.
- private def value_line(io, key, value)
- key = key.to_s
- padding = " " * (@longest_key - key.size)
- lines = value.lines
-
- line(io) do
- io << padding << key.colorize(:red) << ": ".colorize(:red) << lines.shift
- end
-
- unless lines.empty?
- indent(@longest_key + 2) do
- lines.each do |line|
- line(io) { io << line }
- end
- end
- end
- end
-
- # Produces the location line.
- # This is where the result was determined.
- private def location_line(io)
- return unless location = @expectation.location? || @example.location?
-
- line(io) { io << Comment.colorize(location) }
- end
- end
-end
diff --git a/lib/spectator/src/spectator/formatting/components/failure_command_list.cr b/lib/spectator/src/spectator/formatting/components/failure_command_list.cr
deleted file mode 100644
index 7eab4f5..0000000
--- a/lib/spectator/src/spectator/formatting/components/failure_command_list.cr
+++ /dev/null
@@ -1,21 +0,0 @@
-require "../../example"
-require "./example_command"
-
-module Spectator::Formatting::Components
- # Produces a list of commands to run failed examples.
- struct FailureCommandList
- # Creates the component.
- # Requires a set of *failures* to display commands for.
- def initialize(@failures : Enumerable(Example))
- end
-
- # Produces the list of commands to run failed examples.
- def to_s(io : IO) : Nil
- io.puts "Failed examples:"
- io.puts
- @failures.each do |failure|
- io.puts ExampleCommand.new(failure).colorize(:red)
- end
- end
- end
-end
diff --git a/lib/spectator/src/spectator/formatting/components/junit/root.cr b/lib/spectator/src/spectator/formatting/components/junit/root.cr
deleted file mode 100644
index 3c6f440..0000000
--- a/lib/spectator/src/spectator/formatting/components/junit/root.cr
+++ /dev/null
@@ -1,39 +0,0 @@
-require "./test_suite"
-
-module Spectator::Formatting::Components::JUnit
- # Root node of the JUnit XML document.
- # This is the "testsuites" element and all of its children.
- struct Root
- # Creates the root element.
- def initialize(@runtime : Time::Span, @suites : Array(TestSuite), *,
- @total : Int32, @failures : Int32, @errors : Int32)
- end
-
- # Constructs the element from a report.
- def self.from_report(report)
- hostname = System.hostname
- counts = report.counts
- suites = report.examples.group_by { |example| example.location?.try(&.path) || "anonymous" }
- suites = suites.map do |file, examples|
- TestSuite.from_examples(file, examples, hostname)
- end
-
- new(report.runtime, suites,
- total: counts.total,
- failures: counts.fail,
- errors: counts.error)
- end
-
- # Produces the XML fragment.
- def to_xml(xml)
- xml.element("testsuites",
- tests: @total,
- failures: @failures,
- errors: @errors,
- time: @runtime.total_seconds,
- name: "Spec") do
- @suites.each(&.to_xml(xml))
- end
- end
- end
-end
diff --git a/lib/spectator/src/spectator/formatting/components/junit/test_case.cr b/lib/spectator/src/spectator/formatting/components/junit/test_case.cr
deleted file mode 100644
index 796c97f..0000000
--- a/lib/spectator/src/spectator/formatting/components/junit/test_case.cr
+++ /dev/null
@@ -1,102 +0,0 @@
-require "xml"
-require "../../../example"
-
-module Spectator::Formatting::Components::JUnit
- # Test case node of the JUnit XML document.
- # This is the "testsuite" element and all of its children.
- struct TestCase
- # Creates the test case element.
- def initialize(@class_name : String, @example : Example)
- end
-
- # Produces the XML fragment.
- def to_xml(xml)
- result = @example.result
- xml.element("testcase",
- name: @example,
- assertions: result.expectations.size,
- classname: @class_name,
- status: result.accept(StatusVisitor),
- time: result.elapsed.total_seconds) do
- visitor = ElementVisitor.new(xml)
- result.accept(visitor)
- end
- end
-
- # Picks the status string for a result.
- private module StatusVisitor
- extend self
-
- # Returns "PASS".
- def pass(_result)
- "PASS"
- end
-
- # Returns "FAIL".
- def fail(_result)
- "FAIL"
- end
-
- # :ditto:
- def error(result)
- fail(result)
- end
-
- # Returns "TODO".
- def pending(_result)
- "TODO"
- end
- end
-
- # Result visitor that adds elements to the test case node depending on the result.
- private struct ElementVisitor
- # Creates the visitor.
- def initialize(@xml : XML::Builder)
- end
-
- # Does nothing.
- def pass(_result)
- # ...
- end
-
- # Adds a failure element to the test case node.
- def fail(result)
- error = result.error
- result.expectations.each do |expectation|
- next unless expectation.failed?
-
- @xml.element("failure", message: expectation.failure_message, type: error.class) do
- match_data(expectation.values)
- end
- end
- end
-
- # Adds an error element to the test case node.
- def error(result)
- error = result.error
- fail(result) # Include failed expectations.
- @xml.element("error", message: error.message, type: error.class) do
- if backtrace = error.backtrace
- @xml.text(backtrace.join("\n"))
- end
- end
- end
-
- # Adds a skipped element to the test case node.
- def pending(result)
- @xml.element("skipped", message: result.reason)
- end
-
- # Writes match data for a failed expectation.
- private def match_data(values)
- values.each do |(key, value)|
- @xml.text("\n")
- @xml.text(key.to_s)
- @xml.text(": ")
- @xml.text(value)
- end
- @xml.text("\n")
- end
- end
- end
-end
diff --git a/lib/spectator/src/spectator/formatting/components/junit/test_suite.cr b/lib/spectator/src/spectator/formatting/components/junit/test_suite.cr
deleted file mode 100644
index 28b5adc..0000000
--- a/lib/spectator/src/spectator/formatting/components/junit/test_suite.cr
+++ /dev/null
@@ -1,104 +0,0 @@
-require "./test_case"
-
-module Spectator::Formatting::Components::JUnit
- # Test suite node of the JUnit XML document.
- # This is the "testsuite" element and all of its children.
- struct TestSuite
- # Amounts for each type of test result.
- record Counts, total : Int32, failures : Int32, errors : Int32, skipped : Int32
-
- # Creates the test suite element.
- def initialize(@package : String, @name : String, @cases : Array(TestCase),
- @time : Time::Span, @counts : Counts, @hostname : String)
- end
-
- # Constructs the test suite element from a collection of tests.
- # The *examples* should all come from the same *file*.
- def self.from_examples(file, examples, hostname)
- package, name = package_name_from_file(file)
- counts = count_examples(examples)
- time = examples.sum(&.result.elapsed)
- cases = examples.map { |example| TestCase.new(name, example) }
- new(package, name, cases, time, counts, hostname)
- end
-
- # Constructs a package and suite name from a file path.
- private def self.package_name_from_file(file)
- path = Path.new(file.to_s)
- name = path.stem
- directory = path.dirname
- package = directory.gsub(File::SEPARATOR, '.')
- {package, name}
- end
-
- # Counts the number of examples for each result type.
- private def self.count_examples(examples)
- visitor = CountVisitor.new
-
- # Iterate through each example and count the number of each type of result.
- # Don't count examples that haven't run (indicated by `Node#finished?`).
- # This typically happens in fail-fast mode.
- examples.each do |example|
- example.result.accept(visitor) if example.finished?
- end
-
- visitor.counts
- end
-
- # Produces the XML fragment.
- def to_xml(xml)
- xml.element("testsuite",
- package: @package,
- name: @name,
- tests: @counts.total,
- failures: @counts.failures,
- errors: @counts.errors,
- skipped: @counts.skipped,
- time: @time.total_seconds,
- hostname: @hostname) do
- @cases.each(&.to_xml(xml))
- end
- end
-
- # Totals up the number of each type of result.
- # Defines methods for the different types of results.
- # Call `#counts` to retrieve the `Counts` instance.
- private class CountVisitor
- @pass = 0
- @failures = 0
- @errors = 0
- @skipped = 0
-
- # Increments the number of passing examples.
- def pass(_result)
- @pass += 1
- end
-
- # Increments the number of failing (non-error) examples.
- def fail(_result)
- @failures += 1
- end
-
- # Increments the number of error (and failed) examples.
- def error(result)
- fail(result)
- @errors += 1
- end
-
- # Increments the number of pending (skipped) examples.
- def pending(_result)
- @skipped += 1
- end
-
- # Produces the total counts.
- def counts
- Counts.new(
- total: @pass + @failures + @skipped,
- failures: @failures,
- errors: @errors,
- skipped: @skipped
- )
- end
- end
- end
-end
diff --git a/lib/spectator/src/spectator/formatting/components/pending_result_block.cr b/lib/spectator/src/spectator/formatting/components/pending_result_block.cr
deleted file mode 100644
index 95c2481..0000000
--- a/lib/spectator/src/spectator/formatting/components/pending_result_block.cr
+++ /dev/null
@@ -1,29 +0,0 @@
-require "colorize"
-require "../../example"
-require "../../pending_result"
-require "./result_block"
-
-module Spectator::Formatting::Components
- # Displays information about a pending result.
- struct PendingResultBlock < ResultBlock
- # Creates the component.
- def initialize(example : Example, index : Int32, @result : PendingResult)
- super(example, index)
- end
-
- # Content displayed on the second line of the block after the label.
- private def subtitle
- @result.reason
- end
-
- # Prefix for the second line of the block.
- private def subtitle_label
- # TODO: Could be pending or skipped.
- "Pending: ".colorize(:yellow)
- end
-
- # No content for this type of block.
- private def content(io)
- end
- end
-end
diff --git a/lib/spectator/src/spectator/formatting/components/profile.cr b/lib/spectator/src/spectator/formatting/components/profile.cr
deleted file mode 100644
index b98d8f5..0000000
--- a/lib/spectator/src/spectator/formatting/components/profile.cr
+++ /dev/null
@@ -1,41 +0,0 @@
-require "../../profile"
-require "./runtime"
-
-module Spectator::Formatting::Components
- # Displays profiling information for slow examples.
- struct Profile
- # Creates the component with the specified *profile*.
- def initialize(@profile : Spectator::Profile)
- end
-
- # Produces the output containing the profiling information.
- def to_s(io : IO) : Nil
- io << "Top "
- io << @profile.size
- io << " slowest examples ("
- io << Runtime.new(@profile.time)
- io << ", "
- io << @profile.percentage.round(2)
- io.puts "% of total time):"
-
- @profile.each do |example|
- example_profile(io, example)
- end
- end
-
- # Writes a single example's timing to the output.
- private def example_profile(io, example)
- io << " "
- io.puts example
- io << " "
- io << Runtime.new(example.result.elapsed).colorize.bold
-
- if location = example.location
- io << ' '
- io.puts location
- else
- io.puts
- end
- end
- end
-end
diff --git a/lib/spectator/src/spectator/formatting/components/result_block.cr b/lib/spectator/src/spectator/formatting/components/result_block.cr
deleted file mode 100644
index ddd9c47..0000000
--- a/lib/spectator/src/spectator/formatting/components/result_block.cr
+++ /dev/null
@@ -1,95 +0,0 @@
-require "../../example"
-require "./block"
-require "./comment"
-
-module Spectator::Formatting::Components
- # Base class that displayed indexed results in block form.
- # These typically take the form:
- # ```text
- # 1) Title
- # Label: Subtitle
- #
- # Content
- # # Source
- # ```
- abstract struct ResultBlock < Block
- # Creates the block with the specified *index* and for the given *example*.
- def initialize(@example : Example, @index : Int32, @subindex : Int32 = 0)
- super()
- end
-
- # Content displayed on the first line of the block.
- # Will be stringified.
- # By default, uses the example name.
- # Can be overridden to use a different value.
- private def title
- @example
- end
-
- # Content displayed on the second line of the block after the label.
- # Will be stringified.
- private abstract def subtitle
-
- # Prefix for the second line of the block.
- # Will be stringified.
- # This is typically something like "Error:" or "Failure:"
- private abstract def subtitle_label
-
- # Produces the main content of the block.
- # *io* is the stream to write to.
- # `#line` and `#indent` (from `Block`) should be used to maintain spacing.
- private abstract def content(io)
-
- # Writes the component's output to the specified stream.
- def to_s(io : IO) : Nil
- title_line(io)
- # Ident over to align with the spacing used by the index.
- indent(index_digit_count + 2) do
- subtitle_line(io)
- io.puts
- content(io)
- location_line(io)
- end
- end
-
- # Produces the title line.
- private def title_line(io)
- line(io) do
- io << @index
- io << '.' << @subindex if @subindex > 0
- io << ") " << title
- end
- end
-
- # Produces the subtitle line.
- private def subtitle_line(io)
- line(io) do
- io << subtitle_label << subtitle
- end
- end
-
- # Produces the location line.
- # This is where the result was determined.
- private def location_line(io)
- location = if (result = @example.result).responds_to?(:location?)
- result.location?
- end
- location ||= @example.location?
- return unless location
-
- line(io) { io << Comment.colorize(location) }
- end
-
- # Computes the number of spaces the index takes
- private def index_digit_count
- count = digit_count(@index)
- count += 1 + digit_count(@subindex) if @subindex > 0
- count
- end
-
- # Computes the number of spaces an integer takes.
- private def digit_count(integer)
- (Math.log(integer.to_f + 1) / Math::LOG10).ceil.to_i
- end
- end
-end
diff --git a/lib/spectator/src/spectator/formatting/components/runtime.cr b/lib/spectator/src/spectator/formatting/components/runtime.cr
deleted file mode 100644
index 9638d93..0000000
--- a/lib/spectator/src/spectator/formatting/components/runtime.cr
+++ /dev/null
@@ -1,66 +0,0 @@
-module Spectator::Formatting::Components
- # Presents a human readable time span.
- struct Runtime
- # Creates the component.
- def initialize(@span : Time::Span)
- end
-
- # Appends the elapsed time to the output.
- # The text will be formatted as follows, depending on the magnitude:
- # ```text
- # ## microseconds
- # ## milliseconds
- # ## seconds
- # #:##
- # #:##:##
- # # days #:##:##
- # ```
- def to_s(io : IO) : Nil
- millis = @span.total_milliseconds
- return format_micro(io, millis * 1000) if millis < 1
-
- seconds = @span.total_seconds
- return format_millis(io, millis) if seconds < 1
- return format_seconds(io, seconds) if seconds < 60
-
- minutes, seconds = seconds.divmod(60)
- return format_minutes(io, minutes, seconds) if minutes < 60
-
- hours, minutes = minutes.divmod(60)
- return format_hours(io, hours, minutes, seconds) if hours < 24
-
- days, hours = hours.divmod(24)
- format_days(io, days, hours, minutes, seconds)
- end
-
- # Formats for microseconds.
- private def format_micro(io, micros)
- io << micros.round.to_i << " microseconds"
- end
-
- # Formats for milliseconds.
- private def format_millis(io, millis)
- io << millis.round(2) << " milliseconds"
- end
-
- # Formats for seconds.
- private def format_seconds(io, seconds)
- io << seconds.round(2) << " seconds"
- end
-
- # Formats for minutes.
- private def format_minutes(io, minutes, seconds)
- io.printf("%i:%02i", minutes, seconds)
- end
-
- # Formats for hours.
- private def format_hours(io, hours, minutes, seconds)
- io.printf("%i:%02i:%02i", hours, minutes, seconds)
- end
-
- # Formats for days.
- private def format_days(io, days, hours, minutes, seconds)
- io.printf("%i days %i:%02i:%02i", days, hours, minutes, seconds)
- end
- end
-end
diff --git a/lib/spectator/src/spectator/formatting/components/stats.cr b/lib/spectator/src/spectator/formatting/components/stats.cr
deleted file mode 100644
index 47e1063..0000000
--- a/lib/spectator/src/spectator/formatting/components/stats.cr
+++ /dev/null
@@ -1,38 +0,0 @@
-require "colorize"
-require "../../report"
-require "./runtime"
-require "./totals"
-
-module Spectator::Formatting::Components
- # Statistics information displayed at the end of a run.
- struct Stats
- # Creates the component with stats from *report*.
- def initialize(@report : Report)
- end
-
- # Displays the stats.
- def to_s(io : IO) : Nil
- runtime(io)
- totals(io)
- if seed = @report.random_seed?
- random(io, seed)
- end
- end
-
- # Displays the time it took to run the suite.
- private def runtime(io)
- io << "Finished in "
- io.puts Runtime.new(@report.runtime)
- end
-
- # Displays the counts for each type of result.
- private def totals(io)
- io.puts Totals.colorize(@report.counts)
- end
-
- # Displays the random seed.
- private def random(io, seed)
- io.puts "Randomized with seed: #{seed}".colorize(:cyan)
- end
- end
-end
diff --git a/lib/spectator/src/spectator/formatting/components/tap_profile.cr b/lib/spectator/src/spectator/formatting/components/tap_profile.cr
deleted file mode 100644
index 4154e07..0000000
--- a/lib/spectator/src/spectator/formatting/components/tap_profile.cr
+++ /dev/null
@@ -1,42 +0,0 @@
-require "../../profile"
-require "./runtime"
-
-module Spectator::Formatting::Components
- # Displays profiling information for slow examples in a TAP format.
- # Produces output similar to `Profile`, but formatted for TAP.
- struct TAPProfile
- # Creates the component with the specified *profile*.
- def initialize(@profile : Spectator::Profile)
- end
-
- # Produces the output containing the profiling information.
- def to_s(io : IO) : Nil
- io << "# Top "
- io << @profile.size
- io << " slowest examples ("
- io << Runtime.new(@profile.time)
- io << ", "
- io << @profile.percentage.round(2)
- io.puts "% of total time):"
-
- @profile.each do |example|
- example_profile(io, example)
- end
- end
-
- # Writes a single example's timing to the output.
- private def example_profile(io, example)
- io << "# "
- io.puts example
- io << "# "
- io << Runtime.new(example.result.elapsed)
-
- if location = example.location?
- io << ' '
- io.puts location
- else
- io.puts
- end
- end
- end
-end
diff --git a/lib/spectator/src/spectator/formatting/components/totals.cr b/lib/spectator/src/spectator/formatting/components/totals.cr
deleted file mode 100644
index 4063cae..0000000
--- a/lib/spectator/src/spectator/formatting/components/totals.cr
+++ /dev/null
@@ -1,46 +0,0 @@
-require "colorize"
-
-module Spectator::Formatting::Components
- # Displays counts for each type of example result (pass, fail, error, pending).
- struct Totals
- # Creates the component with the specified counts.
- def initialize(@examples : Int32, @failures : Int32, @errors : Int32, @pending : Int32)
- end
-
- # Creates the component by pulling numbers from *counts*.
- def initialize(counts)
- @examples = counts.run
- @failures = counts.fail
- @errors = counts.error
- @pending = counts.pending
- end
-
- # Creates the component, but colors it whether there were pending or failed results.
- # The component will be red if there were failures (or errors),
- # yellow if there were pending/skipped tests,
- # and green if everything passed.
- def self.colorize(counts)
- totals = new(counts)
- if counts.fail > 0
- totals.colorize(:red)
- elsif counts.pending > 0
- totals.colorize(:yellow)
- else
- totals.colorize(:green)
- end
- end
-
- # Writes the counts to the output.
- def to_s(io : IO) : Nil
- io << @examples << " examples, " << @failures << " failures"
-
- if @errors > 0
- io << " (" << @errors << " errors)"
- end
-
- if @pending > 0
- io << ", " << @pending << " pending"
- end
- end
- end
-end
diff --git a/lib/spectator/src/spectator/formatting/document_formatter.cr b/lib/spectator/src/spectator/formatting/document_formatter.cr
deleted file mode 100644
index 882e618..0000000
--- a/lib/spectator/src/spectator/formatting/document_formatter.cr
+++ /dev/null
@@ -1,99 +0,0 @@
-require "../label"
-require "./formatter"
-require "./summary"
-
-module Spectator::Formatting
- # Produces an indented document-style output.
- # Each nested group of examples increases the indent.
- # Example names are output in a color based on their result.
- class DocumentFormatter < Formatter
- include Summary
-
- # Indentation string.
- private INDENT = " "
-
- # String used for groups and examples that don't have a name.
- private NO_NAME = ""
-
- # Output stream to write results to.
- private getter io
-
- @previous_hierarchy = [] of Label
-
- # Creates the formatter.
- # By default, output is sent to STDOUT.
- def initialize(@io : IO = STDOUT)
- end
-
- # Invoked just before an example runs.
- # Prints the example group hierarchy if it changed.
- def example_started(notification)
- hierarchy = group_hierarchy(notification.example)
- tuple = hierarchy_diff(@previous_hierarchy, hierarchy)
- print_sub_hierarchy(*tuple)
- @previous_hierarchy = hierarchy
- end
-
- # Invoked after an example completes successfully.
- # Produces a successful example line.
- def example_passed(notification)
- name = (notification.example.name? || NO_NAME)
- line(name.colorize(:green))
- end
-
- # Invoked after an example is skipped or marked as pending.
- # Produces a pending example line.
- def example_pending(notification)
- name = (notification.example.name? || NO_NAME)
- line(name.colorize(:yellow))
- end
-
- # Invoked after an example fails.
- # Produces a failure example line.
- def example_failed(notification)
- name = (notification.example.name? || NO_NAME)
- line(name.colorize(:red))
- end
-
- # Invoked after an example fails from an unexpected error.
- # Produces a failure example line.
- def example_error(notification)
- example_failed(notification)
- end
-
- # Produces a list of groups making up the hierarchy for an example.
- private def group_hierarchy(example)
- Array(Label).new.tap do |hierarchy|
- group = example.group?
- while group && (parent = group.group?)
- hierarchy << (group.name? || NO_NAME)
- group = parent
- end
- hierarchy.reverse!
- end
- end
-
- # Generates a difference between two hierarchies.
- private def hierarchy_diff(first, second)
- index = -1
- diff = second.skip_while do |group|
- index += 1
- first.size > index && first[index] == group
- end
- {index, diff}
- end
-
- # Displays an indented hierarchy starting partially into the whole hierarchy.
- private def print_sub_hierarchy(start_index, hierarchy)
- hierarchy.each_with_index(start_index) do |name, index|
- line(name, index)
- end
- end
-
- # Displays an indented line of text.
- private def line(text, level = @previous_hierarchy.size)
- level.times { @io << INDENT }
- @io.puts text
- end
- end
-end
diff --git a/lib/spectator/src/spectator/formatting/formatter.cr b/lib/spectator/src/spectator/formatting/formatter.cr
deleted file mode 100644
index d1e6956..0000000
--- a/lib/spectator/src/spectator/formatting/formatter.cr
+++ /dev/null
@@ -1,128 +0,0 @@
-module Spectator::Formatting
- # Base class and interface used to notify systems of events.
- # This is typically used for producing output from test results,
- # but can also be used to send data to external systems.
- #
- # All event methods are implemented as no-ops.
- # To respond to an event, override its method.
- # Every method receives a notification object containing information about the event.
- #
- # Methods are called in this order:
- # 1. `#start`
- # 2. `#example_started`
- # 3. `#example_finished`
- # 4. `#example_passed`
- # 5. `#example_pending`
- # 6. `#example_failed`
- # 7. `#stop`
- # 8. `#start_dump`
- # 9. `#dump_pending`
- # 10. `#dump_failures`
- # 11. `#dump_profile`
- # 12. `#dump_summary`
- # 13. `#close`
- #
- # Only one of the `#example_passed`, `#example_pending`, or `#example_failed` methods
- # will be called after `#example_finished`, depending on the outcome of the test.
- #
- # The "dump" methods are called after all tests that will run have run.
- # They are provided summarized information.
- abstract class Formatter
- # This method is the first method to be invoked
- # and will be called only once.
- # It is called before any examples run.
- # The *notification* will be a `StartNotification` type of object.
- def start(_notification)
- end
-
- # Invoked just before an example runs.
- # This method is called once for every example.
- # The *notification* will be an `ExampleNotification` type of object.
- def example_started(_notification)
- end
-
- # Invoked just after an example completes.
- # This method is called once for every example.
- # One of `#example_passed`, `#example_pending` or `#example_failed`
- # will be called immediately after this method, depending on the example's result.
- # The *notification* will be an `ExampleNotification` type of object.
- def example_finished(_notification)
- end
-
- # Invoked after an example completes successfully.
- # This is called right after `#example_finished`.
- # The *notification* will be an `ExampleNotification` type of object.
- def example_passed(_notification)
- end
-
- # Invoked after an example is skipped or marked as pending.
- # This is called right after `#example_finished`.
- # The *notification* will be an `ExampleNotification` type of object.
- def example_pending(_notification)
- end
-
- # Invoked after an example fails.
- # This is called right after `#example_finished`.
- # The *notification* will be an `ExampleNotification` type of object.
- #
- # NOTE: Errors are normally considered failures,
- # however `#example_error` is called instead if one occurs in an example.
- def example_failed(_notification)
- end
-
- # Invoked after an example fails from an unexpected error.
- # This is called right after `#example_finished`.
- # The *notification* will be an `ExampleNotification` type of object.
- def example_error(_notification)
- end
-
- # Called whenever the example or framework produces a message.
- # This is typically used for logging.
- # The *notification* will be a `MessageNotification` type of object.
- def message(_notification)
- end
-
- # Invoked after all tests that will run have completed.
- # When this method is called, it should be considered that the testing is done.
- # Summary (dump) methods will be called after this.
- def stop
- end
-
- # Invoked after all examples finished.
- # Indicates that summarized report data is about to be produced.
- # This method is called after `#stop` and before `#dump_pending`.
- def start_dump
- end
-
- # Invoked after testing completes with a list of pending examples.
- # This method will be called with an empty list if there were no pending (skipped) examples.
- # Called after `#start_dump` and before `#dump_failures`.
- # The *notification* will be an `ExampleSummaryNotification` type of object.
- def dump_pending(_notification)
- end
-
- # Invoked after testing completes with a list of failed examples.
- # This method will be called with an empty list if there were no failures.
- # Called after `#dump_pending` and before `#dump_summary`.
- # The *notification* will be an `ExampleSummaryNotification` type of object.
- def dump_failures(_notification)
- end
-
- # Invoked after testing completes with profiling information.
- # This method is only called if profiling is enabled.
- # Called after `#dump_failures` and before `#dump_summary`.
- def dump_profile(_notification)
- end
-
- # Invoked after testing completes with summarized information from the test suite.
- # Called after `#dump_profile` and before `#close`.
- # The *notification* will be an `SummaryNotification` type of object.
- def dump_summary(_notification)
- end
-
- # Invoked at the end of the program.
- # Allows the formatter to perform any cleanup and teardown.
- def close
- end
- end
-end
diff --git a/lib/spectator/src/spectator/formatting/html/body.ecr b/lib/spectator/src/spectator/formatting/html/body.ecr
deleted file mode 100644
index 9537921..0000000
--- a/lib/spectator/src/spectator/formatting/html/body.ecr
+++ /dev/null
@@ -1,86 +0,0 @@
-
-
Test Results
- <% escape(totals(report)) %>
- <% escape(runtime(report.runtime)) %>
-
-
-<%- if report.counts.fail > 0 -%>
-Failures (<%= report.counts.fail %>)
-
- <%- report.failures.each do |example| -%>
- -
-
- <% escape(example) %>
-
-
- <%- end -%>
-
-<%- end -%>
-
-<%- if report.counts.pending > 0 -%>
-Pending (<%= report.counts.pending %>)
-
- <%- report.pending.each do |example| -%>
- -
-
- <% escape(example) %>
-
-
- <%- end -%>
-
-<%- end -%>
-
-Examples (<%= report.counts.total %>)
-
- <%- report.examples.each do |example| -%>
- -
-
<% escape(example) %>
- <%= example.result %>
- Took <% escape(runtime(example.result.elapsed)) %>
- <% if location = example.location? %><% escape(location) %><% end %>
- <% if result = example.result.as?(PendingResult) %><% escape(result.reason) %>
-
- <%- elsif result = example.result.as?(ErrorResult) -%>
-
- <% escape(result.error.class) %>
- <% escape(result.error.message) %>
-
- <%- if backtrace = result.error.backtrace? -%>
-
- <%- backtrace.each do |line| -%>
- <% escape(line) %>
- <%- end -%>
-
- <%- end -%>
-
- <%- elsif result = example.result.as?(FailResult) -%>
- <% escape(result.error.message) %>
- <%- end -%>
-
- <%- if example.result.expectations.empty? -%>
- No expectations reported
- <%- else -%>
-
Expectations
-
- <%- example.result.expectations.each do |expectation| -%>
- - "<% if location = expectation.location? %> title="<% escape(location) %>"<% end %>>
- <% escape(expectation.description) %>
- <%- if expectation.satisfied? -%>
- pass
- <%- else -%>
- fail
-
<% escape(expectation.failure_message) %>
-
- <%- expectation.values.each do |key, value| -%>
- - <% escape(key) %>
- - <% escape(value) %>
- <%- end -%>
-
- <%- end -%>
-
- <%- end -%>
-
- <%- end -%>
-
- <%- end -%>
-
diff --git a/lib/spectator/src/spectator/formatting/html/foot.ecr b/lib/spectator/src/spectator/formatting/html/foot.ecr
deleted file mode 100644
index 308b1d0..0000000
--- a/lib/spectator/src/spectator/formatting/html/foot.ecr
+++ /dev/null
@@ -1,2 +0,0 @@
-
-