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,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