ru.Bee 1.1.2 → 1.1.4

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a3080691c90ff2c8d48ac531c6534fe29906fc5e3392b49727701e7c2989024c
4
- data.tar.gz: d9f6579a0a1bcd26caecf0bc518a53124c9890089c059953d92e4503f7c86a8b
3
+ metadata.gz: 1357f41d8c3b31d032d0787838ef095b55a88891506472c1b1921180a8df419a
4
+ data.tar.gz: fa5539ac28e7e3102c804af72bcf75b4a661c92d5d6eb561878166b2454c00f7
5
5
  SHA512:
6
- metadata.gz: 9699fce90a6a07ed7190c3e89bb4f0ea3b81d63dd25423909e9a7ace756a06f9ec14f09a25e289e2638c20955eefed886ed7b33767b7afc5e454607666a6ca9b
7
- data.tar.gz: 8ff79bc9e18a9db76ac7b0c34531d5c3b36b2e31b80e5929b304a5a79fb46560408f199b9bacaa8ea38aa0db9ca2945090380475487d332471d7590394c25fbd
6
+ metadata.gz: 607c43f4a109ee2ec8bee211b1f8f01e8504f2b0b59ce8802c215a623e5791d222d235a2496f42b825d485c461ee287b7dfe246a7c9e6cef994ea88bae5413ac
7
+ data.tar.gz: 8db14bf2a2c08e507c6537a3a7d1413687cf3ab0b9caab3f8ed931277b212f1c488bbe0e3a828e5dab468b8c22573bddd1eaf6edfca7c5410d43fc6e757d9a5d
data/bin/rubee CHANGED
@@ -9,7 +9,6 @@ require 'json'
9
9
  require 'rack'
10
10
  require 'rackup'
11
11
 
12
- require_relative '../lib/version'
13
12
  require_relative '../lib/inits/print_colors'
14
13
  require_relative '../lib/rubee'
15
14
 
@@ -30,7 +29,7 @@ LOGO
30
29
  command = ARGV.first
31
30
 
32
31
  def print_logo
33
- puts "\e[36m" + (LOGO % VERSION) + "\e[0m" # Cyan color
32
+ puts "\e[36m" + (LOGO % Rubee::VERSION) + "\e[0m" # Cyan color
34
33
  end
35
34
 
36
35
  if command =~ /^(start)$|^(start:(\d+))$/
@@ -60,6 +59,11 @@ elsif command == "project"
60
59
  exit 1
61
60
  end
62
61
 
62
+ if project_name == "rubee"
63
+ color_puts "Error: Project 'rubee' is reserved", color: :red
64
+ exit 1
65
+ end
66
+
63
67
  source_dir = File.expand_path("../lib", __dir__)
64
68
  target_dir = File.expand_path("./#{project_name}", Dir.pwd)
65
69
 
@@ -72,8 +76,8 @@ elsif command == "project"
72
76
  FileUtils.mkdir_p(target_dir)
73
77
 
74
78
  # Define blacklist
75
- blacklist_files = %w[rubee.rb print_colors.rb version.rb config.ru]
76
- blacklist_dirs = %w[rubee]
79
+ blacklist_files = %w[rubee.rb print_colors.rb version.rb config.ru test_helper.rb Gemfile.lock test.yml test.db development.db production.db]
80
+ blacklist_dirs = %w[rubee tests .git .github .idea]
77
81
 
78
82
  # Copy files, excluding blacklisted ones
79
83
  Dir.glob("#{source_dir}/**/*", File::FNM_DOTMATCH).each do |file|
@@ -94,6 +98,10 @@ elsif command == "project"
94
98
  end
95
99
  end
96
100
 
101
+ # create tests dir and copy test_helper.rb and user_model_test.rb
102
+ FileUtils.mkdir_p("#{target_dir}/tests")
103
+ FileUtils.cp("#{source_dir}/tests/user_model_test.rb", "#{target_dir}/tests/user_model_test.rb")
104
+
97
105
  # create a gemfile context
98
106
  gemfile = <<~GEMFILE
99
107
  source 'https://rubygems.org'
@@ -120,19 +128,18 @@ elsif command == "project"
120
128
  file.puts gemfile
121
129
  end
122
130
 
123
- # create a test folder
124
- FileUtils.mkdir_p("#{target_dir}/tests")
125
- # create a test_helper context
126
- test_helper = <<~RUBY
131
+ # create test_helper.rb file
132
+ test_helper = <<~TESTHELPER
127
133
  require "bundler/setup"
128
134
  Bundler.require(:test)
129
135
 
130
136
  require 'minitest/autorun'
131
137
  require 'rack/test'
132
- require 'ru.Bee'
138
+ require 'rubee'
133
139
 
134
140
  Rubee::Autoload.call
135
- RUBY
141
+ TESTHELPER
142
+
136
143
  File.open("#{target_dir}/tests/test_helper.rb", 'w') do |file|
137
144
  file.puts test_helper
138
145
  end
@@ -140,19 +147,20 @@ elsif command == "project"
140
147
  color_puts "Project #{project_name} created successfully at #{target_dir}", color: :green
141
148
 
142
149
  elsif command == "version"
143
- puts "ruBee v#{VERSION}"
150
+ color_puts "ru.Bee v#{Rubee::VERSION}", color: :yellow
144
151
  elsif command == "test"
152
+
145
153
  ENV['RACK_ENV'] = 'test'
146
154
  file_name = ARGV[1] # Get the first argument
147
-
155
+ lib = Rubee::PROJECT_NAME == 'rubee' ? '/lib' : ''
148
156
  if file_name
149
157
  color_puts "Running #{file_name} test ...", color: :yellow
