puffs 0.2.04 → 0.2.05

Sign up to get free protection for your applications and to get access to all the features.
data/lib/relation.rb CHANGED
@@ -1,206 +1,208 @@
1
1
  require_relative './../lib/db_connection'
2
2
  require_relative 'sql_object/sql_object'
3
3
 
4
- class Puffs::SQLRelation
5
- def self.build_association(base, included, method_name)
6
- base.included_relations << included
4
+ module Puffs
5
+ class SQLRelation
6
+ def self.build_association(base, included, method_name)
7
+ base.included_relations << included
8
+
9
+ assoc_options = base.klass.assoc_options[method_name]
10
+ has_many = assoc_options.class == HasManyOptions
11
+
12
+ if has_many
13
+ i_send = assoc_options.foreign_key
14
+ b_send = assoc_options.primary_key
15
+ else
16
+ i_send = assoc_options.primary_key
17
+ b_send = assoc_options.foreign_key
18
+ end
7
19
 
8
- assoc_options = base.klass.assoc_options[method_name]
9
- has_many = assoc_options.class == HasManyOptions
20
+ match = proc do
21
+ selection = included.select do |i_sql_obj|
22
+ i_sql_obj.send(i_send) == self.send(b_send)
23
+ end
10
24
 
11
- if has_many
12
- i_send = assoc_options.foreign_key
13
- b_send = assoc_options.primary_key
14
- else
15
- i_send = assoc_options.primary_key
16
- b_send = assoc_options.foreign_key
17
- end
25
+ associated = has_many ? selection : selection.first
18
26
 
19
- match = proc do
20
- selection = included.select do |i_sql_obj|
21
- i_sql_obj.send(i_send) == self.send(b_send)
27
+ #After we find our values iteratively, we overwrite the method again
28
+ #to the result values to reduce future lookup time to O(1).
29
+ new_match = proc { associated }
30
+ Puffs::SQLObject.define_singleton_method_by_proc(
31
+ self, method_name, new_match)
32
+
33
+ associated
22
34
  end
23
35
 
24
- associated = has_many ? selection : selection.first
36
+ #we overwrite the association method for each SQLObject in the
37
+ #collection so that it points to our cached relation and doesn't fire a query.
38
+ base.collection.each do |b_sql_obj|
39
+ Puffs::SQLObject.define_singleton_method_by_proc(
40
+ b_sql_obj, method_name, match)
41
+ end
42
+ end
25
43
 
26
- #After we find our values iteratively, we overwrite the method again
27
- #to the result values to reduce future lookup time to O(1).
28
- new_match = proc { associated }
29
- Puffs::SQLObject.define_singleton_method_by_proc(
30
- self, method_name, new_match)
44
+ attr_reader :klass, :collection, :loaded, :sql_count, :sql_limit
45
+ attr_accessor :included_relations
31
46
 
32
- associated
33
- end
47
+ def initialize(options)
48
+ defaults =
49
+ {
50
+ klass: nil,
51
+ loaded: false,
52
+ collection: []
53
+ }
34
54
 
35
- #we overwrite the association method for each SQLObject in the
36
- #collection so that it points to our cached relation and doesn't fire a query.
37
- base.collection.each do |b_sql_obj|
38
- Puffs::SQLObject.define_singleton_method_by_proc(
39
- b_sql_obj, method_name, match)
55
+ @klass = options[:klass]
56
+ @collection = options[:collection] || defaults[:collection]
57
+ @loaded = options[:loaded] || defaults[:loaded]
40
58
  end
41
- end
42
59
 
43
- attr_reader :klass, :collection, :loaded, :sql_count, :sql_limit
44
- attr_accessor :included_relations
60
+ def <<(item)
61
+ if item.class == klass
62
+ @collection << item
63
+ end
64
+ end
45
65
 
46
- def initialize(options)
47
- defaults =
48
- {
49
- klass: nil,
50
- loaded: false,
51
- collection: []
52
- }
66
+ def count
67
+ @sql_count = true
68
+ load
69
+ end
53
70
 
54
- @klass = options[:klass]
55
- @collection = options[:collection] || defaults[:collection]
56
- @loaded = options[:loaded] || defaults[:loaded]
57
- end
71
+ def included_relations
72
+ @included_relations ||= []
73
+ end
58
74
 
59
- def <<(item)
60
- if item.class == klass
61
- @collection << item
75
+ def includes(klass)
76
+ includes_params << klass
77
+ self
62
78
  end
63
- end
64
79
 
65
- def count
66
- @sql_count = true
67
- load
68
- end
80
+ def includes_params
81
+ @includes_params ||= []
82
+ end
69
83
 
70
- def included_relations
71
- @included_relations ||= []
72
- end
84
+ def limit(n)
85
+ @sql_limit = n
86
+ self
87
+ end
73
88
 
