tgauge 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,163 @@
1
+ require 'active_support/inflector'
2
+ require_relative 'searchable'
3
+ require_relative 'associatable'
4
+ require_relative '../../db/db_connection'
5
+
6
+ module TGauge
7
+ class TRecordBase
8
+ extend Associatable
9
+ extend Searchable
10
+
11
+ def self.my_attr_accessor(*names)
12
+ names.each do |name|
13
+ define_method(name) do
14
+ instance_variable_get("@" + name.to_s)
15
+ end
16
+
17
+ define_method(name.to_s + "=") do |arg|
18
+ instance_variable_set("@" + name.to_s, arg)
19
+ end
20
+ end
21
+ end
22
+
23
+ def self.my_attr_reader(*names)
24
+ names.each do |name|
25
+ define_method(name) do
26
+ instance_variable_get("@" + name.to_s)
27
+ end
28
+ end
29
+ end
30
+
31
+ def self.columns
32
+ # ...
33
+ return @columns if @columns
34
+
35
+ arr = DBConnection.execute(<<-SQL)
36
+ SELECT
37
+ *
38
+ FROM
39
+ #{self.table_name}
40
+ SQL
41
+
42
+ @columns = []
43
+ arr.nfields.times do |i|
44
+ @columns << arr.fname(i)
45
+ end
46
+
47
+ @columns
48
+ end
49
+
50
+ def self.finalize!
51
+ columns.each do |column|
52
+ inst_var = "@" + column.to_s
53
+ define_method(column) do
54
+ attributes[column]
55
+ end
56
+ define_method(column.to_s + "=") do |arg|
57
+ attributes[column] = arg
58
+ end
59
+ end
60
+ end
61
+
62
+ def self.table_name=(table_name)
63
+ @table_name = table_name
64
+ end
65
+
66
+ def self.table_name
67
+ @table_name = @table_name || self.to_s.tableize
68
+ end
69
+
70
+ def self.all
71
+ objs_arr = DBConnection.execute(<<-SQL)
72
+ SELECT
73
+ #{table_name}.*
74
+ FROM
75
+ #{table_name}
76
+ SQL
77
+
78
+ parse_all(objs_arr)
79
+ end
80
+
81
+ def self.parse_all(results)
82
+ # ...
83
+ results.map { |obj_hash| self.new(obj_hash) }
84
+ end
85
+
86
+ def self.find(id)
87
+ obj = DBConnection.execute(<<-SQL, id)
88
+ SELECT
89
+ #{table_name}.*
90
+ FROM
91
+ #{table_name}
92
+ WHERE
93
+ #{table_name}.id = ?
94
+ SQL
95
+
96
+ parse_all(obj).first
97
+ end
98
+
99
+ def initialize(params = {})
100
+ # ...
101
+ params.each do |att_name, val|
102
+ att_name = att_name.to_sym
103
+ raise "unknown attribute '#{att_name}'" unless columns.include?(att_name.to_s)
104
+ self.send(att_name.to_s + "=", val)
105
+ end
106
+ end
107
+
108
+ def attributes
109
+ @attributes ||= {}
110
+ end
111
+
112
+ def attribute_values
113
+ attributes.values
114
+ end
115
+
116
+ def insert
117
+ cols = columns.reject { |col| col == "id" }
118
+ attr_count = cols.count
119
+ column_str = cols.join(", ")
120
+ quest_str = Array.new(attr_count) {"?"}.join(", ")
121
+ debugger
122
+ DBConnection.execute(<<-SQL, attribute_values)
123
+ INSERT INTO
124
+ #{table_name} (#{column_str})
125
+ VALUES
126
+ (#{quest_str})
127
+ SQL
128
+ end
129
+
130
+ def update
131
+ attr_count = columns.count - 1
132
+ column_str = columns[1..-1].map { |col| "#{col} = ?" }.join(", ")
133
+
134
+ DBConnection.execute(<<-SQL, attribute_values)
135
+ UPDATE
136
+ #{table_name}
137
+ SET
138
+ #{column_str}
139
+ WHERE
140
+ id = ?
141
+ SQL
142
+ end
143
+
144
+ def save
145
+ if attributes[:id]
146
+ update
147
+ else
148
+ insert
149
+ end
150
+ end
151
+
152
+ private
153
+
154
+ def columns
155
+ self.class.columns
156
+ end
157
+
158
+ def table_name
159
+ self.class.table_name
160
+ end
161
+
162
+ end
163
+ end
@@ -0,0 +1,99 @@
1
+ require 'pg'
2
+ require 'uri'
3
+ require 'yaml'
4
+
5
+ PRINT_QUERIES = ENV['PRINT_QUERIES'] == 'true'
6
+ MIGRATION_FILES = Dir.glob("./db/migrations/*.sql").to_a
7
+
8
+ module TGauge
9
+ class DBConnection
10
+ def self.app_name
11
+ YAML.load_file(Dir.pwd + '/config/database.yml')['database']
12
+ end
13
+
14
+ def self.open
15
+ @postgres = PG::Connection.new(
16
+ dbname: app_name,
17
+ port: 5432
18
+ )
19
+ end
20
+
21
+ def self.migrate
22
+ ensure_migrations_table
23
+
24
+ MIGRATION_FILES.each do |file|
25
+ filename = file.match(/([\w|-]*)\.sql$/)[1]
26
+
27
+ unless migrated_files.include?(filename)
28
+ instance.exec(File.read(file))
29
+ instance.exec(<<-SQL)
30
+ INSERT INTO
31
+ migrations (filename)
32
+ VALUES
33
+ ('#{filename}')
34
+ SQL
35
+ end
36
+ end
37
+ end
38
+
39
+ def self.instance
40
+ open if @db.nil?
41
+
42
+ @db
43
+ end
44
+
45
+ def self.execute(*args)
46
+ print_query(*args)
47
+ instance.execute(*args)
48
+ end
49
+
50
+ def self.last_insert_row_id
51
+ instance.last_insert_row_id
52
+ end
53
+
54
+ def self.reset
55
+ commands = [
56
+ "dropdb #{app_name}",
57
+ "createdb #{app_name}"
58
+ ]
59
+ commands.each { |command| `#{command}` }
60
+ end
61
+
62
+ private
63
+
64
+ def self.ensure_migrations_table
65
+ table = instance.exec(<<-SQL)
66
+ SELECT to_regclass('migrations') AS exists
67
+ SQL
68
+
69
+ unless table[0]['exists']
70
+ instance.exec(<<-SQL)
71
+ CREATE_TABLE migrations(
72
+ id SERIAL PRIMARY KEY,
73
+ filename VARCHAR(255) NOT NULL
74
+ )
75
+ SQL
76
+ end
77
+ end
78
+
79
+ def self.migrated_files
80
+ Set.new instance.exec(<<-SQL).values.flatten
81
+ SELECT
82
+ filename
83
+ FROM
84
+ migrations
85
+ SQL
86
+ end
87
+
88
+ def self.print_query(query, *interpolation_args)
89
+ return unless PRINT_QUERIES
90
+
91
+ puts '--------------------'
92
+ puts query
93
+ unless interpolation_args.empty?
94
+ puts "interpolate: #{interpolation_args.inspect}"
95
+ end
96
+ puts '--------------------'
97
+ end
98
+ end
99
+ end
data/lib/db/router.rb ADDED
@@ -0,0 +1,74 @@
1
+ class Route
2
+ attr_reader :pattern, :http_method, :controller_class, :action_name
3
+
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) == 0 && req.request_method.downcase == @http_method.to_s
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
+ match_data = @pattern.match(req.path)
20
+ route_params = {}
21
+ match_data.names.each do |key|
22
+ route_params[key] = match_data[key]
23
+ end
24
+
25
+ controller = controller_class.new(req, res, route_params)
26
+ controller.invoke_action(@action_name)
27
+ end
28
+ end
29
+
30
+ class Router
31
+ attr_reader :routes
32
+
33
+ def initialize
34
+ @routes = []
35
+ end
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)
40
+ end
41
+
42
+ # evaluate the proc in the context of the instance
43
+ # for syntactic sugar :)
44
+ def draw(&proc)
45
+ self.instance_eval(&proc)
46
+ end
47
+
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 |path, controller, action_name|
52
+ add_route(path, http_method, controller, action_name)
53
+ end
54
+ end
55
+
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
+ end
61
+ nil
62
+ end
63
+
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.write("Route #{req.path} could not be found.")
71
+ res.status = 404
72
+ end
73
+ end
74
+ end
data/lib/db/server.rb ADDED
@@ -0,0 +1,27 @@
1
+ require 'rack'
2
+ require_relative './config/routes'
3
+ require_relative 'lib/static_viewer'
4
+ require_relative 'lib/show_exceptions'
5
+
6
+ module TGauge
7
+ class Server
8
+ def self.start
9
+ app = Proc.new do |env|
10
+ req = Rack::Request.new(env)
11
+ res = Rack::Response.new
12
+ ROUTER.run(req, res)
13
+ res.finish
14
+ end
15
+
16
+ full_app = Rack::Builder.new do
17
+ use ShowExceptions
18
+ use StaticViewer
19
+ run app
20
+ end.to_app
21
+
22
+ Rack::Server.start({
23
+ app: full_app,
24
+ Port: 3000
25
+ })
26
+ end
27
+ end
@@ -0,0 +1,62 @@
1
+ require 'erb'
2
+ require 'byebug'
3
+
4
+ class ShowExceptions
5
+ attr_reader :app
6
+
7
+ def initialize(app)
8
+ @app = app
9
+ end
10
+
11
+ def call(env)
12
+ app.call(env)
13
+ rescue Exception => e
14
+ render_exception(e)
15
+ end
16
+
17
+ private
18
+
19
+ def render_exception(e)
20
+ dir_path = File.dirname(__FILE__)
21
+ template_fname = File.join(dir_path, "templates", "error_page.html.erb")
22
+ template = File.read(template_fname)
23
+ body = ERB.new(template).result(binding)
24
+
25
+ ['500', {'Content-type' => 'text/html'}, [body]]
26
+ end
27
+
28
+ def error_source_file(e)
29
+ stack_trace_top(e)[0]
30
+ end
31
+
32
+ def stack_trace_top(e)
33
+ e.backtrace[0].split(':')
34
+ end
35
+
36
+ def extract_formatted_source(e)
37
+ source_file_name = error_source_file(e)
38
+ source_line_num = source_line_num(e)
39
+ source_lines = extract_source(source_file_name)
40
+ format_source(source_lines, source_line_num)
41
+ end
42
+
43
+ def source_line_num(e)
44
+ stack_trace_top(e)[1].to_i
45
+ end
46
+
47
+ def formatted_source(file, source_line_num)
48
+ source_lines = extract_source(file)
49
+ format_source(source_lines, source_line_num)
50
+ end
51
+
52
+ def extract_source(file)
53
+ source_file = File.open(file, 'r')
54
+ source_file.readlines
55
+ end
56
+
57
+ def format_source(source_lines, source_line_num)
58
+ start = [0, source_line_num - 3].max
59
+ lines = source_lines[start..(start + 5)]
60
+ Hash[*(start+1..(lines.count + start)).zip(lines).flatten]
61
+ end
62
+ end
@@ -0,0 +1,52 @@
1
+ require 'rack'
2
+ require 'pathname'
3
+
4
+ class StaticViewer
5
+ FILE_TYPE = {
6
+ 'jpg' => 'image/jpeg',
7
+ 'zip' => 'application/zip',
8
+ 'png' => 'image/png',
9
+ 'txt' => 'text/plain'
10
+ }
11
+
12
+ def initialize(app)
13
+ @app = app
14
+ end
15
+
16
+ def call(env)
17
+ if is_public?(env)
18
+ req = Rack::Request.new(env)
19
+ res = Rack::Response.new
20
+
21
+ file_path = "#{req.path}"
22
+ build_response(res, file_path)
23
+ else
24
+ @app.call(env)
25
+ end
26
+ end
27
+
28
+ private
29
+ def build_response(res, file_path)
30
+ type = find_content_type(file_path)
31
+
32
+ if type && Pathname(file_path).exist?
33
+ res.write(File.open(file_path, 'r') { |f| (f.read) })
34
+ res['Content-Type'] = find_content_type(file_path)
35
+ res.finish
36
+ else
37
+ type ? res.write("Could not find file.") : res.write("Unsupported file type")
38
+ res.status = 404
39
+ res['Content-Type'] = 'text/html'
40
+ res.finish
41
+ end
42
+ end
43
+
44
+ def is_public?(env)
45
+ !!(Regexp.new("/public/*") =~ env["PATH_INFO"])
46
+ end
47
+
48
+ def find_content_type(path)
49
+ type = path.match(/\.(\w*)/)[1]
50
+ FILE_TYPE[type]
51
+ end
52
+ end
@@ -0,0 +1,62 @@
1
+ <head>
2
+ <style>
3
+ .header {
4
+ font-family: sans-serif;
5
+ background: #d00;
6
+ padding: 10px;
7
+ color: #fff;
8
+ }
9
+
10
+ .source-view {
11
+ border: 10px solid lightgray;
12
+ padding: 5px;
13
+ width: 800px;
14
+ }
15
+
16
+ .line {
17
+ white-space: pre-wrap;
18
+ font-family: sans-serif;
19
+ padding: 2px 0;
20
+ }
21
+
22
+ .line-num {
23
+ background: lightgray;
24
+ padding: 2px;
25
+ border-top: 1px solid #aaa;
26
+ }
27
+
28
+ .line.error {
29
+ background: #d00;
30
+ color: #fff;
31
+ }
32
+ </style>
33
+ </head>
34
+
35
+ <body>
36
+ <h2 class='header'><%=e.class%>: <%=e.message%></h2>
37
+
38
+ <h4>Extracted source (around line <b><%=source_line_num(e)%></b>):</h4>
39
+
40
+ <div class='source-view'>
41
+ <table cellpadding="0" cellspacing="0">
42
+ <% extract_formatted_source(e).each do |line_num, line| %>
43
+ <tr>
44
+ <td>
45
+ <pre class='line-num'><%=line_num %></pre>
46
+ </td>
47
+ <td>
48
+ <pre class='line
49
+ <%= 'error' if line_num == source_line_num(e)%>'><%= line %></pre>
50
+ </td>
51
+ </tr>
52
+ <% end %>
53
+ </table>
54
+ </div>
55
+ <h5><%= File.expand_path(error_source_file(e)) %></h5>
56
+
57
+ <h3>Stack trace</h3>
58
+ <% e.backtrace.each do |stack_line| %>
59
+ <%= stack_line %>
60
+ <br>
61
+ <% end %>
62
+ </body>
@@ -0,0 +1,3 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem "tgauge"
@@ -0,0 +1,7 @@
1
+ ROUTER = TGauge::Router.new
2
+
3
+ ROUTER.draw do
4
+ #ADD ROUTES HERE
5
+ #EXAMPLE:
6
+ #get Regexp.new("^/MODEL/"), CONTROLLER, :index
7
+ end
@@ -0,0 +1,7 @@
1
+ module TGauge
2
+ class Seed
3
+ def self.populate
4
+ #PUT IN SEEDS HERE
5
+ end
6
+ end
7
+ end
data/lib/tgauge.rb ADDED
@@ -0,0 +1,16 @@
1
+ module TGauge
2
+ end
3
+
4
+ require_relative './version.rb'
5
+
6
+ require_relative './app/models/trecord_base'
7
+ require_relative './app/controllers/tcontroller_base'
8
+
9
+ Dir.glob('./app/models/*.rb') { |file| require file }
10
+ Dir.glob('./app/controllers/*.rb') { |file| require file }
11
+
12
+ require './db/seeds'
13
+
14
+ require_relative './db/db_connection'
15
+ require_relative './db/router'
16
+ require_relative './db/server'
data/lib/version.rb ADDED
@@ -0,0 +1,3 @@
1
+ module TGauge
2
+ VERSION = "0.1.0"
3
+ end