railz_lite 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 (41) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +11 -0
  3. data/.rspec +3 -0
  4. data/.rubocop.yml +13 -0
  5. data/CODE_OF_CONDUCT.md +84 -0
  6. data/Gemfile +7 -0
  7. data/LICENSE.txt +21 -0
  8. data/README.md +43 -0
  9. data/Rakefile +12 -0
  10. data/bin/console +15 -0
  11. data/bin/setup +8 -0
  12. data/exe/railz_lite +4 -0
  13. data/exe/railz_lite.rb~ +3 -0
  14. data/lib/railz_lite.rb +10 -0
  15. data/lib/railz_lite/cli.rb +17 -0
  16. data/lib/railz_lite/controllers/controller_base.rb +101 -0
  17. data/lib/railz_lite/controllers/flash.rb +22 -0
  18. data/lib/railz_lite/controllers/router.rb +68 -0
  19. data/lib/railz_lite/controllers/session.rb +30 -0
  20. data/lib/railz_lite/controllers/show_exceptions.rb +56 -0
  21. data/lib/railz_lite/controllers/static.rb +66 -0
  22. data/lib/railz_lite/controllers/templates/rescue.html.erb +53 -0
  23. data/lib/railz_lite/controllers/templates/rescue.html.erb~ +0 -0
  24. data/lib/railz_lite/generators/project.rb +33 -0
  25. data/lib/railz_lite/generators/project.rb~ +33 -0
  26. data/lib/railz_lite/generators/templates/application_controller.rb~ +0 -0
  27. data/lib/railz_lite/generators/templates/routes.rb +0 -0
  28. data/lib/railz_lite/generators/templates/server.rb +27 -0
  29. data/lib/railz_lite/models/associatable.rb +79 -0
  30. data/lib/railz_lite/models/associatable.rb~ +79 -0
  31. data/lib/railz_lite/models/associatable2.rb +35 -0
  32. data/lib/railz_lite/models/associatable2.rb~ +35 -0
  33. data/lib/railz_lite/models/attr_accessor_object.rb +13 -0
  34. data/lib/railz_lite/models/db_connection.rb +60 -0
  35. data/lib/railz_lite/models/searchable.rb +21 -0
  36. data/lib/railz_lite/models/searchable.rb~ +21 -0
  37. data/lib/railz_lite/models/sql_object.rb +109 -0
  38. data/lib/railz_lite/models/validatable.rb +15 -0
  39. data/lib/railz_lite/version.rb +5 -0
  40. data/railz_lite.gemspec +46 -0
  41. metadata +215 -0
@@ -0,0 +1,30 @@
1
+ require 'json'
2
+ require 'byebug'
3
+
4
+ class Session
5
+ # find the cookie for this app
6
+ # deserialize the cookie into a hash
7
+ def initialize(req)
8
+ cookie = req.cookies['_rails_lite_app']
9
+ @data = cookie.present? ? JSON.parse(cookie) : {}
10
+ end
11
+
12
+ def [](key)
13
+ @data[key]
14
+ end
15
+
16
+ def []=(key, val)
17
+ @data[key] = val
18
+ end
19
+
20
+ # serialize the hash into json and save in a cookie
21
+ # add to the responses cookies
22
+ def store_session(res)
23
+ res.set_cookie(
24
+ '_rails_lite_app',
25
+ { path: '/',
26
+ value: @data.to_json
27
+ }
28
+ )
29
+ end
30
+ end
@@ -0,0 +1,56 @@
1
+ require 'erb'
2
+ require 'byebug'
3
+
4
+ class ShowExceptions
5
+ attr_reader :app
6
+
7
+ def initialize(app)
8
+ @app = app
9
+ end
10
+
11
+ def call(env)
12
+ app.call(env)
13
+ rescue Exception => e
14
+ render_exception(e)
15
+ end
16
+
17
+ private
18
+
19
+ def render_exception(e)
20
+ dir_path = File.dirname(__FILE__)
21
+ template_fname = File.join(dir_path, 'templates', 'rescue.html.erb')
22
+ template = File.read(template_fname)
23
+ body = ERB.new(template).result(binding)
24
+
25
+ ['500', {'Content-type' => 'text/html'}, [body]]
26
+ end
27
+
28
+ def error_source_file(e)
29
+ stack_trace_top(e).first
30
+ end
31
+
32
+ def stack_trace_top(e)
33
+ e.backtrace.first.split(':')
34
+ end
35
+
36
+ def source_line_num(e)
37
+ stack_trace_top(e)[1].to_i
38
+ end
39
+
40
+ def extract_formatted_source(e)
41
+ source_file_name = error_source_file(e)
42
+ source_line_num = source_line_num(e)
43
+ source_lines = extract_source(source_file_name)
44
+ format_source(source_lines, source_line_num)
45
+ end
46
+
47
+ def extract_source(file)
48
+ File.open(file, 'r').readlines
49
+ end
50
+
51
+ def format_source(source_lines, source_line_num)
52
+ start = [0, source_line_num - 3].max
53
+ lines = source_lines[start..(start+5)]
54
+ Hash[*(start+1..(lines.count+start)).zip(lines).flatten]
55
+ end
56
+ end
@@ -0,0 +1,66 @@
1
+ require 'byebug'
2
+ class Static
3
+ attr_reader :app, :file_server, :root
4
+
5
+ def initialize(app)
6
+ @app = app
7
+ @root = 'public'
8
+ @file_server = FileServer.new
9
+ end
10
+
11
+ def call(env)
12
+ req = Rack::Request.new(env)
13
+ path = req.path
14
+
15
+ if can_match?(path)
16
+ file_server.call(env)
17
+ else
18
+ app.call(env)
19
+ end
20
+ end
21
+
22
+ private
23
+
24
+ def can_match?(path)
25
+ path.index("/#{root}")
26
+ end
27
+ end
28
+
29
+
30
+ class FileServer
31
+ MIME_TYPES = {
32
+ '.txt' => 'text/plain',
33
+ '.jpg' => 'image/jpeg',
34
+ '.zip' => 'application/zip'
35
+ }
36
+
37
+ def call(env)
38
+ res = Rack::Response.new
39
+ file_name = requested_file_name(env)
40
+
41
+ if File.exist?(file_name)
42
+ serve_file(file_name, res)
43
+ else
44
+ res.status = 404
45
+ res.write('File not found')
46
+ end
47
+ [res.status, res.headers, res.body]
48
+ end
49
+
50
+ private
51
+
52
+ def serve_file(file_name, res)
53
+ extension = File.extname(file_name)
54
+ content_type = MIME_TYPES[extension]
55
+ file = File.read(file_name)
56
+ res['Content-type'] = content_type
57
+ res.write(file)
58
+ end
59
+
60
+ def requested_file_name(env)
61
+ req = Rack::Request.new(env)
62
+ path = req.path
63
+ dir = File.dirname(__FILE__)
64
+ File.join(dir, '..', path)
65
+ end
66
+ end
@@ -0,0 +1,53 @@
1
+ <head>
2
+ <style>
3
+ .header {
4
+ background: red;
5
+ }
6
+
7
+ .source-view {
8
+ border: 10px solid lightgray;
9
+ width: 800px;
10
+ }
11
+
12
+ .line {
13
+ white-space: pre-wrap;
14
+ }
15
+
16
+ .line-num {
17
+ background: lightgray
18
+ }
19
+
20
+ .line.error {
21
+ background: red;
22
+ }
23
+ </style>
24
+ </head>
25
+
26
+ <body>
27
+ <h2 class='header'><%=e.class%>: <%=e.message%></h2>
28
+
29
+ <h4>Extracted source (around line <b><%=source_line_num(e)%></b>):</h4>
30
+
31
+ <div class='source-view'>
32
+ <table cellpadding="0" cellspacing="0">
33
+ <% extract_formatted_source(e).each do |line_num, line| %>
34
+ <tr>
35
+ <td>
36
+ <pre class='line-num'><%=line_num %></pre>
37
+ </td>
38
+ <td>
39
+ <pre class='line
40
+ <%= 'error' if line_num == source_line_num(e)%>'><%= line %></pre>
41
+ </td>
42
+ </tr>
43
+ <% end %>
44
+ </table>
45
+ </div>
46
+ <h5><%= File.expand_path(error_source_file(e)) %></h5>
47
+
48
+ <h3>Stack trace</h3>
49
+ <% e.backtrace.each do |stack_line| %>
50
+ <%= stack_line %>
51
+ <br>
52
+ <% end %>
53
+ </body>
@@ -0,0 +1,33 @@
1
+ require 'thor/group'
2
+
3
+ module RailzLite
4
+ module Generators
5
+ class Project < Thor::Group
6
+ include Thor::Actions
7
+
8
+ def self.source_root
9
+ File.dirname(__FILE__) + "/templates"
10
+ end
11
+
12
+ def add_controllers
13
+ empty_directory("/controllers")
14
+ end
15
+
16
+ def add_models
17
+ empty_directory("/models")
18
+ end
19
+
20
+ def add_server
21
+ template("server.rb", "/config/server.rb")
22
+ end
23
+
24
+ def add_views
25
+ empty_directory("/views")
26
+ end
27
+
28
+ def add_public
29
+ empty_directory("/public")
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,33 @@
1
+ require 'thor/group'
2
+
3
+ module RailzLite
4
+ module Generators
5
+ class Project < Thor::Group
6
+ argument :project_name, :type => :string
7
+ include Thor::Actions
8
+
9
+ def self.source_root
10
+ File.dirname(__FILE__) + "/templates"
11
+ end
12
+
13
+ def create_project
14
+ empty_directory(project_name)
15
+ end
16
+
17
+ def add_controllers
18
+ template("application_controller.rb", "#{project_name}/application_controller.rb")
19
+ end
20
+ def add_controllers
21
+ template("application_model.rb", "#{project_name}/application_model.rb")
22
+ end
23
+
24
+ def add_views
25
+ empty_directory("#{project_name}/views")
26
+ end
27
+
28
+ def add_public
29
+ empty_directory("#{project_name}/public")
30
+ end
31
+ end
32
+ end
33
+ end
File without changes
@@ -0,0 +1,27 @@
1
+ require 'rack'
2
+ require 'railz_lite/controllers/static'
3
+ require 'railz_lite/controllers/show_exceptions'
4
+ require 'railz_lite/controllers/router'
5
+
6
+ router = Router.new
7
+ router.draw do
8
+ # add routes here
9
+ end
10
+
11
+ app = Proc.new do |env|
12
+ req = Rack::Request.new(env)
13
+ res = Rack::Response.new
14
+ router.run(req, res)
15
+ res.finish
16
+ end
17
+
18
+ app = Rack::Builder.new do
19
+ use Show_Exceptions # generates helpful error messages
20
+ use Static # serves static assets from /public
21
+ run app
22
+ end.to_app
23
+
24
+ Rack::Server.start(
25
+ app: app,
26
+ Port: 3000
27
+ )
@@ -0,0 +1,79 @@
1
+ require_relative 'searchable'
2
+ require 'active_support/inflector'
3
+
4
+ class AssocOptions
5
+ attr_accessor(
6
+ :foreign_key,
7
+ :class_name,
8
+ :primary_key
9
+ )
10
+
11
+ def model_class
12
+ class_name.constantize
13
+ end
14
+
15
+ def table_name
16
+ model_class.table_name
17
+ end
18
+ end
19
+
20
+ class BelongsToOptions < AssocOptions
21
+ def initialize(name, options = {})
22
+ foreign_key_sym = "#{name}_id".to_sym
23
+ class_name_val = name.to_s.camelcase.singularize
24
+ send("primary_key=", :id)
25
+ send("foreign_key=", foreign_key_sym)
26
+ send("class_name=", class_name_val)
27
+
28
+ options.each do |attr, val|
29
+ send("#{attr}=", val)
30
+ end
31
+ end
32
+ end
33
+
34
+ class HasManyOptions < AssocOptions
35
+ def initialize(name, self_class_name, options = {})
36
+ foreign_key_sym = "#{self_class_name.underscore}_id".to_sym
37
+ class_name_val = name.to_s.camelcase.singularize
38
+
39
+ send("primary_key=", :id)
40
+ send("foreign_key=", foreign_key_sym)
41
+ send("class_name=", class_name_val)
42
+
43
+ options.each do |attr, val|
44
+ send("#{attr}=", val)
45
+ end
46
+ end
47
+ end
48
+
49
+ module Associatable
50
+ def belongs_to(name, options = {})
51
+ options = BelongsToOptions.new(name, options)
52
+ assoc_options[name] = options
53
+ define_method(name) do
54
+ foreign_key = send(options.foreign_key)
55
+ primary_key = options.primary_key
56
+ params = [[primary_key, foreign_key]].to_h
57
+ options.model_class.where(params).first
58
+ end
59
+ end
60
+
61
+ def has_many(name, options = {})
62
+ options = HasManyOptions.new(name, self.name, options)
63
+ define_method(name) do
64
+ foreign_key = options.foreign_key
65
+ primary_key = send(options.primary_key)
66
+ params = [[foreign_key, primary_key]].to_h
67
+ options.model_class.where(params)
68
+ end
69
+ end
70
+
71
+ def assoc_options
72
+ @assoc_options ||= {}
73
+ @assoc_options
74
+ end
75
+ end
76
+
77
+ class SQLObject
78
+ extend Associatable
79
+ end
@@ -0,0 +1,79 @@
1
+ require_relative '02_searchable'
2
+ require 'active_support/inflector'
3
+
4
+ class AssocOptions
5
+ attr_accessor(
6
+ :foreign_key,
7
+ :class_name,
8
+ :primary_key
9
+ )
10
+
11
+ def model_class
12
+ class_name.constantize
13
+ end
14
+
15
+ def table_name
16
+ model_class.table_name
17
+ end
18
+ end
19
+
20
+ class BelongsToOptions < AssocOptions
21
+ def initialize(name, options = {})
22
+ foreign_key_sym = "#{name}_id".to_sym
23
+ class_name_val = name.to_s.camelcase.singularize
24
+ send("primary_key=", :id)
25
+ send("foreign_key=", foreign_key_sym)
26
+ send("class_name=", class_name_val)
27
+
28
+ options.each do |attr, val|
29
+ send("#{attr}=", val)
30
+ end
31
+ end
32
+ end
33
+
34
+ class HasManyOptions < AssocOptions
35
+ def initialize(name, self_class_name, options = {})
36
+ foreign_key_sym = "#{self_class_name.underscore}_id".to_sym
37
+ class_name_val = name.to_s.camelcase.singularize
38
+
39
+ send("primary_key=", :id)
40
+ send("foreign_key=", foreign_key_sym)
41
+ send("class_name=", class_name_val)
42
+
43
+ options.each do |attr, val|
44
+ send("#{attr}=", val)
45
+ end
46
+ end
47
+ end
48
+
49
+ module Associatable
50
+ def belongs_to(name, options = {})
51
+ options = BelongsToOptions.new(name, options)
52
+ assoc_options[name] = options
53
+ define_method(name) do
54
+ foreign_key = send(options.foreign_key)
55
+ primary_key = options.primary_key
56
+ params = [[primary_key, foreign_key]].to_h
57
+ options.model_class.where(params).first
58
+ end
59
+ end
60
+
61
+ def has_many(name, options = {})
62
+ options = HasManyOptions.new(name, self.name, options)
63
+ define_method(name) do
64
+ foreign_key = options.foreign_key
65
+ primary_key = send(options.primary_key)
66
+ params = [[foreign_key, primary_key]].to_h
67
+ options.model_class.where(params)
68
+ end
69
+ end
70
+
71
+ def assoc_options
72
+ @assoc_options ||= {}
73
+ @assoc_options
74
+ end
75
+ end
76
+
77
+ class SQLObject
78
+ extend Associatable
79
+ end