kit 0.3.0 → 1.0.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/.gitignore +18 -0
- data/.rspec +0 -0
- data/.yardopts +2 -0
- data/CHANGELOG.rdoc +10 -1
- data/Gemfile +2 -0
- data/LICENSE.txt +22 -0
- data/README.rdoc +84 -19
- data/Rakefile +21 -0
- data/kit.gemspec +27 -0
- data/lib/kit.rb +67 -170
- data/lib/kit/db_support.rb +71 -0
- data/lib/kit/models/bit.rb +34 -0
- data/lib/kit/models/group.rb +5 -0
- data/lib/kit/models/permission.rb +6 -0
- data/lib/kit/models/user.rb +6 -0
- data/lib/kit/rake/admin.rb +3 -0
- data/lib/kit/rake/admin/database.rb +28 -0
- data/lib/kit/rake/admin/make.rb +19 -0
- data/lib/kit/rake/admin/manage.rb +8 -0
- data/lib/kit/version.rb +4 -0
- data/spec/bit_spec.rb +57 -0
- data/spec/kit_db_support_spec.rb +110 -0
- data/spec/kit_spec.rb +56 -0
- metadata +108 -19
- data/LICENCE.txt +0 -21
- data/lib/kit/bit.rb +0 -173
- data/lib/kit/db_sqlite3.rb +0 -212
data/LICENCE.txt
DELETED
@@ -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.
|
data/lib/kit/bit.rb
DELETED
@@ -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
|
-
|
data/lib/kit/db_sqlite3.rb
DELETED
@@ -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
|