150
- exec("ruby -Itest -e \"require './tests/#{file_name}'\"")
158
+ exec("ruby -Itest -e \"require '.#{lib}/tests/#{file_name}'\"")
151
159
  else
152
160
  color_puts "Running all tests ...", color: :yellow
153
- exec("ruby -Itest -e \"Dir.glob('./tests/**/*_test.rb').each { |file| require file }\"")
161
+ exec("ruby -Itest -e \"Dir.glob('.#{lib}/tests/**/*_test.rb').each { |file| require file }\"")
154
162
  end
155
- elsif ['generate', 'g'].include? command
163
+ elsif ['generate', 'gen'].include? command
156
164
  method, path = ARGV[1..2]
157
165
  ENV['RACK_ENV'] ||= 'development'
158
166
 
@@ -171,7 +179,12 @@ elsif command == "db"
171
179
  ENV['RACK_ENV'] ||= 'development'
172
180
 
173
181
  command, file_name = ARGV[1]&.split(':')
174
-
182
+ if Rubee::PROJECT_NAME == 'rubee'
183
+ Rubee::Configuration.setup(env=:test) do |config|
184
+ config.database_url = { url: "sqlite://lib/tests/test.db", env: }
185
+ end
186
+ Rubee::SequelObject.reconnect! unless command == 'init'
187
+ end
175
188
 
176
189
  def ensure_database_exists(db_url)
177
190
  uri = URI.parse(db_url)
@@ -180,7 +193,7 @@ elsif command == "db"
180
193
  begin
181
194
  Sequel.connect(db_url)
182
195
  color_puts "Database #{ENV['RACK_ENV']} exists", color: :cyan
183
- rescue => _
196
+ rescue Exception => e
184
197
  if File.exist?(db_path = db_url.sub(/^sqlite:\/\//, ''))
185
198
  color_puts "Database #{ENV['RACK_ENV']} exists", color: :cyan
186
199
  else
@@ -226,14 +239,24 @@ elsif command == "db"
226
239
 
227
240
  if command == 'run'
228
241
  Rubee::Autoload.call
242
+ file_names = if file_name == 'all'
243
+ lib = Rubee::PROJECT_NAME == 'rubee' ? '/lib' : ''
244
+ Dir.glob(".#{lib}/db/*.rb").map { |file| File.basename(file, '.rb') }.select { |file| file != 'structure' }
245
+ else
246
+ [file_name]
247
+ end
229
248
  Rubee::Configuration.envs.each do |env|
230
249
  ENV['RACK_ENV'] = env.to_s
231
- color_puts "Run #{file_name} file for #{env} env", color: :cyan
232
- Object.const_get(file_name.split('_').map(&:capitalize).join).new.call
250
+ file_names.each do |file_name|
251
+ color_puts "Run #{file_name} file for #{env} env", color: :cyan
252
+ Object.const_get(file_name.split('_').map(&:capitalize).join).new.call
253
+ end
254
+ end
255
+ color_puts "Migration for #{file_name} completed", color: :green
256
+ unless Rubee::PROJECT_NAME == 'rubee'
257
+ color_puts "Regenerate schema file", color: :cyan
258
+ generate_structure
233
259
  end
234
- color_puts "Migration #{file_name} completed", color: :green
235
- color_puts "Regenerate schema file", color: :cyan
236
- generate_structure
237
260
  elsif command == 'init'
238
261
  ensure_database_exists(Rubee::Configuration.get_database_url)
239
262
  elsif command == 'structure'
@@ -246,15 +269,25 @@ elsif ['console'].include? command
246
269
  ENV['RACK_ENV'] ||= 'development'
247
270
 
248
271
  Rubee::Autoload.call
272
+ if Rubee::PROJECT_NAME == 'rubee'
273
+ Rubee::Configuration.setup(env=:test) do |config|
274
+ config.database_url = { url: "sqlite://lib/tests/test.db", env: }
275
+ end
276
+ Rubee::Autoload.call
277
+ Rubee::SequelObject.reconnect!
278
+ end
249
279
 
250
280
  def reload
251
- app_files = Dir["./#{APP_ROOT}/**/*.rb"]
281
+ app_files = Dir["./#{Rubee::APP_ROOT}/**/*.rb"]
252
282
  app_files.each { |file| load file }
253
283
  color_puts "Reloaded ..", color: :green
254
284
  end
255
-
256
- # Start IRB
257
- IRB.start
285
+ begin
286
+ # Start IRB
287
+ IRB.start
288
+ rescue Exception => e
289
+ IRB.start
290
+ end
258
291
  else
259
292
  color_puts "Unknown command: #{command}", color: :red
260
293
  end
@@ -47,6 +47,8 @@
47
47
  <img src="images/rubee.svg" alt="ruBee">
48
48
  <br/>
49
49
  <p>rubee homepage: <a href="https://github.com/nucleom42/rubee"><br/>https://github.com/nucleom42/rubee</a></p>
50
+ <br/>
51
+ <p>Version: <%= Rubee::VERSION %></p>
50
52
  </div>
51
53
  </body>
52
54
  </html>
@@ -0,0 +1,14 @@
1
+ class CreateAccounts
2
+ def call
3
+ unless Rubee::SequelObject::DB.tables.include?(:accounts)
4
+ Rubee::SequelObject::DB.create_table :accounts do
5
+ primary_key :id
6
+ String :addres
7
+ foreign_key :user_id, :users
8
+ end
9
+
10
+ Account.create(addres: "13th Ave, NY", user_id: User.all.first.id)
11
+ Account.create(addres: "14th Ave, NY", user_id: User.all.last.id)
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,13 @@
1
+ class CreateComments
2
+ def call
3
+ unless Rubee::SequelObject::DB.tables.include?(:comments)
4
+ Rubee::SequelObject::DB.create_table :comments do
5
+ primary_key :id
6
+ String :text
7
+ Integer :user_id
8
+ end
9
+
10
+ User.create(email: "ok@ok.com", password: "password")
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,14 @@
1
+ class CreatePosts
2
+ def call
3
+ unless Rubee::SequelObject::DB.tables.include?(:posts)
4
+ Rubee::SequelObject::DB.create_table :posts do
5
+ primary_key :id
6
+ foreign_key :user_id, :users
7
+ foreign_key :comment_id, :comments
8
+ end
9
+
10
+ Post.create(user_id: User.all.first.id, comment_id: Comment.all.first.id)
11
+ Post.create(user_id: User.all.last.id, comment_id: Comment.all.last.id)
12
+ end
13
+ end
14
+ end
data/lib/db/structure.rb CHANGED
@@ -30,5 +30,97 @@ STRUCTURE = {
30
30
  ruby_default: nil,
31
31
  max_length: 255
32
32
  }
33
+ },
34
+ accounts: {
35
+ id: {
36
+ generated: false,
37
+ allow_null: false,
38
+ default: nil,
39
+ db_type: "INTEGER",
40
+ primary_key: true,
41
+ auto_increment: true,
42
+ type: "integer",
43
+ ruby_default: nil
44
+ },
45
+ addres: {
46
+ generated: false,
47
+ allow_null: true,
48
+ default: nil,
49
+ db_type: "varchar(255)",
50
+ primary_key: false,
51
+ type: "string",
52
+ ruby_default: nil,
53
+ max_length: 255
54
+ },
55
+ user_id: {
56
+ generated: false,
57
+ allow_null: true,
58
+ default: nil,
59
+ db_type: "INTEGER",
60
+ primary_key: false,
61
+ type: "integer",
62
+ ruby_default: nil
63
+ }
64
+ },
65
+ posts: {
66
+ id: {
67
+ generated: false,
68
+ allow_null: false,
69
+ default: nil,
70
+ db_type: "INTEGER",
71
+ primary_key: true,
72
+ auto_increment: true,
73
+ type: "integer",
74
+ ruby_default: nil
75
+ },
76
+ user_id: {
77
+ generated: false,
78
+ allow_null: true,
79
+ default: nil,
80
+ db_type: "INTEGER",
81
+ primary_key: false,
82
+ type: "integer",
83
+ ruby_default: nil
84
+ },
85
+ comment_id: {
86
+ generated: false,
87
+ allow_null: true,
88
+ default: nil,
89
+ db_type: "INTEGER",
90
+ primary_key: false,
91
+ type: "integer",
92
+ ruby_default: nil
93
+ }
94
+ },
95
+ comments: {
96
+ id: {
97
+ generated: false,
98
+ allow_null: false,
99
+ default: nil,
100
+ db_type: "INTEGER",
101
+ primary_key: true,
102
+ auto_increment: true,
103
+ type: "integer",
104
+ ruby_default: nil
105
+ },
106
+ text: {
107
+ generated: false,
108
+ allow_null: true,
109
+ default: nil,
110
+ db_type: "varchar(255)",
111
+ primary_key: false,
112
+ type: "string",
113
+ ruby_default: nil,
114
+ max_length: 255
115
+ },
116
+ user_id: {
117
+ generated: false,
118
+ allow_null: true,
119
+ default: nil,
120
+ db_type: "INTEGER",
121
+ primary_key: false,
122
+ type: "integer",
123
+ ruby_default: nil
124
+ }
33
125
  }
34
126
  }
