codebadges 2.0.1 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 54242705f83a6dadf672c4fe0ce820f3006dbe7b
4
- data.tar.gz: 29dfc653ddb4432b5c53013fa0f93fa5aa59ad8f
3
+ metadata.gz: c0cc98b2e33fbeaa97d3d051504dd02780de3003
4
+ data.tar.gz: 585b3efee9ca4c07d320c5628caba2374cdd5611
5
5
  SHA512:
6
- metadata.gz: 69193d21274ae16b60a5db2b3588f0077d75ee38bbfba8f7bc03c6f0e1175286c62944720fd99cb72e663d9cbadb71fa05a3e907e140f5595c99ec6b3e18b95a
7
- data.tar.gz: 7af7e76a996ad85af191b66690adc751c449c9b71bad7229a1c1bfc1763995d844dea80e23126598ae83fbb8f58d768dd7e1bcc7a5b1fd1cdd78378cfe32acc5
6
+ metadata.gz: 3e4e3b8c75dabcf07f503dc0c8662739af9ae37156913da8447d79271ca8a7b43fdc744af3e68bb76cc99cbf9b32d3ad91cb86a904a7fbed651075367012c84d
7
+ data.tar.gz: 9b8f8910a88f9a41889b753c9596a6ddc5f7173e245af68ce312d08255a0ada72a09fc8649178d0415476e53f78c389da067c09e9e9d51056957a569874b997c
@@ -1,8 +1,12 @@
1
1
  language: ruby
2
2
  rvm:
3
- - ruby-head
4
- - jruby-head
3
+ - 2.2.5
4
+ - 2.3.1
5
5
  branches:
6
6
  only:
7
7
  - master
8
8
  - develop
9
+ before_install:
10
+ - "export DISPLAY=:99.0"
11
+ - "sh -e /etc/init.d/xvfb start"
12
+ - sleep 3 # give xvfb some time to start
data/README.md CHANGED
@@ -1,12 +1,13 @@
1
1
  # CodeBadges [![Gem Version](https://badge.fury.io/rb/codebadges.svg)](https://badge.fury.io/rb/codebadges)[![Build Status](https://travis-ci.org/ISS-SOA/Codecademy-Ruby.svg?branch=develop)](https://travis-ci.org/ISS-SOA/Codecademy-Ruby)
2
2
 
3
3
  Codecademy is a great place to learn coding! Unfortunately, Codecademy's website
4
- doesn't provide an API to help us monitor our own coding.
4
+ doesn't provide an API.
5
+
5
6
  So we made the CodeBadges gem to scrape user achievements from Codecademy!
6
7
 
7
8
  Note that we respect Codecademy's `robots.txt`
8
9
 
9
- ## Usage
10
+ ## Installation
10
11
 
11
12
  Install it with the following command:
12
13
  ```sh
@@ -17,15 +18,43 @@ Or else put it in your `Gemfile` as:
17
18
  ```ruby
18
19
  gem codebadges
19
20
  ```
21
+ and run `bundle install`.
22
+
23
+ ## Usage
20
24
 
25
+ ### CLI: Finding user badges
21
26
  Run it from the command line. For example, to get the achievements of user `chenlizhan`:
22
27
  ```
23
28
  $ codebadges chenlizhan
