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,13 +0,0 @@
1
- module Cramp
2
- module Controller
3
- module Rendering
4
-
5
- extend ActiveSupport::Concern
6
-
7
- def render(body)
8
- @body.call(body)
9
- end
10
-
11
- end
12
- end
13
- end
@@ -1,57 +0,0 @@
1
- require 'active_support'
2
- require 'active_support/test_case'
3
-
4
- module Cramp
5
- module Controller
6
- class TestCase < ::ActiveSupport::TestCase
7
-
8
- setup :create_request
9
-
10
- def create_request
11
- @request = Rack::MockRequest.new(app)
12
- end
13
-
14
- def get(path, options = {}, headers = {}, &block)
15
- callback = options.delete(:callback) || block
16
- headers = headers.merge('async.callback' => callback)
17
-
18
- EM.run { @request.get(path, headers) }
19
- end
20
-
21
- def get_body(path, options = {}, headers = {}, &block)
22
- callback = options.delete(:callback) || block
23
- response_callback = proc {|response| response[-1].each {|chunk| callback.call(chunk) } }
24
- headers = headers.merge('async.callback' => response_callback)
25
-
26
- EM.run { @request.get(path, headers) }
27
- end
28
-
29
- def get_body_chunks(path, options = {}, headers = {}, &block)
30
- callback = options.delete(:callback) || block
31
- count = options.delete(:count) || 1
32
-
33
- stopping = false
34
- chunks = []
35
-
36
- get_body(path, options, headers) do |body_chunk|
37
- chunks << body_chunk unless stopping
38
-
39
- if chunks.count >= count
40
- stopping = true
41
- callback.call(chunks) if callback
42
- EM.next_tick { EM.stop }
43
- end
44
- end
45
- end
46
-
47
- def app
48
- raise "Please define a method called 'app' returning an async Rack Application"
49
- end
50
-
51
- def stop
52
- EM.stop
53
- end
54
- end
55
-
56
- end
57
- end
@@ -1,63 +0,0 @@
1
- module Cramp
2
- module Controller
3
- module WebsocketExtension
4
- WEBSOCKET_RECEIVE_CALLBACK = 'websocket.receive_callback'.freeze
5
-
6
- def websocket?
7
- @env['HTTP_CONNECTION'] == 'Upgrade' && @env['HTTP_UPGRADE'] == 'WebSocket'
8
- end
9
-
10
- def websocket_upgrade_data
11
- location = "ws://#{@env['HTTP_HOST']}#{@env['REQUEST_PATH']}"
12
-
13
- upgrade = "HTTP/1.1 101 Web Socket Protocol Handshake\r\n"
14
- upgrade << "Upgrade: WebSocket\r\n"
15
- upgrade << "Connection: Upgrade\r\n"
16
- upgrade << "WebSocket-Origin: #{@env['HTTP_ORIGIN']}\r\n"
17
- upgrade << "WebSocket-Location: #{location}\r\n\r\n"
18
-
19
- upgrade
20
- end
21
- end
22
-
23
- class Websocket < Abstract
24
- include PeriodicTimer
25
-
26
- # TODO : Websockets shouldn't need this in an ideal world
27
- include KeepConnectionAlive
28
-
29
- class_inheritable_accessor :on_data_callbacks, :instance_reader => false
30
- self.on_data_callbacks = []
31
-
32
- class << self
33
- def backend=(backend)
34
- raise "Websocket backend #{backend} is unknown" unless [:thin, :rainbows].include?(backend.to_sym)
35
- require "cramp/controller/websocket/#{backend}_backend.rb"
36
- end
37
-
38
- def on_data(*methods)
39
- self.on_data_callbacks += methods
40
- end
41
- end
42
-
43
- def process
44
- @env['websocket.receive_callback'] = method(:_on_data_receive)
45
- super
46
- end
47
-
48
- def render(body)
49
- @body.call("\x00#{body}\xff")
50
- end
51
-
52
- def _on_data_receive(data)
53
- data = data.split(/\000([^\377]*)\377/).select{|d| !d.empty? }.collect{|d| d.gsub(/^\x00|\xff$/, '') }
54
- self.class.on_data_callbacks.each do |callback|
55
- data.each do |message|
56
- EM.next_tick { send(callback, message) }
57
- end
58
- end
59
- end
60
-
61
- end
62
- end
63
- end
data/lib/cramp/model.rb DELETED
@@ -1,40 +0,0 @@
1
- require 'cramp'
2
- require 'cramp/model/evented_mysql'
3
- require 'cramp/model/emysql_ext'
4
-
5
- require 'mysqlplus'
6
-
7
- require 'arel'
8
- require 'cramp/model/arel_monkey_patches'
9
-
10
- require 'active_model'
11
-
12
- module Cramp
13
- module Model
14
- autoload :Quoting, "cramp/model/quoting"
15
- autoload :Engine, "cramp/model/engine"
16
- autoload :Column, "cramp/model/column"
17
- autoload :Relation, "cramp/model/relation"
18
-
19
- autoload :Base, "cramp/model/base"
20
- autoload :Finders, "cramp/model/finders"
21
- autoload :Attribute, "cramp/model/attribute"
22
- autoload :AttributeMethods, "cramp/model/attribute_methods"
23
- autoload :Status, "cramp/model/status"
24
- autoload :Callbacks, "cramp/model/callbacks"
25
-
26
- def self.init(settings)
27
- Arel::Table.engine = Cramp::Model::Engine.new(settings)
28
- end
29
-
30
- def self.select(query, callback = nil, &block)
31
- callback ||= block
32
-
33
- EventedMysql.select(query) do |rows|
34
- callback.arity == 1 ? callback.call(rows) : callback.call if callback
35
- end
36
- end
37
-
38
- end
39
- end
40
-
@@ -1,66 +0,0 @@
1
- class Arel::Session
2
- def create(insert, &block)
3
- insert.call(&block)
4
- end
5
-
6
- def read(select, &block)
7
- select.call(&block)
8
- end
9
-
10
- def update(update, &block)
11
- update.call(&block)
12
- end
13
-
14
- def delete(delete, &block)
15
- delete.call(&block)
16
- end
17
-
18
- end
19
-
20
- module Arel::Relation
21
- def call(&block)
22
- engine.read(self, &block)
23
- end
24
-
25
- def all(&block)
26
- session.read(self) {|rows| block.call(rows) }
27
- end
28
-
29
- def first(&block)
30
- session.read(self) {|rows| block.call(rows[0]) }
31
- end
32
-
33
- def each(&block)
34
- session.read(self) {|rows| rows.each {|r| block.call(r) } }
35
- end
36
-
37
- def insert(record, &block)
38
- session.create(Arel::Insert.new(self, record), &block)
39
- end
40
-
41
- def update(assignments, &block)
42
- session.update(Arel::Update.new(self, assignments), &block)
43
- end
44
-
45
- def delete(&block)
46
- session.delete(Arel::Deletion.new(self), &block)
47
- end
48
- end
49
-
50
- class Arel::Deletion
51
- def call(&block)
52
- engine.delete(self, &block)
53
- end
54
- end
55
-
56
- class Arel::Insert
57
- def call(&block)
58
- engine.create(self, &block)
59
- end
60
- end
61
-
62
- class Arel::Update
63
- def call(&block)
64
- engine.update(self, &block)
65
- end
66
- end
@@ -1,104 +0,0 @@
1
- # Copyright (c) 2009 Koziarski Software Ltd
2
- #
3
- # Permission to use, copy, modify, and/or distribute this software for any
4
- # purpose with or without fee is hereby granted, provided that the above
5
- # copyright notice and this permission notice appear in all copies.
6
- #
7
- # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8
- # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9
- # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
10
- # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11
- # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
12
- # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
13
- # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14
-
15
- module Cramp
16
- module Model
17
- class Attribute
18
-
19
- FORMATS = {}
20
- FORMATS[Date] = /^\d{4}\/\d{2}\/\d{2}$/
21
- FORMATS[Integer] = /^-?\d+$/
22
- FORMATS[Float] = /^-?\d*\.\d*$/
23
- FORMATS[Time] = /\A\s*
24
- -?\d+-\d\d-\d\d
25
- T
26
- \d\d:\d\d:\d\d
27
- (\.\d*)?
28
- (Z|[+-]\d\d:\d\d)?
29
- \s*\z/ix # lifted from the implementation of Time.xmlschema
30
-
31
- CONVERTERS = {}
32
- CONVERTERS[Date] = Proc.new do |str|
33
- Date.strptime(str, "%Y/%m/%d")
34
- end
35
-
36
- CONVERTERS[Integer] = Proc.new do |str|
37
- Integer(str)
38
- end
39
-
40
- CONVERTERS[Float] = Proc.new do |str|
41
- Float(str)
42
- end
43
-
44
- CONVERTERS[Time] = Proc.new do |str|
45
- Time.xmlschema(str)
46
- end
47
-
48
- attr_reader :name
49
- def initialize(name, owner_class, options)
50
- @name = name.to_s
51
- @owner_class = owner_class
52
- @options = options
53
-
54
- # append_validations!
55
- define_methods!
56
- end
57
-
58
- # I think this should live somewhere in Amo
59
- def check_value!(value)
60
- # Allow nil and Strings to fall back on the validations for typecasting
61
- # Everything else gets checked with is_a?
62
- if value.nil?
63
- nil
64
- elsif value.is_a?(String)
65
- value
66
- elsif value.is_a?(expected_type)
67
- value
68
- else
69
- raise TypeError, "Expected #{expected_type.inspect} but got #{value.inspect}"
70
- end
71
- end
72
-
73
- def expected_type
74
- @options[:type] || String
75
- end
76
-
77
- def type_cast(value)
78
- if value.is_a?(expected_type)
79
- value
80
- elsif (converter = CONVERTERS[expected_type]) && (value =~ FORMATS[expected_type])
81
- converter.call(value)
82
- else
83
- value
84
- end
85
- end
86
-
87
- def append_validations!
88
- if f = FORMATS[expected_type]
89
- @owner_class.validates_format_of @name, :with => f, :unless => lambda {|obj| obj.send(name).is_a? expected_type }, :allow_nil => @options[:allow_nil]
90
- end
91
- end
92
-
93
- def define_methods!
94
- @owner_class.define_attribute_methods(true)
95
- end
96
-
97
- def primary_key?
98
- @options[:primary_key]
99
- end
100
-
101
- end
102
-
103
- end
104
- end
@@ -1,83 +0,0 @@
1
- # Copyright (c) 2009 Koziarski Software Ltd
2
- #
3
- # Permission to use, copy, modify, and/or distribute this software for any
4
- # purpose with or without fee is hereby granted, provided that the above
5
- # copyright notice and this permission notice appear in all copies.
6
- #
7
- # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8
- # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9
- # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
10
- # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11
- # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
12
- # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
13
- # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14
-
15
- module Cramp
16
- module Model
17
- module AttributeMethods
18
-
19
- extend ActiveSupport::Concern
20
- include ActiveModel::AttributeMethods
21
-
22
- module ClassMethods
23
- def attribute(name, options = {})
24
- write_inheritable_hash(:model_attributes, {name => Attribute.new(name, self, options)})
25
- end
26
-
27
- def define_attribute_methods(force = false)
28
- return unless model_attributes
29
- undefine_attribute_methods if force
30
- super(model_attributes.keys)
31
- end
32
- end
33
-
34
- included do
35
- class_inheritable_hash :model_attributes
36
- undef_method(:id) if method_defined?(:id)
37
-
38
- attribute_method_suffix("", "=")
39
- end
40
-
41
- def write_attribute(name, value)
42
- if ma = self.class.model_attributes[name.to_sym]
43
- value = ma.check_value!(value)
44
- end
45
- if(@attributes[name] != value)
46
- send "#{name}_will_change!".to_sym
47
- @attributes[name] = value
48
- end
49
- end
50
-
51
- def read_attribute(name)
52
- if ma = self.class.model_attributes[name]
53
- ma.type_cast(@attributes[name])
54
- else
55
- @attributes[name]
56
- end
57
- end
58
-
59
- def attributes=(attributes)
60
- attributes.each do |(name, value)|
61
- send("#{name}=", value)
62
- end
63
- end
64
-
65
- protected
66
-
67
- def attribute_method?(name)
68
- @attributes.include?(name.to_sym) || model_attributes[name.to_sym]
69
- end
70
-
71
- private
72
-
73
- def attribute(name)
74
- read_attribute(name.to_sym)
75
- end
76
-
77
- def attribute=(name, value)
78
- write_attribute(name.to_sym, value)
79
- end
80
-
81
- end
82
- end
83
- end
@@ -1,119 +0,0 @@
1
- module Cramp
2
- module Model
3
- class Base
4
-
5
- extend Finders
6
- include AttributeMethods
7
- include ActiveModel::Validations
8
- include ActiveModel::Dirty
9
- include Callbacks
10
-
11
- class << self
12
- def columns
13
- @columns ||= arel_table.columns
14
- end
15
-
16
- def column_names
17
- columns.map(&:name)
18
- end
19
-
20
- def primary_key
21
- @primary_key ||= model_attributes.detect {|k, v| v.primary_key? }[0]
22
- end
23
-
24
- def instantiate(record)
25
- object = allocate
26
- object.instance_variable_set("@attributes", record.with_indifferent_access)
27
- object
28
- end
29
- end
30
-
31
- attr_reader :attributes
32
-
33
- def initialize(attributes = {})
34
- @new_record = true
35
- @attributes = {}.with_indifferent_access
36
- self.attributes = attributes
37
- end
38
-
39
- def new_record?
40
- @new_record
41
- end
42
-
43
- def save(callback = nil, &block)
44
- callback ||= block
45
-
46
- if valid?
47
- new_record? ? create_record(callback) : update_record(callback)
48
- else
49
- callback.arity == 1 ? callback.call(Status.new(self, false)) : callback.call if callback
50
- end
51
- end
52
-
53
- def destroy(callback = nil, &block)
54
- callback ||= block
55
-
56
- relation.delete do
57
- status = Status.new(self, true)
58
- after_destroy_callbacks status
59
- callback.arity == 1 ? callback.call(status) : callback.call if callback
60
- end
61
- end
62
-
63
- private
64
-
65
- def create_record(callback = nil, &block)
66
- callback ||= block
67
-
68
- self.class.arel_table.insert(arel_attributes(true)) do |new_id|
69
- if new_id.present?
70
- self.id = new_id
71
- saved = true
72
- @new_record = false
73
- else
74
- saved = false
75
- end
76
-
77
- status = Status.new(self, saved)
78
- after_save status
79
- callback.arity == 1 ? callback.call(status) : callback.call if callback
80
- end
81
- end
82
-
83
- def update_record(callback = nil, &block)
84
- callback ||= block
85
-
86
- relation.update(arel_attributes) do |updated_rows|
87
- status = Status.new(self, true)
88
- after_save status
89
- callback.arity == 1 ? callback.call(status) : callback.call if callback
90
- end
91
- end
92
-
93
- def relation
94
- self.class.arel_table.where(self.class[self.class.primary_key].eq(send(self.class.primary_key)))
95
- end
96
-
97
- def after_save(status)
98
- if status.success?
99
- @previously_changed = changes
100
- changed_attributes.clear
101
- end
102
-
103
- after_save_callbacks status
104
- end
105
-
106
- def arel_attributes(exclude_primary_key = true, attribute_names = @attributes.keys)
107
- attrs = {}
108
-
109
- attribute_names.each do |name|
110
- value = read_attribute(name)
111
- attrs[self.class.arel_table[name]] = value
112
- end
113
-
114
- attrs
115
- end
116
-
117
- end
118
- end
119
- end