lib/how_is/analyzer.rb in how_is-8.0.0 vs lib/how_is/analyzer.rb in how_is-9.0.0
- old
+ new
@@ -1,170 +1,170 @@
-require 'contracts'
-require 'ostruct'
-require 'date'
-require 'json'
-
-module HowIs
- ##
- # Represents a completed analysis of the repository being analyzed.
- class Analysis < OpenStruct
- end
-
- class Analyzer
- include Contracts::Core
-
- class UnsupportedImportFormat < StandardError
- def initialize(format)
- super("Unsupported import format: #{format}")
- end
- end
-
- Contract Fetcher::Results, C::KeywordArgs[analysis_class: C::Optional[Class]] => Analysis
- def call(data, analysis_class: Analysis)
- issues = data.issues
- pulls = data.pulls
-
- analysis_class.new(
- issues_url: "https://github.com/#{data.repository}/issues",
- pulls_url: "https://github.com/#{data.repository}/pulls",
-
- repository: data.repository,
-
- number_of_issues: issues.length,
- number_of_pulls: pulls.length,
-
- issues_with_label: with_label_links(num_with_label(issues), data.repository),
- issues_with_no_label: {link: nil, total: num_with_no_label(issues)},
-
- average_issue_age: average_age_for(issues),
- average_pull_age: average_age_for(pulls),
-
- oldest_issue: issue_or_pull_to_hash(oldest_for(issues)),
- oldest_pull: issue_or_pull_to_hash(oldest_for(pulls)),
- )
- end
-
- def from_file(file)
- extension = file.split('.').last
- raise UnsupportedImportFormat, extension unless extension == 'json'
-
- hash = JSON.parse(open(file).read)
- hash = hash.map do |k, v|
- v = DateTime.parse(v) if k.end_with?('_date')
-
- [k, v]
- end.to_h
-
- %w[oldest_issue oldest_pull].each do |key|
- hash[key]['date'] = DateTime.parse(hash[key]['date'])
- end
-
- Analysis.new(hash)
- end
-
- # Given an Array of issues or pulls, return a Hash specifying how many
- # issues or pulls use each label.
- def num_with_label(issues_or_pulls)
- # Returned hash maps labels to frequency.
- # E.g., given 10 issues/pulls with label "label1" and 5 with label "label2",
- # {
- # "label1" => 10,
- # "label2" => 5
- # }
-
- hash = Hash.new(0)
- issues_or_pulls.each do |iop|
- next unless iop['labels']
-
- iop['labels'].each do |label|
- hash[label['name']] += 1
- end
- end
- hash
- end
-
- def num_with_no_label(issues)
- issues.select { |x| x['labels'].empty? }.length
- end
-
- def average_date_for(issues_or_pulls)
- timestamps = issues_or_pulls.map { |iop| Date.parse(iop['created_at']).strftime('%s').to_i }
- average_timestamp = timestamps.reduce(:+) / issues_or_pulls.length
-
- DateTime.strptime(average_timestamp.to_s, '%s')
- end
-
- # Given an Array of issues or pulls, return the average age of them.
- def average_age_for(issues_or_pulls)
- ages = issues_or_pulls.map {|iop| time_ago_in_seconds(iop['created_at'])}
- raw_average = ages.reduce(:+) / ages.length
-
- seconds_in_a_year = 31_556_926
- seconds_in_a_month = 2_629_743
- seconds_in_a_week = 604_800
- seconds_in_a_day = 86_400
-
- years = raw_average / seconds_in_a_year
- years_remainder = raw_average % seconds_in_a_year
-
- months = years_remainder / seconds_in_a_month
- months_remainder = years_remainder % seconds_in_a_month
-
- weeks = months_remainder / seconds_in_a_week
- weeks_remainder = months_remainder % seconds_in_a_week
-
- days = weeks_remainder / seconds_in_a_day
-
- values = [
- [years, "year"],
- [months, "month"],
- [weeks, "week"],
- [days, "day"],
- ].reject {|(v, k)| v == 0}.map{ |(v,k)|
- k = k + 's' if v != 1
- [v, k]
- }
-
- most_significant = values[0, 2].map {|x| x.join(" ")}
-
- if most_significant.length < 2
- value = most_significant.first
- else
- value = most_significant.join(" and ")
- end
-
- "approximately #{value}"
- end
-
- # Given an Array of issues or pulls, return the creation date of the oldest.
- def oldest_for(issues_or_pulls)
- issues_or_pulls.sort_by {|x| DateTime.parse(x['created_at']) }.first
- end
-
- def date_for(issue_or_pull)
- DateTime.parse(issue_or_pull['created_at'])
- end
-
- private
- def with_label_links(labels, repository)
- labels.map do |label, num_issues|
- label_link = "https://github.com/#{repository}/issues?q=" + CGI.escape("is:open is:issue label:\"#{label}\"")
-
- [label, {link: label_link, total: num_issues}]
- end.to_h
- end
-
- def time_ago_in_seconds(x)
- DateTime.now.strftime("%s").to_i - DateTime.parse(x).strftime("%s").to_i
- end
-
- def issue_or_pull_to_hash(iop)
- ret = {}
-
- ret[:html_url] = iop['html_url']
- ret[:number] = iop['number']
- ret[:date] = date_for(iop)
-
- ret
- end
- end
-end
+require 'contracts'
+require 'ostruct'
+require 'date'
+require 'json'
+
+module HowIs
+ ##
+ # Represents a completed analysis of the repository being analyzed.
+ class Analysis < OpenStruct
+ end
+
+ class Analyzer
+ include Contracts::Core
+
+ class UnsupportedImportFormat < StandardError
+ def initialize(format)
+ super("Unsupported import format: #{format}")
+ end
+ end
+
+ Contract Fetcher::Results, C::KeywordArgs[analysis_class: C::Optional[Class]] => Analysis
+ def call(data, analysis_class: Analysis)
+ issues = data.issues
+ pulls = data.pulls
+
+ analysis_class.new(
+ issues_url: "https://github.com/#{data.repository}/issues",
+ pulls_url: "https://github.com/#{data.repository}/pulls",
+
+ repository: data.repository,
+
+ number_of_issues: issues.length,
+ number_of_pulls: pulls.length,
+
+ issues_with_label: with_label_links(num_with_label(issues), data.repository),
+ issues_with_no_label: {'link' => nil, 'total' => num_with_no_label(issues)},
+
+ average_issue_age: average_age_for(issues),
+ average_pull_age: average_age_for(pulls),
+
+ oldest_issue: issue_or_pull_to_hash(oldest_for(issues)),
+ oldest_pull: issue_or_pull_to_hash(oldest_for(pulls)),
+ )
+ end
+
+ def from_file(file)
+ extension = file.split('.').last
+ raise UnsupportedImportFormat, extension unless extension == 'json'
+
+ hash = JSON.parse(open(file).read)
+ hash = hash.map do |k, v|
+ v = DateTime.parse(v) if k.end_with?('_date')
+
+ [k, v]
+ end.to_h
+
+ %w[oldest_issue oldest_pull].each do |key|
+ hash[key]['date'] = DateTime.parse(hash[key]['date'])
+ end
+
+ Analysis.new(hash)
+ end
+
+ # Given an Array of issues or pulls, return a Hash specifying how many
+ # issues or pulls use each label.
+ def num_with_label(issues_or_pulls)
+ # Returned hash maps labels to frequency.
+ # E.g., given 10 issues/pulls with label "label1" and 5 with label "label2",
+ # {
+ # "label1" => 10,
+ # "label2" => 5
+ # }
+
+ hash = Hash.new(0)
+ issues_or_pulls.each do |iop|
+ next unless iop['labels']
+
+ iop['labels'].each do |label|
+ hash[label['name']] += 1
+ end
+ end
+ hash
+ end
+
+ def num_with_no_label(issues)
+ issues.select { |x| x['labels'].empty? }.length
+ end
+
+ def average_date_for(issues_or_pulls)
+ timestamps = issues_or_pulls.map { |iop| Date.parse(iop['created_at']).strftime('%s').to_i }
+ average_timestamp = timestamps.reduce(:+) / issues_or_pulls.length
+
+ DateTime.strptime(average_timestamp.to_s, '%s')
+ end
+
+ # Given an Array of issues or pulls, return the average age of them.
+ def average_age_for(issues_or_pulls)
+ ages = issues_or_pulls.map {|iop| time_ago_in_seconds(iop['created_at'])}
+ raw_average = ages.reduce(:+) / ages.length
+
+ seconds_in_a_year = 31_556_926
+ seconds_in_a_month = 2_629_743
+ seconds_in_a_week = 604_800
+ seconds_in_a_day = 86_400
+
+ years = raw_average / seconds_in_a_year
+ years_remainder = raw_average % seconds_in_a_year
+
+ months = years_remainder / seconds_in_a_month
+ months_remainder = years_remainder % seconds_in_a_month
+
+ weeks = months_remainder / seconds_in_a_week
+ weeks_remainder = months_remainder % seconds_in_a_week
+
+ days = weeks_remainder / seconds_in_a_day
+
+ values = [
+ [years, "year"],
+ [months, "month"],
+ [weeks, "week"],
+ [days, "day"],
+ ].reject {|(v, k)| v == 0}.map{ |(v,k)|
+ k = k + 's' if v != 1
+ [v, k]
+ }
+
+ most_significant = values[0, 2].map {|x| x.join(" ")}
+
+ if most_significant.length < 2
+ value = most_significant.first
+ else
+ value = most_significant.join(" and ")
+ end
+
+ "approximately #{value}"
+ end
+
+ # Given an Array of issues or pulls, return the creation date of the oldest.
+ def oldest_for(issues_or_pulls)
+ issues_or_pulls.sort_by {|x| DateTime.parse(x['created_at']) }.first
+ end
+
+ def date_for(issue_or_pull)
+ DateTime.parse(issue_or_pull['created_at'])
+ end
+
+ private
+ def with_label_links(labels, repository)
+ labels.map do |label, num_issues|
+ label_link = "https://github.com/#{repository}/issues?q=" + CGI.escape("is:open is:issue label:\"#{label}\"")
+
+ [label, {'link' => label_link, 'total' => num_issues}]
+ end.to_h
+ end
+
+ def time_ago_in_seconds(x)
+ DateTime.now.strftime("%s").to_i - DateTime.parse(x).strftime("%s").to_i
+ end
+
+ def issue_or_pull_to_hash(iop)
+ ret = {}
+
+ ret['html_url'] = iop['html_url']
+ ret['number'] = iop['number']
+ ret['date'] = date_for(iop)
+
+ ret
+ end
+ end
+end