rudisco 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/Gemfile +9 -0
- data/Rakefile +11 -0
- data/bin/rudisco +5 -0
- data/docs/images/image.jpg +0 -0
- data/license.md +9 -0
- data/rakefiles/rudisco.rake +21 -0
- data/readme.md +106 -0
- data/sources/database/rudisco.db +0 -0
- data/sources/rudisco/cli/cli.rb +125 -0
- data/sources/rudisco/cli/presentation/download.rb +56 -0
- data/sources/rudisco/cli/presentation/find.rb +87 -0
- data/sources/rudisco/cli/presentation/git_clone.rb +56 -0
- data/sources/rudisco/cli/presentation/open.rb +22 -0
- data/sources/rudisco/cli/presentation/show.rb +96 -0
- data/sources/rudisco/cli/presentation/update.rb +41 -0
- data/sources/rudisco/cli/presentation.rb +17 -0
- data/sources/rudisco/helpers.rb +74 -0
- data/sources/rudisco/models/gem/actions.rb +116 -0
- data/sources/rudisco/models/gem/dataset_methods.rb +28 -0
- data/sources/rudisco/models/gem/rubygems_scanner.rb +195 -0
- data/sources/rudisco/models/gem.rb +95 -0
- data/sources/rudisco/project_structure.rb +55 -0
- data/sources/rudisco/sqlite.rb +12 -0
- data/sources/rudisco.rb +13 -0
- data/spec/rudisco/models/gem_spec.rb +40 -0
- data/spec/spec_helper.rb +5 -0
- metadata +176 -0
@@ -0,0 +1,74 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
module Rudisco
|
4
|
+
module Helpers
|
5
|
+
##
|
6
|
+
# Opens +url+ in a browser.
|
7
|
+
#
|
8
|
+
# @param [String] url
|
9
|
+
|
10
|
+
def self.open_in_browser(url)
|
11
|
+
return if url.to_s.empty?
|
12
|
+
|
13
|
+
if defined?(Launchy) && Launchy.respond_to?(:open)
|
14
|
+
Launchy.open url
|
15
|
+
else
|
16
|
+
if RbConfig::CONFIG['host_os'] =~ /mswin|mingw|cygwin/
|
17
|
+
system "start #{url}"
|
18
|
+
elsif RbConfig::CONFIG['host_os'] =~ /darwin/
|
19
|
+
system "open #{url}"
|
20
|
+
elsif RbConfig::CONFIG['host_os'] =~ /linux|bsd/
|
21
|
+
system "xdg-open #{url}"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
##
|
27
|
+
# Downloads file from +url+ to +path+.
|
28
|
+
#
|
29
|
+
# @param [String] url
|
30
|
+
#
|
31
|
+
# @param [String, Pathname] path
|
32
|
+
#
|
33
|
+
# @exception NotAUrl
|
34
|
+
# Raised when +url+ not a string or empty.
|
35
|
+
# @exception DirNotExists
|
36
|
+
# Raised when +path+ is not a path to directory.
|
37
|
+
|
38
|
+
def self.download(url, path)
|
39
|
+
raise NotAUrl, url unless url.is_a?(String) && !url.empty?
|
40
|
+
raise DirNotExists, path unless Dir.exists? path
|
41
|
+
|
42
|
+
system "wget -P #{path} #{url} > /dev/null 2>&1"
|
43
|
+
end
|
44
|
+
|
45
|
+
##
|
46
|
+
# Clones git project from +url+ to +path+.
|
47
|
+
#
|
48
|
+
# @param [String] url
|
49
|
+
#
|
50
|
+
# @param [String, Pathname] path
|
51
|
+
#
|
52
|
+
# @exception NotAUrl
|
53
|
+
# Raised when +url+ not a string or empty.
|
54
|
+
# @exception DirShouldNotExists
|
55
|
+
# Raised when git can not clone project, since directory
|
56
|
+
# where it should be saved already exists.
|
57
|
+
|
58
|
+
def self.git_clone(url, path)
|
59
|
+
raise NotAUrl, url unless url.is_a?(String) && !url.empty?
|
60
|
+
raise DirShouldNotExists, path if Dir.exists? path
|
61
|
+
|
62
|
+
system "git clone #{url} #{path} > /dev/null 2>&1"
|
63
|
+
end
|
64
|
+
|
65
|
+
class NotAUrl < Error # no-doc
|
66
|
+
def initialize(url); super "Url '#{url}' is not a string or empty!" end; end
|
67
|
+
|
68
|
+
class DirNotExists < Error # no-doc
|
69
|
+
def initialize(dir); super "Directory '#{dir}' not exists!" end; end
|
70
|
+
|
71
|
+
class DirShouldNotExists < Error # no-doc
|
72
|
+
def initialize(dir); super "Directory '#{dir}' should not exist!" end; end
|
73
|
+
end # module Helpers
|
74
|
+
end # module Rudisco
|
@@ -0,0 +1,116 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
module Rudisco
|
4
|
+
class GemActions
|
5
|
+
# @param [Rudisco::Gem] gem
|
6
|
+
#
|
7
|
+
# @return [Rudisco::GemActions]
|
8
|
+
|
9
|
+
def initialize(gem)
|
10
|
+
@gem = gem
|
11
|
+
end
|
12
|
+
|
13
|
+
##
|
14
|
+
# Creates an instance of GemActions class.
|
15
|
+
#
|
16
|
+
# @param [Symbol] action
|
17
|
+
# Described in Gem#action
|
18
|
+
#
|
19
|
+
# @param [Hash] params
|
20
|
+
# Additional parameters. Optional.
|
21
|
+
#
|
22
|
+
# @exception Rudisco::GemActions::ActionUnknown
|
23
|
+
# Raised when action is unknown.
|
24
|
+
|
25
|
+
def complete(action, params = {})
|
26
|
+
if respond_to? action
|
27
|
+
send action, params
|
28
|
+
else
|
29
|
+
raise Unknown, action
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# ----------------------------------------------------
|
34
|
+
# ------------- External actions methods -------------
|
35
|
+
# ----------------------------------------------------
|
36
|
+
|
37
|
+
##
|
38
|
+
# Updates gems.
|
39
|
+
#
|
40
|
+
# Used to get latest information about gem. This need because some
|
41
|
+
# db.attributes getting update even when gem version not changed.
|
42
|
+
|
43
|
+
def update(params = {})
|
44
|
+
Gem.corteges_scanning gem
|
45
|
+
end
|
46
|
+
|
47
|
+
##
|
48
|
+
# Opens in browser documentation page
|
49
|
+
|
50
|
+
def open_documentation(params = {})
|
51
|
+
Helpers.open_in_browser gem.documentation_url
|
52
|
+
end
|
53
|
+
|
54
|
+
##
|
55
|
+
# Opens in browser bug tracker page
|
56
|
+
|
57
|
+
def open_bug_tracker(params = {})
|
58
|
+
Helpers.open_in_browser gem.bug_tracker_url
|
59
|
+
end
|
60
|
+
|
61
|
+
##
|
62
|
+
# Opens in browser code sources page.
|
63
|
+
|
64
|
+
def open_sources(params = {})
|
65
|
+
Helpers.open_in_browser gem.source_code_url
|
66
|
+
end
|
67
|
+
|
68
|
+
##
|
69
|
+
# Opens in browser wiki page.
|
70
|
+
|
71
|
+
def open_wiki(params = {})
|
72
|
+
Helpers.open_in_browser gem.wiki_url
|
73
|
+
end
|
74
|
+
|
75
|
+
##
|
76
|
+
# Opens in browser gem page on rubygems.org
|
77
|
+
|
78
|
+
def open_rubygems(params = {})
|
79
|
+
Helpers.open_in_browser gem.project_url
|
80
|
+
end
|
81
|
+
|
82
|
+
##
|
83
|
+
# Downloads gem.
|
84
|
+
#
|
85
|
+
# @param [Hash] params
|
86
|
+
# @option params [String] :path (ENV['HOME'])
|
87
|
+
|
88
|
+
def download(params = {})
|
89
|
+
path = params[:path] || ENV['HOME']
|
90
|
+
|
91
|
+
Helpers::download gem.gem_url, path
|
92
|
+
end
|
93
|
+
|
94
|
+
##
|
95
|
+
# Clones gem from git.
|
96
|
+
#
|
97
|
+
# @param [Hash] params
|
98
|
+
# @option params [String] :path (ENV['HOME'])
|
99
|
+
|
100
|
+
def git_clone(params = {})
|
101
|
+
path = params[:path] || ENV['HOME']
|
102
|
+
path = File.join(path, gem.name)
|
103
|
+
|
104
|
+
Helpers::git_clone gem.source_code_url, path
|
105
|
+
end
|
106
|
+
|
107
|
+
private
|
108
|
+
|
109
|
+
# @return [Rudisco::Gem]
|
110
|
+
|
111
|
+
attr_reader :gem
|
112
|
+
|
113
|
+
class Unknown < Error # no-doc
|
114
|
+
def initialize(action); super "Action '#{action}' is unknown!" end; end
|
115
|
+
end # class GemActions
|
116
|
+
end # module Rudisco
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
module Sequel::Plugins::GemExtendedDataset
|
4
|
+
module DatasetMethods
|
5
|
+
# @see Rudisco::Gem#action
|
6
|
+
#
|
7
|
+
# @return [Gem::Dataset]
|
8
|
+
|
9
|
+
def action(command, params = {})
|
10
|
+
each { |cortege| cortege.action command, params }
|
11
|
+
|
12
|
+
return self
|
13
|
+
end
|
14
|
+
|
15
|
+
# @see Rudisco::Gem#find_phrase
|
16
|
+
#
|
17
|
+
# @return [Gem::Dataset]
|
18
|
+
|
19
|
+
def find_phrase(word)
|
20
|
+
search_filter =
|
21
|
+
Sequel.ilike(:name, "%#{word}%") || Sequel.ilike(:description, "%#{word}%")
|
22
|
+
|
23
|
+
dataset = where search_filter
|
24
|
+
|
25
|
+
return dataset
|
26
|
+
end
|
27
|
+
end # module DatasetMethods
|
28
|
+
end # Sequel::Plugins::GemExtendedDataset
|
@@ -0,0 +1,195 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
module Rudisco
|
4
|
+
module RubyGemsScanner # no-doc
|
5
|
+
##
|
6
|
+
# Scans rubygems.org for new gems. Also marks gems as outdated when
|
7
|
+
# new gem version is out.
|
8
|
+
#
|
9
|
+
# To load an actual information for newest gems use #deep_scanning.
|
10
|
+
|
11
|
+
def surface_scanning
|
12
|
+
_surface_scanning
|
13
|
+
end
|
14
|
+
|
15
|
+
##
|
16
|
+
# Long-term task. Updates database with an actual information. Multithread.
|
17
|
+
#
|
18
|
+
# Note: speed limited by rubygems.org.
|
19
|
+
#
|
20
|
+
# Can be increased with advanced concurrent processes setup for
|
21
|
+
# sqlite database.
|
22
|
+
#
|
23
|
+
# However, this is slow since rubygems.org allowing certain requests
|
24
|
+
# per second count.
|
25
|
+
#
|
26
|
+
# @param [Proc<Integer>] callback
|
27
|
+
# Returns count of updated gems, optional.
|
28
|
+
|
29
|
+
def deep_scanning(&callback)
|
30
|
+
_deep_scanning &callback
|
31
|
+
end
|
32
|
+
|
33
|
+
##
|
34
|
+
# Updates cortege(s).
|
35
|
+
#
|
36
|
+
# Used to get latest information about gem(s) total downloads
|
37
|
+
# count and so on.
|
38
|
+
#
|
39
|
+
# @param [Rudisco::Gem, Array<Rudisco::Gem>] corteges
|
40
|
+
|
41
|
+
def corteges_scanning(corteges)
|
42
|
+
rubygems_manage_corteges Array(corteges)
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def _surface_scanning # no-doc
|
48
|
+
rubygems =
|
49
|
+
begin
|
50
|
+
tmp_file = Tempfile.new 'gems.tmp'
|
51
|
+
|
52
|
+
system "gem list --remote > #{tmp_file.path}"
|
53
|
+
rubygems = CSV.open tmp_file.path
|
54
|
+
rubygems = rubygems.map { |r| r.join.delete('()').split }
|
55
|
+
tmp_file.unlink
|
56
|
+
|
57
|
+
rubygems
|
58
|
+
end
|
59
|
+
sqlite_gems = select_hash :name, :version
|
60
|
+
|
61
|
+
## ADD NEW GEMS TO DATABASE
|
62
|
+
db.transaction do
|
63
|
+
new_gems = rubygems.select { |gem| sqlite_gems[gem[0]].nil? }
|
64
|
+
|
65
|
+
new_gems.each do |gem|
|
66
|
+
insert name: gem[0], version: gem[1]
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
## UPDATE RECORDS IF NEED
|
71
|
+
db.transaction do
|
72
|
+
update_gems = rubygems.reject { |gem| sqlite_gems[gem[0]].nil? }
|
73
|
+
.select { |gem| sqlite_gems[gem[0]] != gem[1] }
|
74
|
+
|
75
|
+
update_gems.each do |gem|
|
76
|
+
cortege = where(:name => gem[0]).first
|
77
|
+
next if cortege[:version] > gem[1] # skip downgraded gems
|
78
|
+
|
79
|
+
cortege[:version] = gem[1]
|
80
|
+
cortege[:need_update] = true
|
81
|
+
cortege.save
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def _deep_scanning(&callback) # no-doc
|
87
|
+
_surface_scanning # todo this call should be optional
|
88
|
+
|
89
|
+
bunch =
|
90
|
+
begin
|
91
|
+
gem_update_count = where(need_update: true).count
|
92
|
+
threads_count = gem_update_count > 105 ? 35 : 1
|
93
|
+
bunch_sub_arr_size = gem_update_count / threads_count + 1
|
94
|
+
|
95
|
+
bunch_tmp =
|
96
|
+
Array.new(threads_count) do |i|
|
97
|
+
self.where(need_update: true)
|
98
|
+
.order(:id)
|
99
|
+
.limit(bunch_sub_arr_size).offset(i * bunch_sub_arr_size)
|
100
|
+
end
|
101
|
+
|
102
|
+
bunch_tmp
|
103
|
+
end # bunch = [ [], [], [], [], ... [] ]
|
104
|
+
|
105
|
+
threads = []
|
106
|
+
bunch.count.times do |i|
|
107
|
+
threads << Thread.new(bunch[i], callback) do |sub_array, callback_proc|
|
108
|
+
sub_array.each_slice(20) do |gems|
|
109
|
+
db.transaction { rubygems_manage_corteges gems }
|
110
|
+
callback_proc.call gems.count unless callback_proc.nil?
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
threads.each &:join
|
115
|
+
end
|
116
|
+
|
117
|
+
# @param [String] name
|
118
|
+
# Gem name.
|
119
|
+
#
|
120
|
+
# @return [Nil, String]
|
121
|
+
# Returns +nil+ when rubygems.org not responded, otherwise it
|
122
|
+
# returns encoded json as a string.
|
123
|
+
|
124
|
+
def send_request_to_rubygems(name)
|
125
|
+
for try_count in 1...25 do
|
126
|
+
begin
|
127
|
+
sleep try_count * 0.35
|
128
|
+
url = URI.parse "https://rubygems.org/api/v1/gems/#{name}.json"
|
129
|
+
response = Net::HTTP.get_response(url)
|
130
|
+
|
131
|
+
return response.body unless response.body.empty?
|
132
|
+
rescue Errno::ECONNRESET
|
133
|
+
next
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
return nil
|
138
|
+
end
|
139
|
+
|
140
|
+
##
|
141
|
+
# Updates +cortege+ with a data from +hsh+.
|
142
|
+
#
|
143
|
+
# @param [Rudisco::Gem] cortege
|
144
|
+
#
|
145
|
+
# @param [Hash] hsh
|
146
|
+
|
147
|
+
def update_cortege(cortege, hsh)
|
148
|
+
cortege[:description] = hsh["info"].to_s
|
149
|
+
cortege[:authors] = hsh["authors"].to_s
|
150
|
+
cortege[:license] = Array(hsh["licenses"]).join
|
151
|
+
cortege[:sha] = hsh["sha"].to_s
|
152
|
+
|
153
|
+
# "$ gem -list" and rubygems.org/api can send different information about
|
154
|
+
# last version for a gem. To prevent collision this code not downgrades
|
155
|
+
# gem version.
|
156
|
+
#
|
157
|
+
# In other words "$ gem list" have higher priority under rubygems.org/api
|
158
|
+
if hsh["version"].to_s > cortege[:version]
|
159
|
+
cortege[:version] = hsh["version"].to_s
|
160
|
+
end
|
161
|
+
|
162
|
+
cortege[:source_code_url] = hsh["source_code_uri"].to_s
|
163
|
+
cortege[:project_url] = hsh["project_uri"].to_s
|
164
|
+
cortege[:gem_url] = hsh["gem_uri"].to_s
|
165
|
+
cortege[:wiki_url] = hsh["wiki_uri"].to_s
|
166
|
+
cortege[:documentation_url] = hsh["documentation_uri"].to_s
|
167
|
+
cortege[:mailing_list_url] = hsh["mailing_list_uri"].to_s
|
168
|
+
cortege[:bug_tracker_url] = hsh["bug_tracker_uri"].to_s
|
169
|
+
|
170
|
+
cortege[:total_downloads] = hsh["downloads"].to_i
|
171
|
+
cortege[:version_downloads] = hsh["version_downloads"].to_i
|
172
|
+
|
173
|
+
cortege[:need_update] = false
|
174
|
+
end
|
175
|
+
|
176
|
+
# @param [Array<Rudisco::Gem>] corteges
|
177
|
+
|
178
|
+
def rubygems_manage_corteges(corteges)
|
179
|
+
corteges.each do |cortege|
|
180
|
+
response = send_request_to_rubygems cortege[:name]
|
181
|
+
|
182
|
+
if response.nil?
|
183
|
+
next
|
184
|
+
elsif response =~ /could not be found/
|
185
|
+
cortege.destroy # gem was deleted from rubygems.org
|
186
|
+
else
|
187
|
+
data = JSON.parse response
|
188
|
+
update_cortege cortege, data
|
189
|
+
|
190
|
+
cortege.save
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end # module RubyGemsScanner
|
195
|
+
end # module Rudisco
|
@@ -0,0 +1,95 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
module Rudisco
|
4
|
+
|
5
|
+
##
|
6
|
+
# == Table +gems+ structure:
|
7
|
+
#
|
8
|
+
# CREATE TABLE `gems` (
|
9
|
+
# `id` integer NOT NULL PRIMARY KEY AUTOINCREMENT,
|
10
|
+
#
|
11
|
+
# `name` Text,
|
12
|
+
# `description` Text,
|
13
|
+
# `authors` Text,
|
14
|
+
# `version` Text,
|
15
|
+
# `license` Text,
|
16
|
+
# `sha` Text,
|
17
|
+
#
|
18
|
+
# `source_code_url` Text,
|
19
|
+
# `project_url` Text,
|
20
|
+
# `gem_url` Text,
|
21
|
+
# `wiki_url` Text,
|
22
|
+
# `documentation_url` Text,
|
23
|
+
# `mailing_list_url` Text,
|
24
|
+
# `bug_tracker_url` Text,
|
25
|
+
#
|
26
|
+
# `total_downloads` Integer,
|
27
|
+
# `version_downloads` Integer,
|
28
|
+
#
|
29
|
+
# `need_update` Boolean DEFAULT (1)
|
30
|
+
# );
|
31
|
+
|
32
|
+
class Gem < Sequel::Model
|
33
|
+
extend RubyGemsScanner
|
34
|
+
plugin :gem_extended_dataset
|
35
|
+
|
36
|
+
##
|
37
|
+
# Case insensitive phrase search in :description, :name columns.
|
38
|
+
#
|
39
|
+
# @example
|
40
|
+
# phrase = 'rails'
|
41
|
+
# gems = Rudisco::Gem.find_phrase(phrase)
|
42
|
+
# .select(:name, :description)
|
43
|
+
#
|
44
|
+
# gems.each do |record|
|
45
|
+
# puts record[:name]
|
46
|
+
# puts record[:description]
|
47
|
+
# puts
|
48
|
+
# end
|
49
|
+
#
|
50
|
+
# @param [String] phrase
|
51
|
+
#
|
52
|
+
# @return [Gem::Dataset]
|
53
|
+
|
54
|
+
def self.find_phrase(phrase)
|
55
|
+
result = from(:gems).find_phrase phrase
|
56
|
+
|
57
|
+
return result
|
58
|
+
end
|
59
|
+
|
60
|
+
##
|
61
|
+
# Provides external actions for specified cortege.
|
62
|
+
#
|
63
|
+
# @example
|
64
|
+
# path_to_load = File.join(__dir__, '..', 'tmp')
|
65
|
+
#
|
66
|
+
# sample = Rudisco::Gem.exclude(source_code_url: '').first
|
67
|
+
# sample.action(:open_sources)
|
68
|
+
# .action(:git_clone, path: path_to_load)
|
69
|
+
#
|
70
|
+
# sample2 = Rudisco::Gem.limit(2)
|
71
|
+
# sample2.action(:download, path: path_to_load)
|
72
|
+
#
|
73
|
+
# @param [Symbol] command
|
74
|
+
# Expecting +command+ values:
|
75
|
+
# :update @see GemActions#update
|
76
|
+
# :open_documentation @see GemActions#open_documentation
|
77
|
+
# :open_bug_tracker @see GemActions#open_bug_tracker
|
78
|
+
# :open_sources @see GemActions#open_sources
|
79
|
+
# :open_wiki @see GemActions#open_wiki
|
80
|
+
# :open_rubygems @see GemActions#open_rubygmes
|
81
|
+
# :download @see GemActions#download
|
82
|
+
# :git_clone @see GemActions#git_clone
|
83
|
+
#
|
84
|
+
# @param [Hash] params
|
85
|
+
# Additional parameters. Optional.
|
86
|
+
#
|
87
|
+
# @return [Rudisco::Gem]
|
88
|
+
|
89
|
+
def action(command, params = {})
|
90
|
+
GemActions.new(self).complete command, params
|
91
|
+
|
92
|
+
return self
|
93
|
+
end
|
94
|
+
end # class Gem
|
95
|
+
end # module Rudisco
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
module Rudisco
|
4
|
+
# === Dependencies from core lib
|
5
|
+
|
6
|
+
require 'csv'
|
7
|
+
require 'net/http'
|
8
|
+
require 'uri'
|
9
|
+
require 'json'
|
10
|
+
require 'tempfile'
|
11
|
+
|
12
|
+
# === Dependencies from rubygems.org
|
13
|
+
|
14
|
+
require 'sqlite3'
|
15
|
+
require 'sequel'
|
16
|
+
require 'thor'
|
17
|
+
require 'command_line_reporter'
|
18
|
+
|
19
|
+
# === Project structure
|
20
|
+
|
21
|
+
##
|
22
|
+
# Ancestor class for Rudisco's exceptions.
|
23
|
+
|
24
|
+
class Error < StandardError; end
|
25
|
+
|
26
|
+
##
|
27
|
+
# Loads *.rb files in requested order.
|
28
|
+
|
29
|
+
def self.load(**params)
|
30
|
+
params[:files].each do |f|
|
31
|
+
require File.join(__dir__, params[:folder].to_s, f)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
private_class_method :load
|
35
|
+
|
36
|
+
# === Core
|
37
|
+
|
38
|
+
load files: %w(helpers sqlite)
|
39
|
+
|
40
|
+
load folder: 'models/gem',
|
41
|
+
files: %w(rubygems_scanner actions dataset_methods)
|
42
|
+
|
43
|
+
load folder: 'models',
|
44
|
+
files: %w(gem)
|
45
|
+
|
46
|
+
# === Command-Line-Interface
|
47
|
+
|
48
|
+
load folder: 'cli',
|
49
|
+
files: %w(presentation)
|
50
|
+
|
51
|
+
load folder: 'cli/presentation',
|
52
|
+
files: %w(find show update download git_clone open)
|
53
|
+
|
54
|
+
load files: %w(cli/cli) # cli/routes
|
55
|
+
end # module Rudisco
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
module Rudisco
|
4
|
+
path_to_database =
|
5
|
+
File.join(__dir__, '../../sources/database/rudisco.db')
|
6
|
+
|
7
|
+
Sequel.connect "sqlite://#{path_to_database}",
|
8
|
+
max_connections: 40,
|
9
|
+
pool_sleep_time: 0.015,
|
10
|
+
single_threaded: true,
|
11
|
+
pool_timeout: 60000
|
12
|
+
end # module Rudisco
|
data/sources/rudisco.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
#
|
4
|
+
# Rubygems database (https://rubygems.org)
|
5
|
+
#
|
6
|
+
# @see https://github.com/Medvedu/rudisco
|
7
|
+
# @see readme.md
|
8
|
+
#
|
9
|
+
# @author Kuzichev Michael
|
10
|
+
# @license MIT
|
11
|
+
module Rudisco
|
12
|
+
require_relative 'rudisco/project_structure'
|
13
|
+
end # module Rudisco
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
module Rudisco
|
5
|
+
describe Gem do
|
6
|
+
it 'includes certain columns' do
|
7
|
+
expect(described_class.columns)
|
8
|
+
.to include(:id, :name, :description, :source_code_url)
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'works as Sequel ORM' do
|
12
|
+
expect(described_class.where {total_downloads > 10000000 }.count)
|
13
|
+
.to be > 0
|
14
|
+
end
|
15
|
+
|
16
|
+
# ----------------------------------------------------
|
17
|
+
|
18
|
+
describe "#find_phrase" do
|
19
|
+
it 'case insensitive searches in :description, :name columns' do
|
20
|
+
gems = described_class.find_phrase 'monkey'
|
21
|
+
|
22
|
+
gems.each do |gem|
|
23
|
+
expect((gem.name =~ /monkey/i) || (gem.description =~ /monkey/i))
|
24
|
+
.to_not be_nil
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end # describe "#find_phrase"
|
28
|
+
|
29
|
+
# ----------------------------------------------------
|
30
|
+
|
31
|
+
describe "#action" do
|
32
|
+
it 'raises an exception when action is unknown' do
|
33
|
+
sample = described_class.first
|
34
|
+
|
35
|
+
expect{ sample.action :misspelled_action }
|
36
|
+
.to raise_exception GemActions::Unknown
|
37
|
+
end
|
38
|
+
end # describe "#action"
|
39
|
+
end # describe Gem
|
40
|
+
end # module Rudisco
|