@@ -1,5 +1,5 @@
1
1
  unless defined?(Rubee)
2
- require_relative '../../../../ee.rb'
2
+ require_relative '../../../../rubee.rb'
3
3
  Rubee::Autoload.call
4
4
  end
5
5
 
@@ -43,7 +43,8 @@ module Rubee
43
43
  else # rendering erb view is a default behavior
44
44
  view_file_name = self.class.name.split("Controller").first.downcase
45
45
  erb_file = render_view ? "#{render_view}.erb" : "#{view_file_name}_#{@route[:action]}.erb"
46
- rendered_erb = ERB.new(File.open("app/views/#{erb_file}").read).result(binding)
46
+ lib = Rubee::PROJECT_NAME == 'rubee' ? 'lib/' : ''
47
+ rendered_erb = ERB.new(File.open("#{lib}app/views/#{erb_file}").read).result(binding)
47
48
  return [status, headers.merge("content-type" => "text/html"), [rendered_erb]]
48
49
  end
49
50
  end
@@ -11,7 +11,7 @@ module Rubee
11
11
  base.include(InstanceMethods)
12
12
  base.extend(ClassMethods)
13
13
 
14
- base.attach('AuthTokenMiddleware')
14
+ base.attach('Rubee::AuthTokenMiddleware')
15
15
  end
16
16
 
17
17
  module InstanceMethods
