cramp 0.11 → 0.12

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 (38) hide show
  1. data/lib/cramp.rb +12 -1
  2. data/lib/cramp/abstract.rb +72 -0
  3. data/lib/cramp/action.rb +12 -0
  4. data/lib/cramp/body.rb +48 -0
  5. data/lib/cramp/callbacks.rb +48 -0
  6. data/lib/cramp/keep_connection_alive.rb +19 -0
  7. data/lib/cramp/periodic_timer.rb +49 -0
  8. data/lib/cramp/rendering.rb +11 -0
  9. data/lib/cramp/test_case.rb +54 -0
  10. data/lib/cramp/websocket.rb +84 -0
  11. data/lib/cramp/{controller/websocket → websocket}/rainbows_backend.rb +1 -1
  12. data/lib/cramp/{controller/websocket → websocket}/thin_backend.rb +1 -1
  13. metadata +37 -86
  14. data/lib/cramp/controller.rb +0 -15
  15. data/lib/cramp/controller/abstract.rb +0 -71
  16. data/lib/cramp/controller/action.rb +0 -14
  17. data/lib/cramp/controller/body.rb +0 -50
  18. data/lib/cramp/controller/callbacks.rb +0 -50
  19. data/lib/cramp/controller/keep_connection_alive.rb +0 -21
  20. data/lib/cramp/controller/periodic_timer.rb +0 -51
  21. data/lib/cramp/controller/rendering.rb +0 -13
  22. data/lib/cramp/controller/test_case.rb +0 -57
  23. data/lib/cramp/controller/websocket.rb +0 -63
  24. data/lib/cramp/model.rb +0 -40
  25. data/lib/cramp/model/arel_monkey_patches.rb +0 -66
  26. data/lib/cramp/model/attribute.rb +0 -104
  27. data/lib/cramp/model/attribute_methods.rb +0 -83
  28. data/lib/cramp/model/base.rb +0 -119
  29. data/lib/cramp/model/callbacks.rb +0 -41
  30. data/lib/cramp/model/column.rb +0 -72
  31. data/lib/cramp/model/emysql_ext.rb +0 -21
  32. data/lib/cramp/model/engine.rb +0 -75
  33. data/lib/cramp/model/engine/connection.rb +0 -32
  34. data/lib/cramp/model/evented_mysql.rb +0 -298
  35. data/lib/cramp/model/finders.rb +0 -27
  36. data/lib/cramp/model/quoting.rb +0 -104
  37. data/lib/cramp/model/relation.rb +0 -62
  38. data/lib/cramp/model/status.rb +0 -18
