airbox 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -0
- data/Gemfile +5 -0
- data/LICENSE +8 -0
- data/README.md +83 -0
- data/airbox.gemspec +22 -0
- data/lib/airbox.rb +200 -0
- data/lib/airbox/version.rb +3 -0
- metadata +71 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
----------------------------------------------------------------------------
|
2
|
+
"THE BEER-WARE LICENSE" (Revision 42):
|
3
|
+
<anulman@gmail.com> wrote this file. As long as you retain this notice you
|
4
|
+
can do whatever you want with this stuff. If we meet some day, and you think
|
5
|
+
this stuff is worth it, you can buy me a beer in return. --Aidan Nulman
|
6
|
+
----------------------------------------------------------------------------
|
7
|
+
[thanks to phk@FreeBSD.ORG for the license]
|
8
|
+
|
data/README.md
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
airbox
|
2
|
+
======
|
3
|
+
|
4
|
+
ActiveResource extension to easily access and manipulate objects from Airbrake's reporting API.
|
5
|
+
|
6
|
+
----
|
7
|
+
## Usage
|
8
|
+
|
9
|
+
In your app, define Airbox.site & Airbox.auth_token to initialize the extension:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
Airbox.site = "site_url"
|
13
|
+
Airbox.auth_token = "token"
|
14
|
+
```
|
15
|
+
|
16
|
+
(Airbox will automatically scan for airbox.rb in the project's root directory; feel free to stash an initializer anywhere else).
|
17
|
+
|
18
|
+
----
|
19
|
+
Most of the time, you'll want to start with a collection of resources:
|
20
|
+
|
21
|
+
```ruby
|
22
|
+
@resources = Airbox::Group.find :all
|
23
|
+
@resources = @resources.first.notices(:page => 2)
|
24
|
+
@resources = Airbox::Error.all(show_resolved: true)
|
25
|
+
```
|
26
|
+
|
27
|
+
Collections are paginated, with 30 objects per page. Airbox offers convenient ways to access other pages:
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
@p1 = @resources
|
31
|
+
@p2 = @p1.next_page
|
32
|
+
prest = @p2.next_pages
|
33
|
+
```
|
34
|
+
|
35
|
+
While collecting _all_ pages can be done from any page, it's most efficient from the first:
|
36
|
+
```ruby
|
37
|
+
p1all = @p1.all_pages
|
38
|
+
p2all = @p2.all_pages
|
39
|
+
p1all == p2all
|
40
|
+
```
|
41
|
+
|
42
|
+
You can access most related resources through simple object methods:
|
43
|
+
|
44
|
+
```ruby
|
45
|
+
project = Airbox::Project.first
|
46
|
+
errors = project.errors #Will return all errors associated to the project
|
47
|
+
group = errors.first.group #Will return the group object associated to the first error
|
48
|
+
notices = group.notices #Will return the notices associated to the group object
|
49
|
+
```
|
50
|
+
|
51
|
+
Finally, some objects (looking at you, Error and Group::Notice) don't return with full information on collection calls. So sometimes, you need to request the full object:
|
52
|
+
|
53
|
+
```ruby
|
54
|
+
project = Airbox::Project.first
|
55
|
+
errors = project.errors(show_resolved: true)
|
56
|
+
error = errors.first
|
57
|
+
error.request.url #Will error out, since the request object is not
|
58
|
+
available here
|
59
|
+
full_error = error.full_obj
|
60
|
+
full_error.request.url #Will return the URL for the requested error
|
61
|
+
```
|
62
|
+
|
63
|
+
## Resources
|
64
|
+
|
65
|
+
Resources are defined by [Airbrake's API](http://help.airbrake.io/kb/api-2/api-overview). Collections are paginated, with 30 objects per page.
|
66
|
+
|
67
|
+
Valid resources are Project, Error, Group, and Group::Notice.
|
68
|
+
|
69
|
+
## To Do
|
70
|
+
|
71
|
+
This gem is brand new, so there's still work to be done. The current list includes:
|
72
|
+
|
73
|
+
* Write test suite
|
74
|
+
* Move nested resources (e.g. Group::Notice) to use prefix options vs. hard-coded from
|
75
|
+
* Split resource types into their own files
|
76
|
+
* Look for and patch holes in functionality between Airbrake's reporting API and Airbox
|
77
|
+
* Remove ActiveRecord dependency
|
78
|
+
|
79
|
+
All contributions appreciated; just issue a pull request!
|
80
|
+
|
81
|
+
## License
|
82
|
+
|
83
|
+
This gem is distributed as Beerware. Full text in the LICENSE file, but it's yours to do with as you wish (so long as you keep the LICENSE file around). If you like it, and we meet one day, consider buying me a drink.
|
data/airbox.gemspec
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "airbox/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "airbox"
|
7
|
+
s.version = Airbox::VERSION
|
8
|
+
s.authors = ["Aidan Nulman"]
|
9
|
+
s.email = ["anulman@gmail.com"]
|
10
|
+
s.homepage = "https://github.com/anulman/airbox"
|
11
|
+
s.summary = %q{Airbrake's missing "black box"}
|
12
|
+
s.description = %q{ActiveResource extension to easily access and manipulate objects from Airbrake's reporting API.}
|
13
|
+
s.license = "Beerware"
|
14
|
+
s.required_ruby_version = '>= 1.9.0'
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
s.add_dependency('activeresource', '< 4')
|
22
|
+
end
|
data/lib/airbox.rb
ADDED
@@ -0,0 +1,200 @@
|
|
1
|
+
# *************************************************
|
2
|
+
#
|
3
|
+
# USAGE
|
4
|
+
#
|
5
|
+
# *************************************************
|
6
|
+
#
|
7
|
+
# Define Airbox.site & Airbox.auth_token
|
8
|
+
# (Automatically scans for init.rb in same dir)
|
9
|
+
#
|
10
|
+
# *************************************************
|
11
|
+
#
|
12
|
+
# Resources are paginated. You get 30 at a time.
|
13
|
+
#
|
14
|
+
# @resources = Airbox::Group.find :all
|
15
|
+
# @resources = @resources.first.notices(:page => 2)
|
16
|
+
# @resources = Airbox::Error.all(show_resolved: true)
|
17
|
+
#
|
18
|
+
# *************************************************
|
19
|
+
|
20
|
+
require "active_resource"
|
21
|
+
|
22
|
+
module Airbox
|
23
|
+
# Accessor methods for site/auth_token settings
|
24
|
+
# H/T to Instagram gem team for the inspiration
|
25
|
+
def self.site
|
26
|
+
Resource.site
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.site=(site)
|
30
|
+
Resource.site = site
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.auth_token
|
34
|
+
Resource.auth_token
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.auth_token=(tok)
|
38
|
+
Resource.auth_token=(tok)
|
39
|
+
end
|
40
|
+
|
41
|
+
class Resource < ::ActiveResource::Base
|
42
|
+
# Airbrake's API responds with XML objects
|
43
|
+
self.format = ActiveResource::Formats::XmlFormat
|
44
|
+
|
45
|
+
class << self
|
46
|
+
# Store auth_token as class variable
|
47
|
+
def auth_token=(tok)
|
48
|
+
@@auth_token = tok
|
49
|
+
end
|
50
|
+
|
51
|
+
# Before standard ActiveResource::Base.find, prep params for request
|
52
|
+
def find(*arguments)
|
53
|
+
if !site
|
54
|
+
err = "No site defined. Please run Airbox.site = 'site_url'"
|
55
|
+
raise ConfigError, err
|
56
|
+
end
|
57
|
+
arguments = prepare_params(*arguments)
|
58
|
+
super(*arguments)
|
59
|
+
end
|
60
|
+
|
61
|
+
# Move opts (except for "from") into params hash
|
62
|
+
# Add auth_token to params hash
|
63
|
+
def prepare_params(*arguments)
|
64
|
+
if !class_variable_defined?(:@@auth_token)
|
65
|
+
err = "No auth token. Please run Airbox.auth_token = 'token'"
|
66
|
+
raise ConfigError, err
|
67
|
+
end
|
68
|
+
|
69
|
+
opts = arguments.last.is_a?(Hash) ? arguments.pop : {}
|
70
|
+
|
71
|
+
# Store pre-transformed opts in instance var
|
72
|
+
# Later accessed to ensure continuity on paged results
|
73
|
+
@opts = opts.dup
|
74
|
+
|
75
|
+
opts[:params] = add_relevant_opts_to_params(opts.except(:from))
|
76
|
+
opts[:params].merge!(auth_token: @@auth_token)
|
77
|
+
arguments << opts
|
78
|
+
arguments
|
79
|
+
end
|
80
|
+
|
81
|
+
# Method to move opts into params hash
|
82
|
+
def add_relevant_opts_to_params(opts)
|
83
|
+
params = opts[:params] || {}
|
84
|
+
opts.except(:params).each do |k,v|
|
85
|
+
params[k] = v
|
86
|
+
end
|
87
|
+
params
|
88
|
+
end
|
89
|
+
|
90
|
+
# After standard ActiveResource::Base.instantiate_collection,
|
91
|
+
# ensure collection is returned as Airbox::Array for easier use
|
92
|
+
#
|
93
|
+
# TODO - needs update to ActiveResource4 + backwards compatibility
|
94
|
+
# (Currently conforms to ActiveResource 3.2.13 spec)
|
95
|
+
def instantiate_collection(collection, original_params = {})
|
96
|
+
ary = super(collection, original_params)
|
97
|
+
ary = Array.new(ary)
|
98
|
+
ary.opts = @opts
|
99
|
+
ary
|
100
|
+
end
|
101
|
+
|
102
|
+
def ensure_collection(coll)
|
103
|
+
klass = self.class.to_s.split('::').last.downcase
|
104
|
+
if coll.has_key?(klass)
|
105
|
+
coll = coll[klass]
|
106
|
+
end
|
107
|
+
coll
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
# Airbrake project resources
|
113
|
+
class Project < Resource
|
114
|
+
# For some reason, these return as JSON?
|
115
|
+
self.format = ActiveResource::Formats::JsonFormat
|
116
|
+
|
117
|
+
# Return project's errors
|
118
|
+
def errors(opts={})
|
119
|
+
Error.all(opts.merge(project_id: id))
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
# Airbrake error resources
|
124
|
+
class Error < Resource
|
125
|
+
|
126
|
+
# Collect all associated data
|
127
|
+
def full_obj(opts={})
|
128
|
+
self.class.find(id, opts)
|
129
|
+
end
|
130
|
+
|
131
|
+
# Return related group
|
132
|
+
def group(opts={})
|
133
|
+
Group.find(id)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
# Airbrake group resources
|
138
|
+
class Group < Resource
|
139
|
+
|
140
|
+
# Return group's notices
|
141
|
+
def notices(opts={})
|
142
|
+
Notice.all(opts.merge(from: "/groups/#{id}/notices"))
|
143
|
+
end
|
144
|
+
|
145
|
+
# Airbrake notice resources
|
146
|
+
class Notice < Resource
|
147
|
+
|
148
|
+
# Collect all associated data
|
149
|
+
def full_obj(opts={})
|
150
|
+
self.class.find :one, opts.merge(from: "/groups/#{group_id}/notices/#{id}")
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
# Extend Array class for module use
|
156
|
+
# When Airbox returns collections of resources, give them paging methods
|
157
|
+
class Array < ::Array
|
158
|
+
# Store/retrieve query in opts instance variable
|
159
|
+
attr_accessor :opts
|
160
|
+
|
161
|
+
# Return next page of results for current query
|
162
|
+
def next_page
|
163
|
+
@opts ||= {}
|
164
|
+
@opts[:page] ||= 1
|
165
|
+
return first.class.all(@opts.merge(page: @opts[:page] + 1).dup)
|
166
|
+
end
|
167
|
+
|
168
|
+
# Return all future pages of results for current query
|
169
|
+
def next_pages
|
170
|
+
collection = []
|
171
|
+
current = self
|
172
|
+
while(current.count == 30)
|
173
|
+
current = current.next_page
|
174
|
+
collection += current
|
175
|
+
end
|
176
|
+
collection
|
177
|
+
end
|
178
|
+
|
179
|
+
# Return all pages of results for current query
|
180
|
+
def all_pages
|
181
|
+
if !self.opts || self.opts[:page] == 1 || !self.opts[:page]
|
182
|
+
self + self.next_pages
|
183
|
+
else
|
184
|
+
collection = first.class.all(@opts.except(:page))
|
185
|
+
collection + collection.next_pages
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
class ConfigError < ::StandardError
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
# Load init file in same folder
|
195
|
+
# Rescue if no initialization found
|
196
|
+
begin
|
197
|
+
require "./airbox"
|
198
|
+
rescue LoadError
|
199
|
+
end
|
200
|
+
|
metadata
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: airbox
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Aidan Nulman
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-07-13 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: activeresource
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - <
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '4'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - <
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '4'
|
30
|
+
description: ActiveResource extension to easily access and manipulate objects from
|
31
|
+
Airbrake's reporting API.
|
32
|
+
email:
|
33
|
+
- anulman@gmail.com
|
34
|
+
executables: []
|
35
|
+
extensions: []
|
36
|
+
extra_rdoc_files: []
|
37
|
+
files:
|
38
|
+
- .gitignore
|
39
|
+
- Gemfile
|
40
|
+
- LICENSE
|
41
|
+
- README.md
|
42
|
+
- airbox.gemspec
|
43
|
+
- lib/airbox.rb
|
44
|
+
- lib/airbox/version.rb
|
45
|
+
homepage: https://github.com/anulman/airbox
|
46
|
+
licenses:
|
47
|
+
- Beerware
|
48
|
+
post_install_message:
|
49
|
+
rdoc_options: []
|
50
|
+
require_paths:
|
51
|
+
- lib
|
52
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
54
|
+
requirements:
|
55
|
+
- - ! '>='
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: 1.9.0
|
58
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
59
|
+
none: false
|
60
|
+
requirements:
|
61
|
+
- - ! '>='
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: '0'
|
64
|
+
requirements: []
|
65
|
+
rubyforge_project:
|
66
|
+
rubygems_version: 1.8.24
|
67
|
+
signing_key:
|
68
|
+
specification_version: 3
|
69
|
+
summary: Airbrake's missing "black box"
|
70
|
+
test_files: []
|
71
|
+
has_rdoc:
|