-
Notifications
You must be signed in to change notification settings - Fork 43
2396 - 3 #279
base: master
Are you sure you want to change the base?
2396 - 3 #279
Changes from all commits
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,3 @@ | ||
/config/secrets.yml | ||
config/secrets.yml | ||
app.rb |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
source 'https://rubygems.org' | ||
|
||
gem 'mechanize' | ||
gem 'ohm' | ||
gem 'rack' | ||
gem 'redis' | ||
gem 'shotgun' | ||
gem 'sidekiq' | ||
gem 'sinatra' | ||
gem 'thin' |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
GEM | ||
remote: https://rubygems.org/ | ||
specs: | ||
concurrent-ruby (1.0.5) | ||
connection_pool (2.2.2) | ||
daemons (1.2.6) | ||
domain_name (0.5.20180417) | ||
unf (>= 0.0.5, < 1.0.0) | ||
eventmachine (1.2.5) | ||
hiredis (0.6.1) | ||
http-cookie (1.0.3) | ||
domain_name (~> 0.5) | ||
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) | ||
mime-types (3.1) | ||
mime-types-data (~> 3.2015) | ||
mime-types-data (3.2016.0521) | ||
mini_portile2 (2.3.0) | ||
mustermann (1.0.2) | ||
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 | ||
rack (2.0.5) | ||
rack-protection (2.0.1) | ||
rack | ||
redic (1.5.0) | ||
hiredis | ||
redis (4.0.1) | ||
shotgun (0.9.2) | ||
rack (>= 1.0) | ||
sidekiq (5.1.3) | ||
concurrent-ruby (~> 1.0) | ||
connection_pool (~> 2.2, >= 2.2.0) | ||
rack-protection (>= 1.5.0) | ||
redis (>= 3.3.5, < 5) | ||
sinatra (2.0.1) | ||
mustermann (~> 1.0) | ||
rack (~> 2.0) | ||
rack-protection (= 2.0.1) | ||
tilt (~> 2.0) | ||
stal (0.3.0) | ||
redic (~> 1.5) | ||
thin (1.7.2) | ||
daemons (~> 1.0, >= 1.0.9) | ||
eventmachine (~> 1.0, >= 1.0.4) | ||
rack (>= 1, < 3) | ||
tilt (2.0.8) | ||
unf (0.1.4) | ||
unf_ext | ||
unf_ext (0.0.7.5) | ||
webrobots (0.1.2) | ||
|
||
PLATFORMS | ||
ruby | ||
|
||
DEPENDENCIES | ||
mechanize | ||
ohm | ||
rack | ||
redis | ||
shotgun | ||
sidekiq | ||
sinatra | ||
thin | ||
|
||
BUNDLED WITH | ||
1.16.2 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
require 'sinatra/base' | ||
require 'sidekiq/api' | ||
require 'sidekiq/web' | ||
require 'ohm' | ||
|
||
Dir.glob('./{controllers,helpers,models}/*.rb').sort.each do |file| | ||
require file | ||
end | ||
require './lib/workers/post_worker' | ||
Post.redis = Redic.new('redis://127.0.0.1:6379/0') | ||
Comment.redis = Redic.new('redis://127.0.0.1:6379/1') | ||
|
||
map('/posts') { run PostsController } | ||
map('/sidekiq') { run Sidekiq::Web } | ||
map('/') { run ApplicationController } |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
# This class is the base for my controllers | ||
class ApplicationController < Sinatra::Base | ||
set :views, File.expand_path(File.join(__FILE__, '../../views')) | ||
not_found do | ||
erb :not_found, layout: false | ||
end | ||
|
||
get '/' do | ||
redirect '/posts' | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
# This is class PostsController | ||
class PostsController < ApplicationController | ||
get '/' do | ||
@posts = Post.all | ||
erb :'posts/index' | ||
end | ||
get '/new' do | ||
erb :'posts/new' | ||
end | ||
|
||
post '/create' do | ||
Post.all.each do |post| | ||
post.delete if post.link == params[:link] | ||
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. Можешь рассказать зачем ты это делаешь? 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. Удаляю пост, если он уже был ранее создан. Обновить его данные было бы логичнее... |
||
end | ||
PostWorker.perform_async(params[:link]) | ||
sleep 2 | ||
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. Не, фигня :) 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. Я так понимаю, ты ждешь что твой парсер обработает страницу? А что, если за 2 секунды Но вообще так тоже делать не круто (а делать через pub/sub), но наверное пока сойдет и так. 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. Изначально хотел добавить flash как в рельсах, что ссылка отправлена на анализ, но не успевал и сделал такой костыль. |
||
redirect '/' | ||
end | ||
|
||
get '/delete/:id' do | ||
@post = Post.all[params[:id]] | ||
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. Ты сначала загружаешь все посты в память, а потом только ищешь по айди. Если бы ты внимательно почитал документацию Ohm, то ты бы увидел что можно искать и так https://github.com/soveran/ohm#finding-records |
||
@post.delete | ||
redirect '/' | ||
end | ||
|
||
get '/:id' do | ||
@posts = Post.all | ||
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. Здесь то же самое. |
||
@post = @posts[params[:id]] | ||
erb :'posts/show' | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
require 'json' | ||
require 'mechanize' | ||
|
||
# This is class handling comments for post across API onliner.by | ||
class CommentsParser | ||
LIMIT = 50 | ||
API_PATH = 'https://comments.api.onliner.by/news/tech.post/'.freeze | ||
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. Я так понимаю из url, ты только технические статьи можешь парсить? 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. Хз отчего, но я бы мб вынес эти констаны в 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. Согласен. Добавило бы больше гибкости |
||
API_PARAMS = "/comments?limit=#{LIMIT}&_=0.9841189675826583".freeze | ||
attr_reader :agent | ||
|
||
def initialize | ||
@agent = Mechanize.new | ||
end | ||
|
||
def perform(url) | ||
page_post = agent.get(url) | ||
post_id = page_post.search('span.news_view_count').first.values[1] | ||
comment_list = agent.get(API_PATH + post_id + API_PARAMS) | ||
handling_comments(comment_list) | ||
end | ||
|
||
def self.fetch_title(url) | ||
agent = Mechanize.new | ||
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. Мне не нравится то, что класс называется По ООП тут правильно было бы вынести этот метод в отдельный класс. Либо (чтобы соптимизировать на запросе) фетчить заголовок вместе с комментами и возвращать хешом — 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. Второй вариант рассматривал, но посчитал, что лучше вынести в отдельный метод. |
||
agent.get(url).title | ||
end | ||
|
||
private | ||
|
||
def handling_comments(comment_list) | ||
body = comment_list.body | ||
JSON.parse(body)['comments'].each_with_object([]) do |comment, comments| | ||
comments << comment['text'].gsub("\n", '<br>') | ||
end | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
# This is helper for create post from comments | ||
class CreatePost | ||
attr_reader :link | ||
def initialize(link) | ||
@link = link | ||
end | ||
|
||
def perform | ||
create | ||
end | ||
|
||
private | ||
|
||
def create | ||
comments = CommentsParser.new.perform(link) | ||
rating = RatingCounter.new.perform(comments) | ||
post = Post.create title: fetch_title, link: link, | ||
rating: rating.sum / rating.size | ||
create_comments_for_post(post, comments, rating) | ||
end | ||
|
||
def fetch_title | ||
CommentsParser.fetch_title(link) | ||
end | ||
|
||
def create_comments_for_post(post, comments, rating) | ||
comments.zip(rating).each do |obj| | ||
post.comments.add(Comment.create(text: obj.first, rating: obj.last)) | ||
end | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
require 'net/https' | ||
require 'uri' | ||
require 'json' | ||
require './helpers/setting' | ||
# This is class conects to API AZURE, Analyze sentiment texts and | ||
# fetch score for his | ||
class RatingCounter | ||
KEY_AZURE = Setting.get('key_azure').freeze | ||
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. Вот это тоже бы почему-то вынес в Setting'и. 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. Или даже может сделал |
||
URI_BASE = 'https://westcentralus.api.cognitive.microsoft.com/text/analytics/v2.0/sentiment'.freeze | ||
PATH = URI(URI_BASE).freeze | ||
attr_reader :data, :request | ||
|
||
def initialize | ||
@data = { documents: [] } | ||
end | ||
|
||
def perform(comments) | ||
handling_data(comments) | ||
@request = prepare_request | ||
output_data(send_request) | ||
end | ||
|
||
private | ||
|
||
def handling_data(comments) | ||
comments.each_with_index do |comment, index| | ||
@data[:documents] << { 'id' => index.to_s, 'language' => 'ru', | ||
'text' => comment } | ||
end | ||
end | ||
|
||
def send_request | ||
Net::HTTP.start(PATH.host, PATH.port, | ||
use_ssl: PATH.scheme == 'https') do |http| | ||
http.request(request) | ||
end | ||
end | ||
|
||
def output_data(response) | ||
body = response.body | ||
JSON.parse(body)['documents'].each_with_object([]) do |data, rating| | ||
rating << ((data['score'] * 200).to_i - 100) | ||
end | ||
end | ||
|
||
def headers | ||
heads = {} | ||
heads['Content-Type'] = 'application/json' | ||
heads['Ocp-Apim-Subscription-Key'] = KEY_AZURE | ||
heads | ||
end | ||
|
||
def prepare_request | ||
request = Net::HTTP::Post.new(PATH, headers) | ||
request.body = data.to_json | ||
request | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
require 'yaml' | ||
|
||
class Setting | ||
CONFIG_FILE = 'secrets.yml'.freeze | ||
|
||
class << self | ||
def get(key) | ||
load_settings[key.to_s] | ||
end | ||
|
||
def load_settings | ||
YAML.safe_load(File.read(file_path)) | ||
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. закешируй эту загрузку файла |
||
end | ||
|
||
private | ||
|
||
def file_path | ||
"./config/#{CONFIG_FILE}" | ||
end | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
# This is class perform jobs in background | ||
class PostWorker | ||
include Sidekiq::Worker | ||
def perform(link) | ||
call(link) | ||
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. А в чем смысл метода 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. reek ругался, что лучше вынести в отдельный класс. |
||
end | ||
|
||
private | ||
|
||
def call(link) | ||
CreatePost.new(link).perform | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
# This is model for comments post | ||
class Comment < Ohm::Model | ||
attribute :text | ||
attribute :rating | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
# This is model post | ||
class Post < Ohm::Model | ||
attribute :title | ||
attribute :link | ||
attribute :rating | ||
set :comments, Comment | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="utf-8"> | ||
<meta http-equiv="X-UA-Compatible" content="IE=edge"> | ||
<meta name="viewport" content="width=device-width, initial-scale=1"> | ||
<title>ONLINER</title> | ||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"> | ||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous"> | ||
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries --> | ||
<!-- WARNING: Respond.js doesn't work if you view the page via file:// --> | ||
<!--[if lt IE 9]> | ||
<script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script> | ||
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script> | ||
<![endif]--> | ||
</head> | ||
<body> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
<%= erb :header %> | ||
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. header и head это разные вещи 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. принял |
||
<header> | ||
<%= erb :navbar %> | ||
</header> | ||
<div class="container"> | ||
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. Соблюдай отступы. 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. окей, накладочка. |
||
<div class="row"> | ||
<div class="col-md-12"><%= yield %></div> | ||
</div> | ||
</div> | ||
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) --> | ||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script> | ||
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. JS и CSS скрипты мы обычно складываем в 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. шаблон из документации |
||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script> | ||
|
||
</body> | ||
</html> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
<nav class="navbar navbar-default"> | ||
<div class="container-fluid"> | ||
<div class="navbar-header"> | ||
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false"> | ||
<span class="sr-only">Toggle navigation</span> | ||
<span class="icon-bar"></span> | ||
<span class="icon-bar"></span> | ||
<span class="icon-bar"></span> | ||
</button> | ||
<a class="navbar-brand" href="/">Список статей </a> | ||
</div> | ||
|
||
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1"> | ||
<ul class="nav navbar-nav"> | ||
<li><a href="/sidekiq" target="blank">Sidekiq</a></li> | ||
</ul> <!--background:black !important; --> | ||
<ul class="nav navbar-nav navbar-right"> | ||
<li><a href='/posts/new' class='btn btn-primary' style="color:white;background:#488CC7 !important;">Добавить статью</a></li> | ||
</ul> | ||
</div> | ||
</div> | ||
</nav> |
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.
добавь пустую строку перед этим блоком