rails_lite 0.1.0

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 (80) hide show
  1. checksums.yaml +7 -0
  2. data/.DS_Store +0 -0
  3. data/.gitignore +8 -0
  4. data/Gemfile +6 -0
  5. data/Gemfile.lock +22 -0
  6. data/LICENSE.txt +21 -0
  7. data/README.md +39 -0
  8. data/Rakefile +2 -0
  9. data/bin/console +14 -0
  10. data/bin/setup +8 -0
  11. data/exe/railslite +4 -0
  12. data/lib/.DS_Store +0 -0
  13. data/lib/rails_lite.rb +6 -0
  14. data/lib/rails_lite/.DS_Store +0 -0
  15. data/lib/rails_lite/cli.rb +65 -0
  16. data/lib/rails_lite/version.rb +3 -0
  17. data/lib/scaffold/.DS_Store +0 -0
  18. data/lib/scaffold/Gemfile +12 -0
  19. data/lib/scaffold/app/controllers/albums_controller.rb +55 -0
  20. data/lib/scaffold/app/controllers/application_controller.rb +45 -0
  21. data/lib/scaffold/app/controllers/bands_controller.rb +62 -0
  22. data/lib/scaffold/app/controllers/notes_controller.rb +26 -0
  23. data/lib/scaffold/app/controllers/sessions_controller.rb +34 -0
  24. data/lib/scaffold/app/controllers/tracks_controller.rb +55 -0
  25. data/lib/scaffold/app/controllers/users_controller.rb +41 -0
  26. data/lib/scaffold/app/models/album.rb +14 -0
  27. data/lib/scaffold/app/models/application_model.rb +5 -0
  28. data/lib/scaffold/app/models/band.rb +7 -0
  29. data/lib/scaffold/app/models/note.rb +7 -0
  30. data/lib/scaffold/app/models/track.rb +20 -0
  31. data/lib/scaffold/app/models/user.rb +42 -0
  32. data/lib/scaffold/app/views/albums_controller/edit.html.erb +51 -0
  33. data/lib/scaffold/app/views/albums_controller/new.html.erb +50 -0
  34. data/lib/scaffold/app/views/albums_controller/show.html.erb +25 -0
  35. data/lib/scaffold/app/views/application.html.erb +41 -0
  36. data/lib/scaffold/app/views/bands_controller/edit.html.erb +16 -0
  37. data/lib/scaffold/app/views/bands_controller/index.html.erb +12 -0
  38. data/lib/scaffold/app/views/bands_controller/json.json.jbuilder +3 -0
  39. data/lib/scaffold/app/views/bands_controller/new.html.erb +15 -0
  40. data/lib/scaffold/app/views/bands_controller/show.html.erb +27 -0
  41. data/lib/scaffold/app/views/sessions_controller/new.html.erb +22 -0
  42. data/lib/scaffold/app/views/tracks_controller/edit.html.erb +60 -0
  43. data/lib/scaffold/app/views/tracks_controller/new.html.erb +59 -0
  44. data/lib/scaffold/app/views/tracks_controller/show.html.erb +56 -0
  45. data/lib/scaffold/app/views/users_controller/new.html.erb +22 -0
  46. data/lib/scaffold/app/views/users_controller/show.html.erb +4 -0
  47. data/lib/scaffold/bin/pry +13 -0
  48. data/lib/scaffold/bin/routes +10 -0
  49. data/lib/scaffold/bin/server +32 -0
  50. data/lib/scaffold/config/routes.rb +26 -0
  51. data/lib/scaffold/db/database.db +0 -0
  52. data/lib/scaffold/db/database.sql +48 -0
  53. data/lib/scaffold/lib/.DS_Store +0 -0
  54. data/lib/scaffold/lib/controller/controller_base.rb +183 -0
  55. data/lib/scaffold/lib/controller/controller_callbacks.rb +17 -0
  56. data/lib/scaffold/lib/controller/cookies/flash.rb +33 -0
  57. data/lib/scaffold/lib/controller/cookies/flash_now.rb +15 -0
  58. data/lib/scaffold/lib/controller/cookies/session.rb +29 -0
  59. data/lib/scaffold/lib/controller/strong_params.rb +40 -0
  60. data/lib/scaffold/lib/middleware/file_server.rb +42 -0
  61. data/lib/scaffold/lib/middleware/show_exceptions.rb +62 -0
  62. data/lib/scaffold/lib/middleware/static.rb +31 -0
  63. data/lib/scaffold/lib/middleware/templates/rescue.html.erb +49 -0
  64. data/lib/scaffold/lib/model/associations/assoc_options.rb +16 -0
  65. data/lib/scaffold/lib/model/associations/associatable.rb +120 -0
  66. data/lib/scaffold/lib/model/associations/belongs_to_options.rb +18 -0
  67. data/lib/scaffold/lib/model/associations/has_many_options.rb +17 -0
  68. data/lib/scaffold/lib/model/db_connection.rb +59 -0
  69. data/lib/scaffold/lib/model/model_base.rb +183 -0
  70. data/lib/scaffold/lib/model/model_callbacks.rb +46 -0
  71. data/lib/scaffold/lib/model/relations/relation.rb +151 -0
  72. data/lib/scaffold/lib/model/relations/searchable.rb +27 -0
  73. data/lib/scaffold/lib/model/validations/validations.rb +31 -0
  74. data/lib/scaffold/lib/model/validations/validator.rb +81 -0
  75. data/lib/scaffold/lib/router/route.rb +24 -0
  76. data/lib/scaffold/lib/router/router.rb +192 -0
  77. data/lib/scaffold/lib/utils/url_helpers.rb +96 -0
  78. data/lib/scaffold/public/main.css +165 -0
  79. data/rails_lite.gemspec +41 -0
  80. metadata +168 -0
