Skip to content
This repository was archived by the owner on Nov 15, 2022. It is now read-only.

Latest commit

 

History

History
652 lines (494 loc) · 11 KB

File metadata and controls

652 lines (494 loc) · 11 KB

GitHub Fantasy League

  1. Create the project in .NET
  2. Create the project in Rails
  3. Create the feature in .NET
  4. Create the feature in Rails
  5. Implement steps in .NET
  6. Implement steps in Rails
  7. Spec User in .NET
  8. Spec User in Rails
  9. Spec GitHubScorer in .NET
  10. Spec GitHubScorer in Rails
  11. Implement GitHub API Wrapper in .NET
  12. Implement GitHub API Wrapper in Rails
  13. Implement VCR in Rails
  14. Implement Controller in .NET
  15. Implement Controller in Rails

Git

To remove the current working unstaged files:

git clean -df & git checkout -- .

.NET

Create the Project

  • Create a blank solution in Visual Studio 2010 (save in /SOURCE/ghfl)
  • Create a Visual Studio Web MVC project and add to solution and call it GitHubFantasyLeague
  • Remove jquery.ui, Microsoft Ajax, css/themes

Create the Feature

  • GoTo Tools -> Extension Manager (show that SpecFlow is installed)
  • Add a Class Library project called GitHubFantasyLeague.Specs
  • Open up Package Manager Console
  • Install-Package SpecFlow.NUnit -ProjectName GitHubFantasyLeague.Spec
  • Delete Class.cs
  • Add a Specflow feature file called DisplayTotalScore.feature
Feature: Display total score
  As a unauthorized user
  I should be able to view the total score for a Github user
  In order to compare Github users

  Scenario: Entering a valid Github username
    Given I have a valid Github username
    And I am on the home page
    When I enter the Github username
    Then I should see the total score
  • Add StepDefinitions folder to the project
  • Add Support folder to the project
  • Right-click on feature file and Generate steps for GitHubSteps (copy to clipboard)
  • Right-click on feature file and Generate steps for NavigationSteps (copy to clipboard)
  • Right-click on project and run tests

Implement the Steps

  • Created Engine
  • Added RestfulRouting

Spec User

  • Added project for GitHubFantasyLeague.Tests
  • Added NSpec
  • Added UserSpec
  • Added project for GitHubFantasyLeague.Models

To run the specs, you can use NSpecRunner

> NSpecRunner.exe GitHubFantasyLeague.Tests/bin/debug/GitHubFantasyLeague.Tests.dll

Spec GitHubScorer

  • Added GitHubScorer
  • Added GitHubScorerSpec
  • Updated code in User

Implement API Wrapper

  • Create GitHub class
  • Install RestSharp
  • Install NewtonSoft JSON parser

Implement Controller

  • Added Users routes
  • Added UsersController
  • Added new view

Rails

Create the Project

Since we already have a github-fantasy-league directory due to what we have already done, let's create a ghfl directory and then come back to it.

rails new github-fantasy-league2 --skip-bundle
cd github-fantasy-league2
rm public/index.html
rm app/assets/images/rails.png
l app

Create the Feature

# Gemfile

group :test do
  gem 'cucumber-rails'
  gem 'database_cleaner'
end
bundle install
rails g cucumber:install
# features/display_total_score.feature

Feature: Display total score
  As a unauthorized user
  I should be able to view the total score for a Github user
  In order to compare Github users

  Scenario: Entering a valid Github username
    Given I have a valid Github username
    And I am on the home page
    When I enter the Github username
    Then I should see the total score
be cucumber
# features/step_definitions/github_steps.rb
# place step 1, 3, and 4
# features/step_definitions/navigation_steps.rb
# place step 2

Implement the Steps

# features/step_definitions/github_steps.rb

Given(/^I have a valid GitHub username$/) do
  @username = 'tenderlove'
end

# features/step_definitions/navigation_steps.rb

Given(/^I am on the home page$/) do
  visit '/'
end
be cucumber
# config/routes.rb

root :to => 'home#index'
# app/controllers/home_controller.rb

class HomeController < ApplicationController
 def index
 end
end
# Gemfile

gem 'haml-rails'
# app/views/home/index.html.haml
# features/step_definitions/github_steps.rb

When(/^I enter the GitHub username$/) do
  fill_in 'Username', with: @username
  click_link 'Get scores'
end
# app/views/home/index.html.haml

.field
  %label{ for: 'username' } Username
  %input{ type: 'text', id: 'username', name: 'username'}
.actions
  %a{ href: '#', class: 'score-trigger' } Get scores
# features/step_definitions/github_steps.rb

Then(/^I should see the total score$/) do
  total_score = User.find(@username).calculate.total_score
  within '#total-score' do
    page.should have_content total_score
  end
end

Spec User

# Gemfile

group :test do
  gem 'rspec-rails'
end
bundle install
rails g rspec:install
# spec/models/user_spec.rb

require_relative '../../app/models/user'

describe User do
  describe '.find' do
    it 'should return a new instance'
  end

  describe '.calculate' do
    it 'should enable chaining'
    it 'should populate the total score'
  end
end
# app/models/user.rb

