browse_ai 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.DS_Store +0 -0
- data/.github/dependabot.yml +12 -0
- data/.gitignore +18 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +89 -0
- data/Rakefile +1 -0
- data/browse_ai.gemspec +31 -0
- data/config/gem_secret.yml.example +1 -0
- data/lib/.DS_Store +0 -0
- data/lib/browse_ai/client.rb +78 -0
- data/lib/browse_ai/dsl/monitors.rb +27 -0
- data/lib/browse_ai/dsl/robots.rb +23 -0
- data/lib/browse_ai/dsl/tasks.rb +27 -0
- data/lib/browse_ai/dsl/webhooks.rb +15 -0
- data/lib/browse_ai/dsl.rb +23 -0
- data/lib/browse_ai/errors/client_error.rb +9 -0
- data/lib/browse_ai/errors/resource_not_found_error.rb +8 -0
- data/lib/browse_ai/errors.rb +9 -0
- data/lib/browse_ai/resources/monitor.rb +8 -0
- data/lib/browse_ai/resources/object/attributes.rb +69 -0
- data/lib/browse_ai/resources/object/serializers.rb +104 -0
- data/lib/browse_ai/resources/object.rb +29 -0
- data/lib/browse_ai/resources/robot.rb +8 -0
- data/lib/browse_ai/resources/task.rb +8 -0
- data/lib/browse_ai/resources/webhook.rb +8 -0
- data/lib/browse_ai/resources.rb +12 -0
- data/lib/browse_ai/utils/url_helper.rb +17 -0
- data/lib/browse_ai/utils.rb +8 -0
- data/lib/browse_ai/version.rb +3 -0
- data/lib/browse_ai.rb +24 -0
- data/spec/browse_ai/client_spec.rb +5 -0
- data/spec/browse_ai/dsl/monitors_spec.rb +35 -0
- data/spec/browse_ai/dsl/robots_spec.rb +28 -0
- data/spec/browse_ai/dsl/tasks_spec.rb +35 -0
- data/spec/browse_ai/dsl/webhooks_spec.rb +21 -0
- data/spec/spec_helper.rb +20 -0
- metadata +244 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: bffa5df7a1da9581dcfcfa89c210a0ea078349e98edd4dcdb5d7d66a5e0ff6df
|
|
4
|
+
data.tar.gz: 59670edeb76def4ea436b0547527759b2637f239ef91db7ea560da04692a8d6a
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 31a5722b43a96ded76d0c2dc24430fc5c524772d1f01daa15d898d6a0b2c39682752cc3630eeb5b9a62e7362b8c868999f916f1215f521f391459727934b0c17
|
|
7
|
+
data.tar.gz: 0bdae608d3bf6da3a6aa55f35760da25c74e67adb0419cabb7ac4bc6bb937034721d251b48cadbb2e850249ad4bc2aaef161968f4ed489171d10cab47ad98109
|
data/.DS_Store
ADDED
|
Binary file
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# To get started with Dependabot version updates, you'll need to specify which
|
|
2
|
+
# package ecosystems to update and where the package manifests are located.
|
|
3
|
+
# Please see the documentation for all configuration options:
|
|
4
|
+
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
|
|
5
|
+
|
|
6
|
+
version: 2
|
|
7
|
+
updates:
|
|
8
|
+
- package-ecosystem: "bundler"
|
|
9
|
+
directory: "/"
|
|
10
|
+
schedule:
|
|
11
|
+
interval: "weekly"
|
|
12
|
+
open-pull-requests-limit: 10
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
Copyright (c) 2014 David Iorns
|
|
2
|
+
|
|
3
|
+
MIT License
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
6
|
+
a copy of this software and associated documentation files (the
|
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
11
|
+
the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be
|
|
14
|
+
included in all copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# Browse AI Ruby Client
|
|
2
|
+
|
|
3
|
+
A Ruby wrapper for the Browse AI API.
|
|
4
|
+
|
|
5
|
+
https://www.browse.ai/docs/api/v2
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
Add this line to your application's Gemfile:
|
|
10
|
+
|
|
11
|
+
```ruby
|
|
12
|
+
gem 'browse_ai'
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
And then execute:
|
|
16
|
+
|
|
17
|
+
$ bundle
|
|
18
|
+
|
|
19
|
+
Or install it yourself as:
|
|
20
|
+
|
|
21
|
+
$ gem install browse_ai
|
|
22
|
+
|
|
23
|
+
## Usage
|
|
24
|
+
|
|
25
|
+
Set the client API key.
|
|
26
|
+
```
|
|
27
|
+
BrowseAi.api_key = <your API key>
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Get robots.
|
|
31
|
+
```
|
|
32
|
+
robots = BrowseAi.client.get_robots
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Get a robot.
|
|
36
|
+
```
|
|
37
|
+
robot = BrowseAi.client.get_robot(id: '<robot UUID>')
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Get a robot's tasks.
|
|
41
|
+
```
|
|
42
|
+
tasks = BrowseAi.client.get_tasks(robot_id: '<robot UUID>')
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Get a robot's task.
|
|
46
|
+
```
|
|
47
|
+
task = BrowseAi.client.get_tasks(robot_id: '<robot UUID>', id: '<task UUID>')
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Get a robot's monitors.
|
|
51
|
+
```
|
|
52
|
+
monitors = BrowseAi.client.get_monitors(robot_id: '<robot UUID>')
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Get a robot's monitor.
|
|
56
|
+
```
|
|
57
|
+
monitor = BrowseAi.client.get_monitors(robot_id: '<robot UUID>', id: '<monitor UUID>')
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Get a robot's webhooks.
|
|
61
|
+
```
|
|
62
|
+
webhooks = BrowseAi.client.get_webhooks(robot_id: '<robot UUID>')
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Testing
|
|
66
|
+
|
|
67
|
+
Testing uses [RSpec](https://github.com/rspec/rspec), [Webmock](https://github.com/bblimke/webmock) and [VCR](https://github.com/vcr/vcr).
|
|
68
|
+
|
|
69
|
+
<strong>Tests will make real requests to the API endpoints</strong>. Ensure your test and production data is separated.
|
|
70
|
+
|
|
71
|
+
<strong>Tests currently require real data to exist for each resource.</strong>
|
|
72
|
+
Tests will fail if no data is present in your account for a specific resource.
|
|
73
|
+
For example `spec/browse_ai/dsl/robots_spec.rb` will fail if you have not yet added a robot to your account.
|
|
74
|
+
|
|
75
|
+
### Test setup
|
|
76
|
+
- Copy and rename `config/gem_secret.yml.example` to `config/gem_secret.yml` . <strong>Do not check `config/gem_secret.yml` into version control</strong>.
|
|
77
|
+
- In `config/gem_secret.yml` fill in your test API key. `browse_ai_api_key: '<your API key>'`
|
|
78
|
+
- Run rspec `bundle exec rspec`
|
|
79
|
+
|
|
80
|
+
## API Documentation
|
|
81
|
+
https://www.browse.ai/docs/api/v2
|
|
82
|
+
|
|
83
|
+
## Contributing
|
|
84
|
+
|
|
85
|
+
1. Fork it ( https://github.com/dior001/browse-ai-ruby/fork )
|
|
86
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
|
87
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
|
88
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
|
89
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require 'bundler/gem_tasks'
|
data/browse_ai.gemspec
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
lib = File.expand_path('lib', __dir__)
|
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
3
|
+
require 'browse_ai/version'
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |spec|
|
|
6
|
+
spec.name = 'browse_ai'
|
|
7
|
+
spec.version = BrowseAi::VERSION
|
|
8
|
+
spec.authors = ['David Iorns']
|
|
9
|
+
spec.email = ['david.iorns@gmail.com']
|
|
10
|
+
spec.summary = 'A Ruby wrapper for the Browse AI API. https://www.browse.ai/docs/api/v2'
|
|
11
|
+
spec.homepage = 'https://www.browse.ai/'
|
|
12
|
+
spec.license = 'MIT'
|
|
13
|
+
|
|
14
|
+
spec.files = `git ls-files -z`.split("\x0")
|
|
15
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
|
16
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
|
17
|
+
spec.require_paths = ['lib']
|
|
18
|
+
|
|
19
|
+
spec.required_ruby_version = '>= 3.0.0'
|
|
20
|
+
|
|
21
|
+
spec.add_dependency 'activesupport', '~> 8.0', '>= 8.0.2'
|
|
22
|
+
spec.add_dependency 'faraday', '~> 2.13', '>= 2.13.1'
|
|
23
|
+
spec.add_dependency 'faraday-multipart', '~> 1.1'
|
|
24
|
+
spec.add_dependency 'mime-types', '~> 3.7'
|
|
25
|
+
|
|
26
|
+
spec.add_development_dependency 'bundler', '~> 2.6', '>= 2.6.9'
|
|
27
|
+
spec.add_development_dependency 'rake', '~> 13.3'
|
|
28
|
+
spec.add_development_dependency 'rspec', '~> 3.13', '>= 3.13.1'
|
|
29
|
+
spec.add_development_dependency 'vcr', '~> 6.3', '>= 6.3.1'
|
|
30
|
+
spec.add_development_dependency 'webmock', '~> 3.25', '>= 3.25.1'
|
|
31
|
+
end
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
browse_ai_api_key: 'YOUR TESTING API KEY GOES HERE'
|
data/lib/.DS_Store
ADDED
|
Binary file
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
require 'faraday'
|
|
2
|
+
require 'faraday/multipart'
|
|
3
|
+
require 'json'
|
|
4
|
+
require 'openssl'
|
|
5
|
+
require 'active_support/all'
|
|
6
|
+
require 'browse_ai/dsl'
|
|
7
|
+
require 'browse_ai/errors'
|
|
8
|
+
require 'browse_ai/utils'
|
|
9
|
+
|
|
10
|
+
module BrowseAi
|
|
11
|
+
class Client
|
|
12
|
+
include DSL
|
|
13
|
+
include Errors
|
|
14
|
+
include Utils
|
|
15
|
+
|
|
16
|
+
REQUESTS = %i[get post put delete]
|
|
17
|
+
HEADERS = { 'Accept' => 'application/json', 'Content-Type' => 'application/json' }
|
|
18
|
+
|
|
19
|
+
def initialize(api_key = BrowseAi.api_key, url = BrowseAi.url)
|
|
20
|
+
@api_key = api_key
|
|
21
|
+
@url = url
|
|
22
|
+
|
|
23
|
+
# Setup HTTP request connection to UpWoof.
|
|
24
|
+
@connection ||= Faraday.new do |builder|
|
|
25
|
+
builder.request :multipart
|
|
26
|
+
builder.request :url_encoded
|
|
27
|
+
builder.response :logger
|
|
28
|
+
builder.adapter Faraday.default_adapter
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# @param [:get, :post, :put, :delete] method.
|
|
33
|
+
# @param [String] path.
|
|
34
|
+
# @param [Hash] query (optional).
|
|
35
|
+
# @param [Hash] headers request headers (optional).
|
|
36
|
+
# @raise [ArgumentError] If the response is blank.
|
|
37
|
+
# @raise [ResourceNotFoundError] If the response code is 404.
|
|
38
|
+
# @raise [ClientError] If the response code is not in the success range.
|
|
39
|
+
# @return [Faraday::Response] server response.
|
|
40
|
+
def request(method, path, query = {}, headers = {})
|
|
41
|
+
headers.reverse_merge!(default_headers)
|
|
42
|
+
|
|
43
|
+
unless REQUESTS.include?(method)
|
|
44
|
+
raise ArgumentError,
|
|
45
|
+
"Unsupported method #{method.inspect}. Only :get, :post, :put, :delete are allowed"
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
token_url = UrlHelper.build_url(path: "#{@url}#{path}")
|
|
49
|
+
payload = nil
|
|
50
|
+
if query.present?
|
|
51
|
+
accept = headers.present? ? headers['Accept'] : nil
|
|
52
|
+
payload = if accept.present? && accept == 'application/json'
|
|
53
|
+
JSON.generate(query)
|
|
54
|
+
else
|
|
55
|
+
query
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
response = @connection.run_request(method, token_url, payload, headers)
|
|
59
|
+
|
|
60
|
+
case response.status.to_i
|
|
61
|
+
when 200..299
|
|
62
|
+
response
|
|
63
|
+
when 404
|
|
64
|
+
raise ResourceNotFoundError.new(response: response)
|
|
65
|
+
else
|
|
66
|
+
raise ClientError.new(response: response)
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def default_headers
|
|
71
|
+
{
|
|
72
|
+
'Accept' => 'application/json',
|
|
73
|
+
'Content-Type' => 'application/json',
|
|
74
|
+
'Authorization' => "Bearer #{@api_key}"
|
|
75
|
+
}
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
require 'browse_ai/dsl'
|
|
2
|
+
|
|
3
|
+
module BrowseAi
|
|
4
|
+
module DSL::Monitors
|
|
5
|
+
# GET /Monitors
|
|
6
|
+
# Get monitors.
|
|
7
|
+
# @param [String] robot_id The ID of the robot the monitors belong to.
|
|
8
|
+
# @return [Array, nil].
|
|
9
|
+
def get_monitors(robot_id:)
|
|
10
|
+
raise ArgumentError, 'Robot ID cannot be blank' if robot_id.blank?
|
|
11
|
+
|
|
12
|
+
Resources::Monitor.parse(request(:get, "robots/#{robot_id}/monitors/", nil), %w[monitors items])
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# GET /Monitor/{id}
|
|
16
|
+
# Get a monitor.
|
|
17
|
+
# @param [String] id A monitor's ID.
|
|
18
|
+
# @raise [ArgumentError] If the method arguments are blank.
|
|
19
|
+
# @return [BrowseAi::Resources::Monitor, nil].
|
|
20
|
+
def get_monitor(robot_id:, id:)
|
|
21
|
+
raise ArgumentError, 'Robot ID cannot be blank' if robot_id.blank?
|
|
22
|
+
raise ArgumentError, 'ID cannot be blank' if id.blank?
|
|
23
|
+
|
|
24
|
+
Resources::Monitor.parse(request(:get, "robots/#{robot_id}/monitors/#{id}"), ['monitor'])
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
require 'browse_ai/dsl'
|
|
2
|
+
|
|
3
|
+
module BrowseAi
|
|
4
|
+
module DSL::Robots
|
|
5
|
+
# GET /Robots
|
|
6
|
+
# Get robots.
|
|
7
|
+
# @return [Array, nil].
|
|
8
|
+
def get_robots
|
|
9
|
+
Resources::Robot.parse(request(:get, 'robots/', nil), %w[robots items])
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# GET /Robot/{id}
|
|
13
|
+
# Get a robot.
|
|
14
|
+
# @param [String] id A robot's ID.
|
|
15
|
+
# @raise [ArgumentError] If the method arguments are blank.
|
|
16
|
+
# @return [BrowseAi::Resources::Robot, nil].
|
|
17
|
+
def get_robot(id:)
|
|
18
|
+
raise ArgumentError, 'ID cannot be blank' if id.blank?
|
|
19
|
+
|
|
20
|
+
Resources::Robot.parse(request(:get, "robots/#{id}"), ['robot'])
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
require 'browse_ai/dsl'
|
|
2
|
+
|
|
3
|
+
module BrowseAi
|
|
4
|
+
module DSL::Tasks
|
|
5
|
+
# GET /Tasks
|
|
6
|
+
# Get tasks.
|
|
7
|
+
# @param [String] robot_id The ID of the robot the tasks belong to.
|
|
8
|
+
# @return [Array, nil].
|
|
9
|
+
def get_tasks(robot_id:)
|
|
10
|
+
raise ArgumentError, 'Robot ID cannot be blank' if robot_id.blank?
|
|
11
|
+
|
|
12
|
+
Resources::Task.parse(request(:get, "robots/#{robot_id}/tasks/", nil), %w[tasks items])
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# GET /Task/{id}
|
|
16
|
+
# Get a task.
|
|
17
|
+
# @param [String] id A task's ID.
|
|
18
|
+
# @raise [ArgumentError] If the method arguments are blank.
|
|
19
|
+
# @return [BrowseAi::Resources::Task, nil].
|
|
20
|
+
def get_task(robot_id:, id:)
|
|
21
|
+
raise ArgumentError, 'Robot ID cannot be blank' if robot_id.blank?
|
|
22
|
+
raise ArgumentError, 'ID cannot be blank' if id.blank?
|
|
23
|
+
|
|
24
|
+
Resources::Task.parse(request(:get, "robots/#{robot_id}/tasks/#{id}"), ['task'])
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
require 'browse_ai/dsl'
|
|
2
|
+
|
|
3
|
+
module BrowseAi
|
|
4
|
+
module DSL::Webhooks
|
|
5
|
+
# GET /Webhooks
|
|
6
|
+
# Get webhooks.
|
|
7
|
+
# @param [String] robot_id The ID of the robot the webhooks belong to.
|
|
8
|
+
# @return [Array, nil].
|
|
9
|
+
def get_webhooks(robot_id:)
|
|
10
|
+
raise ArgumentError, 'Robot ID cannot be blank' if robot_id.blank?
|
|
11
|
+
|
|
12
|
+
Resources::Webhook.parse(request(:get, "robots/#{robot_id}/webhooks/", nil), %w[webhooks items])
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
require 'browse_ai'
|
|
2
|
+
|
|
3
|
+
module BrowseAi
|
|
4
|
+
module DSL
|
|
5
|
+
end
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
require 'browse_ai/dsl/monitors'
|
|
9
|
+
require 'browse_ai/dsl/robots'
|
|
10
|
+
require 'browse_ai/dsl/tasks'
|
|
11
|
+
require 'browse_ai/dsl/webhooks'
|
|
12
|
+
require 'browse_ai/utils'
|
|
13
|
+
require 'mime-types'
|
|
14
|
+
|
|
15
|
+
module BrowseAi
|
|
16
|
+
module DSL
|
|
17
|
+
include Monitors
|
|
18
|
+
include Robots
|
|
19
|
+
include Tasks
|
|
20
|
+
include Utils
|
|
21
|
+
include Webhooks
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
module BrowseAi::Resources::Object::Attributes
|
|
2
|
+
module ClassMethods
|
|
3
|
+
def attributes
|
|
4
|
+
@attributes ||=
|
|
5
|
+
if superclass.respond_to?(:attributes)
|
|
6
|
+
superclass.attributes.dup
|
|
7
|
+
else
|
|
8
|
+
Hash.new { |hash, key| hash[key] = ::Object }
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# @return [Module] module holding all attribute accessors
|
|
13
|
+
def attributes_module
|
|
14
|
+
@attributes_module ||= const_set(:AttributeMethods, Module.new)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def define_attribute_accessor(name, type = nil)
|
|
18
|
+
type ||= attributes[name.to_sym] || Object
|
|
19
|
+
attributes_module.send(:define_method, name) do
|
|
20
|
+
deserialize_attribute(name, type)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def attribute(name, type = String)
|
|
25
|
+
attributes[name] = type
|
|
26
|
+
|
|
27
|
+
define_attribute_accessor(name, type)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
alias has_many attribute
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def self.included(base)
|
|
34
|
+
base.extend(ClassMethods)
|
|
35
|
+
super
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def attributes
|
|
39
|
+
{}.tap do |result|
|
|
40
|
+
__getobj__.keys.each do |key|
|
|
41
|
+
attribute = key.to_s.downcase
|
|
42
|
+
result[attribute] = public_send(attribute)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def method_missing(name, *args, &block)
|
|
48
|
+
attribute = name.to_s.upcase
|
|
49
|
+
if __getobj__.key?(attribute)
|
|
50
|
+
self.class.define_attribute_accessor(name)
|
|
51
|
+
deserialize_attribute(name, self.class.attributes[name.to_sym])
|
|
52
|
+
else
|
|
53
|
+
super
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
private
|
|
58
|
+
|
|
59
|
+
def respond_to_missing?(name, include_all = false)
|
|
60
|
+
__getobj__.key?(name.to_s.upcase) || super(name, include_all)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# @param [String, Symbol] name
|
|
64
|
+
# @param [Class, #to_s] type
|
|
65
|
+
def deserialize_attribute(name, type)
|
|
66
|
+
raw = __getobj__[name.to_s.upcase]
|
|
67
|
+
self.class.serializer_for(type).deserialize(raw)
|
|
68
|
+
end
|
|
69
|
+
end
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
require 'logger'
|
|
2
|
+
module BrowseAi
|
|
3
|
+
module Resources
|
|
4
|
+
class Object
|
|
5
|
+
module Serializers
|
|
6
|
+
module Object
|
|
7
|
+
def self.serialize(value)
|
|
8
|
+
value.to_s
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def self.deserialize(value)
|
|
12
|
+
case value
|
|
13
|
+
when Array
|
|
14
|
+
value.map { |v| v.deep_transform_keys { |key| key.downcase } }
|
|
15
|
+
when Hash
|
|
16
|
+
value.deep_transform_keys { |key| key.downcase }
|
|
17
|
+
else
|
|
18
|
+
value
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
module Time
|
|
24
|
+
def self.serialize(value)
|
|
25
|
+
value.utc.xmlschema
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def self.deserialize(value)
|
|
29
|
+
::Time.parse(value)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
module ClassMethods
|
|
34
|
+
# @return [Hash] corresponding serializers for different attributes
|
|
35
|
+
def serializers
|
|
36
|
+
@serializers ||= {}
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# @param [String, Symbol] type type of attribute to be serialized or deserialized
|
|
40
|
+
# @return [#serialize, #deserialize] serializer for provided type
|
|
41
|
+
def serializer_for(type)
|
|
42
|
+
serializers[type] ||=
|
|
43
|
+
begin
|
|
44
|
+
class_symbol = type.to_s.to_sym
|
|
45
|
+
if type.respond_to?(:deserialize) && type.respond_to?(:serialize)
|
|
46
|
+
type
|
|
47
|
+
elsif Serializers.constants.include?(class_symbol)
|
|
48
|
+
Serializers.const_get(class_symbol)
|
|
49
|
+
elsif Resources.constants.include?(class_symbol)
|
|
50
|
+
Resources.const_get(class_symbol)
|
|
51
|
+
else
|
|
52
|
+
Serializers::Object
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Deserialize a Faraday response.
|
|
58
|
+
# @param [Faraday::Response] response.
|
|
59
|
+
# @raise [ArgumentError] If the response is blank.
|
|
60
|
+
# @return [Object, nil].
|
|
61
|
+
def deserialize(response, root = [])
|
|
62
|
+
raise ArgumentError, 'Response cannot be blank' if response.blank?
|
|
63
|
+
|
|
64
|
+
attributes = response.body
|
|
65
|
+
begin
|
|
66
|
+
attributes = JSON.parse(response.body)
|
|
67
|
+
attributes = attributes.dig(*root) if attributes.is_a?(Hash) && root.any?
|
|
68
|
+
|
|
69
|
+
case attributes
|
|
70
|
+
when Array
|
|
71
|
+
return attributes.map { |object| new(object) }
|
|
72
|
+
when Hash
|
|
73
|
+
return new(attributes)
|
|
74
|
+
end
|
|
75
|
+
rescue JSON::ParserError
|
|
76
|
+
logger = Logger.new(STDOUT)
|
|
77
|
+
logger.error("Could not parse: #{response.body}")
|
|
78
|
+
end
|
|
79
|
+
nil
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
alias parse deserialize
|
|
83
|
+
|
|
84
|
+
def serialize(object)
|
|
85
|
+
object.serialize
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def self.included(base)
|
|
90
|
+
super
|
|
91
|
+
base.extend ClassMethods
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def serialize
|
|
95
|
+
{}.tap do |result|
|
|
96
|
+
attributes.each do |name, value|
|
|
97
|
+
result[name.upcase] = self.class.serializer_for(name).serialize(value)
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
require 'delegate'
|
|
2
|
+
require 'json'
|
|
3
|
+
require 'time'
|
|
4
|
+
|
|
5
|
+
module BrowseAi
|
|
6
|
+
module Resources
|
|
7
|
+
class Object < SimpleDelegator
|
|
8
|
+
require 'browse_ai/resources/object/serializers'
|
|
9
|
+
require 'browse_ai/resources/object/attributes'
|
|
10
|
+
|
|
11
|
+
include Serializers
|
|
12
|
+
include Attributes
|
|
13
|
+
|
|
14
|
+
# Define common attributes, applicable to different resources
|
|
15
|
+
attribute :date_created_utc, Time
|
|
16
|
+
attribute :date_updated_utc, Time
|
|
17
|
+
|
|
18
|
+
def inspect
|
|
19
|
+
"#<#{self.class.name}:#{format('0x00%x', (object_id << 1))} #{inspect_attributes}>"
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
|
|
24
|
+
def inspect_attributes
|
|
25
|
+
attributes.map { |key, value| "@#{key}=#{value.inspect}" }.join(' ')
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
require 'browse_ai'
|
|
2
|
+
|
|
3
|
+
module BrowseAi
|
|
4
|
+
module Resources
|
|
5
|
+
end
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
require 'browse_ai/resources/monitor'
|
|
9
|
+
require 'browse_ai/resources/object'
|
|
10
|
+
require 'browse_ai/resources/robot'
|
|
11
|
+
require 'browse_ai/resources/task'
|
|
12
|
+
require 'browse_ai/resources/webhook'
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
module BrowseAi
|
|
2
|
+
module Utils
|
|
3
|
+
class UrlHelper
|
|
4
|
+
# Build a URL with a querystring containing optional params if supplied.
|
|
5
|
+
# @param [String] path The name of the resource path as per the URL e.g. contacts.
|
|
6
|
+
# @param [Hash] params A hash of params we're turning into a querystring (optional).
|
|
7
|
+
# @return [String] The URL of the resource with required params.
|
|
8
|
+
def self.build_url(path:, params: {})
|
|
9
|
+
params.delete_if { |_k, v| v.blank? }
|
|
10
|
+
params = params.to_query
|
|
11
|
+
query = path
|
|
12
|
+
query << ('?' + params) unless params.blank?
|
|
13
|
+
query
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
data/lib/browse_ai.rb
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
require 'browse_ai/version'
|
|
2
|
+
|
|
3
|
+
module BrowseAi
|
|
4
|
+
autoload :Client, 'browse_ai/client'
|
|
5
|
+
autoload :DSL, 'browse_ai/dsl'
|
|
6
|
+
autoload :Resources, 'browse_ai/resources'
|
|
7
|
+
autoload :Errors, 'browse_ai/errors'
|
|
8
|
+
autoload :Utils, 'browse_ai/utils'
|
|
9
|
+
|
|
10
|
+
class << self
|
|
11
|
+
# @return [String]
|
|
12
|
+
attr_accessor :api_key
|
|
13
|
+
attr_accessor :url, :logger
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
self.url = 'https://api.browse.ai/v2/'
|
|
17
|
+
|
|
18
|
+
module_function
|
|
19
|
+
|
|
20
|
+
# @return [BrowseAi::Client]
|
|
21
|
+
def client
|
|
22
|
+
@client ||= Client.new(BrowseAi.api_key, BrowseAi.url)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe BrowseAi::DSL::Monitors do
|
|
4
|
+
def robot_id
|
|
5
|
+
VCR.use_cassette('get_robots') do
|
|
6
|
+
robots = BrowseAi.client.get_robots
|
|
7
|
+
robots.first['id']
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# GET /monitors
|
|
12
|
+
describe '#get_monitors' do
|
|
13
|
+
it 'returns an array of monitors' do
|
|
14
|
+
VCR.use_cassette('get_monitors') do
|
|
15
|
+
monitors = BrowseAi.client.get_monitors(robot_id:)
|
|
16
|
+
expect(monitors).to be_a(Array)
|
|
17
|
+
expect(monitors.first).to be_a(Monitor)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# GET /monitors/{id}
|
|
23
|
+
describe '#get_monitor' do
|
|
24
|
+
it 'returns an monitor' do
|
|
25
|
+
id = VCR.use_cassette('get_monitors') do
|
|
26
|
+
monitors = BrowseAi.client.get_monitors(robot_id:)
|
|
27
|
+
monitors.first['id']
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
VCR.use_cassette('get_monitor') do
|
|
31
|
+
expect(BrowseAi.client.get_monitor(robot_id:, id:)).to be_a(Monitor)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe BrowseAi::DSL::Robots do
|
|
4
|
+
# GET /robots
|
|
5
|
+
describe '#get_robots' do
|
|
6
|
+
it 'returns an array of robots' do
|
|
7
|
+
VCR.use_cassette('get_robots') do
|
|
8
|
+
robots = BrowseAi.client.get_robots
|
|
9
|
+
expect(robots).to be_a(Array)
|
|
10
|
+
expect(robots.first).to be_a(Robot)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# GET /robots/{id}
|
|
16
|
+
describe '#get_robot' do
|
|
17
|
+
it 'returns an robot' do
|
|
18
|
+
id = VCR.use_cassette('get_robots') do
|
|
19
|
+
robots = BrowseAi.client.get_robots
|
|
20
|
+
robots.first['id']
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
VCR.use_cassette('get_robot') do
|
|
24
|
+
expect(BrowseAi.client.get_robot(id:)).to be_a(Robot)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe BrowseAi::DSL::Tasks do
|
|
4
|
+
def robot_id
|
|
5
|
+
VCR.use_cassette('get_robots') do
|
|
6
|
+
robots = BrowseAi.client.get_robots
|
|
7
|
+
robots.first['id']
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# GET /tasks
|
|
12
|
+
describe '#get_tasks' do
|
|
13
|
+
it 'returns an array of tasks' do
|
|
14
|
+
VCR.use_cassette('get_tasks') do
|
|
15
|
+
tasks = BrowseAi.client.get_tasks(robot_id:)
|
|
16
|
+
expect(tasks).to be_a(Array)
|
|
17
|
+
expect(tasks.first).to be_a(Task)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# GET /tasks/{id}
|
|
23
|
+
describe '#get_task' do
|
|
24
|
+
it 'returns an task' do
|
|
25
|
+
id = VCR.use_cassette('get_tasks') do
|
|
26
|
+
tasks = BrowseAi.client.get_tasks(robot_id:)
|
|
27
|
+
tasks.first['id']
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
VCR.use_cassette('get_task') do
|
|
31
|
+
expect(BrowseAi.client.get_task(robot_id:, id:)).to be_a(Task)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe BrowseAi::DSL::Webhooks do
|
|
4
|
+
def robot_id
|
|
5
|
+
VCR.use_cassette('get_robots') do
|
|
6
|
+
robots = BrowseAi.client.get_robots
|
|
7
|
+
robots.first['id']
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# GET /webhooks
|
|
12
|
+
describe '#get_webhooks' do
|
|
13
|
+
it 'returns an array of webhooks' do
|
|
14
|
+
VCR.use_cassette('get_webhooks') do
|
|
15
|
+
webhooks = BrowseAi.client.get_webhooks(robot_id:)
|
|
16
|
+
expect(webhooks).to be_a(Array)
|
|
17
|
+
expect(webhooks.first).to be_a(Webhook)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
data/spec/spec_helper.rb
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
require 'webmock/rspec'
|
|
2
|
+
require 'browse_ai'
|
|
3
|
+
require 'vcr'
|
|
4
|
+
include BrowseAi::Resources
|
|
5
|
+
|
|
6
|
+
APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
|
7
|
+
cnf = YAML.load_file(File.join(APP_ROOT, 'config/gem_secret.yml'))
|
|
8
|
+
browse_ai_api_key = cnf['browse_ai_api_key']
|
|
9
|
+
|
|
10
|
+
VCR.configure do |c|
|
|
11
|
+
c.cassette_library_dir = 'spec/fixtures/vcr_cassettes'
|
|
12
|
+
c.hook_into :webmock
|
|
13
|
+
c.filter_sensitive_data('<BROWSE_AI_API_KEY>') { browse_ai_api_key }
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
RSpec.configure do |config|
|
|
17
|
+
config.before do
|
|
18
|
+
BrowseAi.api_key = browse_ai_api_key
|
|
19
|
+
end
|
|
20
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: browse_ai
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- David Iorns
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 2025-06-25 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: activesupport
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - "~>"
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '8.0'
|
|
19
|
+
- - ">="
|
|
20
|
+
- !ruby/object:Gem::Version
|
|
21
|
+
version: 8.0.2
|
|
22
|
+
type: :runtime
|
|
23
|
+
prerelease: false
|
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
25
|
+
requirements:
|
|
26
|
+
- - "~>"
|
|
27
|
+
- !ruby/object:Gem::Version
|
|
28
|
+
version: '8.0'
|
|
29
|
+
- - ">="
|
|
30
|
+
- !ruby/object:Gem::Version
|
|
31
|
+
version: 8.0.2
|
|
32
|
+
- !ruby/object:Gem::Dependency
|
|
33
|
+
name: faraday
|
|
34
|
+
requirement: !ruby/object:Gem::Requirement
|
|
35
|
+
requirements:
|
|
36
|
+
- - "~>"
|
|
37
|
+
- !ruby/object:Gem::Version
|
|
38
|
+
version: '2.13'
|
|
39
|
+
- - ">="
|
|
40
|
+
- !ruby/object:Gem::Version
|
|
41
|
+
version: 2.13.1
|
|
42
|
+
type: :runtime
|
|
43
|
+
prerelease: false
|
|
44
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
45
|
+
requirements:
|
|
46
|
+
- - "~>"
|
|
47
|
+
- !ruby/object:Gem::Version
|
|
48
|
+
version: '2.13'
|
|
49
|
+
- - ">="
|
|
50
|
+
- !ruby/object:Gem::Version
|
|
51
|
+
version: 2.13.1
|
|
52
|
+
- !ruby/object:Gem::Dependency
|
|
53
|
+
name: faraday-multipart
|
|
54
|
+
requirement: !ruby/object:Gem::Requirement
|
|
55
|
+
requirements:
|
|
56
|
+
- - "~>"
|
|
57
|
+
- !ruby/object:Gem::Version
|
|
58
|
+
version: '1.1'
|
|
59
|
+
type: :runtime
|
|
60
|
+
prerelease: false
|
|
61
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
62
|
+
requirements:
|
|
63
|
+
- - "~>"
|
|
64
|
+
- !ruby/object:Gem::Version
|
|
65
|
+
version: '1.1'
|
|
66
|
+
- !ruby/object:Gem::Dependency
|
|
67
|
+
name: mime-types
|
|
68
|
+
requirement: !ruby/object:Gem::Requirement
|
|
69
|
+
requirements:
|
|
70
|
+
- - "~>"
|
|
71
|
+
- !ruby/object:Gem::Version
|
|
72
|
+
version: '3.7'
|
|
73
|
+
type: :runtime
|
|
74
|
+
prerelease: false
|
|
75
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
76
|
+
requirements:
|
|
77
|
+
- - "~>"
|
|
78
|
+
- !ruby/object:Gem::Version
|
|
79
|
+
version: '3.7'
|
|
80
|
+
- !ruby/object:Gem::Dependency
|
|
81
|
+
name: bundler
|
|
82
|
+
requirement: !ruby/object:Gem::Requirement
|
|
83
|
+
requirements:
|
|
84
|
+
- - "~>"
|
|
85
|
+
- !ruby/object:Gem::Version
|
|
86
|
+
version: '2.6'
|
|
87
|
+
- - ">="
|
|
88
|
+
- !ruby/object:Gem::Version
|
|
89
|
+
version: 2.6.9
|
|
90
|
+
type: :development
|
|
91
|
+
prerelease: false
|
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
93
|
+
requirements:
|
|
94
|
+
- - "~>"
|
|
95
|
+
- !ruby/object:Gem::Version
|
|
96
|
+
version: '2.6'
|
|
97
|
+
- - ">="
|
|
98
|
+
- !ruby/object:Gem::Version
|
|
99
|
+
version: 2.6.9
|
|
100
|
+
- !ruby/object:Gem::Dependency
|
|
101
|
+
name: rake
|
|
102
|
+
requirement: !ruby/object:Gem::Requirement
|
|
103
|
+
requirements:
|
|
104
|
+
- - "~>"
|
|
105
|
+
- !ruby/object:Gem::Version
|
|
106
|
+
version: '13.3'
|
|
107
|
+
type: :development
|
|
108
|
+
prerelease: false
|
|
109
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
110
|
+
requirements:
|
|
111
|
+
- - "~>"
|
|
112
|
+
- !ruby/object:Gem::Version
|
|
113
|
+
version: '13.3'
|
|
114
|
+
- !ruby/object:Gem::Dependency
|
|
115
|
+
name: rspec
|
|
116
|
+
requirement: !ruby/object:Gem::Requirement
|
|
117
|
+
requirements:
|
|
118
|
+
- - "~>"
|
|
119
|
+
- !ruby/object:Gem::Version
|
|
120
|
+
version: '3.13'
|
|
121
|
+
- - ">="
|
|
122
|
+
- !ruby/object:Gem::Version
|
|
123
|
+
version: 3.13.1
|
|
124
|
+
type: :development
|
|
125
|
+
prerelease: false
|
|
126
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
127
|
+
requirements:
|
|
128
|
+
- - "~>"
|
|
129
|
+
- !ruby/object:Gem::Version
|
|
130
|
+
version: '3.13'
|
|
131
|
+
- - ">="
|
|
132
|
+
- !ruby/object:Gem::Version
|
|
133
|
+
version: 3.13.1
|
|
134
|
+
- !ruby/object:Gem::Dependency
|
|
135
|
+
name: vcr
|
|
136
|
+
requirement: !ruby/object:Gem::Requirement
|
|
137
|
+
requirements:
|
|
138
|
+
- - "~>"
|
|
139
|
+
- !ruby/object:Gem::Version
|
|
140
|
+
version: '6.3'
|
|
141
|
+
- - ">="
|
|
142
|
+
- !ruby/object:Gem::Version
|
|
143
|
+
version: 6.3.1
|
|
144
|
+
type: :development
|
|
145
|
+
prerelease: false
|
|
146
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
147
|
+
requirements:
|
|
148
|
+
- - "~>"
|
|
149
|
+
- !ruby/object:Gem::Version
|
|
150
|
+
version: '6.3'
|
|
151
|
+
- - ">="
|
|
152
|
+
- !ruby/object:Gem::Version
|
|
153
|
+
version: 6.3.1
|
|
154
|
+
- !ruby/object:Gem::Dependency
|
|
155
|
+
name: webmock
|
|
156
|
+
requirement: !ruby/object:Gem::Requirement
|
|
157
|
+
requirements:
|
|
158
|
+
- - "~>"
|
|
159
|
+
- !ruby/object:Gem::Version
|
|
160
|
+
version: '3.25'
|
|
161
|
+
- - ">="
|
|
162
|
+
- !ruby/object:Gem::Version
|
|
163
|
+
version: 3.25.1
|
|
164
|
+
type: :development
|
|
165
|
+
prerelease: false
|
|
166
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
167
|
+
requirements:
|
|
168
|
+
- - "~>"
|
|
169
|
+
- !ruby/object:Gem::Version
|
|
170
|
+
version: '3.25'
|
|
171
|
+
- - ">="
|
|
172
|
+
- !ruby/object:Gem::Version
|
|
173
|
+
version: 3.25.1
|
|
174
|
+
email:
|
|
175
|
+
- david.iorns@gmail.com
|
|
176
|
+
executables: []
|
|
177
|
+
extensions: []
|
|
178
|
+
extra_rdoc_files: []
|
|
179
|
+
files:
|
|
180
|
+
- ".DS_Store"
|
|
181
|
+
- ".github/dependabot.yml"
|
|
182
|
+
- ".gitignore"
|
|
183
|
+
- Gemfile
|
|
184
|
+
- LICENSE.txt
|
|
185
|
+
- README.md
|
|
186
|
+
- Rakefile
|
|
187
|
+
- browse_ai.gemspec
|
|
188
|
+
- config/gem_secret.yml.example
|
|
189
|
+
- lib/.DS_Store
|
|
190
|
+
- lib/browse_ai.rb
|
|
191
|
+
- lib/browse_ai/client.rb
|
|
192
|
+
- lib/browse_ai/dsl.rb
|
|
193
|
+
- lib/browse_ai/dsl/monitors.rb
|
|
194
|
+
- lib/browse_ai/dsl/robots.rb
|
|
195
|
+
- lib/browse_ai/dsl/tasks.rb
|
|
196
|
+
- lib/browse_ai/dsl/webhooks.rb
|
|
197
|
+
- lib/browse_ai/errors.rb
|
|
198
|
+
- lib/browse_ai/errors/client_error.rb
|
|
199
|
+
- lib/browse_ai/errors/resource_not_found_error.rb
|
|
200
|
+
- lib/browse_ai/resources.rb
|
|
201
|
+
- lib/browse_ai/resources/monitor.rb
|
|
202
|
+
- lib/browse_ai/resources/object.rb
|
|
203
|
+
- lib/browse_ai/resources/object/attributes.rb
|
|
204
|
+
- lib/browse_ai/resources/object/serializers.rb
|
|
205
|
+
- lib/browse_ai/resources/robot.rb
|
|
206
|
+
- lib/browse_ai/resources/task.rb
|
|
207
|
+
- lib/browse_ai/resources/webhook.rb
|
|
208
|
+
- lib/browse_ai/utils.rb
|
|
209
|
+
- lib/browse_ai/utils/url_helper.rb
|
|
210
|
+
- lib/browse_ai/version.rb
|
|
211
|
+
- spec/browse_ai/client_spec.rb
|
|
212
|
+
- spec/browse_ai/dsl/monitors_spec.rb
|
|
213
|
+
- spec/browse_ai/dsl/robots_spec.rb
|
|
214
|
+
- spec/browse_ai/dsl/tasks_spec.rb
|
|
215
|
+
- spec/browse_ai/dsl/webhooks_spec.rb
|
|
216
|
+
- spec/spec_helper.rb
|
|
217
|
+
homepage: https://www.browse.ai/
|
|
218
|
+
licenses:
|
|
219
|
+
- MIT
|
|
220
|
+
metadata: {}
|
|
221
|
+
rdoc_options: []
|
|
222
|
+
require_paths:
|
|
223
|
+
- lib
|
|
224
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
225
|
+
requirements:
|
|
226
|
+
- - ">="
|
|
227
|
+
- !ruby/object:Gem::Version
|
|
228
|
+
version: 3.0.0
|
|
229
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
230
|
+
requirements:
|
|
231
|
+
- - ">="
|
|
232
|
+
- !ruby/object:Gem::Version
|
|
233
|
+
version: '0'
|
|
234
|
+
requirements: []
|
|
235
|
+
rubygems_version: 3.6.6
|
|
236
|
+
specification_version: 4
|
|
237
|
+
summary: A Ruby wrapper for the Browse AI API. https://www.browse.ai/docs/api/v2
|
|
238
|
+
test_files:
|
|
239
|
+
- spec/browse_ai/client_spec.rb
|
|
240
|
+
- spec/browse_ai/dsl/monitors_spec.rb
|
|
241
|
+
- spec/browse_ai/dsl/robots_spec.rb
|
|
242
|
+
- spec/browse_ai/dsl/tasks_spec.rb
|
|
243
|
+
- spec/browse_ai/dsl/webhooks_spec.rb
|
|
244
|
+
- spec/spec_helper.rb
|