rails_lite 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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,18 @@
1
+ require_relative 'assoc_options'
2
+
3
+ class BelongsToOptions < AssocOptions
4
+
5
+ def initialize(name, options = {})
6
+ default = {
7
+ foreign_key: "#{name}_id".to_sym,
8
+ class_name: name.to_s.capitalize,
9
+ primary_key: :id,
10
+ optional: false
11
+ }
12
+
13
+ default.merge!(options)
14
+ @foreign_key = default[:foreign_key]
15
+ @class_name = default[:class_name]
16
+ @primary_key = default[:primary_key]
17
+ end
18
+ end
@@ -0,0 +1,17 @@
1
+ require_relative 'assoc_options'
2
+
3
+ class HasManyOptions < AssocOptions
4
+
5
+ def initialize(name, self_class_name, options = {})
6
+ default = {
7
+ foreign_key: "#{self_class_name.downcase}_id".to_sym,
8
+ class_name: name.to_s.capitalize.singularize,
9
+ primary_key: :id
10
+ }
11
+
12
+ default.merge!(options)
13
+ @foreign_key = default[:foreign_key]
14
+ @class_name = default[:class_name]
15
+ @primary_key = default[:primary_key]
16
+ end
17
+ end
@@ -0,0 +1,59 @@
1
+ require 'sqlite3'
2
+
3
+ PRINT_QUERIES = ENV['PRINT_QUERIES'] == 'true'
4
+ ROOT_FOLDER = File.join(File.dirname(__FILE__), '..', '..')
5
+ SQL_FILE = File.join(ROOT_FOLDER, 'db', 'database.sql')
6
+ DB_FILE = File.join(ROOT_FOLDER, 'db', 'database.db')
7
+
8
+ class DBConnection
9
+ def self.open(db_file_name)
10
+ @db = SQLite3::Database.new(db_file_name)
11
+ @db.results_as_hash = false
12
+ @db.type_translation = true
13
+
14
+ @db
15
+ end
16
+
17
+ def self.reset
18
+ commands = [
19
+ "rm '#{DB_FILE}'",
20
+ "cat '#{SQL_FILE}' | sqlite3 '#{DB_FILE}'"
21
+ ]
22
+
23
+ commands.each { |command| `#{command}` }
24
+ DBConnection.open(DB_FILE)
25
+ end
26
+
27
+ def self.instance
28
+ DBConnection.open(DB_FILE)
29
+
30
+ @db
31
+ end
32
+
33
+ def self.execute(*args)
34
+ print_query(*args)
35
+ instance.execute(*args)
36
+ end
37
+
38
+ def self.execute2(*args)
39
+ print_query(*args)
40
+ instance.execute2(*args)
41
+ end
42
+
43
+ def self.last_insert_row_id
44
+ instance.last_insert_row_id
45
+ end
46
+
47
+ private
48
+
49
+ def self.print_query(query, *interpolation_args)
50
+ return unless PRINT_QUERIES
51
+
52
+ puts '--------------------'
53
+ puts query
54
+ unless interpolation_args.empty?
55
+ puts "interpolate: #{interpolation_args.inspect}"
56
+ end
57
+ puts '--------------------'
58
+ end
59
+ end
@@ -0,0 +1,183 @@
1
+ require 'active_support/inflector'
2
+ require_relative './db_connection'
3
+ require_relative './relations/searchable'
4
+ require_relative './associations/associatable'
5
+ require_relative './validations/validations'
6
+ require_relative './relations/relation'
7
+ require_relative './model_callbacks'
8
+
9
+ class ModelBase
10
+ extend Searchable
11
+ extend Associatable
12
+ include Validations
13
+ include ModelCallbacks
14
+
15
+ def self.columns
16
+ @columns ||= DBConnection.execute2(<<-SQL)
17
+ Select
18
+ *
19
+ FROM
20
+ '#{self.table_name}'
21
+ LIMIT 0
22
+ SQL
23
+ .first.map!(&:to_sym)
24
+ end
25
+
26
+ def self.finalize!
27
+ columns.each do |column|
28
+ define_method(column) do
29
+ attributes[column]
30
+ end
31
+
32
+ setter_name = column.to_s + "="
33
+ define_method(setter_name) do |val|
34
+ attributes[column] = val
35
+ end
36
+ end
37
+ end
38
+
39
+ def self.table_name=(table_name)
40
+ @table_name = table_name
41
+ end
42
+
43
+ def self.table_name
44
+ @table_name ||= self.name.underscore.pluralize
45
+ end
46
+
47
+ def self.all
48
+ results = DBConnection.execute("Select * FROM #{self.table_name}")
49
+ parse_all(results)
50
+ end
51
+
52
+ def self.first
53
+ results = DBConnection.execute("Select * FROM #{self.table_name} LIMIT 1")
54
+ parse_all(results).first
55
+ end
56
+
57
+ def self.last
58
+ all.last
59
+ end
60
+
61
+ def self.parse_all(results)
62
+ results.map do |arr|
63
+ params = {}
64
+ columns.each_with_index do |column, idx|
65
+ params[column] = arr[idx]
66
+ end
67
+
68
+ self.new(params)
69
+ end
70
+ end
71
+
72
+ def self.find(id)
73
+ results = DBConnection.execute(<<-SQL, id)
74
+ Select
75
+ *
76
+ FROM
77
+ #{table_name}
78
+ WHERE
79
+ id = ?
80
+ SQL
81
+
82
+ parse_all(results).first
83
+ end
84
+
85
+ def initialize(params = {})
86
+ self.class.finalize!
87
+
88
+ params.each do |attribute, val|
89
+ setter = attribute.to_s + "="
90
+ raise "Unknown attribute '#{k}'" unless self.class.method_defined?(setter.to_sym)
91
+ self.send(setter, val)
92
+ end
93
+ end
94
+
95
+ def update(params = {})
96
+ params.each do |attribute, val|
97
+ setter = attribute.to_s + "="
98
+ raise "Unknown attribute '#{k}'" unless self.class.method_defined?(setter.to_sym)
99
+ self.send(setter, val)
100
+ end
101
+
102
+ self
103
+ end
104
+
105
+ def update_attributes(params = {})
106
+ update(params)
107
+ save ? true : false
108
+ end
109
+
110
+ def attributes
111
+ @attributes ||= {}
112
+ end
113
+
114
+ def attribute_values
115
+ attributes.values
116
+ end
117
+
118
+ def save
119
+ if self.valid?
120
+ id ? update_database : insert
121
+ true
122
+ else
123
+ false
124
+ end
125
+ end
126
+
127
+ def save!
128
+ if self.valid?
129
+ id ? update_database : insert
130
+ self
131
+ else
132
+ raise self.errors.join(", ")
133
+ end
134
+ end
135
+
136
+ def destroy
137
+ DBConnection.instance.execute(<<-SQL, id)
138
+ DELETE
139
+ FROM
140
+ #{self.class.table_name}
141
+ WHERE
142
+ id = ?
143
+ SQL
144
+ end
145
+
146
+ private
147
+
148
+ def insert
149
+ raise "#{self} already in database" if self.id
150
+ db_connection = DBConnection.instance
151
+ db_connection.execute(<<-SQL, *attribute_values)
152
+ INSERT INTO
153
+ #{self.class.table_name} (#{column_names})
154
+ VALUES
155
+ (#{question_marks})
156
+ SQL
157
+ self.id = db_connection.last_insert_row_id
158
+ # self.id = DBConnection.execute("SELECT MAX(id) FROM #{self.class.table_name}").first.first
159
+ end
160
+
161
+ def update_database
162
+ DBConnection.instance.execute(<<-SQL, *attribute_values, id)
163
+ UPDATE
164
+ #{self.class.table_name}
165
+ SET
166
+ #{update_string}
167
+ WHERE
168
+ id = ?
169
+ SQL
170
+ end
171
+
172
+ def question_marks
173
+ (["?"] * attributes.count).join(", ")
174
+ end
175
+
176
+ def column_names
177
+ attributes.keys.map(&:to_s).join(", ")
178
+ end
179
+
180
+ def update_string
181
+ attributes.keys.map { |attr| "#{attr} = ?" }.join(", ")
182
+ end
183
+ end
@@ -0,0 +1,46 @@
1
+ require 'active_support/concern'
2
+
3
+ module ModelCallbacks
4
+ extend ActiveSupport::Concern
5
+
6
+ def after_init
7
+ names = self.class.after_init_names[self.class]
8
+ names.each { |name| self.send(name) }
9
+ end
10
+
11
+ def self.included(klass)
12
+ class << klass
13
+ alias_method :__new, :new
14
+ def new(*args)
15
+ e = __new(*args)
16
+ e.after_init
17
+ e
18
+ end
19
+ end
20
+ end
21
+
22
+ def before_valid
23
+ names = self.class.before_valid_names[self.class]
24
+ names.each { |name| self.send(name) }
25
+ end
26
+
27
+
28
+ module ClassMethods
29
+
30
+ def before_valid_names
31
+ @@before_valid_names ||= Hash.new { |h, k| h[k] = [] }
32
+ end
33
+
34
+ def after_init_names
35
+ @@after_init_names ||= Hash.new { |h, k| h[k] = [] }
36
+ end
37
+
38
+ def after_initialize(*names)
39
+ after_init_names[self] += names
40
+ end
41
+
42
+ def before_validation(*names)
43
+ before_valid_names[self] += names
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,151 @@
1
+ class Relation
2
+ attr_reader(
3
+ :where_line,
4
+ :obj_class,
5
+ :where_vals,
6
+ :table_name,
7
+ :join_line,
8
+ :select_line
9
+ )
10
+
11
+ def initialize(options)
12
+ default = {
13
+ class: options[:table_name].singularize.capitalize.constantize,
14
+ select_line: "*",
15
+ table_name: "",
16
+ where_line: "",
17
+ where_vals: [],
18
+ join_line: ""
19
+ }
20
+
21
+ default.merge!(options)
22
+ @table_name = default[:table_name]
23
+ @where_line = default[:where_line]
24
+ @where_vals = default[:where_vals]
25
+ @obj_class = default[:class]
26
+ @join_line = default[:join_line]
27
+ @select_line = default[:select_line]
28
+ end
29
+
30
+ def select(*params)
31
+ if params.length == 1 && params.first.is_a?(String)
32
+ new_line = params.first
33
+ else
34
+ new_line = select_string(*params)
35
+ end
36
+
37
+ self.select_line = new_line
38
+ self
39
+ end
40
+
41
+ def where(params)
42
+ if params.is_a?(Hash)
43
+ new_line = params_string(params)
44
+ new_vals = params.values
45
+ else
46
+ new_line = params
47
+ new_vals = []
48
+ end
49
+
50
+ if where_line.blank?
51
+ self.where_line = new_line
52
+ else
53
+ self.where_line = "#{where_line} AND #{new_line}"
54
+ end
55
+
56
+ self.where_vals = where_vals + new_vals
57
+ self
58
+ end
59
+
60
+ def includes(assoc)
61
+ result_array = []
62
+ result_hash = Hash.new { |h, k| h[k] = [] }
63
+ join_options = obj_class.assoc_options[assoc]
64
+ join_table_name = join_options.table_name
65
+ join_class = join_options.model_class
66
+
67
+ left_joins(join_table_name)
68
+ data = query
69
+ obj_params_length = obj_class.columns.length
70
+
71
+ data.each do |el|
72
+ obj = parse_all([el.take(obj_params_length)]).first
73
+ join_arr = el.drop(obj_params_length)
74
+ join_obj = join_class.parse_all([join_arr]).first
75
+
76
+ result_array << obj if result_hash[obj.id].empty?
77
+ result_hash[obj.id] << join_obj unless join_arr.all?(&:nil?)
78
+ end
79
+
80
+ [result_array, result_hash]
81
+ end
82
+
83
+ def joins(name)
84
+ join_options = obj_class.assoc_options.values
85
+ .find { |options| options.table_name == name.to_s }
86
+
87
+ if join_options.is_a?(BelongsToOptions)
88
+ table_id = join_options.foreign_key
89
+ join_table_id = join_options.primary_key
90
+ else
91
+ table_id = join_options.primary_key
92
+ join_table_id = join_options.foreign_key
93
+ end
94
+
95
+ self.join_line = "JOIN #{join_options.table_name} on #{join_options.table_name}.#{join_table_id} = #{table_name}.#{table_id}"
96
+ self
97
+ end
98
+
99
+ def left_joins(name)
100
+ join_options = obj_class.assoc_options.values
101
+ .find { |options| options.table_name == name.to_s }
102
+
103
+ if join_options.is_a?(BelongsToOptions)
104
+ table_id = join_options.foreign_key
105
+ join_table_id = join_options.primary_key
106
+ else
107
+ table_id = join_options.primary_key
108
+ join_table_id = join_options.foreign_key
109
+ end
110
+
111
+ self.join_line = "LEFT OUTER JOIN #{join_options.table_name} on #{join_options.table_name}.#{join_table_id} = #{table_name}.#{table_id}"
112
+ self
113
+ end
114
+
115
+ def method_missing(m, *args, &block)
116
+ parsed_query.send(m, *args, &block)
117
+ end
118
+
119
+ def parsed_query
120
+ parse_all(query)
121
+ end
122
+
123
+ def query
124
+ result = DBConnection.execute(<<-SQL, where_vals)
125
+ SELECT
126
+ #{select_line}
127
+ FROM
128
+ #{table_name}
129
+ #{join_line}
130
+ #{where_line.blank? ? "" : "WHERE"}
131
+ #{where_line}
132
+ SQL
133
+
134
+ result
135
+ end
136
+
137
+ private
138
+ attr_writer :where_line, :where_vals, :join_line, :select_line
139
+
140
+ def parse_all(results)
141
+ obj_class.parse_all(results)
142
+ end
143
+
144
+ def params_string(params)
145
+ params.keys.map { |key| "#{table_name}.#{key} = ?" }.join(" AND ")
146
+ end
147
+
148
+ def select_string(*params)
149
+ params.map { |column| "#{table_name}.#{column}" }.join(", ")
150
+ end
151
+ end