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.
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