diff options
| -rw-r--r-- | .rspec | 1 | ||||
| -rwxr-xr-x | bin/test | 5 | ||||
| -rw-r--r-- | github_score.rb | 88 | ||||
| -rw-r--r-- | lib/shogun.rb | 5 | ||||
| -rw-r--r-- | lib/shogun/github_score.rb | 51 | ||||
| -rw-r--r-- | spec/shogun/github_score_spec.rb | 31 | ||||
| -rw-r--r-- | spec/spec_helper.rb | 23 |
7 files changed, 116 insertions, 88 deletions
@@ -0,0 +1 @@ +--require spec_helper diff --git a/bin/test b/bin/test new file mode 100755 index 0000000..3824d26 --- /dev/null +++ b/bin/test @@ -0,0 +1,5 @@ +#!/bin/sh + +cd "$(dirname $0)/.." + +bundle exec rspec diff --git a/github_score.rb b/github_score.rb deleted file mode 100644 index 23e8238..0000000 --- a/github_score.rb +++ /dev/null @@ -1,88 +0,0 @@ -#!/usr/bin/env ruby - -require 'net/http' -require 'uri' -require 'json' -require 'rspec/autorun' -require 'webmock/rspec' - -class UserNotFound < ArgumentError -end - -class GithubScore - DEFAULT_POINTS = { - "IssuesEvent" => 1, - "IssueCommentEvent" => 2, - "PushEvent" => 3, - "PullRequestReviewCommentEvent" => 4, - "WatchEvent" => 5, - "CreateEvent" => 6 - }.freeze - - def initialize(handle, points: DEFAULT_POINTS) - @handle = handle - @points = points - end - - def score - calculate_score_for(events) - end - - private - - attr_reader :points, :handle - - def build_url - "https://api.github.com/users/#{handle}/events/public" - end - - def events - response = Net::HTTP.get_response(URI.parse(build_url)) - raise UserNotFound.new(handle) if response.code == "404" - - JSON.parse(response.body) - end - - def calculate_score_for(events) - grouped = events.group_by { |h| h["type"] }.values - score = grouped.map { |g| - event_type = g.first["type"].strip - event_score = points[event_type] || 1 - event_score * g.count - }.sum - score - end -end - - -RSpec.describe GithubScore do - describe "#score" do - subject(:github_score) { GithubScore.new(handle) } - let(:handle) { "tenderlove" } - - context "when calculating the score for a known user" do - let(:events) { [{type: 'PushEvent'}, {type: 'IssuesEvent'}] } - - before do - stub_request(:get, "https://api.github.com/users/#{handle}/events/public") - .to_return(status: 200, body: events.to_json) - end - - it { expect(github_score.score).to eq(4) } - end - - context "when attempting to retrive the score for an unknown user" do - before do - stub_request(:get, "https://api.github.com/users/#{handle}/events/public") - .to_return(status: 404, body: { - "message": "Not Found", - "documentation_url": "https://docs.github.com/rest/reference/activity#list-public-events-for-a-user" - }.to_json) - end - - it { expect { github_score.score }.to raise_error(UserNotFound) } - end - - # it times out - end -end diff --git a/lib/shogun.rb b/lib/shogun.rb new file mode 100644 index 0000000..818e0a5 --- /dev/null +++ b/lib/shogun.rb @@ -0,0 +1,5 @@ +require "net/http" +require "uri" +require "json" + +require "shogun/github_score" diff --git a/lib/shogun/github_score.rb b/lib/shogun/github_score.rb new file mode 100644 index 0000000..48947a0 --- /dev/null +++ b/lib/shogun/github_score.rb @@ -0,0 +1,51 @@ +module Shogun + class UserNotFound < ArgumentError + end + + class GithubScore + DEFAULT_POINTS = { + "IssuesEvent" => 1, + "IssueCommentEvent" => 2, + "PushEvent" => 3, + "PullRequestReviewCommentEvent" => 4, + "WatchEvent" => 5, + "CreateEvent" => 6 + }.freeze + + def initialize(handle, points: DEFAULT_POINTS) + @handle = handle + @points = points + end + + def score + calculate_score_for(events) + end + + private + + attr_reader :points, :handle + + def build_url + "https://api.github.com/users/#{handle}/events/public" + end + + def events + response = Net::HTTP.get_response(URI.parse(build_url)) + raise UserNotFound.new(handle) if response.code == "404" + + JSON.parse(response.body) + end + + def calculate_score_for(events) + grouped = events.group_by { |h| h["type"] }.values + score = grouped.map { |g| + event_type = g.first["type"].strip + event_score = points[event_type] || 1 + event_score * g.count + }.sum + score + end + end + + +end diff --git a/spec/shogun/github_score_spec.rb b/spec/shogun/github_score_spec.rb new file mode 100644 index 0000000..60deb11 --- /dev/null +++ b/spec/shogun/github_score_spec.rb @@ -0,0 +1,31 @@ +RSpec.describe Shogun::GithubScore do + describe "#score" do + subject(:github_score) { described_class.new(handle) } + let(:handle) { "tenderlove" } + + context "when calculating the score for a known user" do + let(:events) { [{type: 'PushEvent'}, {type: 'IssuesEvent'}] } + + before do + stub_request(:get, "https://api.github.com/users/#{handle}/events/public") + .to_return(status: 200, body: events.to_json) + end + + it { expect(github_score.score).to eq(4) } + end + + context "when attempting to retrive the score for an unknown user" do + before do + stub_request(:get, "https://api.github.com/users/#{handle}/events/public") + .to_return(status: 404, body: { + "message": "Not Found", + "documentation_url": "https://docs.github.com/rest/reference/activity#list-public-events-for-a-user" + }.to_json) + end + + it { expect { github_score.score }.to raise_error(Shogun::UserNotFound) } + end + + # it times out + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb new file mode 100644 index 0000000..bfb24e2 --- /dev/null +++ b/spec/spec_helper.rb @@ -0,0 +1,23 @@ +require "webmock/rspec" +require "shogun" + +RSpec.configure do |config| + config.expect_with :rspec do |expectations| + expectations.include_chain_clauses_in_custom_matcher_descriptions = true + end + config.mock_with :rspec do |mocks| + mocks.verify_partial_doubles = true + end + + # This option will default to `:apply_to_host_groups` in RSpec 4 (and will + # have no way to turn it off -- the option exists only for backwards + # compatibility in RSpec 3). It causes shared context metadata to be + # inherited by the metadata hash of host groups and examples, rather than + # triggering implicit auto-inclusion in groups with matching metadata. + config.shared_context_metadata_behavior = :apply_to_host_groups + config.filter_run_when_matching :focus + config.disable_monkey_patching! + config.warnings = true + config.order = :random + Kernel.srand config.seed +end |
