greeenboii 0.1.6 → 0.1.8
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/.idea/greeenboii.iml +30 -25
- data/.idea/jsLibraryMappings.xml +6 -0
- data/.idea/material_theme_project_new.xml +0 -0
- data/.idea/modules.xml +0 -0
- data/.idea/vcs.xml +0 -0
- data/.idea/workspace.xml +189 -110
- data/.rubocop.sorbet.yml +0 -0
- data/.rubocop.yml +0 -0
- data/CHANGELOG.md +16 -0
- data/CODE_OF_CONDUCT.md +0 -0
- data/CONTRIBUTING.md +0 -0
- data/LICENSE.txt +0 -0
- data/Makefile +0 -0
- data/README.md +5 -0
- data/Rakefile +0 -0
- data/exe/greeenboii +0 -0
- data/ext/greeenboii/extconf.rb +0 -0
- data/ext/greeenboii/greeenboii.c +0 -0
- data/ext/greeenboii/greeenboii.h +0 -0
- data/greeenboii_todo.db +0 -0
- data/lib/greeenboii/version.rb +5 -5
- data/lib/greeenboii.rb +880 -235
- data/lib/libsql.rb +159 -0
- data/logs/turso_requests.log +54 -0
- data/logs/turso_responses.log +27 -0
- data/sig/greeenboii/options.rbs +0 -0
- data/sig/greeenboii/search.rbs +0 -0
- data/sig/greeenboii/todo_list.rbs +0 -0
- data/sig/greeenboii.rbs +0 -0
- data/sorbet/config +0 -0
- data/sorbet/rbi/annotations/.gitattributes +0 -0
- data/sorbet/rbi/annotations/minitest.rbi +0 -0
- data/sorbet/rbi/annotations/rainbow.rbi +0 -0
- data/sorbet/rbi/gems/.gitattributes +0 -0
- data/sorbet/rbi/gems/ast@2.4.2.rbi +0 -0
- data/sorbet/rbi/gems/benchmark@0.4.0.rbi +0 -0
- data/sorbet/rbi/gems/bigdecimal@3.1.9.rbi +0 -0
- data/sorbet/rbi/gems/cli-ui@2.3.0.rbi +0 -0
- data/sorbet/rbi/gems/console_table@0.3.1.rbi +0 -0
- data/sorbet/rbi/gems/csv@3.3.2.rbi +0 -0
- data/sorbet/rbi/gems/erubi@1.13.1.rbi +0 -0
- data/sorbet/rbi/gems/httparty@0.22.0.rbi +0 -0
- data/sorbet/rbi/gems/json@2.10.1.rbi +0 -0
- data/sorbet/rbi/gems/language_server-protocol@3.17.0.4.rbi +0 -0
- data/sorbet/rbi/gems/lint_roller@1.1.0.rbi +0 -0
- data/sorbet/rbi/gems/mini_mime@1.1.5.rbi +0 -0
- data/sorbet/rbi/gems/minitest@5.25.4.rbi +0 -0
- data/sorbet/rbi/gems/multi_xml@0.7.1.rbi +0 -0
- data/sorbet/rbi/gems/netrc@0.11.0.rbi +0 -0
- data/sorbet/rbi/gems/nokogiri@1.18.3.rbi +0 -0
- data/sorbet/rbi/gems/parallel@1.26.3.rbi +0 -0
- data/sorbet/rbi/gems/parser@3.3.7.1.rbi +0 -0
- data/sorbet/rbi/gems/prism@1.3.0.rbi +0 -0
- data/sorbet/rbi/gems/racc@1.8.1.rbi +0 -0
- data/sorbet/rbi/gems/rainbow@3.1.1.rbi +0 -0
- data/sorbet/rbi/gems/rake-compiler@1.2.9.rbi +0 -0
- data/sorbet/rbi/gems/rake@13.2.1.rbi +0 -0
- data/sorbet/rbi/gems/rbi@0.2.4.rbi +0 -0
- data/sorbet/rbi/gems/regexp_parser@2.10.0.rbi +0 -0
- data/sorbet/rbi/gems/rubocop-ast@1.38.0.rbi +0 -0
- data/sorbet/rbi/gems/rubocop@1.72.2.rbi +0 -0
- data/sorbet/rbi/gems/ruby-progressbar@1.13.0.rbi +0 -0
- data/sorbet/rbi/gems/spoom@1.5.4.rbi +0 -0
- data/sorbet/rbi/gems/sqlite3@2.6.0.rbi +0 -0
- data/sorbet/rbi/gems/tapioca@0.16.11.rbi +0 -0
- data/sorbet/rbi/gems/thor@1.3.2.rbi +0 -0
- data/sorbet/rbi/gems/unicode-display_width@3.1.4.rbi +0 -0
- data/sorbet/rbi/gems/unicode-emoji@4.0.4.rbi +0 -0
- data/sorbet/rbi/gems/yard-sorbet@0.9.0.rbi +0 -0
- data/sorbet/rbi/gems/yard@0.9.37.rbi +0 -0
- data/sorbet/tapioca/config.yml +0 -0
- data/sorbet/tapioca/require.rb +0 -0
- data/src/main.c +0 -0
- metadata +39 -9
- data/.idea/dataSources/28fe2501-d682-44de-9f2e-9ff4bf02ce84/storage_v2/_src_/schema/main.uQUzAA.meta +0 -2
- data/.idea/dataSources/28fe2501-d682-44de-9f2e-9ff4bf02ce84.xml +0 -1617
- data/.idea/dataSources.local.xml +0 -18
- data/.idea/dataSources.xml +0 -12
- data/.idea/sqldialects.xml +0 -7
data/lib/greeenboii.rb
CHANGED
@@ -1,235 +1,880 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative "greeenboii/version"
|
4
|
-
|
5
|
-
require "
|
6
|
-
require "
|
7
|
-
|
8
|
-
|
9
|
-
require "
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
)
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
#
|
230
|
-
|
231
|
-
|
232
|
-
end
|
233
|
-
end
|
234
|
-
end
|
235
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "greeenboii/version"
|
4
|
+
require_relative "libsql"
|
5
|
+
require "cli/ui"
|
6
|
+
require "date"
|
7
|
+
require "console_table"
|
8
|
+
|
9
|
+
require "nokogiri"
|
10
|
+
require "httparty"
|
11
|
+
|
12
|
+
require "sqlite3"
|
13
|
+
|
14
|
+
require 'json'
|
15
|
+
require 'net/http'
|
16
|
+
require 'uri'
|
17
|
+
|
18
|
+
require 'dotenv'
|
19
|
+
require 'fileutils'
|
20
|
+
|
21
|
+
module Greeenboii
|
22
|
+
class Error < StandardError; end
|
23
|
+
|
24
|
+
class WebsiteBuilder
|
25
|
+
def self.build_website
|
26
|
+
CLI::UI::Frame.open("{{v}} Website Builder") do
|
27
|
+
CLI::UI::Prompt.ask("Choose a template:") do |handler|
|
28
|
+
handler.option("{{green:NextJs-CoolStack}}") { |selection| create_nextjs(selection) }
|
29
|
+
handler.option("{{yellow:Hono-API}}") { |selection| create_hono(selection) }
|
30
|
+
# handler.option("{{blue:Rails}}") { |selection| create_rails(selection) }
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.create_nextjs(_selection)
|
36
|
+
# Ask for a relative path instead
|
37
|
+
location = CLI::UI.ask("Where to install? (relative path)", default: "nextjs-project")
|
38
|
+
CLI::UI.puts("Checking prerequisites...")
|
39
|
+
|
40
|
+
# Check prerequisites
|
41
|
+
node_version = begin
|
42
|
+
`node -v`.strip
|
43
|
+
rescue StandardError
|
44
|
+
nil
|
45
|
+
end
|
46
|
+
unless node_version
|
47
|
+
CLI::UI.puts(CLI::UI.fmt("{{x}} Node.js not found. Please install Node.js first"))
|
48
|
+
return
|
49
|
+
end
|
50
|
+
|
51
|
+
git_version = begin
|
52
|
+
`git --version`.strip
|
53
|
+
rescue StandardError
|
54
|
+
nil
|
55
|
+
end
|
56
|
+
unless git_version
|
57
|
+
CLI::UI.puts(CLI::UI.fmt("{{x}} Git not found. Please install Git first"))
|
58
|
+
return
|
59
|
+
end
|
60
|
+
|
61
|
+
# Create a path relative to current directory
|
62
|
+
full_path = File.expand_path(location, Dir.pwd)
|
63
|
+
|
64
|
+
# Check if directory already exists
|
65
|
+
if Dir.exist?(full_path)
|
66
|
+
# If directory exists, check if it's empty
|
67
|
+
unless Dir.empty?(full_path) # . and .. entries
|
68
|
+
CLI::UI.puts(CLI::UI.fmt("{{x}} Directory not empty: #{full_path}"))
|
69
|
+
return
|
70
|
+
end
|
71
|
+
else
|
72
|
+
# Try to create the directory
|
73
|
+
begin
|
74
|
+
FileUtils.mkdir_p(full_path)
|
75
|
+
rescue StandardError => e
|
76
|
+
CLI::UI.puts(CLI::UI.fmt("{{x}} Cannot create directory: #{e.message}"))
|
77
|
+
return
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
success = false
|
82
|
+
CLI::UI::Spinner.spin("Setting up NextJS + Supabase template") do |spinner|
|
83
|
+
spinner.update_title("Cloning repository...")
|
84
|
+
|
85
|
+
# Clone directly into the target directory
|
86
|
+
clone_cmd = "git clone https://github.com/greeenboi/nextjs-supabase-template.git \"#{full_path}\""
|
87
|
+
result = system(clone_cmd)
|
88
|
+
|
89
|
+
unless result
|
90
|
+
# Try alternative approach if direct cloning fails
|
91
|
+
spinner.update_title("Direct clone failed, trying alternative...")
|
92
|
+
|
93
|
+
# Clone to a temporary directory first
|
94
|
+
temp_dir = "#{Dir.pwd}/temp_clone_#{Time.now.to_i}"
|
95
|
+
FileUtils.mkdir_p(temp_dir)
|
96
|
+
result = system("git clone https://github.com/greeenboi/nextjs-supabase-template.git \"#{temp_dir}\"")
|
97
|
+
|
98
|
+
if result
|
99
|
+
# Copy files to destination
|
100
|
+
FileUtils.cp_r(Dir.glob("#{temp_dir}/*"), full_path)
|
101
|
+
FileUtils.cp_r(Dir.glob("#{temp_dir}/.*").reject { |f| f =~ /\/\.\.?$/ }, full_path)
|
102
|
+
FileUtils.rm_rf(temp_dir)
|
103
|
+
else
|
104
|
+
spinner.update_title("Clone failed")
|
105
|
+
next
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
spinner.update_title("Installing dependencies...")
|
110
|
+
Dir.chdir(full_path) do
|
111
|
+
package_manager = if system("bun -v > /dev/null 2>&1")
|
112
|
+
"bun"
|
113
|
+
elsif system("pnpm -v > /dev/null 2>&1")
|
114
|
+
"pnpm"
|
115
|
+
else
|
116
|
+
"npm"
|
117
|
+
end
|
118
|
+
spinner.update_title("Installing dependencies with #{package_manager}...")
|
119
|
+
system("#{package_manager} install")
|
120
|
+
end
|
121
|
+
|
122
|
+
success = true
|
123
|
+
spinner.update_title("Setup complete!")
|
124
|
+
rescue StandardError => e
|
125
|
+
spinner.update_title("Error: #{e.message}")
|
126
|
+
end
|
127
|
+
|
128
|
+
if success
|
129
|
+
CLI::UI.puts(CLI::UI.fmt("{{v}} NextJS template installed successfully in #{full_path}"))
|
130
|
+
CLI::UI.puts(CLI::UI.fmt("{{*}} To start: cd \"#{location}\" && #{system} run dev"))
|
131
|
+
else
|
132
|
+
CLI::UI.puts(CLI::UI.fmt("{{x}} Installation failed"))
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def self.create_hono(_selection)
|
137
|
+
# Ask for a relative path instead
|
138
|
+
location = CLI::UI.ask("Where to install? (relative path)", default: "hono-api")
|
139
|
+
CLI::UI.puts("Checking prerequisites...")
|
140
|
+
|
141
|
+
# Check prerequisites
|
142
|
+
node_version = begin
|
143
|
+
`node -v`.strip
|
144
|
+
rescue StandardError
|
145
|
+
nil
|
146
|
+
end
|
147
|
+
unless node_version
|
148
|
+
CLI::UI.puts(CLI::UI.fmt("{{x}} Node.js not found. Please install Node.js first"))
|
149
|
+
return
|
150
|
+
end
|
151
|
+
|
152
|
+
git_version = begin
|
153
|
+
`git --version`.strip
|
154
|
+
rescue StandardError
|
155
|
+
nil
|
156
|
+
end
|
157
|
+
unless git_version
|
158
|
+
CLI::UI.puts(CLI::UI.fmt("{{x}} Git not found. Please install Git first"))
|
159
|
+
return
|
160
|
+
end
|
161
|
+
|
162
|
+
# Check for Deno
|
163
|
+
deno_version = begin
|
164
|
+
`deno --version`.strip
|
165
|
+
rescue StandardError
|
166
|
+
nil
|
167
|
+
end
|
168
|
+
unless deno_version
|
169
|
+
CLI::UI.puts(CLI::UI.fmt("{{x}} Deno not found. Please install Deno first"))
|
170
|
+
return
|
171
|
+
end
|
172
|
+
|
173
|
+
# Create a path relative to current directory
|
174
|
+
full_path = File.expand_path(location, Dir.pwd)
|
175
|
+
|
176
|
+
# Check if directory already exists
|
177
|
+
if Dir.exist?(full_path)
|
178
|
+
# If directory exists, check if it's empty
|
179
|
+
unless Dir.empty?(full_path) # . and .. entries
|
180
|
+
CLI::UI.puts(CLI::UI.fmt("{{x}} Directory not empty: #{full_path}"))
|
181
|
+
return
|
182
|
+
end
|
183
|
+
else
|
184
|
+
# Try to create the directory
|
185
|
+
begin
|
186
|
+
FileUtils.mkdir_p(full_path)
|
187
|
+
rescue StandardError => e
|
188
|
+
CLI::UI.puts(CLI::UI.fmt("{{x}} Cannot create directory: #{e.message}"))
|
189
|
+
return
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
success = false
|
194
|
+
CLI::UI::Spinner.spin("Setting up Hono Deno backend template") do |spinner|
|
195
|
+
spinner.update_title("Cloning repository...")
|
196
|
+
|
197
|
+
# Clone directly into the target directory
|
198
|
+
clone_cmd = "git clone https://github.com/greeenboi/hono-deno-backend-template.git \"#{full_path}\""
|
199
|
+
result = system(clone_cmd)
|
200
|
+
|
201
|
+
unless result
|
202
|
+
# Try alternative approach if direct cloning fails
|
203
|
+
spinner.update_title("Direct clone failed, trying alternative...")
|
204
|
+
|
205
|
+
# Clone to a temporary directory first
|
206
|
+
temp_dir = "#{Dir.pwd}/temp_clone_#{Time.now.to_i}"
|
207
|
+
FileUtils.mkdir_p(temp_dir)
|
208
|
+
result = system("git clone https://github.com/greeenboi/hono-deno-backend-template.git \"#{temp_dir}\"")
|
209
|
+
|
210
|
+
if result
|
211
|
+
# Copy files to destination
|
212
|
+
FileUtils.cp_r(Dir.glob("#{temp_dir}/*"), full_path)
|
213
|
+
FileUtils.cp_r(Dir.glob("#{temp_dir}/.*").reject { |f| f =~ /\/\.\.?$/ }, full_path)
|
214
|
+
FileUtils.rm_rf(temp_dir)
|
215
|
+
else
|
216
|
+
spinner.update_title("Clone failed")
|
217
|
+
next
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
success = true
|
222
|
+
spinner.update_title("Setup complete!")
|
223
|
+
rescue StandardError => e
|
224
|
+
spinner.update_title("Error: #{e.message}")
|
225
|
+
end
|
226
|
+
|
227
|
+
if success
|
228
|
+
CLI::UI.puts(CLI::UI.fmt("{{v}} Hono API template installed successfully in #{full_path}"))
|
229
|
+
CLI::UI.puts(CLI::UI.fmt("{{*}} To start: cd \"#{location}\" && deno task start"))
|
230
|
+
else
|
231
|
+
CLI::UI.puts(CLI::UI.fmt("{{x}} Installation failed"))
|
232
|
+
end
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
class Search
|
237
|
+
SEARCH_ENGINES = {
|
238
|
+
"Google" => "https://www.google.com/search?client=opera-gx&q= ",
|
239
|
+
"Bing" => "https://www.bing.com/search?q=",
|
240
|
+
"DuckDuckGo" => "https://duckduckgo.com/?q="
|
241
|
+
}.freeze
|
242
|
+
|
243
|
+
def self.perform_search
|
244
|
+
query = CLI::UI.ask("Enter your search query:", default: "")
|
245
|
+
return if query.empty?
|
246
|
+
|
247
|
+
results = []
|
248
|
+
CLI::UI::SpinGroup.new do |spin_group|
|
249
|
+
SEARCH_ENGINES.each do |engine, base_url|
|
250
|
+
spin_group.add("Searching #{engine}...") do |spinner|
|
251
|
+
suffix = case engine
|
252
|
+
when "Google"
|
253
|
+
"&sourceid=opera&ie=UTF-8&oe=UTF-8"
|
254
|
+
when "Bing"
|
255
|
+
"&sp=-1&pq=test&sc=6-4&qs=n&sk=&cvid=#{SecureRandom.hex(16)}"
|
256
|
+
when "DuckDuckGo"
|
257
|
+
"&t=h_&ia=web"
|
258
|
+
end
|
259
|
+
search_url = "#{base_url}#{URI.encode_www_form_component(query)}#{suffix}"
|
260
|
+
links = scrape_links(engine, search_url)
|
261
|
+
results << { engine: engine, links: links }
|
262
|
+
sleep 1.0 # Simulating search delay
|
263
|
+
spinner.update_title("#{engine} search complete!")
|
264
|
+
end
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
display_results(results)
|
269
|
+
end
|
270
|
+
|
271
|
+
def self.scrape_links(engine, url)
|
272
|
+
headers = {
|
273
|
+
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.54 Safari/537.36",
|
274
|
+
"Accept-Language" => "en-US,en;q=0.5"
|
275
|
+
}
|
276
|
+
|
277
|
+
response = HTTParty.get(url, headers: headers)
|
278
|
+
puts "Debug: HTTP Status: #{response.code}"
|
279
|
+
|
280
|
+
doc = Nokogiri::HTML(response.body)
|
281
|
+
puts "Debug: Page title: #{doc.title}"
|
282
|
+
|
283
|
+
results = []
|
284
|
+
|
285
|
+
case engine
|
286
|
+
when "Google"
|
287
|
+
doc.css("div.g").each do |result|
|
288
|
+
link = result.css(".yuRUbf > a").first
|
289
|
+
next unless link
|
290
|
+
|
291
|
+
title = result.css("h3").text.strip
|
292
|
+
url = link["href"]
|
293
|
+
result.css(".VwiC3b").text.strip
|
294
|
+
|
295
|
+
puts "Debug: Found Google result - Title: #{title}"
|
296
|
+
results << url if url.start_with?("http")
|
297
|
+
end
|
298
|
+
|
299
|
+
when "Bing"
|
300
|
+
doc.css("#b_results li.b_algo").each do |result|
|
301
|
+
link = result.css("h2 a").first
|
302
|
+
next unless link
|
303
|
+
|
304
|
+
url = link["href"]
|
305
|
+
puts "Debug: Found Bing result - URL: #{url}"
|
306
|
+
results << url if url.start_with?("http")
|
307
|
+
end
|
308
|
+
|
309
|
+
else # DuckDuckGo
|
310
|
+
doc.css(".result__body").each do |result|
|
311
|
+
link = result.css(".result__title a").first
|
312
|
+
next unless link
|
313
|
+
|
314
|
+
url = link["href"]
|
315
|
+
puts "Debug: Found DuckDuckGo result - URL: #{url}"
|
316
|
+
results << url if url.start_with?("http")
|
317
|
+
end
|
318
|
+
end
|
319
|
+
|
320
|
+
puts "Debug: Total results found: #{results.length}"
|
321
|
+
results.take(8)
|
322
|
+
end
|
323
|
+
|
324
|
+
def self.display_results(results)
|
325
|
+
CLI::UI.frame_style = :bracket
|
326
|
+
CLI::UI::Frame.open(CLI::UI.fmt("{{green:Search Results}}")) do
|
327
|
+
results.each do |result|
|
328
|
+
puts CLI::UI.fmt("{{v}} {{cyan:#{result[:engine]}}}")
|
329
|
+
result[:links].each_with_index do |link, idx|
|
330
|
+
puts CLI::UI.fmt(" {{*}} ##{idx + 1}: #{link}")
|
331
|
+
end
|
332
|
+
end
|
333
|
+
end
|
334
|
+
end
|
335
|
+
end
|
336
|
+
|
337
|
+
class TodoList
|
338
|
+
def initialize
|
339
|
+
@db = setup_database
|
340
|
+
end
|
341
|
+
|
342
|
+
private def setup_database
|
343
|
+
db = SQLite3::Database.new("greeenboii_todo.db")
|
344
|
+
db.execute <<~SQL
|
345
|
+
CREATE TABLE IF NOT EXISTS todos (
|
346
|
+
id INTEGER PRIMARY KEY,
|
347
|
+
title TEXT NOT NULL,
|
348
|
+
completed BOOLEAN DEFAULT 0,
|
349
|
+
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
350
|
+
)
|
351
|
+
SQL
|
352
|
+
db
|
353
|
+
end
|
354
|
+
|
355
|
+
def add_task
|
356
|
+
title = CLI::UI.ask("Enter task title:")
|
357
|
+
return if title.empty?
|
358
|
+
|
359
|
+
@db.execute("INSERT INTO todos (title) VALUES (?)", [title])
|
360
|
+
puts CLI::UI.fmt "{{green:✓}} Task added successfully!"
|
361
|
+
end
|
362
|
+
|
363
|
+
def list_tasks
|
364
|
+
tasks = @db.execute("SELECT id, title, completed, created_at FROM todos ORDER BY created_at DESC")
|
365
|
+
if tasks.empty?
|
366
|
+
puts CLI::UI.fmt "{{yellow:⚠}} No tasks found"
|
367
|
+
return
|
368
|
+
end
|
369
|
+
|
370
|
+
ConsoleTable.define(%w[ID Title Status Created]) do |table|
|
371
|
+
tasks.each do |id, title, completed, created_at|
|
372
|
+
status = completed == 1 ? "{{green:✓}} Done" : "{{red:✗}} Pending"
|
373
|
+
table << [id, title, CLI::UI.fmt(status), created_at]
|
374
|
+
end
|
375
|
+
end
|
376
|
+
end
|
377
|
+
|
378
|
+
def mark_done
|
379
|
+
list_tasks
|
380
|
+
id = CLI::UI.ask("Enter task ID to mark as done:")
|
381
|
+
return if id.empty?
|
382
|
+
|
383
|
+
@db.execute("UPDATE todos SET completed = 1 WHERE id = ?", [id])
|
384
|
+
puts CLI::UI.fmt "{{green:✓}} Task marked as done!"
|
385
|
+
end
|
386
|
+
|
387
|
+
def delete_task
|
388
|
+
list_tasks
|
389
|
+
id = CLI::UI.ask("Enter task ID to delete:")
|
390
|
+
return if id.empty?
|
391
|
+
|
392
|
+
@db.execute("DELETE FROM todos WHERE id = ?", [id])
|
393
|
+
puts CLI::UI.fmt "{{green:✓}} Task deleted!"
|
394
|
+
end
|
395
|
+
|
396
|
+
def update_task
|
397
|
+
list_tasks
|
398
|
+
id = CLI::UI.ask("Enter task ID to update:")
|
399
|
+
return if id.empty?
|
400
|
+
|
401
|
+
title = CLI::UI.ask("Enter new title:")
|
402
|
+
return if title.empty?
|
403
|
+
|
404
|
+
@db.execute("UPDATE todos SET title = ? WHERE id = ?", [title, id])
|
405
|
+
puts CLI::UI.fmt "{{green:✓}} Task updated!"
|
406
|
+
end
|
407
|
+
|
408
|
+
def show_menu
|
409
|
+
CLI::UI::Frame.divider("{{v}} Todo List")
|
410
|
+
loop do
|
411
|
+
CLI::UI::Prompt.ask("Todo List Options:") do |handler|
|
412
|
+
handler.option("List Tasks") { list_tasks }
|
413
|
+
handler.option("Add Task") { add_task }
|
414
|
+
handler.option("Mark Done") { mark_done }
|
415
|
+
handler.option("Update Task") { update_task }
|
416
|
+
handler.option("Delete Task") { delete_task }
|
417
|
+
handler.option("Exit") { return }
|
418
|
+
end
|
419
|
+
end
|
420
|
+
end
|
421
|
+
end
|
422
|
+
|
423
|
+
class GistManager
|
424
|
+
def initialize
|
425
|
+
Dotenv.load
|
426
|
+
ensure_connection
|
427
|
+
end
|
428
|
+
|
429
|
+
private def ensure_connection
|
430
|
+
return true
|
431
|
+
|
432
|
+
CLI::UI.puts(CLI::UI.fmt("{{yellow:⚠}} Turso credentials not found"))
|
433
|
+
manage_credentials
|
434
|
+
end
|
435
|
+
|
436
|
+
def add_gist
|
437
|
+
unless true
|
438
|
+
CLI::UI.puts(CLI::UI.fmt("{{red:✗}} Cloud credentials required"))
|
439
|
+
return
|
440
|
+
end
|
441
|
+
|
442
|
+
title = CLI::UI.ask("Enter a title for this gist:")
|
443
|
+
return if title.empty?
|
444
|
+
|
445
|
+
url = CLI::UI.ask("Enter GitHub Gist URL:")
|
446
|
+
return if url.empty? || !url.match?(/https:\/\/gist\.github\.com\//)
|
447
|
+
|
448
|
+
description = CLI::UI.ask("Enter a description (optional):", default: "")
|
449
|
+
tags = CLI::UI.ask("Enter tags (comma separated):", default: "")
|
450
|
+
|
451
|
+
# Extract gist ID from URL
|
452
|
+
gist_id = url.split('/').last
|
453
|
+
created_at = Time.now.strftime("%Y-%m-%d %H:%M:%S")
|
454
|
+
|
455
|
+
CLI::UI::Spinner.spin("Saving gist...") do |spinner|
|
456
|
+
begin
|
457
|
+
# First create table if needed
|
458
|
+
create_table_result = turso_execute(
|
459
|
+
"CREATE TABLE IF NOT EXISTS gists (gist_id TEXT PRIMARY KEY, title TEXT NOT NULL, url TEXT NOT NULL, description TEXT, tags TEXT, created_at TEXT)"
|
460
|
+
)
|
461
|
+
|
462
|
+
# Then insert the data
|
463
|
+
insert_result = turso_execute(
|
464
|
+
"INSERT OR REPLACE INTO gists (gist_id, title, url, description, tags, created_at) VALUES (?, ?, ?, ?, ?, ?)",
|
465
|
+
[gist_id, title, url, description, tags, created_at]
|
466
|
+
)
|
467
|
+
|
468
|
+
spinner.update_title("Gist saved successfully")
|
469
|
+
rescue => e
|
470
|
+
spinner.update_title("Error saving gist: #{e.message}")
|
471
|
+
end
|
472
|
+
end
|
473
|
+
end
|
474
|
+
|
475
|
+
def list_gists
|
476
|
+
unless true
|
477
|
+
CLI::UI.puts(CLI::UI.fmt("{{red:✗}} Cloud credentials required"))
|
478
|
+
return
|
479
|
+
end
|
480
|
+
|
481
|
+
CLI::UI::Spinner.spin("Fetching gists...") do |spinner|
|
482
|
+
begin
|
483
|
+
# Create table if needed
|
484
|
+
create_table_result = turso_execute(
|
485
|
+
"CREATE TABLE IF NOT EXISTS gists (gist_id TEXT PRIMARY KEY, title TEXT NOT NULL, url TEXT NOT NULL, description TEXT, tags TEXT, created_at TEXT)"
|
486
|
+
)
|
487
|
+
|
488
|
+
# Get all gists
|
489
|
+
result = turso_execute(
|
490
|
+
"SELECT gist_id, title, url, description, tags, created_at FROM gists ORDER BY created_at DESC"
|
491
|
+
)
|
492
|
+
|
493
|
+
@gists = extract_rows(result)
|
494
|
+
|
495
|
+
if @gists.empty?
|
496
|
+
spinner.update_title("No gists found")
|
497
|
+
else
|
498
|
+
spinner.update_title("Found #{@gists.length} gists")
|
499
|
+
end
|
500
|
+
rescue => e
|
501
|
+
spinner.update_title("Error fetching gists: #{e.message}")
|
502
|
+
end
|
503
|
+
end
|
504
|
+
|
505
|
+
return if !@gists || @gists.empty?
|
506
|
+
|
507
|
+
CLI::UI.puts("\nYour Gists:")
|
508
|
+
@gists.each do |gist|
|
509
|
+
gist_id, title, url, description, tags, created_at = gist
|
510
|
+
CLI::UI.puts(CLI::UI.fmt("{{cyan:#{gist_id}}}: {{bold:#{title}}} - #{url}"))
|
511
|
+
CLI::UI.puts(CLI::UI.fmt(" Description: #{description}")) if description && !description.empty?
|
512
|
+
CLI::UI.puts(CLI::UI.fmt(" Tags: #{tags}")) if tags && !tags.empty?
|
513
|
+
CLI::UI.puts(CLI::UI.fmt(" Created: #{created_at}"))
|
514
|
+
CLI::UI.puts("")
|
515
|
+
end
|
516
|
+
end
|
517
|
+
|
518
|
+
def search_gists
|
519
|
+
unless true
|
520
|
+
CLI::UI.puts(CLI::UI.fmt("{{red:✗}} Cloud credentials required"))
|
521
|
+
return
|
522
|
+
end
|
523
|
+
|
524
|
+
term = CLI::UI.ask("Enter search term:")
|
525
|
+
return if term.empty?
|
526
|
+
|
527
|
+
CLI::UI::Spinner.spin("Searching gists...") do |spinner|
|
528
|
+
begin
|
529
|
+
result = turso_execute(
|
530
|
+
"SELECT gist_id, title, url, description, tags, created_at FROM gists WHERE title LIKE ? OR description LIKE ? OR tags LIKE ? ORDER BY created_at DESC",
|
531
|
+
["%#{term}%", "%#{term}%", "%#{term}%"]
|
532
|
+
)
|
533
|
+
|
534
|
+
@search_results = extract_rows(result)
|
535
|
+
|
536
|
+
if @search_results.empty?
|
537
|
+
spinner.update_title("No matching gists found")
|
538
|
+
else
|
539
|
+
spinner.update_title("Found #{@search_results.length} matching gists")
|
540
|
+
end
|
541
|
+
rescue => e
|
542
|
+
spinner.update_title("Search error: #{e.message}")
|
543
|
+
end
|
544
|
+
end
|
545
|
+
|
546
|
+
return if !@search_results || @search_results.empty?
|
547
|
+
|
548
|
+
CLI::UI.puts(CLI::UI.fmt("\n{{bold:Search Results:}}"))
|
549
|
+
@search_results.each do |gist|
|
550
|
+
gist_id, title, url, description, tags, created_at = gist
|
551
|
+
CLI::UI.puts(CLI::UI.fmt("{{cyan:#{gist_id}}}: {{bold:#{title}}} - #{url}"))
|
552
|
+
CLI::UI.puts(CLI::UI.fmt(" Description: #{description}")) if description && !description.empty?
|
553
|
+
CLI::UI.puts(CLI::UI.fmt(" Tags: #{tags}")) if tags && !tags.empty?
|
554
|
+
CLI::UI.puts(CLI::UI.fmt(" Created: #{created_at}"))
|
555
|
+
CLI::UI.puts("")
|
556
|
+
end
|
557
|
+
end
|
558
|
+
|
559
|
+
def open_gist
|
560
|
+
list_gists
|
561
|
+
|
562
|
+
return if !@gists || @gists.empty?
|
563
|
+
|
564
|
+
gist_id = CLI::UI.ask("Enter gist ID to open:")
|
565
|
+
return if gist_id.empty?
|
566
|
+
|
567
|
+
# Find the matching gist
|
568
|
+
gist = @gists.find { |g| g[0] == gist_id }
|
569
|
+
|
570
|
+
unless gist
|
571
|
+
CLI::UI.puts(CLI::UI.fmt("{{red:✗}} Gist not found"))
|
572
|
+
return
|
573
|
+
end
|
574
|
+
|
575
|
+
url = gist[2] # URL is at index 2
|
576
|
+
|
577
|
+
if RUBY_PLATFORM.match?(/mswin|mingw|cygwin/)
|
578
|
+
system("start #{url}")
|
579
|
+
elsif RUBY_PLATFORM.match?(/darwin/)
|
580
|
+
system("open #{url}")
|
581
|
+
elsif RUBY_PLATFORM.match?(/linux/)
|
582
|
+
system("xdg-open #{url}")
|
583
|
+
else
|
584
|
+
CLI::UI.puts(CLI::UI.fmt("{{yellow:⚠}} Couldn't determine how to open URL on your platform. URL: #{url}"))
|
585
|
+
end
|
586
|
+
end
|
587
|
+
|
588
|
+
def delete_gist
|
589
|
+
list_gists
|
590
|
+
|
591
|
+
return if !@gists || @gists.empty?
|
592
|
+
|
593
|
+
gist_id = CLI::UI.ask("Enter gist ID to delete:")
|
594
|
+
return if gist_id.empty?
|
595
|
+
|
596
|
+
CLI::UI::Spinner.spin("Deleting gist...") do |spinner|
|
597
|
+
begin
|
598
|
+
result = turso_execute("DELETE FROM gists WHERE gist_id = ?", [gist_id])
|
599
|
+
|
600
|
+
# Try to determine if rows were affected
|
601
|
+
affected_rows = get_affected_rows(result)
|
602
|
+
|
603
|
+
if affected_rows > 0
|
604
|
+
spinner.update_title("Gist deleted successfully")
|
605
|
+
else
|
606
|
+
spinner.update_title("Gist not found")
|
607
|
+
end
|
608
|
+
rescue => e
|
609
|
+
spinner.update_title("Error deleting gist: #{e.message}")
|
610
|
+
end
|
611
|
+
end
|
612
|
+
end
|
613
|
+
|
614
|
+
def manage_credentials
|
615
|
+
CLI::UI::Frame.divider("{{v}} Cloud Credentials")
|
616
|
+
|
617
|
+
current_url = 'https://greeenboii-cli-db-greeenboi.aws-ap-south-1.turso.io/v2/pipeline'
|
618
|
+
current_token = "[Hidden]"
|
619
|
+
|
620
|
+
CLI::UI.puts(CLI::UI.fmt("Current settings:"))
|
621
|
+
CLI::UI.puts(CLI::UI.fmt("Database URL: {{cyan:#{current_url}}}"))
|
622
|
+
CLI::UI.puts(CLI::UI.fmt("Auth Token: {{cyan:#{current_token}}}"))
|
623
|
+
CLI::UI.puts("")
|
624
|
+
|
625
|
+
CLI::UI::Prompt.ask("Credential Options:") do |handler|
|
626
|
+
handler.option("Update Database URL") do
|
627
|
+
url = CLI::UI.ask("Enter Turso Database URL:")
|
628
|
+
update_env_file('TURSO_DATABASE_URL', url) unless url.empty?
|
629
|
+
end
|
630
|
+
|
631
|
+
handler.option("Update Auth Token") do
|
632
|
+
token = CLI::UI.ask("Enter Turso Auth Token:")
|
633
|
+
update_env_file('TURSO_AUTH_TOKEN', token) unless token.empty?
|
634
|
+
end
|
635
|
+
|
636
|
+
handler.option("Test Connection") do
|
637
|
+
test_connection
|
638
|
+
end
|
639
|
+
|
640
|
+
handler.option("Back") { return }
|
641
|
+
end
|
642
|
+
end
|
643
|
+
|
644
|
+
private def update_env_file(key, value)
|
645
|
+
env_file = '.env'
|
646
|
+
|
647
|
+
# Read existing .env content
|
648
|
+
content = File.exist?(env_file) ? File.read(env_file) : ""
|
649
|
+
lines = content.split("\n")
|
650
|
+
|
651
|
+
# Find and replace the line with the key, or add it
|
652
|
+
key_found = false
|
653
|
+
lines.map! do |line|
|
654
|
+
if line.start_with?("#{key}=")
|
655
|
+
key_found = true
|
656
|
+
"#{key}=#{value}"
|
657
|
+
else
|
658
|
+
line
|
659
|
+
end
|
660
|
+
end
|
661
|
+
|
662
|
+
lines << "#{key}=#{value}" unless key_found
|
663
|
+
|
664
|
+
# Write back to file
|
665
|
+
File.write(env_file, lines.join("\n"))
|
666
|
+
|
667
|
+
# Reload environment
|
668
|
+
ENV[key] = value
|
669
|
+
|
670
|
+
CLI::UI.puts(CLI::UI.fmt("{{v}} Updated #{key} in .env file"))
|
671
|
+
end
|
672
|
+
|
673
|
+
private def test_connection
|
674
|
+
CLI::UI::Spinner.spin("Testing Turso connection...") do |spinner|
|
675
|
+
begin
|
676
|
+
unless true
|
677
|
+
spinner.update_title("Cloud credentials not found")
|
678
|
+
next
|
679
|
+
end
|
680
|
+
|
681
|
+
result = turso_execute("SELECT 1")
|
682
|
+
spinner.update_title("Connection successful!")
|
683
|
+
rescue => e
|
684
|
+
spinner.update_title("Connection failed: #{e.message}")
|
685
|
+
end
|
686
|
+
end
|
687
|
+
end
|
688
|
+
|
689
|
+
def show_menu
|
690
|
+
CLI::UI::Frame.divider("{{v}} Gist Manager")
|
691
|
+
loop do
|
692
|
+
CLI::UI::Prompt.ask("Gist Manager Options:") do |handler|
|
693
|
+
handler.option("Add Gist") { add_gist }
|
694
|
+
handler.option("List Gists") { list_gists }
|
695
|
+
handler.option("Search Gists") { search_gists }
|
696
|
+
handler.option("Open Gist") { open_gist }
|
697
|
+
handler.option("Delete Gist") { delete_gist }
|
698
|
+
handler.option("Cloud Settings") { manage_credentials }
|
699
|
+
handler.option("Exit") { return }
|
700
|
+
end
|
701
|
+
end
|
702
|
+
end
|
703
|
+
|
704
|
+
private def turso_execute(sql, params = [])
|
705
|
+
url = 'https://greeenboii-cli-db-greeenboi.aws-ap-south-1.turso.io/v2/pipeline'
|
706
|
+
auth_token = 'eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE3NDY0NzY5MjUsImlkIjoiMmMyYjBmYmItMzg0OC00ZDM2LThmYzQtZTNkMmFhMTU4Nzk4IiwicmlkIjoiNDc5ZmE0YjMtY2YwNS00ZmI2LWFlOGUtOWY0YWQ1Yjk5MzRjIn0.qdU6U9kLYGqUXVs62XswYsKGxS4tpO7WkbGePvtCI5IlOhQlxqUVL9nMP87ppd7T6IQ3Irksdn5PGMS8zI_yAQ'
|
707
|
+
|
708
|
+
# Ensure URL has the correct endpoint path for v2 pipeline
|
709
|
+
url = url.end_with?('/v2/pipeline') ? url : "#{url}/v2/pipeline"
|
710
|
+
|
711
|
+
uri = URI(url)
|
712
|
+
request = Net::HTTP::Post.new(uri)
|
713
|
+
request["Authorization"] = "Bearer #{auth_token}"
|
714
|
+
request["Content-Type"] = "application/json"
|
715
|
+
|
716
|
+
# Format parameters into the required format
|
717
|
+
formatted_params = params.map do |param|
|
718
|
+
type = case param
|
719
|
+
when Integer, /^\d+$/
|
720
|
+
"integer"
|
721
|
+
when Float, /^\d+\.\d+$/
|
722
|
+
"float"
|
723
|
+
when TrueClass, FalseClass, /^(true|false)$/i
|
724
|
+
"boolean"
|
725
|
+
when NilClass
|
726
|
+
"null"
|
727
|
+
else
|
728
|
+
"text"
|
729
|
+
end
|
730
|
+
|
731
|
+
{
|
732
|
+
"type": type,
|
733
|
+
"value": param.to_s
|
734
|
+
}
|
735
|
+
end
|
736
|
+
|
737
|
+
# Build the request body
|
738
|
+
stmt = {
|
739
|
+
"sql": sql,
|
740
|
+
"args": formatted_params
|
741
|
+
}
|
742
|
+
|
743
|
+
payload = {
|
744
|
+
"requests": [
|
745
|
+
{ "type": "execute", "stmt": stmt },
|
746
|
+
{ "type": "close" }
|
747
|
+
]
|
748
|
+
}
|
749
|
+
|
750
|
+
request.body = JSON.generate(payload)
|
751
|
+
|
752
|
+
begin
|
753
|
+
# Log the request for debugging
|
754
|
+
ensure_log_directory
|
755
|
+
File.open('logs/turso_requests.log', 'a') do |f|
|
756
|
+
f.puts "#{Time.now} - REQUEST to #{uri}"
|
757
|
+
f.puts "SQL: #{sql}"
|
758
|
+
f.puts "Params: #{params.inspect}"
|
759
|
+
f.puts "Formatted Params: #{formatted_params.inspect}"
|
760
|
+
f.puts "Payload: #{payload.to_json}"
|
761
|
+
f.puts "-" * 80
|
762
|
+
end
|
763
|
+
|
764
|
+
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == 'https') do |http|
|
765
|
+
http.request(request)
|
766
|
+
end
|
767
|
+
|
768
|
+
# Log the response
|
769
|
+
ensure_log_directory
|
770
|
+
File.open('logs/turso_responses.log', 'a') do |f|
|
771
|
+
f.puts "#{Time.now} - RESPONSE (#{response.code})"
|
772
|
+
f.puts "Body: #{response.body}"
|
773
|
+
f.puts "-" * 80
|
774
|
+
end
|
775
|
+
|
776
|
+
if response.code != "200"
|
777
|
+
error_msg = "HTTP error: #{response.code} - #{response.body}"
|
778
|
+
log_error(error_msg)
|
779
|
+
raise error_msg
|
780
|
+
end
|
781
|
+
|
782
|
+
JSON.parse(response.body)
|
783
|
+
rescue JSON::ParserError => e
|
784
|
+
error_msg = "JSON parse error: #{e.message}. Response body: #{response&.body}"
|
785
|
+
log_error(error_msg)
|
786
|
+
raise error_msg
|
787
|
+
rescue => e
|
788
|
+
error_msg = "Query failed: #{e.message}"
|
789
|
+
log_error(error_msg)
|
790
|
+
raise error_msg
|
791
|
+
end
|
792
|
+
end
|
793
|
+
|
794
|
+
private def log_error(message)
|
795
|
+
ensure_log_directory
|
796
|
+
File.open('logs/turso_errors.log', 'a') do |f|
|
797
|
+
f.puts "#{Time.now} - ERROR"
|
798
|
+
f.puts message
|
799
|
+
f.puts "-" * 80
|
800
|
+
end
|
801
|
+
# Also output to console
|
802
|
+
CLI::UI.puts(CLI::UI.fmt("{{red:ERROR}}: #{message}"))
|
803
|
+
end
|
804
|
+
|
805
|
+
private def ensure_log_directory
|
806
|
+
FileUtils.mkdir_p('logs') unless Dir.exist?('logs')
|
807
|
+
end
|
808
|
+
|
809
|
+
private def extract_rows(result)
|
810
|
+
rows = []
|
811
|
+
|
812
|
+
if result &&
|
813
|
+
result["results"] &&
|
814
|
+
result["results"][0] &&
|
815
|
+
result["results"][0]["type"] == "ok" &&
|
816
|
+
result["results"][0]["response"] &&
|
817
|
+
result["results"][0]["response"]["type"] == "execute" &&
|
818
|
+
result["results"][0]["response"]["result"]
|
819
|
+
|
820
|
+
result_data = result["results"][0]["response"]["result"]
|
821
|
+
|
822
|
+
if result_data["rows"]
|
823
|
+
rows = result_data["rows"]
|
824
|
+
end
|
825
|
+
end
|
826
|
+
|
827
|
+
rows
|
828
|
+
end
|
829
|
+
|
830
|
+
private def get_affected_rows(result)
|
831
|
+
if result &&
|
832
|
+
result["results"] &&
|
833
|
+
result["results"][0] &&
|
834
|
+
result["results"][0]["type"] == "ok" &&
|
835
|
+
result["results"][0]["response"] &&
|
836
|
+
result["results"][0]["response"]["type"] == "execute" &&
|
837
|
+
result["results"][0]["response"]["result"] &&
|
838
|
+
result["results"][0]["response"]["result"]["affected_row_count"]
|
839
|
+
|
840
|
+
return result["results"][0]["response"]["result"]["affected_row_count"]
|
841
|
+
end
|
842
|
+
|
843
|
+
0
|
844
|
+
end
|
845
|
+
end
|
846
|
+
|
847
|
+
class Options
|
848
|
+
def self.show_options
|
849
|
+
CLI::UI::Prompt.instructions_color = CLI::UI::Color::GRAY
|
850
|
+
|
851
|
+
CLI::UI::Prompt.ask("Choose an option:") do |handler|
|
852
|
+
handler.option("{{gray:Search Files}}") { |selection| puts "Placeholder, Replaced soon. #{selection}" }
|
853
|
+
handler.option("{{gray:Search Directory}}") { |selection| puts "Placeholder, Replaced soon. #{selection}" }
|
854
|
+
handler.option("{{green:Website Builder}}") { |_selection| WebsiteBuilder.build_website }
|
855
|
+
handler.option("{{yellow:Todo List}}") { |_selection| TodoList.new.show_menu }
|
856
|
+
handler.option("{{cyan:Search Engine}}") { |_selection| Search.perform_search }
|
857
|
+
handler.option("{{blue:Gist Manager}}") { |_selection| GistManager.new.show_menu }
|
858
|
+
handler.option("{{red:Exit}}") { |_selection| exit }
|
859
|
+
end
|
860
|
+
end
|
861
|
+
end
|
862
|
+
|
863
|
+
class Main
|
864
|
+
CLI::UI::StdoutRouter.enable
|
865
|
+
current_time = DateTime.now.strftime("%d-%m-%Y %H:%M:%S")
|
866
|
+
CLI::UI::Frame.open("{{v}} Greeenboi : #{current_time}") do
|
867
|
+
puts "Welcome to Greeenboii"
|
868
|
+
puts "Lets do some magic!"
|
869
|
+
CLI::UI.frame_style = :bracket
|
870
|
+
CLI::UI::Frame.open(CLI::UI.fmt("{{green:Welcome to Greeenboii CLI}}")) do
|
871
|
+
puts CLI::UI.fmt("{{cyan:Version}}: #{Greeenboii::VERSION}")
|
872
|
+
# ConsoleTable.define(%w[Name Version]) do |table|
|
873
|
+
# table << ["Greeenboii", Greeenboii::VERSION]
|
874
|
+
# end
|
875
|
+
puts CLI::UI.fmt("{{yellow:Type 'help' to see available commands}}")
|
876
|
+
Options.show_options
|
877
|
+
end
|
878
|
+
end
|
879
|
+
end
|
880
|
+
end
|