@@ -0,0 +1,52 @@
1
+ module Rubee
2
+ module DatabaseObjectable
3
+ def self.included(base)
4
+ base.extend ClassMethods
5
+ base.include InstanceMethods
6
+ base.prepend Initializer
7
+
8
+ base.include Rubee::Hookable
9
+ base.include Rubee::Serializable
10
+ end
11
+
12
+ module ClassMethods
13
+ def pluralize_class_name
14
+ pluralize(self.name.downcase)
15
+ end
16
+
17
+ def pluralize(word)
18
+ if word.end_with?('y') && !%w[a e i o u].include?(word[-2])
19
+ word[0..-2] + 'ies' # Replace "y" with "ies"
20
+ elsif word.end_with?('s', 'x', 'z', 'ch', 'sh')
21
+ word + 'es' # Add "es" for certain endings
22
+ else
23
+ word + 's' # Default to adding "s"
24
+ end
25
+ end
26
+
27
+ def singularize(word)
28
+ if word.end_with?('ies') && word.length > 3
29
+ word[0..-4] + 'y' # Convert "ies" to "y"
30
+ elsif word.end_with?('es') && %w[s x z ch sh].any? { |ending| word[-(ending.length + 2)..-3] == ending }
31
+ word[0..-3] # Remove "es" for words like "foxes", "buses"
32
+ elsif word.end_with?('s') && word.length > 1
33
+ word[0..-2] # Remove "s" for regular plurals
34
+ else
35
+ word # Return as-is if no plural form is detected
36
+ end
37
+ end
38
+
39
+ def accessor_names
40
+ instance_methods(false)
41
+ .select { |m| method_defined?("#{m}=") } # Check if setter exists
42
+ end
43
+ end
44
+
45
+ module InstanceMethods
46
+ end
47
+
48
+ module Initializer
49
+ end
50
+ end
51
+ end
52
+
@@ -1,9 +1,21 @@
1
1
  module Rubee
2
- class SequelObject < DatabaseObject
3
- DB = Sequel.connect(Rubee::Configuration.get_database_url) rescue nil
4
-
5
- def destroy
6
- self.class.connection.where(id:).delete
2
+ class SequelObject
3
+ include Rubee::DatabaseObjectable
4
+
5
+ def destroy(cascade: false, **options)
6
+ if cascade
7
+ # find all tables with foreign key
8
+ tables_with_fk = DB.tables.select do |table|
9
+ DB.foreign_key_list(table).any? { |fk| fk[:table] == self.class.pluralize_class_name.to_sym }
10
+ end
11
+ # destroy related records
12
+ tables_with_fk.each do |table|
13
+ fk_name ||= "#{self.class.name.to_s.downcase}_id".to_sym
14
+ target_klass = Object.const_get(self.class.singularize(table.to_s).capitalize)
15
+ target_klass.where(fk_name => id).map(&:destroy)
16
+ end
17
+ end
18
+ self.class.dataset.where(id:).delete
7
19
  end
8
20
 
9
21
  def save
@@ -28,7 +40,7 @@ module Rubee
28
40
 
29
41
  def update(args = {})
30
42
  assign_attributes(args)
31
- found_hash = self.class.connection.where(id:)
43
+ found_hash = self.class.dataset.where(id:)
32
44
  return self.class.find(id) if found_hash&.update(**args)
33
45
 
34
46
  false
@@ -44,42 +56,122 @@ module Rubee
44
56
 
45
57
  class << self
46
58
  def last
47
- found_hash = connection.order(:id).last
59
+ found_hash = dataset.order(:id).last
48
60
  return self.new(**found_hash) if found_hash
49
61
 
50
62
  nil
51
63
  end
52
64
 
53
- def connection
54
- @connection ||= DB[pluralize_class_name.to_sym]
65
+ def first
66
+ found_hash = dataset.order(:id).first
67
+ return self.new(**found_hash) if found_hash
68
+
69
+ nil
70
+ end
71
+
72
+ # ## User
73
+ # owns_many :comments
74
+ # > user.comments
75
+ # > [<comment1>, <comment2>]
76
+ def owns_many(assoc, fk_name: nil, over: nil, **options)
77
+ singularized_assoc_name = singularize(assoc.to_s)
78
+ fk_name ||= "#{self.name.to_s.downcase}_id"
79
+
80
+ define_method(assoc) do
81
+ klass = Object.const_get(singularized_assoc_name.capitalize)
82
+ if over
83
+ sequel_dataset = klass
84
+ .join(over.to_sym, "#{singularized_assoc_name}_id".to_sym => :id)
85
+ .where(fk_name.to_sym => id)
86
+ self.class.serialize(sequel_dataset, klass)
87
+ else
88
+ klass.where(fk_name.to_sym => id)
89
+ end
90
+ end
91
+ end
92
+
93
+ # ## Comment
94
+ # owns_one :user
95
+ # > comment.user
96
+ # > <user>
97
+ def owns_one(assoc, options={})
98
+ Sequel::Model.one_to_one(assoc, **options)
99
+ fk_name ||= "#{self.name.to_s.downcase}_id"
100
+ define_method(assoc) do
101
+ Object.const_get(assoc.capitalize).where(fk_name.to_sym => id)&.first
102
+ end
103
+ end
104
+
105
+ # ## Account
106
+ # holds :user
107
+ # > account.user
108
+ # > <user>
109
+ def holds(assoc, fk_name: nil, **options)
110
+ fk_name ||= "#{assoc.to_s.downcase}_id"
111
+ define_method(assoc) do
112
+ target_klass = Object.const_get(assoc.capitalize)
113
+ target_klass.find(self.send(fk_name))
114
+ end
115
+ end
116
+
117
+ def reconnect!
118
+ return if defined?(DB) && !DB.nil?
119
+
120
+ const_set(:DB, Sequel.connect(Rubee::Configuration.get_database_url))
121
+ end
122
+
123
+ def dataset
124
+ @dataset ||= DB[pluralize_class_name.to_sym]
125
+ rescue Exception => _
126
+ reconnect!
127
+ retry
55
128
  end
56
129
 
57
130
  def all
58
- connection.map do |record_hash|
131
+ dataset.map do |record_hash|
59
132
  self.new(**record_hash)
60
133
  end
61
134
  end
62
135
 
63
136
  def find(id)
