rhodes-framework 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.
Files changed (67) hide show
  1. data/.gitignore +2 -0
  2. data/History.txt +37 -0
  3. data/Manifest.txt +66 -0
  4. data/README.rdoc +2 -0
  5. data/Rakefile +50 -0
  6. data/lib/ServeME.rb +7 -0
  7. data/lib/TestServe.rb +9 -0
  8. data/lib/bsearch.rb +120 -0
  9. data/lib/builtinME.rb +626 -0
  10. data/lib/date/format.rb +1339 -0
  11. data/lib/date.rb +1792 -0
  12. data/lib/dateME.rb +24 -0
  13. data/lib/erb.rb +896 -0
  14. data/lib/find.rb +81 -0
  15. data/lib/rational.rb +19 -0
  16. data/lib/rationalME.rb +530 -0
  17. data/lib/rho/render.rb +51 -0
  18. data/lib/rho/rho.rb +255 -0
  19. data/lib/rho/rhoapplication.rb +36 -0
  20. data/lib/rho/rhocontact.rb +110 -0
  21. data/lib/rho/rhocontroller.rb +35 -0
  22. data/lib/rho/rhofsconnector.rb +32 -0
  23. data/lib/rho/rhosupport.rb +146 -0
  24. data/lib/rho/rhoviewhelpers.rb +130 -0
  25. data/lib/rho.rb +1 -0
  26. data/lib/rhodes-framework.rb +2 -0
  27. data/lib/rhodes.rb +9 -0
  28. data/lib/rhoframework.rb +38 -0
  29. data/lib/rhofsconnector.rb +1 -0
  30. data/lib/rhom/rhom.rb +58 -0
  31. data/lib/rhom/rhom_db_adapter.rb +185 -0
  32. data/lib/rhom/rhom_db_adapterME.rb +93 -0
  33. data/lib/rhom/rhom_object.rb +69 -0
  34. data/lib/rhom/rhom_object_factory.rb +309 -0
  35. data/lib/rhom/rhom_source.rb +60 -0
  36. data/lib/rhom.rb +1 -0
  37. data/lib/singleton.rb +137 -0
  38. data/lib/time.rb +489 -0
  39. data/lib/version.rb +8 -0
  40. data/res/sqlite3/constants.rb +49 -0
  41. data/res/sqlite3/database.rb +715 -0
  42. data/res/sqlite3/driver/dl/api.rb +154 -0
  43. data/res/sqlite3/driver/dl/driver.rb +307 -0
  44. data/res/sqlite3/driver/native/driver.rb +257 -0
  45. data/res/sqlite3/errors.rb +68 -0
  46. data/res/sqlite3/pragmas.rb +271 -0
  47. data/res/sqlite3/resultset.rb +176 -0
  48. data/res/sqlite3/sqlite3_api.rb +0 -0
  49. data/res/sqlite3/statement.rb +230 -0
  50. data/res/sqlite3/translator.rb +109 -0
  51. data/res/sqlite3/value.rb +57 -0
  52. data/res/sqlite3/version.rb +14 -0
  53. data/rhodes-framework.gemspec +18 -0
  54. data/rhodes.gemspec +18 -0
  55. data/spec/app_manifest.txt +4 -0
  56. data/spec/configs/account.rb +3 -0
  57. data/spec/configs/case.rb +3 -0
  58. data/spec/configs/employee.rb +3 -0
  59. data/spec/rho_controller_spec.rb +144 -0
  60. data/spec/rho_spec.rb +75 -0
  61. data/spec/rhom_object_factory_spec.rb +372 -0
  62. data/spec/rhom_spec.rb +45 -0
  63. data/spec/spec.opts +1 -0
  64. data/spec/spec_helper.rb +49 -0
  65. data/spec/stubs.rb +39 -0
  66. data/spec/syncdbtest.sqlite +0 -0
  67. metadata +202 -0