@@ -1,41 +0,0 @@
1
- module Cramp
2
- module Model
3
- module Callbacks
4
- extend ActiveSupport::Concern
5
-
6
- included do
7
- class_inheritable_accessor :after_save_callback_names
8
- class_inheritable_accessor :after_destroy_callback_names
9
-
10
- self.after_save_callback_names = []
11
- self.after_destroy_callback_names = []
12
- end
13
-
14
- module ClassMethods
15
- def after_save(*method_names)
16
- self.after_save_callback_names += method_names
17
- end
18
-
19
- def after_destroy(*method_names)
20
- self.after_destroy_callback_names += method_names
21
- end
22
- end
23
-
24
- private
25
- def after_save_callbacks(result)
26
- after_save_callback_names.collect do |callback_name|
27
- callback = method callback_name
28
- callback.arity == 1 ? callback.call(result) : callback.call if callback
29
- end
30
- end
31
-
32
- def after_destroy_callbacks(result)
33
- after_destroy_callback_names.collect do |callback_name|
34
- callback = method callback_name
35
- callback.arity == 1 ? callback.call(result) : callback.call if callback
36
- end
37
- end
38
-
39
- end
40
- end
41
- end
@@ -1,72 +0,0 @@
1
- # Some of it yanked from Rails
2
-
3
- # Copyright (c) 2004-2009 David Heinemeier Hansson
4
- #
5
- # Permission is hereby granted, free of charge, to any person obtaining
6
- # a copy of this software and associated documentation files (the
7
- # "Software"), to deal in the Software without restriction, including
8
- # without limitation the rights to use, copy, modify, merge, publish,
9
- # distribute, sublicense, and/or sell copies of the Software, and to
10
- # permit persons to whom the Software is furnished to do so, subject to
11
- # the following conditions:
12
- #
13
- # The above copyright notice and this permission notice shall be
14
- # included in all copies or substantial portions of the Software.
15
- #
16
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
- # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
- # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
- # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
- # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
- # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
- # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
-
24
- module Cramp
25
- module Model
26
- class Column < Struct.new(:name, :default, :sql_type, :null)
27
- attr_reader :type
28
-
29
- def initialize(name, default, sql_type, null)
30
- super
31
- @type = simplified_type(sql_type)
32
- end
33
-
34
- private
35
-
36
- def simplified_type(field_type)
37
- case field_type
38
- when /int/i
39
- :integer
40
- when /float|double/i
41
- :float
42
- when /decimal|numeric|number/i
43
- extract_scale(field_type) == 0 ? :integer : :decimal
44
- when /datetime/i
45
- :datetime
46
- when /timestamp/i
47
- :timestamp
48
- when /time/i
49
- :time
50
- when /date/i
51
- :date
52
- when /clob/i, /text/i
53
- :text
54
- when /blob/i, /binary/i
55
- :binary
56
- when /char/i, /string/i
57
- :string
58
- when /boolean/i
59
- :boolean
60
- end
61
- end
62
-
63
- def extract_scale(sql_type)
64
- case sql_type
65
- when /^(numeric|decimal|number)\((\d+)\)/i then 0
66
- when /^(numeric|decimal|number)\((\d+)(,(\d+))\)/i then $4.to_i
67
- end
68
- end
69
-
70
- end
71
- end
72
- end
@@ -1,21 +0,0 @@
1
- class EventedMysql
2
- def self.execute_now(query)
3
- @n ||= 0
4
- connection = connection_pool[@n]
5
- @n = 0 if (@n+=1) >= connection_pool.size
6
- connection.execute_now(query)
7
- end
8
-
9
- def execute_now(sql)
10
- log 'mysql sending', sql
11
- @mysql.query(sql)
12
- rescue Mysql::Error => e
13
- log 'mysql error', e.message
14
- if DisconnectErrors.include? e.message
15
- @@queue << [response, sql, cblk, eblk]
16
- return close
17
- else
18
- raise e
19
- end
20
- end
21
- end
@@ -1,75 +0,0 @@
1
- require 'active_support/core_ext/module/attribute_accessors'
2
-
3
- module Cramp
4
- module Model
5
- class Engine
6
- autoload :Connection, "cramp/model/engine/connection"
7
-
8
- include Quoting
9
-
10
- def initialize(settings)
11
- @connection = Connection.new settings
12
- @quoted_column_names, @quoted_table_names = {}, {}
13
- end
14
-
15
- def create(relation, &block)
16
- query = relation.to_sql
17
- log_query(query)
18
- @connection.insert(query) {|rows| yield(rows) if block_given? }
19
- end
20
-
21
- def read(relation, &block)
22
- query = relation.to_sql
23
- log_query(query)
24
- @connection.select(query) {|rows| yield(rows) }
25
- end
26
-
27
- def update(relation)
28
- query = relation.to_sql
29
- log_query(query)
30
- @connection.update(query) {|rows| yield(rows) if block_given? }
31
- end
32
-
33
- def delete(relation)
34
- query = relation.to_sql
35
- log_query(query)
36
- @connection.delete(relation.to_sql) {|rows| yield(rows) if block_given? }
37
- end
38
-
39
- def adapter_name
40
- "mysql"
41
- end
42
-
43
- def connection
44
- # Arel apparently uses this method to check whether the engine is connected or not
45
- @connection
46
- end
47
-
48
- def tables
49
- sql = "SHOW TABLES"
50
- tables = []
51
- result = @connection.execute_now(sql)
52
-
53
- result.each { |field| tables << field[0] }
54
- result.free
55
- tables
56
- end
57
-
58
- def columns(table_name, name = nil)
59
- sql = "SHOW FIELDS FROM #{quote_table_name(table_name)}"
60
- columns = []
61
- result = @connection.execute_now(sql)
62
-
63
- result.each { |field| columns << Column.new(field[0], field[4], field[1], field[2] == "YES") }
64
- result.free
65
- columns
66
- end
67
-
68
- protected
69
-
70
- def log_query(sql)
71
- Cramp.logger.info("[QUERY] #{sql}") if Cramp.logger
72
- end
73
- end
74
- end
75
- end
@@ -1,32 +0,0 @@
1
- module Cramp
2
- module Model
3
- class Engine
4
- class Connection
5
- def initialize(settings)
6
- EventedMysql.settings.update(settings)
7
- end
8
-
9
- def execute_now(sql)
10
- EventedMysql.execute_now sql
11
- end
12
-
13
- def insert(sql, &block)
14
- EventedMysql.insert sql, block
15
- end
16
-
17
- def select(sql, &block)
18
- EventedMysql.select sql, block
19
- end
20
-
21
- def update(sql, &block)
22
- EventedMysql.update sql, block
23
- end
24
-
25
- def delete(sql, &block)
26
- EventedMysql.delete sql, block
27
- end
28
-
29
- end
30
- end
31
- end
32
- end
@@ -1,298 +0,0 @@
1
- # Async MySQL driver for Ruby/EventMachine
2
- # (c) 2008 Aman Gupta (tmm1)
3
- # http://github.com/tmm1/em-mysql
4
-
5
- require 'eventmachine'
6
- require 'fcntl'
7
-
8
- class Mysql
9
- def result
10
- @cur_result
11
- end
12
- end
13
-
14
- class EventedMysql < EM::Connection
15
- def initialize mysql, opts
16
- @mysql = mysql
17
- @fd = mysql.socket
18
- @opts = opts
19
- @current = nil
20
- @@queue ||= []
21
- @processing = false
22
- @connected = true
23
-
24
- log 'mysql connected'
25
-
26
- self.notify_readable = true
27
- EM.add_timer(0){ next_query }
28
- end
29
- attr_reader :processing, :connected, :opts
30
- alias :settings :opts
31
-
32
- DisconnectErrors = [
33
- 'query: not connected',
34
- 'MySQL server has gone away',
35
- 'Lost connection to MySQL server during query'
36
- ] unless defined? DisconnectErrors
37
-
38
- def notify_readable
39
- log 'readable'
40
- if item = @current
41
- @current = nil
42
- start, response, sql, cblk, eblk = item
43
- log 'mysql response', Time.now-start, sql
44
- arg = case response
45
- when :raw
46
- result = @mysql.get_result
47
- @mysql.instance_variable_set('@cur_result', result)
48
- @mysql
49
- when :select
50
- ret = []
51
- result = @mysql.get_result
52
- result.each_hash{|h| ret << h }
53
- log 'mysql result', ret
54
- ret
55
- when :update
56
- result = @mysql.get_result
57
- @mysql.affected_rows
58
- when :insert
59
- result = @mysql.get_result
60
- @mysql.insert_id
61
- else
62
- result = @mysql.get_result
63
- log 'got a result??', result if result
64
- nil
65
- end
66
-
67
- @processing = false
68
- # result.free if result.is_a? Mysql::Result
69
- next_query
70
- cblk.call(arg) if cblk
71
- else
72
- log 'readable, but nothing queued?! probably an ERROR state'
73
- return close
74
- end
75
- rescue Mysql::Error => e
76
- log 'mysql error', e.message
77
- if e.message =~ /Deadlock/
78
- @@queue << [response, sql, cblk, eblk]
79
- @processing = false
80
- next_query
81
- elsif DisconnectErrors.include? e.message
82
- @@queue << [response, sql, cblk, eblk]
83
- return close
84
- elsif cb = (eblk || @opts[:on_error])
85
- cb.call(e)
86
- @processing = false
87
- next_query
88
- else
89
- raise e
90
- end
91
- # ensure
92
- # res.free if res.is_a? Mysql::Result
93
- # @processing = false
94
- # next_query
95
- end
96
-
97
- def unbind
98
- log 'mysql disconnect', $!
99
- # cp = EventedMysql.instance_variable_get('@connection_pool') and cp.delete(self)
100
- @connected = false
101
-
102
- # XXX wait for the next tick until the current fd is removed completely from the reactor
103
- #
104
- # XXX in certain cases the new FD# (@mysql.socket) is the same as the old, since FDs are re-used
105
- # XXX without next_tick in these cases, unbind will get fired on the newly attached signature as well
106
- #
107
- # XXX do _NOT_ use EM.next_tick here. if a bunch of sockets disconnect at the same time, we want
108
- # XXX reconnects to happen after all the unbinds have been processed
109
- EM.add_timer(0) do
110
- log 'mysql reconnecting'
111
- @processing = false
112
- @mysql = EventedMysql._connect @opts
113
- @fd = @mysql.socket
114
-
115
- @signature = EM.attach_fd @mysql.socket, true
116
- EM.set_notify_readable @signature, true
117
- log 'mysql connected'
118
- EM.instance_variable_get('@conns')[@signature] = self
119
- @connected = true
120
- make_socket_blocking
121
- next_query
122
- end
123
- end
124
-
125
- def execute sql, response = nil, cblk = nil, eblk = nil, &blk
126
- cblk ||= blk
127
-
128
- begin
129
- unless @processing or !@connected
130
- # begin
131
- # log 'mysql ping', @mysql.ping
132
- # # log 'mysql stat', @mysql.stat
133
- # # log 'mysql errno', @mysql.errno
134
- # rescue
135
- # log 'mysql ping failed'
136
- # @@queue << [response, sql, blk]
137
- # return close
138
- # end
139
-
140
- @processing = true
141
-
142
- log 'mysql sending', sql
143
- @mysql.send_query(sql)
144
- else
145
- @@queue << [response, sql, cblk, eblk]
146
- return
147
- end
148
- rescue Mysql::Error => e
149
- log 'mysql error', e.message
150
- if DisconnectErrors.include? e.message
151
- @@queue << [response, sql, cblk, eblk]
152
- return close
153
- else
154
- raise e
155
- end
156
- end
157
-
158
- log 'queuing', response, sql
159
- @current = [Time.now, response, sql, cblk, eblk]
160
- end
161
-
162
- def close
163
- @connected = false
164
- fd = detach
165
- log 'detached fd', fd
166
- end
167
-
168
- private
169
-
170
- def next_query
171
- if @connected and !@processing and pending = @@queue.shift
172
- response, sql, cblk, eblk = pending
173
- execute(sql, response, cblk, eblk)
174
- end
175
- end
176
-
177
- def log *args
178
- return unless @opts[:logging]
179
- p [Time.now, @fd, (@signature[-4..-1] if @signature), *args]
180
- end
181
-
182
- public
183
-
184
- def self.connect opts
185
- unless EM.respond_to?(:watch) and Mysql.method_defined?(:socket)
186
- raise RuntimeError, 'mysqlplus and EM.watch are required for EventedMysql'
187
- end
188
-
189
- if conn = _connect(opts)
190
- EM.watch conn.socket, self, conn, opts
191
- else
192
- EM.add_timer(5){ connect opts }
193
- end
194
- end
195
-
196
- self::Mysql = ::Mysql unless defined? self::Mysql
197
-
198
- # stolen from sequel
199
- def self._connect opts
200
- opts = settings.merge(opts)
201
-
202
- conn = Mysql.init
203
-
204
- # set encoding _before_ connecting
205
- if charset = opts[:charset] || opts[:encoding]
206
- conn.options(Mysql::SET_CHARSET_NAME, charset)
207
- end
208
-
209
- conn.options(Mysql::OPT_LOCAL_INFILE, 'client')
210
-
211
- conn.real_connect(
212
- opts[:host] || 'localhost',
213
- opts[:user] || opts[:username] || 'root',
214
- opts[:password],
215
- opts[:database],
216
- opts[:port],
217
- opts[:socket],
218
- 0 +
219
- # XXX multi results require multiple callbacks to parse
220
- # Mysql::CLIENT_MULTI_RESULTS +
221
- # Mysql::CLIENT_MULTI_STATEMENTS +
222
- (opts[:compress] == false ? 0 : Mysql::CLIENT_COMPRESS)
223
- )
224
-
225
- # increase timeout so mysql server doesn't disconnect us
226
- # this is especially bad if we're disconnected while EM.attach is
227
- # still in progress, because by the time it gets to EM, the FD is
228
- # no longer valid, and it throws a c++ 'bad file descriptor' error
229
- # (do not use a timeout of -1 for unlimited, it does not work on mysqld > 5.0.60)
230
- conn.query("set @@wait_timeout = #{opts[:timeout] || 2592000}")
231
-
232
- # we handle reconnecting (and reattaching the new fd to EM)
233
- conn.reconnect = false
234
-
235
- # By default, MySQL 'where id is null' selects the last inserted id
236
- # Turn this off. http://dev.rubyonrails.org/ticket/6778
237
- conn.query("set SQL_AUTO_IS_NULL=0")
238
-
239
- # get results for queries
240
- conn.query_with_result = true
241
-
242
- conn
243
- rescue Mysql::Error => e
244
- if cb = opts[:on_error]
245
- cb.call(e)
246
- nil
247
- else
248
- raise e
249
- end
250
- end
251
- end
252
-
253
- class EventedMysql
254
- def self.settings
255
- @settings ||= { :connections => 4, :logging => false }
256
- end
257
-
258
- def self.execute query, type = nil, cblk = nil, eblk = nil, &blk
259
- unless nil#connection = connection_pool.find{|c| not c.processing and c.connected }
260
- @n ||= 0
261
- connection = connection_pool[@n]
262
- @n = 0 if (@n+=1) >= connection_pool.size
263
- end
264
-
265
- connection.execute(query, type, cblk, eblk, &blk)
266
- end
267
-
268
- %w[ select insert update delete raw ].each do |type| class_eval %[
269
-
270
- def self.#{type} query, cblk = nil, eblk = nil, &blk
271
- execute query, :#{type}, cblk, eblk, &blk
272
- end
273
-
274
- ] end
275
-
276
- def self.all query, type = nil, &blk
277
- responses = 0
278
- connection_pool.each do |c|
279
- c.execute(query, type) do
280
- responses += 1
281
- blk.call if blk and responses == @connection_pool.size
282
- end
283
- end
284
- end
285
-
286
- def self.connection_pool
287
- @connection_pool ||= (1..settings[:connections]).map{ EventedMysql.connect(settings) }
288
- # p ['connpool', settings[:connections], @connection_pool.size]
289
- # (1..(settings[:connections]-@connection_pool.size)).each do
290
- # @connection_pool << EventedMysql.connect(settings)
291
- # end unless settings[:connections] == @connection_pool.size
292
- # @connection_pool
293
- end
294
-
295
- def self.reset_connection_pool!
296
- @connection_pool = nil
297
- end
298
- end