reloj 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +2 -0
  3. data/Gemfile +3 -0
  4. data/Gemfile.lock +64 -0
  5. data/README.md +89 -0
  6. data/Rakefile +1 -0
  7. data/bin/reloj +66 -0
  8. data/lib/reloj/core/controller_base.rb +68 -0
  9. data/lib/reloj/core/flash.rb +38 -0
  10. data/lib/reloj/core/params.rb +52 -0
  11. data/lib/reloj/core/route_helper.rb +45 -0
  12. data/lib/reloj/core/router.rb +89 -0
  13. data/lib/reloj/core/session.rb +32 -0
  14. data/lib/reloj/orm/associatable.rb +70 -0
  15. data/lib/reloj/orm/associatable2.rb +34 -0
  16. data/lib/reloj/orm/db_connection.rb +59 -0
  17. data/lib/reloj/orm/model_base.rb +132 -0
  18. data/lib/reloj/orm/pg_db.rb +59 -0
  19. data/lib/reloj/orm/searchable.rb +26 -0
  20. data/lib/reloj/skeletons/common_files/Gemfile +6 -0
  21. data/lib/reloj/skeletons/common_files/Rakefile +25 -0
  22. data/lib/reloj/skeletons/new_app/app/controllers/.keep +0 -0
  23. data/lib/reloj/skeletons/new_app/app/models/.keep +0 -0
  24. data/lib/reloj/skeletons/new_app/app/views/.keep +0 -0
  25. data/lib/reloj/skeletons/new_app/config/routes.rb +7 -0
  26. data/lib/reloj/skeletons/new_app/db/.keep +0 -0
  27. data/lib/reloj/skeletons/sample_app/app/controllers/cats_controller.rb +24 -0
  28. data/lib/reloj/skeletons/sample_app/app/models/cat.rb +8 -0
  29. data/lib/reloj/skeletons/sample_app/app/views/cats_controller/index.html.erb +5 -0
  30. data/lib/reloj/skeletons/sample_app/app/views/cats_controller/new.html.erb +11 -0
  31. data/lib/reloj/skeletons/sample_app/config/routes.rb +10 -0
  32. data/lib/reloj/skeletons/sample_app/db/setup.sql +46 -0
  33. data/lib/reloj/version.rb +3 -0
  34. data/lib/reloj.rb +8 -0
  35. data/reloj.gemspec +41 -0
  36. 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,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'reloj'
4
+ gem 'pg'
5
+ gem 'rake'
6
+
@@ -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
@@ -0,0 +1,7 @@
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
+ end
7
+ end
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,8 @@
1
+ class Cat < ModelBase
2
+
3
+ def inspect
4
+ { name: self.name }.inspect
5
+ end
6
+
7
+ finalize!
8
+ end
@@ -0,0 +1,5 @@
1
+ <h1>ALL THE CATS</h1>
2
+ <pre><%= @cats.to_s %></pre>
3
+ <a href="/cats/new">New cat!</a>
4
+ <br>
5
+ <p>You've visited this page: <strong><%= session["count"] %></strong> times</p>
@@ -0,0 +1,11 @@
1
+ <form action="/cats" method="POST">
2
+ <label>Name
3
+ <input type="text" name="cat[name]" value="<%= @cat.name %>">
4
+ </label>
5
+
6
+ <label>Owner
7
+ <input type="text" name="cat[owner]" value="<%= @cat.owner %>">
8
+ </label>
9
+
10
+ <input type="submit">
11
+ </form>
@@ -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);
@@ -0,0 +1,3 @@
1
+ module Reloj
2
+ VERSION = "0.1.1"
3
+ end
data/lib/reloj.rb ADDED
@@ -0,0 +1,8 @@
1
+ require "reloj/version"
2
+ require 'reloj/core/controller_base'
3
+ require 'reloj/core/router'
4
+ require 'reloj/orm/pg_db'
5
+ require 'reloj/orm/model_base'
6
+
7
+ module Reloj
8
+ end
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