@@ -0,0 +1,257 @@
1
+ require 'sqlite3/sqlite3_api'
2
+
3
+ module SQLite3 ; module Driver ; module Native
4
+
5
+ class Driver
6
+
7
+ def initialize
8
+ @callback_data = Hash.new
9
+ @authorizer = Hash.new
10
+ @busy_handler = Hash.new
11
+ @trace = Hash.new
12
+ end
13
+
14
+ def complete?( sql, utf16=false )
15
+ API.send( utf16 ? :sqlite3_complete16 : :sqlite3_complete, sql ) != 0
16
+ end
17
+
18
+ def busy_handler( db, data=nil, &block )
19
+ if block
20
+ cb = API::CallbackData.new
21
+ cb.proc = block
22
+ cb.data = data
23
+ result = API.sqlite3_busy_handler( db, API::Sqlite3_ruby_busy_handler, cb )
24
+ # Reference the Callback object so that
25
+ # it is not deleted by the GC
26
+ @busy_handler[db] = cb
27
+ else
28
+ # Unreference the callback *after* having removed it
29
+ # from sqlite
30
+ result = API.sqlite3_busy_handler( db, nil, nil )
31
+ @busy_handler.delete(db)
32
+ end
33
+
34
+ result
35
+ end
36
+
37
+ def set_authorizer( db, data=nil, &block )
38
+ if block
39
+ cb = API::CallbackData.new
40
+ cb.proc = block
41
+ cb.data = data
42
+ result = API.sqlite3_set_authorizer( db, API::Sqlite3_ruby_authorizer, cb )
43
+ @authorizer[db] = cb # see comments in busy_handler
44
+ else
45
+ result = API.sqlite3_set_authorizer( db, nil, nil )
46
+ @authorizer.delete(db) # see comments in busy_handler
47
+ end
48
+
49
+ result
50
+ end
51
+
52
+ def trace( db, data=nil, &block )
53
+ if block
54
+ cb = API::CallbackData.new
55
+ cb.proc = block
56
+ cb.data = data
57
+ result = API.sqlite3_trace( db, API::Sqlite3_ruby_trace, cb )
58
+ @trace[db] = cb # see comments in busy_handler
59
+ else
60
+ result = API.sqlite3_trace( db, nil, nil )
61
+ @trace.delete(db) # see comments in busy_handler
62
+ end
63
+
64
+ result
65
+ end
66
+
67
+ def open( filename, utf16=false )
68
+ API.send( utf16 ? :sqlite3_open16 : :sqlite3_open, filename )
69
+ end
70
+
71
+ def errmsg( db, utf16=false )
72
+ API.send( utf16 ? :sqlite3_errmsg16 : :sqlite3_errmsg, db )
73
+ end
74
+
75
+ def prepare( db, sql, utf16=false )
76
+ API.send( ( utf16 ? :sqlite3_prepare16 : :sqlite3_prepare ),
77
+ db, sql )
78
+ end
79
+
80
+ def bind_text( stmt, index, value, utf16=false )
81
+ API.send( ( utf16 ? :sqlite3_bind_text16 : :sqlite3_bind_text ),
82
+ stmt, index, value.to_s )
83
+ end
84
+
85
+ def column_name( stmt, index, utf16=false )
86
+ API.send( ( utf16 ? :sqlite3_column_name16 : :sqlite3_column_name ),
87
+ stmt, index )
88
+ end
89
+
90
+ def column_decltype( stmt, index, utf16=false )
91
+ API.send(
92
+ ( utf16 ? :sqlite3_column_decltype16 : :sqlite3_column_decltype ),
93
+ stmt, index )
94
+ end
95
+
96
+ def column_text( stmt, index, utf16=false )
97
+ API.send( ( utf16 ? :sqlite3_column_text16 : :sqlite3_column_text ),
98
+ stmt, index )
99
+ end
100
+
101
+ def create_function( db, name, args, text, cookie, func, step, final )
102
+ if func || ( step && final )
103
+ cb = API::CallbackData.new
104
+ cb.proc = cb.proc2 = nil
105
+ cb.data = cookie
106
+ end
107
+
108
+ if func
109
+ cb.proc = func
110
+
111
+ func = API::Sqlite3_ruby_function_step
112
+ step = final = nil
113
+ elsif step && final
114
+ cb.proc = step
115
+ cb.proc2 = final
116
+
117
+ func = nil
118
+ step = API::Sqlite3_ruby_function_step
119
+ final = API::Sqlite3_ruby_function_final
120
+ end
121
+
122
+ result = API.sqlite3_create_function( db, name, args, text, cb, func, step, final )
123
+
124
+ # see comments in busy_handler
125
+ if cb
126
+ @callback_data[ name ] = cb
127
+ else
128
+ @callback_data.delete( name )
129
+ end
130
+
131
+ return result
132
+ end
133
+
134
+ def value_text( value, utf16=false )
135
+ method = case utf16
136
+ when nil, false then :sqlite3_value_text
137
+ when :le then :sqlite3_value_text16le
138
+ when :be then :sqlite3_value_text16be
139
+ else :sqlite3_value_text16
140
+ end
141
+
142
+ API.send( method, value )
143
+ end
144
+
145
+ def result_text( context, result, utf16=false )
146
+ method = case utf16
147
+ when nil, false then :sqlite3_result_text
148
+ when :le then :sqlite3_result_text16le
149
+ when :be then :sqlite3_result_text16be
150
+ else :sqlite3_result_text16
151
+ end
152
+
153
+ API.send( method, context, result.to_s )
154
+ end
155
+
156
+ def result_error( context, value, utf16=false )
157
+ API.send( ( utf16 ? :sqlite3_result_error16 : :sqlite3_result_error ),
158
+ context, value )
159
+ end
160
+
161
+ def libversion (*args) API.sqlite3_libversion( *args ) ; end
162
+ def close (*args) API.sqlite3_close( *args ) ; end
163
+ def last_insert_rowid (*args) API.sqlite3_last_insert_rowid( *args ) ; end
164
+ def changes (*args) API.sqlite3_changes( *args ) ; end
165
+ def total_changes (*args) API.sqlite3_total_changes( *args ) ; end
166
+ def interrupt (*args) API.sqlite3_interrupt( *args ) ; end
167
+ def busy_timeout (*args) API.sqlite3_busy_timeout( *args ) ; end
168
+ def errcode (*args) API.sqlite3_errcode( *args ) ; end
169
+ def bind_blob (*args) API.sqlite3_bind_blob( *args ) ; end
170
+ def bind_double (*args) API.sqlite3_bind_double( *args ) ; end
171
+ def bind_int (*args) API.sqlite3_bind_int( *args ) ; end
172
+ def bind_int64 (*args) API.sqlite3_bind_int64( *args ) ; end
173
+ def bind_null (*args) API.sqlite3_bind_null( *args ) ; end
174
+ def bind_parameter_count (*args) API.sqlite3_bind_parameter_count( *args ) ; end
175
+ def bind_parameter_name (*args) API.sqlite3_bind_parameter_name( *args ) ; end
176
+ def bind_parameter_index (*args) API.sqlite3_bind_parameter_index( *args ) ; end
177
+ def column_count (*args) API.sqlite3_column_count( *args ) ; end
178
+ def step (*args) API.sqlite3_step( *args ) ; end
179
+ def data_count (*args) API.sqlite3_data_count( *args ) ; end
180
+ def column_blob (*args) API.sqlite3_column_blob( *args ) ; end
181
+ def column_bytes (*args) API.sqlite3_column_bytes( *args ) ; end
182
+ def column_bytes16 (*args) API.sqlite3_column_bytes16( *args ) ; end
183
+ def column_double (*args) API.sqlite3_column_double( *args ) ; end
184
+ def column_int (*args) API.sqlite3_column_int( *args ) ; end
185
+ def column_int64 (*args) API.sqlite3_column_int64( *args ) ; end
186
+ def column_type (*args) API.sqlite3_column_type( *args ) ; end
187
+ def finalize (*args) API.sqlite3_finalize( *args ) ; end
188
+ def reset (*args) API.sqlite3_reset( *args ) ; end
189
+ def aggregate_count (*args) API.sqlite3_aggregate_count( *args ) ; end
190
+ def value_blob (*args) API.sqlite3_value_blob( *args ) ; end
191
+ def value_bytes (*args) API.sqlite3_value_bytes( *args ) ; end
192
+ def value_bytes16 (*args) API.sqlite3_value_bytes16( *args ) ; end
193
+ def value_double (*args) API.sqlite3_value_double( *args ) ; end
194
+ def value_int (*args) API.sqlite3_value_int( *args ) ; end
195
+ def value_int64 (*args) API.sqlite3_value_int64( *args ) ; end
196
+ def value_type (*args) API.sqlite3_value_type( *args ) ; end
197
+ def result_blob (*args) API.sqlite3_result_blob( *args ) ; end
198
+ def result_double (*args) API.sqlite3_result_double( *args ) ; end
199
+ def result_int (*args) API.sqlite3_result_int( *args ) ; end
200
+ def result_int64 (*args) API.sqlite3_result_int64( *args ) ; end
201
+ def result_null (*args) API.sqlite3_result_null( *args ) ; end
202
+ def result_value (*args) API.sqlite3_result_value( *args ) ; end
203
+ def aggregate_context (*args) API.sqlite3_aggregate_context( *args ) ; end
204
+
205
+ =begin
206
+ def self.api_delegate( name )
207
+ eval "def #{name} (*args) API.sqlite3_#{name}( *args ) ; end"
208
+ end
209
+
210
+ api_delegate :libversion
211
+ api_delegate :close
212
+ api_delegate :last_insert_rowid
213
+ api_delegate :changes
214
+ api_delegate :total_changes
215
+ api_delegate :interrupt
216
+ api_delegate :busy_timeout
217
+ api_delegate :errcode
218
+ api_delegate :bind_blob
219
+ api_delegate :bind_double
220
+ api_delegate :bind_int
221
+ api_delegate :bind_int64
222
+ api_delegate :bind_null
223
+ api_delegate :bind_parameter_count
224
+ api_delegate :bind_parameter_name
225
+ api_delegate :bind_parameter_index
226
+ api_delegate :column_count
227
+ api_delegate :step
228
+ api_delegate :data_count
229
+ api_delegate :column_blob
230
+ api_delegate :column_bytes
231
+ api_delegate :column_bytes16
232
+ api_delegate :column_double
233
+ api_delegate :column_int
234
+ api_delegate :column_int64
235
+ api_delegate :column_type
236
+ api_delegate :finalize
237
+ api_delegate :reset
238
+ api_delegate :aggregate_count
239
+ api_delegate :value_blob
240
+ api_delegate :value_bytes
241
+ api_delegate :value_bytes16
242
+ api_delegate :value_double
243
+ api_delegate :value_int
244
+ api_delegate :value_int64
245
+ api_delegate :value_type
246
+ api_delegate :result_blob
247
+ api_delegate :result_double
248
+ api_delegate :result_int
249
+ api_delegate :result_int64
250
+ api_delegate :result_null
251
+ api_delegate :result_value
252
+ api_delegate :aggregate_context
253
+ =end
254
+
255
+ end
256
+
257
+ end ; end ; end
@@ -0,0 +1,68 @@
1
+ require 'sqlite3/constants'
2
+
3
+ module SQLite3
4
+
5
+ class Exception < ::StandardError
6
+ @code = 0
7
+
8
+ # The numeric error code that this exception represents.
9
+ def self.code
10
+ @code
11
+ end
12
+
13
+ # A convenience for accessing the error code for this exception.
14
+ def code
15
+ self.class.code
16
+ end
17
+ end
18
+
19
+ class SQLException < Exception; end
20
+ class InternalException < Exception; end
21
+ class PermissionException < Exception; end
22
+ class AbortException < Exception; end
23
+ class BusyException < Exception; end
24
+ class LockedException < Exception; end
25
+ class MemoryException < Exception; end
26
+ class ReadOnlyException < Exception; end
27
+ class InterruptException < Exception; end
28
+ class IOException < Exception; end
29
+ class CorruptException < Exception; end
30
+ class NotFoundException < Exception; end
31
+ class FullException < Exception; end
32
+ class CantOpenException < Exception; end
33
+ class ProtocolException < Exception; end
34
+ class EmptyException < Exception; end
35
+ class SchemaChangedException < Exception; end
36
+ class TooBigException < Exception; end
37
+ class ConstraintException < Exception; end
38
+ class MismatchException < Exception; end
39
+ class MisuseException < Exception; end
40
+ class UnsupportedException < Exception; end
41
+ class AuthorizationException < Exception; end
42
+ class FormatException < Exception; end
43
+ class RangeException < Exception; end
44
+ class NotADatabaseException < Exception; end
45
+
46
+ EXCEPTIONS = [
47
+ nil,
48
+ SQLException, InternalException, PermissionException,
49
+ AbortException, BusyException, LockedException, MemoryException,
50
+ ReadOnlyException, InterruptException, IOException, CorruptException,
51
+ NotFoundException, FullException, CantOpenException, ProtocolException,
52
+ EmptyException, SchemaChangedException, TooBigException,
53
+ ConstraintException, MismatchException, MisuseException,
54
+ UnsupportedException, AuthorizationException, FormatException,
55
+ RangeException, NotADatabaseException
56
+ ].each_with_index { |e,i| e.instance_variable_set( :@code, i ) if e }
57
+
58
+ module Error
59
+ def check( result, db=nil, msg=nil )
60
+ unless result == Constants::ErrorCode::OK
61
+ msg = ( msg ? msg + ": " : "" ) + db.errmsg if db
62
+ raise(( EXCEPTIONS[result] || SQLite3::Exception ), msg)
63
+ end
64
+ end
65
+ module_function :check
66
+ end
67
+
68
+ end
@@ -0,0 +1,271 @@
1
+ require 'sqlite3/errors'
2
+
3
+ module SQLite3
4
+
5
+ # This module is intended for inclusion solely by the Database class. It
6
+ # defines convenience methods for the various pragmas supported by SQLite3.
7
+ #
8
+ # For a detailed description of these pragmas, see the SQLite3 documentation
9
+ # at http://sqlite.org/pragma.html.
10
+ module Pragmas
11
+
12
+ # Returns +true+ or +false+ depending on the value of the named pragma.
13
+ def get_boolean_pragma( name )
14
+ get_first_value( "PRAGMA #{name}" ) != "0"
15
+ end
16
+ private :get_boolean_pragma
17
+
18
+ # Sets the given pragma to the given boolean value. The value itself
19
+ # may be +true+ or +false+, or any other commonly used string or
20
+ # integer that represents truth.
21
+ def set_boolean_pragma( name, mode )
22
+ case mode
23
+ when String
24
+ case mode.downcase
25
+ when "on", "yes", "true", "y", "t"; mode = "'ON'"
26
+ when "off", "no", "false", "n", "f"; mode = "'OFF'"
27
+ else
28
+ raise Exception,
29
+ "unrecognized pragma parameter #{mode.inspect}"
30
+ end
31
+ when true, 1
32
+ mode = "ON"
33
+ when false, 0, nil
34
+ mode = "OFF"
35
+ else
36
+ raise Exception,
37
+ "unrecognized pragma parameter #{mode.inspect}"
38
+ end
39
+
40
+ execute( "PRAGMA #{name}=#{mode}" )
41
+ end
42
+ private :set_boolean_pragma
43
+
44
+ # Requests the given pragma (and parameters), and if the block is given,
45
+ # each row of the result set will be yielded to it. Otherwise, the results
46
+ # are returned as an array.
47
+ def get_query_pragma( name, *parms, &block ) # :yields: row
48
+ if parms.empty?
49
+ execute( "PRAGMA #{name}", &block )
50
+ else
51
+ args = "'" + parms.join("','") + "'"
52
+ execute( "PRAGMA #{name}( #{args} )", &block )
53
+ end
54
+ end
55
+ private :get_query_pragma
56
+
57
+ # Return the value of the given pragma.
58
+ def get_enum_pragma( name )
59
+ get_first_value( "PRAGMA #{name}" )
60
+ end
61
+ private :get_enum_pragma
62
+
63
+ # Set the value of the given pragma to +mode+. The +mode+ parameter must
64
+ # conform to one of the values in the given +enum+ array. Each entry in
65
+ # the array is another array comprised of elements in the enumeration that
66
+ # have duplicate values. See #synchronous, #default_synchronous,
67
+ # #temp_store, and #default_temp_store for usage examples.
68
+ def set_enum_pragma( name, mode, enums )
69
+ match = enums.find { |p| p.find { |i| i.to_s.downcase == mode.to_s.downcase } }
70
+ raise Exception,
71
+ "unrecognized #{name} #{mode.inspect}" unless match
72
+ execute( "PRAGMA #{name}='#{match.first.upcase}'" )
73
+ end
74
+ private :set_enum_pragma
75
+
76
+ # Returns the value of the given pragma as an integer.
77
+ def get_int_pragma( name )
78
+ get_first_value( "PRAGMA #{name}" ).to_i
79
+ end
80
+ private :get_int_pragma
81
+
82
+ # Set the value of the given pragma to the integer value of the +value+
83
+ # parameter.
84
+ def set_int_pragma( name, value )
85
+ execute( "PRAGMA #{name}=#{value.to_i}" )
86
+ end
87
+ private :set_int_pragma
88
+
89
+ # The enumeration of valid synchronous modes.
90
+ SYNCHRONOUS_MODES = [ [ 'full', 2 ], [ 'normal', 1 ], [ 'off', 0 ] ]
91
+
92
+ # The enumeration of valid temp store modes.
93
+ TEMP_STORE_MODES = [ [ 'default', 0 ], [ 'file', 1 ], [ 'memory', 2 ] ]
94
+
95
+ # Does an integrity check on the database. If the check fails, a
96
+ # SQLite3::Exception will be raised. Otherwise it
97
+ # returns silently.
98
+ def integrity_check
99
+ execute( "PRAGMA integrity_check" ) do |row|
100
+ raise Exception, row[0] if row[0] != "ok"
101
+ end
102
+ end
103
+
104
+ def auto_vacuum
105
+ get_boolean_pragma "auto_vacuum"
106
+ end
107
+
108
+ def auto_vacuum=( mode )
109
+ set_boolean_pragma "auto_vacuum", mode
110
+ end
111
+
112
+ def schema_cookie
113
+ get_int_pragma "schema_cookie"
114
+ end
115
+
116
+ def schema_cookie=( cookie )
117
+ set_int_pragma "schema_cookie", cookie
118
+ end
119
+
120
+ def user_cookie
121
+ get_int_pragma "user_cookie"
122
+ end
123
+
124
+ def user_cookie=( cookie )
125
+ set_int_pragma "user_cookie", cookie
126
+ end
127
+
128
+ def cache_size
129
+ get_int_pragma "cache_size"
130
+ end
131
+
132
+ def cache_size=( size )
133
+ set_int_pragma "cache_size", size
134
+ end
135
+
136
+ def default_cache_size
137
+ get_int_pragma "default_cache_size"
138
+ end
139
+
140
+ def default_cache_size=( size )
141
+ set_int_pragma "default_cache_size", size
142
+ end
143
+
144
+ def default_synchronous
145
+ get_enum_pragma "default_synchronous"
146
+ end
147
+
148
+ def default_synchronous=( mode )
149
+ set_enum_pragma "default_synchronous", mode, SYNCHRONOUS_MODES
150
+ end
151
+
152
+ def synchronous
153
+ get_enum_pragma "synchronous"
154
+ end
155
+
156
+ def synchronous=( mode )
157
+ set_enum_pragma "synchronous", mode, SYNCHRONOUS_MODES
158
+ end
159
+
160
+ def default_temp_store
161
+ get_enum_pragma "default_temp_store"
162
+ end
163
+
164
+ def default_temp_store=( mode )
165
+ set_enum_pragma "default_temp_store", mode, TEMP_STORE_MODES
166
+ end
167
+
168
+ def temp_store
169
+ get_enum_pragma "temp_store"
170
+ end
171
+
172
+ def temp_store=( mode )
173
+ set_enum_pragma "temp_store", mode, TEMP_STORE_MODES
174
+ end
175
+
176
+ def full_column_names
177
+ get_boolean_pragma "full_column_names"
178
+ end
179
+
180
+ def full_column_names=( mode )
181
+ set_boolean_pragma "full_column_names", mode
182
+ end
183
+
184
+ def parser_trace
185
+ get_boolean_pragma "parser_trace"
186
+ end
187
+
188
+ def parser_trace=( mode )
189
+ set_boolean_pragma "parser_trace", mode
190
+ end
191
+
192
+ def vdbe_trace
193
+ get_boolean_pragma "vdbe_trace"
194
+ end
195
+
196
+ def vdbe_trace=( mode )
197
+ set_boolean_pragma "vdbe_trace", mode
198
+ end
199
+
200
+ def database_list( &block ) # :yields: row
201
+ get_query_pragma "database_list", &block
202
+ end
203
+
204
+ def foreign_key_list( table, &block ) # :yields: row
205
+ get_query_pragma "foreign_key_list", table, &block
206
+ end
207
+
208
+ def index_info( index, &block ) # :yields: row
209
+ get_query_pragma "index_info", index, &block
210
+ end
211
+
212
+ def index_list( table, &block ) # :yields: row
213
+ get_query_pragma "index_list", table, &block
214
+ end
215
+
216
+ def table_info( table, &block ) # :yields: row
217
+ columns, *rows = execute2("PRAGMA table_info(#{table})")
218
+
219
+ needs_tweak_default = version_compare(driver.libversion, "3.3.7") > 0
220
+
221
+ result = [] unless block_given?
222
+ rows.each do |row|
223
+ new_row = {}
224
+ columns.each_with_index do |name, index|
225
+ new_row[name] = row[index]
226
+ end
227
+
228
+ tweak_default(new_row) if needs_tweak_default
229
+
230
+ if block_given?
231
+ yield new_row
232
+ else
233
+ result << new_row
234
+ end
235
+ end
236
+
237
+ result
238
+ end
239
+
240
+ private
241
+
242
+ # Compares two version strings
243
+ def version_compare(v1, v2)
244
+ v1 = v1.split(".").map { |i| i.to_i }
245
+ v2 = v2.split(".").map { |i| i.to_i }
246
+ parts = [v1.length, v2.length].max
247
+ v1.push 0 while v1.length < parts
248
+ v2.push 0 while v2.length < parts
249
+ v1.zip(v2).each do |a,b|
250
+ return -1 if a < b
251
+ return 1 if a > b
252
+ end
253
+ return 0
254
+ end
255
+
256
+ # Since SQLite 3.3.8, the table_info pragma has returned the default
257
+ # value of the row as a quoted SQL value. This method essentially
258
+ # unquotes those values.
259
+ def tweak_default(hash)
260
+ case hash["dflt_value"]
261
+ when /^null$/i
262
+ hash["dflt_value"] = nil
263
+ when /^'(.*)'$/
264
+ hash["dflt_value"] = $1.gsub(/''/, "'")
265
+ when /^"(.*)"$/
266
+ hash["dflt_value"] = $1.gsub(/""/, '"')
267
+ end
268
+ end
269
+ end
270
+
271
+ end