Skip to content
This repository has been archived by the owner on Jun 27, 2019. It is now read-only.

2199 - 3 #277

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions 2199/3/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.env
12 changes: 12 additions & 0 deletions 2199/3/Gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
source 'https://rubygems.org'

gem 'capybara'
gem 'dotenv'
gem 'ohm'
gem 'poltergeist'
gem 'redis'
gem 'shotgun'
gem 'sinatra'
group :development do
gem 'pry'
end
75 changes: 75 additions & 0 deletions 2199/3/Gemfile.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
GEM
remote: https://rubygems.org/
specs:
addressable (2.5.2)
public_suffix (>= 2.0.2, < 4.0)
capybara (3.4.1)
addressable
mini_mime (>= 0.1.3)
nokogiri (~> 1.8)
rack (>= 1.6.0)
rack-test (>= 0.6.3)
xpath (~> 3.1)
cliver (0.3.2)
coderay (1.1.2)
dotenv (2.4.0)
hiredis (0.6.1)
method_source (0.9.0)
mini_mime (1.0.0)
mini_portile2 (2.3.0)
mustermann (1.0.2)
nest (3.1.1)
redic
nokogiri (1.8.4)
mini_portile2 (~> 2.3.0)
ohm (3.1.1)
nest (~> 3)
redic (~> 1.5.0)
stal
poltergeist (1.18.1)
capybara (>= 2.1, < 4)
cliver (~> 0.3.1)
websocket-driver (>= 0.2.0)
pry (0.11.3)
coderay (~> 1.1.0)
method_source (~> 0.9.0)
public_suffix (3.0.2)
rack (2.0.5)
rack-protection (2.0.3)
rack
rack-test (1.1.0)
rack (>= 1.0, < 3)
redic (1.5.0)
hiredis
redis (4.0.1)
shotgun (0.9.2)
rack (>= 1.0)
sinatra (2.0.3)
mustermann (~> 1.0)
rack (~> 2.0)
rack-protection (= 2.0.3)
tilt (~> 2.0)
stal (0.3.0)
redic (~> 1.5)
tilt (2.0.8)
websocket-driver (0.7.0)
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.3)
xpath (3.1.0)
nokogiri (~> 1.8)

PLATFORMS
ruby

DEPENDENCIES
capybara
dotenv
ohm
poltergeist
pry
redis
shotgun
sinatra

BUNDLED WITH
1.16.1
8 changes: 8 additions & 0 deletions 2199/3/app/capybara_initializer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
require 'capybara'
require 'capybara/poltergeist'
Capybara.register_driver :poltergeist do |app|
Capybara::Poltergeist::Driver.new(app, js_errors: false)
end

# Configure Capybara to use Poltergeist as the driver
Capybara.default_driver = :poltergeist
52 changes: 52 additions & 0 deletions 2199/3/app/comment_analyzer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
require 'dotenv/load'
# analyze comment
class CommentAnalyzer
ACCESS_KEY = ENV['ACCESS_KEY']
AZURE_ENDPOINT = ENV['AZURE_ENDPOINT']
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does Azure endpoint contain responsive information?
If no, why should we store it in .ENV variable?


def initialize(texts)
@texts = texts
end

# :reek:NestedIterators
# rubocop:disable Metrics/AbcSize
def analyze

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Metrics/AbcSize: Assignment Branch Condition size for analyze is too high. [16.03/15]

JSON.parse(run_request.body)['documents'].each_with_object([]) do |result, store|
document = documents.find { |doc| doc[:id].to_s == result['id'] }

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NestedIterators: CommentAnalyzer#analyze contains iterators nested 2 deep. More info.

store << {
text: document[:text],
rating: result['score'] * 200 - 100
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The formula is too magical for me (where do the numbers (*200 - 100 ) come from?)
Let's move it to separate method and describe a little bit.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We get a decimal number and this formula needed to lead it to necessary range

}
end
end
# rubocop:enable Metrics/AbcSize

def endpoint
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, what endpoint? I see from the code below that it's the #azure_endpoint. Why not say it explicitly?

@endpoint ||= URI(AZURE_ENDPOINT)
end

# :reek:FeatureEnvy
def request
request = Net::HTTP::Post.new(endpoint)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can use #tap.

Net::HTTP::Post.new(endpoint).tap do |request|
   request['Content-Type'] = 'application/json'
   request['Ocp-Apim-Subscription-Key'] = ACCESS_KEY
   request.body = serialized_texts
end

request['Content-Type'] = 'application/json'

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FeatureEnvy: CommentAnalyzer#request refers to 'request' more than self (maybe move it to another class?). More info.

request['Ocp-Apim-Subscription-Key'] = ACCESS_KEY
request.body = serialized_texts
request
end

def documents
@documents ||= @texts.map do |text|
{ id: text.object_id, language: 'ru', text: text }
end
end

def serialized_texts
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it's serialized_texts JSON, call it serialized_texts_json :)

{ documents: documents }.to_json
end

def run_request
https = Net::HTTP.new(endpoint.host, endpoint.port)
https.use_ssl = true
https.request(request)
end
end
14 changes: 14 additions & 0 deletions 2199/3/app/comment_parser.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# parse node and find text and rating
class CommentParser
def initialize(node)
@node = node
end

def text
@text ||= @node.all('.news-comment__speech > div > p').map(&:text).reduce(&:+)
end

