Skip to content

Instantly share code, notes, and snippets.

@bestwebua
Last active April 6, 2018 13:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bestwebua/6c4cf4a92bb605119a4f47be325d2f62 to your computer and use it in GitHub Desktop.
Save bestwebua/6c4cf4a92bb605119a4f47be325d2f62 to your computer and use it in GitHub Desktop.
Scraping kata
require 'nokogiri'
require 'open-uri'
class User
attr_reader :name, :clan, :honor
def initialize(name, clan, honor)
@name, @clan, @honor = name, clan, honor
end
end
class Leaderboard
@@leaderboard = []
def self.position
url = 'https://www.codewars.com/users/leaderboard'
page = Nokogiri::HTML(open(url), nil, Encoding::UTF_8.to_s)
rows = page.css("[class='leaderboard pan'] > table > tr")
rows.each do |row|
name, clan, honor = row.css('a').text, row.css('td[3]').text, row.css('td[4]').text.to_i
@@leaderboard << User.new(name, clan, honor)
end
@@leaderboard
end
end
def solution
Leaderboard.position
end
@10XL
Copy link

10XL commented Apr 4, 2018

The it blocks are causing the outputs to not be shown correctly, could you use this in the example test fixture instead. I've just replaced the it blocks with describes.

leaderboard = solution

  describe "should have a size of 500" do
    Test.assert_equals(leaderboard.position.size, 500 )
  end
  describe "should contain the correct names" do
  # since these are hard coded, you should substitute with the current top 5
    Test.assert_equals(leaderboard.position[1].name, 'g964')
    Test.assert_equals(leaderboard.position[2].name, 'myjinxin2015')
    Test.assert_equals(leaderboard.position[3].name, 'Voile')
    Test.assert_equals(leaderboard.position[4].name, 'SteffenVogel_79')
    Test.assert_equals(leaderboard.position[5].name, 'smile67')
  end
  describe "should contain the correct clan" do
  # since these are hard coded, you should substitute with the current top 5
    Test.assert_equals(leaderboard.position[1].clan, 'None')
    Test.assert_equals(leaderboard.position[2].clan, '中国 长垣')
    Test.assert_equals(leaderboard.position[3].clan, 'Gensokyo')
    Test.assert_equals(leaderboard.position[4].clan, 'CSV - SLayer')
    Test.assert_equals(leaderboard.position[5].clan, 'PropertyExpert, Germany')
  end
  describe "should contain the correct honor" do
  # since these are hard coded, you should substitute with the current top 5
    Test.assert_equals(leaderboard.position[1].honor > 110000, true)
    Test.assert_equals(leaderboard.position[2].honor > 110000, true)
    Test.assert_equals(leaderboard.position[3].honor > 60000, true)
    Test.assert_equals(leaderboard.position[4].honor > 55000, true)
    Test.assert_equals(leaderboard.position[5].honor > 50000, true)
  end

@bestwebua
Copy link
Author

Solution

require 'nokogiri'
require 'open-uri'

class User

  attr_reader :name, :clan, :honor

  def initialize(name, clan, honor)
    @name, @clan, @honor = name, clan, honor
  end

end

class LeaderboardArray < Array
  def size
    length-1
  end
end

class Leaderboard

  @@leaderboard = LeaderboardArray.new

  def self.position
    url = 'https://www.codewars.com/users/leaderboard'
    page = Nokogiri::HTML(open(url), nil, Encoding::UTF_8.to_s)
    rows = page.css("[class='leaderboard pan'] > table > tr")
      rows.each do |row|
        name, clan, honor = row.css('a').text, row.css('td[3]').text, row.css('td[4]').text.to_i
        @@leaderboard << User.new(name, clan, honor)
      end
    @@leaderboard
  end

end

def solution
  Leaderboard
end

Test-cases

leaderboard = solution

  describe "should have a size of 500" do
    Test.assert_equals(leaderboard.position.size, 500 )
  end
  describe "should contain the correct names" do
    Test.assert_equals(leaderboard.position[1].name, 'g964')
    Test.assert_equals(leaderboard.position[2].name, 'myjinxin2015')
    Test.assert_equals(leaderboard.position[3].name, 'Voile')
    Test.assert_equals(leaderboard.position[4].name, 'SteffenVogel_79')
    Test.assert_equals(leaderboard.position[5].name, 'smile67')
  end
  describe "should contain the correct clan" do
    Test.assert_equals(leaderboard.position[1].clan, 'None')
    Test.assert_equals(leaderboard.position[2].clan, '中国 长垣')
    Test.assert_equals(leaderboard.position[3].clan, 'Gensokyo')
    Test.assert_equals(leaderboard.position[4].clan, 'CSV - SLayer')
    Test.assert_equals(leaderboard.position[5].clan, 'PropertyExpert, Germany')
  end
  describe "should contain the correct honor" do
    Test.assert_equals(leaderboard.position[1].honor > 110000, true)
    Test.assert_equals(leaderboard.position[2].honor > 110000, true)
    Test.assert_equals(leaderboard.position[3].honor > 60000, true)
    Test.assert_equals(leaderboard.position[4].honor > 55000, true)
    Test.assert_equals(leaderboard.position[5].honor > 50000, true)
  end

@10XL
Copy link

10XL commented Apr 5, 2018

@bestwebua
The tests use Nokogiri's default encoding("ASCII-8bit").
Change
page = Nokogiri::HTML(open(url), nil, Encoding::UTF_8.to_s)
to
page = Nokogiri::HTML(open(url))

@bestwebua
Copy link
Author

@10XL my new code with struct instead class. It has passed all tests.

require 'nokogiri'
require 'open-uri'

class LeaderboardArray < Array
  def size
    length-1
  end
end

class Leaderboard
  def self.build
    Struct.new('Warrior', :name, :clan, :honor)
    @@leaderboard = LeaderboardArray.new

      url = 'https://www.codewars.com/users/leaderboard'
      page = Nokogiri::HTML(open(url))
      rows = page.css("[class='leaderboard pan'] > table > tr")

        rows.each do |row|
          name, clan, honor = row.css('a').text, row.css('td[3]').text, row.css('td[4]').text.to_i
          @@leaderboard << Struct::Warrior.new(name, clan, honor)
        end

    @@leaderboard
  end

  def self.position
    @@leaderboard ||= self.build
  end
end

def solution
  Leaderboard
end

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment