Skip to content
Snippets Groups Projects
Commit 1d514943 authored by Wellington Gabriel Vicente de Souza's avatar Wellington Gabriel Vicente de Souza
Browse files

Merge branch 'master' of https://gitlab.c3sl.ufpr.br/wgvs16/CI320

parents b0fab89c 0cc4258e
No related branches found
No related tags found
No related merge requests found
# STEAMDB V0.0.1
### dependencies: latest version of ruby (2.5.0), active\_record gem, sqlite3 gem
## Introduction
### Wellington Gabriel Vicente de Souza - GRR20163081 - CI320
Hi! This is a project made for the second evaluation of the Tópicos em Programação de Computadores (CI320) course at Universidade Federal do Paraná in Brazil. The objective of this project was purely to solidify our knowledge in the Ruby language.
This project simulates a simplified working database management system similar to sqlite3. It was implemented in the Ruby language and it uses the Active Record gem to establish a connection with sqlite3.
## How to use
### Creating the database
To create the tables defined in the schema.rb file, run:
$ ruby schema.rb
The steamdb.sqlite3 file on this repository already contains a few example rows to simplify the testing of the different functionalities. To reset the entire database, simply delete the steamdb.sqlite3 file and run the schema.rb file again.
The models for each object type are defined in the models.rb file. This database system implements 1 to 1, 1 to n and n to n relationships.
### Seeding the database
This repository includes a seed file for the database. Just execute the seed_db.sh file to seed the database:
$ ./seed_db.sh
### Running SteamDB
To run SteamDB, just enter the following command on your terminal:
$ ruby steamdb.rb
### Instructions
This program contains five basic commands:
- insere (add a new element)
- exclui (remove one or more elements)
- altera (update one or more elements)
- lista (list all the elements of a table)
- sair (exit)
### Command syntax
< op > < table > < { attribute=value } >
possible < op > values are insere, exclui, altera and lista
< table > indicates the name of the table you will be using for the operation
{ ... } indicates the possibility of more than one argument
attribute=value has different meanings, acting both as a WHERE select and as an attribution
To clarify, here are some examples:
Creating a developer named Jose that lives in Brasil:
+ insere developers name="jose" country="brasil"
Listing all the developers
+ lista developers
Changing the name and country values of the row(s) with a "Jose" value on the name column
+ altera developers name="jose" name="joão" country="usa"
Observation: in the "altera" operation, the first (and only the first) attribute=value pair is used to select one or more rows with the defined value
Deleting a row
+ exclui developers name="joão" country="usa"
Deleting all rows of a table
+ exclui developers
## Relationships
1 to 1 = (Game Price), a game can only have one price list
1 to n = (Developer Game), a developer can have one or more games
n to n = (Category Game), a game can have many categories and categories have many games related to them
# -*- coding: utf-8 -*-
# Cria uma nova base de dados a cada vez.
# Para criar o bd execute "ruby criaSchema.rb".
require 'rubygems'
require 'active_record'
# As duas linhas abaixo indicam o SGBD a ser usado (sqlite3) e o nome
# do arquivo que contém o banco de dados (Aulas.sqlite3)
ActiveRecord::Base.establish_connection :adapter => "sqlite3",
:database => "Aulas.sqlite3"
# As linhas abaixo criam a tabela "pessoas" dentro do banco
# "Aulas.sqlite3", indicando os atributos e os seus tipos. No caso,
# todos são "string", mas tem várias outras oportunidades.
ActiveRecord::Base.connection.create_table :pessoas do |t|
t.string :last_name
t.string :first_name
t.string :address
t.string :city
end
# Sugestão de bibliografia:
# http://www.amazon.com/Pro-Active-Record-Databases-Experts/dp/1590598474
=begin
----->>>>
----- Dica de como implementar relações:
1x1 (Pessoa Profissão)
1xn (Pessoa Sapatos)
nxn (Pessoa Casa)
----->>>>
ActiveRecord::Base.connection.create_table :profissaos do |t|
t.integer :pessoa_id
... demais atributos ...
end
ActiveRecord::Base.connection.create_table :sapatos do |t|
t.integer :pessoa_id
... demais atributos ...
end
ActiveRecord::Base.connection.create_table :casas do |t|
... demais atributos ...
end
ActiveRecord::Base.connection.create_table :pessoas do |t|
t.integer :profissao_id
... demais atributos ...
end
ActiveRecord::Base.connection.create_table :casas_pessoas do |t|
t.integer :pessoa_id
t.integer :casa_id
... demais atributos ...
end
=end
......@@ -4,13 +4,14 @@ ActiveRecord::Base.establish_connection :adapter => "sqlite3",
:database => "steamdb.sqlite3"
class Game < ActiveRecord::Base;
has_one :price
has_one :price, dependent: :destroy
belongs_to :developer
has_and_belongs_to_many :categories
has_many :category_games
has_many :categories, through: :category_games, dependent: :destroy
end
class Developer < ActiveRecord::Base;
has_many :games
has_many :games, dependent: :destroy
end
class Price < ActiveRecord::Base;
......@@ -18,5 +19,11 @@ class Price < ActiveRecord::Base;
end
class Category < ActiveRecord::Base;
has_and_belongs_to_many :games
has_many :category_games
has_many :games, through: :category_games, dependent: :destroy
end
class CategoryGame < ActiveRecord::Base;
belongs_to :category
belongs_to :game
end
\ No newline at end of file
# -*- coding: utf-8 -*-
require 'active_record'
# Só execute este programa depois de criar o banco de dados (ruby
# criaSchema.rb)
# Este exemplo só tem dois "parâmetros" (adapter e database). Porém,
# existem outros: (host, username, password), que podem ser usados com
# outros bancos de dados.
ActiveRecord::Base.establish_connection :adapter => "sqlite3",
:database => "Aulas.sqlite3"
class Pessoa < ActiveRecord::Base;
end
# O bacana aqui é que não foram declarados os atributos da classe
# Pessoa. Para isto, o ActiveRecord vai até o banco de dados, procura
# pelos atributos daquela tabela e automaticamente as "insere" como
# atributos da classe.
# Para demonstrar como acessar estes atributos, vamos a alguns exemplos:
# Formas de inserir informação no banco de dados.
# Método 1: campo a campo.
p = Pessoa.new()
p.last_name = "Hansen"
p.first_name = "Ola"
p.address = "Timoteivn 10"
p.city = "Sandnes"
p.save()
# Método 1: em um único comando.
p = Pessoa.new(:last_name => "Svendson",
:first_name => "Tove",
:address => "Borgvn 23",
:city => "Sandnes")
p.save()
p = Pessoa.new(:last_name => "Pettersen",
:first_name => "Kari",
:address => "Storgt 20",
:city => "Stavanger")
p.save()
# Formas de acessar o banco de dados;
# (1) Traz "todo o banco" para uma única variável (Array), e usar os
# iteradores para navegar lá dentro.
pessoas = Pessoa.all;
pessoas.each do |p|
puts "#{p.id}, #{p.last_name}, #{p.first_name}, #{p.address}, #{p.city}"
end
# (2) Usar o método "find", dando como parâmetro o pk. Verifique a
# classe resultante.
p = Pessoa.find(1)
puts "(Pessoa.find(1)): #{p.id}, #{p.last_name}, #{p.first_name}, #{p.address}, #{p.city}"
# (3) Usar os métodos do tipo "dynamic finders". Estes métodos não
# estão implementados em lugar nenhum. A composição é feita da
# seguinte forma: "<Objeto>.find_by_<nome do atributo>". Muito
# esquisito, mas isto é metaprogramação. Um código será "criado" a
# partir destes parâmetros para fazer a busca no BD. Uma coisa
# importante é que tem dois tipos de finders, o "find" e o
# "find_all". O primeiro retorna um objeto da classe espeficiada. O
# segundo retorna um array de objetos da classe.
pes = Pessoa.where(city: "Stavanger").find_each do |p|
puts p.class
puts p.inspect
puts "(Pessoa.find(...): #{p.id}, #{p.last_name}, #{p.first_name}, #{p.address}, #{p.city}"
end
=begin
1x1 (Pessoa Profissão)
1xn (Pessoa Sapatos)
nxn (Pessoa Casa)
class Profissao < ActiveRecord::Base;
belongs_to :pessoa
end
class Sapato < ActiveRecord::Base;
belongs_to :pessoa
end
class Casa < ActiveRecord::Base;
has_and_belongs_to_many :pessoas
end
class Pessoa < ActiveRecord::Base;
has_one :profissao
has_many :sapatos
has_and_belongs_to_many :casas
end
=end
......@@ -28,7 +28,7 @@ ActiveRecord::Base.connection.create_table :categories do |t|
t.text :description
end
ActiveRecord::Base.connection.create_table :categories_games, id: false do |t|
ActiveRecord::Base.connection.create_table :category_games, id: false do |t|
t.references :category
t.references :game
end
\ No newline at end of file
end
#!/bin/sh
eval "ruby steamdb.rb < seeds"
T2/seeds 0 → 100644
insere developers name="Obsidian" country="Luxembourg"
insere developers name="Bethesda" country="USA"
insere developers name="Icarus" country="Argentina"
insere developers name="Capivara Games" country="Brazil"
insere developers name="Degica" country="Japan"
insere developers name="Square Enix" country="Japan"
insere developers name="Eidos Interactive" country="USA"
insere developers name="inXile"
insere developers name="Taleworlds" country="Poland"
insere developers name="EA Games" country="USA"
insere games name="Oblivion" description="second best elder scrolls game" is_released=true developer_id=2
insere games name="Fallout 1" description="one of the best games that ever existed" is_released=true developer_id=1
insere games name="Fallout 2" description="the best game that ever existed" is_released=true developer_id=1
insere games name="Fallout New Vegas" description="this is fallout, not bethesda's fallout 3" is_released=true developer_id=1
insere games name="Fallout 3: Van Buren" is_released=false developer_id=1
insere games name="Capivara Land" description="capivaras!" is_released=true developer_id=4
insere games name="Wasteland 1" description="old but good" is_released=true developer_id=8
insere games name="Wasteland 2" description="a really really good game" is_released=true developer_id=8
insere games name="Mount and Blade: Warband" description="pointy spears" is_released=true developer_id=9
insere games name="Kingdoms of Amalur: Reckoning" description="a really cool rpg" is_released=true developer_id=10
insere prices price_us=530 price_br=239 price_ru=200 game_id=1
insere prices price_us=530 price_br=259 price_ru=230 game_id=2
insere prices price_us=530 price_br=4529 price_ru=400 game_id=3
insere prices price_us=530 price_br=329 price_ru=500 game_id=4
insere prices price_us=530 price_br=219 price_ru=270 game_id=6
insere prices price_us=530 price_br=219 price_ru=120 game_id=7
insere prices price_us=530 price_br=129 price_ru=200 game_id=8
insere prices price_us=530 price_br=29 price_ru=2400 game_id=9
insere prices price_us=530 price_br=29 price_ru=2030 game_id=10
insere categories name="fps" description="first person shooters"
insere categories name="tps" description="third person shooters"
insere categories name="arcade"
insere categories name="platformer"
insere categories name="rpg" description="roleplaying games"
insere categories name="open world" description="games with a huge world to explore"
insere categories name="fantasy" description="fantasy games"
insere categories name="capivaras" description="capivaras!"
insere categories name="post-apocalyptic" description="the one true genre"
insere categories name="high fantasy" description="fantasy x100"
insere category_games category_id=1 game_id=1
insere category_games category_id=2 game_id=1
insere category_games category_id=5 game_id=1
insere category_games category_id=6 game_id=1
insere category_games category_id=7 game_id=1
insere category_games category_id=10 game_id=1
insere category_games category_id=3 game_id=6
insere category_games category_id=5 game_id=7
insere category_games category_id=9 game_id=7
insere category_games category_id=5 game_id=8
insere category_games category_id=9 game_id=8
insere category_games category_id=6 game_id=9
insere category_games category_id=10 game_id=10
sair
This diff is collapsed.
File deleted
* {
margin:0;
padding:0;
}
html, body {
width: 100%;
}
canvas {
display:block;
height: 100%;
width: 100%;
}
div {
position: absolute;
left: 10px;
top: 10px;
width: 300px;
}
#number {
width: 50px;
}
\ No newline at end of file
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="canvas.css">
</head>
<body>
<canvas id="canvas">
Your browser does not support the HTML5 canvas tag.
</canvas>
<div>
<h3> Gerador de Polígonos </h3>
Informe um número de 3 a 8:
<input type="number" id="number" step="1" min="3" max="8" value="3" required/>
<input type="submit" onclick="generatePolygon()" value="Gerar"/>
<span class="validity"></span>
</div>
</body>
<script type="text/javascript" src="lines.js"></script>
</html>
class Line {
constructor(x0,y0,xf,yf) {
this.x0 = x0;
this.y0 = y0;
this.xf = xf;
this.yf = yf;
this.width = Math.abs(xf - x0);
this.height = Math.abs(yf - y0);
if (this.x0 < this.xf)
this.centerX = x0 + this.width/2;
else
this.centerX = xf + this.width/2;
if (this.y0 < this.yf)
this.centerY = y0 + this.height/2;
else
this.centerY = yf + this.height/2;
}
}
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var width = window.innerWidth;
var height = window.innerHeight;
var centerX = width / 2;
var centerY = height / 2;
var mouseX = 0;
var mouseY = 0;
var mouseDown = 0;
var rightClick = 0;
var lines = [];
lines[0] = new Line(centerX-200,centerY,centerX+200,centerY);
var selectedLine = null;
var movingEntireLine = false;
var draggingFirstEnd = false;
var draggingSecondEnd = false;
canvas.width = width;
canvas.height = height;
canvas.style.background = "#333";
document.body.style.color = "#fff";
ctx.strokeStyle = "#fff";
//event listeners
window.addEventListener('resize', resizeCanvas, false);
window.addEventListener('mousedown', handleMouseDown, false);
window.addEventListener('mouseup', handleMouseUp, false);
document.addEventListener("contextmenu", function(e){
e.preventDefault();
}, false);
onmousemove = function(e){
mouseX = e.clientX;
mouseY = e.clientY;
}
//event handlers
function resizeCanvas() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
width = window.innerWidth;
height = window.innerHeight;
centerX = width / 2;
centerY = height / 2;
drawCurrentCanvas();
}
function handleMouseDown(e) {
rightClick = e.button == 2?1:0;
if (!rightClick) mouseDown = 1;
}
function handleMouseUp() {
mouseDown = 0;
rightClick = 0;
selectedLine = null;
movingEntireLine = false;
draggingFirstEnd = false;
draggingSecondEnd = false;
}
function dragLine() {
if (selectedLine != null) {
if (movingEntireLine) {
if (lines[selectedLine].x0 <= lines[selectedLine].xf) {
lines[selectedLine].x0 = mouseX-(lines[selectedLine].width/2);
lines[selectedLine].xf = mouseX+(lines[selectedLine].width/2);
} else {
lines[selectedLine].xf = mouseX-(lines[selectedLine].width/2);
lines[selectedLine].x0 = mouseX+(lines[selectedLine].width/2);
}
if (lines[selectedLine].y0 <= lines[selectedLine].yf) {
lines[selectedLine].y0 = mouseY-(lines[selectedLine].height/2);
lines[selectedLine].yf = mouseY+(lines[selectedLine].height/2);
} else {
lines[selectedLine].yf = mouseY-(lines[selectedLine].height/2);
lines[selectedLine].y0 = mouseY+(lines[selectedLine].height/2);
}
if (lines[selectedLine].x0 <= lines[selectedLine].xf) {
lines[selectedLine].centerX = lines[selectedLine].x0 + lines[selectedLine].width/2;
} else {
lines[selectedLine].centerX = lines[selectedLine].xf + lines[selectedLine].width/2;
}
if (lines[selectedLine].y0 <= lines[selectedLine].yf) {
lines[selectedLine].centerY = lines[selectedLine].y0 + lines[selectedLine].height/2;
} else {
lines[selectedLine].centerY = lines[selectedLine].yf + lines[selectedLine].height/2;
}
} else if (draggingFirstEnd) {
lines[selectedLine].x0 = mouseX;
lines[selectedLine].y0 = mouseY;
lines[selectedLine].width = Math.abs(lines[selectedLine].xf - lines[selectedLine].x0);
lines[selectedLine].height = Math.abs(lines[selectedLine].yf - lines[selectedLine].y0);
if (lines[selectedLine].x0 <= lines[selectedLine].xf) {
lines[selectedLine].centerX = lines[selectedLine].x0 + lines[selectedLine].width/2;
} else {
lines[selectedLine].centerX = lines[selectedLine].xf + lines[selectedLine].width/2;
}
if (lines[selectedLine].y0 <= lines[selectedLine].yf) {
lines[selectedLine].centerY = lines[selectedLine].y0 + lines[selectedLine].height/2;
} else {
lines[selectedLine].centerY = lines[selectedLine].yf + lines[selectedLine].height/2;
}
} else if (draggingSecondEnd) {
lines[selectedLine].xf = mouseX;
lines[selectedLine].yf = mouseY;
lines[selectedLine].width = Math.abs(lines[selectedLine].xf - lines[selectedLine].x0);
lines[selectedLine].height = Math.abs(lines[selectedLine].yf - lines[selectedLine].y0);
if (lines[selectedLine].x0 <= lines[selectedLine].xf) {
lines[selectedLine].centerX = lines[selectedLine].x0 + lines[selectedLine].width/2;
} else {
lines[selectedLine].centerX = lines[selectedLine].xf + lines[selectedLine].width/2;
}
if (lines[selectedLine].y0 <= lines[selectedLine].yf) {
lines[selectedLine].centerY = lines[selectedLine].y0 + lines[selectedLine].height/2;
} else {
lines[selectedLine].centerY = lines[selectedLine].yf + lines[selectedLine].height/2;
}
}
}
}
function handleMouse() {
if (mouseDown && selectedLine == null) {
for (var i = lines.length - 1; i >= 0; i--) {
if (mouseX >= lines[i].centerX - 10 && mouseX <= lines[i].centerX + 10 && mouseY >= lines[i].centerY - 10 && mouseY <= lines[i].centerY + 10) {
selectedLine = i;
movingEntireLine = true;
break;
} else if (mouseX >= lines[i].x0 - 20 && mouseX <= lines[i].x0 + 20 &&
mouseY >= lines[i].y0 - 20 && mouseY <= lines[i].y0 + 20) {
selectedLine = i;
draggingFirstEnd = true;
break;
} else if (mouseX >= lines[i].xf - 20 && mouseX <= lines[i].xf + 20
&& mouseY >= lines[i].yf - 20 && mouseY <= lines[i].yf + 20) {
selectedLine = i;
draggingSecondEnd = true;
break;
}
}
} else if (rightClick) {
for (var i = lines.length - 1; i >= 0; i--) {
if ((mouseY >= lines[i].y0 && mouseY <= lines[i].yf) || (mouseY >= lines[i].yf && mouseY <= lines[i].y0)) {
if (mouseX >= lines[i].x0 && mouseX <= lines[i].xf) {
lines[lines.length] = new Line(mouseX,mouseY,lines[i].xf,lines[i].yf);
lines[i].xf = mouseX;
lines[i].yf = mouseY;
lines[i].width = Math.abs(lines[i].xf - lines[i].x0);
lines[i].height = Math.abs(lines[i].yf - lines[i].y0);
lines[i].centerX = lines[i].x0 + lines[i].width/2;
lines[i].centerY = lines[i].y0 + lines[i].height/2;
rightClick = 0;
break;
} else if (mouseX <= lines[i].x0 && mouseX >= lines[i].xf) {
lines[lines.length] = new Line(mouseX,mouseY,lines[i].x0,lines[i].y0);
lines[i].x0 = mouseX;
lines[i].y0 = mouseY;
lines[i].width = Math.abs(lines[i].xf - lines[i].x0);
lines[i].height = Math.abs(lines[i].yf - lines[i].y0);
lines[i].centerX = lines[i].xf + lines[i].width/2;
lines[i].centerY = lines[i].yf + lines[i].height/2;
rightClick = 0;
break;
}
}
}
}
}
function generatePolygon() {
edges = parseInt(document.getElementById("number").value,10);
if (edges >= 3 && edges <= 8) {
lines = [];
var tmpx0 = centerX + 300;
var tmpy0 = centerY;
var edge = (2 * Math.PI)/edges;
for (var i = 0; i < edges; i++) {
var angle = edge * (i+1);
var tmpxf = 300 * Math.cos(angle) + centerX;
var tmpyf = 300 * Math.sin(angle) + centerY;
lines[i] = new Line(tmpx0, tmpy0, tmpxf,tmpyf);
tmpx0 = tmpxf;
tmpy0 = tmpyf;
}
drawCurrentCanvas();
} else {
alert("Valor inválido! O número de arestas deve estar no intervalo de [3..8].")
}
}
//function that updates screen
function drawCurrentCanvas() {
drawLines();
if ((mouseDown && selectedLine == null) || rightClick) handleMouse();
dragLine();
requestAnimationFrame(drawCurrentCanvas);
}
//function that draws all existing lines
function drawLines() {
ctx.clearRect(0,0,canvas.width,canvas.height);
for (var i = lines.length - 1; i >= 0; i--) {
drawLine(lines[i].x0,lines[i].y0,lines[i].xf,lines[i].yf, i);
}
}
//function that draws a line
function drawLine(x0,y0,xf,yf,i) {
ctx.beginPath();
ctx.lineWidth = 3;
ctx.moveTo(x0,y0);
ctx.lineTo(xf,yf);
if (selectedLine == i) ctx.strokeStyle = "red";
else ctx.strokeStyle = "#fff";
ctx.stroke();
lineX0 = x0;
lineY0 = y0;
lineXf = xf;
lineYf = yf;
}
//start
drawCurrentCanvas();
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment