reloj 0.1.1
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/.rspec +2 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +64 -0
- data/README.md +89 -0
- data/Rakefile +1 -0
- data/bin/reloj +66 -0
- data/lib/reloj/core/controller_base.rb +68 -0
- data/lib/reloj/core/flash.rb +38 -0
- data/lib/reloj/core/params.rb +52 -0
- data/lib/reloj/core/route_helper.rb +45 -0
- data/lib/reloj/core/router.rb +89 -0
- data/lib/reloj/core/session.rb +32 -0
- data/lib/reloj/orm/associatable.rb +70 -0
- data/lib/reloj/orm/associatable2.rb +34 -0
- data/lib/reloj/orm/db_connection.rb +59 -0
- data/lib/reloj/orm/model_base.rb +132 -0
- data/lib/reloj/orm/pg_db.rb +59 -0
- data/lib/reloj/orm/searchable.rb +26 -0
- data/lib/reloj/skeletons/common_files/Gemfile +6 -0
- data/lib/reloj/skeletons/common_files/Rakefile +25 -0
- data/lib/reloj/skeletons/new_app/app/controllers/.keep +0 -0
- data/lib/reloj/skeletons/new_app/app/models/.keep +0 -0
- data/lib/reloj/skeletons/new_app/app/views/.keep +0 -0
- data/lib/reloj/skeletons/new_app/config/routes.rb +7 -0
- data/lib/reloj/skeletons/new_app/db/.keep +0 -0
- data/lib/reloj/skeletons/sample_app/app/controllers/cats_controller.rb +24 -0
- data/lib/reloj/skeletons/sample_app/app/models/cat.rb +8 -0
- data/lib/reloj/skeletons/sample_app/app/views/cats_controller/index.html.erb +5 -0
- data/lib/reloj/skeletons/sample_app/app/views/cats_controller/new.html.erb +11 -0
- data/lib/reloj/skeletons/sample_app/config/routes.rb +10 -0
- data/lib/reloj/skeletons/sample_app/db/setup.sql +46 -0
- data/lib/reloj/version.rb +3 -0
- data/lib/reloj.rb +8 -0
- data/reloj.gemspec +41 -0
- metadata +206 -0
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'sqlite3'
|
2
|
+
|
3
|
+
# https://tomafro.net/2010/01/tip-relative-paths-with-file-expand-path
|
4
|
+
#ROOT_FOLDER = File.join(File.dirname(__FILE__), '../..')
|
5
|
+
ROOT_FOLDER = Dir.pwd
|
6
|
+
CATS_SQL_FILE = File.join(ROOT_FOLDER, 'app/cats.sql')
|
7
|
+
CATS_DB_FILE = File.join(ROOT_FOLDER, 'app/cats.db')
|
8
|
+
|
9
|
+
# This dbconnection was used for testing and is deprecated
|
10
|
+
# I might refactor this in the future, in order to have this orm support
|
11
|
+
# both sqlite3 ane psql
|
12
|
+
|
13
|
+
class DBConnection
|
14
|
+
def self.open(db_file_name)
|
15
|
+
@db = SQLite3::Database.new(db_file_name)
|
16
|
+
@db.results_as_hash = true
|
17
|
+
@db.type_translation = true
|
18
|
+
|
19
|
+
@db
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.reset
|
23
|
+
commands = [
|
24
|
+
"rm '#{CATS_DB_FILE}'",
|
25
|
+
"cat '#{CATS_SQL_FILE}' | sqlite3 '#{CATS_DB_FILE}'"
|
26
|
+
]
|
27
|
+
|
28
|
+
commands.each { |command| `#{command}` }
|
29
|
+
DBConnection.open(CATS_DB_FILE)
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.instance
|
33
|
+
reset if @db.nil?
|
34
|
+
|
35
|
+
@db
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.execute(*args)
|
39
|
+
# make this pretty print
|
40
|
+
puts args[0]
|
41
|
+
|
42
|
+
instance.execute(*args)
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.execute2(*args)
|
46
|
+
puts args[0]
|
47
|
+
|
48
|
+
instance.execute2(*args)
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.last_insert_row_id
|
52
|
+
instance.last_insert_row_id
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def initialize(db_file_name)
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,132 @@
|
|
1
|
+
require_relative 'db_connection'
|
2
|
+
require_relative 'pg_db'
|
3
|
+
require 'active_support/inflector'
|
4
|
+
|
5
|
+
class ModelBase
|
6
|
+
|
7
|
+
# rough idea on how to replace self.finalize!
|
8
|
+
# need to run at end of class definiton, not beginning
|
9
|
+
# def self.inherited(subclass)
|
10
|
+
# attr_writer(*subclass.columns)
|
11
|
+
# end
|
12
|
+
|
13
|
+
def self.columns
|
14
|
+
result = Database.execute(<<-SQL)
|
15
|
+
SELECT
|
16
|
+
*
|
17
|
+
FROM
|
18
|
+
#{self.table_name}
|
19
|
+
LIMIT
|
20
|
+
0;
|
21
|
+
SQL
|
22
|
+
|
23
|
+
result.fields.map(&:to_sym)
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.finalize!
|
27
|
+
self.columns.each do |column|
|
28
|
+
define_method("#{column}=") do |val|
|
29
|
+
attributes[column] = val
|
30
|
+
end
|
31
|
+
define_method(column) do
|
32
|
+
attributes[column]
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.table_name=(table_name)
|
38
|
+
@table_name = table_name
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.table_name
|
42
|
+
@table_name || self.to_s.tableize
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.all
|
46
|
+
results_array = Database.execute(<<-SQL)
|
47
|
+
SELECT
|
48
|
+
*
|
49
|
+
FROM
|
50
|
+
#{table_name};
|
51
|
+
SQL
|
52
|
+
|
53
|
+
self.parse_all(results_array)
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.parse_all(results)
|
57
|
+
# TODO: rewrite with map
|
58
|
+
answer = []
|
59
|
+
results.each do |result|
|
60
|
+
answer << self.new(result)
|
61
|
+
end
|
62
|
+
answer
|
63
|
+
end
|
64
|
+
|
65
|
+
def self.find(id)
|
66
|
+
x = Database.execute(<<-SQL, id)
|
67
|
+
SELECT
|
68
|
+
*
|
69
|
+
FROM
|
70
|
+
#{table_name}
|
71
|
+
WHERE
|
72
|
+
id = ?;
|
73
|
+
SQL
|
74
|
+
|
75
|
+
x.empty? ? nil : self.new(x.first)
|
76
|
+
end
|
77
|
+
|
78
|
+
def initialize(params = {})
|
79
|
+
params.each do |column, value|
|
80
|
+
unless self.class.columns.include?(column.to_sym)
|
81
|
+
raise "unknown attribute '#{column}'"
|
82
|
+
end
|
83
|
+
self.send("#{column}=", value)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def attributes
|
88
|
+
@attributes ||= {}
|
89
|
+
end
|
90
|
+
|
91
|
+
def attribute_values
|
92
|
+
self.class.columns.map do |column|
|
93
|
+
self.send(column)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def insert
|
98
|
+
my_columns = self.class.columns
|
99
|
+
col_names = my_columns.join(", ")
|
100
|
+
n = my_columns.length
|
101
|
+
question_marks = (["?"] * n).join(", ")
|
102
|
+
|
103
|
+
response = Database.execute(<<-SQL, self.attribute_values)
|
104
|
+
INSERT INTO
|
105
|
+
#{self.class.table_name} (#{col_names})
|
106
|
+
VALUES
|
107
|
+
(#{question_marks})
|
108
|
+
RETURNING
|
109
|
+
id;
|
110
|
+
SQL
|
111
|
+
self.id = response[0]['id'].to_i
|
112
|
+
end
|
113
|
+
|
114
|
+
def update
|
115
|
+
columns_line = self.class.columns.map do |col_name|
|
116
|
+
"#{col_name} = ?"
|
117
|
+
end.join(", ")
|
118
|
+
|
119
|
+
Database.execute(<<-SQL, self.attribute_values, self.id)
|
120
|
+
UPDATE
|
121
|
+
#{self.class.table_name}
|
122
|
+
SET
|
123
|
+
#{columns_line}
|
124
|
+
WHERE
|
125
|
+
id = ?;
|
126
|
+
SQL
|
127
|
+
end
|
128
|
+
|
129
|
+
def save
|
130
|
+
id.nil? ? insert : update
|
131
|
+
end
|
132
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'pg'
|
2
|
+
require 'uri'
|
3
|
+
require 'yaml'
|
4
|
+
|
5
|
+
class Database
|
6
|
+
|
7
|
+
def self.create
|
8
|
+
db = PG::Connection.new(dbname: "postgres")
|
9
|
+
db.exec("CREATE DATABASE #{config[:dbname]}")
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.delete
|
13
|
+
db = PG::Connection.new(dbname: "postgres")
|
14
|
+
db.exec("DROP DATABASE IF EXISTS #{config[:dbname]}")
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.setup
|
18
|
+
setup_script = File.read(File.join(Dir.pwd, 'db/setup.sql'))
|
19
|
+
db = PG::Connection.new(dbname: Database.config[:dbname])
|
20
|
+
db.exec(setup_script)
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.reset
|
24
|
+
self.delete
|
25
|
+
self.create
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.config
|
29
|
+
@config ||= YAML.load_file(File.join(Dir.pwd, 'config/db.yml'))
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.parse_params(params)
|
33
|
+
{
|
34
|
+
host: params.host,
|
35
|
+
dbname: params.path[1..-1],
|
36
|
+
port: params.port,
|
37
|
+
password: params.password,
|
38
|
+
user: x.user
|
39
|
+
}
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.set_db
|
43
|
+
params = ENV["DATABASE_URL"] && URI.parse(ENV["DATABASE_URL"])
|
44
|
+
db_options = params.nil? ? config : parse_params(params)
|
45
|
+
|
46
|
+
@db ||= PG::Connection.new(db_options)
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.instance
|
50
|
+
set_db if @db.nil?
|
51
|
+
|
52
|
+
@db
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.execute(*args)
|
56
|
+
instance.exec(*args)
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require_relative 'db_connection'
|
2
|
+
require_relative 'model_base'
|
3
|
+
|
4
|
+
module Searchable
|
5
|
+
|
6
|
+
def where(params)
|
7
|
+
conditions = params.map do |key, value|
|
8
|
+
"#{key} = ?"
|
9
|
+
end.join(" AND ")
|
10
|
+
result = DBConnection.execute(<<-SQL, params.values)
|
11
|
+
SELECT
|
12
|
+
*
|
13
|
+
FROM
|
14
|
+
#{self.table_name}
|
15
|
+
WHERE
|
16
|
+
#{conditions};
|
17
|
+
SQL
|
18
|
+
|
19
|
+
self.parse_all(result)
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
class ModelBase
|
25
|
+
extend Searchable
|
26
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'reloj'
|
2
|
+
|
3
|
+
namespace :db do
|
4
|
+
|
5
|
+
task :create do
|
6
|
+
Database.create
|
7
|
+
end
|
8
|
+
|
9
|
+
task :delete do
|
10
|
+
Database.delete
|
11
|
+
end
|
12
|
+
|
13
|
+
task :setup do
|
14
|
+
Database.setup
|
15
|
+
end
|
16
|
+
|
17
|
+
task :reset do
|
18
|
+
Database.reset
|
19
|
+
end
|
20
|
+
|
21
|
+
task :test do
|
22
|
+
debugger
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
@@ -0,0 +1,24 @@
|
|
1
|
+
class CatsController < Reloj::ControllerBase
|
2
|
+
|
3
|
+
def create
|
4
|
+
@cat = Cat.new(params["cat"])
|
5
|
+
if @cat.save
|
6
|
+
redirect_to("/cats")
|
7
|
+
else
|
8
|
+
render :new
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def index
|
13
|
+
session['count'] ||= 0
|
14
|
+
session['count'] += 1
|
15
|
+
@cats = Cat.all
|
16
|
+
p @cats
|
17
|
+
render :index
|
18
|
+
end
|
19
|
+
|
20
|
+
def new
|
21
|
+
@cat = Cat.new
|
22
|
+
render :new
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
module App
|
2
|
+
ROUTES = Proc.new do
|
3
|
+
# put the routes for your app here, e.g.
|
4
|
+
# get '/cats/:cat_id/statuses', StatusesController, :index
|
5
|
+
|
6
|
+
get '/cats', CatsController, :index
|
7
|
+
get '/cats/new', CatsController, :new
|
8
|
+
post '/cats', CatsController, :create
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
DROP TABLE IF EXISTS cats;
|
2
|
+
CREATE TABLE cats (
|
3
|
+
id INTEGER PRIMARY KEY,
|
4
|
+
name VARCHAR(255) NOT NULL,
|
5
|
+
owner_id INTEGER
|
6
|
+
|
7
|
+
-- FOREIGN KEY(owner_id) REFERENCES humans(id)
|
8
|
+
);
|
9
|
+
|
10
|
+
DROP TABLE IF EXISTS humans;
|
11
|
+
CREATE TABLE humans (
|
12
|
+
id INTEGER PRIMARY KEY,
|
13
|
+
fname VARCHAR(255) NOT NULL,
|
14
|
+
lname VARCHAR(255) NOT NULL,
|
15
|
+
house_id INTEGER
|
16
|
+
|
17
|
+
-- FOREIGN KEY(house_id) REFERENCES houses(id)
|
18
|
+
);
|
19
|
+
|
20
|
+
DROP TABLE IF EXISTS houses;
|
21
|
+
CREATE TABLE houses (
|
22
|
+
id INTEGER PRIMARY KEY,
|
23
|
+
address VARCHAR(255) NOT NULL
|
24
|
+
);
|
25
|
+
|
26
|
+
INSERT INTO
|
27
|
+
houses (id, address)
|
28
|
+
VALUES
|
29
|
+
(1, '26th and Guerrero'), (2, 'Dolores and Market');
|
30
|
+
|
31
|
+
INSERT INTO
|
32
|
+
humans (id, fname, lname, house_id)
|
33
|
+
VALUES
|
34
|
+
(1, 'Devon', 'Watts', 1),
|
35
|
+
(2, 'Matt', 'Rubens', 1),
|
36
|
+
(3, 'Ned', 'Ruggeri', 2),
|
37
|
+
(4, 'Catless', 'Human', NULL);
|
38
|
+
|
39
|
+
INSERT INTO
|
40
|
+
cats (id, name, owner_id)
|
41
|
+
VALUES
|
42
|
+
(1, 'Breakfast', 1),
|
43
|
+
(2, 'Earl', 2),
|
44
|
+
(3, 'Haskell', 3),
|
45
|
+
(4, 'Markov', 3),
|
46
|
+
(5, 'Stray Cat', NULL);
|
data/lib/reloj.rb
ADDED
data/reloj.gemspec
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'reloj/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "reloj"
|
8
|
+
spec.version = Reloj::VERSION
|
9
|
+
spec.authors = ["ougarcia"]
|
10
|
+
spec.email = ["oz.ulysses@gmail.com"]
|
11
|
+
|
12
|
+
spec.summary = %q{A lightewieght mvc framework inspired by Ruby on Rails}
|
13
|
+
spec.description = %q{A lightewieght mvc framework inspired by Ruby on Rails. Try it out!}
|
14
|
+
spec.homepage = "https://github.com/ougarcia/reloj"
|
15
|
+
spec.license = "MIT"
|
16
|
+
|
17
|
+
# Prevent pushing this gem to RubyGems.org by setting 'allowed_push_host', or
|
18
|
+
# delete this section to allow pushing this gem to any host.
|
19
|
+
if spec.respond_to?(:metadata)
|
20
|
+
spec.metadata['allowed_push_host'] = "https://rubygems.org"
|
21
|
+
else
|
22
|
+
raise "RubyGems 2.0 or newer is required to protect against public gem pushes."
|
23
|
+
end
|
24
|
+
|
25
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
26
|
+
f.match(%r{^(test|spec|features|app)/})
|
27
|
+
end
|
28
|
+
spec.executables = ["reloj"]
|
29
|
+
spec.require_paths = ["lib"]
|
30
|
+
|
31
|
+
spec.add_development_dependency "bundler", "~> 1.10"
|
32
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
33
|
+
spec.add_development_dependency "rspec", "~> 3.3"
|
34
|
+
spec.add_development_dependency "byebug", "~> 6.0"
|
35
|
+
spec.add_development_dependency "pry", "~> 0.10"
|
36
|
+
spec.add_runtime_dependency "webrick", "~> 1.3"
|
37
|
+
spec.add_runtime_dependency "activesupport", "~> 4.2"
|
38
|
+
spec.add_runtime_dependency "require_all", "~> 1.3"
|
39
|
+
spec.add_runtime_dependency "pg", "~> 0.18"
|
40
|
+
|
41
|
+
end
|