74
- def includes(klass)
75
- includes_params << klass
76
- self
77
- end
89
+ def load
90
+ if !loaded
91
+ puts "LOADING #{table_name}"
92
+ results = Puffs::DBConnection.execute(<<-SQL, sql_params[:values])
93
+ SELECT
94
+ #{sql_count ? "COUNT(*)" : self.table_name.to_s + ".*"}
95
+ FROM
96
+ #{self.table_name}
97
+ #{sql_params[:where]}
98
+ #{sql_params[:params]}
99
+ #{order_by_string}
100
+ #{"LIMIT #{sql_limit}" if sql_limit};
101
+ SQL
78
102
 
79
- def includes_params
80
- @includes_params ||= []
81
- end
103
+ results = sql_count ? results.first.values.first : parse_all(results)
104
+ end
82
105
 
83
- def limit(n)
84
- @sql_limit = n
85
- self
86
- end
106
+ results = results || self
87
107
 
88
- def load
89
- if !loaded
90
- puts "LOADING #{table_name}"
91
- results = DBConnection.execute(<<-SQL, sql_params[:values])
92
- SELECT
93
- #{sql_count ? "COUNT(*)" : self.table_name.to_s + ".*"}
94
- FROM
95
- #{self.table_name}
96
- #{sql_params[:where]}
97
- #{sql_params[:params]}
98
- #{order_by_string}
99
- #{"LIMIT #{sql_limit}" if sql_limit};
100
- SQL
108
+ unless includes_params.empty?
109
+ results = load_includes(results)
110
+ end
101
111
 
102
- results = sql_count ? results.first.values.first : parse_all(results)
112
+ results
103
113
  end
104
114
 
