Introduce AsciicastPresenter

openid
Marcin Kulik 11 years ago
parent d571be2bbd
commit 86f6af3d78

@ -6,6 +6,8 @@ class AsciicastsController < ApplicationController
respond_to :html, :json, :js
attr_reader :asciicast
def index
render locals: {
page: AsciicastListPresenter.new(params[:category], params[:order],
@ -16,24 +18,23 @@ class AsciicastsController < ApplicationController
def show
respond_to do |format|
format.html do
view_counter.increment(@asciicast, cookies)
@asciicast = AsciicastDecorator.new(@asciicast)
respond_with @asciicast
view_counter.increment(asciicast, cookies)
render locals: { page: AsciicastPresenter.new(asciicast, current_user) }
end
format.json do
respond_with @asciicast
respond_with asciicast
end
format.js do
respond_with @asciicast
respond_with asciicast
end
end
end
def raw
response.headers.delete('X-Frame-Options')
@asciicast = AsciicastDecorator.new(@asciicast)
@asciicast = AsciicastDecorator.new(asciicast)
render :layout => 'raw'
end
@ -45,8 +46,8 @@ class AsciicastsController < ApplicationController
end
def update
if @asciicast.update_attributes(params[:asciicast])
redirect_to asciicast_path(@asciicast),
if asciicast.update_attributes(params[:asciicast])
redirect_to asciicast_path(asciicast),
:notice => 'Asciicast was updated.'
else
render :edit
@ -54,11 +55,11 @@ class AsciicastsController < ApplicationController
end
def destroy
if @asciicast.destroy
if asciicast.destroy
redirect_to profile_path(current_user),
:notice => 'Asciicast was deleted.'
else
redirect_to asciicast_path(@asciicast),
redirect_to asciicast_path(asciicast),
:alert => "Oops, we couldn't remove this asciicast. " \
"Try again later."
end
@ -71,8 +72,8 @@ class AsciicastsController < ApplicationController
end
def ensure_owner!
if current_user != @asciicast.user
redirect_to asciicast_path(@asciicast), :alert => "You can't do that."
if current_user != asciicast.user
redirect_to asciicast_path(asciicast), :alert => "You can't do that."
end
end

@ -47,22 +47,6 @@ class AsciicastDecorator < ApplicationDecorator
user.img_link
end
def other_by_user
if user
AsciicastDecorator.decorate_collection(
user.asciicasts.where('id <> ?', model.id).order('RANDOM()').limit(3)
)
else
[]
end
end
def embed_script
src = h.asciicast_url(model, :format => :js)
id = "asciicast-#{model.id}"
%(<script type="text/javascript" src="#{src}" id="#{id}" async></script>)
end
def formatted_duration
duration = model.duration.to_i
minutes = duration / 60

@ -46,6 +46,10 @@ class User < ActiveRecord::Base
asciicasts.count
end
def asciicasts_excluding(asciicast, limit)
asciicasts.where('id <> ?', asciicast.id).order('RANDOM()').limit(limit)
end
private
def generate_auth_token

@ -0,0 +1,72 @@
class AsciicastPresenter
attr_reader :asciicast, :user
def initialize(asciicast, user)
@asciicast = AsciicastDecorator.new(asciicast)
@user = user
end
def title
asciicast_title
end
def asciicast_title
asciicast.title
end
def author_img_link
asciicast.author_img_link
end
def author_link
asciicast.author_link
end
def asciicast_created_at
asciicast.created_at
end
def asciicast_env_details
"#{asciicast.os} / #{asciicast.shell} / #{asciicast.terminal_type}"
end
def views_count
asciicast.views_count
end
def embed_script(h)
src = h.asciicast_url(asciicast, format: :js)
id = "asciicast-#{asciicast.id}"
%(<script type="text/javascript" src="#{src}" id="#{id}" async></script>)
end
def show_admin_dropdown?
asciicast.managable_by?(user)
end
def show_description?
asciicast.description.present?
end
def description
asciicast.description
end
def show_other_asciicasts_by_author?
author.asciicast_count > 1
end
def other_asciicasts_by_author
asciicasts = author.asciicasts_excluding(asciicast, 3)
AsciicastDecorator.decorate_collection(asciicasts)
end
private
def author
asciicast.user
end
end

@ -1,6 +0,0 @@
- if @asciicast.other_by_user.any?
section.odd
.container
.other-asciicasts
h2 More by #{@asciicast.author_link}
= render 'previews', asciicasts: @asciicast.other_by_user, per_row: 3

@ -1,20 +1,20 @@
- content_for(:title, @asciicast.title)
- content_for(:title, page.title)
.asciicast-page
section.cinema
.container
= player @asciicast
= player page.asciicast
section.odd.info
.container
.row
.col-md-8.col-xs-8
span.author-avatar = @asciicast.author_img_link
h2 = @asciicast.title
small by #{@asciicast.author_link} #{time_ago_tag @asciicast.created_at}
span.author-avatar = page.author_img_link
h2 = page.asciicast_title
small by #{page.author_link} #{time_ago_tag page.asciicast_created_at}
.col-md-4.col-xs-4.text-right
= render 'shared/add_this', title: @asciicast.title, url: asciicast_url(@asciicast)
= render 'shared/add_this', title: page.asciicast_title, url: asciicast_url(page.asciicast)
section.even.meta
.container
@ -23,16 +23,13 @@
ul.meta-list
li
span.glyphicon.glyphicon-info-sign
'
' #{@asciicast.os} /
' #{@asciicast.shell} /
' #{@asciicast.terminal_type}
' #{page.asciicast_env_details}
li
span.glyphicon.glyphicon-eye-open
= " #{@asciicast.views_count}"
' #{page.views_count}
.col-md-4.col-xs-4
- if @asciicast.managable_by?(current_user)
- if page.show_admin_dropdown?
.dropdown.actions-dropdown.pull-right
button.btn.btn-default.dropdown-toggle[type="button" data-toggle="dropdown"]
span.glyphicon.glyphicon-cog
@ -40,11 +37,11 @@
span.caret
ul.dropdown-menu
li
= link_to edit_asciicast_path(@asciicast) do
= link_to edit_asciicast_path(page.asciicast) do
span.glyphicon.glyphicon-edit
' Edit
li
= link_to(asciicast_path(@asciicast), method: :delete, data: { confirm: 'Really delete this asciicast?' }) do
= link_to(asciicast_path(page.asciicast), method: :delete, data: { confirm: 'Really delete this asciicast?' }) do
span.glyphicon.glyphicon-remove
' Delete
@ -58,13 +55,18 @@
.row
.col-md-6.col-md-offset-6
.embed-box.text-right
input[type="text" class="embed-script" value=@asciicast.embed_script data-behavior="auto-select" readonly]
input[type="text" class="embed-script" value=page.embed_script(self) data-behavior="auto-select" readonly]
br
| See the #{link_to 'embedding docs', docs_path(:embedding)} for more options.
- if @asciicast.description.present?
- if page.show_description?
section.even.description
.container
.content = @asciicast.description
.content = page.description
= render 'other_by_user'
- if page.show_other_asciicasts_by_author?
section.odd
.container
.other-asciicasts
h2 More by #{page.author_link}
= render 'previews', asciicasts: page.other_asciicasts_by_author, per_row: 3

@ -28,6 +28,8 @@ describe AsciicastsController do
get :index, category: 'featured', order: 'recency', page: '2'
end
it { should be_success }
it "renders template with AsciicastListPresenter as page" do
expect(controller).to have_received(:render).
with(locals: { page: asciicast_list_presenter })
@ -44,11 +46,14 @@ describe AsciicastsController do
end
context 'for html request' do
let(:asciicast_decorator) { double('decorator', :title => 'The Title') }
let(:asciicast_presenter) { double('asciicast_presenter') }
let(:user) { double('user') }
before do
allow(AsciicastDecorator).to receive(:new).with(asciicast).
and_return(asciicast_decorator)
allow(controller).to receive(:render)
allow(controller).to receive(:current_user) { user }
allow(AsciicastPresenter).to receive(:new).with(asciicast, user).
and_return(asciicast_presenter)
get :show, :id => asciicast.id, :format => :html
end
@ -60,7 +65,10 @@ describe AsciicastsController do
with(asciicast, cookies)
end
specify { expect(assigns(:asciicast)).to eq(asciicast_decorator) }
it "renders template with AsciicastPresenter as page" do
expect(controller).to have_received(:render).
with(locals: { page: asciicast_presenter })
end
end
context 'for json request' do

@ -214,30 +214,6 @@ describe AsciicastDecorator do
it { should eq('img-link') }
end
describe '#other_by_user' do
pending
end
describe '#embed_script' do
let(:src_regexp) {
/src="[^"]+\b123\b[^"]*\.js"/
}
let(:id_regexp) {
/id="asciicast-123"/
}
let(:script_regexp) {
/^<script[^>]+#{src_regexp}[^>]+#{id_regexp}[^>]*><\/script>/
}
before do
allow(asciicast).to receive(:id).and_return(123)
end
it 'should be an async script tag including asciicast id' do
expect(decorator.embed_script).to match(script_regexp)
end
end
describe '#formatted_duration' do
subject { decorator.formatted_duration }

@ -124,4 +124,16 @@ describe User do
it { should eq(2) }
end
describe '#asciicasts_excluding' do
subject { user.asciicasts_excluding(asciicast, 1) }
let(:user) { create(:user) }
let(:asciicast) { create(:asciicast, user: user) }
it "returns other asciicasts by user excluding the given one" do
other = create(:asciicast, user: user)
expect(subject).to eq([other])
end
end
end

@ -0,0 +1,198 @@
require 'spec_helper'
describe AsciicastPresenter do
let(:presenter) { described_class.new(asciicast, current_user) }
let(:asciicast) { stub_model(Asciicast, user: author) }
let(:author) { User.new }
let(:current_user) { User.new }
let(:view_context) {
controller = ApplicationController.new
controller.request = ActionController::TestRequest.new
controller.view_context
}
before do
allow(AsciicastDecorator).to receive(:new).with(asciicast) { asciicast }
end
describe '#title' do
subject { presenter.title }
before do
allow(asciicast).to receive(:title) { 'the-title' }
end
it { should eq('the-title') }
end
describe '#asciicast_title' do
subject { presenter.asciicast_title }
before do
allow(asciicast).to receive(:title) { 'the-title' }
end
it { should eq('the-title') }
end
describe '#author_img_link' do
subject { presenter.author_img_link }
before do
allow(asciicast).to receive(:author_img_link) { '<a href=...>' }
end
it { should eq('<a href=...>') }
end
describe '#author_link' do
subject { presenter.author_link }
before do
allow(asciicast).to receive(:author_link) { '<a href=...>' }
end
it { should eq('<a href=...>') }
end
describe '#asciicast_created_at' do
subject { presenter.asciicast_created_at }
let(:now) { Time.now }
before do
allow(asciicast).to receive(:created_at) { now }
end
it { should eq(now) }
end
describe '#asciicast_env_details' do
subject { presenter.asciicast_env_details }
before do
allow(asciicast).to receive(:os) { 'Linux' }
allow(asciicast).to receive(:shell) { 'bash' }
allow(asciicast).to receive(:terminal_type) { 'xterm' }
end
it { should eq('Linux / bash / xterm') }
end
describe '#views_count' do
subject { presenter.views_count }
before do
allow(asciicast).to receive(:views_count) { 5 }
end
it { should eq(5) }
end
describe '#embed_script' do
subject { presenter.embed_script(view_context) }
let(:src_regexp) { /src="[^"]+\b123\b[^"]*\.js"/ }
let(:id_regexp) { /id="asciicast-123"/ }
let(:script_regexp) {
/^<script[^>]+#{src_regexp}[^>]+#{id_regexp}[^>]*><\/script>/
}
before do
allow(asciicast).to receive(:id).and_return(123)
end
it 'is an async script tag including asciicast id' do
expect(subject).to match(script_regexp)
end
end
describe '#show_admin_dropdown?' do
subject { presenter.show_admin_dropdown? }
before do
allow(asciicast).to receive(:managable_by?).
with(current_user) { managable }
end
context "when asciicast can't be managed by the user" do
let(:managable) { false }
it { should be(false) }
end
context "when asciicast can be managed by the user" do
let(:managable) { true }
it { should be(true) }
end
end
describe '#show_description?' do
subject { presenter.show_description? }
before do
allow(asciicast).to receive(:description) { description }
end
context "when description is present" do
let(:description) { 'i am description' }
it { should be(true) }
end
context "when description isn't present" do
let(:description) { '' }
it { should be(false) }
end
end
describe '#description' do
subject { presenter.description }
before do
allow(asciicast).to receive(:description) { 'i am description' }
end
it { should eq('i am description') }
end
describe '#show_other_asciicasts_by_author?' do
subject { presenter.show_other_asciicasts_by_author? }
before do
allow(author).to receive(:asciicast_count) { count }
end
context "when user has more than 1 asciicast" do
let(:count) { 2 }
it { should be(true) }
end
context "when user doesn't have more than 1 asciicasts" do
let(:count) { 1 }
it { should be(false) }
end
end
describe '#other_asciicasts_by_author' do
subject { presenter.other_asciicasts_by_author }
let(:others) { [stub_model(Asciicast, id: 123)] }
before do
allow(author).to receive(:asciicasts_excluding).
with(asciicast, 3) { others }
end
it "returns decorated asciicasts excluding the given one" do
expect(subject.first.title).to eq('asciicast:123')
end
end
end
Loading…
Cancel
Save