def rating
@rating ||= @node.all('.like-control span').sum { |mark| mark.text.to_i }
end
end
53 changes: 53 additions & 0 deletions 2199/3/app/onliner_page_parser.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
require 'pry'
require_relative '../app/comment_parser'
require_relative 'capybara_initializer'

# class for parsing
class OnlinerPageParser
COMMENTS_TO_TAKE = 50

def initialize(link)
@link = link
end

def browser
@browser ||= Capybara.current_session
end

# :reek:TooManyStatements
def visit_page

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TooManyStatements: OnlinerPageParser#visit_page has approx 7 statements. More info.

attempts = 0
begin
browser.visit(@link)
rescue StandardError => exception
attempts += 1
sleep(2 * attempts)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did you choose 2*attempts formula?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I use exponential backoff. I did something wrong??

retry if attempts <= 3
raise exception
end
end

def show_all_comments
browser.find('.button-style.button-style_subsidiary.button-style_big.news-form__button'\
'.news-form__button_width_full.news-form__button_font-weight_semibold').click
sleep(5)
end

def top_comment_texts
visit_page
show_all_comments
top_comments.map(&:text)
end

def comment_nodes
browser.all('[id^="comment-"]').drop(1)
end

def comments
comment_nodes.map { |comment_node| CommentParser.new(comment_node) }
end

def top_comments
comments.sort_by(&:rating).reverse.first(COMMENTS_TO_TAKE)
end
end
10 changes: 10 additions & 0 deletions 2199/3/config.ru
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
require 'sinatra/base'
require 'ohm'
require_relative 'app/onliner_page_parser'
require_relative 'app/comment_analyzer'
require_relative 'controllers/application_controller'
require_relative 'models/page'
require_relative 'models/comment'

# Dir.glob('./{helpers, controllers}/*.rb').each { |file| require file }
map('/') { run ApplicationController }
38 changes: 38 additions & 0 deletions 2199/3/controllers/application_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
require 'sinatra'
require 'pry'
# class ApplicationController
class ApplicationController < Sinatra::Base
set views: 'views/'

get '/' do
redirect '/pages'
end

get '/pages' do
@pages = Page.all
erb :index
end

get '/pages/new' do
erb :new
end

get '/pages/:id' do
@page = Page[params[:id]]
erb :show
end

post '/pages' do
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's meditate on this endpoint.

I'd like to have less code in here.
Something like this:

#app.rb
post '/pages' do
   if Page.exists?(link: link)
     @page = Page.find(link: link)
   else
     @page = Page.create_from(link: link)
   end
   erb :show
end

It's just an idea, but it will make your post action more verbose and will hide all Page and Comment creation logic.

link = params[:link]
@page = Page.find(link: link).first
unless @page
comment_texts = OnlinerPageParser.new(link).top_comment_texts
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess the Parser is redunant word here.
It's just OnlinerPage.new(link). And then you ask your OnlinerPage about its '#top_comments' and so on.

Or if you want to stick to comments, call it OnlinerPageCommentsParser

comments_with_score = CommentAnalyzer.new(comment_texts).analyze
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Eventually, it's a Comment or Comments analyzer? From your code, I see that it analyzes all comments, not the particular one.

@page = Page.create(link: link)
comments_with_score.each do |comment_data|
Comment.create(comment_data.merge(page: @page))
end
end
erb :show
end
end
6 changes: 6 additions & 0 deletions 2199/3/models/comment.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Comment model
class Comment < Ohm::Model
attribute :text
attribute :rating
reference :page, 'Page'
end
10 changes: 10 additions & 0 deletions 2199/3/models/page.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Page model
class Page < Ohm::Model
attribute :link
collection :comments, 'Comment'
index :link

def rating
comments.sum { |comment| comment.rating.to_f } / comments.count
end
end
20 changes: 20 additions & 0 deletions 2199/3/views/index.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<a href="/pages/new">Analyse new link!! </a>
<table class="table table-striped table-hover">
<thead>
<tr>
<th> Number </th>
<th> Link </th>
<th> Rating </th>
</tr>
</thead>
<tbody>
<% @pages.each do |page| %>
<tr>
<td><a href="<%= url("/pages/#{page.id}") %>"><%= page.id %></a></td>
<td><a href="<%= page.link %>"><%= page.link %></a></td>
<td><%= page.rating %></td>
</tr>
<% end %>
</tbody>
</tbody>
</table>
10 changes: 10 additions & 0 deletions 2199/3/views/layout.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<!doctype html>
<html>
<head>
<title>Analyzer</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" />
</head>
<body>
<%= yield %>
</body>
</html>
6 changes: 6 additions & 0 deletions 2199/3/views/new.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<form method="post" action=<%= url('/pages') %>>
<label for="link">Link:</label>
<input type="text" name="link">
<input type="submit">
</form>
<a href="/">Back to Index</a>
30 changes: 30 additions & 0 deletions 2199/3/views/show.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<table>
<tr>
<td><strong>Link:</strong></td>
<td><%= @page.link %></td>
</tr>
<tr>
<td><strong>Average rating:</strong></td>
<td><%= @page.rating.to_i %></td>
</tr>
</table>

<table class="table table-striped table-hover">
<thead>
<tr>
<th> Rating </th>
<th> Comment </th>
</tr>
</thead>
<tbody>
<% @page.comments.each do |comment| %>
<tr>
<td><%= "#{comment.rating.to_i}" %></td>
<td><%= "#{comment.text}" %></td>
</tr>
<% end %>
</tbody>
</table>


<a href="/">Back to Index</a>