64
- found_hash = connection.where(id:)&.first
137
+ found_hash = dataset.where(id:)&.first
65
138
  return self.new(**found_hash) if found_hash
66
139
 
67
140
  nil
68
141
  end
69
142
 
70
143
  def where(args)
71
- connection.where(**args).map do |record_hash|
144
+ dataset.where(**args).map do |record_hash|
72
145
  self.new(**record_hash)
73
146
  end
74
147
  end
75
148
 
149
+ def order(*args)
150
+ dataset.order(*args).map do |record_hash|
151
+ self.new(**record_hash)
152
+ end
153
+ end
154
+
155
+ def join(assoc, args)
156
+ dataset.join(assoc, **args)
157
+ end
158
+
76
159
  def create(attrs)
77
- out_id = connection.insert(**attrs)
160
+ out_id = dataset.insert(**attrs)
78
161
  self.new(**(attrs.merge(id: out_id)))
79
162
  end
80
163
 
81
- def destroy_all
82
- all.each(&:destroy)
164
+ def destroy_all(cascade: false)
165
+ all.each{ |record| record.destroy(cascade:) }
166
+ end
167
+
168
+ def serialize(suquel_dataset, klass = nil)
169
+ klass ||= self
170
+ suquel_dataset.map do |record_hash|
171
+ target_klass_fields = DB[pluralize(klass.name.downcase).to_sym].columns
172
+ klass_attributes = record_hash.filter{ target_klass_fields.include? _1 }
173
+ klass.new(**klass_attributes)
174
+ end
83
175
  end
84
176
  end
85
177
  end
data/lib/rubee.rb CHANGED
@@ -8,6 +8,7 @@ module Rubee
8
8
  APP_ROOT = File.expand_path(Dir.pwd) unless defined?(APP_ROOT)
9
9
  IMAGE_DIR = File.join(APP_ROOT, 'images') unless defined?(IMAGE_DIR)
10
10
  PROJECT_NAME = File.basename(APP_ROOT) unless defined?(PROJECT_NAME)
11
+ VERSION = '1.1.4'
11
12
 
12
13
  class Application
13
14
  include Singleton
@@ -122,6 +123,8 @@ module Rubee
122
123
  # autoload all rbs
123
124
  root_directory = File.dirname(__FILE__)
124
125
  priority_order_require(root_directory, black_list)
126
+ # ensure sequel object is connected
127
+ Rubee::SequelObject.reconnect!
125
128
 
126
129
  Dir.glob(File.join(APP_ROOT, '**', '*.rb')).sort.each do |file|
127
130
  base_name = File.basename(file)
@@ -138,8 +141,7 @@ module Rubee
138
141
  require_relative file unless black_list.include?("#{file}.rb")
139
142
  end
140
143
  # app inits
141
- lib_dir = PROJECT_NAME == 'rubee' ? 'lib' : ''
142
- Dir[File.join(APP_ROOT, lib_dir, 'inits/**', '*.rb')].each do |file|
144
+ Dir[File.join(APP_ROOT, 'inits/**', '*.rb')].each do |file|
143
145
  require_relative file unless black_list.include?("#{file}.rb")
144
146
  end
145
147
  # rubee async
@@ -147,8 +149,18 @@ module Rubee
147
149
  require_relative file unless black_list.include?("#{file}.rb")
148
150
  end
149
151
  # app config and routes
150
- require_relative File.join(APP_ROOT, lib_dir, "config/base_configuration") unless black_list.include?('base_configuration.rb')
151
- require_relative File.join(APP_ROOT, lib_dir, "config/routes") unless black_list.include?('routes.rb')
152
+ lib = PROJECT_NAME == 'rubee' ? 'lib/' : ''
153
+ require_relative File.join(APP_ROOT, lib, "config/base_configuration") unless black_list.include?('base_configuration.rb')
154
+ # This is necessary prerequisitedb init step
155
+ unless defined?(Rubee::SequelObject::DB)
156
+ if PROJECT_NAME == 'rubee'
157
+ Rubee::Configuration.setup(env=:test) do |config|
158
+ config.database_url = { url: "sqlite://lib/tests/test.db", env: }
159
+ end
160
+ end
161
+ end
162
+
163
+ require_relative File.join(APP_ROOT, lib, "config/routes") unless black_list.include?('routes.rb')
152
164
  # rubee extensions
153
165
  Dir[File.join(root_directory, "rubee/extensions/**", '*.rb')].each do |file|
154
166
  require_relative file unless black_list.include?("#{file}.rb")
@@ -162,7 +174,7 @@ module Rubee
162
174
  end
163
175
  require_relative File.join(root_directory, "rubee/controllers/base_controller") unless black_list.include?('base_controller.rb')
164
176
  # rubee models
165
- require_relative File.join(root_directory, "rubee/models/database_object") unless black_list.include?('database_object.rb')
177
+ require_relative File.join(root_directory, "rubee/models/database_objectable") unless black_list.include?('database_objectable.rb')
166
178
  require_relative File.join(root_directory, "rubee/models/sequel_object") unless black_list.include?('sequel_object.rb')
167
179
  end
168
180
  end
@@ -0,0 +1,19 @@
1
+ require_relative 'test_helper'
2
+
3
+ describe 'Account model' do
4
+ describe 'holds :user' do
5
+ after do
6
+ Account.destroy_all cascade: true
7
+ end
8
+
9
+ describe 'when it holds user_id' do
10
+ it 'returns associated User record' do
11
+ user = User.new(email: "ok-test@test.com", password: "123")
12
+ user.save
13
+ account = Account.new(user_id: user.id, addres: "test")
14
+ account.save
15
+ _(account.user.id).must_equal user.id
16
+ end
17
+ end
18
+ end
19
+ end
@@ -19,7 +19,7 @@ class RubeeAppTest < Minitest::Test
19
19
  end
