matrack 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,32 @@
1
+ require_relative "resources"
2
+
3
+ module Matrack
4
+ class Application
5
+ attr_reader :router
6
+
7
+ def initialize
8
+ @router = Router.new
9
+ end
10
+
11
+ def call(env)
12
+ route = router.route_for(env)
13
+ if route
14
+ route.execute(env)
15
+ response_handler(route)
16
+ else
17
+ controller = BaseController.new(env)
18
+ body = controller.invalid_route
19
+ [404, {}, [body]]
20
+ end
21
+ end
22
+
23
+ def response_handler(route)
24
+ controller = route.mat_controller
25
+ if controller.response
26
+ controller.response
27
+ else
28
+ controller.render(route.action)
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,63 @@
1
+ module Matrack
2
+ class BaseController
3
+ include Matrack::HelperTags
4
+ attr_reader :request, :response
5
+ attr_accessor :session
6
+
7
+ def initialize(env)
8
+ @request = Rack::Request.new(env)
9
+ @session = Session.new(env)
10
+ end
11
+
12
+ def params
13
+ request.params
14
+ end
15
+
16
+ def create_response(body, status = 200, headers = {})
17
+ @response = Rack::Response.new body, status, headers
18
+ end
19
+
20
+ def render(*args)
21
+ create_response(render_template(*args))
22
+ end
23
+
24
+ def render_template(view_name, locals = {})
25
+ template = Tilt::ERBTemplate.new(File.join(APP_PATH, "app", "views",
26
+ "layout", "application.html.erb"))
27
+ title = view_name.to_s.tr("_", " ").capitalize
28
+ view = "#{view_name}.html.erb"
29
+ view_template = Tilt::ERBTemplate.new(File.join(APP_PATH, "app", "views",
30
+ controller_name, view))
31
+ template.render(self, title: title) do
32
+ view_template.render(self, locals.merge!(get_instance_vars))
33
+ end
34
+ end
35
+
36
+ def invalid_route
37
+ template = Tilt::ERBTemplate.new(File.join(APP_PATH, "app", "views",
38
+ "layout", "invalid.html.erb"))
39
+ template.render(self)
40
+ end
41
+
42
+ def get_instance_vars
43
+ vars = {}
44
+ instance_variables.each do |var|
45
+ key = var.to_s.delete("@").to_sym
46
+ vars[key] = instance_variable_get(var)
47
+ end
48
+ vars
49
+ end
50
+
51
+ def controller_name
52
+ self.class.to_s.gsub(/Controller$/, "").to_snake_case
53
+ end
54
+
55
+ def authenticate(password)
56
+ Matrack::DataManager.password_hash(password)
57
+ end
58
+
59
+ def redirect_to(address)
60
+ create_response([], 302, "location" => address)
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,6 @@
1
+ class ::Object
2
+ def self.const_missing(const)
3
+ require const.to_s.to_snake_case
4
+ const_get(const)
5
+ end
6
+ end
@@ -0,0 +1,59 @@
1
+ module Matrack
2
+ module HelperTags
3
+
4
+ def email_validator
5
+ '[A-Za-z0-9_\-\.]+\@[A-Za-z0-9_\-\.]+\.[A-Za-z]{2,4}'
6
+ end
7
+
8
+ def textbox_tag(name, value = "", class_name = "", holder = "", req = nil,
9
+ disabled = nil)
10
+ tag = "<input type='text' name='#{name}' value='#{value}' "
11
+ tag += "placeholder='#{holder}' class='#{class_name}'"
12
+ tag += "required='#{req}'" unless req.nil?
13
+ tag += disabled.nil? ? ">" : " disabled='#{disabled}'>"
14
+ end
15
+
16
+ def password_tag(name, class_name = "", holder = "", req = nil,
17
+ disabled = nil)
18
+ tag = "<input type='password' name='#{name}' "
19
+ tag += "placeholder='#{holder}' class='#{class_name}'"
20
+ tag += "required='#{req}'" unless req.nil?
21
+ tag += disabled.nil? ? ">" : " disabled='#{disabled}'>"
22
+ end
23
+
24
+ def emailbox_tag(name, value = "", class_name = "", holder = "", req = nil,
25
+ disabled = nil, pattern = nil)
26
+ tag = "<input type='email' name='#{name}' value='#{value}' "
27
+ tag += "placeholder='#{holder}' class='#{class_name}'"
28
+ tag += "required='#{req}'" unless req.nil?
29
+ regex_pattern = pattern.nil? ? "#{email_validator}" : "#{pattern}"
30
+ tag += " pattern='#{regex_pattern}'"
31
+ tag += disabled.nil? ? ">" : " disabled='#{disabled}'>"
32
+ end
33
+
34
+ def submit_tag(name, value = "Submit", class_name = "")
35
+ tag = "<input type='submit' name='#{name}' value='#{value}' "
36
+ tag += "class='#{class_name}'>"
37
+ end
38
+
39
+ def link_tag(ref, class_name = "", title = "Link")
40
+ "<a href='#{ref}' class='#{class_name}'>#{title}</a>"
41
+ end
42
+
43
+ def image_tag(name, alt = "image")
44
+ "<img src='../../images/#{name}' alt= '#{alt}'>"
45
+ end
46
+
47
+ def include_stylesheet(name)
48
+ "<link href='../../css/#{name}.css' rel='stylesheet' type= 'text/css'>"
49
+ end
50
+
51
+ def include_javascript(name)
52
+ "<script src='../../js/#{name}.js' type='text/javascript'></script>"
53
+ end
54
+
55
+ def display_favicon
56
+ "<link rel='icon' type='image/png' href='../../images/favicon.png' />"
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,15 @@
1
+ class Route
2
+ attr_reader :matclass, :action, :mat_controller
3
+
4
+ def initialize(route_info)
5
+ matklass = route_info.last[:matclass].to_camel_case
6
+ @matclass = Object.const_get(matklass+"Controller")
7
+ @path = route_info.first
8
+ @action = route_info.last[:method].to_sym
9
+ end
10
+
11
+ def execute(env)
12
+ @mat_controller = matclass.new(env)
13
+ @mat_controller.send(action)
14
+ end
15
+ end
@@ -0,0 +1,42 @@
1
+ class Router
2
+ attr_reader :routes
3
+
4
+ def initialize
5
+ @routes = Hash.new { |hash, key| hash[key] = [] }
6
+ end
7
+
8
+ def draw(&block)
9
+ instance_eval(&block)
10
+ end
11
+
12
+ def root(root_path)
13
+ get "/", root_path
14
+ end
15
+
16
+ %w(get post put delete).each do |request_type|
17
+ define_method(request_type) do | path, options|
18
+ request_type = request_type.to_sym
19
+ if options.is_a? Hash
20
+ @routes[request_type] << [path, case_parser(options[:to])]
21
+ else
22
+ @routes[request_type] << [path, case_parser(options)]
23
+ end
24
+ end
25
+ end
26
+
27
+ def route_for(env)
28
+ path = env["PATH_INFO"]
29
+ verb = env["REQUEST_METHOD"].downcase.to_sym
30
+ route_info = routes[verb].detect do |route|
31
+ route.first == path || route.first == path.sub("/", "")
32
+ end
33
+ Route.new(route_info) if route_info
34
+ end
35
+
36
+ private
37
+
38
+ def case_parser(str)
39
+ matclass, method = str.split("#")
40
+ { matclass: matclass.to_camel_case, method: method.to_snake_case }
41
+ end
42
+ end
@@ -0,0 +1,21 @@
1
+ module Matrack
2
+ class Session
3
+ attr_accessor :request
4
+
5
+ def initialize(env)
6
+ @request = Rack::Request.new(env)
7
+ end
8
+
9
+ def [](key)
10
+ request.session[key.to_sym]
11
+ end
12
+
13
+ def []=(key, value)
14
+ request.session[key.to_sym] = value
15
+ end
16
+
17
+ def clear
18
+ request.session.clear
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,33 @@
1
+ class ::String
2
+ def to_snake_case
3
+ gsub("::", "/").
4
+ gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2').
5
+ gsub(/([a-z\d])([A-Z])/, '\1_\2').tr("-", "_").downcase
6
+ end
7
+
8
+ def to_camel_case
9
+ return self if self !~ /_/ && self =~ /[A-Z]+.*/
10
+ split("_").map(&:capitalize).join
11
+ end
12
+
13
+ def to_b
14
+ return true if !self.nil? && (self == true || downcase == "true")
15
+ return false if self.nil? || downcase == "false" || self == false
16
+ false
17
+ end
18
+
19
+ def titleize
20
+ split.map!(&:capitalize).join(" ")
21
+ end
22
+
23
+ def pluralize
24
+ self + "s" unless self.end_with? "s"
25
+ end
26
+
27
+ end
28
+
29
+ class ::Array
30
+ def hash_getter
31
+ first.select{|k| k.is_a? String}
32
+ end
33
+ end
@@ -0,0 +1,3 @@
1
+ module Matrack
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,57 @@
1
+ module Matrack
2
+ class BaseModel < Queries
3
+ def initialize(hash = {})
4
+ hash.each_pair { |k,v| send("#{k}=", v) }
5
+ self
6
+ end
7
+
8
+ @@query_string = ""
9
+
10
+ class << self
11
+
12
+ def create_table
13
+ query_string = @@query_string.sub(/,[\s]$/,"")
14
+ create_table_fields(table_name,query_string)
15
+ @@query_string = ""
16
+ end
17
+
18
+ def property(name, type = "str", desc = {} )
19
+ field_hash = { name => type }
20
+ if verify_col_type(field_hash) == true
21
+ db_str = DataUtility.type_mapper(field_hash)
22
+ @@query_string += query_builder(db_str.keys, db_str.values, desc)
23
+ @@query_string += ", " unless @@query_string == ""
24
+ get_and_set_property(name)
25
+ else
26
+ puts db_error(verify_col_type(field_hash))
27
+ exit
28
+ end
29
+ end
30
+
31
+ def get_and_set_property(name)
32
+ define_method(name) do
33
+ instance_variable_get("@#{name}")
34
+ end
35
+ define_method("#{name}=") do |value|
36
+ instance_variable_set("@#{name}", "#{value}")
37
+ end
38
+ end
39
+
40
+ def create(field_hash)
41
+ passwordify(field_hash)
42
+ attributes = "#{field_hash.keys}".gsub(/:/, "").gsub(/\[|\]/,"")
43
+ values = "#{field_hash.values}".gsub(/\[|\]/,"").gsub(/\"/,"'")
44
+ db_conn.execute "INSERT INTO #{table_name} (#{attributes}) VALUES (#{
45
+ values});"
46
+ end
47
+
48
+ def passwordify(field_hash)
49
+ if field_hash.keys.include? :password
50
+ hashed_pass = password_hash(field_hash[:password])
51
+ field_hash[:password] = hashed_pass
52
+ end
53
+ field_hash
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,57 @@
1
+ require "sqlite3"
2
+ require "digest/sha1"
3
+
4
+ module Matrack
5
+ class DataManager
6
+
7
+ class << self
8
+ def db_conn
9
+ db = SQLite3::Database.new "#{APP_PATH}/db/app.sqlite3"
10
+ db.results_as_hash = true
11
+ db
12
+ end
13
+
14
+ def db_error(message)
15
+ DataUtility.db_error(message)
16
+ end
17
+
18
+ def query_builder(name, type, desc)
19
+ name = name.join
20
+ type = type.join
21
+ primary_key = "PRIMARY KEY" if desc[:primary_key] == true
22
+ primary_key += " AUTOINCREMENT" if desc[:primary_key] == true &&
23
+ type == "INTEGER"
24
+ primary_key = primary_key ? primary_key : ""
25
+ null_value = desc[:nullable].nil? ? "NULL" : "NOT NULL"
26
+ null_value = "NOT NULL" if desc[:primary_key] == true
27
+ "#{name} #{type} #{primary_key} #{null_value}"
28
+ end
29
+
30
+ def allowed_field_types
31
+ ["int", "str", "time", "date"]
32
+ end
33
+
34
+ def create_table_fields(table_name, qry_str)
35
+ begin
36
+ db_conn.execute "CREATE TABLE IF NOT EXISTS #{table_name} (#{qry_str});"
37
+ rescue
38
+ puts db_error("Can not create table")
39
+ exit
40
+ end
41
+ end
42
+
43
+ def verify_col_type(field_hash)
44
+ return true if valid_col_types?(field_hash)
45
+ "Invalid column type(s) specified"
46
+ end
47
+
48
+ def valid_col_types?(field_hash)
49
+ field_hash.values.all? { |val| allowed_field_types.include? val.to_s }
50
+ end
51
+
52
+ def password_hash(password)
53
+ Digest::SHA1.hexdigest(password)
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,33 @@
1
+ class DataUtility
2
+ class << self
3
+ def type_mapper(field_hash)
4
+ db_data = {}
5
+ field_hash.each_pair do |k, v|
6
+ v = v.to_s
7
+ if v == "str" || v == "time" || v == "date"
8
+ db_data[k] = "VARCHAR"
9
+ elsif v == "int"
10
+ db_data[k] = "INTEGER"
11
+ end
12
+ end
13
+ db_data
14
+ end
15
+
16
+ def create_table_query(db_data)
17
+ db_str = ""
18
+ db_data.each_pair do |k,v|
19
+ db_str +=" " + "#{k}" + " " + "#{v}"
20
+ db_str += "," unless k == db_data.keys.last
21
+ end
22
+ db_str
23
+ end
24
+
25
+ def db_error(message)
26
+ <<-EOS
27
+ *************************************************
28
+ DB ERROR - #{message.to_s.titleize}
29
+ *************************************************
30
+ EOS
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,53 @@
1
+ module Matrack
2
+ class FetchQueries < DataManager
3
+ class << self
4
+ def table_name
5
+ self.to_s.to_snake_case + "s"
6
+ end
7
+
8
+ def uniq_id
9
+ "#{self.to_s.to_snake_case}_id"
10
+ end
11
+
12
+ def execute(query)
13
+ objs = []
14
+ rows = db_conn.execute query
15
+ rows.each{|row| objs << self.new(row.reject!{ |k| !k.is_a? String }) }
16
+ objs
17
+ end
18
+
19
+ def all
20
+ execute "SELECT * FROM #{table_name}"
21
+ end
22
+
23
+ def find(id)
24
+ execute("SELECT * FROM #{table_name} WHERE (#{uniq_id} = #{id})").first
25
+ end
26
+
27
+ def last
28
+ offset = count - 1
29
+ execute("SELECT * FROM #{table_name} LIMIT(1) OFFSET(#{offset})").first
30
+ end
31
+
32
+ def limit(num)
33
+ execute "SELECT * FROM #{table_name} LIMIT(#{num})"
34
+ end
35
+
36
+ def first
37
+ execute("SELECT * FROM #{table_name} LIMIT(1)").first
38
+ end
39
+
40
+ def find_by(col, val)
41
+ execute("SELECT * FROM #{table_name} WHERE (#{col} = '#{val}')
42
+ LIMIT 1").first
43
+ end
44
+
45
+ # firstname: "name", lastname: "last"
46
+ def find_cols(col_hash)
47
+ clause = col_hash.map{|k,v| "#{k.to_s} = " "'#{v}'"}.join(" AND ")
48
+ execute("SELECT * FROM #{table_name} WHERE (#{clause})
49
+ LIMIT 1").first
50
+ end
51
+ end
52
+ end
53
+ end