Dex 0.1.3 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (6) hide show
  1. data/db.db +0 -0
  2. data/lib/Dex.rb +85 -41
  3. data/lib/Dex/version.rb +1 -1
  4. data/spec/Dex.rb +92 -68
  5. data/spec/libs/main.rb +17 -11
  6. 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
- def self.rack_dir
7
- @rack_dir ||= File.join( File.dirname( __FILE__ ) , "/Dex/Rack_App" )
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.default_db
11
- "/tmp/dex_exceptions.db"
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
- def db_file f = :_R_
21
- return @db_file if f == :_R_
22
- @db_file = f
18
+ attr_reader :table
19
+
20
+ def default *args
21
+ Dex.default(*args)
23
22
  end
24
23
 
25
- def keep_only n = 250
26
- c = table.count
27
- return false unless c > 250
28
- table.filter( :id=> Dex.table.select(:id).limit( c-n ) ).delete
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 db name = :_RETURN_
32
- if name != :_RETURN_
33
- @db = begin
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
- @db ||= db(Dex.default_db)
78
+ def fields
79
+ db.schema(table_name).map(&:first)
52
80
  end
53
81
 
54
- def table name = :_RETURN_
55
- if name != :_RETURN_
56
- @table = db[name]
57
- end
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
@@ -1,3 +1,3 @@
1
1
  class Dex
2
- VERSION = "0.1.3"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -1,12 +1,18 @@
1
1
 
2
2
  describe "Dex :db" do
3
-
4
- it "resets :table to nil after specifying a new Database" do
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.table.count
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
- transact {
42
- e = except "One"
43
- Dex.insert e
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
- transact {
50
- e1 = except "One"
51
- e2 = except "Two"
52
- Dex.insert e1
53
- Dex.insert e2
54
- r = Dex.recent
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
- transact {
61
- 3.times do |i|
62
- Dex.insert( except i.to_s )
63
- end
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
- transact {
75
- e = except "My Name"
76
- Dex.insert e
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
- transact {
83
- e = except "My record"
84
- id = Dex.insert(e)
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
- transact {
91
- id = Dex.insert(except "Another record")
92
- Dex.filter(:id=>id).first[:status].should == 0
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
- transact {
101
- 300.times { |i| Dex.insert except(i.to_s) }
102
- Dex.keep_only
103
- Dex.count.should == 250
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
- transact {
110
- 300.times { |i| Dex.insert except(i.to_s) }
111
- Dex.keep_only 12
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
- transact {
122
- (rand 10).times { |i| Dex.insert except(i.to_s) }
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
- transact {
129
- (rand 10).times { |i| Dex.insert except(i.to_s) }
130
- should.raise(NoMethodError) {
131
- Dex.xyz
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
+
@@ -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
- Exit_0 "rm /tmp/dex.test.db" if File.exists?("/tmp/dex.test.db")
25
- Dex.db "/tmp/dex.test.db"
23
+ Dex.db ":memory:"
26
24
 
27
- def transact
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.1.3
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-04 00:00:00.000000000 Z
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