kit 0.3.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,21 +0,0 @@
1
- The MIT License
2
-
3
- Copyright (c) 2011 Evan Boyd Sosenko
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in
13
- all copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
- THE SOFTWARE.
@@ -1,173 +0,0 @@
1
- # Class to manage individual bits.
2
- class Bit < Kit
3
-
4
- # Exceptions.
5
-
6
- # Raised when element exists but was not expected.
7
- class DuplicateElement < RuntimeError
8
- end
9
-
10
- # Raised when no element exists.
11
- class NoElement < RuntimeError
12
- end
13
-
14
- # Raised when not enough info is given to perform the operation.
15
- class MissingValues < RuntimeError
16
- end
17
-
18
- # Raised when an action runs but fails due to an invalid combination of options.
19
- class InvalidAction < RuntimeError
20
- end
21
-
22
- # Raised when an action runs but encounters a fatal error.
23
- class FailedAction < RuntimeError
24
- end
25
-
26
- attr_reader :id
27
-
28
- # Loads all bit info from database, or attempts to add new bit to database.
29
- # Raises a TypeError if not given an integer or hash.
30
- # @param [Integer, Hash] info id of bit or info for new bit
31
- def initialize info
32
- @id = \
33
- if info.is_a? Integer
34
- info
35
- elsif info.is_a? Hash
36
- info.each do |key, value|
37
- instance_variable_set "@#{key}", value
38
- end
39
- g = @group_name if @group_name
40
- g = @group_id if @group_id
41
- self.group = g, info
42
- insert_new
43
- else
44
- fail TypeError
45
- end
46
- load_info
47
- end
48
-
49
- private
50
-
51
- # Add support fot the dynamic instance variables.
52
- class ::Array
53
- # Makes a hash that maps symbols in the array to instance variable values.
54
- # @param [Object] obj the object with the instance variables to use
55
- # @param [Array] exclude instance variables named in this array as symbols are excluded from the hash
56
- # @return [Hash] mapping of symbols in the array to instance variable values
57
- def hash_ivars obj, exclude = []
58
- h = {}
59
- self.each do |x|
60
- h[x] = obj.instance_variable_get "@#{x}" unless exclude.include? x
61
- end
62
- return h
63
- end
64
- end
65
-
66
- # Set group by name or id.
67
- # @param [Integer, String] group id or info for group
68
- def group= group
69
- @group_id = group if group.is_a? Integer
70
- @group_name = group if group.is_a? String
71
-
72
- if @group_id.nil?
73
- g = @@db.select_info_by_name :groups, [ :rowid ], @group_name
74
- @group_id = if g.nil? then insert_new_group else g[:rowid] end
75
- end
76
- end
77
-
78
- # Inserts a new bit into the database using the availible instance variables.
79
- # Raises a MissingValues if required values are not given.
80
- # Raises a DuplicateElement if a bit with unique values already exists.
81
- def insert_new
82
- uniq = @@unique[:bits].hash_ivars self
83
- uniq.each { |x| fail MissingValues if x.nil? }
84
-
85
- fail DuplicateElement if ( lookup_id uniq ).first
86
-
87
- data = @@info[:bits].hash_ivars self, [ :rowid ]
88
- @@db.insert_info :bits, data
89
- end
90
-
91
- # (see #insert_new)
92
- def insert_new_group
93
- fail MissingValues if @group_name.nil?
94
- fail DuplicateElement if @@db.select_info_by_name :groups, @@unique[:groups], @group_name
95
-
96
- data = @@info[:groups].hash_ivars self, [ :rowid, :name ]
97
- data[:name] = @group_name
98
-
99
- @@db.insert_info :groups, data
100
- end
101
-
102
- # Loads all bit info from the database into instance variables.
103
- def load_info
104
- fail MissingValues if @id.nil?
105
- info = @@db.select_info_by_id :bits, @@info[:bits], @id
106
- fail NoElement unless info
107
-
108
- group_info = @@db.select_info_by_id :groups, @@info[:groups], info[:group_id]
109
- info[:group_name] = group_info[:name]
110
- group_info.delete :rowid
111
- group_info.delete :name
112
-
113
- info.merge! group_info
114
- info.delete :rowid
115
-
116
- info.each do |key, value|
117
- instance_variable_set "@#{key}", value
118
- self.class.send :attr_reader, key
119
- self.class.send :public, key
120
- end
121
- end
122
-
123
- public
124
- # Add a task to the array of pending tasks.
125
- # @param [Hash] task info for task
126
- def queue_task task
127
- @tasks = [] unless @tasks
128
- @tasks << task
129
- end
130
-
131
- # def clear_task task
132
- # action = task[:action]
133
- # id = task[:rowid]
134
- #
135
- # @@db.delete_action_by_id action, id
136
- # end
137
-
138
- # Runs all tasks in the list of pending tasks and returns the status of each run task.
139
- # @return [Hash] key is task id
140
- def run_all
141
- tasks = @tasks
142
- status = {}
143
-
144
- tasks.each do |t|
145
- a = t[:action]
146
- id = t[:rowid]
147
- status[a] ||= {}
148
- begin
149
- @@db.update_action_status a, id, { :status => :running }
150
- self.send a, t
151
- stat = :complete
152
- msg = nil
153
- rescue InvalidAction, FailedAction => e
154
- stat = :failed
155
- msg = "#{e.class}: #{e.message}"
156
- ensure
157
- s = { :status => stat, :message => msg }
158
- status[a].merge! ( { id => s } )
159
- @@db.update_action_status a, id, s
160
- end
161
- end
162
- status
163
- end
164
-
165
- # Finds bit ids that match given criteria.
166
- # @param [Hash] criteria field / value pairs that will be matched against
167
- # @return [Array] bit ids that match criteria
168
- def lookup_id criteria
169
- @@db.select_info_by_criteria :bits, [:rowid], criteria
170
- end
171
-
172
- end
173
-
@@ -1,212 +0,0 @@
1
- require 'sqlite3'
2
-
3
- # Methods to make sqlite3 interation more concise.
4
- module SQLite3Tools
5
-
6
- # Array methods.
7
- class ::Array
8
- # Converts an array of symbols to a string of backquoted strings for use in SELECT statement
9
- # @return [String]
10
- # @example
11
- # a = [ :col_1, :col_2 ]
12
- # a.sqlite3_to_str #=> "`col_1`, `col_2`"
13
- def sqlite3_to_str
14
- self.map { |sym| "`" + sym.to_s + "`" }.join(", ")
15
- end
16
-
17
- # Converts an sqlite3 result array to a hash.
18
- # @param keys [Array]
19
- # @return [Hash]
20
- # @example
21
- # a = [ "val_1", 42 ]
22
- # k = [ :col_1, :col_2 ]
23
- # a.to_hash k #=> { :col_1 => "val_1", :col_2 => 42 }
24
- def to_hash keys
25
- Hash[ *( 0...self.size ).inject( [] ) { |arr, ix| arr.push( keys[ix], self[ix] ) } ]
26
- end
27
- end
28
-
29
- # Integer methods.
30
- class ::Integer
31
- # Generates placeholder string for INSERT statements.
32
- # @return String placeholder
33
- # @example
34
- # 3.make_placeholders #=> "?, ?, ?"
35
- def make_placeholders
36
- n = self - 1
37
- placeholders = "?"
38
- n.times { placeholders << ", ?" }
39
- placeholders
40
- end
41
- end
42
-
43
- # SQLite3 database methods.
44
- class SQLite3::Database
45
- # Selects given columns using given query and converts results to to hashes.
46
- # @param [Array<Symbol>] columns names of columns to select
47
- # @param [String] query sqlite3 query fragment to append to SELECT part of query
48
- # @return [Array<Hash>] results with each row a hash in :col => value form
49
- def select columns, query
50
- result = [];
51
- self.execute "SELECT #{columns.sqlite3_to_str} #{query}" do |row|
52
- result.push row.to_hash columns
53
- end
54
- result
55
- end
56
- end
57
- end
58
-
59
- # Backend abstracts database interactions.
60
- class Backend < Kit
61
-
62
- include SQLite3Tools
63
-
64
- attr_reader :db_paths
65
-
66
- # (see #db_prepare)
67
- def initialize db_paths
68
- db_paths.each do |key, db|
69
- name = File.basename db
70
- dir = File.dirname db
71
- dir = @@config_path unless [ "/", "~" ].include? dir[0]
72
- db_paths[key] = "#{dir}/#{name}"
73
- end
74
-
75
- @db_paths = db_paths
76
-
77
- dbs = db_prepare @db_paths
78
- @info_db = dbs[:info]
79
- @action_db = dbs[:actions]
80
- end
81
-
82
- private
83
- # Loads existing database files or creates new ones with kit database schema
84
- # @param [Hash] db_paths absolute or relitive paths to database files
85
- def db_prepare db_paths
86
-
87
- # Makes kit database schema
88
- # @param [Symbol] type name of database
89
- # @param db [SQLite3::Database] database object to load schema into
90
- def db_initialize type, db
91
- sql = File.read @@kit_path + "/sqlite3_#{type}.sql"
92
- db.execute_batch sql
93
- end
94
-
95
- dbs = {}
96
- db_paths.each do |type, path|
97
- dbs[type] = [ ( File.exists? path ), ( SQLite3::Database.new path ) ]
98
- end
99
-
100
- # Set sqlite3 options here
101
- dbs.each do |type, db|
102
- db[1].type_translation = true
103
- end
104
-
105
- dbs.each do |type, db|
106
- begin
107
- ( db_initialize type, db[1] ) unless db[0]
108
- rescue
109
- File.delete db_paths[type]
110
- end
111
- end
112
-
113
- dbs.each do |type, db|
114
- dbs[type] = db[1]
115
- end
116
-
117
- return dbs
118
-
119
- end
120
-
121
- public
122
-
123
- # Deletes database files.
124
- def delete
125
- @db_paths.each do |key, f|
126
- File.delete f
127
- end
128
- end
129
-
130
- # Gets the row from an info table with the given id.
131
- # @param [Symbol] table what database table to query
132
- # @param [Array] fields list of column names to return
133
- # @param [Integer] id rowid of record to return
134
- # @return [Hash] first matched row with a key for each requested field
135
- def select_info_by_id table, fields, id
136
- info = @info_db.select fields, "FROM `#{table}` WHERE `rowid` = '#{id}'"
137
- info.first
138
- end
139
-
140
- # Gets the rows from an info table with the given name.
141
- # @param table (see #select_info_by_id)
142
- # @param fields (see #select_info_by_id)
143
- # @param [String] name of records to return
144
- # @return (see #select_info_by_id)
145
- def select_info_by_name table, fields, name
146
- info = @info_db.select fields, "FROM `#{table}` WHERE `name` = '#{name}'"
147
- info.first
148
- end
149
-
150
- # Gets the rows from an info table with the given criteria.
151
- # @param table (see #select_info_by_id)
152
- # @param fields (see #select_info_by_id)
153
- # @param [Hash] criteria key / value pairs required to match
154
- # @return [Array] hash for each returned row with a key for each requested field
155
- def select_info_by_criteria table, fields, criteria
156
- q = []
157
- criteria.each do |key, value|
158
- q << "`#{key}` = '#{value}'"
159
- end
160
-
161
- info = @info_db.select fields, "FROM `#{table}` WHERE #{q.join " AND "}"
162
- end
163
-
164
- # Inserts a new row into an info table.
165
- # @param table (see #select_info_by_id)
166
- # @param [Hash] data key / value pairs for new row
167
- # @return [Integer] rowid of new row
168
- def insert_info table, data
169
- @info_db.execute "INSERT INTO #{table} ( `#{data.keys.join "`, `"}` ) VALUES ( #{data.length.make_placeholders} )", data.values
170
- @info_db.last_insert_row_id
171
- end
172
-
173
- # Gets the rows from the action table with given status.
174
- # @param table (see #select_info_by_id)
175
- # @param fields (see #select_info_by_id)
176
- # @param [Symbol] status name of status to match
177
- # @return (see #select_info_by_id)
178
- def select_all_actions_by_status table, fields, status
179
- query = "FROM `#{table}` WHERE `status` = '#{status}'"
180
- rows = @action_db.select fields, query
181
-
182
- rows.map { |t| t.merge ( { :action => table, :status => t[:status].to_sym } ) }
183
- end
184
-
185
- # Inserts a new row into an action table.
186
- # @param (see #insert_info)
187
- # @return (see #insert_info)
188
- def insert_action table, data
189
- data.merge! ( { :status => :pending.to_s, :time => Time.now.to_i } )
190
- @action_db.execute "INSERT INTO #{table} ( `#{data.keys.join "`, `"}` ) VALUES ( #{data.length.make_placeholders} )", data.values
191
- @action_db.last_insert_row_id
192
- end
193
-
194
- # Updates the status of a task in an action table.
195
- # @param [Symbol] table name of the action table
196
- # @param [Integer] action rowid to update
197
- # @param [Hash] data key / value pairs to set
198
- def update_action_status table, id, data
199
- data.merge! ( { :status => data[:status].to_s, :time => Time.now.to_i } )
200
- set = []
201
- data.each do |key, value|
202
- set << "`#{key}` = '#{value}'"
203
- end
204
-
205
- @action_db.execute "UPDATE #{table} SET #{set.join ", "} WHERE `rowid` = '#{id}'"
206
- end
207
-
208
- # def delete_action_by_id action, id
209
- # puts "DELETE FROM `#{action}` WHERE `rowid` = #{id}"
210
- # end
211
-
212
- end