hnjobs_cli 1.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 +7 -0
- data/bin/hnjobs_cli +9 -0
- data/lib/controller.rb +100 -0
- data/lib/hnjobs/version.rb +3 -0
- data/lib/job.rb +35 -0
- data/lib/scraper.rb +21 -0
- metadata +78 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: c3f98948d03611a2f682bb9808c297fbf3c45c50
|
4
|
+
data.tar.gz: 120aaeffb237de09cd60057f22974e8dd80c31bd
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: e15f0c7180eea6a440e33b9e793946207085b4855d8cab41f0afbc0e8fc27f7b89fefc0d77ea9a013a17dadbac222b995bbe1ecbe20477c8f15148c6d7df6c83
|
7
|
+
data.tar.gz: 37553c2177615b6f2d7f4333f98b6dcbc8b8743d0adc843eb365e791a1e46c641f264b8312a1e80c0a53d3e439fe9c698aa91d1c5077a02e03a4fec02b060159
|
data/bin/hnjobs_cli
ADDED
data/lib/controller.rb
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
class HNjobsCLI
|
2
|
+
|
3
|
+
# User Flow: First-Timer
|
4
|
+
# 1. user installs gem
|
5
|
+
# 2. user starts app
|
6
|
+
# 3. CLI says hi and provides instructions
|
7
|
+
# 4. user inputs url to scrape or uses default url
|
8
|
+
# 5. CLI scrapes url
|
9
|
+
# 6. CLI outputs list
|
10
|
+
# 7. user inputs number of job posting
|
11
|
+
# 8. CLI outputs further details about job posting
|
12
|
+
# 9. user returns to list via #list
|
13
|
+
# 10. user filters list by #filter
|
14
|
+
# 11. user scrapes new page via #scrape
|
15
|
+
# 12. user exits
|
16
|
+
|
17
|
+
# User interface
|
18
|
+
def call
|
19
|
+
puts greeting
|
20
|
+
scrape
|
21
|
+
input = ''
|
22
|
+
while input != 'exit'
|
23
|
+
input = gets.strip
|
24
|
+
case input
|
25
|
+
when -> (input) { input.to_i != 0 } # this proc lets you make comparisons inside case statements
|
26
|
+
job = Job.find_by_id(input.to_i)
|
27
|
+
if job
|
28
|
+
puts "\n\n" + job.description + "\n\n"
|
29
|
+
puts menu
|
30
|
+
else
|
31
|
+
puts "Out of range. Please input a number between 1 and #{Job.count}"
|
32
|
+
end
|
33
|
+
when 'list'
|
34
|
+
list
|
35
|
+
when 'exit'
|
36
|
+
puts "\n\nGoodbye!\n\n"
|
37
|
+
when 'scrape'
|
38
|
+
scrape
|
39
|
+
when 'filter'
|
40
|
+
filter
|
41
|
+
puts "\n\nEnter the number of a job posting to see more info."
|
42
|
+
else
|
43
|
+
puts 'Unknown command'
|
44
|
+
puts menu
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# List jobs with numbers for reference
|
50
|
+
def list
|
51
|
+
puts "\n\n#{Job.count} job postings found\n\n"
|
52
|
+
Job.list.map do |job|
|
53
|
+
puts "#{job.id}. #{job.firstline}"
|
54
|
+
end
|
55
|
+
puts "\n\nEnter the number of a job posting to see more info."
|
56
|
+
end
|
57
|
+
|
58
|
+
# Scrape page and create jobs
|
59
|
+
def scrape
|
60
|
+
Job.reset
|
61
|
+
puts 'Enter a URL to scrape (or press enter for default):'
|
62
|
+
url = gets.strip
|
63
|
+
url = 'https://news.ycombinator.com/item?id=15601729' if url == ''
|
64
|
+
puts "Scraping...\n\n"
|
65
|
+
jobs_data = Scraper.scrape(url)
|
66
|
+
jobs_data.each_with_index do |job_data, i|
|
67
|
+
job = Job.new(job_data.merge({id: i+1}))
|
68
|
+
end
|
69
|
+
puts list
|
70
|
+
end
|
71
|
+
|
72
|
+
# Filter jobs
|
73
|
+
def filter
|
74
|
+
puts 'Enter keyword:'
|
75
|
+
keyword = gets.strip
|
76
|
+
Job.filter(keyword).each do |job|
|
77
|
+
puts "#{job.id} #{job.firstline}"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def greeting
|
82
|
+
<<~EOL
|
83
|
+
Hello! Welcome to the Hacker News Job Scraper.
|
84
|
+
I can distill an 'Ask HN: Who is hiring?' post down to its fine job postings.
|
85
|
+
Input URL to scrape:
|
86
|
+
EOL
|
87
|
+
end
|
88
|
+
|
89
|
+
def menu
|
90
|
+
<<~EOL
|
91
|
+
Available Commands:
|
92
|
+
Enter the number of a job posting to see its details
|
93
|
+
scrape //--> scrapes a new url and outputs another list of job postings
|
94
|
+
list //--> list job postings from latest scrape
|
95
|
+
filter //--> filter job postings by search terms
|
96
|
+
exit //--> exit the program
|
97
|
+
EOL
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
data/lib/job.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
class Job
|
2
|
+
|
3
|
+
@@all = []
|
4
|
+
|
5
|
+
attr_reader :company, :description, :firstline, :id
|
6
|
+
|
7
|
+
def initialize(options = {})
|
8
|
+
@id = options[:id]
|
9
|
+
@company = options[:company]
|
10
|
+
@firstline = options[:firstline]
|
11
|
+
@description = options[:description]
|
12
|
+
@@all << self
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.find_by_id(id)
|
16
|
+
@@all.select { |job| job.id == id }.first
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.filter(keyword)
|
20
|
+
@@all.select { |job| job.description.include?(keyword) }
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.list
|
24
|
+
@@all
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.count
|
28
|
+
@@all.count
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.reset
|
32
|
+
@@all = []
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
data/lib/scraper.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'open-uri'
|
2
|
+
require 'nokogiri'
|
3
|
+
|
4
|
+
class Scraper
|
5
|
+
|
6
|
+
# Assign nokogiri output to variable & search doc to populate jobs hash
|
7
|
+
def self.scrape(url)
|
8
|
+
@doc = ::Nokogiri::HTML(open(url))
|
9
|
+
@doc.css(".reply").remove
|
10
|
+
@doc.css(".comment").each_with_index.map do |comment, i|
|
11
|
+
unless comment.css(".c00").first === nil || comment.css(".c00").first === "" || !comment.css(".c00").first.to_s.include?('|') || comment.css(".c00").first.to_s.split("|").first.length > 150
|
12
|
+
company = comment.css(".c00").first.to_s.split("|").first.gsub(/<span class="c00">|<p>*|<a.*a>/, '').strip
|
13
|
+
firstline = comment.css(".c00").first.to_s.match(/.*\|*<p>/).to_s.gsub(/<span class="c00">|<p>*|<a.*a>/, '').strip
|
14
|
+
description = comment.css(":not(p)").first.text.strip
|
15
|
+
end
|
16
|
+
job_data = { company: company, firstline: firstline, description: description }
|
17
|
+
job_data unless company === nil || company === ""
|
18
|
+
end.compact
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
metadata
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: hnjobs_cli
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- purple squirrel
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-11-09 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 1.16.a
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 1.16.a
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
description: 'CLI app for checking monthly job postings on Ask HN: Who Is Hiring'
|
42
|
+
email:
|
43
|
+
- mikkanthrope@gmail.com
|
44
|
+
executables:
|
45
|
+
- hnjobs_cli
|
46
|
+
extensions: []
|
47
|
+
extra_rdoc_files: []
|
48
|
+
files:
|
49
|
+
- bin/hnjobs_cli
|
50
|
+
- lib/controller.rb
|
51
|
+
- lib/hnjobs/version.rb
|
52
|
+
- lib/job.rb
|
53
|
+
- lib/scraper.rb
|
54
|
+
homepage: https://github.com/squirrelnest/hnjobs_cli
|
55
|
+
licenses:
|
56
|
+
- MIT
|
57
|
+
metadata: {}
|
58
|
+
post_install_message:
|
59
|
+
rdoc_options: []
|
60
|
+
require_paths:
|
61
|
+
- lib
|
62
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
63
|
+
requirements:
|
64
|
+
- - ">="
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: '0'
|
67
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
68
|
+
requirements:
|
69
|
+
- - ">="
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: '0'
|
72
|
+
requirements: []
|
73
|
+
rubyforge_project:
|
74
|
+
rubygems_version: 2.6.12
|
75
|
+
signing_key:
|
76
|
+
specification_version: 4
|
77
|
+
summary: Extracts job postings from Ycombinator Hacker News
|
78
|
+
test_files: []
|