Dex 0.1.3 → 0.2.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/db.db +0 -0
- data/lib/Dex.rb +85 -41
- data/lib/Dex/version.rb +1 -1
- data/spec/Dex.rb +92 -68
- data/spec/libs/main.rb +17 -11
- metadata +3 -2
data/db.db
ADDED
File without changes
|
data/lib/Dex.rb
CHANGED
@@ -3,62 +3,101 @@ require 'sequel'
|
|
3
3
|
|
4
4
|
class Dex
|
5
5
|
|
6
|
-
|
7
|
-
|
6
|
+
module DEFAULT
|
7
|
+
DB_NAME = "/tmp/dex_exceptions.db"
|
8
|
+
TABLE_NAME = :dex_exceptions
|
9
|
+
RACK_DIR = File.join( File.dirname( __FILE__ ) , "/Dex/Rack" )
|
8
10
|
end
|
9
11
|
|
10
|
-
def self.
|
11
|
-
"
|
12
|
-
end
|
13
|
-
|
14
|
-
def self.default_table
|
15
|
-
:dex_exceptions
|
12
|
+
def self.default k
|
13
|
+
eval "#{self}::DEFAULT::#{k.to_s.upcase}"
|
16
14
|
end
|
17
15
|
|
18
16
|
module DSL
|
19
17
|
|
20
|
-
|
21
|
-
|
22
|
-
|
18
|
+
attr_reader :table
|
19
|
+
|
20
|
+
def default *args
|
21
|
+
Dex.default(*args)
|
23
22
|
end
|
24
23
|
|
25
|
-
def
|
26
|
-
|
27
|
-
|
28
|
-
|
24
|
+
def db *args
|
25
|
+
return @db if args.empty? && instance_variable_defined?(:@db)
|
26
|
+
|
27
|
+
case args.size
|
28
|
+
|
29
|
+
when 0
|
30
|
+
name = default :db_name
|
31
|
+
table = default :table_name
|
32
|
+
|
33
|
+
when 1
|
34
|
+
name = args[0]
|
35
|
+
table = default :table_name
|
36
|
+
|
37
|
+
when 2
|
38
|
+
name = args[0]
|
39
|
+
table = args[1]
|
40
|
+
|
41
|
+
else
|
42
|
+
args.shift
|
43
|
+
args.shift
|
44
|
+
raise ArgumentError, "Unknown arguments: #{args.inspect}"
|
45
|
+
|
46
|
+
end # === case
|
47
|
+
|
48
|
+
@db = Sequel.sqlite(name)
|
49
|
+
@table = @db[table.to_sym]
|
50
|
+
|
51
|
+
@db.create_table?(table_name) {
|
52
|
+
|
53
|
+
primary_key :id
|
54
|
+
String :message
|
55
|
+
String :exception
|
56
|
+
Text :backtrace
|
57
|
+
Integer :status
|
58
|
+
DateTime :created_at
|
59
|
+
|
60
|
+
}
|
61
|
+
|
62
|
+
@db
|
63
|
+
end # === def db
|
64
|
+
|
65
|
+
def db_name
|
66
|
+
db.opts[:database] || default(:db_name)
|
67
|
+
end
|
68
|
+
|
69
|
+
def table_name
|
70
|
+
return nil unless table
|
71
|
+
table.opts[:from].first
|
29
72
|
end
|
30
73
|
|
31
|
-
def
|
32
|
-
|
33
|
-
|
34
|
-
db_file name
|
35
|
-
db = Sequel.sqlite db_file
|
36
|
-
db.create_table?(Dex.default_table) {
|
37
|
-
|
38
|
-
primary_key :id
|
39
|
-
String :message
|
40
|
-
String :exception
|
41
|
-
Text :backtrace
|
42
|
-
Integer :status
|
43
|
-
DateTime :created_at
|
44
|
-
|
45
|
-
}
|
46
|
-
db
|
47
|
-
end
|
48
|
-
@table = nil
|
49
|
-
end
|
74
|
+
def table_exists?
|
75
|
+
db.table_exists?(table_name)
|
76
|
+
end
|
50
77
|
|
51
|
-
|
78
|
+
def fields
|
79
|
+
db.schema(table_name).map(&:first)
|
52
80
|
end
|
53
81
|
|
54
|
-
def
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
@table ||= table(:dex_exceptions)
|
82
|
+
def keep_only n = 250
|
83
|
+
c = table.count
|
84
|
+
return false unless c > 250
|
85
|
+
table.filter( :id=> Dex.table.select(:id).limit( c-n ) ).delete
|
59
86
|
end
|
60
87
|
|
61
|
-
def insert e
|
88
|
+
def insert e, other=Hash[]
|
89
|
+
unless other.keys.empty?
|
90
|
+
keys=other.keys.map(&:to_sym)
|
91
|
+
new_keys = keys - fields
|
92
|
+
unless new_keys.empty?
|
93
|
+
db.alter_table table_name do
|
94
|
+
new_keys.each { |k|
|
95
|
+
add_column k, :string
|
96
|
+
}
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
62
101
|
table.insert \
|
63
102
|
:message => e.message, \
|
64
103
|
:exception => e.exception.class.name, \
|
@@ -67,6 +106,11 @@ class Dex
|
|
67
106
|
:created_at => Time.now.utc
|
68
107
|
end
|
69
108
|
|
109
|
+
def remove_field name
|
110
|
+
db.alter_table table_name do
|
111
|
+
drop_column name
|
112
|
+
end
|
113
|
+
end
|
70
114
|
def recent n = 10
|
71
115
|
ds = table.reverse_order(:created_at, :id).limit(n)
|
72
116
|
if n < 2
|
data/lib/Dex/version.rb
CHANGED
data/spec/Dex.rb
CHANGED
@@ -1,12 +1,18 @@
|
|
1
1
|
|
2
2
|
describe "Dex :db" do
|
3
|
-
|
4
|
-
|
3
|
+
|
4
|
+
behaves_like 'Test DB'
|
5
|
+
|
6
|
+
it "converts String table name to Symbol. (Sequel table name compatibility.)" do
|
7
|
+
t = new_dex
|
8
|
+
t.db "/tmp/db.test.1.db", "my_table"
|
9
|
+
t.table_name.should == "my_table".to_sym
|
10
|
+
end
|
11
|
+
|
12
|
+
it "sets table name to specified value" do
|
5
13
|
t = new_dex
|
6
|
-
t.db "/tmp/db.test.1.db"
|
7
|
-
t.
|
8
|
-
t.db "/tmp/db.test.2.db"
|
9
|
-
t.instance_eval { @table }.should.be == nil
|
14
|
+
t.db "/tmp/db.test.1.db", :my_new_table
|
15
|
+
t.table_name.should == :my_new_table
|
10
16
|
end
|
11
17
|
|
12
18
|
it "allows file names with underscores: my_log.db" do
|
@@ -36,102 +42,120 @@ describe "Dex :db" do
|
|
36
42
|
end # === Dex :db
|
37
43
|
|
38
44
|
describe "Dex :recent" do
|
39
|
-
|
45
|
+
|
46
|
+
behaves_like 'Test DB'
|
47
|
+
|
40
48
|
it "returns first result if n = 1" do
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
Dex.recent( 1 )[:message].should == "One"
|
45
|
-
}
|
49
|
+
e = except "One"
|
50
|
+
Dex.insert e
|
51
|
+
Dex.recent( 1 )[:message].should == "One"
|
46
52
|
end
|
47
53
|
|
48
54
|
it "returns a dataset if n > 1" do
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
r.to_a.size.should == 2
|
56
|
-
}
|
55
|
+
e1 = except "One"
|
56
|
+
e2 = except "Two"
|
57
|
+
Dex.insert e1
|
58
|
+
Dex.insert e2
|
59
|
+
r = Dex.recent
|
60
|
+
r.to_a.size.should == 2
|
57
61
|
end
|
58
|
-
|
62
|
+
|
59
63
|
it "returns results in reverse order" do
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
Dex.recent.map { |d| d[:message] }.should == %w{ 2 1 0 }
|
65
|
-
}
|
64
|
+
3.times do |i|
|
65
|
+
Dex.insert( except i.to_s )
|
66
|
+
end
|
67
|
+
Dex.recent.map { |d| d[:message] }.should == %w{ 2 1 0 }
|
66
68
|
end
|
67
69
|
|
68
70
|
end # === Dex :recent
|
69
71
|
|
70
72
|
|
71
73
|
describe "Dex :insert" do
|
72
|
-
|
74
|
+
|
75
|
+
behaves_like 'Test DB'
|
76
|
+
|
73
77
|
it "saves message of exception" do
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
Dex.recent( 1 )[:message].should == e.message
|
78
|
-
}
|
78
|
+
e = except "My Name"
|
79
|
+
Dex.insert e
|
80
|
+
Dex.recent( 1 )[:message].should == e.message
|
79
81
|
end
|
80
|
-
|
82
|
+
|
81
83
|
it "returns id of new record" do
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
Dex.filter(:id=>id).first[:message].should == "My record"
|
86
|
-
}
|
84
|
+
e = except "My record"
|
85
|
+
id = Dex.insert(e)
|
86
|
+
Dex.filter(:id=>id).first[:message].should == "My record"
|
87
87
|
end
|
88
88
|
|
89
89
|
it "sets :status to 0 by default" do
|
90
|
-
|
91
|
-
|
92
|
-
|
90
|
+
id = Dex.insert(except "Another record")
|
91
|
+
Dex.filter(:id=>id).first[:status].should == 0
|
92
|
+
end
|
93
|
+
|
94
|
+
it "adds new fields to table" do
|
95
|
+
dex = new_dex "new_fields"
|
96
|
+
dex.db.transaction(:rollback=>:always) {
|
97
|
+
dex.insert( except("New fields"), :fd1=>"field 1", :fd2=>"field 2" )
|
98
|
+
fields = dex.db.schema(dex.table_name).map(&:first)
|
99
|
+
fields.should.include :fd1
|
100
|
+
fields.should.include :fd2
|
93
101
|
}
|
94
102
|
end
|
103
|
+
|
95
104
|
end # === Dex :insert
|
96
105
|
|
97
106
|
describe "Dex :keep_only" do
|
98
|
-
|
107
|
+
|
108
|
+
behaves_like 'Test DB'
|
109
|
+
|
99
110
|
it "deletes oldest records leaving most recent 250" do
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
Dex.recent(1)[:message].should == '299'
|
105
|
-
}
|
111
|
+
300.times { |i| Dex.insert except(i.to_s) }
|
112
|
+
Dex.keep_only
|
113
|
+
Dex.count.should == 250
|
114
|
+
Dex.recent(1)[:message].should == '299'
|
106
115
|
end
|
107
|
-
|
116
|
+
|
108
117
|
it "accepts a limit argument" do
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
Dex.table.count.should == 12
|
113
|
-
}
|
118
|
+
300.times { |i| Dex.insert except(i.to_s) }
|
119
|
+
Dex.keep_only 12
|
120
|
+
Dex.table.count.should == 12
|
114
121
|
end
|
115
122
|
|
116
123
|
end # === Dex :keep_only
|
117
124
|
|
118
|
-
describe "Dex missing_method" do
|
119
|
-
|
125
|
+
describe "Dex :missing_method" do
|
126
|
+
|
127
|
+
behaves_like 'Test DB'
|
128
|
+
|
120
129
|
it "sends message to :table if it responds to message" do
|
121
|
-
|
122
|
-
|
123
|
-
Dex.count.should == Dex.table.count
|
124
|
-
}
|
130
|
+
(rand 10).times { |i| Dex.insert except(i.to_s) }
|
131
|
+
Dex.count.should == Dex.table.count
|
125
132
|
end
|
126
133
|
|
127
134
|
it "raises super :missing_method if :table does not respond to message" do
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
}.message.should.match %r!undefined method `xyz' for Dex:Class!
|
133
|
-
}
|
135
|
+
(rand 10).times { |i| Dex.insert except(i.to_s) }
|
136
|
+
should.raise(NoMethodError) {
|
137
|
+
Dex.xyz
|
138
|
+
}.message.should.match %r!undefined method `xyz' for Dex:Class!
|
134
139
|
end
|
135
|
-
|
140
|
+
|
136
141
|
end # === Dex missing_method
|
137
142
|
|
143
|
+
describe "Dex :remove_field" do
|
144
|
+
|
145
|
+
before {
|
146
|
+
@dex = new_dex(':memory:')
|
147
|
+
@dex.table.delete
|
148
|
+
}
|
149
|
+
|
150
|
+
it "removes specified field" do
|
151
|
+
orig = @dex.fields
|
152
|
+
name = :my_field
|
153
|
+
@dex.insert except("remve field"), name => '---'
|
154
|
+
@dex.fields.should.include name
|
155
|
+
@dex.remove_field name
|
156
|
+
|
157
|
+
@dex.fields.should.not.include name
|
158
|
+
end
|
159
|
+
|
160
|
+
end # === Dex :remove_field
|
161
|
+
|
data/spec/libs/main.rb
CHANGED
@@ -18,21 +18,18 @@ Bacon.summary_on_exit
|
|
18
18
|
require 'Bacon_Colored'
|
19
19
|
require 'pry'
|
20
20
|
require 'Exit_0'
|
21
|
-
|
22
21
|
require 'Dex'
|
23
22
|
|
24
|
-
|
25
|
-
Dex.db "/tmp/dex.test.db"
|
23
|
+
Dex.db ":memory:"
|
26
24
|
|
27
|
-
def
|
28
|
-
Dex.db.transaction(:rollback=>:always) {
|
29
|
-
yield
|
30
|
-
}
|
31
|
-
end
|
32
|
-
|
33
|
-
def new_dex
|
25
|
+
def new_dex db = nil
|
34
26
|
@t ||= Class.new { include Dex::DSL }
|
35
|
-
@t.new
|
27
|
+
dex = @t.new
|
28
|
+
if db
|
29
|
+
dex.db(db[':'] ? db : File.join("/tmp", db) )
|
30
|
+
end
|
31
|
+
|
32
|
+
dex
|
36
33
|
end
|
37
34
|
|
38
35
|
def except name
|
@@ -46,6 +43,15 @@ def except name
|
|
46
43
|
end
|
47
44
|
|
48
45
|
|
46
|
+
shared "Test DB" do
|
47
|
+
|
48
|
+
before {
|
49
|
+
Dex.table.delete
|
50
|
+
}
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
|
49
55
|
# ======== Include the tests.
|
50
56
|
if ARGV.size > 1 && ARGV[1, ARGV.size - 1].detect { |a| File.exists?(a) }
|
51
57
|
# Do nothing. Bacon grabs the file.
|
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.2.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-05 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bacon
|
@@ -135,6 +135,7 @@ files:
|
|
135
135
|
- Gemfile
|
136
136
|
- README.md
|
137
137
|
- Rakefile
|
138
|
+
- db.db
|
138
139
|
- lib/Dex.rb
|
139
140
|
- lib/Dex/version.rb
|
140
141
|
- spec/Dex.rb
|