105
- results = results || self
115
+ def load_includes(relation)
116
+ includes_params.each do |param|
117
+ if relation.klass.has_association?(param)
118
+ puts "LOADING #{param.to_s}"
119
+ assoc = klass.assoc_options[param]
120
+ f_k = assoc.foreign_key
121
+ p_k = assoc.primary_key
122
+ includes_table = assoc.table_name.to_s
123
+ in_ids = relation.collection.map do |sqlobject|
124
+ sqlobject.id
125
+ end.join(", ")
126
+
127
+ has_many = assoc.class == HasManyOptions
128
+
129
+ results = Puffs::DBConnection.execute(<<-SQL)
130
+ SELECT
131
+ #{includes_table}.*
132
+ FROM
133
+ #{includes_table}
134
+ WHERE
135
+ #{includes_table}.#{has_many ? f_k : p_k}
136
+ IN
137
+ (#{in_ids});
138
+ SQL
139
+ included = assoc.model_class.parse_all(results)
140
+ SQLRelation.build_association(relation, included, param)
141
+ end
142
+ end
106
143
 
107
- unless includes_params.empty?
108
- results = load_includes(results)
144
+ relation
109
145
  end
110
146
 
111
- results
112
- end
147
+ def method_missing(method, *args, &block)
148
+ self.to_a.send(method, *args, &block)
149
+ end
113
150
 
114
- def load_includes(relation)
115
- includes_params.each do |param|
116
- if relation.klass.has_association?(param)
117
- puts "LOADING #{param.to_s}"
118
- assoc = klass.assoc_options[param]
119
- f_k = assoc.foreign_key
120
- p_k = assoc.primary_key
121
- includes_table = assoc.table_name.to_s
122
- in_ids = relation.collection.map do |sqlobject|
123
- sqlobject.id
124
- end.join(", ")
125
-
126
- has_many = assoc.class == HasManyOptions
127
-
128
- results = DBConnection.execute(<<-SQL)
129
- SELECT
130
- #{includes_table}.*
131
- FROM
132
- #{includes_table}
133
- WHERE
134
- #{includes_table}.#{has_many ? f_k : p_k}
135
- IN
136
- (#{in_ids});
137
- SQL
138
- included = assoc.model_class.parse_all(results)
139
- Puffs::SQLRelation.build_association(relation, included, param)
151
+ def order(params)
152
+ if params.is_a?(Hash)
153
+ order_params_hash.merge!(params)
154
+ else
155
+ order_params_hash.merge!(params => :asc)
140
156
  end
157
+ self
141
158
  end
142
159
 
143
- relation
144
- end
145
-
146
- def method_missing(method, *args, &block)
147
- self.to_a.send(method, *args, &block)
148
- end
149
-
150
- def order(params)
151
- if params.is_a?(Hash)
152
- order_params_hash.merge!(params)
153
- else
154
- order_params_hash.merge!(params => :asc)
160
+ def order_params_hash
161
+ @order_params_hash ||= {}
155
162
  end
156
- self
157
- end
158
163
 
159
- def order_params_hash
160
- @order_params_hash ||= {}
161
- end
164
+ def order_by_string
165
+ hash_string = order_params_hash.map do |column, asc_desc|
166
+ "#{column} #{asc_desc.to_s.upcase}"
167
+ end.join(", ")
162
168
 
163
- def order_by_string
164
- hash_string = order_params_hash.map do |column, asc_desc|
165
- "#{column} #{asc_desc.to_s.upcase}"
166
- end.join(", ")
169
+ hash_string.empty? ? "" : "ORDER BY #{hash_string}"
170
+ end
167
171
 
168
- hash_string.empty? ? "" : "ORDER BY #{hash_string}"
169
- end
172
+ def parse_all(attributes)
173
+ klass.parse_all(attributes).where(where_params_hash).includes(includes_params)
174
+ end
170
175
 
171
- def parse_all(attributes)
172
- klass.parse_all(attributes).where(where_params_hash).includes(includes_params)
173
- end
176
+ def sql_params
177
+ params, values = [], []
174
178
 
175
- def sql_params
176
- params, values = [], []
179
+ i = 1
180
+ where_params_hash.map do |attribute, value|
181
+ params << "#{attribute} = $#{i}"
182
+ values << value
183
+ i += 1
184
+ end
177
185
 
178
- i = 1
179
- where_params_hash.map do |attribute, value|
180
- params << "#{attribute} = $#{i}"
181
- values << value
182
- i += 1
186
+ { params: params.join(" AND "),
187
+ where: params.empty? ? nil : "WHERE",
188
+ values: values }
183
189
  end
184
190
 
185
- { params: params.join(" AND "),
186
- where: params.empty? ? nil : "WHERE",
187
- values: values }
188
- end
189
-
190
- def table_name
191
- klass.table_name
192
- end
191
+ def table_name
192
+ klass.table_name
193
+ end
193
194
 
194
- def to_a
195
- self.load.collection
196
- end
195
+ def to_a
196
+ self.load.collection
197
+ end
197
198
 
198
- def where_params_hash
199
- @where_params_hash ||= {}
200
- end
199
+ def where_params_hash
200
+ @where_params_hash ||= {}
201
+ end
201
202
 
202
- def where(params)
203
- where_params_hash.merge!(params)
204
- self
203
+ def where(params)
204
+ where_params_hash.merge!(params)
205
+ self
206
+ end
205
207
  end
206
208
  end
data/lib/router.rb CHANGED
@@ -1,74 +1,78 @@
1
- class Route
2
- attr_reader :pattern, :http_method, :controller_class, :action_name
1
+ module Puffs
2
+ # The Puffs Router.
3
+ class Router
4
+ attr_reader :routes
3
5
 
4
- def initialize(pattern, http_method, controller_class, action_name)
5
- @pattern = pattern
6
- @http_method = http_method
7
- @controller_class = controller_class
8
- @action_name = action_name
9
- end
10
-
11
- # checks if pattern matches path and method matches request method
12
- def matches?(req)
13
- pattern =~ req.path && req.request_method == http_method.to_s.upcase
14
- end
15
-
16
- # use pattern to pull out route params (save for later?)
17
- # instantiate controller and call controller action
18
- def run(req, res)
19
- matches = pattern.match(req.path)
20
- route_params = {}
6
+ def initialize
7
+ @routes = []
8
+ end
21
9
 
22
- matches.names.each do |name|
23
- route_params[name] = matches[name]
10
+ # Adds a new route to the list of routes
11
+ def add_route(pattern, method, controller_class, action_name)
12
+ routes << Route.new(pattern, method, controller_class, action_name)
24
13
  end
25
14
 
26
- controller_class.new(req, res, route_params).invoke_action(action_name)
27
- end
28
- end
15
+ # evaluate the proc in the context of the instance
16
+ # for syntactic sugar :)
17
+ def draw(&proc)
18
+ instance_eval(&proc)
19
+ end
29
20
 
30
- class Router
31
- attr_reader :routes
21
+ # make each of these methods that
22
+ # when called add route
23
+ [:get, :post, :put, :delete].each do |http_method|
24
+ define_method(http_method) do |pattern, controller_class, action_name|
25
+ add_route(pattern, http_method, controller_class, action_name)
26
+ end
27
+ end
32
28
 
33
- def initialize
34
- @routes = []
35
- end
29
+ # should return the route that matches this request
30
+ def match(req)
31
+ routes.each do |route|
32
+ return route if route.matches?(req)
33
+ end
34
+ nil
35
+ end
36
36
 
37
- # simply adds a new route to the list of routes
38
- def add_route(pattern, method, controller_class, action_name)
39
- routes << Route.new(pattern, method, controller_class, action_name)
37
+ # either throw 404 or call run on a matched route
38
+ def run(req, res)
39
+ route = match(req)
40
+ if route
41
+ route.run(req, res)
42
+ else
43
+ res.status = 404
44
+ res.body = ["Sorry, Charlie. That page doesn't exist."]
45
+ end
46
+ end
40
47
  end
41
48
 
42
- # evaluate the proc in the context of the instance
43
- # for syntactic sugar :)
44
- def draw(&proc)
45
- instance_eval(&proc)
46
- end
49
+ # Router is comprised of Routes.
50
+ class Route
51
+ attr_reader :pattern, :http_method, :controller_class, :action_name
47
52
 
48
- # make each of these methods that
49
- # when called add route
50
- [:get, :post, :put, :delete].each do |http_method|
51
- define_method(http_method) do |pattern, controller_class, action_name|
52
- add_route(pattern, http_method, controller_class, action_name)
53
+ def initialize(pattern, http_method, controller_class, action_name)
54
+ @pattern = pattern
55
+ @http_method = http_method
56
+ @controller_class = controller_class
57
+ @action_name = action_name
53
58
  end
54
- end
55
59
 
56
- # should return the route that matches this request
57
- def match(req)
58
- routes.each do |route|
59
- return route if route.matches?(req)
60
+ # checks if pattern matches path and method matches request method
61
+ def matches?(req)
62
+ pattern =~ req.path && req.request_method == http_method.to_s.upcase
60
63
  end
61
- nil
62
- end
63
64
 
64
- # either throw 404 or call run on a matched route
65
- def run(req, res)
66
- route = match(req)
67
- if route
68
- route.run(req, res)
69
- else
70
- res.status = 404
71
- res.body = ["Sorry, Charlie. That page doesn't exist."]
65
+ # use pattern to pull out route params (save for later?)
66
+ # instantiate controller and call controller action
67
+ def run(req, res)
68
+ matches = pattern.match(req.path)
69
+ route_params = {}
70
+
71
+ matches.names.each do |name|
72
+ route_params[name] = matches[name]
73
+ end
74
+
75
+ controller_class.new(req, res, route_params).invoke_action(action_name)
72
76
  end
73
77
  end
74
78
  end
@@ -1,18 +1,21 @@
1
1
  require 'rack'
2
2
  require './config/routes'
3
3
 
4
- class ServerConnection
5
- def self.start
6
- app = Proc.new do |env|
7
- req = Rack::Request.new(env)
8
- res = Rack::Response.new
9
- ROUTER.run(req, res)
10
- res.finish
11
- end
4
+ module Puffs
5
+ # Invoked through `puffs server` in CLI.
6
+ class ServerConnection
7
+ def self.start
8
+ app = proc do |env|
9
+ req = Rack::Request.new(env)
10
+ res = Rack::Response.new
11
+ ROUTER.run(req, res)
12
+ res.finish
13
+ end
12
14
 
13
- Rack::Server.start(
14
- app: app,
15
- Port: 3000
16
- )
15
+ Rack::Server.start(
16
+ app: app,
17
+ Port: 3000
18
+ )
19
+ end
17
20
  end
18
21
  end
data/lib/session.rb CHANGED
@@ -1,28 +1,36 @@
1
1
  require 'json'
2
2
 
3
- class Session
4
- # find the cookie for this app
5
- # deserialize the cookie into a hash
6
- def initialize(req)
7
- cookie = req.cookies['_rails_lite_app']
8
- if cookie
9
- @session_data = JSON.parse(cookie)
10
- else
11
- @session_data = {}
3
+ module Puffs
4
+ # Session token.
5
+ class Session
6
+ # find the cookie for this app
7
+ # deserialize the cookie into a hash
8
+ def initialize(req)
9
+ cookie = req.cookies['_rails_lite_app']
10
+
11
+ if cookie
12
+ @session_data = JSON.parse(cookie)
13
+ else
14
+ @session_data = {}
15
+ end
12
16
  end
13
- end
14
17
 
15
- def [](key)
16
- @session_data[key]
17
- end
18
+ def [](key)
19
+ @session_data[key]
20
+ end
18
21
 
19
- def []=(key, val)
20
- @session_data[key] = val
21
- end
22
+ def []=(key, val)
23
+ @session_data[key] = val
24
+ end
22
25
 
23
- # serialize the hash into json and save in a cookie
24
- # add to the responses cookies
25
- def store_session(res)
26
- res.set_cookie("_rails_lite_app", { path: '/', value: @session_data.to_json })
26
+ # serialize the hash into json and save in a cookie
27
+ # add to the responses cookies
28
+ def store_session(res)
29
+ res.set_cookie(
30
+ '_rails_lite_app',
31
+ path: '/',
32
+ value: @session_data.to_json
33
+ )
34
+ end
27
35
  end
28
36
  end