@@ -0,0 +1,17 @@
1
+ module ControllerCallbacks
2
+ METHODS = [:index, :create, :new, :edit, :update, :show, :destroy]
3
+
4
+ def before_action(method, options = { only: METHODS, except: [] })
5
+ default = { only: METHODS, except: [] }
6
+ default.merge!(options)
7
+
8
+ names = default[:only] - default[:except]
9
+ names.each do |name|
10
+ m = instance_method(name)
11
+ define_method(name) do
12
+
13
+ m.bind(self).call unless send(method)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,33 @@
1
+ require 'json'
2
+ require_relative 'flash_now'
3
+
4
+ class Flash
5
+ attr_reader :now
6
+
7
+ def initialize(req)
8
+ cookie = req.cookies['_rails_lite_app_flash']
9
+ if cookie
10
+ @now = FlashNow.new(JSON.parse(cookie))
11
+ else
12
+ @now = FlashNow.new
13
+ end
14
+
15
+ @cookie_data = {}
16
+ end
17
+
18
+ def [](key)
19
+ now[key.to_s] || cookie_data[key.to_s]
20
+ end
21
+
22
+ def []=(key, val)
23
+ cookie_data[key.to_s] = val
24
+ end
25
+
26
+ def store_flash(res)
27
+ cookie = { path: '/', value: JSON.generate(cookie_data) }
28
+ res.set_cookie('_rails_lite_app_flash', cookie)
29
+ end
30
+
31
+ private
32
+ attr_reader :cookie_data
33
+ end
@@ -0,0 +1,15 @@
1
+ class FlashNow
2
+ attr_reader :hash
3
+
4
+ def initialize(hash = {})
5
+ @hash = hash
6
+ end
7
+
8
+ def [](key)
9
+ hash[key.to_s]
10
+ end
11
+
12
+ def []=(key, val)
13
+ hash[key.to_s] = val
14
+ end
15
+ end
@@ -0,0 +1,29 @@
1
+ require 'json'
2
+
3
+ class Session
4
+
5
+ def initialize(req)
6
+ cookie = req.cookies['_rails_lite_app']
7
+ if cookie
8
+ @cookie_data = JSON.parse(cookie)
9
+ else
10
+ @cookie_data = {}
11
+ end
12
+ end
13
+
14
+ def [](key)
15
+ cookie_data[key.to_s]
16
+ end
17
+
18
+ def []=(key, val)
19
+ cookie_data[key.to_s] = val
20
+ end
21
+
22
+ def store_session(res)
23
+ cookie = { path: '/', value: JSON.generate(cookie_data) }
24
+ res.set_cookie('_rails_lite_app', cookie)
25
+ end
26
+
27
+ private
28
+ attr_reader :cookie_data
29
+ end
@@ -0,0 +1,40 @@
1
+ class StrongParams
2
+ attr_reader :params
3
+
4
+ def self.to_sym(hash)
5
+ sym_hash = {}
6
+ hash.each do |key, val|
7
+ sym_hash[key.to_sym] = (val.is_a?(Hash) ? to_sym(val) : val)
8
+ end
9
+
10
+ sym_hash
11
+ end
12
+
13
+ def self.new_syms(params)
14
+ StrongParams.new(StrongParams.to_sym(params))
15
+ end
16
+
17
+ def initialize(params)
18
+ @params = params
19
+ end
20
+
21
+ def require(class_name)
22
+ StrongParams.new(params[class_name])
23
+ end
24
+
25
+ def permit(*keys)
26
+ permited_params = {}
27
+ keys.each { |key| permited_params[key] = params[key] }
28
+ permited_params
29
+ end
30
+
31
+ def [](key)
32
+ params[key.to_sym]
33
+ end
34
+
35
+ private
36
+
37
+ def []=(key, val)
38
+ params[key.to_sym] = val
39
+ end
40
+ end
@@ -0,0 +1,42 @@
1
+ class FileServer
2
+
3
+ MIME_TYPES = {
4
+ '.txt' => 'text/plain',
5
+ '.jpg' => 'image/jpeg',
6
+ '.zip' => 'application/zip'
7
+ }
8
+
9
+ def initialize(root)
10
+ @root = root
11
+ end
12
+
13
+ def call(env)
14
+ res = Rack::Response.new
15
+ file_name = requested_file_name(env)
16
+
17
+ if File.exist?(file_name)
18
+ serve_file(file_name, res)
19
+ else
20
+ res.status = 404
21
+ res.write("File not found")
22
+ end
23
+ res
24
+ end
25
+
26
+ private
27
+
28
+ def serve_file(file_name, res)
29
+ extension = File.extname(file_name)
30
+ content_type = MIME_TYPES[extension]
31
+ file = File.read(file_name)
32
+ res["Content-type"] = content_type
33
+ res.write(file)
34
+ end
35
+
36
+ def requested_file_name(env)
37
+ req = Rack::Request.new(env)
38
+ path = req.path
39
+ dir = File.dirname(__FILE__)
40
+ File.join(dir, '..', '..', path)
41
+ end
42
+ end
@@ -0,0 +1,62 @@
1
+ require 'erb'
2
+
3
+ class ShowExceptions
4
+ attr_reader :app
5
+
6
+ def initialize(app)
7
+ @app = app
8
+ end
9
+
10
+ def call(env)
11
+ app.call(env)
12
+ rescue Exception => e
13
+ render_exception(e)
14
+ end
15
+
16
+ private
17
+
18
+ def render_exception(e)
19
+ dir_path = File.dirname(__FILE__)
20
+ template_fname = File.join(dir_path, "templates", "rescue.html.erb")
21
+ template = File.read(template_fname)
22
+ body = ERB.new(template).result(binding)
23
+
24
+ ['500', {'Content-type' => 'text/html'}, [body]]
25
+ end
26
+
27
+ def error_source_file(e)
28
+ # stack_trace_top = e.backtrace.first.split(':')
29
+ stack_trace_top(e)[0]
30
+ end
31
+
32
+ def stack_trace_top(e)
33
+ e.backtrace.first.split(':')
34
+ end
35
+
36
+ def extract_formatted_source(e)
37
+ source_file_name = error_source_file(e)
38
+ source_line_num = source_line_num(e)
39
+ source_lines = extract_source(source_file_name)
40
+ format_source(source_lines, source_line_num)
41
+ end
42
+
43
+ def source_line_num(e)
44
+ stack_trace_top(e)[1].to_i
45
+ end
46
+
47
+ def formatted_source(file, source_line_num)
48
+ source_lines = extract_source(file)
49
+ format_source(source_lines, source_line_num)
50
+ end
51
+
52
+ def extract_source(file)
53
+ source_file = File.open(file, 'r')
54
+ source_file.readlines
55
+ end
56
+
57
+ def format_source(source_lines, source_line_num)
58
+ start = [0, source_line_num - 3].max
59
+ lines = source_lines[start..(start + 5)]
60
+ Hash[*(start+1..(lines.count + start)).zip(lines).flatten]
61
+ end
62
+ end
@@ -0,0 +1,31 @@
1
+ require_relative 'file_server'
2
+
3
+ class Static
4
+ attr_reader :app, :root, :file_server
5
+
6
+ def initialize(app)
7
+ @app = app
8
+ @root = :public
9
+ @file_server = FileServer.new(root)
10
+ end
11
+
12
+ def call(env)
13
+ req = Rack::Request.new(env)
14
+ path = req.path
15
+
16
+ if can_serve?(path)
17
+ res = file_server.call(env)
18
+ else
19
+ res = app.call(env)
20
+ end
21
+
22
+ res
23
+ end
24
+
25
+ private
26
+
27
+ def can_serve?(path)
28
+ path.index("/#{root}")
29
+ end
30
+ end
31
+
@@ -0,0 +1,49 @@
1
+ <head>
2
+ <style>
3
+ .header {
4
+ background: red;
5
+ }
6
+ .source-view {
7
+ border: 10px solid lightgray;
8
+ width: 800px;
9
+ }
10
+ .line {
11
+ white-space: pre-wrap;
12
+ }
13
+ .line-num {
14
+ background: lightgray
15
+ }
16
+ .line.error {
17
+ background: red;
18
+ }
19
+ </style>
20
+ </head>
21
+
22
+ <body>
23
+ <h2 class='header'><%=e.class%>: <%=e.message%></h2>
24
+
25
+ <h4>Extracted source (around line <b><%=source_line_num(e)%></b>):</h4>
26
+
27
+ <div class='source-view'>
28
+ <table cellpadding="0" cellspacing="0">
29
+ <% extract_formatted_source(e).each do |line_num, line| %>
30
+ <tr>
31
+ <td>
32
+ <pre class='line-num'><%=line_num %></pre>
33
+ </td>
34
+ <td>
35
+ <pre class='line
36
+ <%= 'error' if line_num == source_line_num(e)%>'><%= line %></pre>
37
+ </td>
38
+ </tr>
39
+ <% end %>
40
+ </table>
41
+ </div>
42
+ <h5><%= File.expand_path(error_source_file(e)) %></h5>
43
+
44
+ <h3>Stack trace</h3>
45
+ <% e.backtrace.each do |stack_line| %>
46
+ <%= stack_line %>
47
+ <br>
48
+ <% end %>
49
+ </body>
@@ -0,0 +1,16 @@
1
+ class AssocOptions
2
+ attr_accessor(
3
+ :foreign_key,
4
+ :class_name,
5
+ :primary_key,
6
+ :optional
7
+ )
8
+
9
+ def model_class
10
+ class_name.to_s.constantize
11
+ end
12
+
13
+ def table_name
14
+ model_class.table_name
15
+ end
16
+ end
@@ -0,0 +1,120 @@
1
+ require_relative 'has_many_options'
2
+ require_relative 'belongs_to_options'
3
+
4
+ module Associatable
5
+
6
+ def belongs_to(name, options = {})
7
+ options = BelongsToOptions.new(name, options)
8
+ assoc_options[name] = options
9
+
10
+ self.define_method(name) do
11
+ validations = self.class.validators
12
+ .map { |validator| [validator.attribute, validator.options[:presence]] }
13
+
14
+ unless options.optional || validations.include?([options.foreign_key, true])
15
+ self.class.validates options.foreign_key, presence: true
16
+ end
17
+
18
+ options.model_class.find(self.send(options.foreign_key))
19
+ end
20
+ end
21
+
22
+ def has_many(name, options = {})
23
+ if options[:through] && options[:source]
24
+ has_many_through(name, options[:through], options[:source])
25
+ else
26
+ options = HasManyOptions.new(name, self.name, options)
27
+ assoc_options[name] = options
28
+
29
+ self.define_method(name) do
30
+ options.model_class.where(options.foreign_key => self.send(options.primary_key)).parsed_query
31
+ end
32
+ end
33
+ end
34
+
35
+ def assoc_options
36
+ @assoc_options ||= {}
37
+ @assoc_options
38
+ end
39
+
40
+ def has_one(name, options)
41
+ through_name = options[:through]
42
+ source_name = options[:source]
43
+
44
+ define_method(name) do
45
+ through_options = self.class.assoc_options[through_name]
46
+ source_options = through_options.model_class.assoc_options[source_name]
47
+
48
+ through_table = through_options.table_name
49
+ through_pk = through_options.primary_key
50
+ through_fk = through_options.foreign_key
51
+
52
+ source_table = source_options.table_name
53
+ source_pk = source_options.primary_key
54
+ source_fk = source_options.foreign_key
55
+
56
+ key_val = self.send(through_fk)
57
+ results = DBConnection.execute(<<-SQL, key_val)
58
+ SELECT
59
+ #{source_table}.*
60
+ FROM
61
+ #{through_table}
62
+ JOIN
63
+ #{source_table}
64
+ ON
65
+ #{through_table}.#{source_fk} = #{source_table}.#{source_pk}
66
+ WHERE
67
+ #{through_table}.#{through_pk} = ?
68
+ SQL
69
+
70
+ source_options.model_class.parse_all(results).first
71
+ end
72
+ end
73
+
74
+ def has_many_through(name, through_name, source_name)
75
+ define_method(name) do
76
+ through_options = self.class.assoc_options[through_name]
77
+ source_options = through_options.model_class.assoc_options[source_name]
78
+
79
+ if through_options.is_a?(BelongsToOptions)
80
+ through_self_id = through_options.primary_key
81
+ self_through_id = through_options.foreign_key
82
+ else
83
+ through_self_id = through_options.foreign_key
84
+ self_through_id = through_options.primary_key
85
+ end
86
+
87
+ if source_options.is_a?(BelongsToOptions)
88
+ through_source_id = source_options.foreign_key
89
+ source_through_id = source_options.primary_key
90
+ else
91
+ through_source_id = source_options.primary_key
92
+ source_through_id = source_options.foreign_key
93
+ end
94
+
95
+ through_table = through_options.table_name
96
+ source_table = source_options.table_name
97
+
98
+ key_val = self.send(:id)
99
+ results = DBConnection.execute(<<-SQL, key_val)
100
+ SELECT
101
+ #{source_table}.*
102
+ FROM
103
+ #{through_table}
104
+ JOIN
105
+ #{source_table}
106
+ ON
107
+ #{through_table}.#{through_source_id} = #{source_table}.#{source_through_id}
108
+ JOIN
109
+ #{self.class.table_name}
110
+ ON
111
+ #{self.class.table_name}.#{self_through_id} = #{through_table}.#{through_self_id}
112
+ WHERE
113
+ #{self.class.table_name}.id = ?
114
+ SQL
115
+
116
+ source_options.model_class.parse_all(results)
117
+ end
118
+ end
119
+
120
+ end