tgauge 0.1.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.
@@ -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