20
20
 
21
21
  def test_welcome_controller_included_auth_tokenable
22
- WelcomeController.include(AuthTokenable)
22
+ WelcomeController.include(Rubee::AuthTokenable)
23
23
  WelcomeController.auth_methods :show
24
24
 
25
25
  get '/'
@@ -0,0 +1,22 @@
1
+ require_relative 'test_helper'
2
+
3
+ describe 'Comment model' do
4
+ describe 'owns_many :users, over: :posts' do
5
+ after do
6
+ Comment.destroy_all cascade: true
7
+ end
8
+
9
+ describe 'when there are associated comment records' do
10
+ it 'returns all records' do
11
+ comment = Comment.new(content: "test")
12
+ comment.save
13
+ user = User.new(email: "ok-test@test.com", password: "123")
14
+ user.save
15
+ post = Post.new(user_id: user.id, comment_id: comment.id)
16
+ post.save
17
+ _(comment.users.count).must_equal 1
18
+ _(comment.users.first.email).must_equal user.email
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,4 @@
1
+ class Account < Rubee::SequelObject
2
+ attr_accessor :id, :addres, :user_id
3
+ holds :user
4
+ end
@@ -0,0 +1,4 @@
1
+ class Comment < Rubee::SequelObject
2
+ attr_accessor :id, :content
3
+ owns_many :users, over: :posts
4
+ end
@@ -0,0 +1,5 @@
1
+ class Post < Rubee::SequelObject
2
+ attr_accessor :id, :user_id, :comment_id
3
+ holds :comment
4
+ holds :user
5
+ end
@@ -0,0 +1,4 @@
1
+ class User < Rubee::SequelObject
2
+ attr_accessor :id, :email, :password
3
+ owns_many :accounts, cascade: true
4
+ end
data/lib/tests/test.db ADDED
Binary file
@@ -0,0 +1,14 @@
1
+ require "bundler/setup"
2
+ Bundler.require(:test)
3
+
4
+ require 'minitest/autorun'
5
+ require 'rack/test'
6
+ require_relative '../../lib/rubee'
7
+
8
+ Rubee::Autoload.call
9
+ Rubee::Configuration.setup(env=:test) do |config|
10
+ config.database_url = { url: "sqlite://lib/tests/test.db", env: }
11
+ end
12
+ Rubee::SequelObject.reconnect!
13
+
14
+
@@ -0,0 +1,230 @@
1
+ require_relative 'test_helper'
2
+
3
+ describe 'User model' do
4
+ describe ".create" do
5
+ after do
6
+ User.destroy_all cascade: true
7
+ end
8
+
9
+ describe 'when data is valid' do
10
+ it 'persists to db' do
11
+ user = User.create(email: "ok-test@test.com", password: "123")
12
+
13
+ _(user.persisted?).must_equal true
14
+ end
15
+ end
16
+
17
+ describe 'when data is invalid' do
18
+ it 'is not changing users number' do
19
+ initial_count = User.all.count
20
+ User.create(wrong: "test@test") rescue nil
21
+
22
+ _(User.all.count).must_equal initial_count
23
+ end
24
+ end
25
+ end
26
+
27
+ describe '.save' do
28
+ after do
29
+ User.destroy_all cascade: true
30
+ end
31
+
32
+ describe 'when data is valid' do
33
+ it 'persists to db' do
34
+ user = User.new(email: "ok-test@test.com", password: "123")
35
+ user.save
36
+
37
+ _(user.persisted?).must_equal true
38
+ end
39
+ end
40
+
41
+ describe 'when save existing user' do
42
+ it 'persists to db' do
43
+ user = User.new(email: "ok-test@test.com", password: "123")
44
+ user.save
45
+
46
+ _(user.reload.password).must_equal "123"
47
+ end
48
+ end
49
+
50
+ describe 'when data is invalid' do
51
+ it 'is not changing users number' do
52
+ initial_count = User.all.count
53
+ user = User.new(wrong: "test@test") rescue nil
54
+ user.save rescue nil
55
+
56
+ _(User.all.count).must_equal initial_count
57
+ end
58
+ end
59
+ end
60
+
61
+ describe '.update' do
62
+ after do
63
+ User.destroy_all cascade: true
64
+ end
65
+
66
+ describe 'when data is valid' do
67
+ it 'persists to db' do
68
+ user = User.new(email: "ok-test@test.com", password: "123")
69
+ user.save
70
+ user.update(password: "1234")
71
+
72
+ _(user.reload.password).must_equal "1234"
73
+ end
74
+ end
75
+ end
76
+
77
+ describe '.destroy' do
78
+ after do
79
+ User.destroy_all cascade: true
80
+ end
81
+
82
+ describe 'when there is no related recrods' do
83
+ it 'delete the record' do
84
+ user = User.new(email: "ok-test@test.com", password: "123")
85
+ user.save
86
+ user.destroy
87
+
88
+ assert_nil user.reload
89
+ end
90
+ end
91
+
92
+ describe 'when there are related recrods' do
93
+ it 'does not delete the record' do
94
+ user = User.new(email: "ok-test@test.com", password: "123")
95
+ user.save
96
+ Account.new(user_id: user.id, addres: "test").save
97
+ user.destroy rescue nil
98
+
99
+ _(user.reload.id).must_equal user.id
100
+ end
101
+ end
102
+
103
+ describe 'when there are related recrods but passed cascade=true' do
104
+ it 'deletes the record' do
105
+ user = User.new(email: "ok-test@test.com", password: "123")
106
+ user.save
107
+ Account.new(user_id: user.id, addres: "test").save
108
+ user.destroy cascade: true
109
+
110
+ assert_nil user.reload
111
+ end
112
+ end
113
+ end
114
+
115
+ describe '.find' do
116
+ after do
117
+ User.destroy_all cascade: true
118
+ end
119
+
120
+ describe 'when trhere is a record' do
121
+ it 'returns a record' do
122
+ user = User.new(email: "ok-test@test.com", password: "123")
123
+ user.save
124
+ _(User.find(user.id).email).must_equal user.email
125
+ end
126
+ end
127
+
128
+ describe 'when there is no record' do
129
+ it 'returns nil' do
130
+ assert_nil User.find(1)
131
+ end
132
+ end
133
+ end
134
+
135
+ describe '.all' do
136
+ after do
137
+ User.destroy_all cascade: true
138
+ end
139
+
140
+ describe 'when there are records' do
141
+ it 'returns all records' do
142
+ user = User.new(email: "ok-test@test.com", password: "123")
143
+ user2 = User.new(email: "ok-test2@test.com", password: "123")
144
+ user.save
145
+ user2.save
146
+ _(User.all.count).must_equal 2
147
+ end
148
+ end
149
+ end
150
+
151
+ describe '.where' do
152
+ after do
153
+ User.destroy_all cascade: true
154
+ end
155
+
156
+ describe 'when there are records' do
157
+ it 'returns all records' do
158
+ user = User.new(email: "ok-test@test.com", password: "123")
159
+ user2 = User.new(email: "ok-test2@test.com", password: "123")
160
+ user.save
161
+ user2.save
162
+ _(User.where(email: "ok-test2@test.com").count).must_equal 1
163
+ end
164
+ end
165
+ end
166
+
167
+ describe '.first' do
168
+ after do
169
+ User.destroy_all cascade: true
170
+ end
171
+
172
+ describe 'when there are records' do
173
+ it 'returns first record' do
174
+ user = User.new(email: "ok-test@test.com", password: "123")
175
+ user2 = User.new(email: "ok-test2@test.com", password: "123")
176
+ user.save
177
+ user2.save
178
+ _(User.first.email).must_equal user.email
179
+ end
180
+ end
181
+ end
182
+
183
+ describe '.last' do
184
+ after do
185
+ User.destroy_all cascade: true
186
+ end
187
+
188
+ describe 'when there are records' do
189
+ it 'returns last record' do
190
+ user = User.new(email: "ok-test@test.com", password: "123")
191
+ user2 = User.new(email: "ok-test2@test.com", password: "123")
192
+ user.save
193
+ user2.save
194
+ _(User.last.email).must_equal user2.email
195
+ end
196
+ end
197
+ end
198
+
199
+ describe '.order' do
200
+ after do
201
+ User.destroy_all cascade: true
202
+ end
203
+
204
+ describe 'when there are records' do
205
+ it 'returns ordered records' do
206
+ user = User.new(email: "abc@test.com", password: "123")
207
+ user2 = User.new(email: "defg@test.com", password: "123")
208
+ user.save
209
+ user2.save
210
+ _(User.order(:email).first.email).must_equal user.email
211
+ end
212
+ end
213
+ end
214
+
215
+ describe 'owns_many' do
216
+ after do
217
+ User.destroy_all cascade: true
218
+ end
219
+
220
+ describe 'when there are associated account records' do
221
+ it 'returns all records' do
222
+ user = User.new(email: "ok-test@test.com", password: "123")
223
+ user.save
224
+ account = Account.new(user_id: user.id, addres: "test")
225
+ account.save
226
+ _(user.accounts.count).must_equal 1
227
+ end
228
+ end
229
+ end
230
+ end
data/readme.md CHANGED
@@ -14,7 +14,7 @@ The main philosophy of ru.Bee is to focus on Ruby language explicit implementati
14
14
 
