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 +4 -4
- data/bin/rubee +59 -26
- data/lib/app/views/welcome_show.erb +2 -0
- data/lib/db/create_accounts.rb +14 -0
- data/lib/db/create_comments.rb +13 -0
- data/lib/db/create_posts.rb +14 -0
- data/lib/db/structure.rb +92 -0
- data/lib/rubee/async/asyncable.rb +1 -1
- data/lib/rubee/controllers/base_controller.rb +2 -1
- data/lib/rubee/controllers/extensions/auth_tokenable.rb +1 -1
- data/lib/rubee/models/database_objectable.rb +52 -0
- data/lib/rubee/models/sequel_object.rb +107 -15
- data/lib/rubee.rb +17 -5
- data/lib/tests/account_model_test.rb +19 -0
- data/lib/{rubee/tests → tests}/auth_tokenable_test.rb +1 -1
- data/lib/tests/comment_model_test.rb +22 -0
- data/lib/tests/example_models/account.rb +4 -0
- data/lib/tests/example_models/comment.rb +4 -0
- data/lib/tests/example_models/post.rb +5 -0
- data/lib/tests/example_models/user.rb +4 -0
- data/lib/tests/test.db +0 -0
- data/lib/tests/test_helper.rb +14 -0
- data/lib/tests/user_model_test.rb +230 -0
- data/readme.md +20 -2
- metadata +18 -9
- data/lib/rubee/models/database_object.rb +0 -50
- data/lib/rubee/tests/test_helper.rb +0 -11
- data/lib/rubee/tests/user_model_test.rb +0 -51
- data/lib/version.rb +0 -1
- /data/{lib/db → bin}/test.db +0 -0
- /data/lib/{rubee/tests → tests}/rubeeapp_test.rb +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1357f41d8c3b31d032d0787838ef095b55a88891506472c1b1921180a8df419a
|
4
|
+
data.tar.gz: fa5539ac28e7e3102c804af72bcf75b4a661c92d5d6eb561878166b2454c00f7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
124
|
-
|
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 '
|
138
|
+
require 'rubee'
|
133
139
|
|
134
140
|
Rubee::Autoload.call
|
135
|
-
|
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
|
-
|
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 '
|
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('
|
161
|
+
exec("ruby -Itest -e \"Dir.glob('.#{lib}/tests/**/*_test.rb').each { |file| require file }\"")
|
154
162
|
end
|
155
|
-
elsif ['generate', '
|
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
|
-
|
232
|
-
|
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
|
-
|
257
|
-
|
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
|
@@ -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
|
}
|
@@ -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
|
-
|
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
|
@@ -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
|
3
|
-
|
4
|
-
|
5
|
-
def destroy
|
6
|
-
|
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.
|
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 =
|
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
|
54
|
-
|
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
|
-
|
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 =
|
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
|
-
|
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 =
|
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(
|
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
|
-
|
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
|
-
|
151
|
-
require_relative File.join(APP_ROOT,
|
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/
|
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
|
@@ -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
|
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
|
-
|
17
|
+
[](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
|
-
|
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.
|
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-
|
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/
|
68
|
+
- lib/rubee/models/database_objectable.rb
|
66
69
|
- lib/rubee/models/sequel_object.rb
|
67
|
-
- lib/
|
68
|
-
- lib/
|
69
|
-
- lib/
|
70
|
-
- lib/
|
71
|
-
- lib/
|
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,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'
|
/data/{lib/db → bin}/test.db
RENAMED
File without changes
|
File without changes
|