-
Notifications
You must be signed in to change notification settings - Fork 43
2345 - 3 #292
base: master
Are you sure you want to change the base?
2345 - 3 #292
Changes from all commits
7b7a10b
708ada7
c62140e
71c4668
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Onliner2345 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
ruby-2.5.0 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
source 'https://rubygems.org' | ||
|
||
gem 'mechanize', '~> 2.7', '>= 2.7.6' | ||
gem 'ohm', '~> 3.1', '>= 3.1.1' | ||
gem 'redis', '~> 3.3', '>= 3.3.1' | ||
gem 'sinatra', '~> 1.4', '>= 1.4.7' | ||
|
||
group :development do | ||
gem 'pry' | ||
gem 'reek' | ||
gem 'rubocop', '~> 0.54.0' | ||
gem 'shotgun', '~> 0.9.2' | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
GEM | ||
remote: https://rubygems.org/ | ||
specs: | ||
ast (2.4.0) | ||
axiom-types (0.1.1) | ||
descendants_tracker (~> 0.0.4) | ||
ice_nine (~> 0.11.0) | ||
thread_safe (~> 0.3, >= 0.3.1) | ||
codeclimate-engine-rb (0.4.1) | ||
virtus (~> 1.0) | ||
coderay (1.1.2) | ||
coercible (1.0.0) | ||
descendants_tracker (~> 0.0.1) | ||
connection_pool (2.2.2) | ||
descendants_tracker (0.0.4) | ||
thread_safe (~> 0.3, >= 0.3.1) | ||
domain_name (0.5.20180417) | ||
unf (>= 0.0.5, < 1.0.0) | ||
equalizer (0.0.11) | ||
hiredis (0.6.1) | ||
http-cookie (1.0.3) | ||
domain_name (~> 0.5) | ||
ice_nine (0.11.2) | ||
kwalify (0.7.2) | ||
mechanize (2.7.6) | ||
domain_name (~> 0.5, >= 0.5.1) | ||
http-cookie (~> 1.0) | ||
mime-types (>= 1.17.2) | ||
net-http-digest_auth (~> 1.1, >= 1.1.1) | ||
net-http-persistent (>= 2.5.2) | ||
nokogiri (~> 1.6) | ||
ntlm-http (~> 0.1, >= 0.1.1) | ||
webrobots (>= 0.0.9, < 0.2) | ||
method_source (0.9.0) | ||
mime-types (3.1) | ||
mime-types-data (~> 3.2015) | ||
mime-types-data (3.2016.0521) | ||
mini_portile2 (2.3.0) | ||
nest (3.1.1) | ||
redic | ||
net-http-digest_auth (1.4.1) | ||
net-http-persistent (3.0.0) | ||
connection_pool (~> 2.2) | ||
nokogiri (1.8.4) | ||
mini_portile2 (~> 2.3.0) | ||
ntlm-http (0.1.1) | ||
ohm (3.1.1) | ||
nest (~> 3) | ||
redic (~> 1.5.0) | ||
stal | ||
parallel (1.12.1) | ||
parser (2.5.1.2) | ||
ast (~> 2.4.0) | ||
powerpack (0.1.2) | ||
pry (0.11.3) | ||
coderay (~> 1.1.0) | ||
method_source (~> 0.9.0) | ||
rack (1.6.10) | ||
rack-protection (1.5.5) | ||
rack | ||
rainbow (3.0.0) | ||
redic (1.5.0) | ||
hiredis | ||
redis (3.3.5) | ||
reek (5.0.2) | ||
codeclimate-engine-rb (~> 0.4.0) | ||
kwalify (~> 0.7.0) | ||
parser (>= 2.5.0.0, < 2.6, != 2.5.1.1) | ||
rainbow (>= 2.0, < 4.0) | ||
rubocop (0.54.0) | ||
parallel (~> 1.10) | ||
parser (>= 2.5) | ||
powerpack (~> 0.1) | ||
rainbow (>= 2.2.2, < 4.0) | ||
ruby-progressbar (~> 1.7) | ||
unicode-display_width (~> 1.0, >= 1.0.1) | ||
ruby-progressbar (1.9.0) | ||
shotgun (0.9.2) | ||
rack (>= 1.0) | ||
sinatra (1.4.8) | ||
rack (~> 1.5) | ||
rack-protection (~> 1.4) | ||
tilt (>= 1.3, < 3) | ||
stal (0.3.0) | ||
redic (~> 1.5) | ||
thread_safe (0.3.6) | ||
tilt (2.0.8) | ||
unf (0.1.4) | ||
unf_ext | ||
unf_ext (0.0.7.5) | ||
unicode-display_width (1.4.0) | ||
virtus (1.0.5) | ||
axiom-types (~> 0.1) | ||
coercible (~> 1.0) | ||
descendants_tracker (~> 0.0, >= 0.0.3) | ||
equalizer (~> 0.0, >= 0.0.9) | ||
webrobots (0.1.2) | ||
|
||
PLATFORMS | ||
ruby | ||
|
||
DEPENDENCIES | ||
mechanize (~> 2.7, >= 2.7.6) | ||
ohm (~> 3.1, >= 3.1.1) | ||
pry | ||
redis (~> 3.3, >= 3.3.1) | ||
reek | ||
rubocop (~> 0.54.0) | ||
shotgun (~> 0.9.2) | ||
sinatra (~> 1.4, >= 1.4.7) | ||
|
||
BUNDLED WITH | ||
1.16.3 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
Bundler.require | ||
|
||
Dir.glob('./{controllers,models}/*.rb').each { |file| require_relative file } | ||
|
||
map('/articles') { run ArticlesController } | ||
map('/') { run ApplicationController } |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
class ApplicationController < Sinatra::Base | ||
set :views, File.expand_path(File.join(__FILE__, '../../views')) | ||
set :method_override, true | ||
|
||
not_found do | ||
erb :not_found | ||
end | ||
|
||
get '/' do | ||
redirect to '/articles' | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
require_relative './application_controller.rb' | ||
|
||
class ArticlesController < ApplicationController | ||
get '/' do | ||
@articles = Article.all | ||
erb :'/articles/index' | ||
end | ||
|
||
get '/new' do | ||
erb :'/articles/create' | ||
end | ||
|
||
post '/' do | ||
@article = ArticleCreater.new(params).create | ||
redirect to '/' | ||
end | ||
|
||
get '/:id' do | ||
@article = Article[params[:id]] | ||
@comments = @article.comments | ||
erb :'/articles/show' | ||
end | ||
|
||
delete '/:id' do | ||
Article[params[:id]].delete | ||
redirect to '/' | ||
end | ||
|
||
post '/:id' do | ||
@article = Article[params[:id]] | ||
@article.update(link: params[:article]) | ||
redirect to "/#{params[:id]}" | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
class Article < Ohm::Model | ||
attribute :link | ||
attribute :title | ||
attribute :rating | ||
unique :link | ||
collection :comments, :Comment | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
class ArticleCreater | ||
attr_reader :article | ||
|
||
def initialize(options) | ||
@article_link = options[:article] | ||
@comments = ArticleParser.new(@article_link).comments | ||
end | ||
|
||
def create | ||
@article = Article.create(link: @article_link, title: title, rating: article_rating) | ||
CommentsCreater.new(comments_with_rating, article).create | ||
article | ||
end | ||
|
||
private | ||
|
||
def article_rating | ||
comments_with_rating.map { |comment| comment[:rating] }.sum / @comments.size | ||
end | ||
|
||
def comments_with_rating | ||
CommentsRating.new(@comments).put_ratings | ||
end | ||
|
||
def title | ||
ArticleParser.new(@article_link).title | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
require 'mechanize' | ||
|
||
class ArticleParser | ||
def initialize(link = 'https://people.onliner.by/2018/07/23/vodol') | ||
@agent = Mechanize.new | ||
@article_link = link | ||
end | ||
|
||
def title | ||
@agent.get(@article_link).search('.news-header__title').text.strip | ||
end | ||
|
||
def comments | ||
data['comments'].reverse.map do |comment| | ||
{ author: CommentParser.author(comment), | ||
text: CommentParser.text(comment), | ||
votes: CommentParser.votes(comment) } | ||
end | ||
end | ||
|
||
private | ||
|
||
def data | ||
JSON.parse(@agent.get(comment_link).body) | ||
end | ||
|
||
def comment_link | ||
"https://comments.api.onliner.by/news/#{section}.post/#{article_id}/comments?limit=9999" | ||
end | ||
|
||
def section | ||
@article_link[%r{https://(\w+)}, 1] | ||
end | ||
|
||
def article_id | ||
@agent.get(@article_link).search('.news_view_count').attr('news_id').value | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
class Comment < Ohm::Model | ||
attribute :author | ||
attribute :text | ||
attribute :rating | ||
reference :article, :Article | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
module CommentParser | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looks like it should have the same structure as ArticleParser I would do smth like this:
|
||
def self.votes(options) | ||
options['marks'].values.reduce(:+) | ||
end | ||
|
||
def self.author(options) | ||
options['author']['name'] | ||
end | ||
|
||
def self.text(options) | ||
options['text'] | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
class CommentsRating | ||
LIMIT = 50 | ||
|
||
def initialize(comments) | ||
@comments = comments | ||
end | ||
|
||
# :reek:FeatureEnvy | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this is bad practice. If you want - you could add specs for this particular class and I'll show how to fix the 'FeatureEnvy' issue |
||
def put_ratings | ||
selected_for_evaluation = sort_comments_by_votes | ||
ratings = RatingCounter.new(selected_for_evaluation).calculate | ||
selected_for_evaluation.zip(ratings).map do |record| | ||
record.first[:rating] = record.last | ||
record[0] | ||
end | ||
end | ||
|
||
private | ||
|
||
def sort_comments_by_votes | ||
@comments.sort_by { |comment| comment[:votes] }.reverse.first(LIMIT) | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
class CommentsCreater | ||
LIMIT = 50 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. LIMIT = 50 - never used There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. delete it |
||
|
||
def initialize(comments, article) | ||
@comments = comments | ||
@article = article | ||
end | ||
|
||
# :reek:FeatureEnvy | ||
def create | ||
@comments.each do |comment| | ||
Comment.create(author: comment[:author], text: comment[:text], rating: comment[:rating], article: @article) | ||
end | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
require 'net/https' | ||
require 'uri' | ||
require 'json' | ||
|
||
class RatingCounter | ||
URI = 'https://westcentralus.api.cognitive.microsoft.com/text/analytics/v2.0/sentiment'.freeze | ||
ACCESS_KEY = IO.read(File.dirname(__FILE__) + '/pass').freeze | ||
attr_reader :request | ||
|
||
def initialize(comments) | ||
@uri = URI(URI) | ||
@data = { documents: [] } | ||
@comments = comments | ||
end | ||
|
||
def calculate | ||
prepare_comments | ||
@request = create_request | ||
response = send_request | ||
JSON.parse(response.body)['documents'].map do |data| | ||
(data['score'] * 200).to_i - 100 | ||
end | ||
end | ||
|
||
private | ||
|
||
def send_request | ||
Net::HTTP.start(@uri.host, @uri.port, use_ssl: @uri.scheme == 'https') do |http| | ||
http.request(request) | ||
end | ||
end | ||
|
||
def prepare_comments | ||
@comments.each_with_index do |comment, index| | ||
@data[:documents] << { 'id' => index.to_s, 'language' => 'ru', 'text' => comment[:text] } | ||
end | ||
end | ||
|
||
def create_request | ||
request = Net::HTTP::Post.new(@uri, 'Content-Type' => 'application/json', | ||
'Ocp-Apim-Subscription-Key' => ACCESS_KEY) | ||
request.body = @data.to_json | ||
request | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
<html> | ||
<head> | ||
<title> Adding an article </title> | ||
</head> | ||
|
||
<h1>New article</h1> | ||
<body> | ||
<style> #article {width: 450px;} </style> | ||
<form action="/articles" method="post"> | ||
<div class="form-group"> | ||
<input type="text" class="form-control" id="article" title="Example: https://tech.onliner.by/2018/07/30/startup-51" placeholder="Input link" name="article" pattern="^(http|https):\/\/\w+\.onliner.+" autofocus> | ||
</div> | ||
<button type="submit" class="btn btn-success">Add</button> | ||
</form> | ||
</body> | ||
</html> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You break Command Query separation principle:
when you say ArticleCreater#create - it is a command method - it COMMANDs to do smth
when you need article - it is a QUERY for a state of the object - so you should have 2 separate method for it
(I use attr_reader to create this method see example below)
so you should split the #create method into 2 methods