15
15
  Want to get a quick API server up and runing? You can do it for real quick!
16
16
  <br />
17
- Laoding ... (demo is on its way)
17
+ [![Video Title](https://img.youtube.com/vi/ko7H70s7qq0/0.jpg)](https://www.youtube.com/watch?v=ko7H70s7qq0)
18
18
 
19
19
  All greaet features are yet to come!
20
20
 
@@ -107,7 +107,7 @@ Here below is a simple example on how it can be used by rendering json from in m
107
107
 
108
108
  def show
109
109
  # in memory example
110
- apples = [Apple.new(colour: 'red', weight: '1lb'), Apple.new(colour: 'green', weight: '1lb')]
110
+ apples = [Apple.new(colour: 'red', weight: '1lb'), Apple.new(colour: 'green', weight: '1lb')]
111
111
  apple = apples.find { |apple| apple.colour = params[:colour] }
112
112
 
113
113
  response_with object: apple, type: :json
@@ -128,6 +128,24 @@ However, you can simply turn it to ORM object by extending database class.
128
128
  attr_accessor :id, :colour, :weight
129
129
  end
130
130
  ```
131
+ Rubee::SequelObject methods:
132
+
133
+ - `apple.save`
134
+ - `apple.destroy(cascade: true)` # default false
135
+ - `apple.destroy_all`
136
+ - `apple.update(colour: 'red')`
137
+ - `apple.persisted?`
138
+ - `apple.reload`
139
+ - `apple.assign_attributes(colour: 'red', weight: '1lb')`
140
+ - `Apple.last`
141
+ - `Apple.where(colour: 'red')`
142
+ - `Apple.last`
143
+ - `Apple.all`
144
+ - `Apple.create(colour: 'red', weight: '1lb')`
145
+ - `Apple.destroy_all`
146
+ - `Apple.serialize`
147
+ - `Apple.serialize(Apple.dataset.joins(:trees).where(tree: { colour: 'brown' }))`
148
+ ...
131
149
 
132
150
  So in the controller you would need to query your target object now.
133
151
 
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ru.Bee
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.2
4
+ version: 1.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Oleg Saltykov
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-03-17 00:00:00.000000000 Z
10
+ date: 2025-03-31 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: bundler
@@ -39,6 +39,7 @@ extra_rdoc_files: []
39
39
  files:
40
40
  - LICENSE
41
41
  - bin/rubee
42
+ - bin/test.db
42
43
  - lib/Dockerfile
43
44
  - lib/app/controllers/welcome_controller.rb
44
45
  - lib/app/models/user.rb
@@ -46,9 +47,11 @@ files:
46
47
  - lib/config.ru
47
48
  - lib/config/base_configuration.rb
48
49
  - lib/config/routes.rb
50
+ - lib/db/create_accounts.rb
51
+ - lib/db/create_comments.rb
52
+ - lib/db/create_posts.rb
49
53
  - lib/db/create_users.rb
50
54
  - lib/db/structure.rb
51
- - lib/db/test.db
52
55
  - lib/images/rubee.svg
53
56
  - lib/inits/print_colors.rb
54
57
  - lib/rubee.rb
@@ -62,13 +65,19 @@ files:
62
65
  - lib/rubee/controllers/middlewares/auth_token_middleware.rb
63
66
  - lib/rubee/extensions/hookable.rb
64
67
  - lib/rubee/extensions/serializable.rb
65
- - lib/rubee/models/database_object.rb
68
+ - lib/rubee/models/database_objectable.rb
66
69
  - lib/rubee/models/sequel_object.rb
67
- - lib/rubee/tests/auth_tokenable_test.rb
68
- - lib/rubee/tests/rubeeapp_test.rb
69
- - lib/rubee/tests/test_helper.rb
70
- - lib/rubee/tests/user_model_test.rb
71
- - lib/version.rb
70
+ - lib/tests/account_model_test.rb
71
+ - lib/tests/auth_tokenable_test.rb
72
+ - lib/tests/comment_model_test.rb
73
+ - lib/tests/example_models/account.rb
74
+ - lib/tests/example_models/comment.rb
75
+ - lib/tests/example_models/post.rb
76
+ - lib/tests/example_models/user.rb
77
+ - lib/tests/rubeeapp_test.rb
78
+ - lib/tests/test.db
79
+ - lib/tests/test_helper.rb
80
+ - lib/tests/user_model_test.rb
72
81
  - readme.md
73
82
  homepage: https://github.com/nucleom42/rubee
74
83
  licenses:
@@ -1,50 +0,0 @@
1
- module Rubee
2
- class DatabaseObject
3
- include Serializable
4
- include Hookable
5
-
6
- def destroy
7
- end
8
-
9
- def save
10
- end
11
-
12
- def update(args = {})
13
- end
14
-
15
- def reload
16
- end
17
-
18
- class << self
19
- def last
20
- end
21
-
22
- def connection
23
- end
24
-
25
- def all
26
- end
27
-
28
- def find(id)
29
- end
30
-
31
- def where(args)
32
- end
33
-
34
- def create(attrs)
35
- end
36
-
37
- def pluralize_class_name
38
- word = self.name.downcase
39
- # Basic pluralization rules
40
- if word.end_with?('y') && !%w[a e i o u].include?(word[-2])
41
- word[0..-2] + 'ies' # Replace "y" with "ies"
42
- elsif word.end_with?('s', 'x', 'z', 'ch', 'sh')
43
- word + 'es' # Add "es" for certain endings
44
- else
45
- word + 's' # Default to adding "s"
46
- end
47
- end
48
- end
49
- end
50
- end
@@ -1,11 +0,0 @@
1
- require_relative File.join(File.expand_path(Dir.pwd), 'lib', 'rubee.rb')
2
-
3
- require "bundler/setup"
4
- Bundler.require(:default, :test, :development)
5
-
6
- require 'minitest/autorun'
7
- require 'rack/test'
8
-
9
- Rubee::Autoload.call
10
-
11
-
@@ -1,51 +0,0 @@
1
- require_relative 'test_helper'
2
-
3
- describe 'User model' do
4
- describe ".create" do
5
- after do
6
- User.destroy_all
7
- end
8
-
9
- describe 'when data is valid' do
10
- it 'persists to db' do
11
- user = User.create(email: "ok-test@test.com", password: "123")
12
-
13
- _(user.persisted?).must_equal true
14
- end
15
- end
16
-
17
- describe 'when data is invalid' do
18
- it 'is not changing users number' do
19
- initial_count = User.all.count
20
- User.create(wrong: "test@test") rescue nil
21
-
22
- _(User.all.count).must_equal initial_count
23
- end
24
- end
25
- end
26
-
27
- describe '.save' do
28
- after do
29
- User.destroy_all
30
- end
31
-
32
- describe 'when data is valid' do
33
- it 'persists to db' do
34
- user = User.new(email: "ok-test@test.com", password: "123")
35
- user.save
36
-
37
- _(user.persisted?).must_equal true
38
- end
39
- end
40
-
41
- describe 'when data is invalid' do
42
- it 'is not changing users number' do
43
- initial_count = User.all.count
44
- user = User.new(wrong: "test@test") rescue nil
45
- user.save rescue nil
46
-
47
- _(User.all.count).must_equal initial_count
48
- end
49
- end
50
- end
51
- end
data/lib/version.rb DELETED
@@ -1 +0,0 @@
1
- VERSION = '1.1.0'
File without changes
File without changes