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.
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