railz_lite 0.2.3 → 0.2.8

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 582dcdab7ea03cf05ecf37d4ead94d5a2f3cc95ad1b89db6b9e93b98d7732e67
4
- data.tar.gz: 507d329e1fc346cf7ede9892afb1d81a85a1bb1bc14d5c8f8eb6632a57936ae0
3
+ metadata.gz: aff7d4d6f62b5eee1669eef62895d5170f55a5d3241db179191a690bb9dc26f1
4
+ data.tar.gz: 2ab955ed52a300dcf3c614e1a0c4bcbf9f0e8ef81613e2bae9aa7324f08980db
5
5
  SHA512:
6
- metadata.gz: 4d480c89f27783d171aea9fe67862080b108a8e9b2c8320e99f687119a6b5b72b189a6dede703349152c843ad5bd6a0c03fa1bc4dac3377b454b5bb3b3c2e40c
7
- data.tar.gz: b6927c1850fe7bf1e4db6b29fbd13a9105eed8c4b03d0383a15f0bc09ef6fa1691b0a8483413a09c4147aaf08dd37b6af5262d37d88a15adba4556091806d415
6
+ metadata.gz: 0b6b915059bf4ed2ce158b1b6eef235fb742cac8fa3a416bdd88df3d4183510c632021181cec277551e86b3142253bf09732d6aed1954cf1c92b08c820c02b2b
7
+ data.tar.gz: 7118f1462ba3e8d772d4e64bfea0304f8cae53cebd073d9b38c97e318a3129f42bf5560369c96f7edc7b916b9a1e77e22d7d713c18ed31526a189f080f00c25b
data/.gitignore CHANGED
@@ -9,3 +9,4 @@
9
9
 
10
10
  # rspec failure tracking
11
11
  .rspec_status
12
+ Gemfile.lock
data/README.md CHANGED
@@ -1,8 +1,30 @@
1
1
  # RailzLite
