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.
- checksums.yaml +7 -0
- data/.codeclimate.yml +2 -0
- data/.gitignore +11 -0
- data/.rspec +2 -0
- data/.rubocop.yml +237 -0
- data/.travis.yml +4 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +73 -0
- data/Rakefile +6 -0
- data/bin/matrack +7 -0
- data/bin/setup +7 -0
- data/circle.yml +6 -0
- data/generators/generate/Gemfile +3 -0
- data/generators/generate/README.md +20 -0
- data/generators/generate/application.html.erb +18 -0
- data/generators/generate/application.rb +19 -0
- data/generators/generate/application_controller.rb +3 -0
- data/generators/generate/config.ru +12 -0
- data/generators/generate/invalid.html.erb +24 -0
- data/generators/generate/routes.rb +11 -0
- data/generators/generator.rb +78 -0
- data/generators/generator_base.rb +14 -0
- data/generators/mvc_gen.rb +57 -0
- data/index.html +604 -0
- data/lib/matrack.rb +32 -0
- data/lib/matrack/base_controller.rb +63 -0
- data/lib/matrack/dependencies.rb +6 -0
- data/lib/matrack/helper_tags.rb +59 -0
- data/lib/matrack/route.rb +15 -0
- data/lib/matrack/router.rb +42 -0
- data/lib/matrack/session.rb +21 -0
- data/lib/matrack/utility.rb +33 -0
- data/lib/matrack/version.rb +3 -0
- data/lib/orm/base_model.rb +57 -0
- data/lib/orm/data_manager.rb +57 -0
- data/lib/orm/data_utility.rb +33 -0
- data/lib/orm/fetch_queries.rb +53 -0
- data/lib/orm/queries.rb +47 -0
- data/lib/resources.rb +16 -0
- data/matrack.gemspec +43 -0
- metadata +268 -0
data/lib/matrack.rb
ADDED
@@ -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,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,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
|