class User
end
# spec/models/user_spec.rb

describe '.find' do
  it 'should return a new instance' do
    User.find('wycats').username.should == 'wycats'
  end
end
# app/models/user.rb

class User
  attr_reader :username

  def self.find(username)
    User.new(username)
  end

  private

  def initialize(username)
    @username = username
  end
end
# spec/models/user_spec.rb

describe '.calculate' do
  subject { User.find('topfunky') }

  it 'should enable chaining' do
    subject.calculate.should be_a User
  end
end

# app/models/user.rb

class User
...
  def calculate
    self
  end
...
end
# spec/models/user_spec.rb

it 'should populate the total score' do
  subject.calculate.total_score.should_not be_nil
end

# app/models/user.rb

attr_reader :total_score

def calculate
  @total_score = 0
end

Spec GitHubScorer

cd ..
curl https://github.com/tenderlove.json > tenderlove.json
cat tenderlove.json | prettify_json.rb
# app/models/user.rb

def calculate
  @scorer = GithubScorer.new(data)
  @total_score = @scorer.score.total_score
  self
end
# spec/models/github_scorer_spec.rb

require_relative '../../app/models/github_scorer'

describe GithubScorer do
  describe '#score' do
    it 'should parse events'
    it 'should calculate the total score'
  end
end
# app/models/github_scorer.rb

class GithubScorer
end
require 'json'
require_relative '../../app/models/github_scorer'

describe GithubScorer do
  describe '#score' do
    let(:data) {
      JSON.parse('[
        {"type":"CommitCommentEvent"},
        {"type":"IssuesEvent"},
        {"type":"IssueCommentEvent"},
        {"type":"WatchEvent"},
        {"type":"PullRequestEvent"},
        {"type":"PushEvent"},
        {"type":"FollowEvent"},
        {"type":"CreateEvent"}
      ]')
    }

    subject { GithubScorer.new(data) }

    it 'should parse events' do
      subject.score.events.count.should == 8
    end

    it 'should calculate the total score'
  end
end
# app/models/github_scorer.rb

class GithubScorer
  attr_reader :events

  def initialize(data)
    @data = data
    parse
  end

  def score
    self
  end

  private

  def parse
    @events = []
    @data.each do |event|
      @events << event['type']
    end
  end
end
# spec/models/github_scorer_spec.rb

it 'should calculate the total score' do
  subject.score.total_score.should == 24
end
# app/models/github_scorer_spec.rb

class GithubScorer
  attr_reader :events, :total_score

  def initialize(data)
    @data = data
    @total_score = 0
    parse
  end

  def score
    @events.each do |event|
      @total_score += case event
        when 'CommitCommentEvent' then 2
        when 'IssueCommentEvent' then 2
        when 'IssuesEvent' then 3
        when 'WatchEvent' then 1
        when 'PullRequestEvent' then 5
        when 'PushEvent' then 7
        when 'FollowEvent' then 1
        when 'CreateEvent' then 3
        else 0
      end
    end

    self
  end

  private

  def parse
    @events = []
    @data.each do |event|
      @events << event['type']
    end
  end
end

Implement API Wrapper

# spec/models/user_spec.rb

require_relative '../../app/models/github_scorer'
# Gemfile

gem 'httparty'
# lib/github.rb

require github/event
mkdir lib/github
# lib/github/event.rb

require 'httparty'

module Github
  class Event
    include HTTParty
    base_uri 'https://github.com'

    def initialize(username)
      @username = username
    end

    def get
      self.class.get "/#{@username}.json"
    end
  end
end
# app/models/user.rb

require_relative '../../lib/github'

class User
  attr_reader :username, :total_score

  def self.find(username)
    User.new(username)
  end

  def calculate
    @total_score = scorer.total_score
    self
  end

  private

  def initialize(username)
    @username = username
  end

  def scorer
    unless @scorer
      data = Github::Event.new(@username).get
      @scorer = GithubScorer.new(data).score
    end
    @scorer
  end
end

Implement VCR

# Gemfile

group :development do
  gem 'fakeweb'
  gem 'vcr'
end
# spec/spec_helper.rb

require 'vcr'

RSpec.configure do |config|
...
  config.extend VCR::RSpec::Macros
end

VCR.configure do |c|
  c.cassette_library_dir = 'spec/cassettes'
  c.hook_into :fakeweb
  c.default_cassette_options = { :record => :new_episodes }
end
# spec/models/user_spec.rb

require 'spec_helper'

describe '.calculate' do
  use_vcr_cassette 'topfunky'
...
end

Implement Controller

# app/views/home/index.html.haml

= form_tag users_path do
...
  %button{ type: 'submit', class: 'score-trigger' } Get scores
# config/routes.rb

resources :users, only: :create
# features/step_definitions/github_steps.rb

...
click_button 'Get scores'
...
# app/controllers/users_controller

class UsersController < ApplicationController
  def create
    render :new
  end
end
mkdir app/views/users
# app/views/users/new.html.haml

#scores
  .total
    Total score:
    %span#total-score= @total_score
# app/controllers/users_controller.rb

@total_score = User.find(params[:username]).calculate.total_score