2
2
 
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/railz_lite`. To experiment with that code, run `bin/console` for an interactive prompt.
3
+ A lite-weight Ruby gem inspired by Ruby on Rails.
4
4
 
5
- TODO: Delete this and the text above, and describe your gem
5
+ To get started with a new project, execute the command
6
+
7
+ ```
8
+ $ railz_lite new MyWebApp
9
+ ```
10
+
11
+ This will generate controllers/, views/, models/, and other necessary directories.
12
+
13
+ After changing into the root project directory, run the server command to get the Rack server running
14
+
15
+ ```
16
+ $ cd MyWebApp && railz_lite server
17
+ ```
18
+
19
+ To create a new sqlite3 database file, write your desired SQL code in app.sql then execute
20
+
21
+ ```
22
+ $ railz_lite reset_db
23
+ ```
24
+
25
+ An example web app can be found at the following repo:
26
+
27
+ https://github.com/bryanqb07/trash_films
6
28
 
7
29
  ## Installation
8
30
 
@@ -22,7 +44,86 @@ Or install it yourself as:
22
44
 
23
45
  ## Usage
24
46
 
25
- TODO: Write usage instructions here
47
+ ### Controllers
48
+
49
+ All controllers should inherit from the RailzLite::ControllerBase class. An example is as follows:
50
+
51
+ ```ruby
52
+ class FilmsController < RailzLite::ControllerBase
53
+ def index
54
+ @films = Film.all
55
+ end
56
+
57
+ def show
58
+ @film = Film.find(params['id'])
59
+ end
60
+ end
61
+ ```
62
+
63
+ ### Models
64
+
65
+ Models inherit from RailzLite::SQLObject. Please note that any class declaration must be ended with a finalize! statement
66
+
67
+ ```ruby
68
+ class Film < RailzLite::SQLObject
69
+ has_many :reviews, foreign_key: :film_id
70
+ def average_rating
71
+ ratings = reviews.map(&:rating)
72
+ return 0 if ratings.empty?
73
+
74
+ ratings.reduce(:+) / reviews.length
75
+ end
76
+ finalize!
77
+ end
78
+ ```
79
+
80
+ ### Views
81
+
82
+ Views use the rails convention for path-resolution. Also, they are required to end in a .erb extension, even if no embedded ruby is used.
83
+
84
+ ex. FilmsController#index corresponds to /views/films/index.html.erb
85
+
86
+ ### Server + Routes
87
+
88
+ The server file can be found in config/server.
89
+
90
+ Routes are configured in the following structure
91
+
92
+ ```
93
+ http_method, regex to match route, controller, action
94
+ ```
95
+
96
+ Below is an example route config:
97
+ ```ruby
98
+ router.draw do
99
+ # add routes here
100
+ get Regexp.new('^/films$'), FilmsController, :index
101
+ get Regexp.new("^/films/(?<id>\\d+)$"), FilmsController, :show
102
+
103
+ get Regexp.new("^/films/(?<film_id>\\d+)/reviews/new$"), ReviewsController, :new
104
+ post Regexp.new("^/films/(?<film_id>\\d+)/reviews$"), ReviewsController, :create
105
+ end
106
+ ```
107
+
108
+ ### Assets
109
+
110
+ Assets are served via the static middleware included within the framework. The default load paths for assets are "/public" and "/assets".
111
+ Any file within these two folders can be accessed in the app by specifying the root folder + the file name.
112
+
113
+ ex.) MyProject/public/balloons.jpg
114
+
115
+ ```html
116
+ <h1>Congratulations!!! <img src="public/balloons.jpg" /></h1>
117
+ ```
118
+
119
+ ex.) MyProject/assets/home.css
120
+
121
+ ```html
122
+ <head>
123
+ <title>My Project</title>
124
+ <link rel="stylesheet" href="assets/application.css">
125
+ </head>
126
+ ```
26
127
 
27
128
  ## Development
28
129
 
@@ -1,6 +1,7 @@
1
1
  require 'active_support'
2
2
  require 'active_support/core_ext'
3
3
  require 'erb'
4
+ require 'loofah'
4
5
  require_relative './session'
5
6
  require_relative './flash'
6
7
 
@@ -62,7 +63,8 @@ module RailzLite
62
63
  layout.def_method(LayoutRenderer, 'render') # dummy method used so that blocks can be passed to ERB result
63
64
 
64
65
  result = LayoutRenderer.new.render do
65
- inner.result(binding)
66
+ inner_html = inner.result(binding)
67
+ Loofah.fragment(inner_html).scrub!(:prune).to_s # prevent non-safe html from being executed
66
68
  end
67
69
 
68
70
  render_content(result, 'text/html')
@@ -1,11 +1,11 @@
1
1
  require 'rack'
2
2
 
3
3
  class Static
4
- attr_reader :app, :file_server, :root
4
+ attr_reader :app, :file_server, :root_paths
5
5
 
6
6
  def initialize(app)
7
7
  @app = app
8
- @root = 'public'
8
+ @root_paths = ['public', 'assets']
9
9
  @file_server = FileServer.new
10
10
  end
11
11
 
@@ -13,17 +13,21 @@ class Static
13
13
  req = Rack::Request.new(env)
14
14
  path = req.path
15
15
 
16
- if can_match?(path)
17
- file_server.call(env)
18
- else
16
+ asset_dir = get_asset_dir(path)
17
+
18
+ if asset_dir.nil?
19
19
  app.call(env)
20
+ else
21
+ file_server.call(env, asset_dir)
20
22
  end
21
23
  end
22
24
 
23
25
  private
24
26
 
25
- def can_match?(path)
26
- path.index("/#{root}")
27
+ # return the root directory of asset request ex => 'films/assets/app.css' would return 'assets'
28
+ def get_asset_dir(path)
29
+ root_paths.each { |root| return root if path.include?(root) }
30
+ nil
27
31
  end
28
32
  end
29
33
 
@@ -32,12 +36,14 @@ class FileServer
32
36
  MIME_TYPES = {
33
37
  '.txt' => 'text/plain',
34
38
  '.jpg' => 'image/jpeg',
35
- '.zip' => 'application/zip'
39
+ '.zip' => 'application/zip',
40
+ '.css' => 'text/css',
41
+ '.js' => 'text/javascript'
36
42
  }
37
43
 
38
- def call(env)
44
+ def call(env, asset_dir)
39
45
  res = Rack::Response.new
40
- file_name = requested_file_name(env)
46
+ file_name = requested_file_name(env, asset_dir)
41
47
 
42
48
  if File.exist?(file_name)
43
49
  serve_file(file_name, res)
@@ -58,10 +64,11 @@ class FileServer
58
64
  res.write(file)
59
65
  end
60
66
 
61
- def requested_file_name(env)
67
+ def requested_file_name(env, asset_dir)
62
68
  req = Rack::Request.new(env)
63
- path = req.path
64
69
  dir = Dir.pwd
65
- File.join(dir, path)
70
+ path = req.path
71
+ filename = File.basename(path)
72
+ File.join(dir, asset_dir, filename)
66
73
  end
67
74
  end
@@ -29,7 +29,10 @@ module RailzLite
29
29
  def setup_views
30
30
  template('welcome_view.index.html.erb', "#{project_name}/views/welcome/index.html.erb")
31
31
  template('application.html.erb', "#{project_name}/views/application/application.html.erb")
32
- create_file("#{project_name}/views/application/application.css")
32
+ end
33
+
34
+ def add_assets
35
+ create_file("#{project_name}/assets/application.css")
33
36
  end
34
37
 
35
38
  def add_public
@@ -2,7 +2,7 @@
2
2
  <html>
3
3
  <head>
4
4
  <title>App Title</title>
5
- <link rel="stylesheet" href="application.css">
5
+ <link rel="stylesheet" href="assets/application.css">
6
6
  </head>
7
7
  <body>
8
8
  <%= yield %>
@@ -24,7 +24,7 @@ end
24
24
 
25
25
  app = Rack::Builder.new do
26
26
  use ShowExceptions # generates helpful error messages
27
- use Static # serves static assets from /public
27
+ use Static # serves static assets from /public and /assets
28
28
  run app
29
29
  end.to_app
30
30
 
@@ -6,7 +6,7 @@
6
6
  ">
7
7
  <h1>Welcome To Railz Lite!</h1>
8
8
 
9
- <img src="../public/winter_fox_large.jpg" />
9
+ <img src="public/winter_fox_large.jpg" />
10
10
 
11
11
  <h3>For guidelines on how to build an app with this framework see <a href="https://github.com/bryanqb07/railz_lite">here</a>.</h3>
12
12
  </div>
@@ -1,4 +1,5 @@
1
- require 'sqlite3'
1
+ require_relative 'wrappers/pg_wrapper'
2
+ require_relative 'wrappers/sqlite3_wrapper'
2
3
 
3
4
  class DBConnection
4
5
  PRINT_QUERIES = ENV['PRINT_QUERIES'] == 'true'
@@ -10,22 +11,27 @@ class DBConnection
10
11
  DBConnection.open(DB_FILE)
11
12
  end
12
13
 
13
- def self.open(db_file_name)
14
- @db = SQLite3::Database.new(db_file_name)
15
- @db.results_as_hash = true
16
- @db.type_translation = true
14
+ def self.open(db_name) # for sqlite3 we need file.db, for postgresql we need database name
15
+ db_uri = ENV['DATABASE_URL']
16
+
17
+ @db = db_uri.nil? ? SQLite3Wrapper.new(db_name) : PGWrapper.new(db_uri)
17
18
 
18
19
  @db
19
20
  end
20
21
 
21
22
  def self.reset
22
- commands = [
23
- "rm '#{DB_FILE}'",
24
- "cat '#{SQL_FILE}' | sqlite3 '#{DB_FILE}'"
25
- ]
23
+ db_uri = ENV['DATABASE_URL']
26
24
 
27
- commands.each { |command| `#{command}` }
28
- DBConnection.open(DB_FILE)
25
+ if db_uri.nil? # sqlite
26
+ commands = ["rm '#{DB_FILE}'", "cat '#{SQL_FILE}' | sqlite3 '#{DB_FILE}'"]
27
+
28
+ commands.each { |command| `#{command}` }
29
+ DBConnection.open(DB_FILE)
30
+ else # postgres
31
+ DBConnection.open(db_uri)
32
+ sql = File.read(SQL_FILE)
33
+ instance.execute(sql)
34
+ end
29
35
  end
