Dex 0.3.0 → 0.4.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.
- data/Dex.gemspec +4 -0
- data/bin/Dex +155 -0
- data/lib/Dex/version.rb +1 -1
- data/spec/Dex.rb +12 -8
- data/spec/bin.rb +97 -10
- data/spec/libs/main.rb +40 -5
- metadata +69 -3
data/Dex.gemspec
CHANGED
@@ -29,5 +29,9 @@ Gem::Specification.new do |s|
|
|
29
29
|
# Specify any dependencies here; for example:
|
30
30
|
s.add_runtime_dependency 'sqlite3'
|
31
31
|
s.add_runtime_dependency 'sequel'
|
32
|
+
s.add_runtime_dependency 'terminal-table'
|
33
|
+
s.add_runtime_dependency 'chronic_duration'
|
34
|
+
s.add_runtime_dependency 'trollop'
|
35
|
+
s.add_runtime_dependency 'term-ansicolor'
|
32
36
|
|
33
37
|
end
|
data/bin/Dex
ADDED
@@ -0,0 +1,155 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# -*- ruby -*-
|
3
|
+
#
|
4
|
+
|
5
|
+
require "Dex"
|
6
|
+
require 'terminal-table'
|
7
|
+
require 'chronic_duration'
|
8
|
+
require 'trollop'
|
9
|
+
require 'term/ansicolor'
|
10
|
+
include Term::ANSIColor
|
11
|
+
|
12
|
+
module Kernal
|
13
|
+
private
|
14
|
+
|
15
|
+
end # === Kernal
|
16
|
+
|
17
|
+
SUB_COMMANDS = %w{ filter toggle show info delete }
|
18
|
+
STATUS = %w{ r unr both }
|
19
|
+
opts = Trollop::options do
|
20
|
+
opt :db, "Path to database file.", :default=>Dex.default(:db_name).to_s
|
21
|
+
opt :table, "DB table.", :default=>Dex.default(:table_name).to_s
|
22
|
+
opt :action, "Must be in: #{SUB_COMMANDS.join ', '}", :default=>'filter'
|
23
|
+
opt :reverse_order, "Field to reverse order.", :default=>'created_at'
|
24
|
+
opt :limit, "DB limit", :type=>:int
|
25
|
+
opt :offset, "DB limit. If specified, default limit is 1.", :type=>:int
|
26
|
+
opt :status, "Either: #{STATUS.join ', '}", :default=>'unr'
|
27
|
+
opt :toggle, "Equivalent to: --action toggle --offset N", :type=>:int
|
28
|
+
opt :show, "Equivalent to: --action show --offset N", :type=>:int
|
29
|
+
opt :delete, "Equivalent to: --action delete --offset N", :type=>:int
|
30
|
+
opt :backtrace, "Show backtrace. Used for --show. Ignored otherwise." , :default=>false
|
31
|
+
end
|
32
|
+
|
33
|
+
[:toggle, :show, :delete].each { |k|
|
34
|
+
if opts[k]
|
35
|
+
opts[:action] = k.to_s
|
36
|
+
opts[:offset] = opts[k]
|
37
|
+
end
|
38
|
+
}
|
39
|
+
|
40
|
+
|
41
|
+
Trollop::die :status, "must be either: #{STATUS.join ', '}" unless STATUS.include?(opts[:status])
|
42
|
+
Trollop::die :action, "must be either: #{SUB_COMMANDS.join ', '}." unless SUB_COMMANDS.include?(opts[:action])
|
43
|
+
Trollop::die "Unknown options: #{ARGV.inspect}" unless ARGV.empty?
|
44
|
+
|
45
|
+
Dex.db opts[:db], opts[:table]
|
46
|
+
OPTS = opts.dup
|
47
|
+
OPTS.update :ds=> Dex.table
|
48
|
+
|
49
|
+
OPTS[:status]=[0,1] if OPTS[:status]=='both'
|
50
|
+
OPTS[:status]=0 if OPTS[:status]=='unr'
|
51
|
+
OPTS[:status]=1 if OPTS[:status]=='r'
|
52
|
+
(OPTS[:limit] ||=1) if OPTS[:offset]
|
53
|
+
|
54
|
+
def raise_arg v
|
55
|
+
raise ArgumentError, (v.is_a?(Symbol) ? "Unknown argument: #{v.inspect}": v)
|
56
|
+
end
|
57
|
+
|
58
|
+
puts ''
|
59
|
+
|
60
|
+
case OPTS[:action]
|
61
|
+
when 'filter'
|
62
|
+
|
63
|
+
ds = OPTS[:ds].filter( :status=>OPTS[:status] ).reverse_order(OPTS[:reverse_order])
|
64
|
+
|
65
|
+
if OPTS[:limit] || OPTS[:offset]
|
66
|
+
ds = ds.limit(*[OPTS[:limit] || ds.count + 1, OPTS[:offset]].compact)
|
67
|
+
end
|
68
|
+
|
69
|
+
results = []
|
70
|
+
ds_results = ds.to_a
|
71
|
+
ds_results.each_index { |i|
|
72
|
+
h = ds_results[i]
|
73
|
+
offset = ds_results.size - i - 1
|
74
|
+
results << [
|
75
|
+
offset,
|
76
|
+
h[:exception],
|
77
|
+
h[:message],
|
78
|
+
ChronicDuration.output(Time.now.to_i - h[:created_at].to_i, :format=>:short) + " ago",
|
79
|
+
h[:id]
|
80
|
+
]
|
81
|
+
}
|
82
|
+
|
83
|
+
if results.empty?
|
84
|
+
puts "No unresolved exceptions."
|
85
|
+
else
|
86
|
+
puts Terminal::Table.new(:headings=>%w{-o Exception Message Time ID}, :rows=> results)
|
87
|
+
end
|
88
|
+
|
89
|
+
when :toggle.to_s
|
90
|
+
Trollop::die :offset, "must be specified" unless OPTS[:offset]
|
91
|
+
|
92
|
+
r = OPTS[:ds].filter(:status=>OPTS[:status]).order(OPTS[:reverse_order]).limit( 1, OPTS[:offset] ).first
|
93
|
+
|
94
|
+
raise_arg "Record not found." unless r
|
95
|
+
stat = r[:status] == 0 ? 1 : 0
|
96
|
+
OPTS[:ds].filter(:id=>r[:id]).update(:status=>stat)
|
97
|
+
puts "#{r[:id]} => #{stat}"
|
98
|
+
|
99
|
+
when 'delete'
|
100
|
+
r = OPTS[:ds].filter(:status=>OPTS[:status]).reverse_order(OPTS[:reverse_order]).limit( 1, OPTS[:offset]).first
|
101
|
+
Trollop::die "No record found with offset: #{OPTS[:offset]}" unless r
|
102
|
+
OPTS[:ds].filter(:id=>r[:id]).delete
|
103
|
+
puts "Record (id: #{r[:id]}) with offset #{OPTS[:offset]} has been deleted."
|
104
|
+
|
105
|
+
when 'show'
|
106
|
+
r = OPTS[:ds].filter(:status=>OPTS[:status]).reverse_order(OPTS[:reverse_order]).limit( 1, OPTS[:offset]).first
|
107
|
+
raise_args "Record not found with offset: #{OPTS[:offset]}" unless r
|
108
|
+
|
109
|
+
b = r.delete :backtrace
|
110
|
+
|
111
|
+
puts Terminal::Table.new(:rows=>r.to_a)
|
112
|
+
|
113
|
+
if OPTS[:backtrace]
|
114
|
+
puts "Backtrace:"
|
115
|
+
current_line = nil
|
116
|
+
rows = []
|
117
|
+
b.each_line { |l|
|
118
|
+
pieces = l.split(%r!:(\d+):!)
|
119
|
+
line = pieces.shift
|
120
|
+
num = pieces.shift
|
121
|
+
code = pieces.join("")
|
122
|
+
|
123
|
+
if current_line != line
|
124
|
+
rows << [line]
|
125
|
+
current_line = line
|
126
|
+
puts ''
|
127
|
+
puts bold(line.sub(Dir.pwd, '.').sub(File.expand_path('~'), '~'))
|
128
|
+
end
|
129
|
+
|
130
|
+
rows << [num, code]
|
131
|
+
|
132
|
+
puts "#{yellow "#{num}:"} #{code}"
|
133
|
+
}
|
134
|
+
|
135
|
+
puts
|
136
|
+
end
|
137
|
+
|
138
|
+
when 'info'
|
139
|
+
t = [
|
140
|
+
[ :db_name, Dex.db_name ],
|
141
|
+
[ :table_name, Dex.table_name ],
|
142
|
+
[ 'Total:', Dex.count ],
|
143
|
+
[ 'Unresolved:', Dex.filter(:status=>0).count ],
|
144
|
+
[ 'Resolved:' , Dex.filter(:status=>1).count ]
|
145
|
+
]
|
146
|
+
puts Terminal::Table.new(:rows=>t)
|
147
|
+
|
148
|
+
else
|
149
|
+
raise_arg "Unknown action: #{OPTS[:action]}"
|
150
|
+
|
151
|
+
end
|
152
|
+
|
153
|
+
|
154
|
+
|
155
|
+
|
data/lib/Dex/version.rb
CHANGED
data/spec/Dex.rb
CHANGED
@@ -48,7 +48,7 @@ describe "Dex :recent" do
|
|
48
48
|
it "returns first result if n = 1" do
|
49
49
|
e = except "One"
|
50
50
|
Dex.insert e
|
51
|
-
Dex.recent( 1 )[:message].should ==
|
51
|
+
Dex.recent( 1 )[:message].should == e.message
|
52
52
|
end
|
53
53
|
|
54
54
|
it "returns a dataset if n > 1" do
|
@@ -146,16 +146,20 @@ describe "Dex :keep_only" do
|
|
146
146
|
behaves_like 'Test DB'
|
147
147
|
|
148
148
|
it "deletes oldest records leaving most recent 250" do
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
149
|
+
rollback {
|
150
|
+
300.times { |i| Dex.insert except(i.to_s) }
|
151
|
+
Dex.keep_only
|
152
|
+
Dex.count.should == 250
|
153
|
+
Dex.recent(1)[:message].should == '299'
|
154
|
+
}
|
153
155
|
end
|
154
156
|
|
155
157
|
it "accepts a limit argument" do
|
156
|
-
|
157
|
-
|
158
|
-
|
158
|
+
rollback {
|
159
|
+
300.times { |i| Dex.insert except(i.to_s) }
|
160
|
+
Dex.keep_only 12
|
161
|
+
Dex.table.count.should == 12
|
162
|
+
}
|
159
163
|
end
|
160
164
|
|
161
165
|
end # === Dex :keep_only
|
data/spec/bin.rb
CHANGED
@@ -1,13 +1,100 @@
|
|
1
1
|
|
2
2
|
bins = Dir.glob("bin/*")
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
4
|
+
describe "permissions of bin/" do
|
5
|
+
bins.each { |file|
|
6
|
+
it "should chmod 775 for: #{file}" do
|
7
|
+
`stat -c %a #{file}`.strip
|
8
|
+
.should.be == "775"
|
9
|
+
end
|
10
|
+
}
|
11
|
+
end # === permissions of bin/
|
12
|
+
|
13
|
+
|
14
|
+
describe "Dex" do
|
15
|
+
|
16
|
+
it "lists unresolved exceptions" do
|
17
|
+
rollback! do
|
18
|
+
errs = [0,1,2].map { |i|
|
19
|
+
e = except
|
20
|
+
Dex.insert e
|
21
|
+
e
|
22
|
+
}
|
23
|
+
|
24
|
+
o = bin
|
25
|
+
errs.each { |e|
|
26
|
+
o.should.match %r!#{e.exception}!
|
27
|
+
o.should.match %r!#{e.message}!
|
28
|
+
}
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
it "puts a menu number in reversed order" do
|
33
|
+
insert_excepts(3) { |ids, errs|
|
34
|
+
bin.scan( %r!^\|\ +(\d)\ +\|!).flatten
|
35
|
+
.should == %w( 2 1 0)
|
36
|
+
}
|
37
|
+
end
|
38
|
+
|
39
|
+
it "does not list resolved exceptions" do
|
40
|
+
rollback! do
|
41
|
+
|
42
|
+
errs = [0,1,2].map { |i|
|
43
|
+
Dex.insert except, :status => 1
|
44
|
+
}
|
45
|
+
|
46
|
+
bin().should == 'No unresolved exceptions.'
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
end # === dex NAME
|
52
|
+
|
53
|
+
describe "Dex toggle N" do
|
54
|
+
|
55
|
+
it "toggles Nth exception from the bottom" do
|
56
|
+
rollback! do
|
57
|
+
errs = [1,2,3].map { |i| Dex.insert( e = except, :created_at=>Time.parse("2012/0#{i}/0#{i} 01:01:01") ) && e }
|
58
|
+
|
59
|
+
bin "--toggle 0"
|
60
|
+
|
61
|
+
Dex.select(:status).reverse_order(:created_at).to_a.map { |r| r[:status] }
|
62
|
+
.should == [0 , 0 , 1]
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
end # === dex toggle N
|
67
|
+
|
68
|
+
|
69
|
+
describe "Dex --show N" do
|
70
|
+
|
71
|
+
it "displays a single exception" do
|
72
|
+
rollback! do
|
73
|
+
errs = [0,1,2,3].map { |i| Dex.insert(e=except); e }
|
74
|
+
o = bin "--show 1"
|
75
|
+
o.should.match %r!#{Regexp.escape errs[1].message}!
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
it "displays a backtrace with arg: --backtrace" do
|
80
|
+
insert_excepts(4) do |ids, errs|
|
81
|
+
o = bin "--show 1 --backtrace"
|
82
|
+
o.should.match %r!#{Regexp.escape errs[1].backtrace[2].split(':').first.sub(File.expand_path( '.', ''), '')}!
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
end # === Dex --show N
|
87
|
+
|
88
|
+
describe "Dex --delete N" do
|
89
|
+
|
90
|
+
it "deletes exception from database" do
|
91
|
+
rollback! do
|
92
|
+
ids = []
|
93
|
+
errs = [0,1,2,3].map { |i| ids << Dex.insert(e=except); e }
|
94
|
+
o = bin "--delete 1"
|
95
|
+
o.should == "Record (id: #{ids[1]}) with offset 1 has been deleted."
|
96
|
+
Dex.filter(:id=>ids[1]).first.should.be == nil
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end # === Dex --delete N
|
100
|
+
|
data/spec/libs/main.rb
CHANGED
@@ -20,7 +20,11 @@ require 'pry'
|
|
20
20
|
require 'Exit_0'
|
21
21
|
require 'Dex'
|
22
22
|
|
23
|
-
Dex.db "
|
23
|
+
Dex.db "/tmp/dex.db"
|
24
|
+
|
25
|
+
def dex
|
26
|
+
Dex
|
27
|
+
end
|
24
28
|
|
25
29
|
def new_dex db = nil
|
26
30
|
@t ||= Class.new { include Dex::DSL }
|
@@ -32,22 +36,53 @@ def new_dex db = nil
|
|
32
36
|
dex
|
33
37
|
end
|
34
38
|
|
35
|
-
def except name
|
39
|
+
def except name = nil
|
40
|
+
@counter ||= 0
|
41
|
+
name ||= "Error: #{(@counter+=1)}"
|
36
42
|
err = nil
|
37
43
|
begin
|
38
|
-
|
44
|
+
raise ArgumentError, name
|
39
45
|
rescue Object => e
|
40
46
|
err = e
|
41
47
|
end
|
42
48
|
err
|
43
49
|
end
|
44
50
|
|
45
|
-
def rollback
|
46
|
-
dex.db.transaction(:rollback=>:always) {
|
51
|
+
def rollback sequel = nil
|
52
|
+
(sequel || dex).db.transaction(:rollback=>:always) {
|
47
53
|
yield
|
48
54
|
}
|
49
55
|
end
|
50
56
|
|
57
|
+
def rollback!
|
58
|
+
# Dex.db.rollback(:rollback=>:always) {
|
59
|
+
dex.table.delete
|
60
|
+
yield
|
61
|
+
end
|
62
|
+
|
63
|
+
def bin cmd = ""
|
64
|
+
bin_path = File.expand_path(File.dirname(__FILE__) + '/../../bin/Dex')
|
65
|
+
bin_path = "Dex"
|
66
|
+
|
67
|
+
o = `#{bin_path} --db #{dex.db_name} #{cmd} 2>&1`.strip
|
68
|
+
|
69
|
+
if $?.exitstatus != 0
|
70
|
+
raise o
|
71
|
+
end
|
72
|
+
o
|
73
|
+
end
|
74
|
+
|
75
|
+
def insert_excepts n
|
76
|
+
rollback! {
|
77
|
+
ids = []
|
78
|
+
errs = [0,1,2].map { |i|
|
79
|
+
ids << Dex.insert(e=except)
|
80
|
+
e
|
81
|
+
}
|
82
|
+
yield ids, errs
|
83
|
+
}
|
84
|
+
end
|
85
|
+
|
51
86
|
def last dex
|
52
87
|
dex.reverse_order(:id).limit(1).first
|
53
88
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: Dex
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-05-
|
12
|
+
date: 2012-05-11 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bacon
|
@@ -123,10 +123,75 @@ dependencies:
|
|
123
123
|
- - ! '>='
|
124
124
|
- !ruby/object:Gem::Version
|
125
125
|
version: '0'
|
126
|
+
- !ruby/object:Gem::Dependency
|
127
|
+
name: terminal-table
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
129
|
+
none: false
|
130
|
+
requirements:
|
131
|
+
- - ! '>='
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: '0'
|
134
|
+
type: :runtime
|
135
|
+
prerelease: false
|
136
|
+
version_requirements: !ruby/object:Gem::Requirement
|
137
|
+
none: false
|
138
|
+
requirements:
|
139
|
+
- - ! '>='
|
140
|
+
- !ruby/object:Gem::Version
|
141
|
+
version: '0'
|
142
|
+
- !ruby/object:Gem::Dependency
|
143
|
+
name: chronic_duration
|
144
|
+
requirement: !ruby/object:Gem::Requirement
|
145
|
+
none: false
|
146
|
+
requirements:
|
147
|
+
- - ! '>='
|
148
|
+
- !ruby/object:Gem::Version
|
149
|
+
version: '0'
|
150
|
+
type: :runtime
|
151
|
+
prerelease: false
|
152
|
+
version_requirements: !ruby/object:Gem::Requirement
|
153
|
+
none: false
|
154
|
+
requirements:
|
155
|
+
- - ! '>='
|
156
|
+
- !ruby/object:Gem::Version
|
157
|
+
version: '0'
|
158
|
+
- !ruby/object:Gem::Dependency
|
159
|
+
name: trollop
|
160
|
+
requirement: !ruby/object:Gem::Requirement
|
161
|
+
none: false
|
162
|
+
requirements:
|
163
|
+
- - ! '>='
|
164
|
+
- !ruby/object:Gem::Version
|
165
|
+
version: '0'
|
166
|
+
type: :runtime
|
167
|
+
prerelease: false
|
168
|
+
version_requirements: !ruby/object:Gem::Requirement
|
169
|
+
none: false
|
170
|
+
requirements:
|
171
|
+
- - ! '>='
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: '0'
|
174
|
+
- !ruby/object:Gem::Dependency
|
175
|
+
name: term-ansicolor
|
176
|
+
requirement: !ruby/object:Gem::Requirement
|
177
|
+
none: false
|
178
|
+
requirements:
|
179
|
+
- - ! '>='
|
180
|
+
- !ruby/object:Gem::Version
|
181
|
+
version: '0'
|
182
|
+
type: :runtime
|
183
|
+
prerelease: false
|
184
|
+
version_requirements: !ruby/object:Gem::Requirement
|
185
|
+
none: false
|
186
|
+
requirements:
|
187
|
+
- - ! '>='
|
188
|
+
- !ruby/object:Gem::Version
|
189
|
+
version: '0'
|
126
190
|
description: ! "\n A simple function to log errors to sqlite3.\n "
|
127
191
|
email:
|
128
192
|
- i-hate-spam-45671204@mailinator.com
|
129
|
-
executables:
|
193
|
+
executables:
|
194
|
+
- Dex
|
130
195
|
extensions: []
|
131
196
|
extra_rdoc_files: []
|
132
197
|
files:
|
@@ -135,6 +200,7 @@ files:
|
|
135
200
|
- Gemfile
|
136
201
|
- README.md
|
137
202
|
- Rakefile
|
203
|
+
- bin/Dex
|
138
204
|
- db.db
|
139
205
|
- lib/Dex.rb
|
140
206
|
- lib/Dex/version.rb
|