gems_bond 1.0.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: bc62800e859ce8dcf0015580a685bfaf8b5410c69843acae6d49e24fae011c4e
4
+ data.tar.gz: 6ee8416eade996316171af619d7e7fd6f14d3c82817f299c92c793902b5b6076
5
+ SHA512:
6
+ metadata.gz: d82f72f550a6be300e0d5ca5483b10ef8a7070e10912c89e2900675bdafd712ba6c4014728a5641f7789666d84da8ec126ea2c2b4e0d8a155b7134f68261f952
7
+ data.tar.gz: ae59181cbfbf9cff164a4c7c5776ccea3ef5c14a773a18d8ae5706be553fc61eff0b9d2a64b54bd11adeb7da8516152cbca5a1cc78daa04f292fdf43391618bb
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GemsBond
4
+ # Manages gem configuration
5
+ class Configuration
6
+ attr_accessor :github_token
7
+
8
+ def initialize
9
+ @github_token = nil
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,101 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GemsBond
4
+ # Examines gem sanity
5
+ module ExaminationHelper
6
+ SCORES = YAML.safe_load(File.read(File.join(File.dirname(__FILE__), "scores.yml")))
7
+ BOUNDARIES = SCORES["boundaries"]
8
+ RESULTS = SCORES["results"]
9
+
10
+ def version_gap
11
+ memoize(:version_gap) { calculate_version_gap }
12
+ end
13
+
14
+ RESULTS.each do |result, values|
15
+ define_method("#{result}_score") do
16
+ memoize("#{result}_score") do
17
+ weighted_average(
18
+ values.map do |key, weighting|
19
+ [__send__("#{key}_score"), weighting]
20
+ end
21
+ )
22
+ end
23
+ end
24
+ end
25
+
26
+ private
27
+
28
+ # Scores getters and calculation
29
+
30
+ BOUNDARIES.each_key do |key|
31
+ # create a _score getter for each key
32
+ define_method("#{key}_score") do
33
+ instance_variable_get("@#{key}_score") if instance_variable_defined?("@#{key}_score")
34
+
35
+ instance_variable_set("@#{key}_score", __send__("calculate_#{key}_score"))
36
+ end
37
+
38
+ # create a calculation method for each key
39
+ define_method("calculate_#{key}_score") do
40
+ value = public_send(key)
41
+ return unless value
42
+
43
+ min = BOUNDARIES[key]["min"]
44
+ max = BOUNDARIES[key]["max"]
45
+
46
+ # when lower the better (last commit at...)
47
+ if min
48
+ threshold = Float(BOUNDARIES[key]["threshold"] || 0)
49
+ return Float(1) if value <= threshold
50
+ return Float(0) if value >= min
51
+
52
+ soften(min - Float(value) + threshold, min + threshold)
53
+
54
+ # when higher the better (downloads count...)
55
+ else
56
+ return Float(1) if value >= max
57
+ return Float(0) if value <= 1
58
+
59
+ soften(Float(value), max)
60
+ end
61
+ end
62
+ end
63
+
64
+ def soften(value, comparison)
65
+ # returns a shaped curve
66
+ sigmoid = ->(x) { 1 / (1 + Math.exp(-x * 10)) }
67
+ # simoid boundaries are [0.5, 1]
68
+ # so remove 0.5 and multiply by 2 to have boundaries [0, 1]
69
+ (sigmoid.call(value / comparison) - 0.5) * 2
70
+ end
71
+
72
+ # --- COMPUTE
73
+
74
+ def weighted_average(scores)
75
+ acc = 0
76
+ weight = 0
77
+ scores.each do |score|
78
+ value, weighting = score
79
+ next unless value
80
+
81
+ acc += value * weighting
82
+ weight += weighting
83
+ end.compact
84
+ return if weight.zero?
85
+
86
+ acc / weight
87
+ 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
+ end
101
+ end
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "gems_bond/fetcher/ruby_gems"
4
+ require "gems_bond/fetcher/github"
5
+
6
+ module GemsBond
7
+ # Handles gem data
8
+ module FetchHelper
9
+ RUBY_GEM_KEYS = %i[
10
+ last_version_date
11
+ downloads_count
12
+ source_code_uri
13
+ versions
14
+ last_version
15
+ last_version_date
16
+ days_since_last_version
17
+ ].freeze
18
+
19
+ GITHUB_KEYS = %i[
20
+ contributors_count
21
+ stars_count
22
+ forks_count
23
+ last_commit_date
24
+ open_issues_count
25
+ days_since_last_commit
26
+ ].freeze
27
+
28
+ KEYS = RUBY_GEM_KEYS + GITHUB_KEYS
29
+
30
+ RUBY_GEM_KEYS.each do |key|
31
+ define_method(key) do
32
+ memoize(key) do
33
+ fetch(ruby_gems_fetcher, key)
34
+ end
35
+ end
36
+ end
37
+
38
+ GITHUB_KEYS.each do |key|
39
+ define_method(key) do
40
+ memoize(key) do
41
+ fetch(github_fetcher, key)
42
+ end
43
+ end
44
+ end
45
+
46
+ def fetch_all(verbose: false)
47
+ KEYS.each do |key|
48
+ __send__(key)
49
+ end
50
+ verbose && puts(name)
51
+ end
52
+
53
+ private
54
+
55
+ def fetch(fetcher, key)
56
+ fetcher&.public_send(key)
57
+ end
58
+
59
+ def ruby_gems_fetcher
60
+ return @ruby_gems_fetcher if defined?(@ruby_gems_fetcher)
61
+
62
+ @ruby_gems_fetcher = GemsBond::Fetcher::RubyGems.new(name).start
63
+ end
64
+
65
+ def github_fetcher
66
+ return @github_fetcher if defined?(@github_fetcher)
67
+
68
+ @github_fetcher = github_url && GemsBond::Fetcher::Github.new(github_url).start
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,121 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "octokit"
4
+
5
+ module GemsBond
6
+ module Fetcher
7
+ # Fetches data from GitHub
8
+ class Github
9
+ REPOSITORY_REGEX = %r{https?://github.com/(?<repository>.*/.*)}.freeze
10
+
11
+ class << self
12
+ def valid_url?(url)
13
+ url&.match?(REPOSITORY_REGEX)
14
+ end
15
+ end
16
+
17
+ def initialize(url)
18
+ @url = url
19
+ end
20
+
21
+ def source
22
+ "github"
23
+ end
24
+
25
+ def start
26
+ parse_url
27
+ login
28
+ set_repository
29
+ self
30
+ rescue Octokit::Unauthorized, Octokit::InvalidRepository, Octokit::NotFound
31
+ nil
32
+ end
33
+
34
+ def forks_count
35
+ @repository["forks"]
36
+ end
37
+
38
+ def stars_count
39
+ @repository["watchers"]
40
+ end
41
+
42
+ def contributors_count
43
+ client = Octokit::Client.new(access_token: token, per_page: 1)
44
+ client.contributors(@repository_path)
45
+ response = client.last_response
46
+ links = response.headers[:link]
47
+ return 0 unless links
48
+
49
+ Integer(links.match(/.*page=(?<last>\d+)>; rel="last"/)[:last], 10)
50
+ end
51
+
52
+ def open_issues_count
53
+ @repository["open_issues"]
54
+ end
55
+
56
+ def last_commit_date
57
+ date = client.commits(@repository_path).first[:commit][:committer][:date]
58
+ return unless date
59
+
60
+ Date.parse(date.to_s)
61
+ end
62
+
63
+ def days_since_last_commit
64
+ return unless last_commit_date
65
+
66
+ Date.today - last_commit_date
67
+ end
68
+
69
+ def lib_size
70
+ contents_size = dir_size("lib")
71
+ return unless contents_size
72
+
73
+ lines_count_estimation = contents_size / 25
74
+ return lines_count_estimation if lines_count_estimation < 100
75
+
76
+ lines_count_estimation - lines_count_estimation % 100
77
+ end
78
+
79
+ private
80
+
81
+ def parse_url
82
+ matches = @url.match(REPOSITORY_REGEX)
83
+ raise Octokit::InvalidRepository unless matches
84
+
85
+ path = matches[:repository].split("/")
86
+ @repository_path = "#{path[0]}/#{path[1]}"
87
+ end
88
+
89
+ def login
90
+ @login ||= client.user.login
91
+ end
92
+
93
+ def client
94
+ Octokit::Client.new(access_token: token)
95
+ end
96
+
97
+ def token
98
+ GemsBond.configuration&.github_token
99
+ end
100
+
101
+ def set_repository
102
+ @repository = client.repo(@repository_path)
103
+ end
104
+
105
+ def dir_size(dir_path)
106
+ contents = client.contents(@repository_path, path: dir_path)
107
+ acc =
108
+ contents
109
+ .select { |content| content[:type] == "file" }
110
+ .sum { |content| content[:size] }
111
+ acc +=
112
+ contents
113
+ .select { |content| content[:type] == "dir" }
114
+ .sum { |sub_dir| dir_size("#{dir_path}/#{sub_dir[:name]}") }
115
+ acc
116
+ rescue Octokit::NotFound
117
+ nil
118
+ end
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "gems"
4
+ require "rubygems"
5
+
6
+ module GemsBond
7
+ module Fetcher
8
+ # Fetches data from RubyGems
9
+ class RubyGems
10
+ def initialize(name)
11
+ @name = name
12
+ end
13
+
14
+ def source
15
+ "ruby gems"
16
+ end
17
+
18
+ def start
19
+ @info = Gems.info(@name)
20
+ self
21
+ rescue Gems::NotFound
22
+ nil
23
+ end
24
+
25
+ def downloads_count
26
+ Gems.total_downloads(@name)[:total_downloads]
27
+ end
28
+
29
+ def source_code_uri
30
+ @info["metadata"]["source_code_uri"]
31
+ end
32
+
33
+ def versions
34
+ Gems.versions(@name).map do |version|
35
+ {
36
+ number: version["number"],
37
+ created_at: Date.parse(version["created_at"]),
38
+ prerelease: version["prerelease"]
39
+ }
40
+ end
41
+ end
42
+
43
+ def last_version
44
+ versions&.first&.dig(:number)
45
+ end
46
+
47
+ def last_version_date
48
+ versions&.first&.dig(:created_at)
49
+ end
50
+
51
+ def days_since_last_version
52
+ return unless last_version_date
53
+
54
+ Date.today - last_version_date
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "gems_bond/fetch_helper"
4
+ require "gems_bond/examination_helper"
5
+
6
+ module GemsBond
7
+ # Handles gem data
8
+ class Gem
9
+ include FetchHelper
10
+ include ExaminationHelper
11
+
12
+ def initialize(dependency)
13
+ @dependency = dependency
14
+ end
15
+
16
+ def name
17
+ memoize(__method__) { @dependency.name }
18
+ end
19
+
20
+ def description
21
+ memoize(__method__) { @dependency.description }
22
+ end
23
+
24
+ def version
25
+ memoize(__method__) { @dependency.to_spec.version.to_s }
26
+ end
27
+
28
+ def homepage
29
+ memoize(__method__) { @dependency.to_spec.homepage }
30
+ end
31
+
32
+ def url
33
+ homepage || source_code_uri
34
+ end
35
+
36
+ def github_url
37
+ return homepage if GemsBond::Fetcher::Github.valid_url?(homepage)
38
+
39
+ source_code_uri if GemsBond::Fetcher::Github.valid_url?(source_code_uri)
40
+ end
41
+
42
+ private
43
+
44
+ def memoize(key)
45
+ return instance_variable_get("@#{key}") if instance_variable_defined?("@#{key}")
46
+
47
+ instance_variable_set("@#{key}", yield)
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,88 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "erb"
4
+ require "fileutils"
5
+
6
+ module GemsBond
7
+ # Prints gems table
8
+ class Printer
9
+ MISSING = "-"
10
+
11
+ def initialize(gems)
12
+ @gems = gems
13
+ end
14
+
15
+ def call
16
+ puts "\nPreparing data for printing results..."
17
+ create_directory
18
+ File.open("gems_bond/spy.html", "w") do |file|
19
+ file.puts content
20
+ end
21
+ puts "Open file gems_bond/spy.html to display the results."
22
+ end
23
+
24
+ private
25
+
26
+ def create_directory
27
+ return if File.directory?("gems_bond")
28
+
29
+ FileUtils.mkdir_p("gems_bond")
30
+ end
31
+
32
+ def template
33
+ File.read(File.join(File.dirname(__FILE__), "../../views/", "diagnosis.erb"))
34
+ end
35
+
36
+ def content
37
+ ERB.new(template).result(binding)
38
+ end
39
+
40
+ def sorted_gems
41
+ # sort with putting gems without average_score at the end
42
+ @gems.sort do |a, b|
43
+ if a.average_score && b.average_score
44
+ a.average_score <=> b.average_score
45
+ else
46
+ a.average_score ? -1 : 1
47
+ end
48
+ end
49
+ end
50
+
51
+ def version_color(gap)
52
+ return "secondary" if gap.nil?
53
+ return "success" if gap.zero?
54
+
55
+ gap < 3 ? "warning" : "danger"
56
+ end
57
+
58
+ def color(score)
59
+ return "secondary" if score.nil?
60
+
61
+ if score < 0.33
62
+ "danger"
63
+ elsif score < 0.66
64
+ "warning"
65
+ else
66
+ "success"
67
+ end
68
+ end
69
+
70
+ def human_date(date)
71
+ return MISSING if date.nil?
72
+
73
+ date.strftime("%F")
74
+ end
75
+
76
+ def human_number(number)
77
+ return MISSING if number.nil?
78
+
79
+ number.to_s.gsub(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1 ")
80
+ end
81
+
82
+ def human_score(score)
83
+ return MISSING if score.nil?
84
+
85
+ (score * 100).round
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GemsBond
4
+ # Makes Rails aware of the tasks
5
+ class Railtie < Rails::Railtie
6
+ rake_tasks do
7
+ load "tasks/gems_bond/spy.rake"
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+ boundaries:
3
+ days_since_last_version:
4
+ min: 730
5
+ threshold: 90
6
+ days_since_last_commit:
7
+ min: 365
8
+ threshold: 2
9
+ open_issues_count:
10
+ max: 300
11
+ downloads_count:
12
+ max: 200_000_000
13
+ contributors_count:
14
+ max: 350
15
+ forks_count:
16
+ max: 15_000
17
+ stars_count:
18
+ max: 30_000
19
+ results:
20
+ activity:
21
+ days_since_last_version: 3
22
+ days_since_last_commit: 5
23
+ contributors_count: 2
24
+ open_issues_count: 1
25
+ popularity:
26
+ downloads_count: 2
27
+ contributors_count: 3
28
+ forks_count: 1
29
+ stars_count: 1
30
+ average:
31
+ activity: 1
32
+ popularity: 2
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "gems_bond/gem"
4
+ require "gems_bond/printer"
5
+
6
+ module GemsBond
7
+ # Inspects gems and outputs the result
8
+ class Spy
9
+ RETRIES = 2
10
+
11
+ def call
12
+ chrono do
13
+ fetch_gems
14
+ GemsBond::Printer.new(gems).call
15
+ end
16
+ end
17
+
18
+ def gems_count
19
+ @gems_count ||= gems.count
20
+ end
21
+
22
+ private
23
+
24
+ def chrono
25
+ start_at = Time.now
26
+ yield
27
+ seconds = Time.now - start_at
28
+ time_per_gem_text = "#{(seconds / Float(gems_count)).round(2)} second(s) per gem"
29
+ puts "\nIt took #{seconds} second(s) to spy #{gems_count} gem(s) (#{time_per_gem_text})."
30
+ end
31
+
32
+ def gems
33
+ @gems ||=
34
+ Bundler.load.current_dependencies.map do |dependency|
35
+ GemsBond::Gem.new(dependency)
36
+ end
37
+ end
38
+
39
+ def fetch_gems
40
+ puts "Fetching data for..."
41
+ gems.each_slice(100) do |batch|
42
+ threads = []
43
+ batch.each do |gem|
44
+ threads << gem_thread(gem)
45
+ end
46
+ threads.each(&:join)
47
+ end
48
+ end
49
+
50
+ def gem_thread(gem)
51
+ Thread.new do
52
+ begin
53
+ retries ||= 0
54
+ gem.fetch_all(verbose: true)
55
+ # rescue SocketError, Faraday::ConnectionFailed...
56
+ rescue StandardError
57
+ (retries += 1) <= RETRIES ? retry : nil
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GemsBond
4
+ VERSION = "1.0.4"
5
+ end
data/lib/gems_bond.rb ADDED
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "gems_bond/configuration"
4
+ require "gems_bond/railtie" if defined?(Rails)
5
+
6
+ # Gem module
7
+ module GemsBond
8
+ class Error < StandardError; end
9
+
10
+ class << self
11
+ attr_accessor :configuration
12
+
13
+ def configure
14
+ self.configuration ||= Configuration.new
15
+ yield(configuration)
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "gems_bond/spy"
4
+
5
+ begin
6
+ require "#{Rails.root}/config/initializers/gems_bond" if defined?(Rails)
7
+ rescue LoadError
8
+ nil
9
+ end
10
+
11
+ namespace :gems_bond do
12
+ desc "Investigates gems"
13
+ task :spy do
14
+ puts "Welcome, my name is Bond, Gems Bond."\
15
+ " I will do some spying on your gems for you..."
16
+
17
+ GemsBond.configure do |config|
18
+ # set github_token from ENV if given
19
+ config.github_token = ENV["GITHUB_TOKEN"] if ENV["GITHUB_TOKEN"]
20
+ end
21
+
22
+ unless GemsBond.configuration.github_token
23
+ puts "It seems that you didn't provide any GitHub token."\
24
+ " This is necessary to fetch more data from GitHub,"\
25
+ " like the last commit date, the forks count, the sise of the repository..."
26
+
27
+ puts "Please provide a GitHub token by adding it in the configuration"\
28
+ " or passing GITHUB_TOKEN=<token> when running the task."
29
+ exit
30
+ end
31
+
32
+ GemsBond::Spy.new.call
33
+ end
34
+ end
@@ -0,0 +1,116 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <title>Gems Bond Diagnosis</title>
6
+ <link
7
+ href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css"
8
+ rel="stylesheet"
9
+ integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1"
10
+ crossorigin="anonymous"
11
+ >
12
+ <script
13
+ src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/js/bootstrap.bundle.min.js"
14
+ integrity="sha384-ygbV9kiqUc6oa4msXn9868pTtWMgiQaeYH7/t7LECLbyPA2x65Kgf80OJFdroafW"
15
+ crossorigin="anonymous"
16
+ ></script>
17
+ </head>
18
+ <body style="margin: 40px;">
19
+ <div class="container">
20
+ <div class="row justify-content-center">
21
+ <div class="list-group">
22
+ <table class="table table-hover small text-nowrap">
23
+ <thead>
24
+ <tr>
25
+ <th scope="col">#</th>
26
+ <th scope="col">Name</th>
27
+ <th scope="col">Version</th>
28
+ <th scope="col">Activity</th>
29
+ <th scope="col">Popularity</th>
30
+ <th scope="col">Diagnosis</th>
31
+ </tr>
32
+ </thead>
33
+ <tbody>
34
+ <% sorted_gems.each_with_index do |gem, i| %>
35
+ <tr>
36
+ <th scope="row"><%= i %></th>
37
+ <td>
38
+ <% if gem.url %>
39
+ <a href="<%= gem.url %>" target="_blank" class="text-decoration-none"><%= gem.name %></a>
40
+ <% else %>
41
+ <%= gem.name %>
42
+ <% end %>
43
+ </td>
44
+ <td class="text-wrap">
45
+ <div>
46
+ <p class="mb-1"><%= gem.version || "-" %></p>
47
+ <% if gem.version_gap&.zero? %>
48
+ <p class="badge bg-<%= version_color(gem.version_gap) %>">
49
+ up-to-date
50
+ </p>
51
+ <% elsif gem.version_gap %>
52
+ <p class="badge bg-<%= version_color(gem.version_gap) %>">
53
+ <%= gem.version_gap %> behind <%= gem.last_version %>
54
+ </p>
55
+ <% end %>
56
+ </div>
57
+ </td>
58
+ <td>
59
+ <div class="mb-1">
60
+ <p class="small m-0 fw-bold">Last version</p>
61
+ <p class="small m-0"><%= human_date(gem.last_version_date) %></p>
62
+ </div>
63
+ <div class="mb-1">
64
+ <p class="small m-0 fw-bold">Last commit</p>
65
+ <p class="small m-0"><%= human_date(gem.last_commit_date) %></p>
66
+ </div>
67
+ <div class="mb-1">
68
+ <p class="small m-0 fw-bold">Contributors</p>
69
+ <p class="small m-0"><%= human_number(gem.contributors_count) %></p>
70
+ </div>
71
+ </td>
72
+ <td>
73
+ <div class="mb-1">
74
+ <p class="small m-0 fw-bold">Downloads</p>
75
+ <p class="small m-0"><%= human_number(gem.downloads_count) %></p>
76
+ </div>
77
+ <div class="mb-1">
78
+ <p class="small m-0 fw-bold">Forks</p>
79
+ <p class="small m-0"><%= human_number(gem.forks_count) %></p>
80
+ </div>
81
+ <div class="mb-1">
82
+ <p class="small m-0 fw-bold">Stars</p>
83
+ <p class="small m-0"><%= gem.stars_count || "-" %></p>
84
+ </div>
85
+ </td>
86
+ <td>
87
+ <div class="row align-items-end">
88
+ <div class="col-6">
89
+ <div class="alert alert-<%= color(gem.average_score) %> text-wrap text-center" role="alert">
90
+ <p class="mb-0">SCORE</p>
91
+ <p class="mb-0" style="font-size: 40px; font-weight: 600"><%= human_score(gem.average_score) %></p>
92
+ </div>
93
+ </div>
94
+ <div class="col-3">
95
+ <div class="alert alert-<%= color(gem.activity_score) %> text-wrap text-center" role="alert">
96
+ <p class="mb-0">ACTIVITY</p>
97
+ <p class="mb-0" style="font-size: 30px;"><%= human_score(gem.activity_score) %></p>
98
+ </div>
99
+ </div>
100
+ <div class="col-3">
101
+ <div class="alert alert-<%= color(gem.popularity_score) %> text-wrap text-center" role="alert">
102
+ <p class="mb-0">POPULARITY</p>
103
+ <p class="font-weight-bold mb-0" style="font-size: 30px;"><%= human_score(gem.popularity_score) %></p>
104
+ </div>
105
+ </div>
106
+ </div>
107
+ </td>
108
+ </tr>
109
+ <% end %>
110
+ </tbody>
111
+ </table>
112
+ </div>
113
+ </div>
114
+ </div>
115
+ </body>
116
+ </html>
metadata ADDED
@@ -0,0 +1,87 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: gems_bond
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.4
5
+ platform: ruby
6
+ authors:
7
+ - Edouard Piron
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2021-01-29 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: gems
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: octokit
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '4.0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '4.0'
41
+ description: Inspect gems relying on data from RubyGems and GitHub
42
+ email:
43
+ - edouard.piron@gmail.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - lib/gems_bond.rb
49
+ - lib/gems_bond/configuration.rb
50
+ - lib/gems_bond/examination_helper.rb
51
+ - lib/gems_bond/fetch_helper.rb
52
+ - lib/gems_bond/fetcher/github.rb
53
+ - lib/gems_bond/fetcher/ruby_gems.rb
54
+ - lib/gems_bond/gem.rb
55
+ - lib/gems_bond/printer.rb
56
+ - lib/gems_bond/railtie.rb
57
+ - lib/gems_bond/scores.yml
58
+ - lib/gems_bond/spy.rb
59
+ - lib/gems_bond/version.rb
60
+ - lib/tasks/gems_bond/spy.rake
61
+ - views/diagnosis.erb
62
+ homepage: https://github.com/BigBigDoudou/gems_bond
63
+ licenses:
64
+ - MIT
65
+ metadata:
66
+ homepage_uri: https://github.com/BigBigDoudou/gems_bond
67
+ source_code_uri: https://github.com/BigBigDoudou/gems_bond
68
+ post_install_message:
69
+ rdoc_options: []
70
+ require_paths:
71
+ - lib
72
+ required_ruby_version: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: '2.4'
77
+ required_rubygems_version: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ requirements: []
83
+ rubygems_version: 3.0.3
84
+ signing_key:
85
+ specification_version: 4
86
+ summary: Inspect gems
87
+ test_files: []