gems_bond 1.0.4 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/gems_bond.rb +3 -2
- data/lib/gems_bond/configuration.rb +2 -0
- data/lib/gems_bond/{examination_helper.rb → examination.rb} +30 -18
- data/lib/gems_bond/fetchers/fetcher.rb +34 -0
- data/lib/gems_bond/{fetcher → fetchers}/github.rb +54 -10
- data/lib/gems_bond/fetchers/ruby_gems.rb +82 -0
- data/lib/gems_bond/gem.rb +128 -10
- data/lib/gems_bond/helpers/concurrency_helper.rb +24 -0
- data/lib/gems_bond/helpers/formatting_helper.rb +48 -0
- data/lib/gems_bond/printers/csv.rb +54 -0
- data/lib/gems_bond/printers/html.rb +61 -0
- data/lib/gems_bond/printers/printer.rb +58 -0
- data/lib/gems_bond/printers/stdout.rb +90 -0
- data/lib/gems_bond/railtie.rb +2 -1
- data/lib/gems_bond/spy/all.rb +93 -0
- data/lib/gems_bond/spy/one.rb +59 -0
- data/lib/gems_bond/version.rb +1 -1
- data/lib/tasks/gems_bond/spy/all.rake +36 -0
- data/lib/tasks/gems_bond/spy/one.rake +29 -0
- metadata +17 -10
- data/lib/gems_bond/fetch_helper.rb +0 -71
- data/lib/gems_bond/fetcher/ruby_gems.rb +0 -58
- data/lib/gems_bond/printer.rb +0 -88
- data/lib/gems_bond/spy.rb +0 -62
- data/lib/tasks/gems_bond/spy.rake +0 -34
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2cafc096896bf8383fde404d0c47020e4b8f9b1fe49c5cabfc1e8357c766682e
|
4
|
+
data.tar.gz: 48b00b4c32c30eafa88fa8c839b8ad9c7ddab251420e501c6010853062064047
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bfe4e248242f9609bad37d5b72cd5a6ef1557ec59039729c76b5f5658f08dea6dcf9ab5c563bab778c27de15688ad77b3f7d9cbea4e569c22f0bfb84b3aa3fd2
|
7
|
+
data.tar.gz: b46f8529d54c8a3b3e6de88f9951bb78c61e2747bb8033de3f712556a874d58548428aa1d2fea8216997487e9962f906b112c1c268964d426f4d2a68b27a5308
|
data/lib/gems_bond.rb
CHANGED
@@ -5,11 +5,12 @@ require "gems_bond/railtie" if defined?(Rails)
|
|
5
5
|
|
6
6
|
# Gem module
|
7
7
|
module GemsBond
|
8
|
-
class Error < StandardError; end
|
9
|
-
|
10
8
|
class << self
|
11
9
|
attr_accessor :configuration
|
12
10
|
|
11
|
+
# Configures Gems Bond
|
12
|
+
# @return GemsBond::Configuration
|
13
|
+
# @yieldparam [Proc] configuration to apply
|
13
14
|
def configure
|
14
15
|
self.configuration ||= Configuration.new
|
15
16
|
yield(configuration)
|
@@ -1,16 +1,25 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "yaml"
|
4
|
+
|
3
5
|
module GemsBond
|
4
6
|
# Examines gem sanity
|
5
|
-
module
|
7
|
+
module Examination
|
6
8
|
SCORES = YAML.safe_load(File.read(File.join(File.dirname(__FILE__), "scores.yml")))
|
7
9
|
BOUNDARIES = SCORES["boundaries"]
|
8
10
|
RESULTS = SCORES["results"]
|
9
11
|
|
10
|
-
|
11
|
-
|
12
|
-
|
12
|
+
# @!method activity_score
|
13
|
+
# Returns activity score
|
14
|
+
# @return [Integer, nil] in [0, 1] (memoized)
|
15
|
+
|
16
|
+
# @!method popularity_score
|
17
|
+
# Returns popularity score
|
18
|
+
# @return [Integer, nil] in [0, 1] (memoized)
|
13
19
|
|
20
|
+
# @!method average_score
|
21
|
+
# Returns average score
|
22
|
+
# @return [Integer, nil] in [0, 1] (memoized)
|
14
23
|
RESULTS.each do |result, values|
|
15
24
|
define_method("#{result}_score") do
|
16
25
|
memoize("#{result}_score") do
|
@@ -27,6 +36,9 @@ module GemsBond
|
|
27
36
|
|
28
37
|
# Scores getters and calculation
|
29
38
|
|
39
|
+
# For each inspected data, generate two methods:
|
40
|
+
# - <data>_score that memoizes the calculated score
|
41
|
+
# - calculate_<data>_score that calculates the score and returns [Integer, nil] in [0, 1]
|
30
42
|
BOUNDARIES.each_key do |key|
|
31
43
|
# create a _score getter for each key
|
32
44
|
define_method("#{key}_score") do
|
@@ -61,6 +73,15 @@ module GemsBond
|
|
61
73
|
end
|
62
74
|
end
|
63
75
|
|
76
|
+
# Returns a score with a logarithmic approach
|
77
|
+
# @param value [Float] the value for inspected data
|
78
|
+
# @param comparison [Numeric] the value giving the maximal score (1)
|
79
|
+
# @returns [Float]
|
80
|
+
# @example
|
81
|
+
# soften(10.to_f,100.to_f) #=> 0.46
|
82
|
+
# The idea is that a gem with half as much stars
|
83
|
+
# than rails gem (which is very high and stands for comparison here)
|
84
|
+
# should get a very high score but still be behind rails itself
|
64
85
|
def soften(value, comparison)
|
65
86
|
# returns a shaped curve
|
66
87
|
sigmoid = ->(x) { 1 / (1 + Math.exp(-x * 10)) }
|
@@ -69,8 +90,11 @@ module GemsBond
|
|
69
90
|
(sigmoid.call(value / comparison) - 0.5) * 2
|
70
91
|
end
|
71
92
|
|
72
|
-
#
|
73
|
-
|
93
|
+
# Returns an average after including weight for each value
|
94
|
+
# @param scores [Array<Array<Float, Integer>>] each hash looks like [value, weight]
|
95
|
+
# @returns [Float]
|
96
|
+
# @example
|
97
|
+
# weighted_average([[4.0, 2], [1.0, 3]]) #=> 2.2
|
74
98
|
def weighted_average(scores)
|
75
99
|
acc = 0
|
76
100
|
weight = 0
|
@@ -85,17 +109,5 @@ module GemsBond
|
|
85
109
|
|
86
110
|
acc / weight
|
87
111
|
end
|
88
|
-
|
89
|
-
# --- VERSION STATUS
|
90
|
-
|
91
|
-
def calculate_version_gap
|
92
|
-
return unless version && versions
|
93
|
-
|
94
|
-
index = versions.index { |v| v[:number] == version }
|
95
|
-
return unless index
|
96
|
-
|
97
|
-
gap = versions[0..index].count { |v| !v[:prerelease] } - 1
|
98
|
-
gap.positive? ? gap : 0
|
99
|
-
end
|
100
112
|
end
|
101
113
|
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "octokit"
|
4
|
+
|
5
|
+
module GemsBond
|
6
|
+
module Fetchers
|
7
|
+
class NotStartedError < StandardError; end
|
8
|
+
|
9
|
+
# Fetches data
|
10
|
+
class Fetcher
|
11
|
+
# Initializes an instance
|
12
|
+
# @param param [Object] Fetcher dependent
|
13
|
+
# @return [GemsBond::Fetchers::Fetcher]
|
14
|
+
def initialize(param); end
|
15
|
+
|
16
|
+
# Starts the service and returns self
|
17
|
+
# @note rescue connection errors with nil
|
18
|
+
def start
|
19
|
+
@started = true
|
20
|
+
end
|
21
|
+
|
22
|
+
# Starts the service and returns self
|
23
|
+
# @note rescue connection errors with nil
|
24
|
+
def stop
|
25
|
+
@started = false
|
26
|
+
end
|
27
|
+
|
28
|
+
# Is the service started?
|
29
|
+
def started?
|
30
|
+
@started
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -1,58 +1,79 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "octokit"
|
4
|
+
require "gems_bond/fetchers/fetcher"
|
4
5
|
|
5
6
|
module GemsBond
|
6
|
-
module
|
7
|
+
module Fetchers
|
7
8
|
# Fetches data from GitHub
|
8
|
-
class Github
|
9
|
+
class Github < Fetcher
|
10
|
+
# GitHub repository pattern, e.g.: "https://github.com/BigBigDoudou/gems_bond"
|
9
11
|
REPOSITORY_REGEX = %r{https?://github.com/(?<repository>.*/.*)}.freeze
|
10
12
|
|
11
13
|
class << self
|
14
|
+
# Validates that `url` matches GitHub repository URL
|
12
15
|
def valid_url?(url)
|
13
16
|
url&.match?(REPOSITORY_REGEX)
|
14
17
|
end
|
15
18
|
end
|
16
19
|
|
20
|
+
# Initializes an instance
|
21
|
+
# @param url [String] URL of the GitHub repository
|
22
|
+
# @return [GemsBond::Fetchers::Github]
|
17
23
|
def initialize(url)
|
24
|
+
super(url)
|
18
25
|
@url = url
|
19
26
|
end
|
20
27
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
28
|
+
# Starts the service
|
29
|
+
# @return [Boolean]
|
30
|
+
# @note rescue connection errors with nil
|
25
31
|
def start
|
32
|
+
super
|
26
33
|
parse_url
|
27
34
|
login
|
35
|
+
# ensure repository exists (otherwise it raises Octokit error)
|
28
36
|
set_repository
|
29
|
-
self
|
30
37
|
rescue Octokit::Unauthorized, Octokit::InvalidRepository, Octokit::NotFound
|
31
|
-
|
38
|
+
stop
|
32
39
|
end
|
33
40
|
|
41
|
+
# Returns number of forks
|
42
|
+
# @return [Integer]
|
34
43
|
def forks_count
|
35
44
|
@repository["forks"]
|
36
45
|
end
|
37
46
|
|
47
|
+
# Returns number of stars
|
48
|
+
# @return [Integer]
|
38
49
|
def stars_count
|
39
50
|
@repository["watchers"]
|
40
51
|
end
|
41
52
|
|
53
|
+
# Returns number of contributors
|
54
|
+
# @return [Integer]
|
55
|
+
# @note GitHub API does not provide this number out of the box
|
56
|
+
# so we fetch all repository contributors and paginate with 1 per page
|
57
|
+
# thus the last page (from headers) should equal the number of contributors
|
42
58
|
def contributors_count
|
43
59
|
client = Octokit::Client.new(access_token: token, per_page: 1)
|
44
60
|
client.contributors(@repository_path)
|
45
61
|
response = client.last_response
|
46
62
|
links = response.headers[:link]
|
63
|
+
# e.g.: "[...] <https://api.github.com/repositories/8514/contributors?per_page=1&page=377>; rel=\"last\""
|
47
64
|
return 0 unless links
|
48
65
|
|
49
|
-
Integer(links.match(/.*page=(?<last>\d+)>; rel="last"/)[:last], 10)
|
66
|
+
Integer(links.match(/.*per_page=1&page=(?<last>\d+)>; rel="last"/)[:last], 10)
|
50
67
|
end
|
51
68
|
|
69
|
+
# Returns number of open issues
|
70
|
+
# @return [Integer]
|
52
71
|
def open_issues_count
|
53
72
|
@repository["open_issues"]
|
54
73
|
end
|
55
74
|
|
75
|
+
# Returns date of last commit (on main branch)
|
76
|
+
# @return [Date]
|
56
77
|
def last_commit_date
|
57
78
|
date = client.commits(@repository_path).first[:commit][:committer][:date]
|
58
79
|
return unless date
|
@@ -60,12 +81,16 @@ module GemsBond
|
|
60
81
|
Date.parse(date.to_s)
|
61
82
|
end
|
62
83
|
|
84
|
+
# Returns number of days since last commit
|
85
|
+
# @return [Date]
|
63
86
|
def days_since_last_commit
|
64
87
|
return unless last_commit_date
|
65
88
|
|
66
|
-
Date.today - last_commit_date
|
89
|
+
Integer(Date.today - last_commit_date)
|
67
90
|
end
|
68
91
|
|
92
|
+
# Returns size of the lib directory
|
93
|
+
# @return [Integer]
|
69
94
|
def lib_size
|
70
95
|
contents_size = dir_size("lib")
|
71
96
|
return unless contents_size
|
@@ -78,6 +103,9 @@ module GemsBond
|
|
78
103
|
|
79
104
|
private
|
80
105
|
|
106
|
+
# Parses url to find out repository path
|
107
|
+
# @return [String]
|
108
|
+
# @raise Octokit::InvalidRepository if the url pattern is invalid
|
81
109
|
def parse_url
|
82
110
|
matches = @url.match(REPOSITORY_REGEX)
|
83
111
|
raise Octokit::InvalidRepository unless matches
|
@@ -86,28 +114,44 @@ module GemsBond
|
|
86
114
|
@repository_path = "#{path[0]}/#{path[1]}"
|
87
115
|
end
|
88
116
|
|
117
|
+
# Logs with client
|
118
|
+
# @return [String] GitHub'username
|
89
119
|
def login
|
120
|
+
return unless token
|
121
|
+
|
90
122
|
@login ||= client.user.login
|
91
123
|
end
|
92
124
|
|
125
|
+
# Initializes a client
|
126
|
+
# @return [Octokit::Client]
|
93
127
|
def client
|
94
128
|
Octokit::Client.new(access_token: token)
|
95
129
|
end
|
96
130
|
|
131
|
+
# Returns token from configuration
|
132
|
+
# @return [String, nil]
|
97
133
|
def token
|
98
134
|
GemsBond.configuration&.github_token
|
99
135
|
end
|
100
136
|
|
137
|
+
# Returns repository object
|
138
|
+
# @return [Sawyer::Resource]
|
101
139
|
def set_repository
|
102
140
|
@repository = client.repo(@repository_path)
|
103
141
|
end
|
104
142
|
|
143
|
+
# Returns size of the given directory
|
144
|
+
# @param dir_path [String] path to the directory, e.g.: "lib/devise/strategies"
|
145
|
+
# @return [Integer]
|
146
|
+
# @note sum size of each subdirectories recursively
|
105
147
|
def dir_size(dir_path)
|
106
148
|
contents = client.contents(@repository_path, path: dir_path)
|
149
|
+
# starts accumulator with size of files
|
107
150
|
acc =
|
108
151
|
contents
|
109
152
|
.select { |content| content[:type] == "file" }
|
110
153
|
.sum { |content| content[:size] }
|
154
|
+
# adds size of subdirectories to the accumulator, with recursion
|
111
155
|
acc +=
|
112
156
|
contents
|
113
157
|
.select { |content| content[:type] == "dir" }
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "gems"
|
4
|
+
require "rubygems"
|
5
|
+
require "gems_bond/fetchers/fetcher"
|
6
|
+
|
7
|
+
module GemsBond
|
8
|
+
module Fetchers
|
9
|
+
# Fetches data from RubyGems
|
10
|
+
class RubyGems < Fetcher
|
11
|
+
# Initializes an instance
|
12
|
+
# @param name [String] name of the gem
|
13
|
+
# @return [GemsBond::Fetchers::RubyGems]
|
14
|
+
def initialize(name)
|
15
|
+
super(name)
|
16
|
+
@name = name
|
17
|
+
end
|
18
|
+
|
19
|
+
# Starts the service
|
20
|
+
# @return [Boolean]
|
21
|
+
# @note rescue connection errors with nil
|
22
|
+
def start
|
23
|
+
super
|
24
|
+
# ensure gem exists (otherwise it raises Gems error)
|
25
|
+
@info = Gems.info(@name)
|
26
|
+
rescue Gems::NotFound
|
27
|
+
stop
|
28
|
+
end
|
29
|
+
|
30
|
+
# Returns gem description
|
31
|
+
# @return [String]
|
32
|
+
def info
|
33
|
+
@info["info"]
|
34
|
+
end
|
35
|
+
|
36
|
+
# Returns number of downloads
|
37
|
+
# @return [Integer]
|
38
|
+
def downloads_count
|
39
|
+
Gems.total_downloads(@name)[:total_downloads]
|
40
|
+
end
|
41
|
+
|
42
|
+
# Returns source code URI
|
43
|
+
# @return [String]
|
44
|
+
def source_code_uri
|
45
|
+
@info["source_code_uri"]
|
46
|
+
end
|
47
|
+
|
48
|
+
# Returns versions data (number, date and if it is a prerelease)
|
49
|
+
# @return [Array<Hash>]
|
50
|
+
# @note each hash structure: { number: String, created_at: Date, prerelease: Boolean }
|
51
|
+
def versions
|
52
|
+
Gems.versions(@name).map do |version|
|
53
|
+
{
|
54
|
+
number: version["number"],
|
55
|
+
created_at: Date.parse(version["created_at"]),
|
56
|
+
prerelease: version["prerelease"]
|
57
|
+
}
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# Returns last version number
|
62
|
+
# @return [String]
|
63
|
+
def last_version
|
64
|
+
versions&.first&.dig(:number)
|
65
|
+
end
|
66
|
+
|
67
|
+
# Returns last version date
|
68
|
+
# @return [Date]
|
69
|
+
def last_version_date
|
70
|
+
versions&.first&.dig(:created_at)
|
71
|
+
end
|
72
|
+
|
73
|
+
# Returns number of days since last version
|
74
|
+
# @return [Integer]
|
75
|
+
def days_since_last_version
|
76
|
+
return unless last_version_date
|
77
|
+
|
78
|
+
Integer(Date.today - last_version_date)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
data/lib/gems_bond/gem.rb
CHANGED
@@ -1,46 +1,164 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "gems_bond/
|
4
|
-
require "gems_bond/
|
3
|
+
require "gems_bond/helpers/concurrency_helper"
|
4
|
+
require "gems_bond/fetchers/ruby_gems"
|
5
|
+
require "gems_bond/fetchers/github"
|
6
|
+
require "gems_bond/examination"
|
5
7
|
|
6
8
|
module GemsBond
|
7
9
|
# Handles gem data
|
8
10
|
class Gem
|
9
|
-
include
|
10
|
-
include
|
11
|
+
include GemsBond::Helpers::ConcurrencyHelper
|
12
|
+
include GemsBond::Examination
|
11
13
|
|
12
|
-
|
14
|
+
attr_reader :unknown
|
15
|
+
|
16
|
+
RUBY_GEM_KEYS = %i[
|
17
|
+
days_since_last_version downloads_count info last_version last_version_date source_code_uri versions
|
18
|
+
].freeze
|
19
|
+
|
20
|
+
GITHUB_KEYS = %i[
|
21
|
+
contributors_count days_since_last_commit forks_count last_commit_date open_issues_count stars_count
|
22
|
+
].freeze
|
23
|
+
|
24
|
+
# Initializes an instance
|
25
|
+
# @param dependency [Bundler::Dependency]
|
26
|
+
# @param unknown [Boolean] is it a current dependency?
|
27
|
+
# @return [GemsBond::Gem]
|
28
|
+
def initialize(dependency, unknown: false)
|
13
29
|
@dependency = dependency
|
30
|
+
@unknown = unknown
|
14
31
|
end
|
15
32
|
|
33
|
+
# Is the gem hosted on RubyGems?
|
34
|
+
# @retun [Boolean]
|
35
|
+
def exist?
|
36
|
+
ruby_gems_fetcher.started?
|
37
|
+
end
|
38
|
+
|
39
|
+
# Returns name
|
40
|
+
# @return [String] (memoized)
|
16
41
|
def name
|
17
42
|
memoize(__method__) { @dependency.name }
|
18
43
|
end
|
19
44
|
|
45
|
+
# Returns description
|
46
|
+
# @return [String] (memoized)
|
20
47
|
def description
|
21
|
-
memoize(__method__)
|
48
|
+
memoize(__method__) do
|
49
|
+
unknown ? info : @dependency.to_spec.description
|
50
|
+
end
|
22
51
|
end
|
23
52
|
|
53
|
+
# Returns used version
|
54
|
+
# @return [String] (memoized)
|
24
55
|
def version
|
25
|
-
memoize(__method__)
|
56
|
+
memoize(__method__) do
|
57
|
+
@dependency.to_spec.version.to_s unless unknown
|
58
|
+
end
|
26
59
|
end
|
27
60
|
|
61
|
+
# Returns homepage
|
62
|
+
# @return [String] (memoized)
|
28
63
|
def homepage
|
29
|
-
memoize(__method__)
|
64
|
+
memoize(__method__) do
|
65
|
+
@dependency.to_spec.homepage unless unknown
|
66
|
+
end
|
30
67
|
end
|
31
68
|
|
69
|
+
# Returns url
|
70
|
+
# @return [String]
|
32
71
|
def url
|
33
72
|
homepage || source_code_uri
|
34
73
|
end
|
35
74
|
|
75
|
+
# Returns GitHub url if exist
|
76
|
+
# @return [String, nil]
|
36
77
|
def github_url
|
37
|
-
|
78
|
+
[homepage, source_code_uri].find do |url|
|
79
|
+
GemsBond::Fetchers::Github.valid_url?(url)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
RUBY_GEM_KEYS.each do |key|
|
84
|
+
define_method(key) do
|
85
|
+
memoize(key) do
|
86
|
+
fetch(ruby_gems_fetcher, key)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
GITHUB_KEYS.each do |key|
|
92
|
+
define_method(key) do
|
93
|
+
memoize(key) do
|
94
|
+
fetch(github_fetcher, key)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
# Returns gap between installed and last released version, in days
|
100
|
+
# @return [Integer, nil] (memoized)
|
101
|
+
def version_gap
|
102
|
+
memoize(:version_gap) do
|
103
|
+
return unless version && versions
|
104
|
+
|
105
|
+
index = versions.index { |v| v[:number] == version }
|
106
|
+
return unless index
|
38
107
|
|
39
|
-
|
108
|
+
gap = versions[0..index].count { |v| !v[:prerelease] } - 1
|
109
|
+
gap.positive? ? gap : 0
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
# Fetches data from APIs
|
114
|
+
# @param concurrency [Boolean] should it be run concurrently?
|
115
|
+
# @param verbose [Boolean] should gem's name be stdout?
|
116
|
+
# @return [void]
|
117
|
+
def prepare_data(keys: nil, concurrency: false, verbose: false)
|
118
|
+
fetch_key = ->(key) { (keys.nil? || key.in?(keys)) && __send__(key) }
|
119
|
+
if concurrency
|
120
|
+
each_concurrently(RUBY_GEM_KEYS + GITHUB_KEYS, &fetch_key)
|
121
|
+
else
|
122
|
+
(RUBY_GEM_KEYS + GITHUB_KEYS).each(&fetch_key)
|
123
|
+
end
|
124
|
+
puts(name) if verbose
|
40
125
|
end
|
41
126
|
|
42
127
|
private
|
43
128
|
|
129
|
+
# Fetches the given data with the given fetcher
|
130
|
+
# @param fetcher [GemsBond::Fetchers]
|
131
|
+
# @param key [String]
|
132
|
+
# @return [Object, nil]
|
133
|
+
def fetch(fetcher, key)
|
134
|
+
return if fetcher.nil?
|
135
|
+
raise GemsBond::Fetchers::NotStartedError unless fetcher.started?
|
136
|
+
|
137
|
+
fetcher.public_send(key)
|
138
|
+
end
|
139
|
+
|
140
|
+
# Returns a started RubyGems fetcher
|
141
|
+
# @return [GemsBond::Fetchers::RubyGems, nil]
|
142
|
+
# @note #start is needed to ensure the fetcher works
|
143
|
+
def ruby_gems_fetcher
|
144
|
+
return @ruby_gems_fetcher if defined?(@ruby_gems_fetcher)
|
145
|
+
|
146
|
+
@ruby_gems_fetcher = GemsBond::Fetchers::RubyGems.new(name).tap(&:start)
|
147
|
+
end
|
148
|
+
|
149
|
+
# Returns a started GitHub fetcher
|
150
|
+
# @return [GemsBond::Fetchers::Github, nil]
|
151
|
+
# @note #start is needed to ensure the fetcher works (especially the token)
|
152
|
+
def github_fetcher
|
153
|
+
return @github_fetcher if defined?(@github_fetcher)
|
154
|
+
|
155
|
+
@github_fetcher = github_url && GemsBond::Fetchers::Github.new(github_url).tap(&:start)
|
156
|
+
end
|
157
|
+
|
158
|
+
# Memoizes the given key and apply the given block
|
159
|
+
# @param key [String] the instance variable key
|
160
|
+
# @yieldparam [Object] the value to memoize
|
161
|
+
# @return [Object]
|
44
162
|
def memoize(key)
|
45
163
|
return instance_variable_get("@#{key}") if instance_variable_defined?("@#{key}")
|
46
164
|
|