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.
@@ -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
+
@@ -1,3 +1,3 @@
1
1
  class Dex
2
- VERSION = "0.3.0"
2
+ VERSION = "0.4.0"
3
3
  end
@@ -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 == "One"
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
- 300.times { |i| Dex.insert except(i.to_s) }
150
- Dex.keep_only
151
- Dex.count.should == 250
152
- Dex.recent(1)[:message].should == '299'
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
- 300.times { |i| Dex.insert except(i.to_s) }
157
- Dex.keep_only 12
158
- Dex.table.count.should == 12
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
@@ -1,13 +1,100 @@
1
1
 
2
2
  bins = Dir.glob("bin/*")
3
3
 
4
- unless bins.empty?
5
- describe "permissions of bin/" do
6
- bins.each { |file|
7
- it "should chmod 755 for: #{file}" do
8
- `stat -c %a #{file}`.strip
9
- .should.be == "755"
10
- end
11
- }
12
- end # === permissions of bin/
13
- end # === unless bins.empty?
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
+
@@ -20,7 +20,11 @@ require 'pry'
20
20
  require 'Exit_0'
21
21
  require 'Dex'
22
22
 
23
- Dex.db ":memory:"
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
- raise name
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 dex
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.3.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-08 00:00:00.000000000 Z
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