24
29
  ```
25
30
 
26
- Or use it from your Ruby code:
31
+ You will be required to enter username/password credentials to access codecademy user achievements.
32
+ This gem *never* stores your credentials nor uses them for any other purpose.
33
+ ### Code: Finding user badges
34
+ Use it from your Ruby code:
27
35
  ````ruby
28
36
  require 'codebadges'
29
- lee = CodeBadges::CodecademyBadges.new('chenlizhan')
30
- badges = lee.badges
37
+
38
+ cademy_badges = CodeBadges::GetCodecademyBadges.new('my_username', 'my_password')
39
+ badges = cademy_badges.call('chenlizhan')
31
40
  ````
41
+
42
+ ### Code: Finding full course list
43
+ Use it from your Ruby code:
44
+ ```ruby
45
+ courses = CodeBadges::GetCodecademyCourses.call
46
+ ```
47
+
48
+ ## Testing
49
+
50
+ First, setup environment variables called `CC_USERNAME` and `CC_PASSWORD` with your Codecademy username and password.
51
+
52
+ Then:
53
+ ```
54
+ rake spec
55
+ ```
56
+
57
+ Alternatively:
58
+ ```
59
+ CC_USERNAME=myusername CC_PASSWORD=mypassword rake spec
60
+ ```
@@ -1,14 +1,22 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require 'codebadges' # for production
4
- # require '../lib/codebadges/badges.rb' # for cmd line testing purposes
3
+ require 'io/console'
4
+ require 'codebadges' # for production
5
+ # require '../lib/codebadges/badges.rb' # for cmd line testing purposes
5
6
 
6
- fail ArgumentError, "Usage: codebadges [username]\n" if ARGV.count == 0
7
+ abort "Usage: codebadges [username]\n" if ARGV.count == 0
7
8
 
8
- username = ARGV[0]
9
- badges_found = CodeBadges::CodecademyBadges.new(username).badges
9
+ print 'Login Username: '
10
+ username = STDIN.gets.chomp
10
11
 
11
- puts "#{username} has collected #{badges_found.size} badges."
12
+ print 'Login Password: '
13
+ password = STDIN.noecho(&:gets).chomp
14
+
15
+ cadet_name = ARGV[0]
16
+ cademy = CodeBadges::GetCodecademyBadges.new(username, password)
17
+ badges_found = cademy.call(cadet_name)
18
+
19
+ puts "#{cadet_name} has collected #{badges_found.size} badges."
12
20
  badges_found.each do |title, date|
13
21
  puts "Earned '#{title}' on #{date}."
14
22
  end
@@ -7,17 +7,15 @@ Gem::Specification.new do |s|
7
7
  s.date = CodeBadges::DATE
8
8
  s.executables << 'codebadges'
9
9
  s.summary = 'Access user and course information on Codecademy'
10
- s.description = 'Get user achievements and course info from Codecademy'
11
- s.authors = ['Lee Chen', 'Soumya Ray']
12
- s.email = ['chung1350@hotmail.com', 'soumya.ray@gmail.com']
10
+ s.description = 'Get user user achievements and course lists from Codecademy'
11
+ s.authors = ['Soumya Ray', 'Lee Chen']
12
+ s.email = ['soumya.ray@gmail.com', 'chung1350@hotmail.com']
13
13
  s.files = `git ls-files`.split("\n")
14
14
  s.test_files = `git ls-files spec/*`.split("\n")
15
15
  s.homepage = 'https://github.com/ISS-SOA/Codecademy-Ruby'
16
16
  s.license = 'MIT'
17
17
 
18
- s.add_development_dependency 'minitest'
19
- s.add_development_dependency 'minitest-rg'
20
- s.add_development_dependency 'vcr'
21
- s.add_development_dependency 'webmock'
22
- s.add_runtime_dependency 'oga'
18
+ s.add_development_dependency 'minitest', '~> 5.9'
19
+ s.add_development_dependency 'minitest-rg', '~> 5.2'
20
+ s.add_runtime_dependency 'mechanize', '~> 2.7'
23
21
  end
@@ -1,2 +1,3 @@
1
+ require 'codebadges/site.rb'
1
2
  require 'codebadges/badges.rb'
2
3
  require 'codebadges/courses.rb'
@@ -1,38 +1,23 @@
1
- require 'oga'
2
- require 'open-uri'
3
- require 'date'
1
+ require_relative 'site'
4
2
 
5
3
  module CodeBadges
6
- # This class get the user account as an input
7
- # return a hash of user's badges information
8
- class CodecademyBadges
9
- USERS_URL = 'https://www.codecademy.com/users'
10
- ACHIEVEMENTS_DIR = 'achievements'
11
- ACHIEVEMENT_XPATH = "//div[contains(@class,'achievement-card')]"
12
- ACH_TITLE_XPATH = 'h5'
13
- ACH_DATE_XPATH = 'small/small'
14
-
15
- def initialize(username)
16
- parse_html(username)
17
- end
18
-
19
- def badges
20
- @badges ||= extract_achievements
4
+ # Service object class that takes credentials and username
5
+ # returns a hash of user's badges information
6
+ class GetCodecademyBadges
7
+ def initialize(username, password)
8
+ @username = username
9
+ @password = password
21
10
  end
22
11
 
23
- private
24
-
25
- def parse_html(username)
26
- url = "#{USERS_URL}/#{username}/#{ACHIEVEMENTS_DIR}"
27
- @document = Oga.parse_html(open(url))
28
- end
12
+ def call(cadet)
13
+ CademySite.new do |site|
14
+ site.goto CademySite::LOGIN_URL
15
+ site.login(@username, @password)
16
+ site.goto CademySite.cadet_achievements_url(cadet)
17
+ @badges = site.extract_achievements
18
+ end
29
19
 
30
- def extract_achievements
31
- @document.xpath(ACHIEVEMENT_XPATH).map do |achievement|
32
- title = achievement.xpath(ACH_TITLE_XPATH).text
33
- date = Date.parse(achievement.xpath(ACH_DATE_XPATH).text)
34
- [title, date]
35
- end.to_h
20
+ @badges
36
21
  end
37
22
  end
38
23
  end
@@ -1,25 +1,15 @@
1
- require 'oga'
2
- require 'open-uri'
3
- require 'date'
1
+ require_relative 'site'
4
2
 
5
3
  module CodeBadges
6
- # This class get the user account as an input
7
- # return a hash of user's badges information
8
- class CodecademyCourses
9
- MAIN_URL = 'https://www.codecademy.com'
10
- XPATH_COURSES = "//div[h5/strong/text()='Learn To Code']/div/div/ul/li/a"
11
-
12
- def courses
13
- @courses ||= extract_main_courses
14
- end
15
-
16
- private
17
-
18
- def extract_main_courses
19
- doc = Oga.parse_html(open(MAIN_URL))
20
- doc.xpath(XPATH_COURSES).map do |course|
21
- [course.text, URI.join(MAIN_URL, course.get('href'))]
22
- end.to_h
4
+ # Service object class that returns all courses
5
+ class GetCodecademyCourses
6
+ def self.call
7
+ CademySite.new do |site|
8
+ site.goto CademySite::MAIN_URL
9
+ @courses = site.extract_main_courses
10
+ end
11
+
12
+ @courses
23
13
  end
24
14
  end
25
15
  end
@@ -0,0 +1,60 @@
1
+ require 'mechanize'
2
+ require 'date'
3
+
4
+ module CodeBadges
5
+ ## CodeCademy web automation and scraper
6
+ class CademySite
7
+ MAIN_URL = 'https://www.codecademy.com'.freeze
8
+ USERS_URL = "#{MAIN_URL}/users".freeze
9
+ ACHIEVEMENTS_DIR = 'achievements'.freeze
10
+
11
+ LOGIN_URL = "#{MAIN_URL}/login".freeze
12
+ USERNAME_TEXTFIELD_ID = 'user_login'.freeze
13
+ PASSWORD_TEXTFIELD_ID = 'user_password'.freeze
14
+ LOGIN_BUTTON_ID = 'user_submit'.freeze
15
+
16
+ ACHIEVEMENT_XPATH = "//div[contains(@class,'achievement-card')]".freeze
17
+ ACH_TITLE_XPATH = 'h5'.freeze
18
+ ACH_DATE_XPATH = 'small/small'.freeze
19
+
20
+ COURSES_XPATH = "//div[h5/strong/text()='Learn To Code']/div/div/ul/li/a".freeze
21
+
22
+ def initialize
23
+ @browser = Mechanize.new do |agent|
24
+ agent.user_agent_alias = 'Linux Firefox'
25
+ end
26
+
27
+ yield self if block_given?
28
+ end
29
+
30
+ def self.cadet_achievements_url(cadet)
31
+ "#{USERS_URL}/#{cadet}/#{ACHIEVEMENTS_DIR}"
32
+ end
33
+
34
+ def goto(url)
35
+ @browser.get(url)
36
+ end
37
+
38
+ def login(username, password)
39
+ @browser.page.form do |form|
40
+ form.field(id: USERNAME_TEXTFIELD_ID).value = username
41
+ form.field(id: PASSWORD_TEXTFIELD_ID).value = password
42
+ form.submit
43
+ end
44
+ end
45
+
46
+ def extract_achievements
47
+ @browser.page.xpath(ACHIEVEMENT_XPATH).map do |achievement|
48
+ title = achievement.xpath(ACH_TITLE_XPATH).text
49
+ date = Date.parse(achievement.xpath(ACH_DATE_XPATH).text)
50
+ [title, date]
51
+ end.to_h
52
+ end
53
+
54
+ def extract_main_courses
55
+ @browser.page.xpath(COURSES_XPATH).map do |course|
56
+ [course.text, URI.join(MAIN_URL, course.attribute('href').value)]
57
+ end.to_h
58
+ end
59
+ end
60
+ end
@@ -1,5 +1,5 @@
1
1
  # Versioning
2
2
  module CodeBadges
3
- VERSION = '2.0.1'
4
- DATE = '2015-10-11'
3
+ VERSION = '3.0.0'
4
+ DATE = '2016-07-10'
5
5
  end
@@ -1,30 +1,22 @@
1
1
  require 'minitest/autorun'
2
2
  require 'minitest/rg'
3
3
  require 'yaml'
4
- require 'vcr'
5
- require 'webmock/minitest'
6
- require './lib/codebadges.rb'
4
+ require './lib/codebadges/badges.rb'
7
5
 
8
- USERNAME = 'soumya.ray'
6
+ USERNAME = 'soumya.ray'.freeze
9
7
  badges_from_file = YAML.load(File.read('./spec/fixtures/badges.yml'))
10
8
 
11
- VCR.configure do |config|
12
- config.cassette_library_dir = 'spec/fixtures/vcr_cassettes'
13
- config.hook_into :webmock
14
- end
15
-
16
- VCR.use_cassette('badges') do
17
- badges_found = CodeBadges::CodecademyBadges.new(USERNAME).badges
9
+ describe 'Get badges for one cadet' do
10
+ cademy = CodeBadges::GetCodecademyBadges.new(ENV['CC_USERNAME'], ENV['CC_PASSWORD'])
11
+ badges_found = cademy.call('soumya.ray')
18
12
 
19
- describe 'Get badges for one user' do
20
- it 'has the right number of badges' do
21
- badges_found.size.wont_be :<, badges_from_file[USERNAME].size
22
- end
13
+ it 'has the right number of badges' do
14
+ badges_found.size.wont_be :<, badges_from_file[USERNAME].size
15
+ end
23
16
 
24
- badges_from_file[USERNAME].map do |b_name, b_date|
25
- it "finds '#{b_name}' badge" do
26
- badges_found[b_name].must_equal Date.parse(b_date)
27
- end
17
+ badges_from_file[USERNAME].map do |b_name, b_date|
18
+ it "finds '#{b_name}' badge" do
19
+ badges_found[b_name].must_equal Date.parse(b_date)
28
20
  end
29
21
  end
30
22
  end
@@ -1,30 +1,20 @@
1
1
  require 'minitest/autorun'
2
2
  require 'minitest/rg'
3
3
  require 'yaml'
4
- require 'vcr'
5
- require 'webmock/minitest'
6
4
  require './lib/codebadges.rb'
7
5
 
8
6
  test_courses = YAML.load(File.read('spec/fixtures/courses.yml'))
9
7
 
10
- VCR.configure do |config|
11
- config.cassette_library_dir = 'spec/fixtures/vcr_cassettes'
12
- config.hook_into :webmock
13
- end
14
-
15
- VCR.use_cassette('courses') do
16
- codecademy = CodeBadges::CodecademyCourses.new
17
- courses = codecademy.courses
8
+ courses = CodeBadges::GetCodecademyCourses.call
18
9
 
19
- describe 'Find all test courses' do
20
- it 'has the right number of badges' do
21
- courses.size.wont_be :<, test_courses.size
22
- end
10
+ describe 'Find all test courses' do
11
+ it 'has the right number of badges' do
12
+ courses.size.wont_be :<, test_courses.size
13
+ end
23
14
 
24
- test_courses.map do |course_name|
25
- it "finds course '#{course_name}'" do
26
- codecademy.courses.keys.include? course_name
27
- end
15
+ test_courses.map do |course_name|
16
+ it "finds course '#{course_name}'" do
17
+ courses.keys.include? course_name
28
18
  end
29
19
  end
30
20
  end
metadata CHANGED
@@ -1,90 +1,62 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: codebadges
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.1
4
+ version: 3.0.0
5
5
  platform: ruby
6
6
  authors:
7
- - Lee Chen
8
7
  - Soumya Ray
8
+ - Lee Chen
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-10-11 00:00:00.000000000 Z
12
+ date: 2016-07-10 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: minitest
16
16
  requirement: !ruby/object:Gem::Requirement
17
17
  requirements:
18
- - - ">="
18
+ - - "~>"
19
19
  - !ruby/object:Gem::Version
20
- version: '0'
20
+ version: '5.9'
21
21
  type: :development
22
22
  prerelease: false
23
23
  version_requirements: !ruby/object:Gem::Requirement
24
24
  requirements:
25
- - - ">="
25
+ - - "~>"
26
26
  - !ruby/object:Gem::Version
27
- version: '0'
27
+ version: '5.9'
28
28
  - !ruby/object:Gem::Dependency
29
29
  name: minitest-rg
30
30
  requirement: !ruby/object:Gem::Requirement
31
31
  requirements:
32
- - - ">="
33
- - !ruby/object:Gem::Version
34
- version: '0'
35
- type: :development
36
- prerelease: false
37
- version_requirements: !ruby/object:Gem::Requirement
38
- requirements:
39
- - - ">="
40
- - !ruby/object:Gem::Version
41
- version: '0'
42
- - !ruby/object:Gem::Dependency
43
- name: vcr
44
- requirement: !ruby/object:Gem::Requirement
45
- requirements:
46
- - - ">="
32
+ - - "~>"
47
33
  - !ruby/object:Gem::Version
48
- version: '0'
34
+ version: '5.2'
49
35
  type: :development
50
36
  prerelease: false
51
37
  version_requirements: !ruby/object:Gem::Requirement
52
38
  requirements:
53
- - - ">="
39
+ - - "~>"
54
40
  - !ruby/object:Gem::Version
55
- version: '0'
41
+ version: '5.2'
56
42
  - !ruby/object:Gem::Dependency
57
- name: webmock
43
+ name: mechanize
58
44
  requirement: !ruby/object:Gem::Requirement
59
45
  requirements:
60
- - - ">="
46
+ - - "~>"
61
47
  - !ruby/object:Gem::Version
62
- version: '0'
63
- type: :development
64
- prerelease: false
65
- version_requirements: !ruby/object:Gem::Requirement
66
- requirements:
67
- - - ">="
68
- - !ruby/object:Gem::Version
69
- version: '0'
70
- - !ruby/object:Gem::Dependency
71
- name: oga
72
- requirement: !ruby/object:Gem::Requirement
73
- requirements:
74
- - - ">="
75
- - !ruby/object:Gem::Version
76
- version: '0'
48
+ version: '2.7'
77
49
  type: :runtime
78
50
  prerelease: false
79
51
  version_requirements: !ruby/object:Gem::Requirement
80
52
  requirements:
81
- - - ">="
53
+ - - "~>"
82
54
  - !ruby/object:Gem::Version
83
- version: '0'
84
- description: Get user achievements and course info from Codecademy
55
+ version: '2.7'
56
+ description: Get user user achievements and course lists from Codecademy
85
57
  email:
86
- - chung1350@hotmail.com
87
58
  - soumya.ray@gmail.com
59
+ - chung1350@hotmail.com
88
60
  executables:
89
61
  - codebadges
90
62
  extensions: []
@@ -101,13 +73,12 @@ files:
101
73
  - lib/codebadges.rb
102
74
  - lib/codebadges/badges.rb
103
75
  - lib/codebadges/courses.rb
76
+ - lib/codebadges/site.rb
104
77
  - lib/codebadges/version.rb
105
78
  - spec/badges_spec.rb
106
79
  - spec/courses_spec.rb
107
80
  - spec/fixtures/badges.yml
108
81
  - spec/fixtures/courses.yml
109
- - spec/fixtures/vcr_cassettes/badges.yml
110
- - spec/fixtures/vcr_cassettes/courses.yml
111
82
  homepage: https://github.com/ISS-SOA/Codecademy-Ruby
112
83
  licenses:
113
84
  - MIT
@@ -128,7 +99,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
128
99
  version: '0'
129
100
  requirements: []
130
101
  rubyforge_project:
131
- rubygems_version: 2.4.6
102
+ rubygems_version: 2.6.6
132
103
  signing_key:
133
104
  specification_version: 4
134
105
  summary: Access user and course information on Codecademy
@@ -137,5 +108,3 @@ test_files:
137
108
  - spec/courses_spec.rb
138
109
  - spec/fixtures/badges.yml
139
110
  - spec/fixtures/courses.yml
140
- - spec/fixtures/vcr_cassettes/badges.yml
141
- - spec/fixtures/vcr_cassettes/courses.yml