30
36
 
31
37
  def self.instance
@@ -34,20 +40,25 @@ class DBConnection
34
40
  @db
35
41
  end
36
42
 
43
+ # results hash of results [{id: 1, name: 'Bob'}...]
37
44
  def self.execute(*args)
38
45
  print_query(*args)
39
46
  instance.execute(*args)
40
47
  end
41
48
 
49
+ # returns result with header fields [['id', 'name'...], { id: 1, name: 'Bob' ... }
42
50
  def self.execute2(*args)
43
51
  print_query(*args)
44
52
  instance.execute2(*args)
45
53
  end
46
54
 
47
- def self.last_insert_row_id
48
- instance.last_insert_row_id
55
+ # used to insert data into tables
56
+ def self.insert(*args)
57
+ print_query(*args)
58
+ instance.insert(*args)
49
59
  end
50
60
 
61
+
51
62
  private
52
63
 
53
64
  def self.print_query(query, *interpolation_args)
@@ -82,13 +82,13 @@ module RailzLite
82
82
  end
83
83
 
84
84
  def insert
85
- DBConnection.execute(<<-SQL, *attribute_values)
85
+ last_row_id = DBConnection.insert(<<-SQL, *attribute_values)
86
86
  INSERT INTO
87
87
  #{self.class.table_name}(#{self.class.columns.join(',')})
88
88
  VALUES
89
89
  (#{(["?"] * attribute_values.length).join(',')})
90
90
  SQL
91
- self.id = DBConnection.last_insert_row_id
91
+ self.id = last_row_id
92
92
  end
93
93
 
94
94
  def update
@@ -0,0 +1,46 @@
1
+ require 'pg'
2
+
3
+ class PGWrapper
4
+ def initialize(db_uri)
5
+ @db = PG::Connection.new(db_uri)
6
+ @db.type_map_for_results = PG::BasicTypeMapForResults.new(@db) # converts pgsql strings to ruby type
7
+ @db
8
+ end
9
+
10
+ def execute(sql, *args)
11
+ converted_sql = convert_escaped_question_marks(sql)
12
+ @db.exec_params(converted_sql, args).to_a
13
+ end
14
+
15
+ def execute2(sql, *args)
16
+ converted_sql = convert_escaped_question_marks(sql)
17
+ result = @db.exec_params(converted_sql, args)
18
+ [result.fields, result.to_a]
19
+ end
20
+
21
+ def insert(sql, *args)
22
+ sql.insert(sql.index(';'), ' RETURNING ID')
23
+ converted_sql = convert_escaped_question_marks(sql)
24
+ result = @db.exec_params(converted_sql, *args)
25
+ result.to_a.first['id']
26
+ end
27
+
28
+
29
+ private
30
+
31
+ # for pgsql, SELECT * FROM films WHERE x = ?; must be converted to SELECT * FROM films WHERE x = $1;
32
+ def convert_escaped_question_marks(sql)
33
+ converted_sql = ""
34
+ index = 1
35
+ sql.each_char do |char|
36
+ if char == '?'
37
+ converted_sql += "$#{index}"
38
+ index += 1
39
+ else
40
+ converted_sql += char
41
+ end
42
+ end
43
+ converted_sql
44
+ end
45
+
46
+ end
@@ -0,0 +1,30 @@
1
+ require 'sqlite3'
2
+
3
+ class SQLite3Wrapper
4
+ def initialize(db_file_name)
5
+ @db = SQLite3::Database.new(db_file_name)
6
+ @db.results_as_hash = true
7
+ @db.type_translation = true
8
+
9
+ @db
10
+ end
11
+
12
+ def execute(*args)
13
+ @db.execute(*args)
14
+ end
15
+
16
+ def execute2(*args)
17
+ @db.execute2(*args)
18
+ end
19
+
20
+ def insert(*args)
21
+ execute(*args)
22
+ last_insert_row_id
23
+ end
24
+
25
+ private
26
+
27
+ def self.last_insert_row_id
28
+ @db.last_insert_row_id
29
+ end
30
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RailzLite
4
- VERSION = "0.2.3"
4
+ VERSION = "0.2.8"
5
5
  end
data/railz_lite.gemspec CHANGED
@@ -29,11 +29,13 @@ Gem::Specification.new do |spec|
29
29
  spec.require_paths = ["lib"]
30
30
 
31
31
  # Uncomment to register a new dependency of your gem
32
- spec.add_dependency "rack"
33
- spec.add_dependency "activesupport"
34
- spec.add_dependency "puma"
35
- spec.add_dependency "sqlite3"
36
- spec.add_dependency "thor"
32
+ spec.add_dependency "rack", '~> 2.2.3'
33
+ spec.add_dependency "activesupport", '~> 6.1.4'
34
+ spec.add_dependency "puma", '~> 5.3.2'
35
+ spec.add_dependency "sqlite3", '~> 1.4.2'
36
+ spec.add_dependency "pg", '~> 1.2.3'
37
+ spec.add_dependency "thor", '~> 1.1.0'
38
+ spec.add_dependency "loofah", '~> 2.10.0'
37
39
 
38
40
 
39
41
  spec.add_development_dependency "byebug"
metadata CHANGED
@@ -1,85 +1,113 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: railz_lite
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.3
4
+ version: 0.2.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - bryan lynch
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-07-03 00:00:00.000000000 Z
11
+ date: 2021-07-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ">="
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '0'
19
+ version: 2.2.3
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ">="
24
+ - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '0'
26
+ version: 2.2.3
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: activesupport
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ">="
31
+ - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '0'
33
+ version: 6.1.4
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - ">="
38
+ - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '0'
40
+ version: 6.1.4
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: puma
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - ">="
45
+ - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '0'
47
+ version: 5.3.2
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - ">="
52
+ - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '0'
54
+ version: 5.3.2
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: sqlite3
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - ">="
59
+ - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '0'
61
+ version: 1.4.2
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - ">="
66
+ - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '0'
68
+ version: 1.4.2
69
+ - !ruby/object:Gem::Dependency
70
+ name: pg
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 1.2.3
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 1.2.3
69
83
  - !ruby/object:Gem::Dependency
70
84
  name: thor
71
85
  requirement: !ruby/object:Gem::Requirement
72
86
  requirements:
73
- - - ">="
87
+ - - "~>"
74
88
  - !ruby/object:Gem::Version
75
- version: '0'
89
+ version: 1.1.0
76
90
  type: :runtime
77
91
  prerelease: false
78
92
  version_requirements: !ruby/object:Gem::Requirement
79
93
  requirements:
80
- - - ">="
94
+ - - "~>"
81
95
  - !ruby/object:Gem::Version
82
- version: '0'
96
+ version: 1.1.0
97
+ - !ruby/object:Gem::Dependency
98
+ name: loofah
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: 2.10.0
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: 2.10.0
83
111
  - !ruby/object:Gem::Dependency
84
112
  name: byebug
85
113
  requirement: !ruby/object:Gem::Requirement
@@ -178,6 +206,8 @@ files:
178
206
  - lib/railz_lite/models/searchable.rb
179
207
  - lib/railz_lite/models/sql_object.rb
180
208
  - lib/railz_lite/models/validatable.rb
209
+ - lib/railz_lite/models/wrappers/pg_wrapper.rb
210
+ - lib/railz_lite/models/wrappers/sqlite3_wrapper.rb
181
211
  - lib/railz_lite/version.rb
182
212
  - railz_lite.gemspec
183
213
  homepage: https://github.com/bryanqb07/my_rails